Skip to content

feat(cli): use system default browser with real user profile + nodeExec adapter mode#190

Open
bobleer wants to merge 3 commits intoepiral:mainfrom
bobleer:feat/use-system-default-browser
Open

feat(cli): use system default browser with real user profile + nodeExec adapter mode#190
bobleer wants to merge 3 commits intoepiral:mainfrom
bobleer:feat/use-system-default-browser

Conversation

@bobleer
Copy link
Copy Markdown

@bobleer bobleer commented Apr 12, 2026

Summary

This PR adds three improvements to browser control in bb-browser:

1. Use system default browser (with Chromium fallback)

Instead of hardcoding Chrome as the only option, bb-browser now:

  • Detects the system default browser (macOS/Linux/Windows)
  • Uses it if it's Chromium-based (Chrome, Edge, Brave, Arc, Vivaldi, Opera, Chromium)
  • Warns and falls back to searching for known Chromium browsers if the default is not Chromium-based

2. Use real user profile (with history, bookmarks, passwords)

Previously bb-browser launched a blank isolated profile. Now it:

  • Detects the real user-data-dir for the discovered browser
  • If the browser is running without CDP, gracefully restarts it with --remote-debugging-port while keeping the real profile
  • Preserves session tabs on restart (no about:blank override)
  • Uses lstatSync instead of existsSync to correctly detect SingletonLock (which is a dangling symlink on macOS/Linux)

3. Attach to already-running browser via DevToolsActivePort (no restart needed)

When the user enables remote debugging in chrome://inspect/#remote-debugging or edge://inspect/#remote-debugging, the browser writes a DevToolsActivePort file containing the dynamic CDP port. bb-browser now:

  • Scans all known browser user-data directories for DevToolsActivePort files (Edge, Chrome, Brave, Chromium, Arc, Opera, Vivaldi on macOS/Linux/Windows)
  • Connects directly to the running browser without restarting it
  • Falls back to the restart approach only when no DevToolsActivePort is found

This means users who enable remote debugging once never need to have their browser restarted again.

One-time setup: Open edge://inspect/#remote-debugging (or chrome://inspect), enable remote debugging, restart the browser once. After that, bb-browser connects instantly without ever restarting the browser.

4. nodeExec adapter mode to bypass browser CORS

Site adapters that only need HTTP APIs (no DOM interaction) can now set "nodeExec": true in their @meta block. bb-browser will execute them directly in the Node.js process instead of via Runtime.evaluate, bypassing browser CORS restrictions entirely.

Bug fix: tsup.config.ts Node.js built-ins as ESM externals

Node.js built-in modules (fs, path, os, child_process) are now marked as external in tsup config. This ensures they are emitted as ESM static imports (import { readFileSync } from "fs") rather than bundled via __require(), which throws 'Dynamic require of "fs" is not supported' at runtime in ESM context.

Test plan

  • Default browser detection works on macOS (tested with Edge as default)
  • Real user profile loads with history/bookmarks/passwords
  • Session tabs are restored after restart
  • DevToolsActivePort discovery connects without restarting browser (tested: Edge PID unchanged)
  • Falls back to restart when no DevToolsActivePort present
  • nodeExec adapters run in Node.js context with no CORS errors
  • All existing tests pass (pnpm test: 119 daemon + 24 cli tests, 0 failures)

bowen628 added 3 commits April 12, 2026 12:57
- Detect the system default browser on macOS/Linux/Windows via OS APIs
  (LaunchServices on macOS, xdg-settings on Linux, registry on Windows)
- Prefer the detected browser if it is Chromium-based; warn and fall
  back to the existing candidate list if it is not (e.g. Firefox/Safari)
- Launch the browser with the user's real user-data-dir so history,
  bookmarks, passwords and cookies are available to adapters
- If the real browser is already running without CDP, gracefully shut it
  down (SIGTERM all processes sharing the app bundle, wait up to 5 s,
  SIGKILL stragglers) then restart with --remote-debugging-port
- Fix SingletonLock detection: use lstatSync instead of existsSync
  because Chromium's SingletonLock is a dangling symlink whose target
  is a "hostname-pid" string, not a real file path
- Do not pass a URL argument when launching with the real profile so the
  browser restores the previous session (tabs) per the user's startup
  settings; keep about:blank only for the isolated managed profile
- Increase launch timeout from 8 s to 15 s to accommodate real profiles
  with large amounts of data
Some adapters call third-party APIs that do not return
Access-Control-Allow-Origin headers, causing fetch() to fail when
executed inside a browser page via CDP Runtime.evaluate.

Add a nodeExec: boolean field to the @meta block. When true, the
adapter function is executed directly in the Node.js process using
new Function(), bypassing the browser entirely. This eliminates CORS
restrictions and the 30-second CDP command timeout for API-only
adapters that do not require browser DOM or user cookies.

The Node.js execution path supports the same jq/--json output flags as
the browser path, and propagates structured { error, hint, action }
objects the same way.
…estart

When the user enables remote debugging in chrome://inspect or edge://inspect,
the browser writes a DevToolsActivePort file containing the dynamic CDP port.
bb-browser now reads this file to connect directly without restarting the browser.

Changes:
- Add readDevToolsActivePortFile() to parse DevToolsActivePort files
- Add discoverViaDevToolsActivePort() scanning all known browser user-data dirs
  (Edge, Chrome, Brave, Chromium, Arc, Opera, Vivaldi on macOS/Linux/Windows)
- Insert as priority 5 in discoverCdpPort(), before launchManagedBrowser()
- In launchManagedBrowser(), reuse running browser with CDP instead of restarting
- Fix tsup.config.ts: mark Node.js built-ins as external so readFileSync is
  emitted as ESM static import instead of __require() which fails at runtime
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