Skip to content

fix: add default timeout for terminal command tool execution#10550

Open
amabito wants to merge 1 commit intocontinuedev:mainfrom
amabito:fix/runTerminalCommand-default-timeout
Open

fix: add default timeout for terminal command tool execution#10550
amabito wants to merge 1 commit intocontinuedev:mainfrom
amabito:fix/runTerminalCommand-default-timeout

Conversation

@amabito
Copy link

@amabito amabito commented Feb 16, 2026

Summary

  • runTerminalCommand could hang indefinitely, blocking the entire session
  • Adds a default 2-minute timeout with graceful SIGTERM -> SIGKILL shutdown
  • All timers properly cleared on close/error (no resource leaks)

Changes

  • core/tools/implementations/runTerminalCommand.ts — timeout logic for both streaming and non-streaming modes
  • core/tools/implementations/runTerminalCommand.timeout.vitest.ts — 5 test cases covering timeout, cleanup, and background process exclusion

Details

  • DEFAULT_TOOL_TIMEOUT_MS = 120_000 (2 minutes)
  • SIGTERM first, SIGKILL after 5s grace period if still alive
  • Inner SIGKILL timer is also cleared on process exit (no dangling timers)
  • waitForCompletion=false (background) processes are not affected
  • Timeout message appended to output: [Timeout: process killed after 2 minutes]

Test plan

  • runTerminalCommand.timeout.vitest.ts passes
  • Existing runTerminalCommand.vitest.ts unaffected
  • Manual: run a long command, verify it terminates after 2 min

🤖 Generated with Claude Code


Continue Tasks: ✅ 1 no changes — View all


Summary by cubic

Add a default 2-minute timeout to runTerminalCommand so hung commands don’t block sessions. Gracefully terminates processes and cleans up timers to prevent leaks.

  • Bug Fixes
    • Works in streaming and non-streaming; skipped for background runs (waitForCompletion=false).
    • On timeout: update UI status, send SIGTERM, then SIGKILL after 5s if still running; clear the SIGKILL timer if the process exits during the grace period.
    • Append “[Timeout: process killed after 2 minutes]” to output; clear all timers on close/error; add tests for timeout and cleanup.

Written for commit ce37e50. Summary will update on new commits.

@amabito amabito requested a review from a team as a code owner February 16, 2026 13:10
@amabito amabito requested review from sestinj and removed request for a team February 16, 2026 13:10
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Feb 16, 2026
@github-actions
Copy link

github-actions bot commented Feb 16, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@amabito
Copy link
Author

amabito commented Feb 16, 2026

I have read the CLA Document and I hereby sign the CLA

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 2 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="core/tools/implementations/runTerminalCommand.ts">

<violation number="1" location="core/tools/implementations/runTerminalCommand.ts:179">
P3: Non-streaming waitForCompletion schedules timeout/sigkill timers but the error handler does not clear them, leaving timers to fire after rejection and potentially kill/mutate output for a failed spawn.</violation>

<violation number="2" location="core/tools/implementations/runTerminalCommand.ts:180">
P2: SIGKILL fallback never runs because childProc.killed becomes true immediately after SIGTERM; it does not indicate process exit. Use exitCode/signalCode to detect whether the process is still running.</violation>
</file>

<file name="core/tools/implementations/runTerminalCommand.timeout.vitest.ts">

<violation number="1" location="core/tools/implementations/runTerminalCommand.timeout.vitest.ts:35">
P2: Extra closing brace ends the describe block before the final test, leaving the last test outside the setup/teardown and out of scope for helpers/mocks.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

// Set up timeout for waitForCompletion mode
if (waitForCompletion) {
timeoutId = setTimeout(() => {
if (!childProc.killed) {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: SIGKILL fallback never runs because childProc.killed becomes true immediately after SIGTERM; it does not indicate process exit. Use exitCode/signalCode to detect whether the process is still running.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At core/tools/implementations/runTerminalCommand.ts, line 180:

<comment>SIGKILL fallback never runs because childProc.killed becomes true immediately after SIGTERM; it does not indicate process exit. Use exitCode/signalCode to detect whether the process is still running.</comment>

<file context>
@@ -168,6 +174,42 @@ export const runTerminalCommandImpl: ToolImpl = async (args, extras) => {
+          // Set up timeout for waitForCompletion mode
+          if (waitForCompletion) {
+            timeoutId = setTimeout(() => {
+              if (!childProc.killed) {
+                terminalOutput += "
+[Timeout: process killed after 2 minutes]
</file context>
Fix with Cubic

@amabito
Copy link
Author

amabito commented Feb 16, 2026

I have read the CLA Document and I hereby sign the CLA

@amabito
Copy link
Author

amabito commented Feb 16, 2026

recheck

@amabito amabito force-pushed the fix/runTerminalCommand-default-timeout branch from e585e06 to 03595e5 Compare February 16, 2026 13:35
@amabito
Copy link
Author

amabito commented Feb 16, 2026

I have read the CLA Document and I hereby sign the CLA

Terminal commands with waitForCompletion=true had no timeout, risking
indefinite hangs. Adds a 2-minute default timeout with graceful
SIGTERM -> 5s grace period -> SIGKILL escalation. Both streaming
and non-streaming code paths are covered. The SIGKILL timer is
properly cleared if the process exits during the grace period.
@amabito amabito force-pushed the fix/runTerminalCommand-default-timeout branch from 03595e5 to ce37e50 Compare February 16, 2026 13:50
@amabito
Copy link
Author

amabito commented Feb 16, 2026

@sestinj CI is fully green (including both required checks), and this is a small, self-contained safety improvement (default 2-min timeout + proper SIGKILL timer cleanup, tests included).

Would appreciate a quick review when you have a moment. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

1 participant