From 92f4246aa2908d9323b36aaa299733e62e40e216 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Mon, 7 Sep 2026 07:43:11 -0700 Subject: [PATCH] fix(cli): hide the console window for banner/update git probes `hermes_cli/banner.py::_git_run` is the shared spawn path for every banner and passive update-check git probe (rev-parse, rev-list, remote get-url, ls-remote). It carried the UTF-8 text contract but not `creationflags=windows_hide_flags()`, so on Windows each probe run from a GUI-hosted backend (desktop-spawned `hermes serve`, `tui_gateway` import kicking off `prefetch_update_check`) flashes a console window. Every other short-lived helper in `hermes_cli/` already passes the flag; this brings the banner path in line. Surfaced by CI on this PR: the stray `git ... origin` spawn from the prefetch daemon landed in `test_env_probe_run_hides_console_window`'s process-wide `subprocess.run` capture and tripped its call-count assertion. The test now scopes its assertion through the module's `_spawns` helper like its siblings, so an unrelated daemon spawn cannot fail it (the production fix is what makes that stray spawn carry the flag in the first place). A/B: base `_git_run` -> no `creationflags` kwarg; fixed -> 0x08000000. --- hermes_cli/banner.py | 9 ++++++--- tests/test_windows_subprocess_no_window_flags.py | 5 +++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/hermes_cli/banner.py b/hermes_cli/banner.py index 291701523c..b4410592e6 100644 --- a/hermes_cli/banner.py +++ b/hermes_cli/banner.py @@ -168,10 +168,13 @@ def _git_run(args: list[str], *, cwd: Optional[Path] = None, timeout: int = 5, t encoding. ``network=True`` (ls-remote/fetch) detaches stdin and disables git/GCM prompts so a passive update check can never hang on a ``Username for 'https://github.com':`` prompt. """ - kwargs: dict = {} + from hermes_cli._subprocess_compat import noninteractive_git_env, windows_hide_flags + + # The banner/update probes run from GUI-hosted backends too (desktop-spawned + # ``hermes serve``), where a bare git child flashes a console window. + kwargs: dict = {"creationflags": windows_hide_flags()} if network: - from hermes_cli._subprocess_compat import noninteractive_git_env - kwargs = {"stdin": subprocess.DEVNULL, "env": noninteractive_git_env()} + kwargs.update({"stdin": subprocess.DEVNULL, "env": noninteractive_git_env()}) try: return subprocess.run( ["git", *args], capture_output=True, timeout=timeout, cwd=str(cwd) if cwd is not None else None, diff --git a/tests/test_windows_subprocess_no_window_flags.py b/tests/test_windows_subprocess_no_window_flags.py index f6ea2c9bde..21c563646f 100644 --- a/tests/test_windows_subprocess_no_window_flags.py +++ b/tests/test_windows_subprocess_no_window_flags.py @@ -360,8 +360,9 @@ def test_env_probe_run_hides_console_window(monkeypatch): rc, out, err = env_probe._run(["python3", "--version"], timeout=1.0) assert rc == 0 - assert len(captured) == 1, captured - cmd, kwargs = captured[0] + spawns = _spawns(captured, "python3", "--version") + assert len(spawns) == 1, captured + cmd, kwargs = spawns[0] assert cmd == ["python3", "--version"] assert kwargs["creationflags"] == _CREATE_NO_WINDOW # The temp-file capture contract (#67964) must survive: stdout/stderr are