Browser Debugger CLI (bdg)

repository·main·Indexed 40 days ago

https://github.com/szymdzum/browser-debugger-cli

A command-line tool providing raw Chrome DevTools Protocol (CDP) access directly in the terminal. Designed for developers and AI agents, it offers direct, composable browser control via Unix pipes and JSON output without heavy frameworks. Version 0.7.2 includes features for CDP method discovery, high-level DOM helpers, and a 3-process architecture (CLI, Daemon, and Worker) to manage isolated browser sessions.

Tokens
87.2K
Snippets
275
Records
379
Agent score
52%

What's inside Browser Debugger CLI

  1. Core capabilities of bdg (v0.6.10)

    main

    As of version 0.6.10, bdg provides the following core capabilities for browser automation and debugging:

    • CDP Access: 100% coverage of the Chrome DevTools Protocol (53 domains, 300+ methods) with type-safe wrappers.
    • Daemon Architecture: Uses Unix sockets for persistent CDP connections, enabling fast CLI execution.
    • Telemetry: Collects network requests, console messages, DOM snapshots, and the accessibility tree.
    • Form Automation: Compatible with React, Vue, and Angular for filling, clicking, and key presses.
    • Agent-Friendly: Provides semantic exit codes, JSON output, and token-efficient formats.
    • Network Inspection: Includes DevTools-compatible filtering (10 types, 8 presets) and full HAR 1.2 export with WebSocket capture.
    • Console & Screenshots: Supports rich object expansion in console logs, element-specific screenshots via --selector or --index, and continuous capture via --follow mode.
    • Stale Cache Recovery: Automatically refreshes the DOM cache after navigation to ensure commands succeed without manual validation.
  2. Design principles for agent-friendly CLI tools

    main

    To make a CLI tool effective for AI agents, design should focus on minimizing token usage, ensuring deterministic behavior, and providing structured data. Key principles include:

    • Context without verbosity: Avoid chatty narration. Provide structured context (like JSON) instead of long prose explanations.
    • Machine-friendly escape hatches: Provide flags like --json for structured data and --no-interactive to prevent blocking on user input.
    • Output as API contracts: Treat CLI output as a stable, versioned schema that agents can rely on.
    • Semantic Exit Codes: Use specific exit code ranges to communicate error types (e.g., user errors vs. software errors) so agents can decide on recovery steps.
    • Composability: Follow the Unix philosophy—commands should do one thing well, support piping, and accept stdin where appropriate.
  3. Requirements for integrating chrome-inspector

    main

    The chrome-inspector library is not tied to specific frameworks like Puppeteer or Playwright. To use it, you must provide a CDP client that implements the following interface:

    • send(method: string, params?: any): Promise<any>
    • on(event: string, callback: Function): void
    • off(event: string, callback: Function): void
    // Required CDP client interface
    interface CDPClient {
      send(method: string, params?: any): Promise<any>;
      on(event: string, callback: Function): void;
      off(event: string, callback: Function): void;
    }
  4. How typo detection works via Levenshtein distance

    main

    The browser-debugger-cli (bdg) uses the Levenshtein distance algorithm to provide typo detection, making the CLI more forgiving for both humans and AI agents.

    Key Concepts:

    • Edit Distance (Levenshtein): Measures the minimum number of single-character changes (insertions, deletions, or substitutions) required to transform one string into another.
    • Distance Threshold: The tool uses a threshold (typically $\le 3$) to balance providing helpful suggestions against introducing noise. If a typo is within this threshold, the CLI suggests the correct command or method name.
    • Implementation Detail: The algorithm is implemented using dynamic programming to efficiently solve the edit distance problem.

    This approach is chosen over Damerau-Levenshtein (which includes transpositions), Soundex (phonetic matching), or general fuzzy matching (like fzf) because standard Levenshtein is sufficient for programmatic method names and offers a better balance of simplicity and utility for CDP (Chrome DevTools Protocol) interactions.

  5. How element staleness detection works

    main

    To prevent errors when nodeIds become invalid after page navigation, bdg implements an automatic cache refresh mechanism. When a command is issued, the DomElementResolver detects if a navigationId mismatch has occurred. If so, it transparently re-queries the DOM to refresh the cache before executing the command.

    This allows commands to 'just work' even after navigating to a different page.

    Exit Codes:

    • 87 (STALE_CACHE): Returned if the auto-refresh mechanism fails to recover the stale cache.
    # Commands work transparently after navigation
    bdg dom query "button"
    # ... navigate to different page ...
    bdg dom click --index 0  # Auto-refreshes cache and succeeds
  6. Trace the Bidirectional IPC message flow

    main

    To diagnose where a request is failing, trace the message lifecycle through these five stages using the log patterns provided:

    1. CLI to Daemon: Verify the socket connection and request transmission.
    2. Daemon to Worker: Verify the daemon received the request and forwarded it to the worker via stdin.
    3. Worker Processing: Verify the worker received the IPC message and is executing CDP (Chrome DevTools Protocol) commands.
    4. Worker to Daemon: Verify the worker sent a response via stdout and the daemon parsed it.
    5. Daemon to CLI: Verify the daemon forwarded the response back to the client via the socket.
    # 1. CLI to Daemon
    [client] Connected to daemon for foo request
    [client] foo request sent
    
    # 2. Daemon to Worker
    [daemon] Foo request received (sessionId: uuid)
    [daemon] Forwarded foo_request to worker (requestId: foo_123_abc)
    
    # 3. Worker Processing
    [worker] Received IPC message: foo_request
    [worker] Handling foo_request (param1: test)
    [worker] Sent foo_response
    
    # 4. Worker to Daemon
    [daemon] Received worker response: foo_response (requestId: foo_123_abc)
    [daemon] Forwarded foo_response to client
    
    # 5. Daemon to CLI
    [client] foo response received
  7. Compare CLI vs MCP for agent integration

    main

    When deciding between a CLI-first approach and the Model Context Protocol (MCP) for agent tools, consider these trade-offs:

    CLI Advantages

    • Context Efficiency: Command structures act as the schema, reducing protocol overhead and token usage.
    • Debuggability: Errors are direct and visible in the terminal without protocol wrapping.
    • Composability: Naturally integrates with Unix tools like jq, grep, and sort via pipelines.
    • Model Knowledge: LLMs have extensive training on bash/zsh patterns.

    MCP Advantages

    • Dynamic Discovery: Agents discover capabilities at runtime via schema negotiation.
    • Standardization: Provides a single protocol for integration across different ecosystems.
    • Complex Interactions: Better suited for stateful, multi-turn, or bidirectional communication.
  8. Programmatic usage with BdgClient (SDK Concept)

    main

    While currently in development, the architecture supports a Node.js SDK (BdgClient) for programmatic browser debugging and automation.

    import { BdgClient } from 'bdg';
    
    const client = await BdgClient.connect('localhost:3000');
    await client.dom.fill('input[name="email"]', 'test@example.com');
    await client.dom.click('button[type="submit"]');
    const har = await client.network.exportHar();
    await client.stop();
  9. How DOM Mirroring and Element Handles work

    main

    The bdg project uses a DOM Mirroring concept to improve performance and stability:

    1. DOM Mirroring: A JSDOM mirror of the target page is maintained in a worker process. This allows for near-instant selector queries and reduces 'chatter' (network/protocol overhead) with the Chrome DevTools Protocol (CDP). The mirror is kept in sync via DOM mutation events and refreshed on documentUpdated.
    2. Tracked Element Handles: Instead of using strings (selectors) for every action, bdg provides handles containing a nodeId and metadata.
    3. Staleness Detection: Handles include a timestamp and tracking mechanism. If the document changes or the element is removed, the handle is marked as stale, allowing the CLI to fail fast with clear error messages rather than performing incorrect operations.
    4. Fallback: If the mirror becomes out-of-sync, the system can fall back to live CDP queries to ensure correctness.
  10. Understand bdg Session Files and Storage

    main

    The bdg CLI stores session-related files in ~/.bdg/. Understanding these files is important for managing the daemon and inspecting session state:

    • daemon.pid: The process ID of the running daemon.
    • daemon.sock: The Unix socket used for Inter-Process Communication (IPC).
    • session.meta.json: Contains session metadata such as the Chrome PID, CDP port, and target information.
    • session.json: The final output file, which is written only when the session is stopped.
    • chrome-profile/: The directory containing the Chrome user data.

    Key Session Behaviors

    • Single Session Lock: Only one session can run at a time; a lock prevents concurrent sessions.
    • Automatic Cleanup: All session files in ~/.bdg/ are removed when the session stops.
    • Stale Session Detection: If the daemon detects a dead PID, it automatically cleans up stale session files.
    • In-Memory Data: Data is not written to session.json incrementally; it stays in memory until the session is stopped. However, live data can be accessed via IPC queries.
  11. Understand the BDG 3-process architecture

    main

    BDG operates using three distinct processes to manage browser debugging sessions. Understanding this separation is key to knowing how commands are dispatched and how data is collected in the background:

    1. CLI Process: The short-lived process triggered by your user command (e.g., bdg <url>). Its primary job is to check for a running daemon, dispatch the command via IPC, and then exit immediately after the session starts.
    2. Daemon Process: A long-running background process that acts as an IPC server. It listens on a Unix socket and manages the lifecycle of worker processes.
    3. Worker Process: A background process that manages a specific Chrome DevTools Protocol (CDP) session. It launches Chrome, connects to it via WebSockets, and runs collectors (Network, Console, DOM) to accumulate data.

    This architecture allows the CLI to exit while the actual debugging and data collection continue uninterrupted in the background.

    ┌─────────────────────────────────────────────────────────────────┐
    │                         CLI Process                             │
    │  (node dist/index.js localhost:3000)                           │
    │                                                                 │
    │  index.ts → start.ts → daemonSessionController.ts              │
    │                           │                                     │
    │                           │ Unix Socket                         │
    │                           │ ~/.bdg/daemon.sock                  │
    │                           ▼                                     │
    │  ┌───────────────────────────────────────────────────────────┐ │
    │  │              Daemon Process (background)                  │ │
    │  │         (node dist/daemon.js, detached)                   │ │
    │  │                                                           │ │
    │  │  daemon.ts → ipcServer.ts → startSession.ts              │ │
    │  │                                  │                        │ │
    │  │                                  │ spawn worker           │ │
    │  │                                  ▼                        │ │
    │  │  ┌────────────────────────────────────────────────────┐  │ │
    │  │  │         Worker Process (background)               │  │ │
    │  │  │   (node dist/daemon/worker.js, detached)          │  │ │
    │  │  │                                                    │  │ │
    │  │  │  worker.ts → launcher.ts → Chrome Process         │  │ │
    │  │  │           → cdp.ts (WebSocket)                    │  │ │
    │  │  │           → collectors/*.ts (Network/Console/DOM) │  │ │
    │  │  │                                                    │  │ │
    │  │  └────────────────────────────────────────────────────┘  │ │
    │  │                                                           │ │
    │  └───────────────────────────────────────────────────────────┘ │
    │                                                                 │
    │  CLI exits after starting session (exit code 0)                │
    └─────────────────────────────────────────────────────────────────┘
  12. Testing Philosophy: Test the Contract, Not the Implementation

    main

    The project follows a 'Black Box' testing philosophy. The goal is to create robust tests that catch bugs while enabling refactoring.

    Core Concept:

    • Contract: The public API and expected behavior (Inputs $\rightarrow$ Outputs).
    • Implementation: The internal logic and how the code works.

    The Rule: Test what the module does, not how it does it. A good test should pass even if you completely rewrite the internal logic, provided the external behavior remains unchanged.