-
Notifications
You must be signed in to change notification settings - Fork 8
Description
Summary
Add a --chrome-port option to automatically discover and connect to an existing Chrome instance without requiring manual WebSocket URL retrieval.
Current Behavior
Users must manually retrieve the WebSocket URL from Chrome's debugging endpoint:
# Step 1: Get WebSocket URL
WS_URL=$(curl -s http://localhost:9222/json | jq -r '.[0].webSocketDebuggerUrl')
# Step 2: Connect bdg
bdg example.com --chrome-ws-url "$WS_URL"Proposed Enhancement
Add --chrome-port option for single-step connection:
bdg example.com --chrome-port 9222This would:
- Query
http://localhost:9222/json/listfor available targets - Select appropriate page target (see selection logic below)
- Extract
webSocketDebuggerUrl - Connect to the target (same flow as
--chrome-ws-url)
Implementation Details
1. CLI Option
File: src/commands/start.ts
.addOption(
new Option('--chrome-port <port>', 'Auto-discover and connect to existing Chrome on port')
.argParser(parseInt)
.conflicts(['chromeWsUrl']) // Mutually exclusive with --chrome-ws-url
)2. Configuration
File: src/daemon/worker/types.ts
export interface WorkerConfig {
// ... existing fields
chromeWsUrl?: string;
chromePort?: number; // NEW
}3. Chrome Connection Logic
File: src/daemon/lifecycle/chromeConnection.ts
export async function setupChromeConnection(
config: WorkerConfig,
telemetryStore: TelemetryStore,
log: Logger
): Promise<LaunchedChrome | null> {
// NEW: Auto-discovery flow
if (config.chromePort) {
return setupChromeByPort(config, telemetryStore, log);
}
// Existing: Direct WebSocket URL
if (config.chromeWsUrl) {
return setupExternalChrome(config, telemetryStore);
}
// Existing: Launch Chrome
return setupLaunchedChrome(config, telemetryStore, log);
}4. New Function: setupChromeByPort
async function setupChromeByPort(
config: WorkerConfig,
telemetryStore: TelemetryStore,
log: Logger
): Promise<LaunchedChrome | null> {
const port = config.chromePort!;
// Fetch available targets
const targets = await fetchCDPTargets(port);
// Select target (see selection logic below)
const target = selectTarget(targets, config.targetUrl);
if (!target) {
throw new CommandError(
`No suitable Chrome target found on port ${port}`,
{
suggestion: 'Ensure Chrome is running with --remote-debugging-port and has a page open',
details: `Found ${targets.length} target(s) but none matched criteria`
},
EXIT_CODES.RESOURCE_NOT_FOUND
);
}
log.info(`Connecting to existing Chrome target: ${target.title}`);
// Use existing external Chrome setup with discovered WebSocket URL
return setupExternalChrome(
{ ...config, chromeWsUrl: target.webSocketDebuggerUrl },
telemetryStore
);
}5. Target Selection Logic
Strategy: Prefer exact URL match, fallback to first page
function selectTarget(
targets: CDPTarget[],
targetUrl?: string
): CDPTarget | undefined {
// Filter to page targets only (exclude service workers, extensions, etc.)
const pages = targets.filter(t => t.type === 'page');
if (pages.length === 0) {
return undefined;
}
// If targetUrl specified, try to match
if (targetUrl) {
const normalizedTarget = normalizeUrl(targetUrl);
const match = pages.find(page =>
page.url.includes(normalizedTarget) ||
normalizedTarget.includes(page.url)
);
if (match) return match;
}
// Fallback: Return first page target
return pages[0];
}User Workflows
Workflow 1: Connect to First Available Tab
# Chrome already running with debugging on port 9222
bdg example.com --chrome-port 9222Workflow 2: Connect to Specific Tab by URL
# If multiple tabs open, bdg will prefer tab matching the target URL
bdg github.com --chrome-port 9222 # Connects to GitHub tab if openWorkflow 3: Chrome in Docker
# Launch Chrome container
docker run -d -p 9222:9222 browserless/chrome \
--remote-debugging-port=9222 \
--remote-debugging-address=0.0.0.0
# Connect bdg with auto-discovery
bdg example.com --chrome-port 9222Error Handling
No Targets Available
Error: No suitable Chrome target found on port 9222
Suggestion: Ensure Chrome is running with --remote-debugging-port and has a page open
Details: Found 0 target(s) but none matched criteria
Exit Code: 83 (RESOURCE_NOT_FOUND)
Connection Failed
Error: Failed to connect to Chrome on port 9222
Suggestion: Check if Chrome is running and port is accessible
Caused by: ECONNREFUSED
Exit Code: 101 (CDP_CONNECTION_FAILURE)
Multiple Matches (Future Enhancement)
If multiple tabs match the target URL, could add --interactive mode to let user select.
Testing Strategy
Unit Tests
- Target selection logic with various scenarios
- URL matching behavior
- Error cases (no targets, connection failure)
Integration Tests
- Connect to Chrome launched separately
- Navigate and collect telemetry
- Verify session cleanup doesn't kill external Chrome
Manual Testing
# Terminal 1: Launch Chrome with debugging
google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome
# Terminal 2: Test bdg connection
bdg localhost:3000 --chrome-port 9222
bdg peek
bdg stopBenefits
- Single-step connection - No manual URL retrieval
- Simpler UX - Port number more intuitive than WebSocket URL
- Backward compatible -
--chrome-ws-urlstill works for advanced use cases - Scriptable - Easier to automate in CI/CD pipelines
Drawbacks
- Less explicit - Users don't see which tab was selected
- Ambiguity - Multiple tabs require selection heuristics
- Added complexity - More code paths in connection logic
Alternatives Considered
1. Keep Only --chrome-ws-url
Pros: Simple, explicit, already works
Cons: Requires manual URL discovery (two-step process)
2. Add bdg discover Command First
Pros: Helps users find WebSocket URLs without changing connection flow
Cons: Still requires two steps
3. Support Both --chrome-port and bdg discover
Pros: Covers both convenience and explicit control
Cons: More surface area to maintain
Recommendation
Implement --chrome-port as described above. It provides the best balance of convenience and control while maintaining backward compatibility.
Related
- Existing implementation:
--chrome-ws-url(src/daemon/lifecycle/chromeConnection.ts:27-70) - Target discovery:
fetchCDPTargets()already exists in src/utils/http.ts - Documentation: Update docs/CLI_REFERENCE.md and docs/DOCKER.md with new option
Acceptance Criteria
-
--chrome-portoption added to start command - Auto-discovery connects to appropriate target
- Error messages guide users when connection fails
-
--chrome-portand--chrome-ws-urlare mutually exclusive - Session cleanup doesn't kill external Chrome
- Documentation updated (CLI_REFERENCE.md, README.md, CLAUDE.md)
- Tests added for target selection logic
- Integration test with externally launched Chrome