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.
This commit is contained in:
Teknium
2026-09-07 07:43:11 -07:00
parent a46ddf0f32
commit 92f4246aa2
2 changed files with 9 additions and 5 deletions
+6 -3
View File
@@ -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,
@@ -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