From 32087e4bc962744b1496da05c8d6e8b770068c12 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Sun, 28 Jun 2026 17:41:47 -0500 Subject: [PATCH 1/3] fix(windows): hide console flash on checkpoint git + skills_hub gh probes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The #54236/#54417 backend git/gh sweep routed git_probe, the repo-file picker, coding_context, context_references, copilot_auth, and the gateway process scans through CREATE_NO_WINDOW, but two sibling spawn legs that also run inside the console-less desktop/gateway backend were missed: - tools/checkpoint_manager.py `_run_git` (and the one-shot `git init --bare` in `_init_store`) — when checkpoints are enabled, every file-mutating turn fires multiple bare `git` calls (status, add, write-tree/commit-tree, update-ref). Spawned from a parent with no console (Electron spawns the backend with windowsHide → CREATE_NO_WINDOW), each one allocates its own conhost window → a flurry of terminal popups. - tools/skills_hub.py `GitHubAuth._try_gh_cli` — `gh auth token`, the same bug class as the already-fixed copilot_auth gh probe. Route both through `windows_hide_flags()` (no-op on POSIX), matching the established per-site pattern. Tests added to tests/test_windows_subprocess_no_window_flags.py. --- ...test_windows_subprocess_no_window_flags.py | 38 +++++++++++++++++++ tools/checkpoint_manager.py | 7 ++++ tools/skills_hub.py | 2 + 3 files changed, 47 insertions(+) diff --git a/tests/test_windows_subprocess_no_window_flags.py b/tests/test_windows_subprocess_no_window_flags.py index 7768f5fec08..3777182167e 100644 --- a/tests/test_windows_subprocess_no_window_flags.py +++ b/tests/test_windows_subprocess_no_window_flags.py @@ -300,6 +300,44 @@ def test_local_stt_audio_prep_hides_ffmpeg_window(monkeypatch, tmp_path): assert captured[0][0][0] == "ffmpeg" assert captured[0][1]["creationflags"] == _CREATE_NO_WINDOW +def test_checkpoint_manager_git_hides_windows(monkeypatch): + from tools import checkpoint_manager + + captured = [] + + def fake_run(cmd, **kwargs): + captured.append((cmd, kwargs)) + return _Completed(stdout="clean\n") + + monkeypatch.setattr(checkpoint_manager, "IS_WINDOWS", True) + monkeypatch.setattr(checkpoint_manager, "windows_hide_flags", lambda: _CREATE_NO_WINDOW) + monkeypatch.setattr(checkpoint_manager.subprocess, "run", fake_run) + + ok, _, _ = checkpoint_manager._run_git(["status", "--short"], Path("C:/store"), ".") + assert ok + assert captured[0][0][0] == "git" + assert captured[0][1]["creationflags"] == _CREATE_NO_WINDOW + + +def test_skills_hub_gh_token_hides_windows(monkeypatch): + from tools import skills_hub + + captured = [] + + def fake_run(cmd, **kwargs): + captured.append((cmd, kwargs)) + return _Completed(stdout="gho_from_cli\n") + + monkeypatch.setattr(skills_hub, "IS_WINDOWS", True) + monkeypatch.setattr(skills_hub, "windows_hide_flags", lambda: _CREATE_NO_WINDOW) + monkeypatch.setattr(skills_hub.subprocess, "run", fake_run) + + auth = skills_hub.GitHubAuth.__new__(skills_hub.GitHubAuth) + assert auth._try_gh_cli() == "gho_from_cli" + assert captured[0][0] == ["gh", "auth", "token"] + assert captured[0][1]["creationflags"] == _CREATE_NO_WINDOW + + def test_tui_slash_worker_hides_python_window(monkeypatch): from tui_gateway import server diff --git a/tools/checkpoint_manager.py b/tools/checkpoint_manager.py index 720973b67e0..589c993ba6b 100644 --- a/tools/checkpoint_manager.py +++ b/tools/checkpoint_manager.py @@ -58,6 +58,7 @@ import subprocess import time from pathlib import Path from hermes_constants import get_hermes_home +from hermes_cli._subprocess_compat import IS_WINDOWS, windows_hide_flags from typing import Dict, List, Optional, Set, Tuple from utils import env_int @@ -321,6 +322,10 @@ def _run_git( env = _git_env(store, str(normalized_working_dir), index_file=index_file) cmd = ["git"] + list(args) allowed_returncodes = allowed_returncodes or set() + # Checkpoints run inside the console-less desktop/gateway backend; a bare + # git spawn there pops a fresh conhost window per call (status, add, + # commit, …) on Windows. No-op on POSIX. + _popen_kwargs = {"creationflags": windows_hide_flags()} if IS_WINDOWS else {} try: result = subprocess.run( cmd, @@ -330,6 +335,7 @@ def _run_git( env=env, cwd=str(normalized_working_dir), stdin=subprocess.DEVNULL, + **_popen_kwargs, ) ok = result.returncode == 0 stdout = result.stdout.strip() @@ -450,6 +456,7 @@ def _init_store(store: Path, working_dir: str) -> Optional[str]: capture_output=True, text=True, env=init_env, timeout=_GIT_TIMEOUT, stdin=subprocess.DEVNULL, + **({"creationflags": windows_hide_flags()} if IS_WINDOWS else {}), ) if result.returncode != 0: return f"Shadow store init failed: {result.stderr.strip()}" diff --git a/tools/skills_hub.py b/tools/skills_hub.py index 76969fb8d8c..676b6c81f76 100644 --- a/tools/skills_hub.py +++ b/tools/skills_hub.py @@ -26,6 +26,7 @@ from dataclasses import dataclass, field from datetime import datetime, timezone from pathlib import Path, PurePosixPath from hermes_constants import get_hermes_home +from hermes_cli._subprocess_compat import IS_WINDOWS, windows_hide_flags from agent.skill_utils import is_excluded_skill_path from typing import Any, Dict, List, Optional, Tuple, Union from urllib.parse import urljoin, urlparse, urlunparse @@ -302,6 +303,7 @@ class GitHubAuth: ["gh", "auth", "token"], capture_output=True, text=True, timeout=5, stdin=subprocess.DEVNULL, + **({"creationflags": windows_hide_flags()} if IS_WINDOWS else {}), ) if result.returncode == 0 and result.stdout.strip(): return result.stdout.strip() From ee22d853eb131ecdce3a8ba54a9a1c39ee5ca4a1 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Sun, 28 Jun 2026 17:43:27 -0500 Subject: [PATCH 2/3] fix(windows): hide pdftoppm console flash on PDF attach server.py's PDF-attach handler shells out to `pdftoppm` from the console-less desktop/gateway backend; on Windows that pops a conhost window each attach. Route it through windows_hide_flags() like the sibling _list_repo_files git calls (no-op on POSIX). --- tui_gateway/server.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tui_gateway/server.py b/tui_gateway/server.py index a654d690496..4eb4a1b2ff9 100644 --- a/tui_gateway/server.py +++ b/tui_gateway/server.py @@ -9126,8 +9126,13 @@ def _(rid, params: dict) -> dict: "-f", str(first_page), "-l", str(last_page), str(pdf_path), str(out_prefix), ] + from hermes_cli._subprocess_compat import windows_hide_flags + try: - res = subprocess.run(argv, capture_output=True, text=True, timeout=120, stdin=subprocess.DEVNULL) + res = subprocess.run( + argv, capture_output=True, text=True, timeout=120, stdin=subprocess.DEVNULL, + creationflags=windows_hide_flags(), + ) except subprocess.TimeoutExpired: return _err(rid, 5028, "pdftoppm timed out (>120s)") if res.returncode != 0: From cb1bb1a48d76a7b1584b66f541e85d1a84b6bb06 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Sun, 28 Jun 2026 17:44:47 -0500 Subject: [PATCH 3/3] refactor(windows): unify windowless spawn form across the touched sites windows_hide_flags() already returns 0 on POSIX (and creationflags=0 is the no-op default there, exactly how server.py::_list_repo_files does it), so drop the IS_WINDOWS import + ternary/one-use-dict gating and just pass creationflags=windows_hide_flags() directly. Tests lose the now-pointless IS_WINDOWS monkeypatch. --- tests/test_windows_subprocess_no_window_flags.py | 2 -- tools/checkpoint_manager.py | 14 +++++++------- tools/skills_hub.py | 4 ++-- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/tests/test_windows_subprocess_no_window_flags.py b/tests/test_windows_subprocess_no_window_flags.py index 3777182167e..37635cc24b3 100644 --- a/tests/test_windows_subprocess_no_window_flags.py +++ b/tests/test_windows_subprocess_no_window_flags.py @@ -309,7 +309,6 @@ def test_checkpoint_manager_git_hides_windows(monkeypatch): captured.append((cmd, kwargs)) return _Completed(stdout="clean\n") - monkeypatch.setattr(checkpoint_manager, "IS_WINDOWS", True) monkeypatch.setattr(checkpoint_manager, "windows_hide_flags", lambda: _CREATE_NO_WINDOW) monkeypatch.setattr(checkpoint_manager.subprocess, "run", fake_run) @@ -328,7 +327,6 @@ def test_skills_hub_gh_token_hides_windows(monkeypatch): captured.append((cmd, kwargs)) return _Completed(stdout="gho_from_cli\n") - monkeypatch.setattr(skills_hub, "IS_WINDOWS", True) monkeypatch.setattr(skills_hub, "windows_hide_flags", lambda: _CREATE_NO_WINDOW) monkeypatch.setattr(skills_hub.subprocess, "run", fake_run) diff --git a/tools/checkpoint_manager.py b/tools/checkpoint_manager.py index 589c993ba6b..f256ec7c3d3 100644 --- a/tools/checkpoint_manager.py +++ b/tools/checkpoint_manager.py @@ -58,7 +58,7 @@ import subprocess import time from pathlib import Path from hermes_constants import get_hermes_home -from hermes_cli._subprocess_compat import IS_WINDOWS, windows_hide_flags +from hermes_cli._subprocess_compat import windows_hide_flags from typing import Dict, List, Optional, Set, Tuple from utils import env_int @@ -322,10 +322,7 @@ def _run_git( env = _git_env(store, str(normalized_working_dir), index_file=index_file) cmd = ["git"] + list(args) allowed_returncodes = allowed_returncodes or set() - # Checkpoints run inside the console-less desktop/gateway backend; a bare - # git spawn there pops a fresh conhost window per call (status, add, - # commit, …) on Windows. No-op on POSIX. - _popen_kwargs = {"creationflags": windows_hide_flags()} if IS_WINDOWS else {} + try: result = subprocess.run( cmd, @@ -335,7 +332,10 @@ def _run_git( env=env, cwd=str(normalized_working_dir), stdin=subprocess.DEVNULL, - **_popen_kwargs, + # Checkpoints fire several bare git calls per turn from the + # console-less desktop/gateway backend; suppress the per-call + # conhost flash on Windows (no-op on POSIX). + creationflags=windows_hide_flags(), ) ok = result.returncode == 0 stdout = result.stdout.strip() @@ -456,7 +456,7 @@ def _init_store(store: Path, working_dir: str) -> Optional[str]: capture_output=True, text=True, env=init_env, timeout=_GIT_TIMEOUT, stdin=subprocess.DEVNULL, - **({"creationflags": windows_hide_flags()} if IS_WINDOWS else {}), + creationflags=windows_hide_flags(), ) if result.returncode != 0: return f"Shadow store init failed: {result.stderr.strip()}" diff --git a/tools/skills_hub.py b/tools/skills_hub.py index 676b6c81f76..9e2918ffc5e 100644 --- a/tools/skills_hub.py +++ b/tools/skills_hub.py @@ -26,7 +26,7 @@ from dataclasses import dataclass, field from datetime import datetime, timezone from pathlib import Path, PurePosixPath from hermes_constants import get_hermes_home -from hermes_cli._subprocess_compat import IS_WINDOWS, windows_hide_flags +from hermes_cli._subprocess_compat import windows_hide_flags from agent.skill_utils import is_excluded_skill_path from typing import Any, Dict, List, Optional, Tuple, Union from urllib.parse import urljoin, urlparse, urlunparse @@ -303,7 +303,7 @@ class GitHubAuth: ["gh", "auth", "token"], capture_output=True, text=True, timeout=5, stdin=subprocess.DEVNULL, - **({"creationflags": windows_hide_flags()} if IS_WINDOWS else {}), + creationflags=windows_hide_flags(), ) if result.returncode == 0 and result.stdout.strip(): return result.stdout.strip()