- cursor returns since threshold instead of 0 on empty results,
preventing infinite re-fetch in incremental polling loops
- Guard shutdown against double-call (SIGINT + /shutdown race)
- Fix timer leak in discoverCdpPort when fetch fails
Co-Authored-By: Claude Opus 4.6 (1M context) <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>
* fix: auto-reconnect after Hub restart
Two bugs prevented reconnection when pinixd restarts:
1. reconnectTimer was unref'd via maybeUnref(), so it didn't keep the
event loop alive — the setTimeout callback never fired
2. gRPC transport was reused across reconnects, causing "protocol error:
missing status" loops from stale HTTP/2 connection state
Fix: remove maybeUnref on reconnect timer, create fresh transport on
each reconnect attempt, remove unused runPromise guard.
Closes#103
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: auto-launch Chrome when CDP not available in bb-browserd
bb-browserd now automatically starts a managed Chrome instance if no
CDP connection is found, instead of failing with "Chrome not reachable".
Also adds clip.json for Pinix Registry publishing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two bugs prevented reconnection when pinixd restarts:
1. reconnectTimer was unref'd via maybeUnref(), so it didn't keep the
event loop alive — the setTimeout callback never fired
2. gRPC transport was reused across reconnects, causing "protocol error:
missing status" loops from stale HTTP/2 connection state
Fix: remove maybeUnref on reconnect timer, create fresh transport on
each reconnect attempt, remove unused runPromise guard.
Closes#103
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Part of manifest file removal across Pinix ecosystem (epiral/pinix#47).
Clip identity comes from package.json; commands/domain/etc from SDK code at runtime.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes:
- fix: remove replMode from CDP evaluate to fix async/Promise results
- fix: open new tabs in background (background: true)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Pattern 1: Structural DOM extraction using semantic HTML elements
instead of CSS classes (Google search example)
- Pattern 2: Dynamic webpack module discovery by source code signatures
instead of hardcoded module IDs (Twitter/X example)
- Pattern 3: Vue/React internal state access
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>
GITHUB_TOKEN-created releases don't trigger other workflows (GitHub
Actions limitation to prevent loops). Changed publish.yml to use
workflow_call (invoked by release-please) + workflow_dispatch (manual
retry from Actions tab).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously all publish steps lived in release-please.yml gated on
release_created. If the release-please run failed (e.g. permissions)
but the release was created manually, npm publish could never be
retried — subsequent runs saw the release already existed and skipped.
Now release-please.yml only manages PRs/releases, and a new
publish.yml triggers on release:published to handle build, extension
upload, and npm publish independently. Publish failures can be re-run
without needing release-please to fire again.
Closes#94
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>
Replace WebSocket /ws/provider with Connect-RPC ProviderStream for
communicating with pinixd Hub. Same functionality, unified protocol.
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>