fix(windows): hide console-window flash on gateway-runtime subprocess spawns#44105
fix(windows): hide console-window flash on gateway-runtime subprocess spawns#44105AIalliAI wants to merge 6 commits into
Conversation
… probes The terminal tool's synchronous probe spawns (sudo NOPASSWD check, docker and apptainer/singularity availability checks) called subprocess.run without creationflags, so on Windows each one briefly pops a console window that also steals focus. The main command-execution path already passes windows_hide_flags() (tools/environments/local.py), but these probe sites were missed. Pass creationflags=windows_hide_flags() at each site. The helper returns 0 on non-Windows, so POSIX behavior is unchanged (creationflags=0 is the subprocess default). Fixes NousResearch#43848 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
When the gateway runs without a console on Windows (Desktop app, service), every console child process (git probes, rg, hooks, pip, taskkill, backend version probes) opens a visible conhost window that flickers and steals focus on each agent call. Pass creationflags=windows_hide_flags() (CREATE_NO_WINDOW; 0 on POSIX) to the subprocess spawn sites reachable during an agent turn, following the existing convention in tools/environments/local.py, tools/process_registry.py and cron/scheduler.py. Fixes NousResearch#43848 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Pushed a second commit expanding this beyond the terminal-tool probes: the dominant flicker sources on the default local backend turn out to be the spawns that run on every agent message — the git workspace probes in |
gateway/status.py now passes creationflags=windows_hide_flags() to the taskkill subprocess.run; the narrow fake_run signature rejected the new kwarg. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
_ensure_docker_available now passes creationflags=windows_hide_flags() (0 on POSIX) so the exact-kwargs assertion in test_ensure_docker_available_uses_resolved_executable must include it, mirroring the earlier TestTerminatePid taskkill stub fix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
check-attribution flagged the email introduced by this branch's 2026-06-12 follow-up commit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # scripts/release.py
|
Requesting maintainer review — this is ready to land from my side. Just merge-synced with current main (the only conflict was a trivial AUTHOR_MAP keep-both in scripts/release.py); the PR's touched test files pass locally on the merged head. Standalone fork CI is pending first-run approval here; the rollup branch in #44061 carrying this session's batch is fully green on upstream CI. |
Summary
On Windows, when the gateway runs without a console (Desktop app / background service), every console child process it spawns opens a visible conhost window that flickers and steals focus — the behavior reported in #43848.
The main terminal-tool execution path already hides its window via
windows_hide_flags()(tools/environments/local.py), and the same convention exists intools/process_registry.pyandcron/scheduler.py— but a number of spawn sites reachable during a normal agent turn were missed. The most user-visible ones run on every message (git workspace probes during prompt building) or on every file edit (checkpoint git calls), which is what makes the flicker so noticeable.Change
Pass
creationflags=windows_hide_flags()(CREATE_NO_WINDOW; returns0on POSIX, so non-Windows behavior is unchanged) at the gateway-runtime spawn sites:Per agent turn
agent/coding_context.py— git workspace probes during prompt building (several per message)agent/context_references.py—@git/@diffreference git calls andrg --fileslistingtools/checkpoint_manager.py— shadow-store git calls on every checkpointed file editagent/shell_hooks.py— user-configured hook commandsagent/skill_preprocessing.py— SKILL.md inline-shell snippetsTerminal tool probes (first commit)
tools/terminal_tool.py—sudo -n trueprobe (Windows 11 ships asudo),docker version/apptainer --versionbackend probesProcess cleanup (
taskkilltree-kills, Windows-only branches)gateway/status.py::terminate_pid,tools/tts_tool.py,tools/transcription_tools.pyRuntime installs / probes
tools/lazy_deps.py—uv pip/pip/ensurepipruntime dependency installs (these otherwise show a console window for the whole install)tools/env_probe.py— interpreter/binary version probesContainer/remote backends
tools/environments/base.py—_popen_bashnow defaultscreationflagstowindows_hide_flags()(viasetdefault, so callers can still override), covering the shareddocker exec/sshper-command spawn pathtools/environments/docker.py— container lifecycle and probe spawns (docker ps/rm/inspect/run/start/stop/info/create)tools/environments/ssh.py— control-master setup, scp/tar sync, and remote command spawnsSites intentionally left alone: macOS-only spawns (
security,scutil), interactive flows that must keep the console (claude setup-token), and the interactive CLI (a console already exists there, so nothing flashes).Testing
tests/tools/test_windows_native_support.py(TestGatewayRuntimeSpawnsHideConsole) simulate Windows by flippingIS_WINDOWSin_subprocess_compatand assert theCREATE_NO_WINDOWbit reachessubprocess.runfor the per-turn probes, taskkill paths, and inline-shell helper. Verified they fail against unpatched modules.test_coding_context,test_context_references,test_shell_hooks,test_checkpoint_manager,test_env_probe,test_lazy_deps,test_windows_native_support,test_status, plus the terminal-tool suites (220 more).Fixes #43848
🤖 Generated with Claude Code