Skip to content

Force-kill stuck AI terminal commands#316

Merged
hendrikmennen merged 1 commit into
mainfrom
fix/ai-terminal-kill-stuck
Jul 15, 2026
Merged

Force-kill stuck AI terminal commands#316
hendrikmennen merged 1 commit into
mainfrom
fix/ai-terminal-kill-stuck

Conversation

@hendrikmennen

Copy link
Copy Markdown
Contributor

Problem

A runTerminalCommand could open a terminal tab, get stuck forever, and be impossible to escape — even the stop button / manual Ctrl+C couldn't recover it. Because the AI reuses the same automation terminal, once it was stuck every subsequent command hung too.

Investigation

The keyboard input path is sound (Ctrl+C maps to \u0003, the terminal control is Focusable), and pressing Ctrl+C in a healthy shell does recover it. The unrecoverable case is when the running process ignores SIGINT or the shell itself is hung — the previous gentle-interrupt recovery had no fallback, so the terminal stayed stuck and poisoned all later commands.

Changes

On cancellation/timeout the shell is still sent Ctrl+C first (keeps the terminal reusable for well-behaved commands). If it does not return to a usable prompt within the grace period:

  • PseudoTerminalConnection.KillProcess forcibly kills the shell and its entire child process tree.
  • TerminalViewModel.KillProcess exposes this to the manager.
  • TerminalManagerViewModel kills the process tree and discards the stuck automation terminal, so the next AI command always starts from a fresh, responsive terminal instead of reusing a hung one.

This guarantees a stuck command can always be terminated (via the Copilot stop button, which cancels the tool's CancellationToken), and that the AI terminal never stays permanently wedged.

Testing

  • dotnet build src/OneWare.TerminalManager succeeds (only pre-existing warnings).

When an AI terminal command is cancelled or times out, the shell is first
sent Ctrl+C to recover the prompt. If the shell does not return to a
usable prompt within the grace period (the process ignores SIGINT or is
itself hung), the terminal previously stayed stuck forever and, because
the automation terminal is reused, every subsequent command hung too.

Now, if the interrupt fails to recover the prompt, the child process tree
is forcibly killed and the stuck automation terminal is discarded, so the
next command always starts from a fresh, responsive terminal.

- PseudoTerminalConnection.KillProcess kills the shell and its children.
- TerminalViewModel.KillProcess exposes this to the manager.
- TerminalManagerViewModel now kills and discards the terminal when
  interrupt-based recovery fails.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@hendrikmennen
hendrikmennen merged commit d88a07a into main Jul 15, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant