browser-devtools-mcp 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +202 -28
  2. package/dist/cli/index.d.ts +1 -0
  3. package/dist/cli/runner.js +158 -0
  4. package/dist/core-B3VLZZCP.js +1 -0
  5. package/dist/core-IV5QBQ2N.js +13 -0
  6. package/dist/core-NLBNZBEB.js +1124 -0
  7. package/dist/daemon-server.js +1 -1
  8. package/dist/index.js +2 -209
  9. package/dist/platform/browser/cli/runner.js +2 -0
  10. package/dist/platform/browser/index.d.ts +2 -0
  11. package/dist/platform/browser/tools/a11y/index.d.ts +2 -0
  12. package/dist/platform/browser/tools/content/index.d.ts +2 -0
  13. package/dist/platform/browser/tools/debug/index.d.ts +2 -0
  14. package/dist/platform/browser/tools/figma/index.d.ts +2 -0
  15. package/dist/platform/browser/tools/index.d.ts +5 -0
  16. package/dist/platform/browser/tools/interaction/index.d.ts +2 -0
  17. package/dist/platform/browser/tools/navigation/index.d.ts +2 -0
  18. package/dist/platform/browser/tools/o11y/index.d.ts +2 -0
  19. package/dist/platform/browser/tools/react/index.d.ts +2 -0
  20. package/dist/platform/browser/tools/run/index.d.ts +2 -0
  21. package/dist/platform/browser/tools/stub/index.d.ts +2 -0
  22. package/dist/platform/browser/tools/sync/index.d.ts +2 -0
  23. package/dist/platform/index.d.ts +3 -0
  24. package/dist/platform/node/cli/runner.js +2 -0
  25. package/dist/platform/node/entry.js +2 -0
  26. package/dist/platform/node/index.d.ts +11 -0
  27. package/dist/platform/node/tools/debug/index.d.ts +6 -0
  28. package/dist/platform/node/tools/index.d.ts +10 -0
  29. package/dist/platform/node/tools/run/index.d.ts +2 -0
  30. package/dist/platform/types.d.ts +15 -0
  31. package/dist/tools/index.d.ts +1 -4
  32. package/dist/tools/types.d.ts +8 -3
  33. package/package.json +6 -2
  34. package/dist/cli.js +0 -179
  35. package/dist/core.js +0 -764
  36. package/dist/tools/a11y/index.d.ts +0 -2
  37. package/dist/tools/content/index.d.ts +0 -2
  38. package/dist/tools/debug/index.d.ts +0 -2
  39. package/dist/tools/figma/index.d.ts +0 -2
  40. package/dist/tools/interaction/index.d.ts +0 -2
  41. package/dist/tools/navigation/index.d.ts +0 -2
  42. package/dist/tools/o11y/index.d.ts +0 -2
  43. package/dist/tools/react/index.d.ts +0 -2
  44. package/dist/tools/run/index.d.ts +0 -2
  45. package/dist/tools/stub/index.d.ts +0 -2
  46. package/dist/tools/sync/index.d.ts +0 -2
  47. /package/dist/{otel → platform/browser/otel}/otel-initializer.bundle.js +0 -0
  48. /package/dist/{tools → platform/browser/tools}/figma/compare/index.d.ts +0 -0
  49. /package/dist/{tools → platform/browser/tools}/figma/compare/types.d.ts +0 -0
  50. /package/dist/{types.d.ts → platform/browser/types.d.ts} +0 -0
package/README.md CHANGED
@@ -1,24 +1,43 @@
1
1
  <p align="center">
2
- <img src="public/icon.svg" alt="Browser DevTools MCP" width="128" height="128">
2
+ <img src="https://browser-devtools.com/assets/icons/icon.svg" alt="Browser DevTools MCP" width="128" height="128">
3
3
  <br>
4
4
  <strong style="font-size: 2em;">Browser DevTools MCP</strong>
5
5
  </p>
6
6
 
7
7
  <p align="center">
8
- <a href="https://github.com/serkan-ozal/browser-devtools-mcp/actions/workflows/build.yml"><img src="https://github.com/serkan-ozal/browser-devtools-mcp/actions/workflows/build.yml/badge.svg" alt="Build Status"></a>
9
8
  <a href="https://www.npmjs.com/package/browser-devtools-mcp"><img src="https://badge.fury.io/js/browser-devtools-mcp.svg" alt="NPM Version"></a>
10
- <a href="https://github.com/serkan-ozal/browser-devtools-mcp/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Elastic--2.0-blue" alt="License"></a>
9
+ <a href="https://browser-devtools.com"><img src="https://img.shields.io/badge/license-Elastic--2.0-blue" alt="License"></a>
11
10
  </p>
12
11
 
13
12
  <p align="center">
14
- A powerful <a href="https://modelcontextprotocol.io">Model Context Protocol (MCP)</a> server that provides AI coding assistants with comprehensive browser automation and debugging capabilities using Playwright. This server enables both <strong>execution-level debugging</strong> (logs, network requests) and <strong>visual debugging</strong> (screenshots, ARIA snapshots) to help AI assistants understand and interact with web pages effectively.
13
+ A powerful <a href="https://modelcontextprotocol.io">Model Context Protocol (MCP)</a> server that provides AI coding assistants with comprehensive automation and debugging capabilities across multiple platforms. This server enables both <strong>execution-level debugging</strong> (logs, network requests) and <strong>visual debugging</strong> (screenshots, accessibility snapshots) to help AI assistants understand and interact with applications effectively.
15
14
  </p>
16
15
 
17
16
  ## Overview
18
17
 
19
- Browser DevTools MCP exposes a Playwright-powered browser runtime to AI agents, enabling deep, bidirectional debugging and interaction with live web pages. It supports both visual understanding and code-level inspection of browser state, making it ideal for AI-driven exploration, diagnosis, and automation.
18
+ Browser DevTools MCP is a platform-extensible MCP server designed to give AI agents deep inspection and control over application runtimes. The architecture supports multiple platforms through a unified interface, with each platform providing specialized tools for its environment.
20
19
 
21
- ### Key Capabilities
20
+ ### Supported Platforms
21
+
22
+ | Platform | Description | Status |
23
+ |----------|-------------|--------|
24
+ | **Browser** | Playwright-powered browser automation with full DevTools integration | ✅ Available |
25
+ | **Node** | Non-blocking debugging for Node.js backend processes via Inspector Protocol | ✅ Available |
26
+
27
+ The **Browser Platform** exposes a Playwright-powered browser runtime to AI agents, enabling deep, bidirectional debugging and interaction with live web pages. It supports both visual understanding and code-level inspection of browser state, making it ideal for AI-driven exploration, diagnosis, and automation.
28
+
29
+ The **Node Platform** provides non-blocking debugging for Node.js backend processes. It connects to running Node.js processes via the Inspector Protocol (Chrome DevTools Protocol over WebSocket) and offers tracepoints, logpoints, exceptionpoints, watch expressions, and source map support—ideal for debugging APIs, workers, and server-side code.
30
+
31
+ ### Platform Selection
32
+
33
+ Choose the platform by running the appropriate MCP server or CLI:
34
+
35
+ | Use Case | MCP Server | CLI |
36
+ |----------|------------|-----|
37
+ | Browser automation & debugging | `browser-devtools-mcp` | `browser-devtools-cli` |
38
+ | Node.js backend debugging | `node-devtools-mcp` | `node-devtools-cli` |
39
+
40
+ ### Browser Platform Capabilities
22
41
 
23
42
  - **Visual Inspection**: Screenshots, ARIA snapshots, HTML/text extraction, PDF generation
24
43
  - **Design Comparison**: Compare live page UI against Figma designs with similarity scoring
@@ -30,7 +49,16 @@ Browser DevTools MCP exposes a Playwright-powered browser runtime to AI agents,
30
49
  - **Session Management**: Long-lived, session-based debugging with automatic cleanup
31
50
  - **Multiple Transport Modes**: Supports both stdio and HTTP transports
32
51
 
33
- ## Features
52
+ ### Node Platform Capabilities
53
+
54
+ - **Connection**: Connect to Node.js processes by PID, process name, port, WebSocket URL, or Docker container
55
+ - **Non-Blocking Debugging**: Tracepoints, logpoints, exceptionpoints without pausing execution
56
+ - **JavaScript Execution**: Run arbitrary JavaScript in the connected Node process via `run_js-in-node` (CDP Runtime.evaluate)—inspect `process.memoryUsage()`, call `require()` modules, read globals
57
+ - **Source Map Support**: Resolves bundled/minified code to original source locations; `debug_resolve-source-location` translates stack traces and bundle locations to original source
58
+ - **OpenTelemetry Integration**: When the Node process uses `@opentelemetry/api`, tracepoint/logpoint snapshots automatically include `traceContext` (traceId, spanId) for correlating backend traces with browser traces
59
+ - **Docker Support**: Connect to Node.js processes running inside Docker containers (`containerId` / `containerName`)
60
+
61
+ ## Browser Platform Features
34
62
 
