Codex review pass 2 flagged a [P2]: Node emits 'error' but not 'exit'
when the spawned binary is missing, so the lifecycle Promise that only
listened to 'exit' hangs forever. `await proc.exited` waits until the
caller's own timeout fires, which on a missing `bun`, `powershell`, or
similar burns the full 10 s the DPAPI helper allows.
Listen to both 'exit' and 'error' on the lifecycle Promise so spawn
failures resolve immediately. Also add 'close' as a third resolve
trigger on the pipe drains for the same reason — the stdio streams may
fire 'close' without 'end' or 'error' when the process never started.
Regression test asserts proc.exited resolves (not 'TIMEOUT') when the
binary doesn't exist.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codex review on the prior commit flagged the pull-based Readable.toWeb
approach: when the child writes more than the OS pipe buffer (~16-64 KB
depending on platform) and the consumer awaits proc.exited before
reading stdout, the buffer fills, the child blocks in write(), and exit
never fires. browser-skill-commands.ts hits exactly this pattern when
a spawned skill produces non-trivial output.
Replace toWeb with eager-drain-then-replay: stdout and stderr are read
into in-memory chunk arrays via 'data' events the moment the child
starts, so pipes never back-pressure. proc.exited now resolves only
after both exit and the drain have completed, so consumers reading
stdout AFTER awaiting exit always see the full output. Consumers
reading BEFORE awaiting exit still get the full output too — the
replayed ReadableStream's start() awaits the drain before enqueueing.
Adds a regression test that writes 1 MB to stdout — pre-fix this hangs
forever, post-fix it returns in <500 ms. Removes the now-unused
stream.Readable require.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Bun.spawn polyfill omitted `proc.exited`, so eight call sites in
browse/src/ that `await proc.exited` (DPAPI decryption, isBrowserRunning,
browser-skill-commands, cli, terminal-agent) silently no-op on Windows —
the await resolves to `undefined` immediately, the caller reads stdout
before the child has produced anything, and the operation looks like a
silent failure. Most visible symptom: cookie picker's DPAPI helper
reports `DPAPI decryption failed:` with empty stderr.
Adding `proc.exited` exposes the second-order issue: every consumer that
awaits exited *before* reading stdout hits `Response body disturbed or
locked`, because Node's auto-flowing Readable has already drained by the
time the consumer wraps it. `Readable.toWeb()` (Node 18+) hands the
consumer a buffered Web ReadableStream that behaves like Bun's native
API regardless of read order. Falls back to the raw Node Readable on
Node < 18 so the polyfill stays backward-compatible.
The test file's existing `require('${polyfillPath}')` interpolation
escaped its backslashes on Windows, so the tests had been silently
unrunnable there; a `.replace(/\/g, '/')` on the resolved path fixes
the interpolation and lets the new regressions run on the
windows-free-tests matrix.
Test plan
- bun test browse/test/bun-polyfill.test.ts — 7 pass (3 new + 4 existing)
- bun test browse/test/cookie-import-browser.test.ts — 22 pass
- bun test (full suite) — passes; the unrelated batch.test.ts
beforeEach-timeout flake is the only fail and is present on main.
Related: #764 (Windows cookie import), PR #392 (open WIP for full DPAPI
+ v20 fallback support — this PR is strictly scoped to the polyfill so
it can land independently of that broader effort).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: Windows support — Node.js server fallback for Playwright
Setup hangs on Windows 11 because Bun's child_process can't handle
Playwright's --remote-debugging-pipe (fd 3/4 pipe handles). Fall back
to Node.js on Windows for both the setup verification and server
runtime. macOS/Linux completely unaffected — all Windows code behind
IS_WINDOWS / process.platform === 'win32' guards.
Based on community PR #194 by @sozairali. Fixed sed -i portability
(perl -pi -e) in build-node-server.sh for macOS compatibility.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: cross-platform path handling for Windows compatibility
Replace hardcoded '/tmp' and 'dir + "/"' path checks with
platform-aware constants from new platform.ts module. On macOS/Linux
this evaluates identically ('/tmp', '/'); on Windows it uses
os.tmpdir() and path.sep. Zero behavior change on Unix.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: add tests for Windows polyfill, platform constants, and Node server resolution
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: Windows support in README + CHANGELOG (v0.9.1.1)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: bump version and changelog (v0.9.3.0)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>