fix(cli): reset terminal input modes on TUI exit to stop focus/mouse leaks - #36864
Merged
ethernet8023 merged 1 commit intoJun 2, 2026
Conversation
maxmilian
force-pushed
the
fix/tui-reset-terminal-input-modes-on-exit
branch
from
June 1, 2026 15:24
16409b8 to
5216c7e
Compare
…leaks When the TUI exits via Ctrl+C, SIGTERM/SIGHUP, or a crash, prompt_toolkit's teardown can be bypassed, leaving DEC 1004 (focus reporting) and 1000/1002/1003 (mouse tracking) enabled. The terminal then emits raw ESC[I/ESC[O focus events and fragmented SGR mouse reports as visible text in whatever runs next in the same tab. _run_cleanup() — the once-only cleanup that runs on every catchable exit path (atexit-registered + called on the normal/EOF/interrupt exit) — now emits _TERMINAL_INPUT_MODE_RESET_SEQ (the same disable sequence the in-session leak recovery already uses) as its FIRST step, so the terminal is usable immediately on Ctrl+C and a later teardown step raising can't skip it. The reset is gated on a new _tui_input_modes_active flag (set right before app.run(), cleared once the modes are disabled) so non-TUI one-shot CLI runs — which share _run_cleanup via atexit — don't emit codes for modes they never enabled. Writes to sys.stdout when it's the terminal, else falls back to /dev/tty. SIGKILL is uncatchable and the kanban worker's os._exit(0) bypasses atexit, but both are non-TTY/non-TUI so there is nothing to reset there. Adds tests/cli/test_tui_terminal_reset_on_exit.py (9): emits on a TTY when the TUI ran, no-ops when the TUI never ran, /dev/tty fallback when stdout is redirected, no-op when neither is available, swallows stdout errors, flag set and cleared, and wired into _run_cleanup as the first step even when a later step raises. Fixes NousResearch#36823 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
maxmilian
force-pushed
the
fix/tui-reset-terminal-input-modes-on-exit
branch
from
June 1, 2026 15:27
5216c7e to
038ed94
Compare
maxmilian
marked this pull request as ready for review
June 1, 2026 15:44
tonydwb
approved these changes
Jun 1, 2026
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved
✅ Looks Good
- Fixes a real UX issue: terminal input modes (focus reporting + mouse tracking) leaking into next shell session
- Properly gated on
_tui_input_modes_activeflag so one-shot non-TUI CLI runs don't emit escape codes - Written as first step in
_run_cleanup(atexit) so it runs even if later cleanup raises - Falls back to
/dev/ttywhen stdout is redirected - Graceful error handling: all exceptions swallowed (cleanup must never raise)
- Comprehensive tests: 7 test cases covering TTY, non-TTY, /dev/tty fallback, stdout errors, flag lifecycle, and cleanup wiring
- Known limitation documented:
kill -9andos._exit(0)paths bypass atexit
Reviewed by Hermes Agent
This was referenced Jun 2, 2026
1 task
alt-glitch
pushed a commit
that referenced
this pull request
Jun 14, 2026
…-modes-on-exit fix(cli): reset terminal input modes on TUI exit to stop focus/mouse leaks
T02200059
pushed a commit
to T02200059/hermes-agent
that referenced
this pull request
Jun 18, 2026
…rminal-input-modes-on-exit fix(cli): reset terminal input modes on TUI exit to stop focus/mouse leaks
waefrebeorn
pushed a commit
to waefrebeorn/slermes
that referenced
this pull request
Jul 2, 2026
…rminal-input-modes-on-exit fix(cli): reset terminal input modes on TUI exit to stop focus/mouse leaks
santhreal
pushed a commit
to santhreal/hermes-agent
that referenced
this pull request
Jul 13, 2026
…rminal-input-modes-on-exit fix(cli): reset terminal input modes on TUI exit to stop focus/mouse leaks
Gravezzz
pushed a commit
to Gravezzz/hermes-agent
that referenced
this pull request
Jul 21, 2026
…rminal-input-modes-on-exit fix(cli): reset terminal input modes on TUI exit to stop focus/mouse leaks
leewenjie
pushed a commit
to leewenjie/hermes-agent
that referenced
this pull request
Aug 7, 2026
…rminal-input-modes-on-exit fix(cli): reset terminal input modes on TUI exit to stop focus/mouse leaks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When the TUI exits via Ctrl+C, SIGTERM/SIGHUP, or a crash, prompt_toolkit's teardown can be bypassed, leaving DEC 1004 (focus reporting) and 1000/1002/1003 (mouse tracking) enabled. The terminal then emits raw
ESC[I/ESC[Ofocus events and fragmented SGR mouse reports as visible text in whatever runs next in the same tab.Fixes #36823.
Root cause
_TERMINAL_INPUT_MODE_RESET_SEQalready exists and is emitted by_recover_terminal_input_modes— but only reactively, mid-session, when leaked mouse reports are detected. Nothing emits it on exit. On a clean teardown prompt_toolkit restores the modes itself; on Ctrl+C / signal / crash that unwind is skipped and the modes leak.Fix
_run_cleanup()— the once-only cleanup that runs on every exit path (it'satexit-registered and also called explicitly on normal/EOF/interrupt exit) — now calls a new_reset_terminal_input_modes_on_exit()as its final step. The helper writes_TERMINAL_INPUT_MODE_RESET_SEQtosys.stdoutguarded onisatty(). The disable codes are no-ops for any mode that was never enabled, so emitting them unconditionally on a TTY is safe and idempotent.Scope / known limitation:
SIGKILLis uncatchable, sokill -9mid-run still leaves the modes set — nothing in-process can prevent that. This fix covers normal quit, Ctrl+C, and SIGTERM/SIGHUP, which are the catchable paths.Tests
tests/cli/test_tui_terminal_reset_on_exit.py(4, all pass):ESC[?1004l) and flushes on a TTY_run_cleanup(the catch-all exit path)ruff checkclean;scripts/check-windows-footguns.pyclean; existingtests/cliimport sanity passes.Infographic