35
63
  ### Content Tools
36
64
  - **Screenshots**: Capture full page or specific elements (PNG/JPEG) with image data
@@ -110,6 +138,7 @@ Non-blocking debugging tools that capture snapshots without pausing execution. I
110
138
  - `clear-*-snapshots`: Clear captured snapshots
111
139
 
112
140
  **Additional Tools:**
141
+ - **Resolve Source Location**: Resolve a generated/bundle location (URL + line + column) to original source via source maps—useful for translating minified stack traces
113
142
  - **Watch Expressions**: Add expressions to evaluate at every tracepoint/exceptionpoint hit
114
143
  - **Status**: Get current debugging status (enabled, probe counts, snapshot stats)
115
144
 
@@ -118,6 +147,7 @@ Non-blocking debugging tools that capture snapshots without pausing execution. I
118
147
  - Automatic debugging enablement on first tool use
119
148
  - Configurable limits (max snapshots, call stack depth, async segments)
120
149
  - Sequence numbers for efficient snapshot polling
150
+ - OpenTelemetry trace context in Node snapshots (traceId, spanId when process uses @opentelemetry/api)
121
151
 
122
152
  ## Prerequisites
123
153
 
@@ -149,12 +179,29 @@ This installs the CLI skill that enables AI agents to automate browsers for web
149
179
 
150
180
  ## MCP Client Configuration
151
181
 
152
- ### Claude Desktop
182
+ To use the **Node platform** (Node.js backend debugging), use `node-devtools-mcp` instead of `browser-devtools-mcp`:
183
+
184
+ ```json
185
+ {
186
+ "mcpServers": {
187
+ "node-devtools": {
188
+ "command": "npx",
189
+ "args": ["-y", "-p", "browser-devtools-mcp", "node-devtools-mcp"]
190
+ }
191
+ }
192
+ }
193
+ ```
194
+
195
+ Alternatively, set `PLATFORM=node` when running `browser-devtools-mcp`.
196
+
197
+ <details>
198
+ <summary><strong>Claude Desktop</strong></summary>
153
199
 
154
200
  #### Local Server
155
201
  Add the following configuration into the `claude_desktop_config.json` file.
156
202
  See the [Claude Desktop MCP docs](https://modelcontextprotocol.io/docs/develop/connect-local-servers) for more info.
157
203
 
204
+ **Browser platform (default):**
158
205
  ```json
159
206
  {
160
207
  "mcpServers": {
@@ -166,6 +213,18 @@ See the [Claude Desktop MCP docs](https://modelcontextprotocol.io/docs/develop/c
166
213
  }
167
214
  ```
168
215
 
216
+ **Node platform:**
217
+ ```json
218
+ {
219
+ "mcpServers": {
220
+ "node-devtools": {
221
+ "command": "npx",
222
+ "args": ["-y", "-p", "browser-devtools-mcp", "node-devtools-mcp"]
223
+ }
224
+ }
225
+ }
226
+ ```
227
+
169
228
  #### Remote Server (HTTP Transport)
170
229
  First, start the server with HTTP transport:
171
230
  ```bash
@@ -176,7 +235,10 @@ Then, go to `Settings` > `Connectors` > `Add Custom Connector` in Claude Desktop
176
235
  - Name: `Browser DevTools`
177
236
  - Remote MCP server URL: Point to where your server is hosted (e.g., `http://localhost:3000/mcp` if running locally, or `https://your-server.com/mcp` if hosted remotely)
178
237
 
179
- ### Claude Code
238
+ </details>
239
+
240
+ <details>
241
+ <summary><strong>Claude Code</strong></summary>
180
242
 
181
243
  Run the following command.
182
244
  See [Claude Code MCP docs](https://docs.anthropic.com/en/docs/claude-code/mcp) for more info.
@@ -199,7 +261,10 @@ claude mcp add --transport http browser-devtools <SERVER_URL>
199
261
 
200
262
  Replace `<SERVER_URL>` with your server URL (e.g., `http://localhost:3000/mcp` if running locally, or `https://your-server.com/mcp` if hosted remotely).
201
263
 
202
- ### Cursor
264
+ </details>
265
+
266
+ <details>
267
+ <summary><strong>Cursor</strong></summary>
203
268
 
204
269
  Add the following configuration into the `~/.cursor/mcp.json` file (or `.cursor/mcp.json` in your project folder).
205
270
  See the [Cursor MCP docs](https://docs.cursor.com/context/model-context-protocol) for more info.
@@ -235,7 +300,10 @@ Then add the configuration:
235
300
 
236
301
  Replace `<SERVER_URL>` with your server URL (e.g., `http://localhost:3000/mcp` if running locally, or `https://your-server.com/mcp` if hosted remotely).
237
302
 
238
- ### VS Code
303
+ </details>
304
+
305
+ <details>
306
+ <summary><strong>VS Code</strong></summary>
239
307
 
240
308
  Add the following configuration into the `.vscode/mcp.json` file.
241
309
  See the [VS Code MCP docs](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) for more info.
@@ -277,7 +345,10 @@ Then add the configuration:
277
345
 
278
346
  Replace `<SERVER_URL>` with your server URL (e.g., `http://localhost:3000/mcp` if running locally, or `https://your-server.com/mcp` if hosted remotely).
279
347
 
280
- ### Windsurf
348
+ </details>
349
+
350
+ <details>
351
+ <summary><strong>Windsurf</strong></summary>
281
352
 
282
353
  Add the following configuration into the `~/.codeium/windsurf/mcp_config.json` file.
283
354
  See the [Windsurf MCP docs](https://docs.windsurf.com/windsurf/cascade/mcp) for more info.
@@ -313,7 +384,10 @@ Then add the configuration:
313
384
 
314
385
  Replace `<SERVER_URL>` with your server URL (e.g., `http://localhost:3000/mcp` if running locally, or `https://your-server.com/mcp` if hosted remotely).
315
386
 
316
- ### Copilot Coding Agent
387
+ </details>
388
+
389
+ <details>
390
+ <summary><strong>Copilot Coding Agent</strong></summary>
317
391
 
318
392
  Add the following configuration to the `mcpServers` section of your Copilot Coding Agent configuration through
319
393
  `Repository` > `Settings` > `Copilot` > `Coding agent` > `MCP configuration`.
@@ -352,7 +426,10 @@ Then add the configuration:
352
426
 
353
427
  Replace `<SERVER_URL>` with your server URL (e.g., `http://localhost:3000/mcp` if running locally, or `https://your-server.com/mcp` if hosted remotely).
354
428
 
355
- ### Gemini CLI
429
+ </details>
430
+
431
+ <details>
432
+ <summary><strong>Gemini CLI</strong></summary>
356
433
 
357
434
  Add the following configuration into the `~/.gemini/settings.json` file.
358
435
  See the [Gemini CLI MCP docs](https://google-gemini.github.io/gemini-cli/docs/tools/mcp-server.html) for more info.
@@ -388,7 +465,10 @@ Then add the configuration:
388
465
 
389
466
  Replace `<SERVER_URL>` with your server URL (e.g., `http://localhost:3000/mcp` if running locally, or `https://your-server.com/mcp` if hosted remotely).
390
467
 
391
- ### Smithery
468
+ </details>
469
+
470
+ <details>
471
+ <summary><strong>Smithery</strong></summary>
392
472
 
393
473
  Run the following command.
394
474
  You can find your Smithery API key [here](https://smithery.ai/account/api-keys).
@@ -398,6 +478,8 @@ See the [Smithery CLI docs](https://smithery.ai/docs/concepts/cli) for more info
398
478
  npx -y @smithery/cli install serkan-ozal/browser-devtools-mcp --client <SMITHERY-CLIENT-NAME> --key <SMITHERY-API-KEY>
399
479
  ```
400
480
 
481
+ </details>
482
+
401
483
  ## HTTP Transport
402
484
 
403
485
  To use HTTP transport, start the server with:
@@ -431,9 +513,14 @@ npx -y browser-devtools-mcp --transport=streamable-http --port=3000
431
513
  npx -y @modelcontextprotocol/inspector http://localhost:3000/mcp --transport http
432
514
  ```
433
515
 
434
- ## CLI Tool
516
+ ## CLI Tools
517
+
518
+ Browser DevTools MCP includes standalone CLI tools for both platforms:
519
+
520
+ - **`browser-devtools-cli`**: Browser platform—navigation, screenshots, interaction, a11y, debugging, etc.
521
+ - **`node-devtools-cli`**: Node platform—connect to Node.js processes, tracepoints, logpoints, exceptionpoints
435
522
 
436
- Browser DevTools MCP includes a standalone CLI tool (`browser-devtools-cli`) for direct command-line access to browser automation capabilities. This is particularly useful for:
523
+ This is particularly useful for:
437
524
 
438
525
  - **Scripting and automation**: Use in shell scripts, CI/CD pipelines, or automated workflows
439
526
  - **Session-based testing**: Maintain browser state across multiple commands with session IDs
@@ -441,15 +528,17 @@ Browser DevTools MCP includes a standalone CLI tool (`browser-devtools-cli`) for
441
528
 
442
529
  ### Installation
443
530
 
444
- The CLI is included with the npm package:
531
+ The CLIs are included with the npm package:
445
532
 
446
533
  ```bash
447
534
  # Run directly with npx
448
- npx -y browser-devtools-mcp browser-devtools-cli --help
535
+ npx -y browser-devtools-cli --help
536
+ npx -y node-devtools-cli --help
449
537
 
450
538
  # Or install globally
451
539
  npm install -g browser-devtools-mcp
452
540
  browser-devtools-cli --help
541
+ node-devtools-cli --help
453
542
  ```
454
543
 
455
544
  ### Global Options
@@ -475,9 +564,34 @@ browser-devtools-cli --help
475
564
 
476
565
  **Note:** Browser options are applied when the daemon server starts. If the daemon is already running, stop it first (`daemon stop`) then start with new options.
477
566
 
478
- ### Commands
567
+ ### Node CLI Commands
568
+
569
+ `node-devtools-cli` provides Node.js backend debugging:
570
+
571
+ ```
572
+ node-devtools-cli
573
+ ├── daemon # Manage the daemon server
574
+ ├── session # Manage Node.js debugging sessions
575
+ ├── tools # List and inspect available tools
576
+ ├── config # Show current configuration
577
+ ├── completion # Generate shell completion scripts
578
+ ├── interactive (repl) # Start interactive REPL mode
579
+ ├── update # Check for updates
580
+ ├── run # Script execution commands
581
+ │ └── js-in-node # Run JavaScript in the connected Node process
582
+ └── debug # Debug commands
583
+ ├── connect # Connect to Node.js process (pid, processName, port, containerId, etc.)
584
+ ├── disconnect # Disconnect from current process
585
+ ├── status # Show connection status
586
+ ├── put-tracepoint # Set a tracepoint
587
+ ├── put-logpoint # Set a logpoint
588
+ ├── put-exceptionpoint # Configure exception catching
589
+ └── ... # Watch, snapshots, probes management
590
+ ```
591
+
592
+ ### Browser CLI Commands
479
593
 
480
- The CLI organizes tools into domain-based subcommands:
594
+ `browser-devtools-cli` organizes tools into domain-based subcommands:
481
595
 
482
596
  ```
483
597
  browser-devtools-cli
@@ -998,7 +1112,9 @@ For the full list of available skills and documentation, see the [browser-devtoo
998
1112
 
999
1113
  ## Configuration
1000
1114
 
1001
- The server can be configured using environment variables:
1115
+ The server can be configured using environment variables. Configuration is divided into server-level settings and platform-specific settings.
1116
+
1117
+ ### Server Configuration
1002
1118
 
1003
1119
  | Variable | Description | Default |
1004
1120
  |----------|-------------|---------|
@@ -1006,6 +1122,18 @@ The server can be configured using environment variables:
1006
1122
  | `SESSION_IDLE_SECONDS` | Idle session timeout (seconds) | `300` |
1007
1123
  | `SESSION_IDLE_CHECK_SECONDS` | Interval for checking idle sessions (seconds) | `30` |
1008
1124
  | `SESSION_CLOSE_ON_SOCKET_CLOSE` | Close session when socket closes | `false` |
1125
+
1126
+ ### Node Platform Configuration
1127
+
1128
+ | Variable | Description | Default |
1129
+ |----------|-------------|---------|
1130
+ | `NODE_CONSOLE_MESSAGES_BUFFER_SIZE` | Maximum console messages to buffer from Node.js process | `1000` |
1131
+ | `PLATFORM` | Platform to use: `browser` or `node` | `browser` |
1132
+
1133
+ ### Browser Platform Configuration
1134
+
1135
+ | Variable | Description | Default |
1136
+ |----------|-------------|---------|
1009
1137
  | `CONSOLE_MESSAGES_BUFFER_SIZE` | Maximum console messages to buffer | `1000` |
1010
1138
  | `HTTP_REQUESTS_BUFFER_SIZE` | Maximum HTTP requests to buffer | `1000` |
1011
1139
  | `BROWSER_HEADLESS_ENABLE` | Run browser in headless mode | `true` |
@@ -1024,7 +1152,7 @@ The server can be configured using environment variables:
1024
1152
  | `FIGMA_ACCESS_TOKEN` | Figma API access token for design comparison | (none) |
1025
1153
  | `FIGMA_API_BASE_URL` | Figma API base URL | `https://api.figma.com/v1` |
1026
1154
 
1027
- ## Available Tools
1155
+ ## Browser Platform Tools
1028
1156
 
1029
1157
  ### Content Tools
1030
1158
 
@@ -1322,6 +1450,33 @@ The server can be configured using environment variables:
1322
1450
  - The timeoutMs parameter limits synchronous execution time, but does not automatically time out awaited Promises
1323
1451
  </details>
1324
1452
 
1453
+ <details>
1454
+ <summary><code>run_js-in-node</code> - Runs custom JavaScript INSIDE the connected Node.js process (Node platform only).</summary>
1455
+
1456
+ **Parameters:**
1457
+ - `script` (string, required): JavaScript code to execute in the Node process
1458
+ - `timeoutMs` (number, optional): Max evaluation time in milliseconds (default: 5000, max: 30000)
1459
+
1460
+ **Returns:**
1461
+ - `result` (any): The result of the evaluation. Can be primitives, arrays, or objects. Must be serializable (JSON-compatible).
1462
+
1463
+ **Notes:**
1464
+ - Requires `debug_connect` first—must be connected to a Node.js process
1465
+ - Executes in the NODE PROCESS CONTEXT (real Node.js environment):
1466
+ - Has access to process, require, global, and all loaded modules
1467
+ - Can read/modify process state
1468
+ - Full Node.js APIs (fs, http, etc.)
1469
+ - Execution blocks the Node event loop until the script completes
1470
+ - Long-running scripts will block the process; use short expressions
1471
+ - Return value must be serializable
1472
+
1473
+ **Typical use cases:**
1474
+ - Inspect process state: `process.memoryUsage()`, `process.uptime()`
1475
+ - Call loaded modules: `require('os').loadavg()`
1476
+ - Read globals or cached data
1477
+ - One-off diagnostic commands
1478
+ </details>
1479
+
1325
1480
  ### Observability (O11Y) Tools
1326
1481
 
1327
1482
  <details>
@@ -1694,17 +1849,27 @@ The server can be configured using environment variables:
1694
1849
 
1695
1850
  ## Architecture
1696
1851
 
1852
+ ### Platform Architecture
1853
+
1854
+ Browser DevTools MCP is built on a platform-extensible architecture that allows for supporting multiple runtime environments through a unified MCP interface. Each platform provides:
1855
+
1856
+ - **Platform-specific tools**: Specialized tools optimized for the target environment
1857
+ - **Unified session management**: Consistent session handling across platforms
1858
+ - **Shared infrastructure**: Common transport, configuration, and plugin systems
1859
+
1860
+ The **Browser Platform** is powered by Playwright for comprehensive browser automation and DevTools integration. The **Node Platform** provides non-blocking debugging for Node.js backend processes via the Chrome DevTools Protocol over WebSocket.
1861
+
1697
1862
  ### Session Management
1698
1863
 
1699
- The server uses session-based architecture where each MCP client connection gets its own browser context and page. Sessions are automatically cleaned up when:
1864
+ The server uses session-based architecture where each MCP client connection gets its own isolated runtime context. For the Browser platform, this means each session gets its own browser context and page. Sessions are automatically cleaned up when:
1700
1865
 
1701
1866
  - The client disconnects
1702
1867
  - The session becomes idle (configurable timeout)
1703
1868
  - The session is explicitly closed
1704
1869
 
1705
- ### Browser Support
1870
+ ### Browser Platform Details
1706
1871
 
1707
- The server supports multiple browser engines:
1872
+ The Browser platform supports multiple browser engines:
1708
1873
  - **Chromium** (default)
1709
1874
  - **Firefox**
1710
1875
  - **WebKit**
@@ -1810,9 +1975,18 @@ npm run build
1810
1975
 
1811
1976
  ## Use Cases
1812
1977
 
1813
- ### For AI Coding Assistants
1978
+ ### Node Platform Use Cases
1979
+
1980
+ The Node platform enables AI assistants to:
1981
+
1982
+ 1. **Debug Node.js APIs**: Connect to a running server, set tracepoints at API handlers, capture request/response context
1983
+ 2. **Inspect Backend State**: Use watch expressions and tracepoints to understand variable values, call stacks
1984
+ 3. **Catch Exceptions**: Enable exception breakpoints to capture uncaught errors with full stack traces
1985
+ 4. **Docker Debugging**: Connect to Node.js processes running inside Docker containers
1986
+
1987
+ ### Browser Platform Use Cases
1814
1988
 
1815
- This server enables AI assistants to:
1989
+ The Browser platform enables AI assistants to:
1816
1990
 
1817
1991
  1. **Debug Web Applications**: Capture screenshots, inspect DOM, check console errors
1818
1992
  2. **Monitor Network Activity**: Track API calls, analyze request/response patterns
@@ -0,0 +1 @@
1
+ export * from './provider';
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env node
2
+ import{a as me}from"../core-NLBNZBEB.js";import{A as se,B as re,C as ie,D as ae,E as le,F as B,G as ce,H as de,a as u,p as Y,q as z,r as Q,u as X,v as ee,x as oe,y as ne,z as te}from"../core-IV5QBQ2N.js";import{Command as pe,Option as E}from"commander";import{ZodFirstPartyTypeKind as _}from"zod";function ve(o){let i=o,l=!1,m;for(;;){let b=i._def.typeName;if(b===_.ZodOptional)l=!0,i=i._def.innerType;else if(b===_.ZodDefault)l=!0,m=i._def.defaultValue(),i=i._def.innerType;else if(b===_.ZodNullable)l=!0,i=i._def.innerType;else break}return{innerType:i,isOptional:l,defaultValue:m}}u(ve,"_unwrapZodType");function we(o){return o._def.description}u(we,"_getDescription");function Oe(o){return o.replace(/[-_]([a-z])/g,(i,l)=>l.toUpperCase())}u(Oe,"_toCamelCase");function Te(o){return o.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}u(Te,"_toKebabCase");function _e(o,i){let{innerType:l,isOptional:m,defaultValue:b}=ve(i),p=we(i)||`The ${o} value`,O=Te(o),R=l._def.typeName,y;switch(R){case _.ZodString:y=new E(`--${O} <string>`,p);break;case _.ZodNumber:y=new E(`--${O} <number>`,p),y.argParser(c=>{let d=Number(c);if(!Number.isFinite(d))throw new Error(`Invalid number: ${c}`);return d});break;case _.ZodBoolean:y=new E(`--${O}`,p);break;case _.ZodEnum:let P=l._def.values;y=new E(`--${O} <choice>`,p).choices(P);break;case _.ZodArray:y=new E(`--${O} <value...>`,p);break;case _.ZodObject:case _.ZodRecord:y=new E(`--${O} <json>`,p),y.argParser(c=>{try{return JSON.parse(c)}catch{throw new Error(`Invalid JSON: ${c}`)}});break;case _.ZodAny:case _.ZodUnknown:y=new E(`--${O} <value>`,p),y.argParser(c=>{try{return JSON.parse(c)}catch{return c}});break;case _.ZodLiteral:let n=l._def.value;typeof n=="boolean"?y=new E(`--${O}`,p):(y=new E(`--${O} <value>`,p),y.default(n));break;case _.ZodUnion:let s=l._def.options;if(s.every(c=>c._def.typeName===_.ZodLiteral)){let c=s.map(d=>String(d._def.value));y=new E(`--${O} <choice>`,p).choices(c)}else y=new E(`--${O} <value>`,p),y.argParser(c=>{try{return JSON.parse(c)}catch{return c}});break;default:y=new E(`--${O} <value>`,p);break}return b!==void 0&&y.default(b),!m&&b===void 0&&y.makeOptionMandatory(!0),y}u(_e,"_createOption");function Se(o){let i=[];for(let[l,m]of Object.entries(o)){let b=_e(l,m);b&&i.push(b)}return i}u(Se,"_generateOptionsFromSchema");function Ce(o){let i={};for(let[l,m]of Object.entries(o)){let b=Oe(l);m!==void 0&&(i[b]=m)}return i}u(Ce,"_parseOptionsToToolInput");function Ee(o){let i=o.indexOf("_");return i===-1?{domain:"default",commandName:o}:{domain:o.substring(0,i),commandName:o.substring(i+1)}}u(Ee,"_parseToolName");function W(o,i,l){let m=new Map;for(let b of i){let{domain:p,commandName:O}=Ee(b.name()),R=m.get(p);R||(R=new pe(p).description(`${p.charAt(0).toUpperCase()+p.slice(1)} commands`),m.set(p,R),o.addCommand(R));let y=new pe(O).description(b.description().trim()),P=Se(b.inputSchema());for(let n of P)y.addOption(n);y.action(async n=>{let s=Ce(n),r=o.opts();await l(b.name(),s,r)}),R.addCommand(y)}}u(W,"registerToolCommands");import{spawn as De,execSync as Re}from"node:child_process";import{createRequire as Ae}from"node:module";import*as q from"node:path";import*as K from"node:readline";import{fileURLToPath as Ne}from"node:url";import{Command as D,Option as x}from"commander";var F=Ae(import.meta.url),Pe=Ne(import.meta.url),Ie=q.dirname(Pe),h=me.cliInfo.cliProvider,N=h.tools,S=3e4,ge=!1,be=!1;function w(o,i){if(ge){let l=new Date().toISOString();i!==void 0?console.error(`[${l}] [DEBUG] ${o}`,i):console.error(`[${l}] [DEBUG] ${o}`)}}u(w,"_debug");function e(o){be||console.log(o)}u(e,"_output");function f(o){console.error(o)}u(f,"_error");async function C(o){w(`Checking if daemon is running on port ${o}`);try{let i=await fetch(`http://localhost:${o}/health`,{method:"GET",signal:AbortSignal.timeout(3e3)});if(i.ok){let m=(await i.json()).status==="ok";return w(`Daemon health check result: ${m?"running":"not running"}`),m}return w(`Daemon health check failed: HTTP ${i.status}`),!1}catch(i){return w(`Daemon health check error: ${i.message}`),!1}}u(C,"_isDaemonRunning");function ke(o){return h.buildEnv(o)}u(ke,"_buildDaemonEnv");function G(o){let i=q.join(Ie,"..","daemon-server.js"),l=ke(o);w(`Starting daemon server from: ${i}`),w(`Daemon port: ${o.port}`);let m=De(process.execPath,[i,"--port",String(o.port)],{detached:!0,stdio:"ignore",env:l});m.unref(),w(`Daemon process spawned with PID: ${m.pid}`),e(`Started daemon server as detached process (PID: ${m.pid})`)}u(G,"_startDaemonDetached");async function k(o){if(await C(o.port))w("Daemon is already running");else{e(`Daemon server is not running on port ${o.port}, starting...`),G(o);let l=10,m=500;w(`Waiting for daemon to be ready (max ${l} retries, ${m}ms delay)`);for(let b=0;b<l;b++)if(await new Promise(p=>setTimeout(p,m)),w(`Retry ${b+1}/${l}: checking daemon status...`),await C(o.port)){w("Daemon is now ready"),e("Daemon server is ready");return}throw new Error(`Daemon server failed to start within ${l*m/1e3} seconds`)}}u(k,"_ensureDaemonRunning");async function U(o,i){try{return(await fetch(`http://localhost:${o}/shutdown`,{method:"POST",signal:AbortSignal.timeout(i)})).ok}catch{return!1}}u(U,"_stopDaemon");async function ue(o,i,l,m,b){let p={"Content-Type":"application/json"};m&&(p["session-id"]=m);let O={toolName:i,toolInput:l};w(`Calling tool: ${i}`),w("Tool input:",l),w(`Session ID: ${m||"(default)"}`),w(`Timeout: ${b||"none"}`);let R=Date.now(),y=await fetch(`http://localhost:${o}/call`,{method:"POST",headers:p,body:JSON.stringify(O),signal:b?AbortSignal.timeout(b):void 0}),P=Date.now()-R;if(w(`Tool call completed in ${P}ms, status: ${y.status}`),!y.ok){let s=await y.json().catch(()=>({}));throw w("Tool call error:",s),new Error(s?.error?.message||`HTTP ${y.status}: ${y.statusText}`)}let n=await y.json();return w("Tool call result:",n.toolError?{error:n.toolError}:{success:!0}),n}u(ue,"_callTool");async function je(o,i,l){try{return(await fetch(`http://localhost:${o}/session`,{method:"DELETE",headers:{"session-id":i},signal:AbortSignal.timeout(l)})).ok}catch{return!1}}u(je,"_deleteSession");async function J(o,i){try{let l=await fetch(`http://localhost:${o}/info`,{method:"GET",signal:AbortSignal.timeout(i)});return l.ok?await l.json():null}catch{return null}}u(J,"_getDaemonInfo");async function fe(o,i){try{let l=await fetch(`http://localhost:${o}/sessions`,{method:"GET",signal:AbortSignal.timeout(i)});return l.ok?await l.json():null}catch{return null}}u(fe,"_listSessions");async function xe(o,i,l){try{let m=await fetch(`http://localhost:${o}/session`,{method:"GET",headers:{"session-id":i},signal:AbortSignal.timeout(l)});return m.ok?await m.json():null}catch{return null}}u(xe,"_getSessionInfo");function j(o){let i=Math.floor(o/86400),l=Math.floor(o%86400/3600),m=Math.floor(o%3600/60),b=o%60,p=[];return i>0&&p.push(`${i}d`),l>0&&p.push(`${l}h`),m>0&&p.push(`${m}m`),p.push(`${b}s`),p.join(" ")}u(j,"_formatUptime");function V(o){return new Date(o).toISOString()}u(V,"_formatTimestamp");function Z(o){let i=o._def.typeName;return i==="ZodOptional"||i==="ZodNullable"||i==="ZodDefault"?Z(o._def.innerType):i==="ZodArray"?`${Z(o._def.type)}[]`:i==="ZodEnum"?o._def.values.join(" | "):i==="ZodLiteral"?JSON.stringify(o._def.value):i==="ZodUnion"?o._def.options.map(m=>Z(m)).join(" | "):{ZodString:"string",ZodNumber:"number",ZodBoolean:"boolean",ZodObject:"object",ZodRecord:"Record<string, any>",ZodAny:"any"}[i]||i.replace("Zod","").toLowerCase()}u(Z,"_getZodTypeName");function H(o){if(o._def.description)return o._def.description;if(o._def.typeName==="ZodOptional"||o._def.typeName==="ZodNullable"||o._def.typeName==="ZodDefault")return H(o._def.innerType)}u(H,"_getZodDescription");function Ze(o){let i=o._def.typeName;return i==="ZodOptional"||i==="ZodNullable"}u(Ze,"_isZodOptional");function ye(o){return o._def.typeName==="ZodDefault"?!0:o._def.typeName==="ZodOptional"||o._def.typeName==="ZodNullable"?ye(o._def.innerType):!1}u(ye,"_hasZodDefault");function $e(o){if(o._def.typeName==="ZodDefault")return o._def.defaultValue();if(o._def.typeName==="ZodOptional"||o._def.typeName==="ZodNullable")return $e(o._def.innerType)}u($e,"_getZodDefault");function L(o,i=0){let l=" ".repeat(i);if(o==null)return`${l}(empty)`;if(typeof o=="string")return o.split(`
3
+ `).map(m=>`${l}${m}`).join(`
4
+ `);if(typeof o=="number"||typeof o=="boolean")return`${l}${o}`;if(Array.isArray(o))return o.length===0?`${l}[]`:o.map(m=>L(m,i)).join(`
5
+ `);if(typeof o=="object"){let m=[];for(let[b,p]of Object.entries(o))p!==void 0&&(typeof p=="object"&&p!==null&&!Array.isArray(p)?(m.push(`${l}${b}:`),m.push(L(p,i+1))):Array.isArray(p)?(m.push(`${l}${b}:`),m.push(L(p,i+1))):m.push(`${l}${b}: ${p}`));return m.join(`
6
+ `)}return`${l}${String(o)}`}u(L,"_formatOutput");function $(o,i,l=!1){let m=i?JSON.stringify(o,null,2):String(o);l?console.error(m):console.log(m)}u($,"_printOutput");function Ge(o){return o.addOption(new x("--port <number>","Daemon server port").argParser(i=>{let l=Number(i);if(!Number.isInteger(l)||l<1||l>65535)throw new Error("Port must be an integer between 1 and 65535");return l}).default(B)).addOption(new x("--session-id <string>","Session ID for maintaining state across commands")).addOption(new x("--json","Output results as JSON")).addOption(new x("--quiet","Suppress log messages, only show output")).addOption(new x("--verbose","Enable verbose/debug output")).addOption(new x("--timeout <ms>","Timeout for operations in milliseconds").argParser(i=>{let l=Number(i);if(!Number.isFinite(l)||l<0)throw new Error("Timeout must be a positive number");return l}).default(S)),h.addOptions(o)}u(Ge,"_addGlobalOptions");async function Le(){let o=Ge(new D(h.cliName).description(h.cliDescription).version(F("../../package.json").version));o.hook("preAction",n=>{let s=n.opts();s.verbose&&(ge=!0),s.quiet&&(be=!0),w("Verbose mode enabled"),w("CLI version:",F("../../package.json").version),w("Node version:",process.version),w("Platform:",process.platform)});let i=new D("daemon").description("Manage the daemon server");i.command("start").description("Start the daemon server").action(async()=>{let n=o.opts();if(await C(n.port)){n.json?$({status:"already_running",port:n.port},!0):e(`Daemon server is already running on port ${n.port}`);return}G(n);let r=10,c=500;for(let d=0;d<r;d++)if(await new Promise(t=>setTimeout(t,c)),await C(n.port)){n.json?$({status:"started",port:n.port},!0):e(`Daemon server started on port ${n.port}`);return}n.json?$({status:"failed",error:"Daemon server failed to start"},!0,!0):f("Failed to start daemon server"),process.exit(1)}),i.command("stop").description("Stop the daemon server").action(async()=>{let n=o.opts();if(!await C(n.port)){n.json?$({status:"not_running",port:n.port},!0):e(`Daemon server is not running on port ${n.port}`);return}await U(n.port,n.timeout??S)?n.json?$({status:"stopped",port:n.port},!0):e(`Daemon server stopped on port ${n.port}`):(n.json?$({status:"failed",error:"Failed to stop daemon server"},!0,!0):f("Failed to stop daemon server"),process.exit(1))}),i.command("restart").description("Restart the daemon server (stop + start)").action(async()=>{let n=o.opts(),s=await C(n.port);s&&(w("Stopping daemon server..."),await U(n.port,n.timeout??S)||(n.json?$({status:"failed",error:"Failed to stop daemon server"},!0,!0):f("Failed to stop daemon server"),process.exit(1)),w("Waiting for port to be released..."),await new Promise(t=>setTimeout(t,1e3))),w("Starting daemon server..."),G(n);let r=10,c=500;for(let d=0;d<r;d++)if(await new Promise(t=>setTimeout(t,c)),await C(n.port)){n.json?$({status:"restarted",port:n.port},!0):e(`Daemon server ${s?"restarted":"started"} on port ${n.port}`);return}n.json?$({status:"failed",error:"Daemon server failed to start"},!0,!0):f("Failed to start daemon server"),process.exit(1)}),i.command("status").description("Check daemon server status").action(async()=>{let n=o.opts(),s=await C(n.port);n.json?$({status:s?"running":"stopped",port:n.port},!0):e(s?`Daemon server is running on port ${n.port}`:`Daemon server is not running on port ${n.port}`)}),i.command("info").description("Get detailed daemon server information").action(async()=>{let n=o.opts();await C(n.port)||(n.json?$({status:"not_running",port:n.port},!0,!0):f(`Daemon server is not running on port ${n.port}`),process.exit(1));let r=await J(n.port,n.timeout??S);r?n.json?$(r,!0):(e("Daemon Server Information:"),e(` Version: ${r.version}`),e(` Port: ${r.port}`),e(` Uptime: ${j(r.uptime)}`),e(` Sessions: ${r.sessionCount}`)):(n.json?$({status:"error",error:"Failed to get daemon info"},!0,!0):f("Failed to get daemon info"),process.exit(1))}),o.addCommand(i);let l=new D("session").description(h.sessionDescription);l.command("list").description("List all active sessions").action(async()=>{let n=o.opts();try{await k(n);let s=await fe(n.port,n.timeout??S);if(s)if(n.json)$(s,!0);else if(s.sessions.length===0)e("No active sessions");else{e(`Active Sessions (${s.sessions.length}):`);for(let r of s.sessions)e(` ${r.id}`),e(` Created: ${V(r.createdAt)}`),e(` Last Active: ${V(r.lastActiveAt)}`),e(` Idle: ${j(r.idleSeconds)}`)}else n.json?$({status:"error",error:"Failed to list sessions"},!0,!0):f("Failed to list sessions"),process.exit(1)}catch(s){n.json?$({status:"error",error:s.message},!0,!0):f(`Error: ${s.message}`),process.exit(1)}}),l.command("info <session-id>").description("Get information about a specific session").action(async n=>{let s=o.opts();try{await k(s);let r=await xe(s.port,n,s.timeout??S);r?s.json?$(r,!0):(e(`Session: ${r.id}`),e(` Created: ${V(r.createdAt)}`),e(` Last Active: ${V(r.lastActiveAt)}`),e(` Idle: ${j(r.idleSeconds)}`)):(s.json?$({status:"not_found",sessionId:n},!0,!0):f(`Session '${n}' not found`),process.exit(1))}catch(r){s.json?$({status:"error",error:r.message},!0,!0):f(`Error: ${r.message}`),process.exit(1)}}),l.command("delete <session-id>").description("Delete a specific session").action(async n=>{let s=o.opts();try{await k(s),await je(s.port,n,s.timeout??S)?s.json?$({status:"deleted",sessionId:n},!0):e(`Session '${n}' deleted`):(s.json?$({status:"not_found",sessionId:n},!0,!0):f(`Session '${n}' not found or already deleted`),process.exit(1))}catch(r){s.json?$({status:"error",error:r.message},!0,!0):f(`Error: ${r.message}`),process.exit(1)}}),o.addCommand(l);let m=new D("tools").description("List and inspect available tools");m.command("list").description("List all available tools").option("--domain <domain>","Filter by domain (e.g., navigation, content, interaction)").action(n=>{let s=o.opts(),r=new Map;for(let c of N){let t=c.name().split("_")[0];n.domain&&t!==n.domain||(r.has(t)||r.set(t,[]),r.get(t).push(c))}if(s.json){let c=[];for(let[d,t]of r)c.push({domain:d,tools:t.map(a=>({name:a.name(),description:a.description().trim().split(`
7
+ `)[0]}))});$(c,!0)}else{if(r.size===0){e("No tools found");return}e(`Available Tools (${N.length} total):
8
+ `);for(let[c,d]of r){e(` ${c}:`);for(let t of d){let a=t.name().split("_")[1]||t.name(),g=t.description().trim().split(`
9
+ `)[0];e(` ${a.padEnd(30)} ${g}`)}e("")}}}),m.command("info <tool-name>").description("Get detailed information about a specific tool").action(n=>{let s=o.opts(),r=N.find(t=>t.name()===n);r||(r=N.find(t=>t.name().split("_")[1]===n)),r||(s.json?$({status:"not_found",toolName:n},!0,!0):f(`Tool '${n}' not found`),process.exit(1));let c=r.inputSchema(),d=[];for(let[t,a]of Object.entries(c))d.push({name:t,type:Z(a),required:!Ze(a),description:H(a),default:ye(a)?$e(a):void 0});if(s.json)$({name:r.name(),description:r.description().trim(),parameters:d},!0);else{let t=r.name().split("_");if(e(`Tool: ${r.name()}`),e(`Domain: ${t[0]}`),e(`
10
+ Description:`),e(r.description().trim().split(`
11
+ `).map(a=>` ${a}`).join(`
12
+ `)),e(`
13
+ Parameters:`),d.length===0)e(" (none)");else for(let a of d){let g=a.required?"(required)":"(optional)";e(` --${a.name} <${a.type}> ${g}`),a.description&&e(` ${a.description}`),a.default!==void 0&&e(` Default: ${JSON.stringify(a.default)}`)}e(`
14
+ Usage:`),e(` ${h.cliName} ${t[0]} ${t[1]||r.name()} [options]`)}}),m.command("search <query>").description("Search tools by name or description").action(n=>{let s=o.opts(),r=n.toLowerCase(),c=N.filter(d=>{let t=d.name().toLowerCase(),a=d.description().toLowerCase();return t.includes(r)||a.includes(r)});if(s.json){let d=c.map(t=>{let a=t.name().split("_");return{name:t.name(),domain:a[0],description:t.description().trim().split(`
15
+ `)[0]}});$(d,!0)}else{if(c.length===0){e(`No tools found matching "${n}"`);return}e(`Tools matching "${n}" (${c.length} found):
16
+ `);for(let d of c){let t=d.name().split("_"),a=t[0],g=t[1]||d.name(),v=d.description().trim().split(`
17
+ `)[0];e(` ${a}/${g}`),e(` ${v}
18
+ `)}}}),o.addCommand(m);let b=new D("config").description("Show current configuration").action(()=>{let n=o.opts(),s={daemon:{port:B,sessionIdleSeconds:ce,sessionIdleCheckSeconds:de},[h.platform]:h.getConfig(),otel:{enabled:Y,serviceName:z,serviceVersion:Q,exporterType:X,exporterHttpUrl:ee},aws:{region:oe,profile:ne},bedrock:{enabled:te,imageEmbedModelId:se,textEmbedModelId:re,visionModelId:ie},figma:{accessToken:ae?"***":void 0,apiBaseUrl:le}};n.json?$(s,!0):(e(`Current Configuration:
19
+ `),e(" Daemon:"),e(` Port: ${s.daemon.port}`),e(` Session Idle (sec): ${s.daemon.sessionIdleSeconds}`),e(` Idle Check Interval: ${s.daemon.sessionIdleCheckSeconds}`),e(`
20
+ `+h.formatConfig(s[h.platform])),e(`
21
+ OpenTelemetry:`),e(` Enabled: ${s.otel.enabled}`),e(` Service Name: ${s.otel.serviceName}`),e(` Service Version: ${s.otel.serviceVersion||"(not set)"}`),e(` Exporter Type: ${s.otel.exporterType}`),e(` Exporter HTTP URL: ${s.otel.exporterHttpUrl||"(not set)"}`),e(`
22
+ AWS:`),e(` Region: ${s.aws.region||"(not set)"}`),e(` Profile: ${s.aws.profile||"(not set)"}`),e(`
23
+ Bedrock:`),e(` Enabled: ${s.bedrock.enabled}`),e(` Image Embed Model ID: ${s.bedrock.imageEmbedModelId||"(not set)"}`),e(` Text Embed Model ID: ${s.bedrock.textEmbedModelId||"(not set)"}`),e(` Vision Model ID: ${s.bedrock.visionModelId||"(not set)"}`),e(`
24
+ Figma:`),e(` Access Token: ${s.figma.accessToken||"(not set)"}`),e(` API Base URL: ${s.figma.apiBaseUrl}`))});o.addCommand(b);let p=new D("completion").description("Generate shell completion scripts");p.command("bash").description("Generate bash completion script").action(()=>{let n=`_${h.cliName.replace(/-/g,"_")}_completions`,s=`
25
+ # ${h.cliName} bash completion
26
+ ${n}() {
27
+ local cur="\${COMP_WORDS[COMP_CWORD]}"
28
+ local prev="\${COMP_WORDS[COMP_CWORD-1]}"
29
+
30
+ # Main commands
31
+ local commands="${h.bashCompletionCommands}"
32
+
33
+ # Daemon subcommands
34
+ local daemon_cmds="start stop restart status info"
35
+
36
+ # Session subcommands
37
+ local session_cmds="list info delete"
38
+
39
+ # Tools subcommands
40
+ local tools_cmds="list info search"
41
+
42
+ case "\${prev}" in
43
+ ${h.cliName})
44
+ COMPREPLY=( $(compgen -W "\${commands}" -- "\${cur}") )
45
+ return 0
46
+ ;;
47
+ daemon)
48
+ COMPREPLY=( $(compgen -W "\${daemon_cmds}" -- "\${cur}") )
49
+ return 0
50
+ ;;
51
+ session)
52
+ COMPREPLY=( $(compgen -W "\${session_cmds}" -- "\${cur}") )
53
+ return 0
54
+ ;;
55
+ tools)
56
+ COMPREPLY=( $(compgen -W "\${tools_cmds}" -- "\${cur}") )
57
+ return 0
58
+ ;;
59
+ esac
60
+
61
+ # Global options
62
+ if [[ "\${cur}" == -* ]]; then
63
+ local opts="--port --session-id --json --quiet --verbose --timeout ${h.bashCompletionOptions} --help --version"
64
+ COMPREPLY=( $(compgen -W "\${opts}" -- "\${cur}") )
65
+ return 0
66
+ fi
67
+ }
68
+
69
+ complete -F ${n} ${h.cliName}
70
+ `;console.log(s),f(`
71
+ # To enable, add to your ~/.bashrc:`),f(`# eval "$(${h.cliName} completion bash)"`)}),p.command("zsh").description("Generate zsh completion script").action(()=>{let n=`_${h.cliName.replace(/-/g,"_")}`,s=h.zshCompletionCommands.map(c=>` '${c.name}:${c.description}'`).join(`
72
+ `),r=`
73
+ #compdef ${h.cliName}
74
+
75
+ ${n}() {
76
+ local -a commands
77
+ commands=(
78
+ ${s}
79
+ )
80
+
81
+ local -a daemon_cmds
82
+ daemon_cmds=(
83
+ 'start:Start the daemon server'
84
+ 'stop:Stop the daemon server'
85
+ 'restart:Restart the daemon server'
86
+ 'status:Check daemon server status'
87
+ 'info:Get detailed daemon info'
88
+ )
89
+
90
+ local -a session_cmds
91
+ session_cmds=(
92
+ 'list:List all active sessions'
93
+ 'info:Get information about a session'
94
+ 'delete:Delete a specific session'
95
+ )
96
+
97
+ local -a tools_cmds
98
+ tools_cmds=(
99
+ 'list:List all available tools'
100
+ 'info:Get detailed tool information'
101
+ 'search:Search tools by keyword'
102
+ )
103
+
104
+ _arguments -C \\
105
+ '--port[Daemon server port]:port' \\
106
+ '--session-id[Session ID]:session_id' \\
107
+ '--json[Output as JSON]' \\
108
+ '--quiet[Suppress log messages]' \\
109
+ '--verbose[Enable verbose output]' \\
110
+ '--timeout[Operation timeout]:ms' \\
111
+ ${h.zshCompletionOptions}
112
+ '--help[Show help]' \\
113
+ '--version[Show version]' \\
114
+ '1: :->cmd' \\
115
+ '*:: :->args'
116
+
117
+ case "$state" in
118
+ cmd)
119
+ _describe 'command' commands
120
+ ;;
121
+ args)
122
+ case "$words[1]" in
123
+ daemon)
124
+ _describe 'subcommand' daemon_cmds
125
+ ;;
126
+ session)
127
+ _describe 'subcommand' session_cmds
128
+ ;;
129
+ tools)
130
+ _describe 'subcommand' tools_cmds
131
+ ;;
132
+ esac
133
+ ;;
134
+ esac
135
+ }
136
+
137
+ ${n}
138
+ `;console.log(r),f(`
139
+ # To enable, add to your ~/.zshrc:`),f(`# eval "$(${h.cliName} completion zsh)"`)}),o.addCommand(p);function O(n){let s=new D("repl").exitOverride().configureOutput({writeOut:u(t=>e(t.trimEnd()),"writeOut"),writeErr:u(t=>f(t.trimEnd()),"writeErr")}),r=new D("daemon").description("Manage daemon server").exitOverride();r.command("start").description("Start the daemon server").action(async()=>{let t=n;await C(t.port)?e(`Daemon server is already running on port ${t.port}`):(G(t),await k(t),e(`Daemon server started on port ${t.port}`))}),r.command("stop").description("Stop the daemon server").action(async()=>{let t=n;await C(t.port)?await U(t.port,t.timeout??S)?e("Daemon server stopped"):f("Failed to stop daemon server"):e("Daemon server is not running")}),r.command("restart").description("Restart the daemon server").action(async()=>{let t=n;await C(t.port)&&(await U(t.port,t.timeout??S),await new Promise(g=>setTimeout(g,1e3))),G(t),await k(t),e(`Daemon server restarted on port ${t.port}`)}),r.command("status").description("Check daemon server status").action(async()=>{let t=n,a=await C(t.port);e(a?`Daemon server is running on port ${t.port}`:"Daemon server is not running")}),r.command("info").description("Show daemon server information").action(async()=>{let t=n,a=await J(t.port,t.timeout??S);a?(e(`Version: ${a.version}`),e(`Uptime: ${j(a.uptime)}`),e(`Sessions: ${a.sessionCount}`),e(`Port: ${a.port}`)):e("Daemon server is not running")}),s.addCommand(r);let c=new D("session").description(h.sessionDescription).exitOverride();c.command("list").description("List active sessions").action(async()=>{let t=n,a=await fe(t.port,t.timeout??S);if(a&&a.sessions.length>0){e(`Active sessions: ${a.sessions.length}`);for(let g of a.sessions)e(` ${g.id} (idle: ${j(g.idleSeconds)})`)}else e("No active sessions")}),c.command("info <session-id>").description("Show session information").action(async t=>{let a=n;try{let g=await fetch(`http://localhost:${a.port}/session`,{method:"GET",headers:{"session-id":t},signal:AbortSignal.timeout(a.timeout??S)});if(g.ok){let v=await g.json();e(`Session: ${v.id}`),e(`Created: ${new Date(v.createdAt).toISOString()}`),e(`Last Active: ${new Date(v.lastActiveAt).toISOString()}`),e(`Idle: ${j(v.idleSeconds)}`)}else e(`Session not found: ${t}`)}catch(g){f(`Error: ${g.message}`)}}),c.command("delete <session-id>").description("Delete a session").action(async t=>{let a=n;try{(await fetch(`http://localhost:${a.port}/session`,{method:"DELETE",headers:{"session-id":t},signal:AbortSignal.timeout(a.timeout??S)})).ok?e(`Session deleted: ${t}`):e(`Session not found: ${t}`)}catch(g){f(`Error: ${g.message}`)}}),s.addCommand(c);let d=new D("tools").description("Discover and inspect available tools").exitOverride();return d.command("list").description("List all available tools").action(()=>{let t=new Set;for(let a of N)t.add(a.name().split("_")[0]);e(`Available domains: ${Array.from(t).join(", ")}`),e(`Total tools: ${N.length}`)}),d.command("search <query>").description("Search tools by name or description").action(t=>{let a=t.toLowerCase(),g=N.filter(v=>v.name().toLowerCase().includes(a)||v.description().toLowerCase().includes(a));if(g.length>0){e(`Found ${g.length} tools:`);for(let v of g)e(` ${v.name()} - ${v.description()}`)}else e(`No tools found matching "${t}"`)}),d.command("info <tool-name>").description("Show detailed information about a tool").action(t=>{let a=N.find(g=>g.name()===t);if(a){e(`
140
+ Tool: ${a.name()}`),e(`Description: ${a.description()}`),e("Input Schema:");let g=a.inputSchema();for(let[v,T]of Object.entries(g)){let I=Z(T),M=H(T)||"",A=T.isOptional();e(` --${v} <${I}>${A?" (optional)":""} ${M}`)}}else e(`Tool not found: ${t}`)}),s.addCommand(d),s.command("config").description("Show current configuration").action(()=>{let t=n;e(`
141
+ Current Configuration:`),e(` port = ${t.port}`),e(` session-id = ${t.sessionId||"(auto)"}`),e(h.formatConfigForRepl(t)),e(` timeout = ${t.timeout??S}`),e(` json = ${t.json??!1}`),e(` quiet = ${t.quiet??!1}`),e(` verbose = ${t.verbose??!1}`),e(`
142
+ Tip: Start interactive mode with options:`),e(` ${h.cliExamples[0]}`)}),s.command("update").description("Check for updates").option("--check","Only check for updates without installing").action(async t=>{let a=F("../../package.json").version,g=h.packageName;e(`Checking for updates...
143
+ `);try{let v=await fetch(`https://registry.npmjs.org/${g}/latest`,{signal:AbortSignal.timeout(1e4)});if(!v.ok){f("Failed to check for updates");return}let I=(await v.json()).version;e(`Current version: ${a}`),e(`Latest version: ${I}`),a===I?e(`
144
+ You are using the latest version!`):(e(`
145
+ A new version is available!`),t.check||e(`Run: npm install -g ${g}@latest`))}catch(v){f(`Error checking for updates: ${v.message}`)}}),s.command("status").description("Show daemon status summary").action(async()=>{let t=n,a=await J(t.port,t.timeout??S);e(a?`Daemon: running (v${a.version}, uptime: ${j(a.uptime)}, sessions: ${a.sessionCount})`:"Daemon: not running")}),W(s,N,async(t,a,g)=>{let v=n;try{let T=await ue(v.port,t,a,v.sessionId,v.timeout);T.toolError?f(`Error: ${T.toolError.message}`):T.toolOutput&&(v.json?e(JSON.stringify(T.toolOutput,null,2)):e(L(T.toolOutput)))}catch(T){f(`Error: ${T.message}`)}}),s}u(O,"_createReplProgram");function R(n){let s=[],r="",c=!1,d="";for(let t=0;t<n.length;t++){let a=n[t];c?a===d?(c=!1,s.push(r),r=""):r+=a:a==='"'||a==="'"?(c=!0,d=a):a===" "||a===" "?r&&(s.push(r),r=""):r+=a}return r&&s.push(r),s}u(R,"_parseReplInput");let y=new D("interactive").alias("repl").description("Start interactive REPL mode").action(async()=>{let n=o.opts();e(`${h.cliDescription} - Interactive Mode`),e(`Type "help" for available commands, "exit" to quit
146
+ `);try{await k(n)}catch(c){f(`Error: ${c.message}`),process.exit(1)}let s=O(n),r=K.createInterface({input:process.stdin,output:process.stdout,prompt:h.replPrompt});r.prompt(),r.on("line",async c=>{let d=c.trim();if(!d){r.prompt();return}if((d==="exit"||d==="quit")&&(e("Goodbye!"),r.close(),process.exit(0)),d==="help"){e(`
147
+ REPL Commands:`),e(" help Show this help"),e(" exit, quit Exit interactive mode"),e(`
148
+ Available Commands:`),e(" status Show daemon status summary"),e(" config Show current configuration"),e(" update Check for CLI updates"),e(" daemon <cmd> Daemon management (start, stop, restart, status, info)"),e(" session <cmd> Session management (list, info, delete)"),e(" tools <cmd> Tool discovery (list, search, info)"),e(" <domain> <tool> Execute a tool (e.g., navigation go-to --url ...)"),e(`
149
+ Examples:`),e(" # Daemon & Session"),e(" daemon status"),e(" daemon info"),e(" session list"),e(" session delete my-session"),e(""),e(" # Tool Discovery"),e(" tools list"),e(" tools search screenshot"),e(" tools info navigation_go-to"),e(""),e(" # Navigation"),e(' navigation go-to --url "https://example.com"'),e(" navigation go-back"),e(" navigation reload"),e(""),e(" # Content"),e(' content take-screenshot --name "test"'),e(" content get-as-text"),e(' content get-as-html --selector "#main"'),e(""),e(" # Interaction"),e(' interaction click --ref "Submit"'),e(' interaction fill --ref "Email" --value "test@example.com"'),e(' interaction hover --ref "Menu"'),e(""),e(" # Accessibility"),e(" a11y get-snapshot"),e(" a11y get-ax-tree-snapshot"),e(`
150
+ Tip: Use global options when starting interactive mode:`);for(let t of h.cliExamples)e(` ${t}`);e(""),r.prompt();return}try{let t=R(d);await s.parseAsync(["node","repl",...t])}catch(t){t.code==="commander.help"||(t.code==="commander.unknownCommand"?(e(`Unknown command: ${d}`),e('Type "help" for available commands')):t.code==="commander.missingArgument"?f(`Missing argument: ${t.message}`):t.code==="commander.invalidArgument"?f(`Invalid argument: ${t.message}`):t.code&&t.code.startsWith("commander.")||f(`Error: ${t.message}`))}r.prompt()}),r.on("close",()=>{process.exit(0)})});o.addCommand(y);let P=new D("update").description("Check for updates and optionally install them").option("--check","Only check for updates without installing").action(async n=>{let s=o.opts(),r=F("../../package.json").version,c=h.packageName;e(`Checking for updates...
151
+ `);try{let d=await fetch(`https://registry.npmjs.org/${c}/latest`,{method:"GET",signal:AbortSignal.timeout(1e4)});if(!d.ok)throw new Error(`Failed to check npm registry: HTTP ${d.status}`);let a=(await d.json()).version;if(s.json){$({currentVersion:r,latestVersion:a,updateAvailable:a!==r},!0);return}if(e(` Current version: ${r}`),e(` Latest version: ${a}`),e(""),a===r){e("\x1B[32m\u2713 You are using the latest version!\x1B[0m");return}let g=r.split(".").map(Number),v=a.split(".").map(Number),T=!1;for(let A=0;A<3;A++)if(v[A]>g[A]){T=!0;break}else if(v[A]<g[A])break;if(!T){e("\x1B[32m\u2713 You are using a newer version than published!\x1B[0m");return}if(e(`\x1B[33m\u26A0 Update available: ${r} \u2192 ${a}\x1B[0m
152
+ `),n.check){e("To update, run:"),e(` npm install -g ${c}@latest`),e("or"),e(` npx ${c}@latest`);return}let I=K.createInterface({input:process.stdin,output:process.stdout}),M=await new Promise(A=>{I.question("Do you want to update now? (y/N) ",he=>{I.close(),A(he.toLowerCase())})});if(M!=="y"&&M!=="yes"){e(`
153
+ Update cancelled.`);return}e(`
154
+ Updating...
155
+ `);try{Re(`npm install -g ${c}@latest`,{stdio:"inherit"}),e(`
156
+ \x1B[32m\u2713 Update complete!\x1B[0m`),e("Please restart your terminal or run a new command to use the updated version.")}catch{f(`
157
+ \x1B[31m\u2717 Update failed.\x1B[0m`),f("Try running manually with sudo:"),f(` sudo npm install -g ${c}@latest`),process.exit(1)}}catch(d){s.json?$({error:d.message,currentVersion:r},!0,!0):(f(`\x1B[31m\u2717 Failed to check for updates: ${d.message}\x1B[0m`),f(`
158
+ You can manually check at:`),f(` https://www.npmjs.com/package/${c}`)),process.exit(1)}});o.addCommand(P),W(o,N,async(n,s,r)=>{let c=r;try{await k(c);let d=await ue(c.port,n,s,c.sessionId,c.timeout);d.toolError&&(c.json?$({error:d.toolError},!0,!0):f(`Error: ${d.toolError.message||"Unknown error"}`),process.exit(1)),d.toolOutput&&(c.json?$(d.toolOutput,!0):e(L(d.toolOutput)))}catch(d){c.json?$({error:d.message},!0,!0):f(`Error: ${d.message}`),process.exit(1)}}),await o.parseAsync(process.argv)}u(Le,"main");Le().catch(o=>{f(`Fatal error: ${o.message}`),process.exit(1)});
@@ -0,0 +1 @@
1
+ import{$ as f,W as a,X as b,Y as c,Z as d,_ as e,aa as g,ba as h,ca as i,da as j,ea as k,fa as l,ga as m,ha as n,ia as o,ja as p,ka as q,la as r,ma as s,na as t,oa as u,pa as v,qa as w,ra as x,sa as y,ta as z,ua as A,va as B,wa as C,xa as D,ya as E}from"./core-IV5QBQ2N.js";export{b as DEFAULT_NODE_DEBUG_CONFIG,a as ProbeKind,w as addWatchExpression,p as clearProbes,s as clearSnapshots,t as clearSnapshotsByProbe,z as clearWatchExpressions,m as createProbe,f as detachDebugging,e as disableDebugging,d as enableDebugging,E as evaluateInNode,v as getConsoleMessages,l as getExceptionBreakpoint,C as getOriginalSources,D as getScripts,u as getSnapshotStats,q as getSnapshots,r as getSnapshotsByProbe,h as getStore,c as getStoreKey,B as hasSourceMaps,g as isDebuggingEnabled,o as listProbes,j as listStoreKeys,y as listWatchExpressions,A as loadSourceMaps,n as removeProbe,x as removeWatchExpression,i as resolveSourceLocation,k as setExceptionBreakpoint};