fix: prevent TUI gateway stdin EOF crash across all TUI-context subprocess calls

When Hermes runs in TUI mode, the gateway child process communicates with
the Node.js parent over a JSON-RPC protocol on stdin. Subprocess calls that
inherit this stdin fd can trigger a race condition where the child's stdin
read returns EOF, causing the gateway to exit cleanly (exit code 0) mid-tool-
execution.

This is the same root cause as issue #14036 (byterover plugin) and PR #39257
(SSH environment backend). This commit applies the fix — stdin=subprocess.DEVNULL
— to all 85 subprocess.run() and subprocess.Popen() calls that execute inside
the TUI gateway child process.

Scope: TUI-context code only (agent/, tools/, plugins/, tui_gateway/server.py).
CLI code (cli.py, hermes_cli/), tests, scripts, and gateway process management
are excluded — they don't run inside the TUI child and inherit the terminal's
stdin, not the JSON-RPC pipe.

85 call sites across 28 files. All files pass syntax check.
This commit is contained in:
m4dni5
2026-06-08 22:46:57 -07:00
committed by Teknium
parent 54318c65b0
commit d1f23bb2d5
27 changed files with 84 additions and 20 deletions
+2
View File
@@ -307,6 +307,7 @@ def _run_git(
timeout=timeout,
env=env,
cwd=str(normalized_working_dir),
stdin=subprocess.DEVNULL,
)
ok = result.returncode == 0
stdout = result.stdout.strip()
@@ -426,6 +427,7 @@ def _init_store(store: Path, working_dir: str) -> Optional[str]:
["git", "init", "--bare", str(store)],
capture_output=True, text=True,
env=init_env, timeout=_GIT_TIMEOUT,
stdin=subprocess.DEVNULL,
)
if result.returncode != 0:
return f"Shadow store init failed: {result.stderr.strip()}"