Skip to content

fix: bundle server into browse binary, eliminate fallback chain#635

Open
sternryan wants to merge 1 commit intogarrytan:mainfrom
sternryan:fix/browse-bundle-server
Open

fix: bundle server into browse binary, eliminate fallback chain#635
sternryan wants to merge 1 commit intogarrytan:mainfrom
sternryan:fix/browse-bundle-server

Conversation

@sternryan
Copy link
Copy Markdown

Summary

  • The compiled browse binary now bundles server.ts via bun build --compile, eliminating the fragile resolveServerScript() fallback chain that caused bugs in v0.3.2
  • When invoked with --server, the binary runs as the persistent Chromium daemon instead of the CLI -- the CLI spawns itself with --server rather than searching for server.ts on disk
  • Dev mode (bun run browse/src/cli.ts) is unchanged and still uses resolveServerScript() via lazy resolution

Technical approach

The problem: resolveServerScript() tries multiple filesystem paths to find server.ts at runtime (adjacent to cli.ts, relative to execPath, BROWSE_SERVER_SCRIPT env). In compiled binaries where import.meta.dir is inside $bunfs, this chain falls through to the execPath-relative check, which fails when the binary isn't installed in the expected browse/dist/browse directory structure.

The fix:

  1. Server mode gate (top of cli.ts): Check process.argv for --server. When present, import('./server') triggers server.ts's top-level start() call. The CLI's main() is gated on !IS_SERVER_MODE.

  2. Compiled binary detection: IS_COMPILED = import.meta.dir.includes('$bunfs') -- Bun's compiled binaries use a virtual filesystem prefix.

  3. startServer() priority chain:

    • Windows: Node.js launcher (unchanged)
    • Compiled binary: Bun.spawn([process.execPath, '--server'], ...)
    • Dev mode: Bun.spawn(['bun', 'run', getServerScript()], ...)
  4. Build change: Added --external electron to the browse binary build command. Since server.ts is now bundled, Bun follows the import chain through playwright-core which has an unused Electron loader dependency.

  5. Lazy server script resolution: resolveServerScript() is now only called when actually needed (dev mode), not eagerly at module load time.

Test plan

  • bun run build compiles successfully (377 modules bundled into browse binary)
  • bun test test/skill-validation.test.ts test/gen-skill-docs.test.ts -- 601 tests pass
  • bun test browse/test/config.test.ts -- 31 tests pass (includes resolveServerScript unit tests)
  • Manual: verify browse/dist/browse status auto-starts server via --server flag
  • Manual: verify bun run dev status still works via dev mode path
  • Manual: verify BROWSE_SERVER_SCRIPT=/path/to/server.ts browse status still works

…) fallback chain

The compiled browse binary now includes server.ts bundled via bun build --compile.
When invoked with --server, the binary runs in server mode (the persistent Chromium
daemon). The CLI spawns itself with --server instead of trying to locate server.ts
on disk through the fragile resolveServerScript() fallback chain.

Changes:
- Add --server flag gate at top of cli.ts: dynamic import of server.ts
- Add IS_COMPILED detection (import.meta.dir contains $bunfs)
- startServer() spawns process.execPath --server in compiled mode
- Dev mode (bun run) still uses resolveServerScript() via lazy getServerScript()
- Add --external electron to build command (needed since server.ts now pulls in
  playwright-core which has an unused electron loader dependency)
- Legacy process detection includes 'browse' binary name
- main() gated on !IS_SERVER_MODE to prevent CLI execution in server mode

Resolves TODOS.md P2: "Bundle server.ts into compiled binary"
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