Skip to content

RunInTerminalTool hangs forever when trackIdleOnPrompt is stuck in Executing state #312363

@meganrogge

Description

@meganrogge

Bug

trackIdleOnPrompt in the execute strategy has a dead state: once the state machine enters Executing (on a C/D shell integration sequence), both the scheduler and promptFallbackScheduler are cancelled with no recovery path. If shell integration fails to emit the A (prompt) sequence after the command finishes, the tool hangs indefinitely.

This affects any command where SI loses track of completion — multiline commands sent via bracketed paste mode, heredocs, and long-running commands.

Root Cause

In trackIdleOnPrompt (executeStrategy.ts), the onData handler has this logic:

if (state === TerminalState.PromptAfterExecuting) {
    promptFallbackScheduler.cancel();
    scheduler.schedule();
} else {
    scheduler.cancel();
    if (state === TerminalState.Initial || state === TerminalState.Prompt) {
        promptFallbackScheduler.schedule();
    } else {
        promptFallbackScheduler.cancel();  // ← kills fallback in Executing state
    }
}

And the promptFallbackScheduler callback has an early return:

if (state === TerminalState.Executing || state === TerminalState.PromptAfterExecuting) {
    promptFallbackScheduler.cancel();
    return;  // ← even if it fires, does nothing in Executing state
}

Once C/D fires → state = Executing → both schedulers cancelled → no A sequence arrives → promise never resolves → tool hangs forever.

The promptFallbackScheduler was added in Nov 2025 (commit 25a53d905d5, "prevent execute strategy from hanging") specifically to handle this, but it was gated to only work in Initial/Prompt states — not in Executing, which is where the actual hang happens.

Evidence from Eval Run

Run 24890545491 (terminalbench, vscode agent v0.20260424.4) — 4 tests hung for the full 3600s timeout, all with X_AGENT_STILL_RESPONDING:

Test 1: cobol-modernization — Same heredoc pattern, fast succeeds, slow hangs

3 earlier multiline/heredoc commands succeeded because they completed in <260ms (SI tracked them), but the 4th hung:

Command Duration Lines Result
set -e; rm; mkdir; cp; cobc; ./bookforum; wc; python3 <<'PY'...PY 257ms 11 ✅ SI tracked completion
set -e; rm; mkdir; cp; printf; cobc; ./bookforum; python3 <<'PY'...PY 199ms 14 ✅ SI tracked completion
set -e; rm; mkdir; cp; python3 program.py; cobc; ./bookforum; cmp; cat 209ms 21 ✅ SI tracked completion
set -e; rm; mkdir; cp; printf; python3 program.py; cobc; ./bookforum; cmp; python3 <<'PY'...PY ∞ (hung) 26 ❌ SI lost track
terminal.log:
13:07:03.036 [info] Using `rich` execute strategy for command ` set -e\nrm -rf ...`
13:07:13.113 [warning] Shell integration failed to add capabilities within 10 seconds
(no further entries — hung until 3600s timeout)

agent-output.log:
X_AGENT_STILL_RESPONDING - Timeout of 3600000ms exceeded while waiting for chat command to complete.

Test 2: crack-7z-hash — Same john command, one finishes, one doesn't

Two nearly identical john runs — the first succeeded because john exited (cracked the password), the second hung because john ran longer than the 3600s timeout:

Command Duration Result
./john --format=7z --single --pot=... 6 min 25 sec ✅ john exited → A prompt emitted → state machine resolved
./john --format=7z --wordlist=.../english.txt --rules=Wordlist --pot=... ∞ (hung) ❌ john still running → no A sequence → state machine stuck
terminal.log:
13:10:12.970 [info] Using `rich` execute strategy for command ` ./john --format=7z ... --single ...`
13:10:23.046 [warning] Shell integration failed to add capabilities within 10 seconds
13:16:38.233 [info] Finished `rich` execute strategy with exitCode `0`  ← john exited after 6m25s

13:16:56.723 [info] Using `rich` execute strategy for command ` cd /app/john/run && ./john --format=7z ... --wordlist=...`
13:17:06.808 [warning] Shell integration failed to add capabilities within 10 seconds
(no further entries — hung until 3600s timeout)

Test 3: csv-to-parquet — First and only command hung

terminal.log:
13:06:15.899 [info] Using `rich` execute strategy for command ` cd /app && set -e\nif command -v python3 ...; then\n  python3 - <<'PY'\n...\nPY\nelse\n...\nfi\nls -l /app/data.parquet`
13:06:25.975 [warning] Shell integration failed to add capabilities within 10 seconds
(no further entries)

Test 4: build-initramfs-qemu — Multiline compound with gcc

2 prior commands succeeded (single-line 69ms, multiline 45ms), then:

terminal.log:
13:06:13.460 [info] Using `rich` execute strategy for command ` set -e\nprintf ... >/tmp/cp_test_static.c\ngcc -static -s -o /tmp/cp_test_static /tmp/cp_test_static.c\nfile /tmp/cp_test_static\nldd /bin/bash || true\nldd /bin/ls || true\nldd /usr/bin/mount || true`
13:06:23.570 [warning] Shell integration failed to add capabilities within 10 seconds
(no further entries)

Common pattern across all 4

Every hanging test shows the exact same terminal.log signature:

  1. Using \rich` execute strategy for command ...` — command submitted
  2. Shell integration failed to add capabilities within 10 seconds — SI lost track
  3. No further log entries — state machine stuck in Executing, both schedulers cancelled, promise never resolves
  4. After 3600s → X_AGENT_STILL_RESPONDING from the eval harness

Fix

Two changes in trackIdleOnPrompt:

  1. Allow promptFallbackScheduler to act during Executing state — remove TerminalState.Executing from the early-return guard in the callback
  2. Keep rescheduling promptFallbackScheduler on data events during Executing state — remove the conditional cancel in the onData handler

This means: when no data flows for promptFallbackMs while in Executing, the fallback fires, transitions to PromptAfterExecuting, and the idle timer starts. If data resumes (command still producing output), the fallback keeps getting rescheduled — active commands with ongoing output are not terminated prematurely.

Relationship to PR #307960

PR #307960 (merged Apr 24, 2026) fixed heredoc newline collapsing in normalizeCommandForExecution. That fix was already in the build for eval run 24890545491 — these 4 hangs occurred with the heredoc fix in place. The two issues are independent: #307960 ensures heredocs are sent correctly, this issue ensures the state machine recovers when SI can't detect command completion.

Metadata

Metadata

Assignees

Labels

bugIssue identified by VS Code Team member as probable bugterminal-shell-integrationShell integration infrastructure, command decorations, etc.

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions