Skip to content

fix(win32): prevent TUI exit from closing terminal window#22002

Open
bamboodew wants to merge 2 commits intoanomalyco:devfrom
bamboodew:fix/win32-tui-exit-console-close
Open

fix(win32): prevent TUI exit from closing terminal window#22002
bamboodew wants to merge 2 commits intoanomalyco:devfrom
bamboodew:fix/win32-tui-exit-console-close

Conversation

@bamboodew
Copy link
Copy Markdown

@bamboodew bamboodew commented Apr 11, 2026

Issue for this PR

Closes #22003

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

On Windows, Ctrl+D exit closes the terminal window instead of returning to the shell.

I traced this with kernel32 FFI (SetConsoleCtrlHandler + GetConsoleWindow polling). The worker's graceful shutdown kills MCP
server subprocesses, and those exits detach the main process from its console — GetConsoleWindow() goes from a valid handle to
0x0. No CTRL_CLOSE_EVENT fires; the console is silently lost.

Both worker.terminate() and await client.call("shutdown") trigger this. terminate() crashes the console immediately; awaiting
shutdown destroys it ~4s later during MCP cleanup.

Fix in thread.ts: On Windows, fire-and-forget the shutdown signal and skip worker.terminate(). The existing
process.exit(0) tears everything down cleanly.

Fix in win32.ts: setImmediate(enforce) queued by the setRawMode wrapper during renderer.destroy() could fire after
unguard() and re-clear ENABLE_PROCESSED_INPUT. Moved done flag before enforce() and check it on entry.

How did you verify your code works?

  • All 3 existing tui thread tests pass
  • New test verifies platform-specific process.exit behavior
  • Manual testing on Windows 11 + Windows Terminal + cmd.exe: Ctrl+D exits TUI, terminal stays open, can type normally

Screenshots / recordings

N/A — terminal behavior fix, not UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

On Windows, exiting the TUI (Ctrl+D) causes the terminal window to close
instead of returning to the shell prompt. This happens because the worker's
graceful shutdown kills MCP server subprocesses, which detaches the main
process from its console (GetConsoleWindow → 0x0).

Two fixes:

1. **thread.ts**: On Windows, fire-and-forget the worker shutdown signal
   instead of awaiting it. Neither `worker.terminate()` nor awaiting the
   graceful shutdown is safe — both destroy the console window. Let
   `process.exit(0)` tear down all subprocesses instead.

2. **win32.ts**: Fix a race condition where a pending `setImmediate(enforce)`
   callback could re-clear `ENABLE_PROCESSED_INPUT` after `unguard()` had
   already restored the console mode. Move `done` flag before `enforce()`
   and check it on entry.
@github-actions
Copy link
Copy Markdown
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions github-actions bot added the needs:compliance This means the issue will auto-close after 2 hours. label Apr 11, 2026
@github-actions
Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Based on my search, I found two potentially related PRs (excluding the current PR #22002):

  1. fix: restore terminal state on exit to prevent mouse escape sequence … #21429 - fix: restore terminal state on exit to prevent mouse escape sequence ...

    • Related because it addresses terminal state restoration on exit, which is related to the console window handling issue in this PR
  2. fix: flush stdin on POSIX exit to prevent stale bytes leaking to shell #17083 - fix: flush stdin on POSIX exit to prevent stale bytes leaking to shell

    • Related because it handles terminal/shell cleanup on exit for POSIX systems, addressing similar concerns as this PR but for Windows

These PRs appear to address related but distinct platform-specific issues with terminal state management during exit. PR #22002 is specifically targeting Windows console behavior, while these others handle POSIX/general terminal concerns.

The unconditional process.exit(0) at the end of the TUI handler causes
the Linux CI test to fail. On non-Windows platforms, the index.ts
finally{} safety-net handles process exit. Only Windows needs the
explicit exit because the worker is not terminated there.
@github-actions github-actions bot removed needs:issue needs:compliance This means the issue will auto-close after 2 hours. labels Apr 11, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

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.

bug: TUI exit closes terminal window on Windows

1 participant