When Chrome disconnects or CDP connection fails, the daemon now:
- Returns 503 immediately instead of waiting 30 seconds
- Includes CDP target address, failure reason, and remediation hint
- Stores lastError in CdpConnection for diagnostic context
Before: {"error":"CDP connection timeout"} after 30s wait
After: {"error":"Chrome not connected (CDP at host:port)","reason":"...","hint":"..."} immediately
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: auto-launch Chrome when daemon starts (#136, #143, #141)
CLI's ensureDaemon() now discovers/launches Chrome via cdp-discovery
before spawning the daemon, and passes --cdp-host/--cdp-port to it.
Previously the daemon was spawned with no CDP info, failed silently,
and users got "Daemon did not start in time" for every command.
- CLI: call discoverCdpPort() before spawn, pass CDP endpoint to daemon
- CLI: improve error messages with specific remediation steps
- CLI: increase startup timeout from 5s to 10s (Chrome launch time)
- MCP: read managed port file and pass --cdp-port to daemon
- Tests: 8 new daemon-startup tests reproducing and verifying the fix
- Tests: fix daemon-lifecycle tests (unique ports, tsx runner, proper cleanup)
Closes#136, closes#143, relates to #141, #118, #146
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove unused variable in MCP ensureDaemon
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: fix daemon-lifecycle kill-9 assertion for parallel CI
Relax PID equality assertion since parallel test suites share
daemon.json in CI. Assert file existence and valid structure instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Revert "test: fix daemon-lifecycle kill-9 assertion for parallel CI"
This reverts commit ba572d0f2a.
* fix: isolate test suites with BB_BROWSER_HOME to avoid parallel conflicts
Daemon and CLI tests both spawn daemon processes that write to
~/.bb-browser/daemon.json. When turbo runs them in parallel, they
conflict. Fix by:
- Support BB_BROWSER_HOME env var in daemon and daemon-manager
- Each test suite uses its own temp dir via BB_BROWSER_HOME
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use DAEMON_DIR for managed port file path in daemon
The managed port file path was hardcoded to ~/.bb-browser/browser/cdp-port
ignoring BB_BROWSER_HOME. This broke test isolation in CI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace separate PID file (/tmp/bb-browser.pid) and token file
(~/.bb-browser/daemon.token) with a single ~/.bb-browser/daemon.json
containing pid, host, port, and token.
CLI now reads daemon.json to connect, using the actual bound address
instead of hardcoded DAEMON_HOST. PID liveness check via process.kill(0)
detects stale daemon.json from crashed processes and auto-recovers.
Add harness tests for PID strategy and cold-start recovery scenario.
Closes#140
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move buildDomTree.js to packages/shared/. Delete packages/extension/
entirely. Update path references in daemon and CLI. Remove
build:extension script and release-please manifest sync.
The daemon connects directly to Chrome via CDP WebSocket since v0.11.0.
The Extension is no longer needed.
BREAKING CHANGE: Chrome Extension is removed. Users who relied on the
extension-based flow should use the daemon-direct mode instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(cli): support cdpUrl and cdpHost from OpenClaw
- Prioritize cdpUrl field for full CDP endpoint URL
- Fall back to cdpHost + cdpPort if cdpUrl not available
- cdpHost defaults to 127.0.0.1 when not specified
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(cli): increase openclaw timeout to 30s
* perf(cli): add env var and file cache for CDP discovery
---------
Co-authored-by: User <user@example.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Merge daemon + cdp-monitor into a single CDP-direct backend. All CLI
and MCP commands now route through the daemon HTTP API instead of
direct CDP connections or Extension relay.
Key changes:
- Daemon: rewrite to hold persistent CDP WebSocket, handle all 30+
commands via dispatchRequest, per-tab event state with RingBuffer,
short tab IDs (4-char hex), global seq counter, incremental queries
via since/cursor mechanism
- CLI: all commands route through daemon HTTP, --tab accepts string
short IDs, add --since/--method/--status flags for network queries,
fix tab close with --tab flag, fix invalid tab ID silent fallback
- MCP: tab parameter z.number() → z.string(), add browser_console
and browser_errors tools, add since/method/status/limit params to
browser_network, remove Extension dependency hints
- Shared: export additional types for daemon consumption
Bug fixes from harness testing:
- Invalid tab ID now errors instead of silent fallback
- tab_new works with zero existing tabs
- console.warn() correctly captured as type "warn"
- --tab flag works with tab close command
Closes#131
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
replMode: true caused Chrome to treat Promise values as plain objects,
bypassing awaitPromise: true. This made all async site adapters
(twitter/reply, twitter/search, etc.) return empty {} instead of
actual results.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Chrome Dev installs to %LOCALAPPDATA% on Windows, not Program Files.
Without these paths bb-browser falls through to Edge even when Chrome
Dev is installed.
Fixes feedback from @NormanMises_
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- #82: extract EXEC_TIMEOUT_BUFFER_MS constant for magic number 5000
- #91: remove failed tabs from sessionOpenedTabs to prevent stale entries
- #25: update platform/command counts from 35/97 to 36/103
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add `background: true` to both `Target.createTarget` CDP calls so that
`bb-browser open --tab` and `bb-browser tab new` no longer activate the
Chrome window. This prevents disrupting the user's workflow when agents
run browser automation in the background.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Monitoring commands (network, console, errors, trace) are broken in
direct CDP mode because each CLI invocation is a new short-lived
process that cannot accumulate events over time.
This introduces a long-running background monitor process that
maintains a persistent CDP connection and collects events:
- cdp-monitor-state.ts: MonitorState class extracted from cdp-client.ts
event handling logic (Network.*, Runtime.*, trace)
- cdp-monitor.ts: standalone Node.js process that connects to Chrome
via CDP, attaches to all page targets, and serves an HTTP API on
127.0.0.1 with bearer-token auth
- monitor-manager.ts: CLI-side lifecycle management (spawn, health
check, shutdown, command forwarding)
- client.ts: routes monitor actions (network/console/errors/trace)
through the monitor with graceful fallback to direct CDP
- tsup.config.ts: adds cdp-monitor as a build entry point
The monitor auto-discovers new tabs, writes PID/port/token files to
~/.bb-browser/, and auto-exits after 30 minutes of inactivity.
cdp-client.ts is intentionally left untouched to avoid regressions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add DOM.getDocument before DOM.performSearch in xpath fallback (fixes cross-process click/fill)
- Persist refs to /tmp/bb-browser-refs-<targetId>.json for cross-process usage
- Fix fill command: use backendNodeId for DOM.focus, add insertTextIntoNode helper
- Graceful snapshot fallback for complex pages (google.com)
All 13 core commands tested and passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Unref WebSocket so it doesn't keep the event loop alive
- Call process.exit(0) after main() resolves
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Major architecture change: remove dependency on Chrome extension and daemon.
bb-browser now manages its own Chrome instance with --remote-debugging-port
and connects directly via CDP WebSocket.
New files:
- cdp-client.ts: CDP WebSocket client, implements all actions directly
- cdp-discovery.ts: auto-discover CDP port (OpenClaw → managed Chrome → auto-launch)
- history-sqlite.ts: read browser history from SQLite (Chrome/Edge/Brave/Arc)
Key changes:
- Auto-launch managed Chrome at ~/.bb-browser/browser/ on port 19825
- User data persists (logins saved across sessions)
- SQLite history replaces chrome.history extension API
- site recommend reads from main Chrome's history (not managed instance)
- Flat CDP protocol support (Chrome 146+)
- --port flag for explicit CDP port override
- All actions implemented: eval, click, snapshot, network, console, frame, dialog, trace
Zero config setup: npm install -g bb-browser → just works
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Bump version to 0.7.0
- Fix VERSION constant in index.ts (was stuck at 0.3.0)
- On `site update`, check npm registry for newer version and show upgrade hint
- Only prompt when npm version is higher than current
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- `bb-browser star` — stars epiral/bb-browser and epiral/bb-sites via gh CLI
- Show hint after `site update` output to guide agents and users
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Run site adapters directly through OpenClaw's built-in Chrome browser,
without needing bb-browser's Chrome extension or daemon.
bb-browser site v2ex/hot --openclaw
bb-browser site zhihu/hot 3 --openclaw --jq '.items[].title'
The bridge (openclaw-bridge.ts, ~40 lines) uses `npx openclaw browser`
commands: tabs/open/evaluate. Adapter JS is passed directly via
execFileSync to avoid shell escaping issues.
Existing daemon-based flow is unchanged when --openclaw is not set.
Closes#28
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ensureDaemonRunning() previously returned as soon as the daemon HTTP
server was ready, but the Chrome extension might not have connected
via SSE yet. This caused intermittent "extension not connected" (503)
or "Failed to fetch" errors on the first command.
Now polls /status for extensionConnected (up to 10s) after daemon
starts, ensuring the full CLI → daemon → extension pipeline is ready
before sending any command.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Spawn a detached `git pull --ff-only` in the background after each
site command. Non-blocking, no output, keeps community adapters fresh
without user intervention.
Closes#20
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>