Skip to content

fix(browse): stop the Bun polyfill flashing console windows on Windows#2290

Open
WimvandenHeijkant wants to merge 1 commit into
garrytan:mainfrom
WimvandenHeijkant:fix/windows-hide-console-popup
Open

fix(browse): stop the Bun polyfill flashing console windows on Windows#2290
WimvandenHeijkant wants to merge 1 commit into
garrytan:mainfrom
WimvandenHeijkant:fix/windows-hide-console-popup

Conversation

@WimvandenHeijkant

Copy link
Copy Markdown

The symptom

On Windows, using any browse-backed skill pops up empty black bun.exe console windows — one roughly every 60 seconds, with nothing in them.

The cause

browse/src/bun-polyfill.cjs supplies a Bun global so the bundled browse/dist/server-node.mjs can run under Node. Its spawn/spawnSync forward to child_process without windowsHide, and Node defaults that to false — so every child gets a console window on Windows. Real Bun.spawn doesn't do this, so the polyfill was quietly drifting from the API it emulates.

Two details explain the exact symptom:

  • Why every ~60s: the agent watchdog in browse/src/server.ts (GSTACK_AGENT_WATCHDOG_TICK_MS, default 60000) respawns the terminal-agent when it isn't alive. A crash-looping agent therefore yields a fresh window per tick.
  • Why empty: the agent is spawned with stdio: ['ignore', 'ignore', 'ignore'], so the window it opens has no output in it.

It isn't only the terminal-agent — the tasklist, powershell, and chrome --version helpers all flow through the same polyfill and pop windows too.

The fix

windowsHide: options.windowsHide !== false on both polyfill spawn paths. Fixed at the polyfill rather than at each call site because it's the single choke point every Bun.spawn under Node passes through. An explicit windowsHide: false still wins, so anyone who genuinely wants a visible console keeps the escape hatch.

Verification

Intercepted child_process and compared the current polyfill against the patched one:

spawnSync spawn explicit windowsHide: false
before undefined undefined undefined
after true true false

undefined is what Node reads as false — hence the window.

Added two regression tests to browse/test/bun-polyfill.test.ts, following the file's existing "require the polyfill in a Node subprocess" style. They assert the option reaches child_process rather than trying to observe a window, so they're meaningful on Linux CI too. Confirmed they fail against the unpatched polyfill and pass against the patched one.

Notes for the reviewer

  • Scope is deliberately limited to the Node polyfill, which is what server-node.mjs uses. The Bun.spawn call in browse/src/terminal-agent-control.ts (the real-Bun path, used by the compiled browse.exe) is untouched — I couldn't verify real-Bun window behaviour on this machine and didn't want to guess. Happy to extend if you know it needs the same treatment.
  • browse/test/bun-polyfill.test.ts currently can't run on Windows at all, independent of this PR: it interpolates an absolute path into a node -e string, so on Windows require('C:\Users\...') hits invalid \U/\A escapes, and two tests also assume a POSIX echo. Left alone as out of scope — mentioning it since this is a Windows fix whose tests only actually execute on Linux.
  • No VERSION/CHANGELOG.md bump, so version-gate doesn't trigger. Let me know if you'd like one.

🤖 Generated with Claude Code

The Node bun-polyfill forwards Bun.spawn/spawnSync to child_process
without windowsHide. Node defaults that option to false, so on Windows
every child the browse server starts opens a console window -- Bun
itself does not behave this way, so the polyfill was drifting from the
API it emulates.

The visible symptom is an empty black bun.exe window appearing every
~60s: server.ts's agent watchdog respawns a crashed terminal-agent on
each tick, and the agent is spawned with stdio ['ignore','ignore',
'ignore'], so the window it opens has nothing in it. The tasklist,
powershell and chrome --version helpers pop windows the same way.

Fixed at the polyfill rather than the call sites, since it is the one
choke point every Bun.spawn under Node passes through. An explicit
windowsHide: false is still honoured for callers that want a visible
console.

Verified against the unpatched polyfill (spawn/spawnSync both received
undefined) and the patched one (both receive true, explicit false still
wins).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@trunk-io

trunk-io Bot commented Jul 17, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

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

@WimvandenHeijkant

Copy link
Copy Markdown
Author

/trunk merge

@trunk-io

trunk-io Bot commented Jul 17, 2026

Copy link
Copy Markdown

An error occurred while submitting your PR to the queue: Only users that are a part of this repo's Trunk organization or have write permissions to the repo can submit a PR to the queue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant