browser-devtools-mcp 0.2.2 → 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 +200 -25
  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
@@ -10,14 +10,34 @@
10
10
  </p>
11
11
 
12
12
  <p align="center">
13
- 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.
14
14
  </p>
15
15
 
16
16
  ## Overview
17
17
 
18
- 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.
19
19
 
20
- ### 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
21
41
 
22
42
  - **Visual Inspection**: Screenshots, ARIA snapshots, HTML/text extraction, PDF generation
23
43
  - **Design Comparison**: Compare live page UI against Figma designs with similarity scoring
@@ -29,7 +49,16 @@ Browser DevTools MCP exposes a Playwright-powered browser runtime to AI agents,
29
49
  - **Session Management**: Long-lived, session-based debugging with automatic cleanup
30
50
  - **Multiple Transport Modes**: Supports both stdio and HTTP transports
31
51
 
32
- ## 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
33
62
 
34
63
  ### Content Tools
35
64
  - **Screenshots**: Capture full page or specific elements (PNG/JPEG) with image data
@@ -109,6 +138,7 @@ Non-blocking debugging tools that capture snapshots without pausing execution. I
109
138
  - `clear-*-snapshots`: Clear captured snapshots
110
139
 
111
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
112
142
  - **Watch Expressions**: Add expressions to evaluate at every tracepoint/exceptionpoint hit
113
143
  - **Status**: Get current debugging status (enabled, probe counts, snapshot stats)
114
144
 
@@ -117,6 +147,7 @@ Non-blocking debugging tools that capture snapshots without pausing execution. I
117
147
  - Automatic debugging enablement on first tool use
118
148
  - Configurable limits (max snapshots, call stack depth, async segments)
119
149
  - Sequence numbers for efficient snapshot polling
150
+ - OpenTelemetry trace context in Node snapshots (traceId, spanId when process uses @opentelemetry/api)
120
151
 
121
152
  ## Prerequisites
122
153
 
@@ -148,12 +179,29 @@ This installs the CLI skill that enables AI agents to automate browsers for web
148
179
 
149
180
  ## MCP Client Configuration
150
181
 
151
- ### 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>
152
199
 
153
200
  #### Local Server
154
201
  Add the following configuration into the `claude_desktop_config.json` file.
155
202
  See the [Claude Desktop MCP docs](https://modelcontextprotocol.io/docs/develop/connect-local-servers) for more info.
156
203
 
204
+ **Browser platform (default):**
157
205
  ```json
158
206
  {
159
207
  "mcpServers": {
@@ -165,6 +213,18 @@ See the [Claude Desktop MCP docs](https://modelcontextprotocol.io/docs/develop/c
165
213
  }
166
214
  ```
167
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
+
168
228
  #### Remote Server (HTTP Transport)
169
229
  First, start the server with HTTP transport:
170
230
  ```bash
@@ -175,7 +235,10 @@ Then, go to `Settings` > `Connectors` > `Add Custom Connector` in Claude Desktop
175
235
  - Name: `Browser DevTools`
176
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)
177
237
 
178
- ### Claude Code
238
+ </details>
239
+
240
+ <details>
241
+ <summary><strong>Claude Code</strong></summary>
179
242
 
180
243
  Run the following command.
181
244
  See [Claude Code MCP docs](https://docs.anthropic.com/en/docs/claude-code/mcp) for more info.
@@ -198,7 +261,10 @@ claude mcp add --transport http browser-devtools <SERVER_URL>
198
261
 
199
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).
200
263
 
201
- ### Cursor
264
+ </details>
265
+
266
+ <details>
267
+ <summary><strong>Cursor</strong></summary>
202
268
 
203
269
  Add the following configuration into the `~/.cursor/mcp.json` file (or `.cursor/mcp.json` in your project folder).
204
270
  See the [Cursor MCP docs](https://docs.cursor.com/context/model-context-protocol) for more info.
@@ -234,7 +300,10 @@ Then add the configuration:
234
300
 
235
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).
236
302
 
237
- ### VS Code
303
+ </details>
304
+
305
+ <details>
306
+ <summary><strong>VS Code</strong></summary>
238
307
 
239
308
  Add the following configuration into the `.vscode/mcp.json` file.
240
309
  See the [VS Code MCP docs](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) for more info.
@@ -276,7 +345,10 @@ Then add the configuration:
276
345
 
277
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).
278
347
 
279
- ### Windsurf
348
+ </details>
349
+
350
+ <details>
351
+ <summary><strong>Windsurf</strong></summary>
280
352
 
281
353
  Add the following configuration into the `~/.codeium/windsurf/mcp_config.json` file.
282
354
  See the [Windsurf MCP docs](https://docs.windsurf.com/windsurf/cascade/mcp) for more info.
@@ -312,7 +384,10 @@ Then add the configuration:
312
384
 
313
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).
314
386
 
315
- ### Copilot Coding Agent
387
+ </details>
388
+
389
+ <details>
390
+ <summary><strong>Copilot Coding Agent</strong></summary>
316
391
 
317
392
  Add the following configuration to the `mcpServers` section of your Copilot Coding Agent configuration through
318
393
  `Repository` > `Settings` > `Copilot` > `Coding agent` > `MCP configuration`.
@@ -351,7 +426,10 @@ Then add the configuration:
351
426
 
352
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).
353
428
 
354
- ### Gemini CLI
429
+ </details>
430
+
431
+ <details>
432
+ <summary><strong>Gemini CLI</strong></summary>
355
433
 
356
434
  Add the following configuration into the `~/.gemini/settings.json` file.
357
435
  See the [Gemini CLI MCP docs](https://google-gemini.github.io/gemini-cli/docs/tools/mcp-server.html) for more info.
@@ -387,7 +465,10 @@ Then add the configuration:
387
465
 
388
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).
389
467
 
390
- ### Smithery
468
+ </details>
469
+
470
+ <details>
471
+ <summary><strong>Smithery</strong></summary>
391
472
 
392
473
  Run the following command.
393
474
  You can find your Smithery API key [here](https://smithery.ai/account/api-keys).
@@ -397,6 +478,8 @@ See the [Smithery CLI docs](https://smithery.ai/docs/concepts/cli) for more info
397
478
  npx -y @smithery/cli install serkan-ozal/browser-devtools-mcp --client <SMITHERY-CLIENT-NAME> --key <SMITHERY-API-KEY>
398
479
  ```
399
480
 
481
+ </details>
482
+
400
483
  ## HTTP Transport
401
484
 
402
485
  To use HTTP transport, start the server with:
@@ -430,9 +513,14 @@ npx -y browser-devtools-mcp --transport=streamable-http --port=3000
430
513
  npx -y @modelcontextprotocol/inspector http://localhost:3000/mcp --transport http
431
514
  ```
432
515
 
433
- ## 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
434
522
 
435
- 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:
436
524
 
437
525
  - **Scripting and automation**: Use in shell scripts, CI/CD pipelines, or automated workflows
438
526
  - **Session-based testing**: Maintain browser state across multiple commands with session IDs
@@ -440,15 +528,17 @@ Browser DevTools MCP includes a standalone CLI tool (`browser-devtools-cli`) for
440
528
 
441
529
  ### Installation
442
530
 
443
- The CLI is included with the npm package:
531
+ The CLIs are included with the npm package:
444
532
 
445
533
  ```bash
446
534
  # Run directly with npx
447
- npx -y browser-devtools-mcp browser-devtools-cli --help
535
+ npx -y browser-devtools-cli --help
536
+ npx -y node-devtools-cli --help
448
537
 
449
538
  # Or install globally
450
539
  npm install -g browser-devtools-mcp
451
540
  browser-devtools-cli --help
541
+ node-devtools-cli --help
452
542
  ```
453
543
 
454
544
  ### Global Options
@@ -474,9 +564,34 @@ browser-devtools-cli --help
474
564
 
475
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.
476
566
 
477
- ### 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
478
593
 
479
- The CLI organizes tools into domain-based subcommands:
594
+ `browser-devtools-cli` organizes tools into domain-based subcommands:
480
595
 
481
596
  ```
482
597
  browser-devtools-cli
@@ -997,7 +1112,9 @@ For the full list of available skills and documentation, see the [browser-devtoo
997
1112
 
998
1113
  ## Configuration
999
1114
 
1000
- 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
1001
1118
 
1002
1119
  | Variable | Description | Default |
1003
1120
  |----------|-------------|---------|
@@ -1005,6 +1122,18 @@ The server can be configured using environment variables:
1005
1122
  | `SESSION_IDLE_SECONDS` | Idle session timeout (seconds) | `300` |
1006
1123
  | `SESSION_IDLE_CHECK_SECONDS` | Interval for checking idle sessions (seconds) | `30` |
1007
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
+ |----------|-------------|---------|
1008
1137
  | `CONSOLE_MESSAGES_BUFFER_SIZE` | Maximum console messages to buffer | `1000` |
1009
1138
  | `HTTP_REQUESTS_BUFFER_SIZE` | Maximum HTTP requests to buffer | `1000` |
1010
1139
  | `BROWSER_HEADLESS_ENABLE` | Run browser in headless mode | `true` |
@@ -1023,7 +1152,7 @@ The server can be configured using environment variables:
1023
1152
  | `FIGMA_ACCESS_TOKEN` | Figma API access token for design comparison | (none) |
1024
1153
  | `FIGMA_API_BASE_URL` | Figma API base URL | `https://api.figma.com/v1` |
1025
1154
 
1026
- ## Available Tools
1155
+ ## Browser Platform Tools
1027
1156
 
1028
1157
  ### Content Tools
1029
1158
 
@@ -1321,6 +1450,33 @@ The server can be configured using environment variables:
1321
1450
  - The timeoutMs parameter limits synchronous execution time, but does not automatically time out awaited Promises
1322
1451
  </details>
1323
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
+
1324
1480
  ### Observability (O11Y) Tools
1325
1481
 
1326
1482
  <details>
@@ -1693,17 +1849,27 @@ The server can be configured using environment variables:
1693
1849
 
1694
1850
  ## Architecture
1695
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
+
1696
1862
  ### Session Management
1697
1863
 
1698
- 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:
1699
1865
 
1700
1866
  - The client disconnects
1701
1867
  - The session becomes idle (configurable timeout)
1702
1868
  - The session is explicitly closed
1703
1869
 
1704
- ### Browser Support
1870
+ ### Browser Platform Details
1705
1871
 
1706
- The server supports multiple browser engines:
1872
+ The Browser platform supports multiple browser engines:
1707
1873
  - **Chromium** (default)
1708
1874
  - **Firefox**
1709
1875
  - **WebKit**
@@ -1809,9 +1975,18 @@ npm run build
1809
1975
 
1810
1976
  ## Use Cases
1811
1977
 
1812
- ### 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
1813
1988
 
1814
- This server enables AI assistants to:
1989
+ The Browser platform enables AI assistants to:
1815
1990
 
1816
1991
  1. **Debug Web Applications**: Capture screenshots, inspect DOM, check console errors
1817
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};