fix(browse): stop stray Windows console windows during browse#2060
Open
blueverse-hh wants to merge 1 commit into
Open
fix(browse): stop stray Windows console windows during browse#2060blueverse-hh wants to merge 1 commit into
blueverse-hh wants to merge 1 commit into
Conversation
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
The browse daemon is launched detached (cli.ts startServer), which on Windows
gives it NO console. Console children it then spawns -- chrome-headless-shell.exe
via Playwright, `bun` skill helpers, the taskkill cleanup -- find no console to
inherit, so Windows allocates a fresh VISIBLE console window for each. Users see
stray chrome-headless-shell / bun terminal windows during browse use; some linger
for the browser's lifetime. Neither the user's default-terminal choice nor a flag
on the daemon itself fixes it: a detached process has no console regardless.
Verified on Windows 11: a child of a detached/console-less parent is visible
without windowsHide and hidden with it (windowsHide => CREATE_NO_WINDOW, which
suppresses the window even when the parent has no console).
Fix: the daemon defaults windowsHide:true for every child_process spawn
(win-console-hide.ts, imported first in server.ts so it patches the
child_process singleton before Playwright's first launch()). playwright-core
reads spawn via a live `__toESM(require("child_process")).spawn` getter at call
time, so patching the singleton covers its browser launch even though spawn
options can't be passed through chromium.launch(). gstack's own Bun.spawn skill
helpers and the detached launcher / attack-telemetry spawns set windowsHide
directly.
End-to-end: `browse goto` now starts the daemon and 4 chrome-headless-shell
processes with zero visible windows.
Adds a static-grep tripwire so the flag and import order can't regress.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
96caef8 to
a8b5bc5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
During
browseuse on Windows, stray terminal windows pop up —chrome-headless-shell.exeandbun.exe— some lingering for the browser's lifetime.Root cause
The browse daemon is launched detached (
cli.tsstartServer), which on Windows means it has no console. When that console-less daemon spawns console children —chrome-headless-shell.exe(via Playwright),bunskill helpers, thetaskkillcleanup — each finds no console to inherit, so Windows allocates a fresh visible console window.This is not fixable via the user's "Default terminal application" setting (Console Host shows a window too), nor by setting
windowsHideon the daemon itself — a detached process has no console regardless, so its children still allocate visible ones.Verified on Windows 11: a child of a detached/console-less parent is visible without
windowsHideand hidden with it.windowsHide⇒CREATE_NO_WINDOW, which suppresses the window even when the parent has no console.Fix
The daemon defaults
windowsHide: truefor everychild_processspawn, viawin-console-hide.tsimported first inserver.ts. This covers Playwright's browser launch:playwright-core'sprocessLauncherreadsspawnthrough a live__toESM(require("child_process")).spawngetter at call time, so patching thechild_processsingleton before the firstlaunch()applies — even though spawn options can't be passed throughchromium.launch(). gstack's ownBun.spawnskill helpers and the detached launcher / attack-telemetry spawns setwindowsHidedirectly.windowsHideis a documented no-op on macOS/Linux.Verification
Built on Windows 11 and ran
browse goto https://example.com:chrome-headless-shellprocesses spawnedEnumWindows/IsWindowVisible: zero visible windows for any gstack process (daemon, chrome, bun)Before the fix the same processes each opened a visible console window.
Adds
browse/test/windows-hide-detached-console.test.ts— a static-grep tripwire pinning thewindowsHidedefaults and thewin-console-hideimport order so this can't regress.Note (out of scope)
Several existing source-scanning tests fail on Windows because they derive the source dir via
new URL(import.meta.url).pathname(yields/C:/...→ doubled-driveC:\C:\...→ ENOENT), e.g.terminal-agent-pid-identity.test.ts(verified failing onmain). The new test usesimport.meta.dir. Happy to send a follow-up switching those over.🤖 Generated with Claude Code