fix(tui v2): stop tool subprocesses inheriting TTY stdin (multi-session key-eating on macOS/Linux)#656
Open
ggandmee-cloud wants to merge 1 commit into
Open
Conversation
6bcf7fa to
ed3d9c7
Compare
…ion key-eating on macOS/Linux Symptom ga tui2 with several concurrent sessions randomly swallows typed input — letters, digits, space and Enter vanish while agents are running tools. Single idle session is mostly unaffected. Environment Observed on macOS (Apple Silicon, zsh, Ghostty) with ga tui2 (frontends/tuiapp_v2.py, Textual). Not terminal-specific: any POSIX platform is affected. Windows never showed it — see below. Root cause code_run (ga.py) spawned tool subprocesses with stdout/stderr piped but stdin left untouched, so every bash/python child inherited the TUI's terminal as fd 0, in the same foreground process group as Textual. Any child that reads stdin (input(), interactive prompts, stdin-probing tools, readline tcsetattr on import) races Textual for the same keyboard bytes and can flip the tty out of raw mode. More sessions -> more concurrent children -> more collisions, hence 'multi-session' presentation. Windows was immune by accident: the existing creationflags=CREATE_NO_WINDOW branch detaches children from the console, so they can never touch its input buffer. The POSIX branch passed 0 — no isolation at all. This fix gives POSIX the same isolation Windows already had; behavior on Windows is unchanged. Fix Pass stdin=DEVNULL wherever no child legitimately needs the terminal: - ga.py code_run Popen (the main path every tool call goes through) - tuiapp_v2.py !shell inline command (30s window) - tuiapp_v2.py clipboard helper (only when no input= is fed) - checklist_helper.py _PK spawns (long-lived worker/master/bbs) Verification py_compile clean; code_run 'echo' unchanged; 'read -t 5 x' child now gets immediate EOF (~1s) instead of holding the tty for 5s.
ed3d9c7 to
0798c1e
Compare
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.
Symptom
Running
ga tui2with several concurrent sessions on macOS randomly swallows typed input — letters, digits, space and Enter vanish while agents are running tools. A single idle session is mostly unaffected, so it presents as a "multi-session" bug.Environment
frontends/tuiapp_v2.py(Textual)Root cause
code_run(ga.py) spawns tool subprocesses with stdout/stderr piped but stdin left untouched, so every bash/python child inherits the TUI's terminal as fd 0, in the same foreground process group as Textual. Any child that reads stdin —input(), interactive prompts, stdin-probing tools, or readline'stcsetattron import — races Textual for the same keyboard bytes and can flip the tty out of raw mode. More sessions → more concurrent children → more collisions.Windows is immune because the existing
creationflags=CREATE_NO_WINDOWbranch detaches children from the console, so they can never touch its input buffer. The POSIX branch passes0— no isolation at all. This fix gives POSIX the same isolation Windows already had; Windows behavior is unchanged.Fix
Pass
stdin=subprocess.DEVNULLwherever no child legitimately needs the terminal:ga.pycode_runPopen — the main path every tool call goes throughtuiapp_v2.py!shellinline command (30s window)tuiapp_v2.pyclipboard helper (only when noinput=is fed;pbcopy/xclipdata path unaffected)checklist_helper.py_PKspawns (long-lived worker/master/bbs processes)Verification
py_compileclean on all three filescode_run('echo ...')output unchangedcode_run('read -t 5 x; echo rc=$?')child now gets immediate EOF (~1s) instead of holding the tty for 5 secondsga tui2with multiple concurrent sessions running tools while typing — no more swallowed keystrokes