browser-devtools-mcp 0.2.27 → 0.3.1
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.
- package/README.md +143 -48
- package/SECURITY.md +0 -2
- package/dist/cli/runner.js +4 -4
- package/dist/{core-247YVH6X.js → core-DOXUXYCD.js} +3 -3
- package/dist/{core-FCPLN2O4.js → core-LAPVCKSF.js} +1 -1
- package/dist/core-PIEDD6UN.js +5 -0
- package/dist/core-RRWTV5B5.js +956 -0
- package/dist/daemon-server.js +1 -1
- package/dist/index.js +2 -2
- package/dist/platform/browser/types.d.ts +2 -1
- package/dist/telemetry/index.d.ts +2 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/types.d.ts +7 -0
- package/package.json +8 -2
- package/dist/core-GIHDFCBF.js +0 -1195
package/README.md
CHANGED
|
@@ -127,8 +127,6 @@ Non-blocking debugging tools that capture snapshots without pausing execution. I
|
|
|
127
127
|
- **Tracepoint**: Captures call stack, local variables, and async stack traces at a code location
|
|
128
128
|
- **Logpoint**: Evaluates and logs expressions without full debug context (lightweight)
|
|
129
129
|
- **Exceptionpoint**: Captures snapshots when exceptions occur (uncaught or all)
|
|
130
|
-
- **Dompoint**: Monitors DOM mutations (subtree-modified, attribute-modified, node-removed)
|
|
131
|
-
- **Netpoint**: Monitors network requests/responses matching a URL pattern
|
|
132
130
|
|
|
133
131
|
**Core Operations (per probe type):**
|
|
134
132
|
- `put-*`: Create a probe at a location
|
|
@@ -552,6 +550,7 @@ node-devtools-cli --help
|
|
|
552
550
|
| `--quiet` | Suppress log messages, only show output | `false` |
|
|
553
551
|
| `--verbose` | Enable verbose/debug output for troubleshooting | `false` |
|
|
554
552
|
| `--timeout <ms>` | Timeout for operations in milliseconds | `30000` |
|
|
553
|
+
| `--no-telemetry` | Disable anonymous usage telemetry for this invocation | `false` |
|
|
555
554
|
|
|
556
555
|
### Browser Options
|
|
557
556
|
|
|
@@ -581,7 +580,7 @@ node-devtools-cli
|
|
|
581
580
|
├── run # Script execution commands
|
|
582
581
|
│ └── js-in-node # Run JavaScript in the connected Node process
|
|
583
582
|
└── debug # Debug commands
|
|
584
|
-
├── connect # Connect to Node.js process (pid, processName,
|
|
583
|
+
├── connect # Connect to Node.js process (pid, processName, inspectorPort, containerId, etc.)
|
|
585
584
|
├── disconnect # Disconnect from current process
|
|
586
585
|
├── status # Show connection status
|
|
587
586
|
├── put-tracepoint # Set a tracepoint
|
|
@@ -618,8 +617,7 @@ browser-devtools-cli
|
|
|
618
617
|
├── update # Check for and install updates
|
|
619
618
|
├── navigation # Navigation commands
|
|
620
619
|
│ ├── go-to # Navigate to a URL
|
|
621
|
-
│ ├── go-back
|
|
622
|
-
│ ├── go-forward # Navigate forward
|
|
620
|
+
│ ├── go-back-or-forward # Navigate back or forward in history (direction: back | forward)
|
|
623
621
|
│ └── reload # Reload the page
|
|
624
622
|
├── content # Content extraction commands
|
|
625
623
|
│ ├── take-screenshot # Take a screenshot
|
|
@@ -662,36 +660,14 @@ browser-devtools-cli
|
|
|
662
660
|
│ └── wait-for-network-idle # Wait for network idle
|
|
663
661
|
├── debug # Non-blocking debugging commands
|
|
664
662
|
│ ├── put-tracepoint # Set a tracepoint (captures call stack)
|
|
665
|
-
│ ├── remove-
|
|
666
|
-
│ ├── list-
|
|
667
|
-
│ ├── clear-tracepoints # Clear all tracepoints
|
|
663
|
+
│ ├── remove-probe # Remove a tracepoint, logpoint, or watch by ID (type + id)
|
|
664
|
+
│ ├── list-probes # List tracepoints, logpoints, and/or watches (optional types; omit to list all)
|
|
668
665
|
│ ├── put-logpoint # Set a logpoint (evaluates expression)
|
|
669
|
-
│ ├── remove-logpoint # Remove a logpoint
|
|
670
|
-
│ ├── list-logpoints # List all logpoints
|
|
671
|
-
│ ├── clear-logpoints # Clear all logpoints
|
|
672
666
|
│ ├── put-exceptionpoint # Enable exception catching
|
|
673
|
-
│ ├── put-dompoint # Set DOM mutation breakpoint
|
|
674
|
-
│ ├── remove-dompoint # Remove a DOM breakpoint
|
|
675
|
-
│ ├── list-dompoints # List all DOM breakpoints
|
|
676
|
-
│ ├── clear-dompoints # Clear all DOM breakpoints
|
|
677
|
-
│ ├── put-netpoint # Set network request breakpoint
|
|
678
|
-
│ ├── remove-netpoint # Remove a network breakpoint
|
|
679
|
-
│ ├── list-netpoints # List all network breakpoints
|
|
680
|
-
│ ├── clear-netpoints # Clear all network breakpoints
|
|
681
667
|
│ ├── add-watch # Add a watch expression
|
|
682
|
-
│ ├──
|
|
683
|
-
│ ├──
|
|
684
|
-
│ ├── clear-
|
|
685
|
-
│ ├── get-tracepoint-snapshots # Get tracepoint snapshots
|
|
686
|
-
│ ├── clear-tracepoint-snapshots # Clear tracepoint snapshots
|
|
687
|
-
│ ├── get-logpoint-snapshots # Get logpoint snapshots
|
|
688
|
-
│ ├── clear-logpoint-snapshots # Clear logpoint snapshots
|
|
689
|
-
│ ├── get-exceptionpoint-snapshots # Get exception snapshots
|
|
690
|
-
│ ├── clear-exceptionpoint-snapshots # Clear exception snapshots
|
|
691
|
-
│ ├── get-dompoint-snapshots # Get DOM mutation snapshots
|
|
692
|
-
│ ├── clear-dompoint-snapshots # Clear DOM snapshots
|
|
693
|
-
│ ├── get-netpoint-snapshots # Get network snapshots
|
|
694
|
-
│ ├── clear-netpoint-snapshots # Clear network snapshots
|
|
668
|
+
│ ├── clear-probes # Clear tracepoints, logpoints, and/or watches (optional types; omit to clear all)
|
|
669
|
+
│ ├── get-probe-snapshots # Get tracepoint/logpoint/exceptionpoint snapshots (optional types; response: tracepointSnapshots, logpointSnapshots, exceptionpointSnapshots)
|
|
670
|
+
│ ├── clear-probe-snapshots # Clear tracepoint/logpoint/exceptionpoint snapshots (optional types; omit to clear all)
|
|
695
671
|
│ └── status # Get debugging status
|
|
696
672
|
└── figma # Figma integration commands
|
|
697
673
|
└── compare-page-with-design
|
|
@@ -827,7 +803,7 @@ browser-devtools-cli tools list
|
|
|
827
803
|
#
|
|
828
804
|
# navigation:
|
|
829
805
|
# go-to Navigate the browser to the given URL...
|
|
830
|
-
# go-back
|
|
806
|
+
# go-back-or-forward Navigate back or forward in history (direction: back | forward)
|
|
831
807
|
# ...
|
|
832
808
|
|
|
833
809
|
# Filter tools by domain
|
|
@@ -1120,6 +1096,7 @@ The server can be configured using environment variables. Configuration is divid
|
|
|
1120
1096
|
| Variable | Description | Default |
|
|
1121
1097
|
|----------|-------------|---------|
|
|
1122
1098
|
| `PORT` | Port for HTTP transport | `3000` |
|
|
1099
|
+
| `TELEMETRY_ENABLE` | Set to `false` to disable anonymous usage telemetry | (unset) |
|
|
1123
1100
|
| `SESSION_IDLE_SECONDS` | Idle session timeout (seconds) | `300` |
|
|
1124
1101
|
| `SESSION_IDLE_CHECK_SECONDS` | Interval for checking idle sessions (seconds) | `30` |
|
|
1125
1102
|
| `SESSION_CLOSE_ON_SOCKET_CLOSE` | Close session when socket closes | `false` |
|
|
@@ -1131,7 +1108,7 @@ The server can be configured using environment variables. Configuration is divid
|
|
|
1131
1108
|
| Variable | Description | Default |
|
|
1132
1109
|
|----------|-------------|---------|
|
|
1133
1110
|
| `NODE_CONSOLE_MESSAGES_BUFFER_SIZE` | Maximum console messages to buffer from Node.js process | `1000` |
|
|
1134
|
-
| `NODE_INSPECTOR_HOST` | Inspector host for `debug_connect` when MCP runs in Docker (e.g. `host.docker.internal`). Use with host-mapped `
|
|
1111
|
+
| `NODE_INSPECTOR_HOST` | Inspector host for `debug_connect` when MCP runs in Docker (e.g. `host.docker.internal`). Use with host-mapped `inspectorPort` so the MCP connects to the right address. | `127.0.0.1` |
|
|
1135
1112
|
| `PLATFORM` | Platform to use: `browser` or `node` | `browser` |
|
|
1136
1113
|
|
|
1137
1114
|
### Browser Platform Configuration
|
|
@@ -1156,6 +1133,86 @@ The server can be configured using environment variables. Configuration is divid
|
|
|
1156
1133
|
| `FIGMA_ACCESS_TOKEN` | Figma API access token for design comparison | (none) |
|
|
1157
1134
|
| `FIGMA_API_BASE_URL` | Figma API base URL | `https://api.figma.com/v1` |
|
|
1158
1135
|
|
|
1136
|
+
## Telemetry
|
|
1137
|
+
|
|
1138
|
+
Browser DevTools MCP collects **anonymous usage data** to understand which tools are used, detect errors, and improve the product over time. Telemetry is **opt-out** — it is enabled by default and can be disabled at any time with zero friction.
|
|
1139
|
+
|
|
1140
|
+
### What is collected
|
|
1141
|
+
|
|
1142
|
+
Only non-personal, non-sensitive data is sent. No page content, URLs, error messages, or any application-specific data is ever included.
|
|
1143
|
+
|
|
1144
|
+
| Property | Description |
|
|
1145
|
+
|----------|-------------|
|
|
1146
|
+
| `tool_name` | Name of the tool that was called |
|
|
1147
|
+
| `source` | How the tool was invoked (see table below) |
|
|
1148
|
+
| `duration_ms` | Tool execution time in milliseconds |
|
|
1149
|
+
| `success` | Whether the call succeeded (`true` / `false`) |
|
|
1150
|
+
| `error_type` | Error class name (e.g. `TypeError`) — only on failure |
|
|
1151
|
+
| `error_code` | Error code (e.g. `ECONNREFUSED`) — only on failure |
|
|
1152
|
+
| `browser_devtools_version` | Package version (e.g. `0.2.27`) |
|
|
1153
|
+
| `node_version` | Node.js runtime version (e.g. `v20.10.0`) |
|
|
1154
|
+
| `os_platform` | Operating system (e.g. `darwin`, `linux`, `win32`) |
|
|
1155
|
+
| `os_arch` | CPU architecture (e.g. `x64`, `arm64`) |
|
|
1156
|
+
| `timezone` | Local timezone (e.g. `America/New_York`) |
|
|
1157
|
+
| `timestamp` | UTC timestamp of the event |
|
|
1158
|
+
| `session_id` | MCP session ID from the transport (MCP only) |
|
|
1159
|
+
| `client_name` | Raw MCP client name from the initialize handshake (MCP only) |
|
|
1160
|
+
|
|
1161
|
+
**What is never collected:**
|
|
1162
|
+
|
|
1163
|
+
- Any personally identifiable information (PII)
|
|
1164
|
+
- `error.message` content — only the error class name and code are sent
|
|
1165
|
+
- URLs, page content, screenshots, or any application data
|
|
1166
|
+
- IP addresses — PostHog is configured to discard them
|
|
1167
|
+
|
|
1168
|
+
A persistent anonymous UUID is stored locally at `~/.browser-devtools-mcp/config.json`. It is never linked to any user identity.
|
|
1169
|
+
|
|
1170
|
+
### Source values
|
|
1171
|
+
|
|
1172
|
+
The `source` field identifies the calling context:
|
|
1173
|
+
|
|
1174
|
+
| Value | Meaning |
|
|
1175
|
+
|-------|---------|
|
|
1176
|
+
| `cli` | Called via `browser-devtools-cli` or `node-devtools-cli` |
|
|
1177
|
+
| `cli_cursor` | CLI invoked from within Cursor (env var with `CURSOR_` prefix detected) |
|
|
1178
|
+
| `cli_claude` | CLI invoked from within Claude (env var with `CLAUDE_` prefix detected) |
|
|
1179
|
+
| `cli_codex` | CLI invoked from within Codex (env var with `CODEX_` prefix detected) |
|
|
1180
|
+
| `mcp-cursor` | MCP client is Cursor |
|
|
1181
|
+
| `mcp-claude` | MCP client is Claude Desktop or Claude Code |
|
|
1182
|
+
| `mcp-codex` | MCP client is OpenAI Codex CLI |
|
|
1183
|
+
| `mcp-unknown` | MCP client could not be identified |
|
|
1184
|
+
|
|
1185
|
+
### How to disable telemetry
|
|
1186
|
+
|
|
1187
|
+
**MCP server** — set `TELEMETRY_ENABLE=false` in your MCP client config:
|
|
1188
|
+
|
|
1189
|
+
```json
|
|
1190
|
+
{
|
|
1191
|
+
"mcpServers": {
|
|
1192
|
+
"browser-devtools": {
|
|
1193
|
+
"command": "npx",
|
|
1194
|
+
"args": ["-y", "browser-devtools-mcp"],
|
|
1195
|
+
"env": { "TELEMETRY_ENABLE": "false" }
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
```
|
|
1200
|
+
|
|
1201
|
+
**CLI** — pass `--no-telemetry` to any command:
|
|
1202
|
+
|
|
1203
|
+
```bash
|
|
1204
|
+
browser-devtools-cli --no-telemetry navigation go-to --url "https://example.com"
|
|
1205
|
+
```
|
|
1206
|
+
|
|
1207
|
+
To disable telemetry permanently for all CLI invocations, add an alias to your shell profile:
|
|
1208
|
+
|
|
1209
|
+
```bash
|
|
1210
|
+
# ~/.zshrc or ~/.bashrc
|
|
1211
|
+
alias browser-devtools-cli="browser-devtools-cli --no-telemetry"
|
|
1212
|
+
```
|
|
1213
|
+
|
|
1214
|
+
Once disabled, no data is sent and no network requests are made to PostHog.
|
|
1215
|
+
|
|
1159
1216
|
## Browser Platform Tools
|
|
1160
1217
|
|
|
1161
1218
|
### Content Tools
|
|
@@ -1387,17 +1444,9 @@ The server can be configured using environment variables. Configuration is divid
|
|
|
1387
1444
|
</details>
|
|
1388
1445
|
|
|
1389
1446
|
<details>
|
|
1390
|
-
<summary><code>navigation_go-back</code> - Navigates
|
|
1391
|
-
|
|
1392
|
-
**Parameters:** `timeout`, `waitUntil`, `includeSnapshot` (default true), `snapshotInteractiveOnly`, `snapshotCursorInteractive` — same semantics as navigation_go-to for snapshot/refs.
|
|
1393
|
-
|
|
1394
|
-
**Returns:** `url`, `status`, `statusText`, `ok`; when includeSnapshot is true also `output` and `refs` (ARIA snapshot with refs).
|
|
1395
|
-
</details>
|
|
1396
|
-
|
|
1397
|
-
<details>
|
|
1398
|
-
<summary><code>navigation_go-forward</code> - Navigates forward in browser history.</summary>
|
|
1447
|
+
<summary><code>navigation_go-back-or-forward</code> - Navigates back or forward in browser history.</summary>
|
|
1399
1448
|
|
|
1400
|
-
**Parameters:** `timeout`, `waitUntil`, `includeSnapshot` (default true), `snapshotInteractiveOnly`, `snapshotCursorInteractive` — same semantics as navigation_go-to for snapshot/refs.
|
|
1449
|
+
**Parameters:** `direction` (required: `"back"` or `"forward"`), `timeout`, `waitUntil`, `includeSnapshot` (default true), `snapshotInteractiveOnly`, `snapshotCursorInteractive` — same semantics as navigation_go-to for snapshot/refs.
|
|
1401
1450
|
|
|
1402
1451
|
**Returns:** `url`, `status`, `statusText`, `ok`; when includeSnapshot is true also `output` and `refs` (ARIA snapshot with refs).
|
|
1403
1452
|
</details>
|
|
@@ -1675,13 +1724,13 @@ The server can be configured using environment variables. Configuration is divid
|
|
|
1675
1724
|
- `output` (string): Includes the page URL, title, and a YAML-formatted accessibility tree
|
|
1676
1725
|
|
|
1677
1726
|
**Usage:**
|
|
1678
|
-
- Use in combination with `
|
|
1727
|
+
- Use in combination with `a11y_take-ax-tree-snapshot` for comprehensive UI analysis
|
|
1679
1728
|
- Provides semantic structure and accessibility roles
|
|
1680
1729
|
- Helps identify accessibility issues and page hierarchy problems
|
|
1681
1730
|
</details>
|
|
1682
1731
|
|
|
1683
1732
|
<details>
|
|
1684
|
-
<summary><code>
|
|
1733
|
+
<summary><code>a11y_take-ax-tree-snapshot</code> - Captures a UI-focused snapshot by combining Chromium's Accessibility (AX) tree with runtime visual diagnostics.</summary>
|
|
1685
1734
|
|
|
1686
1735
|
**Parameters:**
|
|
1687
1736
|
- `roles` (array, optional): Optional role allowlist (button, link, textbox, checkbox, radio, combobox, switch, tab, menuitem, dialog, heading, listbox, listitem, option). If omitted, a built-in set of interactive roles is used
|
|
@@ -2007,6 +2056,52 @@ npm run build
|
|
|
2007
2056
|
- `npm run inspector:http` - Run MCP Inspector (HTTP)
|
|
2008
2057
|
- `npm run lint:check` - Check code formatting
|
|
2009
2058
|
- `npm run lint:format` - Format code
|
|
2059
|
+
- `npm run tools:token-report` - Generate tool definition token consumption report (see below)
|
|
2060
|
+
|
|
2061
|
+
#### Tool definition token report
|
|
2062
|
+
|
|
2063
|
+
The script counts tokens for each tool’s MCP definition (name, description, inputSchema, outputSchema) using **gpt-tokenizer** (OpenAI-style BPE). Useful for understanding context size when clients load the tool list.
|
|
2064
|
+
|
|
2065
|
+
When run without `--platform`, **both browser and node** are measured (default). The script starts the MCP server separately for each platform (`PLATFORM=browser` then `PLATFORM=node`), connects as an MCP client, calls `tools/list` for each, and counts characters from the **actual payload** (so the report matches what clients receive per platform). **Requires a built server** (`npm run build`). Run from the repo root.
|
|
2066
|
+
|
|
2067
|
+
```bash
|
|
2068
|
+
# Via npm (recommended): MCP-based, writes to docs/TOOL-DEFINITION-TOKENS.md
|
|
2069
|
+
npm run tools:token-report
|
|
2070
|
+
```
|
|
2071
|
+
|
|
2072
|
+
**Options:**
|
|
2073
|
+
|
|
2074
|
+
| Option | Description |
|
|
2075
|
+
|--------|-------------|
|
|
2076
|
+
| *(default)* | Run server with output schema disabled (measure name + description + inputSchema only; Output schema column omitted); write to `docs/TOOL-DEFINITION-TOKENS.md` |
|
|
2077
|
+
| `--platform browser` or `--platform node` | Run only one platform (faster; report has a single section) |
|
|
2078
|
+
| `--output-schema` | Run server with output schema enabled (include output schema in measurement and table) |
|
|
2079
|
+
| `--no-output-schema` | Explicitly run without output schema (same as default) |
|
|
2080
|
+
| `--stdout` | Print report to stdout instead of writing to the default file |
|
|
2081
|
+
| `--output=path` or `-o path` | Write report to the given file path |
|
|
2082
|
+
|
|
2083
|
+
Examples:
|
|
2084
|
+
|
|
2085
|
+
```bash
|
|
2086
|
+
# Default: measure without output schema, write to docs/TOOL-DEFINITION-TOKENS.md
|
|
2087
|
+
npm run tools:token-report
|
|
2088
|
+
|
|
2089
|
+
# Include output schema in the report
|
|
2090
|
+
npm run tools:token-report -- --output-schema
|
|
2091
|
+
|
|
2092
|
+
# Print to console
|
|
2093
|
+
npm run tools:token-report -- --stdout
|
|
2094
|
+
|
|
2095
|
+
# Only browser or only node platform
|
|
2096
|
+
npm run tools:token-report -- --platform browser
|
|
2097
|
+
npm run tools:token-report -- --platform node
|
|
2098
|
+
|
|
2099
|
+
# Write to a custom file
|
|
2100
|
+
npm run tools:token-report -- --output=./my-report.md
|
|
2101
|
+
npm run tools:token-report -- -o reports/tokens.md
|
|
2102
|
+
```
|
|
2103
|
+
|
|
2104
|
+
The generated report is [docs/TOOL-DEFINITION-TOKENS.md](docs/TOOL-DEFINITION-TOKENS.md).
|
|
2010
2105
|
|
|
2011
2106
|
## Use Cases
|
|
2012
2107
|
|
|
@@ -2017,7 +2112,7 @@ The Node platform enables AI assistants to:
|
|
|
2017
2112
|
1. **Debug Node.js APIs**: Connect to a running server, set tracepoints at API handlers, capture request/response context
|
|
2018
2113
|
2. **Inspect Backend State**: Use watch expressions and tracepoints to understand variable values, call stacks
|
|
2019
2114
|
3. **Catch Exceptions**: Enable exception breakpoints to capture uncaught errors with full stack traces
|
|
2020
|
-
4. **Docker Debugging**: Connect to Node.js processes running inside Docker containers. When the MCP runs in a container, set `NODE_INSPECTOR_HOST=host.docker.internal` and pass the host-mapped debug port to `debug_connect` (e.g. `debug_connect({ containerName: "my-service",
|
|
2115
|
+
4. **Docker Debugging**: Connect to Node.js processes running inside Docker containers. When the MCP runs in a container, set `NODE_INSPECTOR_HOST=host.docker.internal` and pass the host-mapped debug port to `debug_connect` (e.g. `debug_connect({ containerName: "my-service", inspectorPort: 30019 })`).
|
|
2021
2116
|
|
|
2022
2117
|
### Browser Platform Use Cases
|
|
2023
2118
|
|
|
@@ -2040,7 +2135,7 @@ The Browser platform enables AI assistants to:
|
|
|
2040
2135
|
3. Take a screenshot with `content_take-screenshot` to see the current state
|
|
2041
2136
|
4. Check console messages with `o11y_get-console-messages` for errors
|
|
2042
2137
|
5. Monitor HTTP requests with `o11y_get-http-requests` to see API calls
|
|
2043
|
-
6. Capture accessibility snapshots with `a11y_take-aria-snapshot` and `
|
|
2138
|
+
6. Capture accessibility snapshots with `a11y_take-aria-snapshot` and `a11y_take-ax-tree-snapshot` to understand page structure
|
|
2044
2139
|
7. Compare page with Figma design using `figma_compare-page-with-design` to validate design parity
|
|
2045
2140
|
8. Interact with elements using `interaction_click`, `interaction_fill`, etc.
|
|
2046
2141
|
9. Extract content using `content_get-as-html` or `content_get-as-text`
|
package/SECURITY.md
CHANGED
|
@@ -66,8 +66,6 @@ Browser DevTools MCP provides powerful browser automation capabilities. Users sh
|
|
|
66
66
|
- Tracepoints capture call stack and local variables (may include sensitive data)
|
|
67
67
|
- Logpoints evaluate expressions in page context
|
|
68
68
|
- Exception snapshots capture error state and stack traces
|
|
69
|
-
- Network monitors (netpoints) capture request/response bodies
|
|
70
|
-
- DOM monitors (dompoints) capture element mutations
|
|
71
69
|
- Snapshots are stored in memory and cleared on session end
|
|
72
70
|
|
|
73
71
|
### API Keys and Secrets
|
package/dist/cli/runner.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{platformInfo}from"../core-GIHDFCBF.js";import{AMAZON_BEDROCK_ENABLE,AMAZON_BEDROCK_IMAGE_EMBED_MODEL_ID,AMAZON_BEDROCK_TEXT_EMBED_MODEL_ID,AMAZON_BEDROCK_VISION_MODEL_ID,AWS_PROFILE,AWS_REGION,DAEMON_PORT,DAEMON_SESSION_IDLE_CHECK_SECONDS,DAEMON_SESSION_IDLE_SECONDS,FIGMA_ACCESS_TOKEN,FIGMA_API_BASE_URL,OTEL_ENABLE,OTEL_EXPORTER_HTTP_URL,OTEL_EXPORTER_TYPE,OTEL_SERVICE_NAME,OTEL_SERVICE_VERSION}from"../core-247YVH6X.js";import{Command,Option}from"commander";import{ZodFirstPartyTypeKind}from"zod";function _unwrapZodType(zodType){let current=zodType,isOptional=!1,defaultValue;for(;;){let typeName=current._def.typeName;if(typeName===ZodFirstPartyTypeKind.ZodOptional)isOptional=!0,current=current._def.innerType;else if(typeName===ZodFirstPartyTypeKind.ZodDefault)isOptional=!0,defaultValue=current._def.defaultValue(),current=current._def.innerType;else if(typeName===ZodFirstPartyTypeKind.ZodNullable)isOptional=!0,current=current._def.innerType;else break}return{innerType:current,isOptional,defaultValue}}function _getDescription(zodType){return zodType._def.description}function _toCamelCase(str){return str.replace(/[-_]([a-z])/g,(_,letter)=>letter.toUpperCase())}function _toKebabCase(str){return str.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}function _createOption(name,zodType){let{innerType,isOptional,defaultValue}=_unwrapZodType(zodType),description=_getDescription(zodType)||`The ${name} value`,flagName=_toKebabCase(name),typeName=innerType._def.typeName,option;switch(typeName){case ZodFirstPartyTypeKind.ZodString:option=new Option(`--${flagName} <string>`,description);break;case ZodFirstPartyTypeKind.ZodNumber:option=new Option(`--${flagName} <number>`,description),option.argParser(value=>{let n=Number(value);if(!Number.isFinite(n))throw new Error(`Invalid number: ${value}`);return n});break;case ZodFirstPartyTypeKind.ZodBoolean:option=new Option(`--${flagName}`,description);break;case ZodFirstPartyTypeKind.ZodEnum:let enumValues=innerType._def.values;option=new Option(`--${flagName} <choice>`,description).choices(enumValues);break;case ZodFirstPartyTypeKind.ZodArray:option=new Option(`--${flagName} <value...>`,description);break;case ZodFirstPartyTypeKind.ZodObject:case ZodFirstPartyTypeKind.ZodRecord:option=new Option(`--${flagName} <json>`,description),option.argParser(value=>{try{return JSON.parse(value)}catch{throw new Error(`Invalid JSON: ${value}`)}});break;case ZodFirstPartyTypeKind.ZodAny:case ZodFirstPartyTypeKind.ZodUnknown:option=new Option(`--${flagName} <value>`,description),option.argParser(value=>{try{return JSON.parse(value)}catch{return value}});break;case ZodFirstPartyTypeKind.ZodLiteral:let literalValue=innerType._def.value;typeof literalValue=="boolean"?option=new Option(`--${flagName}`,description):(option=new Option(`--${flagName} <value>`,description),option.default(literalValue));break;case ZodFirstPartyTypeKind.ZodUnion:let unionOptions=innerType._def.options;if(unionOptions.every(opt=>opt._def.typeName===ZodFirstPartyTypeKind.ZodLiteral)){let choices=unionOptions.map(opt=>String(opt._def.value));option=new Option(`--${flagName} <choice>`,description).choices(choices)}else option=new Option(`--${flagName} <value>`,description),option.argParser(value=>{try{return JSON.parse(value)}catch{return value}});break;default:option=new Option(`--${flagName} <value>`,description);break}return defaultValue!==void 0&&option.default(defaultValue),!isOptional&&defaultValue===void 0&&option.makeOptionMandatory(!0),option}function _generateOptionsFromSchema(schema){let options=[];for(let[name,zodType]of Object.entries(schema)){let option=_createOption(name,zodType);option&&options.push(option)}return options}function _parseOptionsToToolInput(options){let result={};for(let[key,value]of Object.entries(options)){let camelKey=_toCamelCase(key);value!==void 0&&(result[camelKey]=value)}return result}function _parseToolName(toolName){let underscoreIndex=toolName.indexOf("_");return underscoreIndex===-1?{domain:"default",commandName:toolName}:{domain:toolName.substring(0,underscoreIndex),commandName:toolName.substring(underscoreIndex+1)}}function registerToolCommands(program,tools2,handler){let domainCommands=new Map;for(let tool of tools2){let{domain,commandName}=_parseToolName(tool.name()),domainCommand=domainCommands.get(domain);domainCommand||(domainCommand=new Command(domain).description(`${domain.charAt(0).toUpperCase()+domain.slice(1)} commands`),domainCommands.set(domain,domainCommand),program.addCommand(domainCommand));let toolCommand=new Command(commandName).description(tool.description().trim()),options=_generateOptionsFromSchema(tool.inputSchema());for(let option of options)toolCommand.addOption(option);toolCommand.action(async opts=>{let toolInput=_parseOptionsToToolInput(opts),globalOptions=program.opts();await handler(tool.name(),toolInput,globalOptions)}),domainCommand.addCommand(toolCommand)}}import{spawn,execSync}from"node:child_process";import{createRequire}from"node:module";import*as path from"node:path";import*as readline from"node:readline";import{fileURLToPath}from"node:url";import{Command as Command2,Option as Option2}from"commander";var require2=createRequire(import.meta.url),__filename=fileURLToPath(import.meta.url),__dirname=path.dirname(__filename),cliProvider=platformInfo.cliInfo.cliProvider,tools=cliProvider.tools,DEFAULT_TIMEOUT=3e4,verboseEnabled=!1,quietEnabled=!1;function _debug(message,data){if(verboseEnabled){let timestamp=new Date().toISOString();data!==void 0?console.error(`[${timestamp}] [DEBUG] ${message}`,data):console.error(`[${timestamp}] [DEBUG] ${message}`)}}function _output(message){quietEnabled||console.log(message)}function _error(message){console.error(message)}async function _isDaemonRunning(port){_debug(`Checking if daemon is running on port ${port}`);try{let response=await fetch(`http://localhost:${port}/health`,{method:"GET",signal:AbortSignal.timeout(3e3)});if(response.ok){let isRunning=(await response.json()).status==="ok";return _debug(`Daemon health check result: ${isRunning?"running":"not running"}`),isRunning}return _debug(`Daemon health check failed: HTTP ${response.status}`),!1}catch(err){return _debug(`Daemon health check error: ${err.message}`),!1}}function _buildDaemonEnv(opts){return cliProvider.buildEnv(opts)}function _startDaemonDetached(opts){let daemonServerPath=path.join(__dirname,"..","daemon-server.js"),env=_buildDaemonEnv(opts);_debug(`Starting daemon server from: ${daemonServerPath}`),_debug(`Daemon port: ${opts.port}`);let child=spawn(process.execPath,[daemonServerPath,"--port",String(opts.port)],{detached:!0,stdio:"ignore",env});child.unref(),_debug(`Daemon process spawned with PID: ${child.pid}`),_output(`Started daemon server as detached process (PID: ${child.pid})`)}async function _ensureDaemonRunning(opts){if(await _isDaemonRunning(opts.port))_debug("Daemon is already running");else{_output(`Daemon server is not running on port ${opts.port}, starting...`),_startDaemonDetached(opts);let maxRetries=10,retryDelay=500;_debug(`Waiting for daemon to be ready (max ${maxRetries} retries, ${retryDelay}ms delay)`);for(let i=0;i<maxRetries;i++)if(await new Promise(resolve=>setTimeout(resolve,retryDelay)),_debug(`Retry ${i+1}/${maxRetries}: checking daemon status...`),await _isDaemonRunning(opts.port)){_debug("Daemon is now ready"),_output("Daemon server is ready");return}throw new Error(`Daemon server failed to start within ${maxRetries*retryDelay/1e3} seconds`)}}async function _stopDaemon(port,timeout){try{return(await fetch(`http://localhost:${port}/shutdown`,{method:"POST",signal:AbortSignal.timeout(timeout)})).ok}catch{return!1}}async function _callTool(port,toolName,toolInput,sessionId,timeout){let headers={"Content-Type":"application/json"};sessionId&&(headers["session-id"]=sessionId);let request={toolName,toolInput};_debug(`Calling tool: ${toolName}`),_debug("Tool input:",toolInput),_debug(`Session ID: ${sessionId||"(default)"}`),_debug(`Timeout: ${timeout||"none"}`);let startTime=Date.now(),response=await fetch(`http://localhost:${port}/call`,{method:"POST",headers,body:JSON.stringify(request),signal:timeout?AbortSignal.timeout(timeout):void 0}),duration=Date.now()-startTime;if(_debug(`Tool call completed in ${duration}ms, status: ${response.status}`),!response.ok){let errorBody=await response.json().catch(()=>({}));throw _debug("Tool call error:",errorBody),new Error(errorBody?.error?.message||`HTTP ${response.status}: ${response.statusText}`)}let result=await response.json();return _debug("Tool call result:",result.toolError?{error:result.toolError}:{success:!0}),result}async function _deleteSession(port,sessionId,timeout){try{return(await fetch(`http://localhost:${port}/session`,{method:"DELETE",headers:{"session-id":sessionId},signal:AbortSignal.timeout(timeout)})).ok}catch{return!1}}async function _getDaemonInfo(port,timeout){try{let response=await fetch(`http://localhost:${port}/info`,{method:"GET",signal:AbortSignal.timeout(timeout)});return response.ok?await response.json():null}catch{return null}}async function _listSessions(port,timeout){try{let response=await fetch(`http://localhost:${port}/sessions`,{method:"GET",signal:AbortSignal.timeout(timeout)});return response.ok?await response.json():null}catch{return null}}async function _getSessionInfo(port,sessionId,timeout){try{let response=await fetch(`http://localhost:${port}/session`,{method:"GET",headers:{"session-id":sessionId},signal:AbortSignal.timeout(timeout)});return response.ok?await response.json():null}catch{return null}}function _formatUptime(seconds){let days=Math.floor(seconds/86400),hours=Math.floor(seconds%86400/3600),minutes=Math.floor(seconds%3600/60),secs=seconds%60,parts=[];return days>0&&parts.push(`${days}d`),hours>0&&parts.push(`${hours}h`),minutes>0&&parts.push(`${minutes}m`),parts.push(`${secs}s`),parts.join(" ")}function _formatTimestamp(timestamp){return new Date(timestamp).toISOString()}function _getZodTypeName(schema){let typeName=schema._def.typeName;return typeName==="ZodOptional"||typeName==="ZodNullable"||typeName==="ZodDefault"?_getZodTypeName(schema._def.innerType):typeName==="ZodArray"?`${_getZodTypeName(schema._def.type)}[]`:typeName==="ZodEnum"?schema._def.values.join(" | "):typeName==="ZodLiteral"?JSON.stringify(schema._def.value):typeName==="ZodUnion"?schema._def.options.map(opt=>_getZodTypeName(opt)).join(" | "):{ZodString:"string",ZodNumber:"number",ZodBoolean:"boolean",ZodObject:"object",ZodRecord:"Record<string, any>",ZodAny:"any"}[typeName]||typeName.replace("Zod","").toLowerCase()}function _getZodDescription(schema){if(schema._def.description)return schema._def.description;if(schema._def.typeName==="ZodOptional"||schema._def.typeName==="ZodNullable"||schema._def.typeName==="ZodDefault")return _getZodDescription(schema._def.innerType)}function _isZodOptional(schema){let typeName=schema._def.typeName;return typeName==="ZodOptional"||typeName==="ZodNullable"}function _hasZodDefault(schema){return schema._def.typeName==="ZodDefault"?!0:schema._def.typeName==="ZodOptional"||schema._def.typeName==="ZodNullable"?_hasZodDefault(schema._def.innerType):!1}function _getZodDefault(schema){if(schema._def.typeName==="ZodDefault")return schema._def.defaultValue();if(schema._def.typeName==="ZodOptional"||schema._def.typeName==="ZodNullable")return _getZodDefault(schema._def.innerType)}function _formatOutput(output,indent=0){let prefix=" ".repeat(indent);if(output==null)return`${prefix}(empty)`;if(typeof output=="string")return output.split(`
|
|
2
|
+
import{isToolEnabled,platformInfo}from"../core-RRWTV5B5.js";import{AMAZON_BEDROCK_ENABLE,AMAZON_BEDROCK_IMAGE_EMBED_MODEL_ID,AMAZON_BEDROCK_TEXT_EMBED_MODEL_ID,AMAZON_BEDROCK_VISION_MODEL_ID,AWS_PROFILE,AWS_REGION,DAEMON_PORT,DAEMON_SESSION_IDLE_CHECK_SECONDS,DAEMON_SESSION_IDLE_SECONDS,FIGMA_ACCESS_TOKEN,FIGMA_API_BASE_URL,OTEL_ENABLE,OTEL_EXPORTER_HTTP_URL,OTEL_EXPORTER_TYPE,OTEL_SERVICE_NAME,OTEL_SERVICE_VERSION}from"../core-DOXUXYCD.js";import{Command,Option}from"commander";import{ZodFirstPartyTypeKind}from"zod";function _unwrapZodType(zodType){let current=zodType,isOptional=!1,defaultValue;for(;;){let typeName=current._def.typeName;if(typeName===ZodFirstPartyTypeKind.ZodOptional)isOptional=!0,current=current._def.innerType;else if(typeName===ZodFirstPartyTypeKind.ZodDefault)isOptional=!0,defaultValue=current._def.defaultValue(),current=current._def.innerType;else if(typeName===ZodFirstPartyTypeKind.ZodNullable)isOptional=!0,current=current._def.innerType;else break}return{innerType:current,isOptional,defaultValue}}function _getDescription(zodType){return zodType._def.description}function _toCamelCase(str){return str.replace(/[-_]([a-z])/g,(_,letter)=>letter.toUpperCase())}function _toKebabCase(str){return str.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}function _createOption(name,zodType){let{innerType,isOptional,defaultValue}=_unwrapZodType(zodType),description=_getDescription(zodType)||`The ${name} value`,flagName=_toKebabCase(name),typeName=innerType._def.typeName,option;switch(typeName){case ZodFirstPartyTypeKind.ZodString:option=new Option(`--${flagName} <string>`,description);break;case ZodFirstPartyTypeKind.ZodNumber:option=new Option(`--${flagName} <number>`,description),option.argParser(value=>{let n=Number(value);if(!Number.isFinite(n))throw new Error(`Invalid number: ${value}`);return n});break;case ZodFirstPartyTypeKind.ZodBoolean:option=new Option(`--${flagName}`,description);break;case ZodFirstPartyTypeKind.ZodEnum:let enumValues=innerType._def.values;option=new Option(`--${flagName} <choice>`,description).choices(enumValues);break;case ZodFirstPartyTypeKind.ZodArray:option=new Option(`--${flagName} <value...>`,description);break;case ZodFirstPartyTypeKind.ZodObject:case ZodFirstPartyTypeKind.ZodRecord:option=new Option(`--${flagName} <json>`,description),option.argParser(value=>{try{return JSON.parse(value)}catch{throw new Error(`Invalid JSON: ${value}`)}});break;case ZodFirstPartyTypeKind.ZodAny:case ZodFirstPartyTypeKind.ZodUnknown:option=new Option(`--${flagName} <value>`,description),option.argParser(value=>{try{return JSON.parse(value)}catch{return value}});break;case ZodFirstPartyTypeKind.ZodLiteral:let literalValue=innerType._def.value;typeof literalValue=="boolean"?option=new Option(`--${flagName}`,description):(option=new Option(`--${flagName} <value>`,description),option.default(literalValue));break;case ZodFirstPartyTypeKind.ZodUnion:let unionOptions=innerType._def.options;if(unionOptions.every(opt=>opt._def.typeName===ZodFirstPartyTypeKind.ZodLiteral)){let choices=unionOptions.map(opt=>String(opt._def.value));option=new Option(`--${flagName} <choice>`,description).choices(choices)}else option=new Option(`--${flagName} <value>`,description),option.argParser(value=>{try{return JSON.parse(value)}catch{return value}});break;default:option=new Option(`--${flagName} <value>`,description);break}return defaultValue!==void 0&&option.default(defaultValue),!isOptional&&defaultValue===void 0&&option.makeOptionMandatory(!0),option}function _generateOptionsFromSchema(schema,toolName){let options=[];for(let[name,zodType]of Object.entries(schema)){let option=_createOption(name,zodType);option&&options.push(option)}return options}function _parseOptionsToToolInput(options){let result={};for(let[key,value]of Object.entries(options)){let camelKey=_toCamelCase(key);value!==void 0&&(result[camelKey]=value)}return result}function _parseToolName(toolName){let underscoreIndex=toolName.indexOf("_");return underscoreIndex===-1?{domain:"default",commandName:toolName}:{domain:toolName.substring(0,underscoreIndex),commandName:toolName.substring(underscoreIndex+1)}}function registerToolCommands(program,tools2,handler){let domainCommands=new Map;for(let tool of tools2){let{domain,commandName}=_parseToolName(tool.name()),domainCommand=domainCommands.get(domain);domainCommand||(domainCommand=new Command(domain).description(`${domain.charAt(0).toUpperCase()+domain.slice(1)} commands`),domainCommands.set(domain,domainCommand),program.addCommand(domainCommand));let toolCommand=new Command(commandName).description(tool.description().trim()),options=_generateOptionsFromSchema(tool.inputSchema(),tool.name());for(let option of options)toolCommand.addOption(option);toolCommand.action(async opts=>{let toolInput=_parseOptionsToToolInput(opts),globalOptions=program.opts();await handler(tool.name(),toolInput,globalOptions)}),domainCommand.addCommand(toolCommand)}}import{spawn,execSync}from"node:child_process";import{createRequire}from"node:module";import*as path from"node:path";import*as readline from"node:readline";import{fileURLToPath}from"node:url";import{Command as Command2,Option as Option2}from"commander";var require2=createRequire(import.meta.url),__filename=fileURLToPath(import.meta.url),__dirname=path.dirname(__filename),cliProvider=platformInfo.cliInfo.cliProvider,tools=cliProvider.tools.filter(isToolEnabled),DEFAULT_TIMEOUT=3e4,verboseEnabled=!1,quietEnabled=!1;function _debug(message,data){if(verboseEnabled){let timestamp=new Date().toISOString();data!==void 0?console.error(`[${timestamp}] [DEBUG] ${message}`,data):console.error(`[${timestamp}] [DEBUG] ${message}`)}}function _output(message){quietEnabled||console.log(message)}function _error(message){console.error(message)}async function _isDaemonRunning(port){_debug(`Checking if daemon is running on port ${port}`);try{let response=await fetch(`http://localhost:${port}/health`,{method:"GET",signal:AbortSignal.timeout(3e3)});if(response.ok){let isRunning=(await response.json()).status==="ok";return _debug(`Daemon health check result: ${isRunning?"running":"not running"}`),isRunning}return _debug(`Daemon health check failed: HTTP ${response.status}`),!1}catch(err){return _debug(`Daemon health check error: ${err.message}`),!1}}function _buildDaemonEnv(opts){return cliProvider.buildEnv(opts)}function _startDaemonDetached(opts){let daemonServerPath=path.join(__dirname,"..","daemon-server.js"),env=_buildDaemonEnv(opts);_debug(`Starting daemon server from: ${daemonServerPath}`),_debug(`Daemon port: ${opts.port}`);let child=spawn(process.execPath,[daemonServerPath,"--port",String(opts.port)],{detached:!0,stdio:"ignore",env});child.unref(),_debug(`Daemon process spawned with PID: ${child.pid}`),_output(`Started daemon server as detached process (PID: ${child.pid})`)}async function _ensureDaemonRunning(opts){if(await _isDaemonRunning(opts.port))_debug("Daemon is already running");else{_output(`Daemon server is not running on port ${opts.port}, starting...`),_startDaemonDetached(opts);let maxRetries=10,retryDelay=500;_debug(`Waiting for daemon to be ready (max ${maxRetries} retries, ${retryDelay}ms delay)`);for(let i=0;i<maxRetries;i++)if(await new Promise(resolve=>setTimeout(resolve,retryDelay)),_debug(`Retry ${i+1}/${maxRetries}: checking daemon status...`),await _isDaemonRunning(opts.port)){_debug("Daemon is now ready"),_output("Daemon server is ready");return}throw new Error(`Daemon server failed to start within ${maxRetries*retryDelay/1e3} seconds`)}}async function _stopDaemon(port,timeout){try{return(await fetch(`http://localhost:${port}/shutdown`,{method:"POST",signal:AbortSignal.timeout(timeout)})).ok}catch{return!1}}async function _callTool(port,toolName,toolInput,sessionId,timeout){let headers={"Content-Type":"application/json"};sessionId&&(headers["session-id"]=sessionId);let request={toolName,toolInput};_debug(`Calling tool: ${toolName}`),_debug("Tool input:",toolInput),_debug(`Session ID: ${sessionId||"(default)"}`),_debug(`Timeout: ${timeout||"none"}`);let startTime=Date.now(),response=await fetch(`http://localhost:${port}/call`,{method:"POST",headers,body:JSON.stringify(request),signal:timeout?AbortSignal.timeout(timeout):void 0}),duration=Date.now()-startTime;if(_debug(`Tool call completed in ${duration}ms, status: ${response.status}`),!response.ok){let errorBody=await response.json().catch(()=>({}));_debug("Tool call error:",errorBody);let message=errorBody?.toolError?.message||errorBody?.error?.message||`HTTP ${response.status}: ${response.statusText}`;throw new Error(message)}let result=await response.json();return _debug("Tool call result:",result.toolError?{error:result.toolError}:{success:!0}),result}async function _deleteSession(port,sessionId,timeout){try{return(await fetch(`http://localhost:${port}/session`,{method:"DELETE",headers:{"session-id":sessionId},signal:AbortSignal.timeout(timeout)})).ok}catch{return!1}}async function _getDaemonInfo(port,timeout){try{let response=await fetch(`http://localhost:${port}/info`,{method:"GET",signal:AbortSignal.timeout(timeout)});return response.ok?await response.json():null}catch{return null}}async function _listSessions(port,timeout){try{let response=await fetch(`http://localhost:${port}/sessions`,{method:"GET",signal:AbortSignal.timeout(timeout)});return response.ok?await response.json():null}catch{return null}}async function _getSessionInfo(port,sessionId,timeout){try{let response=await fetch(`http://localhost:${port}/session`,{method:"GET",headers:{"session-id":sessionId},signal:AbortSignal.timeout(timeout)});return response.ok?await response.json():null}catch{return null}}function _formatUptime(seconds){let days=Math.floor(seconds/86400),hours=Math.floor(seconds%86400/3600),minutes=Math.floor(seconds%3600/60),secs=seconds%60,parts=[];return days>0&&parts.push(`${days}d`),hours>0&&parts.push(`${hours}h`),minutes>0&&parts.push(`${minutes}m`),parts.push(`${secs}s`),parts.join(" ")}function _formatTimestamp(timestamp){return new Date(timestamp).toISOString()}function _getZodTypeName(schema){let typeName=schema._def.typeName;return typeName==="ZodOptional"||typeName==="ZodNullable"||typeName==="ZodDefault"?_getZodTypeName(schema._def.innerType):typeName==="ZodArray"?`${_getZodTypeName(schema._def.type)}[]`:typeName==="ZodEnum"?schema._def.values.join(" | "):typeName==="ZodLiteral"?JSON.stringify(schema._def.value):typeName==="ZodUnion"?schema._def.options.map(opt=>_getZodTypeName(opt)).join(" | "):{ZodString:"string",ZodNumber:"number",ZodBoolean:"boolean",ZodObject:"object",ZodRecord:"Record<string, any>",ZodAny:"any"}[typeName]||typeName.replace("Zod","").toLowerCase()}function _getZodDescription(schema){if(schema._def.description)return schema._def.description;if(schema._def.typeName==="ZodOptional"||schema._def.typeName==="ZodNullable"||schema._def.typeName==="ZodDefault")return _getZodDescription(schema._def.innerType)}function _isZodOptional(schema){let typeName=schema._def.typeName;return typeName==="ZodOptional"||typeName==="ZodNullable"}function _hasZodDefault(schema){return schema._def.typeName==="ZodDefault"?!0:schema._def.typeName==="ZodOptional"||schema._def.typeName==="ZodNullable"?_hasZodDefault(schema._def.innerType):!1}function _getZodDefault(schema){if(schema._def.typeName==="ZodDefault")return schema._def.defaultValue();if(schema._def.typeName==="ZodOptional"||schema._def.typeName==="ZodNullable")return _getZodDefault(schema._def.innerType)}function _formatOutput(output,indent=0){let prefix=" ".repeat(indent);if(output==null)return`${prefix}(empty)`;if(typeof output=="string")return output.split(`
|
|
3
3
|
`).map(line=>`${prefix}${line}`).join(`
|
|
4
4
|
`);if(typeof output=="number"||typeof output=="boolean")return`${prefix}${output}`;if(Array.isArray(output))return output.length===0?`${prefix}[]`:output.map(item=>_formatOutput(item,indent)).join(`
|
|
5
5
|
`);if(typeof output=="object"){let lines=[];for(let[key,value]of Object.entries(output))value!==void 0&&(typeof value=="object"&&value!==null&&!Array.isArray(value)?(lines.push(`${prefix}${key}:`),lines.push(_formatOutput(value,indent+1))):Array.isArray(value)?(lines.push(`${prefix}${key}:`),lines.push(_formatOutput(value,indent+1))):lines.push(`${prefix}${key}: ${value}`));return lines.join(`
|
|
6
|
-
`)}return`${prefix}${String(output)}`}function _printOutput(data,json,isError=!1){let output=json?JSON.stringify(data,null,2):String(data);isError?console.error(output):console.log(output)}function _addGlobalOptions(cmd){return cmd.addOption(new Option2("--port <number>","Daemon server port").argParser(value=>{let n=Number(value);if(!Number.isInteger(n)||n<1||n>65535)throw new Error("Port must be an integer between 1 and 65535");return n}).default(DAEMON_PORT)).addOption(new Option2("--session-id <string>","Session ID for maintaining state across commands")).addOption(new Option2("--json","Output results as JSON")).addOption(new Option2("--quiet","Suppress log messages, only show output")).addOption(new Option2("--verbose","Enable verbose/debug output")).addOption(new Option2("--timeout <ms>","Timeout for operations in milliseconds").argParser(value=>{let n=Number(value);if(!Number.isFinite(n)||n<0)throw new Error("Timeout must be a positive number");return n}).default(DEFAULT_TIMEOUT)),cliProvider.addOptions(cmd)}async function main(){let program=_addGlobalOptions(new Command2(cliProvider.cliName).description(cliProvider.cliDescription).version(require2("../../package.json").version));program.hook("preAction",thisCommand=>{let opts=thisCommand.opts();opts.verbose&&(verboseEnabled=!0),opts.quiet&&(quietEnabled=!0)
|
|
6
|
+
`)}return`${prefix}${String(output)}`}function _printOutput(data,json,isError=!1){let output=json?JSON.stringify(data,null,2):String(data);isError?console.error(output):console.log(output)}function _addGlobalOptions(cmd){return cmd.addOption(new Option2("--port <number>","Daemon server port").argParser(value=>{let n=Number(value);if(!Number.isInteger(n)||n<1||n>65535)throw new Error("Port must be an integer between 1 and 65535");return n}).default(DAEMON_PORT)).addOption(new Option2("--session-id <string>","Session ID for maintaining state across commands")).addOption(new Option2("--json","Output results as JSON")).addOption(new Option2("--quiet","Suppress log messages, only show output")).addOption(new Option2("--verbose","Enable verbose/debug output")).addOption(new Option2("--timeout <ms>","Timeout for operations in milliseconds").argParser(value=>{let n=Number(value);if(!Number.isFinite(n)||n<0)throw new Error("Timeout must be a positive number");return n}).default(DEFAULT_TIMEOUT)),cliProvider.addOptions(cmd)}async function main(){let program=_addGlobalOptions(new Command2(cliProvider.cliName).description(cliProvider.cliDescription).version(require2("../../package.json").version));program.hook("preAction",(thisCommand,actionCommand)=>{let opts=thisCommand.opts();opts.verbose&&(verboseEnabled=!0),opts.quiet&&(quietEnabled=!0)});let daemonCmd=new Command2("daemon").description("Manage the daemon server");daemonCmd.command("start").description("Start the daemon server").action(async()=>{let opts=program.opts();if(await _isDaemonRunning(opts.port)){opts.json?_printOutput({status:"already_running",port:opts.port},!0):_output(`Daemon server is already running on port ${opts.port}`);return}_startDaemonDetached(opts);let maxRetries=10,retryDelay=500;for(let i=0;i<maxRetries;i++)if(await new Promise(resolve=>setTimeout(resolve,retryDelay)),await _isDaemonRunning(opts.port)){opts.json?_printOutput({status:"started",port:opts.port},!0):_output(`Daemon server started on port ${opts.port}`);return}opts.json?_printOutput({status:"failed",error:"Daemon server failed to start"},!0,!0):_error("Failed to start daemon server"),process.exit(1)}),daemonCmd.command("stop").description("Stop the daemon server").action(async()=>{let opts=program.opts();if(!await _isDaemonRunning(opts.port)){opts.json?_printOutput({status:"not_running",port:opts.port},!0):_output(`Daemon server is not running on port ${opts.port}`);return}await _stopDaemon(opts.port,opts.timeout??DEFAULT_TIMEOUT)?opts.json?_printOutput({status:"stopped",port:opts.port},!0):_output(`Daemon server stopped on port ${opts.port}`):(opts.json?_printOutput({status:"failed",error:"Failed to stop daemon server"},!0,!0):_error("Failed to stop daemon server"),process.exit(1))}),daemonCmd.command("restart").description("Restart the daemon server (stop + start)").action(async()=>{let opts=program.opts(),wasRunning=await _isDaemonRunning(opts.port);wasRunning&&(_debug("Stopping daemon server..."),await _stopDaemon(opts.port,opts.timeout??DEFAULT_TIMEOUT)||(opts.json?_printOutput({status:"failed",error:"Failed to stop daemon server"},!0,!0):_error("Failed to stop daemon server"),process.exit(1)),_debug("Waiting for port to be released..."),await new Promise(resolve=>setTimeout(resolve,1e3))),_debug("Starting daemon server..."),_startDaemonDetached(opts);let maxRetries=10,retryDelay=500;for(let i=0;i<maxRetries;i++)if(await new Promise(resolve=>setTimeout(resolve,retryDelay)),await _isDaemonRunning(opts.port)){opts.json?_printOutput({status:"restarted",port:opts.port},!0):_output(`Daemon server ${wasRunning?"restarted":"started"} on port ${opts.port}`);return}opts.json?_printOutput({status:"failed",error:"Daemon server failed to start"},!0,!0):_error("Failed to start daemon server"),process.exit(1)}),daemonCmd.command("status").description("Check daemon server status").action(async()=>{let opts=program.opts(),isRunning=await _isDaemonRunning(opts.port);opts.json?_printOutput({status:isRunning?"running":"stopped",port:opts.port},!0):_output(isRunning?`Daemon server is running on port ${opts.port}`:`Daemon server is not running on port ${opts.port}`)}),daemonCmd.command("info").description("Get detailed daemon server information").action(async()=>{let opts=program.opts();await _isDaemonRunning(opts.port)||(opts.json?_printOutput({status:"not_running",port:opts.port},!0,!0):_error(`Daemon server is not running on port ${opts.port}`),process.exit(1));let info=await _getDaemonInfo(opts.port,opts.timeout??DEFAULT_TIMEOUT);info?opts.json?_printOutput(info,!0):(_output("Daemon Server Information:"),_output(` Version: ${info.version}`),_output(` Port: ${info.port}`),_output(` Uptime: ${_formatUptime(info.uptime)}`),_output(` Sessions: ${info.sessionCount}`)):(opts.json?_printOutput({status:"error",error:"Failed to get daemon info"},!0,!0):_error("Failed to get daemon info"),process.exit(1))}),program.addCommand(daemonCmd);let sessionCmd=new Command2("session").description(cliProvider.sessionDescription);sessionCmd.command("list").description("List all active sessions").action(async()=>{let opts=program.opts();try{await _ensureDaemonRunning(opts);let result=await _listSessions(opts.port,opts.timeout??DEFAULT_TIMEOUT);if(result)if(opts.json)_printOutput(result,!0);else if(result.sessions.length===0)_output("No active sessions");else{_output(`Active Sessions (${result.sessions.length}):`);for(let session of result.sessions)_output(` ${session.id}`),_output(` Created: ${_formatTimestamp(session.createdAt)}`),_output(` Last Active: ${_formatTimestamp(session.lastActiveAt)}`),_output(` Idle: ${_formatUptime(session.idleSeconds)}`)}else opts.json?_printOutput({status:"error",error:"Failed to list sessions"},!0,!0):_error("Failed to list sessions"),process.exit(1)}catch(err){opts.json?_printOutput({status:"error",error:err.message},!0,!0):_error(`Error: ${err.message}`),process.exit(1)}}),sessionCmd.command("info <session-id>").description("Get information about a specific session").action(async sessionId=>{let opts=program.opts();try{await _ensureDaemonRunning(opts);let info=await _getSessionInfo(opts.port,sessionId,opts.timeout??DEFAULT_TIMEOUT);info?opts.json?_printOutput(info,!0):(_output(`Session: ${info.id}`),_output(` Created: ${_formatTimestamp(info.createdAt)}`),_output(` Last Active: ${_formatTimestamp(info.lastActiveAt)}`),_output(` Idle: ${_formatUptime(info.idleSeconds)}`)):(opts.json?_printOutput({status:"not_found",sessionId},!0,!0):_error(`Session '${sessionId}' not found`),process.exit(1))}catch(err){opts.json?_printOutput({status:"error",error:err.message},!0,!0):_error(`Error: ${err.message}`),process.exit(1)}}),sessionCmd.command("delete <session-id>").description("Delete a specific session").action(async sessionId=>{let opts=program.opts();try{await _ensureDaemonRunning(opts),await _deleteSession(opts.port,sessionId,opts.timeout??DEFAULT_TIMEOUT)?opts.json?_printOutput({status:"deleted",sessionId},!0):_output(`Session '${sessionId}' deleted`):(opts.json?_printOutput({status:"not_found",sessionId},!0,!0):_error(`Session '${sessionId}' not found or already deleted`),process.exit(1))}catch(err){opts.json?_printOutput({status:"error",error:err.message},!0,!0):_error(`Error: ${err.message}`),process.exit(1)}}),program.addCommand(sessionCmd);let toolsCmd=new Command2("tools").description("List and inspect available tools");toolsCmd.command("list").description("List all available tools").option("--domain <domain>","Filter by domain (e.g., navigation, content, interaction)").action(cmdOpts=>{let opts=program.opts(),toolsByDomain=new Map;for(let tool of tools){let domain=tool.name().split("_")[0];cmdOpts.domain&&domain!==cmdOpts.domain||(toolsByDomain.has(domain)||toolsByDomain.set(domain,[]),toolsByDomain.get(domain).push(tool))}if(opts.json){let result=[];for(let[domain,domainTools]of toolsByDomain)result.push({domain,tools:domainTools.map(t=>({name:t.name(),description:t.description().trim().split(`
|
|
7
7
|
`)[0]}))});_printOutput(result,!0)}else{if(toolsByDomain.size===0){_output("No tools found");return}_output(`Available Tools (${tools.length} total):
|
|
8
8
|
`);for(let[domain,domainTools]of toolsByDomain){_output(` ${domain}:`);for(let tool of domainTools){let name=tool.name().split("_")[1]||tool.name(),desc=tool.description().trim().split(`
|
|
9
|
-
`)[0];_output(` ${name.padEnd(30)} ${desc}`)}_output("")}}}),toolsCmd.command("info <tool-name>").description(
|
|
9
|
+
`)[0];_output(` ${name.padEnd(30)} ${desc}`)}_output("")}}}),toolsCmd.command("info <tool-name> [other-parts...]").description('Get detailed information about a specific tool (e.g. "tools info navigation go-to" or "tools info navigation_go-to")').action((toolName,otherParts=[])=>{let opts=program.opts(),resolvedName=otherParts.length>0?[toolName,...otherParts].join("_"):toolName,tool=tools.find(t=>t.name()===resolvedName);tool||(tool=tools.find(t=>t.name().split("_")[1]===resolvedName)),tool||(opts.json?_printOutput({status:"not_found",toolName:resolvedName},!0,!0):_error(`Tool '${resolvedName}' not found`),process.exit(1));let inputSchema=tool.inputSchema(),params=[];for(let[key,schema]of Object.entries(inputSchema))params.push({name:key,type:_getZodTypeName(schema),required:!_isZodOptional(schema),description:_getZodDescription(schema),default:_hasZodDefault(schema)?_getZodDefault(schema):void 0});if(opts.json)_printOutput({name:tool.name(),description:tool.description().trim(),parameters:params},!0);else{let nameParts=tool.name().split("_");if(_output(`Tool: ${tool.name()}`),_output(`Domain: ${nameParts[0]}`),_output(`
|
|
10
10
|
Description:`),_output(tool.description().trim().split(`
|
|
11
11
|
`).map(line=>` ${line}`).join(`
|
|
12
12
|
`)),_output(`
|
|
@@ -146,7 +146,7 @@ A new version is available!`),cmdOpts.check||_output(`Run: npm install -g ${pack
|
|
|
146
146
|
`);try{await _ensureDaemonRunning(opts)}catch(err){_error(`Error: ${err.message}`),process.exit(1)}let replProgram=_createReplProgram(opts),rl=readline.createInterface({input:process.stdin,output:process.stdout,prompt:cliProvider.replPrompt});rl.prompt(),rl.on("line",async line=>{let input=line.trim();if(!input){rl.prompt();return}if((input==="exit"||input==="quit")&&(_output("Goodbye!"),rl.close(),process.exit(0)),input==="help"){_output(`
|
|
147
147
|
REPL Commands:`),_output(" help Show this help"),_output(" exit, quit Exit interactive mode"),_output(`
|
|
148
148
|
Available Commands:`),_output(" status Show daemon status summary"),_output(" config Show current configuration"),_output(" update Check for CLI updates"),_output(" daemon <cmd> Daemon management (start, stop, restart, status, info)"),_output(" session <cmd> Session management (list, info, delete)"),_output(" tools <cmd> Tool discovery (list, search, info)"),_output(" <domain> <tool> Execute a tool (e.g., navigation go-to --url ...)"),_output(`
|
|
149
|
-
Examples:`),_output(" # Daemon & Session"),_output(" daemon status"),_output(" daemon info"),_output(" session list"),_output(" session delete my-session"),_output(""),_output(" # Tool Discovery"),_output(" tools list"),_output(" tools search screenshot"),_output(" tools info navigation_go-to"),_output(""),_output(" # Navigation"),_output(' navigation go-to --url "https://example.com"'),_output(" navigation go-back"),_output(" navigation reload"),_output(""),_output(" # Content"),_output(' content take-screenshot --name "test"'),_output(" content get-as-text"),_output(' content get-as-html --selector "#main"'),_output(""),_output(" # Interaction"),_output(' interaction click --ref "Submit"'),_output(' interaction fill --ref "Email" --value "test@example.com"'),_output(' interaction hover --ref "Menu"'),_output(""),_output(" # Accessibility"),_output(" a11y get-snapshot"),_output(" a11y get-ax-tree-snapshot"),_output(`
|
|
149
|
+
Examples:`),_output(" # Daemon & Session"),_output(" daemon status"),_output(" daemon info"),_output(" session list"),_output(" session delete my-session"),_output(""),_output(" # Tool Discovery"),_output(" tools list"),_output(" tools search screenshot"),_output(" tools info navigation_go-to"),_output(""),_output(" # Navigation"),_output(' navigation go-to --url "https://example.com"'),_output(" navigation go-back-or-forward --direction back"),_output(" navigation reload"),_output(""),_output(" # Content"),_output(' content take-screenshot --name "test"'),_output(" content get-as-text"),_output(' content get-as-html --selector "#main"'),_output(""),_output(" # Interaction"),_output(' interaction click --ref "Submit"'),_output(' interaction fill --ref "Email" --value "test@example.com"'),_output(' interaction hover --ref "Menu"'),_output(""),_output(" # Accessibility"),_output(" a11y get-snapshot"),_output(" a11y get-ax-tree-snapshot"),_output(`
|
|
150
150
|
Tip: Use global options when starting interactive mode:`);for(let example of cliProvider.cliExamples)_output(` ${example}`);_output(""),rl.prompt();return}try{let args=_parseReplInput(input);await replProgram.parseAsync(["node","repl",...args])}catch(err){err.code==="commander.help"||(err.code==="commander.unknownCommand"?(_output(`Unknown command: ${input}`),_output('Type "help" for available commands')):err.code==="commander.missingArgument"?_error(`Missing argument: ${err.message}`):err.code==="commander.invalidArgument"?_error(`Invalid argument: ${err.message}`):err.code&&err.code.startsWith("commander.")||_error(`Error: ${err.message}`))}rl.prompt()}),rl.on("close",()=>{process.exit(0)})});program.addCommand(interactiveCmd);let updateCmd=new Command2("update").description("Check for updates and optionally install them").option("--check","Only check for updates without installing").action(async cmdOpts=>{let opts=program.opts(),currentVersion=require2("../../package.json").version,packageName=cliProvider.packageName;_output(`Checking for updates...
|
|
151
151
|
`);try{let response=await fetch(`https://registry.npmjs.org/${packageName}/latest`,{method:"GET",signal:AbortSignal.timeout(1e4)});if(!response.ok)throw new Error(`Failed to check npm registry: HTTP ${response.status}`);let latestVersion=(await response.json()).version;if(opts.json){_printOutput({currentVersion,latestVersion,updateAvailable:latestVersion!==currentVersion},!0);return}if(_output(` Current version: ${currentVersion}`),_output(` Latest version: ${latestVersion}`),_output(""),latestVersion===currentVersion){_output("\x1B[32m\u2713 You are using the latest version!\x1B[0m");return}let currentParts=currentVersion.split(".").map(Number),latestParts=latestVersion.split(".").map(Number),isNewer=!1;for(let i=0;i<3;i++)if(latestParts[i]>currentParts[i]){isNewer=!0;break}else if(latestParts[i]<currentParts[i])break;if(!isNewer){_output("\x1B[32m\u2713 You are using a newer version than published!\x1B[0m");return}if(_output(`\x1B[33m\u26A0 Update available: ${currentVersion} \u2192 ${latestVersion}\x1B[0m
|
|
152
152
|
`),cmdOpts.check){_output("To update, run:"),_output(` npm install -g ${packageName}@latest`),_output("or"),_output(` npx ${packageName}@latest`);return}let rl=readline.createInterface({input:process.stdin,output:process.stdout}),answer=await new Promise(resolve=>{rl.question("Do you want to update now? (y/N) ",ans=>{rl.close(),resolve(ans.toLowerCase())})});if(answer!=="y"&&answer!=="yes"){_output(`
|