browser-devtools-mcp 0.5.3 → 0.6.0
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 +42 -7
- package/dist/cli/runner.js +1 -1
- package/dist/collector/index.d.ts +4 -0
- package/dist/collector/types.d.ts +27 -0
- package/dist/{core-X7CLDI7H.js → core-5GP5ISLC.js} +1 -1
- package/dist/{core-VG5O43O7.js → core-MEE5B4UB.js} +74 -48
- package/dist/{core-P5HBF7J2.js → core-X3FD2EZG.js} +2 -2
- package/dist/{core-UCG5EXSY.js → core-Y6NR2NG6.js} +2 -2
- package/dist/daemon-server.js +1 -1
- package/dist/index.js +2 -2
- package/dist/platform/browser/otel/otel-initializer.bundle.js +1 -1
- package/dist/platform/browser/tools/index.d.ts +1 -0
- package/dist/platform/browser/tools/scenario/index.d.ts +7 -0
- package/dist/scenario/index.d.ts +3 -0
- package/dist/scenario/types.d.ts +9 -0
- package/dist/search/index.d.ts +3 -0
- package/dist/search/types.d.ts +20 -0
- package/dist/tools/index.d.ts +2 -1
- package/dist/tools/types.d.ts +17 -0
- package/package.json +11 -4
package/README.md
CHANGED
|
@@ -64,6 +64,7 @@ Choose the platform by running the appropriate MCP server or CLI:
|
|
|
64
64
|
- **Screenshots**: Capture full page or specific elements (PNG/JPEG) with image data; optional `annotate: true` overlays numbered labels (1, 2, ...) on elements from the last ARIA snapshot refs and returns an `annotations` array (ref, number, role, name, box). If the ref map is empty, a snapshot is taken automatically. Set `annotateContent: true` to also include content elements (headings, list items, etc.) in the overlay. Set `annotateCursorInteractive: true` to also include cursor-interactive elements (clickable/focusable by CSS without ARIA role) in the overlay. The `selector` parameter accepts a ref (e.g. `e1`, `@e1`), a getByRole/getByLabel/getByText/etc. expression, or a CSS selector; with `selector` set, only annotations overlapping that element are returned and box coordinates are element-relative; with `fullPage: true` (no selector), box coordinates are document-relative.
|
|
65
65
|
- **HTML/Text Extraction**: Get page content with filtering, cleaning, and minification options
|
|
66
66
|
- **PDF Export**: Save pages as PDF documents with customizable format and margins
|
|
67
|
+
- **Video Recording**: Record browser page interactions as WebM video using CDP screencast. Start with `content_start-recording`, stop with `content_stop-recording`. Works in all modes (headless, headed, persistent, CDP attach). Chromium only.
|
|
67
68
|
|
|
68
69
|
### Interaction Tools
|
|
69
70
|
- **Click**: Click elements by snapshot ref (e.g. `e1`, `@e1`, `ref=e1`), Playwright-style expression (e.g. `getByRole('button', { name: 'Login' })`, `getByLabel('Email')`, `getByText('Register')`, `getByPlaceholder('demo@example.com')`, `getByTitle('…')`, `getByAltText('…')`, `getByTestId('…')`), or CSS selector. Refs come from `a11y_take-aria-snapshot` and are valid until the next snapshot or navigation.
|
|
@@ -91,6 +92,12 @@ Choose the platform by running the appropriate MCP server or CLI:
|
|
|
91
92
|
- **OpenTelemetry Tracing**: Automatic trace injection into web pages, UI trace collection (document load, fetch, XMLHttpRequest, user interactions), and trace context propagation for backend correlation
|
|
92
93
|
- **Trace ID Management**: Get, set, and generate OpenTelemetry compatible trace IDs for distributed tracing across API calls
|
|
93
94
|
|
|
95
|
+
### Scenario Tools
|
|
96
|
+
- **Scenario Add/Update/Delete**: Manage reusable test scenarios stored as JS scripts in `.browser-devtools-mcp/scenarios.json` (project-level or global)
|
|
97
|
+
- **Scenario Run**: Execute a saved scenario by name. Runs in the same sandbox as `execute` — supports `callTool()`, composable via nested `scenario-run` calls (max depth: 5)
|
|
98
|
+
- **Scenario List**: List all available scenarios from project and/or global scope
|
|
99
|
+
- **Scenario Search**: Search scenarios by description using configurable strategy (simple default or FTS5)
|
|
100
|
+
|
|
94
101
|
### Synchronization Tools
|
|
95
102
|
- **Wait for Network Idle**: Wait until the page reaches a network-idle condition based on the session’s tracked in-flight request count (tunable via `sync_wait-for-network-idle` like `idleTimeMs` / `maxConnections`), useful for SPA pages and before taking screenshots
|
|
96
103
|
|
|
@@ -687,9 +694,9 @@ browser-devtools-cli
|
|
|
687
694
|
│ ├── get-console-messages # Get console logs
|
|
688
695
|
│ ├── get-http-requests # Get HTTP requests
|
|
689
696
|
│ ├── get-web-vitals # Get Web Vitals metrics
|
|
690
|
-
│ ├── get-trace-
|
|
697
|
+
│ ├── get-trace-context # Get current trace context
|
|
691
698
|
│ ├── new-trace-id # Generate new trace ID
|
|
692
|
-
│ └── set-trace-
|
|
699
|
+
│ └── set-trace-context # Set trace context
|
|
693
700
|
├── react # React debugging commands
|
|
694
701
|
│ ├── get-component-for-element
|
|
695
702
|
│ └── get-element-for-component
|
|
@@ -1182,7 +1189,7 @@ Tool inputs are validated with a strict schema; unknown or misspelled argument k
|
|
|
1182
1189
|
| `OTEL_SERVICE_NAME` | OpenTelemetry service name | `frontend` |
|
|
1183
1190
|
| `OTEL_SERVICE_VERSION` | OpenTelemetry service version | (none) |
|
|
1184
1191
|
| `OTEL_ASSETS_DIR` | Directory containing OpenTelemetry bundle files | (uses default) |
|
|
1185
|
-
| `OTEL_EXPORTER_TYPE` | OpenTelemetry exporter type: "otlp/http", "console", or "none" | `none` |
|
|
1192
|
+
| `OTEL_EXPORTER_TYPE` | OpenTelemetry exporter type: "otlp/http-json", "otlp/http-protobuf", "console", or "none" (alias: "otlp/http" = "otlp/http-json") | `none` |
|
|
1186
1193
|
| `OTEL_EXPORTER_HTTP_URL` | OpenTelemetry collector base URL (e.g., "http://localhost:4318") | (none) |
|
|
1187
1194
|
| `OTEL_EXPORTER_HTTP_HEADERS` | OpenTelemetry exporter HTTP headers (comma-separated key=value pairs) | (none) |
|
|
1188
1195
|
| `OTEL_INSTRUMENTATION_USER_INTERACTION_EVENTS` | User interaction events to instrument (comma-separated, e.g., "click,submit") | `click` |
|
|
@@ -1359,6 +1366,32 @@ Once disabled, no data is sent and no network requests are made to PostHog.
|
|
|
1359
1366
|
- `filePath` (string): Full path of the saved PDF file
|
|
1360
1367
|
</details>
|
|
1361
1368
|
|
|
1369
|
+
<details>
|
|
1370
|
+
<summary><code>content_start-recording</code> - Starts video recording of the browser page.</summary>
|
|
1371
|
+
|
|
1372
|
+
**Parameters:**
|
|
1373
|
+
- `outputDir` (string, optional): Directory where the video file will be saved (default: OS temp directory)
|
|
1374
|
+
- `name` (string, optional): Name for the video file without extension (default: "recording")
|
|
1375
|
+
**Returns:**
|
|
1376
|
+
- `message` (string): Status message
|
|
1377
|
+
|
|
1378
|
+
**Notes:**
|
|
1379
|
+
- Uses CDP screencast — works in all modes (headless, headed, persistent, CDP attach)
|
|
1380
|
+
- Only supported on Chromium-based browsers
|
|
1381
|
+
- Recording captures all page interactions until `content_stop-recording` is called
|
|
1382
|
+
</details>
|
|
1383
|
+
|
|
1384
|
+
<details>
|
|
1385
|
+
<summary><code>content_stop-recording</code> - Stops video recording and saves the video file.</summary>
|
|
1386
|
+
|
|
1387
|
+
**Returns:**
|
|
1388
|
+
- `filePath` (string, optional): Full path of the saved WebM video file
|
|
1389
|
+
|
|
1390
|
+
**Notes:**
|
|
1391
|
+
- Must be called after `content_start-recording`
|
|
1392
|
+
- The video is saved as a WebM file (VP8 codec)
|
|
1393
|
+
</details>
|
|
1394
|
+
|
|
1362
1395
|
### Interaction Tools
|
|
1363
1396
|
|
|
1364
1397
|
<details>
|
|
@@ -1684,13 +1717,14 @@ await callTool('content_take-screenshot', {}, true);
|
|
|
1684
1717
|
</details>
|
|
1685
1718
|
|
|
1686
1719
|
<details>
|
|
1687
|
-
<summary><code>o11y_get-trace-
|
|
1720
|
+
<summary><code>o11y_get-trace-context</code> - Gets the OpenTelemetry trace context of the current session.</summary>
|
|
1688
1721
|
|
|
1689
1722
|
**Parameters:**
|
|
1690
1723
|
- No input parameters
|
|
1691
1724
|
|
|
1692
1725
|
**Returns:**
|
|
1693
1726
|
- `traceId` (string, optional): The OpenTelemetry compatible trace id of the current session if available
|
|
1727
|
+
- `traceState` (string, optional): The W3C tracestate value of the current session if available
|
|
1694
1728
|
|
|
1695
1729
|
**Note:** Requires OpenTelemetry to be enabled (`OTEL_ENABLE=true`).
|
|
1696
1730
|
</details>
|
|
@@ -1708,15 +1742,16 @@ await callTool('content_take-screenshot', {}, true);
|
|
|
1708
1742
|
</details>
|
|
1709
1743
|
|
|
1710
1744
|
<details>
|
|
1711
|
-
<summary><code>o11y_set-trace-
|
|
1745
|
+
<summary><code>o11y_set-trace-context</code> - Sets or clears the OpenTelemetry trace context of the current session.</summary>
|
|
1712
1746
|
|
|
1713
1747
|
**Parameters:**
|
|
1714
|
-
- `traceId` (string, optional):
|
|
1748
|
+
- `traceId` (string, optional): 32-char lowercase hex trace id (non-all-zero). Pass **empty string** to **clear** the MCP-pinned trace id (new root traces use random ids until you set an id again). Use `o11y_new-trace-id` to pin a fresh random id.
|
|
1749
|
+
- `traceState` (string, optional): W3C `tracestate` list (`key=value` members, comma-separated; max 512 chars / 32 members). Pass **empty string** to **clear** tracestate (no MCP `tracestate` on outgoing requests).
|
|
1715
1750
|
|
|
1716
1751
|
**Returns:**
|
|
1717
1752
|
- No return value
|
|
1718
1753
|
|
|
1719
|
-
**Note:** Requires OpenTelemetry to be enabled (`OTEL_ENABLE=true`).
|
|
1754
|
+
**Note:** Requires OpenTelemetry to be enabled (`OTEL_ENABLE=true`). At least one of `traceId` or `traceState` must appear in the input (each may be an empty string for clear). Invalid `traceState` is rejected with an error. Values are propagated via tracing headers when applicable.
|
|
1720
1755
|
</details>
|
|
1721
1756
|
|
|
1722
1757
|
### Synchronization Tools
|
package/dist/cli/runner.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{isToolEnabled,platformInfo}from"../core-VG5O43O7.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-P5HBF7J2.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 schemaFieldToCliFlag(fieldName){return _toKebabCase(fieldName)}function _createOptionsForField(name,zodType){let{innerType,isOptional,defaultValue}=_unwrapZodType(zodType),description=_getDescription(zodType)||`The ${name} value`,flagName=_toKebabCase(name),typeName=innerType._def.typeName;if(typeName===ZodFirstPartyTypeKind.ZodBoolean){if(defaultValue===!0){let positive=new Option(`--${flagName}`,description);positive.default(!0);let negative=new Option(`--no-${flagName}`,`Disable: ${description}`);return[positive,negative]}let boolOpt=new Option(`--${flagName}`,description);return defaultValue===!1&&boolOpt.default(!1),!isOptional&&defaultValue===void 0&&boolOpt.makeOptionMandatory(!0),[boolOpt]}let 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.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;if(typeof literalValue=="boolean"){if(literalValue===!0){let positive=new Option(`--${flagName}`,description);positive.default(!0);let negative=new Option(`--no-${flagName}`,`Disable: ${description}`);return[positive,negative]}let litFalse=new Option(`--${flagName}`,description);return litFalse.default(!1),[litFalse]}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))name!=="_metadata"&&options.push(..._createOptionsForField(name,zodType));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{existsSync,readFileSync}from"node:fs";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);function _resolveDaemonServerScriptPath(){let dir=__dirname;for(let i=0;i<10;i++){let candidate=path.join(dir,"daemon-server.js");if(existsSync(candidate))return candidate;let parent=path.dirname(dir);if(parent===dir)break;dir=parent}throw new Error("Could not find daemon-server.js (rebuild with npm run build or reinstall the package).")}var 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=_resolveDaemonServerScriptPath(),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(resolve2=>setTimeout(resolve2,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(`
|
|
2
|
+
import{isToolEnabled,platformInfo}from"../core-MEE5B4UB.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-X3FD2EZG.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 schemaFieldToCliFlag(fieldName){return _toKebabCase(fieldName)}function _createOptionsForField(name,zodType){let{innerType,isOptional,defaultValue}=_unwrapZodType(zodType),description=_getDescription(zodType)||`The ${name} value`,flagName=_toKebabCase(name),typeName=innerType._def.typeName;if(typeName===ZodFirstPartyTypeKind.ZodBoolean){if(defaultValue===!0){let positive=new Option(`--${flagName}`,description);positive.default(!0);let negative=new Option(`--no-${flagName}`,`Disable: ${description}`);return[positive,negative]}let boolOpt=new Option(`--${flagName}`,description);return defaultValue===!1&&boolOpt.default(!1),!isOptional&&defaultValue===void 0&&boolOpt.makeOptionMandatory(!0),[boolOpt]}let 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.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;if(typeof literalValue=="boolean"){if(literalValue===!0){let positive=new Option(`--${flagName}`,description);positive.default(!0);let negative=new Option(`--no-${flagName}`,`Disable: ${description}`);return[positive,negative]}let litFalse=new Option(`--${flagName}`,description);return litFalse.default(!1),[litFalse]}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))name!=="_metadata"&&options.push(..._createOptionsForField(name,zodType));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{existsSync,readFileSync}from"node:fs";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);function _resolveDaemonServerScriptPath(){let dir=__dirname;for(let i=0;i<10;i++){let candidate=path.join(dir,"daemon-server.js");if(existsSync(candidate))return candidate;let parent=path.dirname(dir);if(parent===dir)break;dir=parent}throw new Error("Could not find daemon-server.js (rebuild with npm run build or reinstall the package).")}var 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=_resolveDaemonServerScriptPath(),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(resolve2=>setTimeout(resolve2,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(`
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { sendToolCallToCollector } from './collector';
|
|
2
|
+
export { uploadArtifact } from './artifact-uploader';
|
|
3
|
+
export type { ArtifactUploadResult } from './artifact-uploader';
|
|
4
|
+
export type { CollectorEvent, ToolCallResult, CollectorConfig, CollectorMetadata, } from './types';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ToolInputMetadata } from '../tools/types';
|
|
2
|
+
export interface CollectorEvent {
|
|
3
|
+
id: string;
|
|
4
|
+
type: string;
|
|
5
|
+
timestamp: number;
|
|
6
|
+
session_id?: string;
|
|
7
|
+
project_name?: string;
|
|
8
|
+
verification_id?: string;
|
|
9
|
+
trace_id?: string;
|
|
10
|
+
tool_name: string;
|
|
11
|
+
tool_input?: unknown;
|
|
12
|
+
tool_response?: unknown;
|
|
13
|
+
duration: number;
|
|
14
|
+
error?: string;
|
|
15
|
+
source: string;
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
export interface ToolCallResult {
|
|
19
|
+
duration: number;
|
|
20
|
+
tool_response?: unknown;
|
|
21
|
+
error?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface CollectorConfig {
|
|
24
|
+
url: string;
|
|
25
|
+
apiKey?: string;
|
|
26
|
+
}
|
|
27
|
+
export type CollectorMetadata = ToolInputMetadata | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DEFAULT_NODE_DEBUG_CONFIG,ProbeKind,addWatchExpression,clearProbes,clearSnapshots,clearSnapshotsByProbe,clearWatchExpressions,createProbe,detachDebugging,disableDebugging,enableDebugging,evaluateInNode,getConsoleMessages,getExceptionBreakpoint,getOriginalSources,getScripts,getSnapshotStats,getSnapshots,getSnapshotsByProbe,getStore,getStoreKey,hasSourceMaps,isDebuggingEnabled,listProbes,listStoreKeys,listWatchExpressions,loadSourceMaps,removeProbe,removeWatchExpression,resolveSourceLocation,setExceptionBreakpoint}from"./core-
|
|
1
|
+
import{DEFAULT_NODE_DEBUG_CONFIG,ProbeKind,addWatchExpression,clearProbes,clearSnapshots,clearSnapshotsByProbe,clearWatchExpressions,createProbe,detachDebugging,disableDebugging,enableDebugging,evaluateInNode,getConsoleMessages,getExceptionBreakpoint,getOriginalSources,getScripts,getSnapshotStats,getSnapshots,getSnapshotsByProbe,getStore,getStoreKey,hasSourceMaps,isDebuggingEnabled,listProbes,listStoreKeys,listWatchExpressions,loadSourceMaps,removeProbe,removeWatchExpression,resolveSourceLocation,setExceptionBreakpoint}from"./core-X3FD2EZG.js";export{DEFAULT_NODE_DEBUG_CONFIG,ProbeKind,addWatchExpression,clearProbes,clearSnapshots,clearSnapshotsByProbe,clearWatchExpressions,createProbe,detachDebugging,disableDebugging,enableDebugging,evaluateInNode,getConsoleMessages,getExceptionBreakpoint,getOriginalSources,getScripts,getSnapshotStats,getSnapshots,getSnapshotsByProbe,getStore,getStoreKey,hasSourceMaps,isDebuggingEnabled,listProbes,listStoreKeys,listWatchExpressions,loadSourceMaps,removeProbe,removeWatchExpression,resolveSourceLocation,setExceptionBreakpoint};
|