Skip to content

feat: native Windows support for browse tool#191

Open
fqueiro wants to merge 3 commits intogarrytan:mainfrom
fqueiro:fix/windows-support
Open

feat: native Windows support for browse tool#191
fqueiro wants to merge 3 commits intogarrytan:mainfrom
fqueiro:fix/windows-support

Conversation

@fqueiro
Copy link

@fqueiro fqueiro commented Mar 18, 2026

Summary

  • Add native Windows support for the gstack browse tool (headless Chromium server + CLI)
  • On Windows, Bun's subprocess/pipe handling breaks Playwright's CDP connection, so the browse server runs under Node+tsx via a new server-node.mjs entry point
  • Cross-platform platform.ts module replaces all hardcoded /tmp paths, startsWith('/') checks, and dir + '/' path comparisons with OS-aware equivalents
  • Cookie import correctly gated to macOS-only (requires Keychain access)

Key changes

  • browse/src/platform.ts — new shared module: IS_WINDOWS, IS_MACOS, TEMP_DIR, getSafeDirectories(), isPathWithin()
  • browse/src/server-node.mjs — Node-compatible server entry point for Windows with Bun API shim (Bun.which, Bun.sleep)
  • browse/src/server-shared.ts — extracted generateHelpText(), wrapError(), dispatchCommand() shared between Bun and Node servers
  • browse/src/cli.ts — Windows: resolve .cmd shim to real bun.exe, use child_process.spawn with detached:true, use node --import tsx for server
  • browse/src/config.ts — replace Bun.spawnSync with Node spawnSync for git commands
  • browse/src/cookie-import-browser.ts — dynamic bun:sqlite import, macOS-only guards, async listDomains()
  • browse/src/find-browse.ts — look for browse.exe on Windows
  • browse/src/meta-commands.ts, read-commands.ts, snapshot.ts, write-commands.ts — use platform.ts for safe paths
  • package.json — add tsx devDependency for Windows Node server

Test plan

  • 25 new tests: platform.test.ts (12) + server-shared.test.ts (13) — all pass on Windows, platform-agnostic
  • Existing cookie-import-browser.test.ts updated for async listDomains() — passes
  • find-browse.test.ts — passes (finds browse.exe)
  • Manual: verify $B goto <url> works end-to-end on Windows — ✅ tested: server starts, navigates, screenshots, snapshots with refs all work
  • Manual: verify browse tool still works on macOS (no regressions) — needs maintainer verification (I don't have access to a Mac)

🤖 Generated with Claude Code

fqueiro and others added 3 commits March 18, 2026 19:22
Bun's subprocess pipe handling breaks Playwright's CDP connection on
Windows, causing chromium.launch() to hang indefinitely. On Windows,
the server now runs under Node (via tsx) instead of Bun, with a
dedicated server-node.mjs entry point using Node's http module.

Changes by category:

Cross-platform path handling:
- New platform.ts with TEMP_DIR, getSafeDirectories(), isPathWithin()
- Replace hardcoded /tmp with os.tmpdir() across all modules
- Fix path validation to use path.sep instead of hardcoded /
- Fix dev mode detection to use path.isAbsolute() not startsWith('/')

Windows process management:
- cli.ts: Use child_process.spawn with detached:true on Windows
- cli.ts: killServer() uses process.kill(pid) on Windows (no SIGTERM)
- cli.ts: Skip legacy /tmp cleanup on Windows
- cli.ts: Resolve bun.exe through npm .cmd shims
- server.ts: Add process.on('exit') handler for state file cleanup

Cross-runtime compatibility:
- config.ts: Bun.spawnSync → child_process.spawnSync
- write-commands.ts: Bun.spawn → child_process.spawn for URL open
- cookie-import-browser.ts: Dynamic import for bun:sqlite
- cookie-import-browser.ts: Platform guard (macOS-only) for browser
  cookie import
- find-browse.ts: .exe suffix for binary discovery on Windows

New files:
- server-node.mjs: Node-compatible HTTP server for Windows
- platform.ts: Shared cross-platform helpers
- launch-chromium.mjs: Node-based Chromium launcher helper

Adds tsx as devDependency for Node TypeScript support on Windows.

Fixes garrytan#69

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Delete dead launch-chromium.mjs (unused debugging artifact)
- Fix broken tests: listDomains is now async, use rejects.toThrow
- Fix cookie-picker crash in server-node.mjs (Node IncomingMessage lacks .json())
- Fix silent fallback: resolveNodeServerScript throws on Windows if missing
- Fix command injection in Bun.which shim: validate input before shell interpolation
- Fix stale comment: --experimental-strip-types → --import tsx
- Inline await_import_child_process, remove extra blank lines

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create server-shared.ts with generateHelpText, wrapError, and
  dispatchCommand — shared between server.ts (Bun) and server-node.mjs
  (Node) to eliminate 156 lines of duplication
- Fix uncaught JSON.parse crash in server-node.mjs that left HTTP
  responses hanging on malformed input
- Add top-level try/catch in Node server request handler to prevent
  unhandled promise rejections
- Add platform.test.ts (12 tests) and server-shared.test.ts (13 tests)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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