browser-devtools-mcp 0.2.25 → 0.2.27
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 +20 -18
- package/dist/cli/runner.js +1 -1
- package/dist/{core-JLIRPQ77.js → core-247YVH6X.js} +2 -2
- package/dist/{core-QH4KRWJ5.js → core-FCPLN2O4.js} +1 -1
- package/dist/{core-S6ISAJDU.js → core-GIHDFCBF.js} +10 -10
- package/dist/daemon-server.js +1 -1
- package/dist/index.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -61,18 +61,18 @@ Choose the platform by running the appropriate MCP server or CLI:
|
|
|
61
61
|
## Browser Platform Features
|
|
62
62
|
|
|
63
63
|
### Content Tools
|
|
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.
|
|
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
67
|
|
|
68
68
|
### Interaction Tools
|
|
69
|
-
- **Click**: Click elements by
|
|
70
|
-
- **Fill**: Fill form inputs (
|
|
71
|
-
- **Hover**: Hover over elements (
|
|
72
|
-
- **Press Key**: Simulate keyboard input; optional
|
|
73
|
-
- **Select**: Select dropdown options (
|
|
74
|
-
- **Drag**: Drag and drop
|
|
75
|
-
- **Scroll**: Scroll the page viewport or specific scrollable elements with multiple modes (by, to, top, bottom, left, right); optional
|
|
69
|
+
- **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.
|
|
70
|
+
- **Fill**: Fill form inputs (ref, getByRole/getByLabel/getByPlaceholder/etc., or CSS selector)
|
|
71
|
+
- **Hover**: Hover over elements (ref, getByXYZ expression, or CSS selector)
|
|
72
|
+
- **Press Key**: Simulate keyboard input; optional ref, getByXYZ expression, or CSS selector to focus an element before sending the key
|
|
73
|
+
- **Select**: Select dropdown options (ref, getByRole/getByTestId/etc., or CSS selector)
|
|
74
|
+
- **Drag**: Drag and drop (source and target as ref, getByXYZ expression, or CSS selector)
|
|
75
|
+
- **Scroll**: Scroll the page viewport or specific scrollable elements with multiple modes (by, to, top, bottom, left, right); optional ref, getByXYZ, or CSS selector for scrollable container
|
|
76
76
|
- **Resize Viewport**: Resize the page viewport using Playwright viewport emulation
|
|
77
77
|
- **Resize Window**: Resize the real browser window (OS-level) using Chrome DevTools Protocol
|
|
78
78
|
|
|
@@ -97,7 +97,7 @@ Choose the platform by running the appropriate MCP server or CLI:
|
|
|
97
97
|
- **Wait for Network Idle**: Wait until the page reaches a network-idle condition based on in-flight request count, useful for SPA pages and before taking screenshots
|
|
98
98
|
|
|
99
99
|
### Accessibility (A11Y) Tools
|
|
100
|
-
- **ARIA Snapshots**: Capture semantic structure and accessibility roles in YAML format. Returns a tree with element refs (e1, e2, ...) and a `refs` map; refs are stored in session context for use in interaction tools (click, fill, hover, select, drag, scroll, press-key) as the selector (e.g. `e1`, `@e1`, `ref=e1`). Refs are valid until the next ARIA snapshot or navigation—re-snapshot after page/DOM changes. Options: **interactiveOnly** (only interactive elements get refs); **cursorInteractive: true** (also assign refs to elements that are clickable/focusable by CSS but have no ARIA role, e.g. custom div/span buttons); **selector** (scope the snapshot to an element).
|
|
100
|
+
- **ARIA Snapshots**: Capture semantic structure and accessibility roles in YAML format. Returns a tree with element refs (e1, e2, ...) and a `refs` map; refs are stored in session context for use in interaction tools (click, fill, hover, select, drag, scroll, press-key) as the selector (e.g. `e1`, `@e1`, `ref=e1`). You can also use Playwright-style expressions in those tools: `getByRole('button', { name: 'Login' })`, `getByLabel('Email')`, `getByText('Register')`, `getByPlaceholder('…')`, `getByTitle('…')`, `getByAltText('…')`, `getByTestId('…')`, or CSS selectors. Refs are valid until the next ARIA snapshot or navigation—re-snapshot after page/DOM changes. Options: **interactiveOnly** (only interactive elements get refs); **cursorInteractive: true** (also assign refs to elements that are clickable/focusable by CSS but have no ARIA role, e.g. custom div/span buttons); **selector** (scope the snapshot to an element).
|
|
101
101
|
- **AX Tree Snapshots**: Combine Chromium's Accessibility tree with runtime visual diagnostics (bounding boxes, visibility, occlusion detection, computed styles)
|
|
102
102
|
|
|
103
103
|
### Stub Tools
|
|
@@ -1123,6 +1123,8 @@ The server can be configured using environment variables. Configuration is divid
|
|
|
1123
1123
|
| `SESSION_IDLE_SECONDS` | Idle session timeout (seconds) | `300` |
|
|
1124
1124
|
| `SESSION_IDLE_CHECK_SECONDS` | Interval for checking idle sessions (seconds) | `30` |
|
|
1125
1125
|
| `SESSION_CLOSE_ON_SOCKET_CLOSE` | Close session when socket closes | `false` |
|
|
1126
|
+
| `TOOL_OUTPUT_SCHEMA_DISABLE` | When true, omit tool output schema from MCP tool registration (can reduce token usage for some clients) | `false` |
|
|
1127
|
+
| `AVAILABLE_TOOL_DOMAINS` | Optional comma-separated list of tool domains to enable. When set, only tools from these domains are registered; unset means all tools. **Browser domains:** `a11y`, `content`, `debug`, `figma`, `interaction`, `navigation`, `o11y`, `react`, `run`, `stub`, `sync`. **Node domains:** `debug`, `run`. Example: `AVAILABLE_TOOL_DOMAINS=navigation,interaction,a11y` | (all tools) |
|
|
1126
1128
|
|
|
1127
1129
|
### Node Platform Configuration
|
|
1128
1130
|
|
|
@@ -1164,7 +1166,7 @@ The server can be configured using environment variables. Configuration is divid
|
|
|
1164
1166
|
**Parameters:**
|
|
1165
1167
|
- `outputPath` (string, optional): Directory path where screenshot will be saved (default: OS temp directory)
|
|
1166
1168
|
- `name` (string, optional): Screenshot name (default: "screenshot")
|
|
1167
|
-
- `selector` (string, optional): CSS selector for element to capture
|
|
1169
|
+
- `selector` (string, optional): Ref (e.g. `e1`, `@e1`), getByRole/getByLabel/getByText/getByPlaceholder/getByTitle/getByAltText/getByTestId expression, or CSS selector for element to capture
|
|
1168
1170
|
- `fullPage` (boolean, optional): Capture full scrollable page (default: false)
|
|
1169
1171
|
- `type` (enum, optional): Image format - "png" or "jpeg" (default: "png")
|
|
1170
1172
|
- `quality` (number, optional): The quality of the image, between 0-100. Not applicable to PNG images, only used for JPEG format (default: 100)
|
|
@@ -1235,7 +1237,7 @@ The server can be configured using environment variables. Configuration is divid
|
|
|
1235
1237
|
<summary><code>interaction_click</code> - Clicks an element on the page.</summary>
|
|
1236
1238
|
|
|
1237
1239
|
**Parameters:**
|
|
1238
|
-
- `selector` (string, required):
|
|
1240
|
+
- `selector` (string, required): Ref (e.g. `e1`, `@e1`, `ref=e1`), getByRole/getByLabel/getByText/getByPlaceholder/getByTitle/getByAltText/getByTestId expression, or CSS selector for the element to click
|
|
1239
1241
|
- `timeoutMs` (number, optional): Time to wait for the element in ms (default: 10000)
|
|
1240
1242
|
</details>
|
|
1241
1243
|
|
|
@@ -1243,7 +1245,7 @@ The server can be configured using environment variables. Configuration is divid
|
|
|
1243
1245
|
<summary><code>interaction_fill</code> - Fills a form input field.</summary>
|
|
1244
1246
|
|
|
1245
1247
|
**Parameters:**
|
|
1246
|
-
- `selector` (string, required):
|
|
1248
|
+
- `selector` (string, required): Ref (e.g. `e1`, `@e1`), getByRole/getByLabel/getByPlaceholder expression, or CSS selector for the input field
|
|
1247
1249
|
- `value` (string, required): Value to fill
|
|
1248
1250
|
- `timeoutMs` (number, optional): Time to wait for the element in ms (default: 10000)
|
|
1249
1251
|
</details>
|
|
@@ -1252,7 +1254,7 @@ The server can be configured using environment variables. Configuration is divid
|
|
|
1252
1254
|
<summary><code>interaction_hover</code> - Hovers over an element.</summary>
|
|
1253
1255
|
|
|
1254
1256
|
**Parameters:**
|
|
1255
|
-
- `selector` (string, required):
|
|
1257
|
+
- `selector` (string, required): Ref (e.g. `e1`, `@e1`), getByRole/getByText/etc. expression, or CSS selector for the element to hover
|
|
1256
1258
|
- `timeoutMs` (number, optional): Time to wait for the element in ms (default: 10000)
|
|
1257
1259
|
</details>
|
|
1258
1260
|
|
|
@@ -1261,7 +1263,7 @@ The server can be configured using environment variables. Configuration is divid
|
|
|
1261
1263
|
|
|
1262
1264
|
**Parameters:**
|
|
1263
1265
|
- `key` (string, required): Key to press (e.g., "Enter", "Escape", "Tab")
|
|
1264
|
-
- `selector` (string, optional):
|
|
1266
|
+
- `selector` (string, optional): Ref (e.g. `e1`, `@e1`), getByRole/getByLabel/etc. expression, or CSS selector to focus before sending the key
|
|
1265
1267
|
- `holdMs` (number, optional): Duration in milliseconds to hold the key (repeat duration if `repeat` is true)
|
|
1266
1268
|
- `repeat` (boolean, optional, default: false): If true, simulates key auto-repeat by pressing repeatedly during `holdMs`
|
|
1267
1269
|
- `repeatIntervalMs` (number, optional, default: 50, min: 10): Interval between repeated key presses in ms (only when `repeat` is true)
|
|
@@ -1272,7 +1274,7 @@ The server can be configured using environment variables. Configuration is divid
|
|
|
1272
1274
|
<summary><code>interaction_select</code> - Selects an option from a dropdown.</summary>
|
|
1273
1275
|
|
|
1274
1276
|
**Parameters:**
|
|
1275
|
-
- `selector` (string, required):
|
|
1277
|
+
- `selector` (string, required): Ref (e.g. `e1`, `@e1`), getByRole/getByTestId expression, or CSS selector for the select element
|
|
1276
1278
|
- `value` (string, required): Value to select
|
|
1277
1279
|
- `timeoutMs` (number, optional): Time to wait for the element in ms (default: 10000)
|
|
1278
1280
|
</details>
|
|
@@ -1281,8 +1283,8 @@ The server can be configured using environment variables. Configuration is divid
|
|
|
1281
1283
|
<summary><code>interaction_drag</code> - Performs drag and drop operation.</summary>
|
|
1282
1284
|
|
|
1283
1285
|
**Parameters:**
|
|
1284
|
-
- `sourceSelector` (string, required):
|
|
1285
|
-
- `targetSelector` (string, required):
|
|
1286
|
+
- `sourceSelector` (string, required): Ref (e.g. `e1`, `@e1`), getByRole/getByText/etc. expression, or CSS selector for the source element
|
|
1287
|
+
- `targetSelector` (string, required): Ref, getByRole/getByText/etc. expression, or CSS selector for the target element
|
|
1286
1288
|
- `timeoutMs` (number, optional): Time to wait for source and target elements in ms (default: 10000)
|
|
1287
1289
|
</details>
|
|
1288
1290
|
|
|
@@ -1291,7 +1293,7 @@ The server can be configured using environment variables. Configuration is divid
|
|
|
1291
1293
|
|
|
1292
1294
|
**Parameters:**
|
|
1293
1295
|
- `mode` (enum, optional): Scroll mode - "by" (relative delta), "to" (absolute position), "top", "bottom", "left", "right" (default: "by")
|
|
1294
|
-
- `selector` (string, optional):
|
|
1296
|
+
- `selector` (string, optional): Ref (e.g. `e1`, `@e1`), getByRole/getByText/etc. expression, or CSS selector for a scrollable container. If omitted, scrolls the document viewport
|
|
1295
1297
|
- `dx` (number, optional): Horizontal scroll delta in pixels (used when mode="by", default: 0)
|
|
1296
1298
|
- `dy` (number, optional): Vertical scroll delta in pixels (used when mode="by", default: 0)
|
|
1297
1299
|
- `x` (number, optional): Absolute horizontal scroll position in pixels (used when mode="to")
|
package/dist/cli/runner.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{platformInfo}from"../core-S6ISAJDU.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-JLIRPQ77.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{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(`
|
|
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(`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import path from"node:path";function _envStr(name){let v=process.env[name];if(!v)return;let t=v.trim();return t||void 0}function _envInt(name){let v=_envStr(name);if(!v)return;let n=Number(v);if(Number.isFinite(n))return Math.floor(n)}function _envBool(name){let v=_envStr(name);if(v)return v==="true"}function _parseKeyValueFromEnv(envValue){let headers={};if(!envValue)return headers;let pairs=envValue.split(",");for(let pair of pairs){let trimmed=pair.trim();if(!trimmed)continue;let eqIndex=trimmed.indexOf("=");if(eqIndex===-1)continue;let key=trimmed.slice(0,eqIndex).trim(),value=trimmed.slice(eqIndex+1).trim();!key||!value||(headers[key]=value)}return headers}var PORT=_envInt("PORT")??3e3,TOOL_OUTPUT_SCHEMA_DISABLE=_envBool("TOOL_OUTPUT_SCHEMA_DISABLE")??!1,_PLATFORM_RAW=_envStr("PLATFORM"),PLATFORM=_PLATFORM_RAW==="browser"||_PLATFORM_RAW==="node"?_PLATFORM_RAW:"browser",SESSION_IDLE_SECONDS=_envInt("SESSION_IDLE_SECONDS")??300,SESSION_IDLE_CHECK_SECONDS=_envInt("SESSION_IDLE_CHECK_SECONDS")??30,SESSION_CLOSE_ON_SOCKET_CLOSE=_envBool("SESSION_CLOSE_ON_SOCKET_CLOSE")??!1,BROWSER_HEADLESS_ENABLE=_envBool("BROWSER_HEADLESS_ENABLE")??!0,BROWSER_PERSISTENT_ENABLE=_envBool("BROWSER_PERSISTENT_ENABLE")??!1,BROWSER_PERSISTENT_USER_DATA_DIR=_envStr("BROWSER_PERSISTENT_USER_DATA_DIR")??path.join(process.cwd(),"browser-devtools-mcp"),BROWSER_USE_INSTALLED_ON_SYSTEM=_envBool("BROWSER_USE_INSTALLED_ON_SYSTEM")??!1,BROWSER_EXECUTABLE_PATH=_envStr("BROWSER_EXECUTABLE_PATH"),BROWSER_LOCALE=_envStr("BROWSER_LOCALE"),BROWSER_CONSOLE_MESSAGES_BUFFER_SIZE=_envInt("BROWSER_CONSOLE_MESSAGES_BUFFER_SIZE")??1e3,BROWSER_HTTP_REQUESTS_BUFFER_SIZE=_envInt("BROWSER_HTTP_REQUESTS_BUFFER_SIZE")??1e3,NODE_CONSOLE_MESSAGES_BUFFER_SIZE=_envInt("NODE_CONSOLE_MESSAGES_BUFFER_SIZE")??1e3,NODE_INSPECTOR_HOST=_envStr("NODE_INSPECTOR_HOST"),OTEL_ENABLE=_envBool("OTEL_ENABLE")??!1,OTEL_SERVICE_NAME=_envStr("OTEL_SERVICE_NAME")??"frontend",OTEL_SERVICE_VERSION=_envStr("OTEL_SERVICE_VERSION"),OTEL_ASSETS_DIR=_envStr("OTEL_ASSETS_DIR"),OTEL_INSTRUMENTATION_USER_INTERACTION_EVENTS=_envStr("OTEL_INSTRUMENTATION_USER_INTERACTION_EVENTS")?.split(",")??["click"],OTEL_EXPORTER_TYPE=_envStr("OTEL_EXPORTER_TYPE")??"none",OTEL_EXPORTER_HTTP_URL=_envStr("OTEL_EXPORTER_HTTP_URL"),OTEL_EXPORTER_HTTP_HEADERS=_parseKeyValueFromEnv(_envStr("OTEL_EXPORTER_HTTP_HEADERS")),AWS_REGION=_envStr("AWS_REGION"),AWS_PROFILE=_envStr("AWS_PROFILE"),AMAZON_BEDROCK_ENABLE=_envBool("AMAZON_BEDROCK_ENABLE")??!1,AMAZON_BEDROCK_IMAGE_EMBED_MODEL_ID=_envStr("AMAZON_BEDROCK_IMAGE_EMBED_MODEL_ID"),AMAZON_BEDROCK_TEXT_EMBED_MODEL_ID=_envStr("AMAZON_BEDROCK_TEXT_EMBED_MODEL_ID"),AMAZON_BEDROCK_VISION_MODEL_ID=_envStr("AMAZON_BEDROCK_VISION_MODEL_ID"),FIGMA_ACCESS_TOKEN=_envStr("FIGMA_ACCESS_TOKEN")??"",FIGMA_API_BASE_URL=_envStr("FIGMA_API_BASE_URL")??"https://api.figma.com/v1",DAEMON_PORT=_envInt("DAEMON_PORT")??2020,DAEMON_SESSION_IDLE_SECONDS=_envInt("DAEMON_SESSION_IDLE_SECONDS")??300,DAEMON_SESSION_IDLE_CHECK_SECONDS=_envInt("DAEMON_SESSION_IDLE_CHECK_SECONDS")??30;var ConsoleMessageLevelName=(ConsoleMessageLevelName2=>(ConsoleMessageLevelName2.ALL="all",ConsoleMessageLevelName2.DEBUG="debug",ConsoleMessageLevelName2.INFO="info",ConsoleMessageLevelName2.WARNING="warning",ConsoleMessageLevelName2.ERROR="error",ConsoleMessageLevelName2))(ConsoleMessageLevelName||{});var ConsoleMessageLevel={all:{code:-1},debug:{code:0},info:{code:1},warning:{code:2},error:{code:3}};var BANNER_TEXT="[BROWSER-DEVTOOLS]",enabled=!0,debugEnabled=process.env.DEBUG_ENABLE==="true";function _timeAsString(){return`${new Date().toLocaleTimeString(void 0,{hour:"numeric",minute:"numeric",second:"numeric",hour12:!1,timeZoneName:"short"})}`}function _normalizeArgs(...args){return isDebugEnabled()?args:(args||[]).map(arg=>arg?arg instanceof Error||arg.name&&arg.message&&arg.stack?`${arg.name}: ${arg.message}`:arg:"")}function enable(){enabled=!0}function disable(){enabled=!1}function isDebugEnabled(){return debugEnabled}function debug(...args){enabled&&isDebugEnabled()&&console.debug(BANNER_TEXT,_timeAsString(),"|","DEBUG","-",..._normalizeArgs(...args))}function info(...args){enabled&&console.info(BANNER_TEXT,_timeAsString(),"|","INFO ","-",..._normalizeArgs(...args))}function warn(...args){enabled&&console.warn(BANNER_TEXT,_timeAsString(),"|","WARN ","-",..._normalizeArgs(...args))}function error(...args){enabled&&console.error(BANNER_TEXT,_timeAsString(),"|","ERROR","-",..._normalizeArgs(...args))}function _getCircularReplacer(){let seen=new WeakSet;return(key,value)=>{if(typeof value=="object"&&value!==null){if(seen.has(value))return;seen.add(value)}return value}}function toJson(obj){return JSON.stringify(obj,_getCircularReplacer())}var BASE64_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",BASE64_MAP=new Map;for(let i=0;i<BASE64_CHARS.length;i++)BASE64_MAP.set(BASE64_CHARS[i],i);function _decodeVLQ(encoded){let values=[],shift=0,value=0;for(let char of encoded){let digit=BASE64_MAP.get(char);if(digit===void 0)throw new Error(`Invalid base64 character: ${char}`);let hasContinuation=(digit&32)!==0;if(value+=(digit&31)<<shift,hasContinuation)shift+=5;else{let isNegative=(value&1)!==0;value=value>>1,isNegative&&(value=-value),values.push(value),value=0,shift=0}}return values}function _parseMappings(mappings,sources){let entries=[],lines=mappings.split(";"),generatedLine=0,sourceIndex=0,originalLine=0,originalColumn=0,nameIndex=0;for(let line of lines){let generatedColumn=0,segments=line.split(",");for(let segment of segments){if(!segment)continue;let values=_decodeVLQ(segment);if(values.length===0)continue;generatedColumn+=values[0];let entry={generatedLine,generatedColumn};values.length>=4&&(sourceIndex+=values[1],originalLine+=values[2],originalColumn+=values[3],entry.source=sources[sourceIndex],entry.originalLine=originalLine,entry.originalColumn=originalColumn,values.length>=5&&(nameIndex+=values[4])),entries.push(entry)}generatedLine++}return entries}var SourceMapResolver=class{scripts=new Map;scriptsByUrl=new Map;sourceToScripts=new Map;fetchCache=new Map;page;customFetcher;constructor(source){typeof source=="function"?this.customFetcher=source:this.page=source}registerScript(script){let resolved={scriptId:script.scriptId,url:script.url,sourceMapURL:script.sourceMapURL,originalSources:[]};if(this.scripts.set(script.scriptId,resolved),script.url){let existing=this.scriptsByUrl.get(script.url)||[];existing.push(resolved),this.scriptsByUrl.set(script.url,existing)}}getScriptUrl(scriptId){return this.scripts.get(scriptId)?.url}async loadSourceMap(scriptId){let script=this.scripts.get(scriptId);if(!script||!script.sourceMapURL)return!1;if(script.sourceMap)return!0;try{let sourceMap=await this._fetchSourceMap(script.sourceMapURL,script.url);if(!sourceMap)return!1;script.sourceMap=sourceMap,script.mappings=_parseMappings(sourceMap.mappings,sourceMap.sources),script.originalSources=sourceMap.sources.map(s=>this._resolveSourcePath(s,sourceMap.sourceRoot,script.url));for(let source of script.originalSources){let existing=this.sourceToScripts.get(source)||[];existing.push(script),this.sourceToScripts.set(source,existing)}return!0}catch(error2){return debug(`Failed to load source map for ${script.url}:`,error2),!1}}async loadAllSourceMaps(){let loaded=0;for(let scriptId of this.scripts.keys())await this.loadSourceMap(scriptId)&&loaded++;return loaded}originalToGenerated(originalSource,line,column=0){let normalizedSource=this._normalizeSourcePath(originalSource),scripts=this._findScriptsForSource(normalizedSource);if(scripts.length!==0)for(let script of scripts){if(!script.mappings)continue;let sourceIndex=script.originalSources.findIndex(s=>this._normalizeSourcePath(s)===normalizedSource||s.endsWith(normalizedSource)||normalizedSource.endsWith(s));if(sourceIndex===-1)continue;let bestMatch,bestDistance=1/0;for(let mapping of script.mappings)if(mapping.source===script.sourceMap?.sources[sourceIndex]&&mapping.originalLine!==void 0&&mapping.originalLine===line){let colDist=mapping.originalColumn!==void 0?Math.abs(mapping.originalColumn-column):0;colDist<bestDistance&&(bestDistance=colDist,bestMatch=mapping)}if(bestMatch)return{scriptId:script.scriptId,location:{line:bestMatch.generatedLine,column:bestMatch.generatedColumn}}}}async resolveLocationByUrl(url,line,column=1){let line0=Math.max(0,line-1),column0=Math.max(0,column-1),candidates=this.scriptsByUrl.get(url)||[];if(candidates.length===0)for(let script of this.scripts.values())(script.url===url||script.url.endsWith(url)||url.endsWith(script.url))&&candidates.push(script);for(let script of candidates){if(!await this.loadSourceMap(script.scriptId)||!script.mappings)continue;let resolved=this.generatedToOriginal(script.scriptId,line0,column0);if(resolved)return resolved}return null}generatedToOriginal(scriptId,line,column=0){let script=this.scripts.get(scriptId);if(!script?.mappings)return;let bestMatch,bestDistance=1/0;for(let mapping of script.mappings){if(mapping.generatedLine!==line||mapping.source===void 0)continue;let colDist=Math.abs(mapping.generatedColumn-column);colDist<bestDistance&&(bestDistance=colDist,bestMatch=mapping)}if(bestMatch&&bestMatch.source!==void 0&&bestMatch.originalLine!==void 0){let sourceIndex=script.sourceMap?.sources.indexOf(bestMatch.source);return{source:sourceIndex!==void 0&&sourceIndex>=0?script.originalSources[sourceIndex]:bestMatch.source,line:bestMatch.originalLine,column:bestMatch.originalColumn??0,name:bestMatch.name}}}getOriginalSources(){return Array.from(this.sourceToScripts.keys())}findScriptsForSource(sourcePattern){let normalized=this._normalizeSourcePath(sourcePattern);return this._findScriptsForSource(normalized)}hasSourceMaps(){for(let script of this.scripts.values())if(script.sourceMap)return!0;return!1}clear(){this.scripts.clear(),this.scriptsByUrl.clear(),this.sourceToScripts.clear(),this.fetchCache.clear()}_findScriptsForSource(normalizedSource){let exact=this.sourceToScripts.get(normalizedSource);if(exact&&exact.length>0)return exact;let results=[];for(let[source,scripts]of this.sourceToScripts.entries()){let normalizedKey=this._normalizeSourcePath(source);(normalizedKey.endsWith(normalizedSource)||normalizedSource.endsWith(normalizedKey))&&results.push(...scripts)}return results}_normalizeSourcePath(path3){let normalized=path3.replace(/^webpack:\/\/[^/]*\//,"").replace(/^file:\/\//,"").replace(/^\.*\//,"");for(normalized=normalized.replace(/\\/g,"/");normalized.startsWith("./");)normalized=normalized.slice(2);return normalized}_resolveSourcePath(source,sourceRoot,scriptUrl){return source.startsWith("webpack://")||source.startsWith("http://")||source.startsWith("https://")||sourceRoot&&(source=sourceRoot.replace(/\/$/,"")+"/"+source),source}async _fetchSourceMap(sourceMapURL,scriptUrl){if(sourceMapURL.startsWith("data:"))return this._parseDataUrl(sourceMapURL);let absoluteUrl=this._resolveUrl(sourceMapURL,scriptUrl);if(this.fetchCache.has(absoluteUrl))return this.fetchCache.get(absoluteUrl)||null;try{let sourceMap=null;if(this.customFetcher){let content=await this.customFetcher(absoluteUrl,scriptUrl);content&&(sourceMap=JSON.parse(content))}else this.page&&(sourceMap=await this._fetchViaBrowser(absoluteUrl));return this.fetchCache.set(absoluteUrl,sourceMap),sourceMap}catch(error2){return debug(`Failed to fetch source map from ${absoluteUrl}:`,error2),this.fetchCache.set(absoluteUrl,null),null}}_parseDataUrl(dataUrl){try{let match=dataUrl.match(/^data:[^,]*(?:;base64)?,(.*)$/);if(!match)return null;let isBase64=dataUrl.includes(";base64,"),data=match[1],json=isBase64?Buffer.from(data,"base64").toString("utf-8"):decodeURIComponent(data);return JSON.parse(json)}catch{return null}}_resolveUrl(url,baseUrl){if(url.startsWith("http://")||url.startsWith("https://"))return url;try{return new URL(url,baseUrl).href}catch{return baseUrl.replace(/[^/]*$/,"")+url}}async _fetchViaBrowser(url){if(!this.page)return null;try{let result=await this.page.evaluate(async fetchUrl=>{try{let response=await fetch(fetchUrl);return response.ok?{data:await response.text()}:{error:`HTTP ${response.status}`}}catch(err){return{error:err.message||"Fetch failed"}}},url);return"error"in result?(debug(`Browser fetch error for ${url}: ${result.error}`),null):JSON.parse(result.data)}catch(error2){return debug(`Failed to fetch ${url} via browser:`,error2),null}}};var V8API_DEFAULT_OPTIONS={maxDepth:3,maxProperties:50,maxArrayLength:100,maxStringLength:1e3},V8Api=class{cdp=null;enabled=!1;scripts=new Map;scriptsByUrl=new Map;eventHandlers={};options;cdpProvider;constructor(source,options){if(this.options={...V8API_DEFAULT_OPTIONS,...options},typeof source=="function")this.cdpProvider=source;else if(source&&typeof source.context=="function"){let page=source;this.cdpProvider=async()=>await page.context().newCDPSession(page)}else if(source&&typeof source.send=="function"){let session=source;this.cdp=session,this.cdpProvider=async()=>session}else throw new Error("V8Api: Invalid source. Expected Page, CDPSessionProvider, or ICDPSession.")}getOptions(){return{...this.options}}isEnabled(){return this.enabled}async getCdp(){return this.cdp||(this.cdp=await this.cdpProvider()),this.cdp}on(event,handler){this.eventHandlers[event]=handler}off(event){delete this.eventHandlers[event]}async enable(){if(this.enabled)return;let cdp=await this.getCdp();cdp.on("Debugger.scriptParsed",event=>{let parsed=event;if(this.scripts.set(parsed.scriptId,parsed),parsed.url){let existing=this.scriptsByUrl.get(parsed.url)||[];existing.push(parsed),this.scriptsByUrl.set(parsed.url,existing)}this.eventHandlers.scriptParsed&&this.eventHandlers.scriptParsed(parsed)}),cdp.on("Debugger.paused",event=>{let pausedEvent=event;this.eventHandlers.paused&&this.eventHandlers.paused(pausedEvent)}),cdp.on("Debugger.resumed",()=>{this.eventHandlers.resumed&&this.eventHandlers.resumed()}),await cdp.send("Debugger.enable",{maxScriptsCacheSize:1e8}),await cdp.send("Runtime.enable"),this.enabled=!0}async disable(){if(!(!this.enabled||!this.cdp)){try{await this.cdp.send("Debugger.disable"),await this.cdp.send("Runtime.disable")}catch{}this.scripts.clear(),this.scriptsByUrl.clear(),this.enabled=!1}}async detach(){if(await this.disable(),this.cdp){try{await this.cdp.detach()}catch{}this.cdp=null}}getScripts(){return Array.from(this.scripts.values())}getScript(scriptId){return this.scripts.get(scriptId)}findScriptsByUrl(urlPattern){let regex=new RegExp(urlPattern),results=[];for(let script of this.scripts.values())script.url&®ex.test(script.url)&&results.push(script);return results}async setBreakpointByUrl(options){let cdp=await this.getCdp(),params={lineNumber:options.lineNumber};options.urlRegex?params.urlRegex=options.urlRegex:options.url&&(params.url=options.url),options.columnNumber!==void 0&&(params.columnNumber=options.columnNumber),options.condition&&(params.condition=options.condition);let result=await cdp.send("Debugger.setBreakpointByUrl",params);return{breakpointId:result.breakpointId,locations:result.locations||[]}}async setBreakpoint(location,condition){let cdp=await this.getCdp(),params={location:{scriptId:location.scriptId,lineNumber:location.lineNumber,columnNumber:location.columnNumber}};condition&&(params.condition=condition);let result=await cdp.send("Debugger.setBreakpoint",params);return{breakpointId:result.breakpointId,actualLocation:result.actualLocation}}async removeBreakpoint(breakpointId){await(await this.getCdp()).send("Debugger.removeBreakpoint",{breakpointId})}async resume(){await(await this.getCdp()).send("Debugger.resume")}async stepOver(){await(await this.getCdp()).send("Debugger.stepOver")}async stepInto(){await(await this.getCdp()).send("Debugger.stepInto")}async stepOut(){await(await this.getCdp()).send("Debugger.stepOut")}async pause(){await(await this.getCdp()).send("Debugger.pause")}async setPauseOnExceptions(state){await(await this.getCdp()).send("Debugger.setPauseOnExceptions",{state})}async evaluateOnCallFrame(callFrameId,expression,options){let result=await(await this.getCdp()).send("Debugger.evaluateOnCallFrame",{callFrameId,expression,returnByValue:options?.returnByValue??!0,generatePreview:options?.generatePreview??!0,throwOnSideEffect:options?.throwOnSideEffect??!1});return{result:result.result,exceptionDetails:result.exceptionDetails}}async getProperties(objectId,options){let result=await(await this.getCdp()).send("Runtime.getProperties",{objectId,ownProperties:options?.ownProperties??!0,accessorPropertiesOnly:options?.accessorPropertiesOnly??!1,generatePreview:options?.generatePreview??!0});return{result:result.result||[],internalProperties:result.internalProperties,privateProperties:result.privateProperties}}async getScopeVariables(scope,options){if(!scope.object.objectId)return{};let opts={maxDepth:options?.maxDepth??this.options.maxDepth,maxProperties:options?.maxProperties??this.options.maxProperties,maxArrayLength:options?.maxArrayLength??this.options.maxArrayLength},{result}=await this.getProperties(scope.object.objectId,{ownProperties:!0,generatePreview:!0}),variables={},visited=new Set,propCount=0;for(let prop of result){if(propCount>=opts.maxProperties){variables.__truncated__=`${result.length-propCount} more properties`;break}prop.value&&(variables[prop.name]=await this.extractValueDeep(prop.value,opts.maxDepth,opts.maxProperties,opts.maxArrayLength,visited),propCount++)}return variables}extractValue(obj){return this._extractValueShallow(obj)}async extractValueDeep(obj,maxDepth,maxProperties,maxArrayLength,visited=new Set){let depth=maxDepth??this.options.maxDepth,props=maxProperties??this.options.maxProperties,arrLen=maxArrayLength??this.options.maxArrayLength;if(obj.value!==void 0)return typeof obj.value=="string"&&obj.value.length>this.options.maxStringLength?obj.value.slice(0,this.options.maxStringLength)+`... (${obj.value.length} chars)`:obj.value;if(obj.unserializableValue)return obj.unserializableValue==="NaN"?NaN:obj.unserializableValue==="Infinity"?1/0:obj.unserializableValue==="-Infinity"?-1/0:obj.unserializableValue==="-0"?-0:obj.unserializableValue.endsWith("n")?`BigInt(${obj.unserializableValue.slice(0,-1)})`:obj.unserializableValue;if(obj.subtype==="null")return null;if(obj.type!=="undefined"){if(obj.type==="function")return`[function${obj.description?`: ${obj.description.split(`
|
|
1
|
+
import path from"node:path";function _envStr(name){let v=process.env[name];if(!v)return;let t=v.trim();return t||void 0}function _envInt(name){let v=_envStr(name);if(!v)return;let n=Number(v);if(Number.isFinite(n))return Math.floor(n)}function _envBool(name){let v=_envStr(name);if(v)return v==="true"}function _parseKeyValueFromEnv(envValue){let headers={};if(!envValue)return headers;let pairs=envValue.split(",");for(let pair of pairs){let trimmed=pair.trim();if(!trimmed)continue;let eqIndex=trimmed.indexOf("=");if(eqIndex===-1)continue;let key=trimmed.slice(0,eqIndex).trim(),value=trimmed.slice(eqIndex+1).trim();!key||!value||(headers[key]=value)}return headers}var PORT=_envInt("PORT")??3e3,TOOL_OUTPUT_SCHEMA_DISABLE=_envBool("TOOL_OUTPUT_SCHEMA_DISABLE")??!1,AVAILABLE_TOOL_DOMAINS=(()=>{let v=_envStr("AVAILABLE_TOOL_DOMAINS");if(!v)return;let set=new Set(v.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));return set.size>0?set:void 0})(),_PLATFORM_RAW=_envStr("PLATFORM"),PLATFORM=_PLATFORM_RAW==="browser"||_PLATFORM_RAW==="node"?_PLATFORM_RAW:"browser",SESSION_IDLE_SECONDS=_envInt("SESSION_IDLE_SECONDS")??300,SESSION_IDLE_CHECK_SECONDS=_envInt("SESSION_IDLE_CHECK_SECONDS")??30,SESSION_CLOSE_ON_SOCKET_CLOSE=_envBool("SESSION_CLOSE_ON_SOCKET_CLOSE")??!1,BROWSER_HEADLESS_ENABLE=_envBool("BROWSER_HEADLESS_ENABLE")??!0,BROWSER_PERSISTENT_ENABLE=_envBool("BROWSER_PERSISTENT_ENABLE")??!1,BROWSER_PERSISTENT_USER_DATA_DIR=_envStr("BROWSER_PERSISTENT_USER_DATA_DIR")??path.join(process.cwd(),"browser-devtools-mcp"),BROWSER_USE_INSTALLED_ON_SYSTEM=_envBool("BROWSER_USE_INSTALLED_ON_SYSTEM")??!1,BROWSER_EXECUTABLE_PATH=_envStr("BROWSER_EXECUTABLE_PATH"),BROWSER_LOCALE=_envStr("BROWSER_LOCALE"),BROWSER_CONSOLE_MESSAGES_BUFFER_SIZE=_envInt("BROWSER_CONSOLE_MESSAGES_BUFFER_SIZE")??1e3,BROWSER_HTTP_REQUESTS_BUFFER_SIZE=_envInt("BROWSER_HTTP_REQUESTS_BUFFER_SIZE")??1e3,NODE_CONSOLE_MESSAGES_BUFFER_SIZE=_envInt("NODE_CONSOLE_MESSAGES_BUFFER_SIZE")??1e3,NODE_INSPECTOR_HOST=_envStr("NODE_INSPECTOR_HOST"),OTEL_ENABLE=_envBool("OTEL_ENABLE")??!1,OTEL_SERVICE_NAME=_envStr("OTEL_SERVICE_NAME")??"frontend",OTEL_SERVICE_VERSION=_envStr("OTEL_SERVICE_VERSION"),OTEL_ASSETS_DIR=_envStr("OTEL_ASSETS_DIR"),OTEL_INSTRUMENTATION_USER_INTERACTION_EVENTS=_envStr("OTEL_INSTRUMENTATION_USER_INTERACTION_EVENTS")?.split(",")??["click"],OTEL_EXPORTER_TYPE=_envStr("OTEL_EXPORTER_TYPE")??"none",OTEL_EXPORTER_HTTP_URL=_envStr("OTEL_EXPORTER_HTTP_URL"),OTEL_EXPORTER_HTTP_HEADERS=_parseKeyValueFromEnv(_envStr("OTEL_EXPORTER_HTTP_HEADERS")),AWS_REGION=_envStr("AWS_REGION"),AWS_PROFILE=_envStr("AWS_PROFILE"),AMAZON_BEDROCK_ENABLE=_envBool("AMAZON_BEDROCK_ENABLE")??!1,AMAZON_BEDROCK_IMAGE_EMBED_MODEL_ID=_envStr("AMAZON_BEDROCK_IMAGE_EMBED_MODEL_ID"),AMAZON_BEDROCK_TEXT_EMBED_MODEL_ID=_envStr("AMAZON_BEDROCK_TEXT_EMBED_MODEL_ID"),AMAZON_BEDROCK_VISION_MODEL_ID=_envStr("AMAZON_BEDROCK_VISION_MODEL_ID"),FIGMA_ACCESS_TOKEN=_envStr("FIGMA_ACCESS_TOKEN")??"",FIGMA_API_BASE_URL=_envStr("FIGMA_API_BASE_URL")??"https://api.figma.com/v1",DAEMON_PORT=_envInt("DAEMON_PORT")??2020,DAEMON_SESSION_IDLE_SECONDS=_envInt("DAEMON_SESSION_IDLE_SECONDS")??300,DAEMON_SESSION_IDLE_CHECK_SECONDS=_envInt("DAEMON_SESSION_IDLE_CHECK_SECONDS")??30;var ConsoleMessageLevelName=(ConsoleMessageLevelName2=>(ConsoleMessageLevelName2.ALL="all",ConsoleMessageLevelName2.DEBUG="debug",ConsoleMessageLevelName2.INFO="info",ConsoleMessageLevelName2.WARNING="warning",ConsoleMessageLevelName2.ERROR="error",ConsoleMessageLevelName2))(ConsoleMessageLevelName||{});var ConsoleMessageLevel={all:{code:-1},debug:{code:0},info:{code:1},warning:{code:2},error:{code:3}};var BANNER_TEXT="[BROWSER-DEVTOOLS]",enabled=!0,debugEnabled=process.env.DEBUG_ENABLE==="true";function _timeAsString(){return`${new Date().toLocaleTimeString(void 0,{hour:"numeric",minute:"numeric",second:"numeric",hour12:!1,timeZoneName:"short"})}`}function _normalizeArgs(...args){return isDebugEnabled()?args:(args||[]).map(arg=>arg?arg instanceof Error||arg.name&&arg.message&&arg.stack?`${arg.name}: ${arg.message}`:arg:"")}function enable(){enabled=!0}function disable(){enabled=!1}function isDebugEnabled(){return debugEnabled}function debug(...args){enabled&&isDebugEnabled()&&console.debug(BANNER_TEXT,_timeAsString(),"|","DEBUG","-",..._normalizeArgs(...args))}function info(...args){enabled&&console.info(BANNER_TEXT,_timeAsString(),"|","INFO ","-",..._normalizeArgs(...args))}function warn(...args){enabled&&console.warn(BANNER_TEXT,_timeAsString(),"|","WARN ","-",..._normalizeArgs(...args))}function error(...args){enabled&&console.error(BANNER_TEXT,_timeAsString(),"|","ERROR","-",..._normalizeArgs(...args))}function _getCircularReplacer(){let seen=new WeakSet;return(key,value)=>{if(typeof value=="object"&&value!==null){if(seen.has(value))return;seen.add(value)}return value}}function toJson(obj){return JSON.stringify(obj,_getCircularReplacer())}var BASE64_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",BASE64_MAP=new Map;for(let i=0;i<BASE64_CHARS.length;i++)BASE64_MAP.set(BASE64_CHARS[i],i);function _decodeVLQ(encoded){let values=[],shift=0,value=0;for(let char of encoded){let digit=BASE64_MAP.get(char);if(digit===void 0)throw new Error(`Invalid base64 character: ${char}`);let hasContinuation=(digit&32)!==0;if(value+=(digit&31)<<shift,hasContinuation)shift+=5;else{let isNegative=(value&1)!==0;value=value>>1,isNegative&&(value=-value),values.push(value),value=0,shift=0}}return values}function _parseMappings(mappings,sources){let entries=[],lines=mappings.split(";"),generatedLine=0,sourceIndex=0,originalLine=0,originalColumn=0,nameIndex=0;for(let line of lines){let generatedColumn=0,segments=line.split(",");for(let segment of segments){if(!segment)continue;let values=_decodeVLQ(segment);if(values.length===0)continue;generatedColumn+=values[0];let entry={generatedLine,generatedColumn};values.length>=4&&(sourceIndex+=values[1],originalLine+=values[2],originalColumn+=values[3],entry.source=sources[sourceIndex],entry.originalLine=originalLine,entry.originalColumn=originalColumn,values.length>=5&&(nameIndex+=values[4])),entries.push(entry)}generatedLine++}return entries}var SourceMapResolver=class{scripts=new Map;scriptsByUrl=new Map;sourceToScripts=new Map;fetchCache=new Map;page;customFetcher;constructor(source){typeof source=="function"?this.customFetcher=source:this.page=source}registerScript(script){let resolved={scriptId:script.scriptId,url:script.url,sourceMapURL:script.sourceMapURL,originalSources:[]};if(this.scripts.set(script.scriptId,resolved),script.url){let existing=this.scriptsByUrl.get(script.url)||[];existing.push(resolved),this.scriptsByUrl.set(script.url,existing)}}getScriptUrl(scriptId){return this.scripts.get(scriptId)?.url}async loadSourceMap(scriptId){let script=this.scripts.get(scriptId);if(!script||!script.sourceMapURL)return!1;if(script.sourceMap)return!0;try{let sourceMap=await this._fetchSourceMap(script.sourceMapURL,script.url);if(!sourceMap)return!1;script.sourceMap=sourceMap,script.mappings=_parseMappings(sourceMap.mappings,sourceMap.sources),script.originalSources=sourceMap.sources.map(s=>this._resolveSourcePath(s,sourceMap.sourceRoot,script.url));for(let source of script.originalSources){let existing=this.sourceToScripts.get(source)||[];existing.push(script),this.sourceToScripts.set(source,existing)}return!0}catch(error2){return debug(`Failed to load source map for ${script.url}:`,error2),!1}}async loadAllSourceMaps(){let loaded=0;for(let scriptId of this.scripts.keys())await this.loadSourceMap(scriptId)&&loaded++;return loaded}originalToGenerated(originalSource,line,column=0){let normalizedSource=this._normalizeSourcePath(originalSource),scripts=this._findScriptsForSource(normalizedSource);if(scripts.length!==0)for(let script of scripts){if(!script.mappings)continue;let sourceIndex=script.originalSources.findIndex(s=>this._normalizeSourcePath(s)===normalizedSource||s.endsWith(normalizedSource)||normalizedSource.endsWith(s));if(sourceIndex===-1)continue;let bestMatch,bestDistance=1/0;for(let mapping of script.mappings)if(mapping.source===script.sourceMap?.sources[sourceIndex]&&mapping.originalLine!==void 0&&mapping.originalLine===line){let colDist=mapping.originalColumn!==void 0?Math.abs(mapping.originalColumn-column):0;colDist<bestDistance&&(bestDistance=colDist,bestMatch=mapping)}if(bestMatch)return{scriptId:script.scriptId,location:{line:bestMatch.generatedLine,column:bestMatch.generatedColumn}}}}async resolveLocationByUrl(url,line,column=1){let line0=Math.max(0,line-1),column0=Math.max(0,column-1),candidates=this.scriptsByUrl.get(url)||[];if(candidates.length===0)for(let script of this.scripts.values())(script.url===url||script.url.endsWith(url)||url.endsWith(script.url))&&candidates.push(script);for(let script of candidates){if(!await this.loadSourceMap(script.scriptId)||!script.mappings)continue;let resolved=this.generatedToOriginal(script.scriptId,line0,column0);if(resolved)return resolved}return null}generatedToOriginal(scriptId,line,column=0){let script=this.scripts.get(scriptId);if(!script?.mappings)return;let bestMatch,bestDistance=1/0;for(let mapping of script.mappings){if(mapping.generatedLine!==line||mapping.source===void 0)continue;let colDist=Math.abs(mapping.generatedColumn-column);colDist<bestDistance&&(bestDistance=colDist,bestMatch=mapping)}if(bestMatch&&bestMatch.source!==void 0&&bestMatch.originalLine!==void 0){let sourceIndex=script.sourceMap?.sources.indexOf(bestMatch.source);return{source:sourceIndex!==void 0&&sourceIndex>=0?script.originalSources[sourceIndex]:bestMatch.source,line:bestMatch.originalLine,column:bestMatch.originalColumn??0,name:bestMatch.name}}}getOriginalSources(){return Array.from(this.sourceToScripts.keys())}findScriptsForSource(sourcePattern){let normalized=this._normalizeSourcePath(sourcePattern);return this._findScriptsForSource(normalized)}hasSourceMaps(){for(let script of this.scripts.values())if(script.sourceMap)return!0;return!1}clear(){this.scripts.clear(),this.scriptsByUrl.clear(),this.sourceToScripts.clear(),this.fetchCache.clear()}_findScriptsForSource(normalizedSource){let exact=this.sourceToScripts.get(normalizedSource);if(exact&&exact.length>0)return exact;let results=[];for(let[source,scripts]of this.sourceToScripts.entries()){let normalizedKey=this._normalizeSourcePath(source);(normalizedKey.endsWith(normalizedSource)||normalizedSource.endsWith(normalizedKey))&&results.push(...scripts)}return results}_normalizeSourcePath(path3){let normalized=path3.replace(/^webpack:\/\/[^/]*\//,"").replace(/^file:\/\//,"").replace(/^\.*\//,"");for(normalized=normalized.replace(/\\/g,"/");normalized.startsWith("./");)normalized=normalized.slice(2);return normalized}_resolveSourcePath(source,sourceRoot,scriptUrl){return source.startsWith("webpack://")||source.startsWith("http://")||source.startsWith("https://")||sourceRoot&&(source=sourceRoot.replace(/\/$/,"")+"/"+source),source}async _fetchSourceMap(sourceMapURL,scriptUrl){if(sourceMapURL.startsWith("data:"))return this._parseDataUrl(sourceMapURL);let absoluteUrl=this._resolveUrl(sourceMapURL,scriptUrl);if(this.fetchCache.has(absoluteUrl))return this.fetchCache.get(absoluteUrl)||null;try{let sourceMap=null;if(this.customFetcher){let content=await this.customFetcher(absoluteUrl,scriptUrl);content&&(sourceMap=JSON.parse(content))}else this.page&&(sourceMap=await this._fetchViaBrowser(absoluteUrl));return this.fetchCache.set(absoluteUrl,sourceMap),sourceMap}catch(error2){return debug(`Failed to fetch source map from ${absoluteUrl}:`,error2),this.fetchCache.set(absoluteUrl,null),null}}_parseDataUrl(dataUrl){try{let match=dataUrl.match(/^data:[^,]*(?:;base64)?,(.*)$/);if(!match)return null;let isBase64=dataUrl.includes(";base64,"),data=match[1],json=isBase64?Buffer.from(data,"base64").toString("utf-8"):decodeURIComponent(data);return JSON.parse(json)}catch{return null}}_resolveUrl(url,baseUrl){if(url.startsWith("http://")||url.startsWith("https://"))return url;try{return new URL(url,baseUrl).href}catch{return baseUrl.replace(/[^/]*$/,"")+url}}async _fetchViaBrowser(url){if(!this.page)return null;try{let result=await this.page.evaluate(async fetchUrl=>{try{let response=await fetch(fetchUrl);return response.ok?{data:await response.text()}:{error:`HTTP ${response.status}`}}catch(err){return{error:err.message||"Fetch failed"}}},url);return"error"in result?(debug(`Browser fetch error for ${url}: ${result.error}`),null):JSON.parse(result.data)}catch(error2){return debug(`Failed to fetch ${url} via browser:`,error2),null}}};var V8API_DEFAULT_OPTIONS={maxDepth:3,maxProperties:50,maxArrayLength:100,maxStringLength:1e3},V8Api=class{cdp=null;enabled=!1;scripts=new Map;scriptsByUrl=new Map;eventHandlers={};options;cdpProvider;constructor(source,options){if(this.options={...V8API_DEFAULT_OPTIONS,...options},typeof source=="function")this.cdpProvider=source;else if(source&&typeof source.context=="function"){let page=source;this.cdpProvider=async()=>await page.context().newCDPSession(page)}else if(source&&typeof source.send=="function"){let session=source;this.cdp=session,this.cdpProvider=async()=>session}else throw new Error("V8Api: Invalid source. Expected Page, CDPSessionProvider, or ICDPSession.")}getOptions(){return{...this.options}}isEnabled(){return this.enabled}async getCdp(){return this.cdp||(this.cdp=await this.cdpProvider()),this.cdp}on(event,handler){this.eventHandlers[event]=handler}off(event){delete this.eventHandlers[event]}async enable(){if(this.enabled)return;let cdp=await this.getCdp();cdp.on("Debugger.scriptParsed",event=>{let parsed=event;if(this.scripts.set(parsed.scriptId,parsed),parsed.url){let existing=this.scriptsByUrl.get(parsed.url)||[];existing.push(parsed),this.scriptsByUrl.set(parsed.url,existing)}this.eventHandlers.scriptParsed&&this.eventHandlers.scriptParsed(parsed)}),cdp.on("Debugger.paused",event=>{let pausedEvent=event;this.eventHandlers.paused&&this.eventHandlers.paused(pausedEvent)}),cdp.on("Debugger.resumed",()=>{this.eventHandlers.resumed&&this.eventHandlers.resumed()}),await cdp.send("Debugger.enable",{maxScriptsCacheSize:1e8}),await cdp.send("Runtime.enable"),this.enabled=!0}async disable(){if(!(!this.enabled||!this.cdp)){try{await this.cdp.send("Debugger.disable"),await this.cdp.send("Runtime.disable")}catch{}this.scripts.clear(),this.scriptsByUrl.clear(),this.enabled=!1}}async detach(){if(await this.disable(),this.cdp){try{await this.cdp.detach()}catch{}this.cdp=null}}getScripts(){return Array.from(this.scripts.values())}getScript(scriptId){return this.scripts.get(scriptId)}findScriptsByUrl(urlPattern){let regex=new RegExp(urlPattern),results=[];for(let script of this.scripts.values())script.url&®ex.test(script.url)&&results.push(script);return results}async setBreakpointByUrl(options){let cdp=await this.getCdp(),params={lineNumber:options.lineNumber};options.urlRegex?params.urlRegex=options.urlRegex:options.url&&(params.url=options.url),options.columnNumber!==void 0&&(params.columnNumber=options.columnNumber),options.condition&&(params.condition=options.condition);let result=await cdp.send("Debugger.setBreakpointByUrl",params);return{breakpointId:result.breakpointId,locations:result.locations||[]}}async setBreakpoint(location,condition){let cdp=await this.getCdp(),params={location:{scriptId:location.scriptId,lineNumber:location.lineNumber,columnNumber:location.columnNumber}};condition&&(params.condition=condition);let result=await cdp.send("Debugger.setBreakpoint",params);return{breakpointId:result.breakpointId,actualLocation:result.actualLocation}}async removeBreakpoint(breakpointId){await(await this.getCdp()).send("Debugger.removeBreakpoint",{breakpointId})}async resume(){await(await this.getCdp()).send("Debugger.resume")}async stepOver(){await(await this.getCdp()).send("Debugger.stepOver")}async stepInto(){await(await this.getCdp()).send("Debugger.stepInto")}async stepOut(){await(await this.getCdp()).send("Debugger.stepOut")}async pause(){await(await this.getCdp()).send("Debugger.pause")}async setPauseOnExceptions(state){await(await this.getCdp()).send("Debugger.setPauseOnExceptions",{state})}async evaluateOnCallFrame(callFrameId,expression,options){let result=await(await this.getCdp()).send("Debugger.evaluateOnCallFrame",{callFrameId,expression,returnByValue:options?.returnByValue??!0,generatePreview:options?.generatePreview??!0,throwOnSideEffect:options?.throwOnSideEffect??!1});return{result:result.result,exceptionDetails:result.exceptionDetails}}async getProperties(objectId,options){let result=await(await this.getCdp()).send("Runtime.getProperties",{objectId,ownProperties:options?.ownProperties??!0,accessorPropertiesOnly:options?.accessorPropertiesOnly??!1,generatePreview:options?.generatePreview??!0});return{result:result.result||[],internalProperties:result.internalProperties,privateProperties:result.privateProperties}}async getScopeVariables(scope,options){if(!scope.object.objectId)return{};let opts={maxDepth:options?.maxDepth??this.options.maxDepth,maxProperties:options?.maxProperties??this.options.maxProperties,maxArrayLength:options?.maxArrayLength??this.options.maxArrayLength},{result}=await this.getProperties(scope.object.objectId,{ownProperties:!0,generatePreview:!0}),variables={},visited=new Set,propCount=0;for(let prop of result){if(propCount>=opts.maxProperties){variables.__truncated__=`${result.length-propCount} more properties`;break}prop.value&&(variables[prop.name]=await this.extractValueDeep(prop.value,opts.maxDepth,opts.maxProperties,opts.maxArrayLength,visited),propCount++)}return variables}extractValue(obj){return this._extractValueShallow(obj)}async extractValueDeep(obj,maxDepth,maxProperties,maxArrayLength,visited=new Set){let depth=maxDepth??this.options.maxDepth,props=maxProperties??this.options.maxProperties,arrLen=maxArrayLength??this.options.maxArrayLength;if(obj.value!==void 0)return typeof obj.value=="string"&&obj.value.length>this.options.maxStringLength?obj.value.slice(0,this.options.maxStringLength)+`... (${obj.value.length} chars)`:obj.value;if(obj.unserializableValue)return obj.unserializableValue==="NaN"?NaN:obj.unserializableValue==="Infinity"?1/0:obj.unserializableValue==="-Infinity"?-1/0:obj.unserializableValue==="-0"?-0:obj.unserializableValue.endsWith("n")?`BigInt(${obj.unserializableValue.slice(0,-1)})`:obj.unserializableValue;if(obj.subtype==="null")return null;if(obj.type!=="undefined"){if(obj.type==="function")return`[function${obj.description?`: ${obj.description.split(`
|
|
2
2
|
`)[0]}`:""}]`;if(!obj.objectId)return this._extractValueShallow(obj);if(depth<=0)return this._getShallowDescription(obj);if(visited.has(obj.objectId))return"[Circular]";visited.add(obj.objectId);try{return obj.subtype==="array"?await this._extractArray(obj.objectId,depth-1,props,arrLen,visited):obj.subtype==="map"?await this._extractMap(obj.objectId,depth-1,props,arrLen,visited):obj.subtype==="set"?await this._extractSet(obj.objectId,depth-1,arrLen,visited):obj.subtype==="date"?obj.description||"[Date]":obj.subtype==="regexp"?obj.description||"[RegExp]":obj.subtype==="error"?obj.description||"[Error]":obj.subtype==="promise"?`[Promise: ${obj.description||"pending"}]`:obj.subtype==="node"||obj.className?.includes("Element")||obj.className?.includes("Node")?`[DOM: ${obj.description||obj.className||"Node"}]`:obj.type==="object"?await this._extractObject(obj.objectId,depth-1,props,arrLen,visited,obj.className):this._extractValueShallow(obj)}catch{return this._getShallowDescription(obj)}}}async _extractArray(objectId,maxDepth,maxProperties,maxArrayLength,visited){let{result}=await this.getProperties(objectId,{ownProperties:!0,generatePreview:!0}),arr=[],length=0;for(let prop of result)if(prop.name==="length"&&prop.value?.value!==void 0){length=prop.value.value;break}for(let prop of result){let index=parseInt(prop.name,10);if(!(isNaN(index)||index<0)){if(arr.length>=maxArrayLength)break;prop.value&&(arr[index]=await this.extractValueDeep(prop.value,maxDepth,maxProperties,maxArrayLength,visited))}}return length>maxArrayLength&&(arr.__truncated__=`${length-maxArrayLength} more items`),arr}async _extractMap(objectId,maxDepth,maxProperties,maxArrayLength,visited){let{internalProperties}=await this.getProperties(objectId,{ownProperties:!0,generatePreview:!0}),mapObj={__type__:"Map"},entries=[],entriesProp=internalProperties?.find(p=>p.name==="[[Entries]]");if(entriesProp?.value?.objectId){let{result:entryResults}=await this.getProperties(entriesProp.value.objectId,{ownProperties:!0,generatePreview:!0}),count=0;for(let entry of entryResults){if(count>=maxArrayLength)break;let index=parseInt(entry.name,10);if(isNaN(index)||!entry.value?.objectId)continue;let{result:kvResult}=await this.getProperties(entry.value.objectId,{ownProperties:!0,generatePreview:!0}),keyProp=kvResult.find(p=>p.name==="key"),valueProp=kvResult.find(p=>p.name==="value");if(keyProp?.value&&valueProp?.value){let key=await this.extractValueDeep(keyProp.value,maxDepth,maxProperties,maxArrayLength,visited),value=await this.extractValueDeep(valueProp.value,maxDepth,maxProperties,maxArrayLength,visited);entries.push([key,value])}count++}}return mapObj.entries=entries,mapObj}async _extractSet(objectId,maxDepth,maxArrayLength,visited){let{internalProperties}=await this.getProperties(objectId,{ownProperties:!0,generatePreview:!0}),setObj={__type__:"Set"},values=[],entriesProp=internalProperties?.find(p=>p.name==="[[Entries]]");if(entriesProp?.value?.objectId){let{result:entryResults}=await this.getProperties(entriesProp.value.objectId,{ownProperties:!0,generatePreview:!0}),count=0;for(let entry of entryResults){if(count>=maxArrayLength)break;let index=parseInt(entry.name,10);isNaN(index)||(entry.value&&values.push(await this.extractValueDeep(entry.value,maxDepth,50,maxArrayLength,visited)),count++)}}return setObj.values=values,setObj}async _extractObject(objectId,maxDepth,maxProperties,maxArrayLength,visited,className){let{result}=await this.getProperties(objectId,{ownProperties:!0,generatePreview:!0}),obj={};className&&className!=="Object"&&(obj.__class__=className);let count=0;for(let prop of result){if(count>=maxProperties){obj.__truncated__=`${result.length-count} more properties`;break}prop.isOwn&&(prop.name.startsWith("__")&&prop.name.endsWith("__")||prop.value&&(obj[prop.name]=await this.extractValueDeep(prop.value,maxDepth,maxProperties,maxArrayLength,visited),count++))}return obj}_extractValueShallow(obj){if(obj.value!==void 0)return obj.value;if(obj.unserializableValue)return obj.unserializableValue==="NaN"?NaN:obj.unserializableValue==="Infinity"?1/0:obj.unserializableValue==="-Infinity"?-1/0:obj.unserializableValue==="-0"?-0:obj.unserializableValue.endsWith("n")?`BigInt(${obj.unserializableValue.slice(0,-1)})`:obj.unserializableValue;if(obj.subtype==="null")return null;if(obj.type!=="undefined")return this._getShallowDescription(obj)}_getShallowDescription(obj){if(obj.description){let desc=obj.description.split(`
|
|
3
3
|
`)[0];return desc.length>100?`[${obj.type}${obj.subtype?`:${obj.subtype}`:""}] ${desc.slice(0,100)}...`:`[${obj.type}${obj.subtype?`:${obj.subtype}`:""}] ${desc}`}return`[${obj.type}${obj.subtype?`:${obj.subtype}`:""}]`}async getScriptSource(scriptId){return await(await this.getCdp()).send("Debugger.getScriptSource",{scriptId})}async setScriptSource(scriptId,scriptSource,dryRun){let result=await(await this.getCdp()).send("Debugger.setScriptSource",{scriptId,scriptSource,dryRun:dryRun??!1});return{callFrames:result.callFrames,stackChanged:result.stackChanged,asyncStackTrace:result.asyncStackTrace,exceptionDetails:result.exceptionDetails}}};import*as fs from"node:fs";import*as http from"node:http";import*as https from"node:https";import*as path2 from"node:path";var ProbeKind=(ProbeKind2=>(ProbeKind2.TRACEPOINT="tracepoint",ProbeKind2.LOGPOINT="logpoint",ProbeKind2))(ProbeKind||{}),DEFAULT_NODE_DEBUG_CONFIG={maxSnapshots:1e3,maxCallStackDepth:20,maxFramesWithScopes:5,maxAsyncStackSegments:10,maxFramesPerAsyncSegment:10},STORES=new Map;function _generateId(){let t=Date.now(),r=Math.floor(Math.random()*1e6);return`${t.toString(36)}-${r.toString(36)}`}function _locationKey(urlPattern,lineNumber,columnNumber){return`${urlPattern}:${lineNumber}:${columnNumber}`}function _cdpConsoleTypeToLevelName(type){switch(type){case"error":return"error";case"warning":case"warn":return"warning";case"info":return"info";case"debug":return"debug";default:return"info"}}function _cdpArgsToText(args){return!args||args.length===0?"":args.map(a=>a.type==="string"&&a.value!==void 0||a.value!==void 0?String(a.value):a.description?a.description:"[object]").join(" ")}function _evaluateHitCondition(hitCondition,hitCount){try{let condition=hitCondition.trim();return/^[=<>!%]/.test(condition)&&(condition=`hitCount ${condition}`),!!new Function("hitCount",`return (${condition});`)(hitCount)}catch{return!1}}async function _getOtelTraceContext(session){let expression=`(function(){
|
|
4
4
|
try {
|
|
@@ -12,4 +12,4 @@ try {
|
|
|
12
12
|
}
|
|
13
13
|
})()`;try{let result=await session.send("Runtime.evaluate",{expression,returnByValue:!0,timeout:500});if(result.exceptionDetails)return null;let value=result.result?.value;if(value&&typeof value.traceId=="string"&&typeof value.spanId=="string")return{traceId:value.traceId,spanId:value.spanId}}catch{}return null}function _createNodeSourceMapFetcher(){return async(url,baseUrl)=>{let filePath=null;if(url.startsWith("file://"))filePath=url.replace("file://","");else if(url.startsWith("/")||url.match(/^[a-zA-Z]:\\/))filePath=url;else if(baseUrl.startsWith("file://")){let baseDir=path2.dirname(baseUrl.replace("file://",""));filePath=path2.resolve(baseDir,url)}else if(!url.startsWith("http://")&&!url.startsWith("https://")){let baseDir=path2.dirname(baseUrl.replace(/^file:\/\//,""));filePath=path2.resolve(baseDir,url)}if(filePath)try{return fs.readFileSync(filePath,"utf-8")}catch{}return url.startsWith("http://")||url.startsWith("https://")?new Promise(resolve2=>{let req=(url.startsWith("https://")?https:http).get(url,res=>{if(res.statusCode!==200){resolve2(null);return}let data="";res.on("data",chunk=>{data+=chunk}),res.on("end",()=>resolve2(data))});req.on("error",()=>resolve2(null)),req.setTimeout(5e3,()=>{req.destroy(),resolve2(null)})}):null}}async function _captureScopes(v8Api,callFrame,maxDepth=3){let scopeSnapshots=[];for(let scope of callFrame.scopeChain)if(!(scope.type==="global"||scope.type==="script"||scope.type==="with"||scope.type==="eval"||scope.type==="wasm-expression-stack")){if(scopeSnapshots.length>=maxDepth)break;try{let variables=await v8Api.getScopeVariables(scope),scopeVariables=[];for(let[name,value]of Object.entries(variables))scopeVariables.push({name,value,type:typeof value});scopeSnapshots.push({type:scope.type,name:scope.name,variables:scopeVariables})}catch{}}return scopeSnapshots}async function _callFrameToSnapshot(v8Api,frame,captureScopes,sourceMapResolver){let scopes=[];captureScopes&&(scopes=await _captureScopes(v8Api,frame));let originalLocation;if(sourceMapResolver){let resolved=sourceMapResolver.generatedToOriginal(frame.location.scriptId,frame.location.lineNumber,frame.location.columnNumber??0);resolved&&(originalLocation={source:resolved.source,line:resolved.line+1,column:resolved.column!==void 0?resolved.column+1:void 0,name:resolved.name})}return{functionName:frame.functionName||"(anonymous)",url:frame.url||"",lineNumber:frame.location.lineNumber+1,columnNumber:frame.location.columnNumber!==void 0?frame.location.columnNumber+1:void 0,scriptId:frame.location.scriptId,scopes,originalLocation}}function _convertAsyncStackTrace(asyncTrace,sourceMapResolver,maxSegments,maxFramesPerSegment){if(!asyncTrace)return;let maxSegs=maxSegments??DEFAULT_NODE_DEBUG_CONFIG.maxAsyncStackSegments,maxFrames=maxFramesPerSegment??DEFAULT_NODE_DEBUG_CONFIG.maxFramesPerAsyncSegment,segments=[],currentTrace=asyncTrace,segmentCount=0;for(;currentTrace&&segmentCount<maxSegs;){let asyncFrames=[];for(let frame of currentTrace.callFrames.slice(0,maxFrames)){let originalLocation;if(sourceMapResolver){let resolved=sourceMapResolver.generatedToOriginal(frame.location.scriptId,frame.location.lineNumber,frame.location.columnNumber??0);resolved&&(originalLocation={source:resolved.source,line:resolved.line+1,column:resolved.column!==void 0?resolved.column+1:void 0,name:resolved.name})}asyncFrames.push({functionName:frame.functionName||"(anonymous)",url:frame.url||"",lineNumber:frame.location.lineNumber+1,columnNumber:frame.location.columnNumber!==void 0?frame.location.columnNumber+1:void 0,originalLocation})}asyncFrames.length>0&&segments.push({description:currentTrace.description,callFrames:asyncFrames}),currentTrace=currentTrace.parent,segmentCount++}return segments.length===0?void 0:{segments}}async function _evaluateWatchExpressionsOnFrame(v8Api,callFrameId,watchExpressions){let results={};for(let watch of watchExpressions.values())try{let result=await v8Api.evaluateOnCallFrame(callFrameId,watch.expression);result.exceptionDetails?results[watch.expression]=`[Error: ${result.exceptionDetails.text||"Evaluation failed"}]`:results[watch.expression]=await v8Api.extractValueDeep(result.result,2)}catch(e){results[watch.expression]=`[Error: ${e.message||"Unknown error"}]`}return results}function getStoreKey(pid,wsUrl){return wsUrl||`pid:${pid}`}async function enableDebugging(storeKey,session,processInfo,v8Options,config){if(STORES.get(storeKey)?.enabled)return;let v8Api=new V8Api(session,v8Options),sourceMapResolver=new SourceMapResolver(_createNodeSourceMapFetcher()),mergedConfig={...DEFAULT_NODE_DEBUG_CONFIG,...config},store={v8Api,sourceMapResolver,probes:new Map,locationIndex:new Map,watchExpressions:new Map,snapshots:[],snapshotSequence:0,consoleMessages:[],consoleMessageSequence:0,config:mergedConfig,enabled:!1,sourceMapsLoaded:!1,exceptionBreakpoint:"none",session,processInfo};STORES.set(storeKey,store),await store.v8Api.enable(),session.on("Runtime.consoleAPICalled",params=>{let type=params.type||"log",args=params.args||[],text=_cdpArgsToText(args),levelName=_cdpConsoleTypeToLevelName(type),levelCode=ConsoleMessageLevel[levelName]?.code??1,location,stackTrace=params.stackTrace;if(stackTrace?.callFrames?.length){let frame=stackTrace.callFrames[0];location={url:frame.url||"",lineNumber:frame.lineNumber??0,columnNumber:frame.columnNumber??0}}store.consoleMessageSequence++,store.consoleMessages.push({type,text,level:{name:levelName,code:levelCode},location,timestamp:Date.now(),sequenceNumber:store.consoleMessageSequence}),store.consoleMessages.length>NODE_CONSOLE_MESSAGES_BUFFER_SIZE&&store.consoleMessages.splice(0,store.consoleMessages.length-NODE_CONSOLE_MESSAGES_BUFFER_SIZE)}),store.v8Api.on("scriptParsed",script=>{store.sourceMapResolver.registerScript(script)});for(let script of store.v8Api.getScripts())store.sourceMapResolver.registerScript(script);store.v8Api.on("paused",async event=>{let startTime=Date.now();try{let isException=event.reason==="exception"||event.reason==="promiseRejection",hitBreakpointIds=event.hitBreakpoints||[],hitProbes=[];for(let probe of store.probes.values()){if(!probe.enabled)continue;if(probe.v8BreakpointIds.some(id=>hitBreakpointIds.includes(id))){let conditionMet=!0;probe.hitCondition&&(conditionMet=_evaluateHitCondition(probe.hitCondition,probe.hitCount+1)),hitProbes.push({probe,conditionMet})}}let shouldCaptureBreakpoint=hitProbes.some(p=>p.conditionMet),shouldCaptureException=isException&&store.exceptionBreakpoint!=="none";for(let{probe}of hitProbes)probe.hitCount++,probe.lastHitAt=Date.now();if((shouldCaptureBreakpoint||shouldCaptureException)&&event.callFrames.length>0){let topFrame=event.callFrames[0],exceptionInfo;if(isException&&event.data){let excData=event.data;exceptionInfo={type:event.reason==="promiseRejection"?"promiseRejection":"exception",message:excData.description||excData.value||String(excData),name:excData.className,stack:excData.description}}let originalLocation,resolvedLoc=store.sourceMapResolver.generatedToOriginal(topFrame.location.scriptId,topFrame.location.lineNumber,topFrame.location.columnNumber??0);resolvedLoc&&(originalLocation={source:resolvedLoc.source,line:resolvedLoc.line+1,column:resolvedLoc.column!==void 0?resolvedLoc.column+1:void 0,name:resolvedLoc.name});let callStackFull=[],framesToProcess=event.callFrames.slice(0,store.config.maxCallStackDepth);for(let i=0;i<framesToProcess.length;i++)callStackFull.push(await _callFrameToSnapshot(store.v8Api,framesToProcess[i],i<store.config.maxFramesWithScopes,store.sourceMapResolver));let asyncStackTraceFull=_convertAsyncStackTrace(event.asyncStackTrace,store.sourceMapResolver,store.config.maxAsyncStackSegments,store.config.maxFramesPerAsyncSegment),traceContext=await _getOtelTraceContext(store.session),probesToCapture=hitProbes.filter(p=>p.conditionMet),snapshotCount=probesToCapture.length+(shouldCaptureException?1:0);for(let s=0;s<snapshotCount;s++){let probeId,isLogpoint,logResult,callStack,asyncStackTrace,watchResults;if(s<probesToCapture.length){let{probe}=probesToCapture[s];if(probeId=probe.id,isLogpoint=probe.kind==="logpoint",isLogpoint&&probe.logExpression)try{let evalResult=await store.v8Api.evaluateOnCallFrame(topFrame.callFrameId,probe.logExpression,{returnByValue:!0,generatePreview:!0});logResult=store.v8Api.extractValue(evalResult.result)}catch{logResult="[evaluation error]"}else logResult=void 0;isLogpoint?(callStack=[],asyncStackTrace=void 0,watchResults=void 0):(callStack=callStackFull,asyncStackTrace=asyncStackTraceFull,watchResults=store.watchExpressions.size>0?await _evaluateWatchExpressionsOnFrame(store.v8Api,topFrame.callFrameId,store.watchExpressions):void 0)}else probeId="__exception__",isLogpoint=!1,logResult=void 0,callStack=callStackFull,asyncStackTrace=asyncStackTraceFull,watchResults=store.watchExpressions.size>0?await _evaluateWatchExpressionsOnFrame(store.v8Api,topFrame.callFrameId,store.watchExpressions):void 0;let snapshot={id:_generateId(),probeId,timestamp:Date.now(),sequenceNumber:++store.snapshotSequence,url:topFrame.url||"",lineNumber:topFrame.location.lineNumber+1,columnNumber:topFrame.location.columnNumber!==void 0?topFrame.location.columnNumber+1:void 0,originalLocation,exception:exceptionInfo,callStack,asyncStackTrace,logResult,watchResults,captureTimeMs:Date.now()-startTime,traceContext:traceContext??void 0};store.snapshots.push(snapshot)}store.snapshots.length>store.config.maxSnapshots&&store.snapshots.splice(0,store.snapshots.length-store.config.maxSnapshots)}}finally{await store.v8Api.resume()}}),store.enabled=!0,store.sourceMapResolver.loadAllSourceMaps().then(()=>{store.sourceMapsLoaded=!0}).catch(()=>{})}async function disableDebugging(storeKey){let store=STORES.get(storeKey);if(store?.enabled){for(let entry of store.locationIndex.values())try{await store.v8Api.removeBreakpoint(entry.breakpointId)}catch{}store.locationIndex.clear(),store.probes.clear(),store.snapshots.length=0,store.snapshotSequence=0,store.consoleMessages.length=0,store.consoleMessageSequence=0,await store.v8Api.disable(),store.enabled=!1}}async function detachDebugging(storeKey){let store=STORES.get(storeKey);store&&(await disableDebugging(storeKey),await store.v8Api.detach(),STORES.delete(storeKey))}function isDebuggingEnabled(storeKey){return STORES.get(storeKey)?.enabled??!1}function getStore(storeKey){return STORES.get(storeKey)}async function resolveSourceLocation(storeKey,url,line,column=1){let store=STORES.get(storeKey);if(!store?.enabled)throw new Error("Not connected to Node.js process or debugging not enabled. Call debug_connect first.");let resolved=await store.sourceMapResolver.resolveLocationByUrl(url,line,column);return resolved?{source:resolved.source,line:resolved.line+1,column:resolved.column+1,name:resolved.name}:null}function listStoreKeys(){return Array.from(STORES.keys())}async function setExceptionBreakpoint(storeKey,state){let store=STORES.get(storeKey);if(!store?.enabled)throw new Error("Debugging is not enabled");await store.v8Api.setPauseOnExceptions(state),store.exceptionBreakpoint=state}function getExceptionBreakpoint(storeKey){return STORES.get(storeKey)?.exceptionBreakpoint??"none"}async function createProbe(storeKey,options){let store=STORES.get(storeKey);if(!store?.enabled)throw new Error("Debugging is not enabled");let probeId=_generateId(),columnNormalized=options.columnNumber??1,locationKey=_locationKey(options.urlPattern,options.lineNumber,columnNormalized),existingEntry=store.locationIndex.get(locationKey);if(existingEntry){existingEntry.refCount++;let probe2={id:probeId,kind:options.kind,enabled:!0,urlPattern:options.urlPattern,lineNumber:options.lineNumber,columnNumber:options.columnNumber,condition:options.condition,logExpression:options.logExpression,hitCondition:options.hitCondition,v8BreakpointIds:[existingEntry.breakpointId],resolvedLocations:existingEntry.resolvedLocations,hitCount:0,createdAt:Date.now()};return store.probes.set(probeId,probe2),probe2}let fullCondition=options.condition?`(${options.condition})`:"true",line0based=options.lineNumber-1,column0based=columnNormalized-1,resolved=store.sourceMapResolver.originalToGenerated(options.urlPattern,line0based,column0based),breakpointId,resolvedLocationsCount=0;if(resolved)try{breakpointId=(await store.v8Api.setBreakpoint({scriptId:resolved.scriptId,lineNumber:resolved.location.line,columnNumber:resolved.location.column},fullCondition)).breakpointId,resolvedLocationsCount=1}catch{let scriptUrl=store.sourceMapResolver.getScriptUrl(resolved.scriptId);if(scriptUrl){let result=await store.v8Api.setBreakpointByUrl({url:scriptUrl,lineNumber:resolved.location.line,columnNumber:resolved.location.column,condition:fullCondition});breakpointId=result.breakpointId,resolvedLocationsCount=result.locations.length}else throw new Error("Failed to set breakpoint at resolved location and could not fall back (script URL unknown). A probe may already exist at this line; remove it first or use a different line.")}else{let urlRegex=options.urlPattern.replace(/\\([.*+?^${}()|[\]\\/-])/g,"$1").replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,".*").replace(/\\\?/g,"."),result=await store.v8Api.setBreakpointByUrl({urlRegex,lineNumber:options.lineNumber-1,columnNumber:options.columnNumber?options.columnNumber-1:void 0,condition:fullCondition});breakpointId=result.breakpointId,resolvedLocationsCount=result.locations.length}store.locationIndex.set(locationKey,{breakpointId,resolvedLocations:resolvedLocationsCount,refCount:1});let probe={id:probeId,kind:options.kind,enabled:!0,urlPattern:options.urlPattern,lineNumber:options.lineNumber,columnNumber:options.columnNumber,condition:options.condition,logExpression:options.logExpression,hitCondition:options.hitCondition,v8BreakpointIds:[breakpointId],resolvedLocations:resolvedLocationsCount,hitCount:0,createdAt:Date.now()};return store.probes.set(probeId,probe),probe}async function removeProbe(storeKey,probeId){let store=STORES.get(storeKey);if(!store)return!1;let probe=store.probes.get(probeId);if(!probe)return!1;let locationKey=_locationKey(probe.urlPattern,probe.lineNumber,probe.columnNumber??1),entry=store.locationIndex.get(locationKey);if(entry&&(entry.refCount--,entry.refCount===0)){try{await store.v8Api.removeBreakpoint(entry.breakpointId)}catch{}store.locationIndex.delete(locationKey)}return store.probes.delete(probeId),!0}function listProbes(storeKey){return Array.from(STORES.get(storeKey)?.probes.values()??[])}async function clearProbes(storeKey){let store=STORES.get(storeKey);if(!store)return 0;let count=store.probes.size;for(let entry of store.locationIndex.values())try{await store.v8Api.removeBreakpoint(entry.breakpointId)}catch{}return store.locationIndex.clear(),store.probes.clear(),count}function getSnapshots(storeKey){return[...STORES.get(storeKey)?.snapshots??[]]}function getSnapshotsByProbe(storeKey,probeId){return(STORES.get(storeKey)?.snapshots??[]).filter(s=>s.probeId===probeId)}function clearSnapshots(storeKey){let store=STORES.get(storeKey);if(!store)return 0;let count=store.snapshots.length;return store.snapshots.length=0,count}function clearSnapshotsByProbe(storeKey,probeId){let store=STORES.get(storeKey);if(!store)return 0;let before=store.snapshots.length;return store.snapshots=store.snapshots.filter(s=>s.probeId!==probeId),before-store.snapshots.length}function getSnapshotStats(storeKey){let store=STORES.get(storeKey);if(!store||store.snapshots.length===0)return{totalSnapshots:0,snapshotsByProbe:{},averageCaptureTimeMs:0};let snapshotsByProbe={},totalCaptureTime=0;for(let s of store.snapshots)snapshotsByProbe[s.probeId]=(snapshotsByProbe[s.probeId]||0)+1,totalCaptureTime+=s.captureTimeMs;return{totalSnapshots:store.snapshots.length,snapshotsByProbe,oldestTimestamp:store.snapshots[0].timestamp,newestTimestamp:store.snapshots[store.snapshots.length-1].timestamp,averageCaptureTimeMs:totalCaptureTime/store.snapshots.length}}function getConsoleMessages(storeKey){return[...STORES.get(storeKey)?.consoleMessages??[]]}function addWatchExpression(storeKey,expression){let store=STORES.get(storeKey);if(!store)throw new Error("Debug store not initialized");let id=_generateId(),watchExpr={id,expression,createdAt:Date.now()};return store.watchExpressions.set(id,watchExpr),watchExpr}function removeWatchExpression(storeKey,watchExpressionId){return STORES.get(storeKey)?.watchExpressions.delete(watchExpressionId)??!1}function listWatchExpressions(storeKey){return Array.from(STORES.get(storeKey)?.watchExpressions.values()??[])}function clearWatchExpressions(storeKey){let store=STORES.get(storeKey);if(!store)return 0;let count=store.watchExpressions.size;return store.watchExpressions.clear(),count}async function loadSourceMaps(storeKey){let store=STORES.get(storeKey);if(!store?.enabled)throw new Error("Debugging is not enabled");let loaded=await store.sourceMapResolver.loadAllSourceMaps(),sources=store.sourceMapResolver.getOriginalSources();return store.sourceMapsLoaded=!0,{loaded,sources}}function hasSourceMaps(storeKey){return STORES.get(storeKey)?.sourceMapResolver.hasSourceMaps()??!1}function getOriginalSources(storeKey){return STORES.get(storeKey)?.sourceMapResolver.getOriginalSources()??[]}function getScripts(storeKey){return STORES.get(storeKey)?.v8Api.getScripts()??[]}function wrapScriptInAsyncIIFE(script){return`(async function() { ${script} })()`}function formatEvaluationException(exc){let parts=[],text=exc.text??exc.description;text&&parts.push(text);let desc=exc.exception?.description;desc&&desc!==text&&parts.push(desc);let className=exc.exception?.className;className&&!parts.some(p=>p.includes(className))&&parts.push(className),parts.length===0&&parts.push(JSON.stringify(exc));let stack=exc.stackTrace?.callFrames?.slice(0,5).map(f=>` at ${f.functionName??"?"} (${f.url??"?"}:${f.lineNumber??0})`).join(`
|
|
14
14
|
`);return stack&&parts.push(`Stack:
|
|
15
|
-
${stack}`),parts.join(" \u2014 ")}async function evaluateInNode(storeKey,expression,timeoutMs=5e3){let store=STORES.get(storeKey);if(!store?.enabled)throw new Error("Not connected to Node.js process or debugging not enabled. Call debug_connect first.");let codeToRun=wrapScriptInAsyncIIFE(expression),result=await store.session.send("Runtime.evaluate",{expression:codeToRun,returnByValue:!0,awaitPromise:!0,timeout:Math.min(timeoutMs,3e4)});if(result.exceptionDetails){let exc=result.exceptionDetails,message=formatEvaluationException(exc);throw new Error(`Node evaluation failed: ${message}`)}return store.v8Api.extractValue(result.result)}export{PORT,TOOL_OUTPUT_SCHEMA_DISABLE,PLATFORM,SESSION_IDLE_SECONDS,SESSION_IDLE_CHECK_SECONDS,SESSION_CLOSE_ON_SOCKET_CLOSE,BROWSER_HEADLESS_ENABLE,BROWSER_PERSISTENT_ENABLE,BROWSER_PERSISTENT_USER_DATA_DIR,BROWSER_USE_INSTALLED_ON_SYSTEM,BROWSER_EXECUTABLE_PATH,BROWSER_LOCALE,BROWSER_CONSOLE_MESSAGES_BUFFER_SIZE,BROWSER_HTTP_REQUESTS_BUFFER_SIZE,NODE_CONSOLE_MESSAGES_BUFFER_SIZE,NODE_INSPECTOR_HOST,OTEL_ENABLE,OTEL_SERVICE_NAME,OTEL_SERVICE_VERSION,OTEL_ASSETS_DIR,OTEL_INSTRUMENTATION_USER_INTERACTION_EVENTS,OTEL_EXPORTER_TYPE,OTEL_EXPORTER_HTTP_URL,OTEL_EXPORTER_HTTP_HEADERS,AWS_REGION,AWS_PROFILE,AMAZON_BEDROCK_ENABLE,AMAZON_BEDROCK_IMAGE_EMBED_MODEL_ID,AMAZON_BEDROCK_TEXT_EMBED_MODEL_ID,AMAZON_BEDROCK_VISION_MODEL_ID,FIGMA_ACCESS_TOKEN,FIGMA_API_BASE_URL,DAEMON_PORT,DAEMON_SESSION_IDLE_SECONDS,DAEMON_SESSION_IDLE_CHECK_SECONDS,enable,disable,isDebugEnabled,debug,info,warn,error,toJson,V8Api,SourceMapResolver,ConsoleMessageLevelName,ConsoleMessageLevel,ProbeKind,DEFAULT_NODE_DEBUG_CONFIG,getStoreKey,enableDebugging,disableDebugging,detachDebugging,isDebuggingEnabled,getStore,resolveSourceLocation,listStoreKeys,setExceptionBreakpoint,getExceptionBreakpoint,createProbe,removeProbe,listProbes,clearProbes,getSnapshots,getSnapshotsByProbe,clearSnapshots,clearSnapshotsByProbe,getSnapshotStats,getConsoleMessages,addWatchExpression,removeWatchExpression,listWatchExpressions,clearWatchExpressions,loadSourceMaps,hasSourceMaps,getOriginalSources,getScripts,evaluateInNode};
|
|
15
|
+
${stack}`),parts.join(" \u2014 ")}async function evaluateInNode(storeKey,expression,timeoutMs=5e3){let store=STORES.get(storeKey);if(!store?.enabled)throw new Error("Not connected to Node.js process or debugging not enabled. Call debug_connect first.");let codeToRun=wrapScriptInAsyncIIFE(expression),result=await store.session.send("Runtime.evaluate",{expression:codeToRun,returnByValue:!0,awaitPromise:!0,timeout:Math.min(timeoutMs,3e4)});if(result.exceptionDetails){let exc=result.exceptionDetails,message=formatEvaluationException(exc);throw new Error(`Node evaluation failed: ${message}`)}return store.v8Api.extractValue(result.result)}export{PORT,TOOL_OUTPUT_SCHEMA_DISABLE,AVAILABLE_TOOL_DOMAINS,PLATFORM,SESSION_IDLE_SECONDS,SESSION_IDLE_CHECK_SECONDS,SESSION_CLOSE_ON_SOCKET_CLOSE,BROWSER_HEADLESS_ENABLE,BROWSER_PERSISTENT_ENABLE,BROWSER_PERSISTENT_USER_DATA_DIR,BROWSER_USE_INSTALLED_ON_SYSTEM,BROWSER_EXECUTABLE_PATH,BROWSER_LOCALE,BROWSER_CONSOLE_MESSAGES_BUFFER_SIZE,BROWSER_HTTP_REQUESTS_BUFFER_SIZE,NODE_CONSOLE_MESSAGES_BUFFER_SIZE,NODE_INSPECTOR_HOST,OTEL_ENABLE,OTEL_SERVICE_NAME,OTEL_SERVICE_VERSION,OTEL_ASSETS_DIR,OTEL_INSTRUMENTATION_USER_INTERACTION_EVENTS,OTEL_EXPORTER_TYPE,OTEL_EXPORTER_HTTP_URL,OTEL_EXPORTER_HTTP_HEADERS,AWS_REGION,AWS_PROFILE,AMAZON_BEDROCK_ENABLE,AMAZON_BEDROCK_IMAGE_EMBED_MODEL_ID,AMAZON_BEDROCK_TEXT_EMBED_MODEL_ID,AMAZON_BEDROCK_VISION_MODEL_ID,FIGMA_ACCESS_TOKEN,FIGMA_API_BASE_URL,DAEMON_PORT,DAEMON_SESSION_IDLE_SECONDS,DAEMON_SESSION_IDLE_CHECK_SECONDS,enable,disable,isDebugEnabled,debug,info,warn,error,toJson,V8Api,SourceMapResolver,ConsoleMessageLevelName,ConsoleMessageLevel,ProbeKind,DEFAULT_NODE_DEBUG_CONFIG,getStoreKey,enableDebugging,disableDebugging,detachDebugging,isDebuggingEnabled,getStore,resolveSourceLocation,listStoreKeys,setExceptionBreakpoint,getExceptionBreakpoint,createProbe,removeProbe,listProbes,clearProbes,getSnapshots,getSnapshotsByProbe,clearSnapshots,clearSnapshotsByProbe,getSnapshotStats,getConsoleMessages,addWatchExpression,removeWatchExpression,listWatchExpressions,clearWatchExpressions,loadSourceMaps,hasSourceMaps,getOriginalSources,getScripts,evaluateInNode};
|
|
@@ -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-247YVH6X.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};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
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,BROWSER_CONSOLE_MESSAGES_BUFFER_SIZE,BROWSER_EXECUTABLE_PATH,BROWSER_HEADLESS_ENABLE,BROWSER_HTTP_REQUESTS_BUFFER_SIZE,BROWSER_LOCALE,BROWSER_PERSISTENT_ENABLE,BROWSER_PERSISTENT_USER_DATA_DIR,BROWSER_USE_INSTALLED_ON_SYSTEM,ConsoleMessageLevel,ConsoleMessageLevelName,FIGMA_ACCESS_TOKEN,FIGMA_API_BASE_URL,NODE_CONSOLE_MESSAGES_BUFFER_SIZE,NODE_INSPECTOR_HOST,OTEL_ASSETS_DIR,OTEL_ENABLE,OTEL_EXPORTER_HTTP_HEADERS,OTEL_EXPORTER_HTTP_URL,OTEL_EXPORTER_TYPE,OTEL_INSTRUMENTATION_USER_INTERACTION_EVENTS,OTEL_SERVICE_NAME,OTEL_SERVICE_VERSION,PLATFORM,SourceMapResolver,V8Api,addWatchExpression,clearWatchExpressions,createProbe,debug,detachDebugging,enableDebugging,evaluateInNode,getConsoleMessages,getExceptionBreakpoint,getSnapshotStats,getSnapshots,getSnapshotsByProbe,getStoreKey,hasSourceMaps,isDebuggingEnabled,listProbes,listWatchExpressions,removeProbe,removeWatchExpression,resolveSourceLocation,setExceptionBreakpoint,toJson,warn}from"./core-
|
|
1
|
+
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,BROWSER_CONSOLE_MESSAGES_BUFFER_SIZE,BROWSER_EXECUTABLE_PATH,BROWSER_HEADLESS_ENABLE,BROWSER_HTTP_REQUESTS_BUFFER_SIZE,BROWSER_LOCALE,BROWSER_PERSISTENT_ENABLE,BROWSER_PERSISTENT_USER_DATA_DIR,BROWSER_USE_INSTALLED_ON_SYSTEM,ConsoleMessageLevel,ConsoleMessageLevelName,FIGMA_ACCESS_TOKEN,FIGMA_API_BASE_URL,NODE_CONSOLE_MESSAGES_BUFFER_SIZE,NODE_INSPECTOR_HOST,OTEL_ASSETS_DIR,OTEL_ENABLE,OTEL_EXPORTER_HTTP_HEADERS,OTEL_EXPORTER_HTTP_URL,OTEL_EXPORTER_TYPE,OTEL_INSTRUMENTATION_USER_INTERACTION_EVENTS,OTEL_SERVICE_NAME,OTEL_SERVICE_VERSION,PLATFORM,SourceMapResolver,V8Api,addWatchExpression,clearWatchExpressions,createProbe,debug,detachDebugging,enableDebugging,evaluateInNode,getConsoleMessages,getExceptionBreakpoint,getSnapshotStats,getSnapshots,getSnapshotsByProbe,getStoreKey,hasSourceMaps,isDebuggingEnabled,listProbes,listWatchExpressions,removeProbe,removeWatchExpression,resolveSourceLocation,setExceptionBreakpoint,toJson,warn}from"./core-247YVH6X.js";var INTERACTIVE_ROLES=new Set(["button","link","textbox","checkbox","radio","combobox","listbox","menuitem","menuitemcheckbox","menuitemradio","option","searchbox","slider","spinbutton","switch","tab","treeitem"]),CONTENT_ROLES=new Set(["heading","cell","gridcell","columnheader","rowheader","listitem","article","region","main","navigation"]),STRUCTURAL_ROLES=new Set(["generic","group","list","table","row","rowgroup","grid","treegrid","menu","menubar","toolbar","tablist","tree","directory","document","application","presentation","none"]),refCounter=0;function nextRef(){return`e${++refCounter}`}function buildSelectorDescriptor(role,name){if(name!==void 0&&name!==""){let escaped=JSON.stringify(name);return`getByRole('${role}', { name: ${escaped}, exact: true })`}return`getByRole('${role}')`}function createRoleNameTracker(){let counts=new Map,refsByKey=new Map;return{getKey(role,name){return`${role}:${name??""}`},getNextIndex(role,name){let key=this.getKey(role,name),current=counts.get(key)??0;return counts.set(key,current+1),current},trackRef(role,name,ref){let key=this.getKey(role,name),refs=refsByKey.get(key)??[];refs.push(ref),refsByKey.set(key,refs)},getDuplicateKeys(){let duplicates=new Set;for(let[key,refs]of refsByKey)refs.length>1&&duplicates.add(key);return duplicates}}}function removeNthFromNonDuplicates(refs,tracker){let duplicateKeys=tracker.getDuplicateKeys();for(let entry of Object.values(refs)){let key=tracker.getKey(entry.role,entry.name);duplicateKeys.has(key)||delete entry.nth}}function getIndentLevel(line){let m=line.match(/^(\s*)/);return m?Math.floor(m[1].length/2):0}function processLine(line,refs,options,tracker){let depth=getIndentLevel(line);if(options.maxDepth!==void 0&&depth>options.maxDepth)return null;let match=line.match(/^(\s*-\s*)(\w+)(?:\s+"([^"]*)")?(.*)$/);if(!match)return options.interactiveOnly?null:line;let[,prefix,role,name,suffix]=match,roleLower=role.toLowerCase();if(role.startsWith("/"))return line;let isInteractive=INTERACTIVE_ROLES.has(roleLower),isContent=CONTENT_ROLES.has(roleLower),isStructural=STRUCTURAL_ROLES.has(roleLower);if(options.interactiveOnly&&!isInteractive||options.compact&&isStructural&&!name)return null;if(!(isInteractive||isContent&&name))return line;let ref=nextRef(),nth=tracker.getNextIndex(roleLower,name);tracker.trackRef(roleLower,name,ref);let entry={role:roleLower,name:name??void 0,selector:buildSelectorDescriptor(roleLower,name),nth};refs[ref]=entry;let enhanced=`${prefix}${role}`;return name&&(enhanced+=` "${name}"`),enhanced+=` [ref=${ref}]`,nth>0&&(enhanced+=` [nth=${nth}]`),suffix&&suffix.trim()&&(enhanced+=suffix),enhanced}function compactTree(tree){let lines=tree.split(`
|
|
2
2
|
`),result=[];for(let i=0;i<lines.length;i++){let line=lines[i];if(line.includes("[ref=")){result.push(line);continue}if(line.includes(":")&&!line.endsWith(":")){result.push(line);continue}let currentIndent=getIndentLevel(line),hasRelevantChildren=!1;for(let j=i+1;j<lines.length&&!(getIndentLevel(lines[j])<=currentIndent);j++)if(lines[j].includes("[ref=")){hasRelevantChildren=!0;break}hasRelevantChildren&&result.push(line)}return result.join(`
|
|
3
3
|
`)}function processAriaTreeWithRefs(ariaTree,options={}){refCounter=0;let refs={};if(!ariaTree||!ariaTree.trim())return{tree:"(empty)",refs:{}};let lines=ariaTree.split(`
|
|
4
4
|
`),result=[],tracker=createRoleNameTracker();if(options.interactiveOnly){for(let line of lines){let m=line.match(/^(\s*-\s*)(\w+)(?:\s+"([^"]*)")?(.*)$/);if(!m)continue;let[,,role,name,suffix]=m,roleLower=role.toLowerCase();if(!INTERACTIVE_ROLES.has(roleLower))continue;let ref=nextRef(),nth=tracker.getNextIndex(roleLower,name);tracker.trackRef(roleLower,name,ref),refs[ref]={role:roleLower,name:name??void 0,selector:buildSelectorDescriptor(roleLower,name),nth};let enhanced=`- ${role}`;name&&(enhanced+=` "${name}"`),enhanced+=` [ref=${ref}]`,nth>0&&(enhanced+=` [nth=${nth}]`),suffix&&suffix.includes("[")&&(enhanced+=suffix),result.push(enhanced)}return removeNthFromNonDuplicates(refs,tracker),{tree:result.length?result.join(`
|
|
5
5
|
`):"(no interactive elements)",refs}}for(let line of lines){let processed=processLine(line,refs,options,tracker);processed!==null&&result.push(processed)}removeNthFromNonDuplicates(refs,tracker);let tree=result.join(`
|
|
6
|
-
`);return options.compact&&(tree=compactTree(tree)),{tree,refs}}var NATIVE_INTERACTIVE_TAGS=new Set(["BUTTON","A","INPUT","SELECT","TEXTAREA"]),INTERACTIVE_ARIA_ROLES=new Set(["button","link","textbox","checkbox","radio","combobox","listbox","menuitem","menuitemcheckbox","menuitemradio","option","searchbox","slider","spinbutton","switch","tab","treeitem"]);async function findCursorInteractiveElements(page,rootSelector){let interactiveRolesList=[...INTERACTIVE_ARIA_ROLES],nativeTagsList=[...NATIVE_INTERACTIVE_TAGS],rootSel=rootSelector??null,result=await page.evaluate(args=>{let root=args.rootSel!=null?document.querySelector(args.rootSel):document.body;if(!root)return[];let interactiveRoles=new Set(args.interactiveRoles.map(r=>r.toLowerCase())),nativeTags=new Set(args.nativeTags.map(t=>t.toUpperCase())),candidates=[];function isCursorInteractive(el){let style=getComputedStyle(el);if(style.visibility==="hidden"||style.display==="none")return!1;let tag=el.tagName.toUpperCase();if(nativeTags.has(tag))return!1;let role=(el.getAttribute("role")||"").toLowerCase();if(role&&interactiveRoles.has(role))return!1;if(style.cursor==="pointer"||el.hasAttribute("onclick")||typeof el.onclick=="function")return!0;let tabindex=el.getAttribute("tabindex");return tabindex!=null&&parseInt(tabindex,10)>=0}function buildSelector(el){let tid=el.getAttribute("data-testid");if(tid&&tid.trim())try{return`[data-testid="${CSS.escape(tid)}"]`}catch{return`[data-testid="${tid.replace(/"/g,"\\22 ")}"]`}let id=el.id;if(id&&typeof document.querySelectorAll=="function")try{let escaped=CSS.escape(id);if(document.querySelectorAll(`#${escaped}`).length===1)return`#${escaped}`}catch{}let tag=el.tagName.toLowerCase(),cn=el.className&&typeof el.className=="string"?el.className.trim().split(/\s+/).filter(Boolean).slice(0,3).map(c=>"."+CSS.escape(c)).join(""):"";return tag+cn||tag}function getName(el){return(el.getAttribute("aria-label")||el.getAttribute("title")||el.textContent||"").trim().slice(0,80)||void 0}let all=root.querySelectorAll("*");for(let i=0;i<all.length;i++){let el=all[i];if(!isCursorInteractive(el))continue;let rect=el.getBoundingClientRect();if(rect.width===0&&rect.height===0)continue;let role=getComputedStyle(el).cursor==="pointer"||el.onclick!=null||el.hasAttribute("onclick")?"clickable":"focusable";candidates.push({selector:buildSelector(el),role,name:getName(el)})}let bySelector={};candidates.forEach(c=>{bySelector[c.selector]||(bySelector[c.selector]=[]),bySelector[c.selector].push(c)});let out=[];return candidates.forEach(c=>{let arr=bySelector[c.selector],idx=arr.indexOf(c);out.push({selector:c.selector,role:c.role,name:c.name,nth:arr.length>1?idx:void 0})}),out},{rootSel,interactiveRoles:interactiveRolesList,nativeTags:nativeTagsList});return Array.isArray(result)?result:[]}import{z}from"zod";async function takeAriaSnapshotWithRefs(context,options={}){let rawSnapshot=await context.page.locator(options.selector||"body").ariaSnapshot(),{tree,refs}=processAriaTreeWithRefs(rawSnapshot,{interactiveOnly:options.interactiveOnly,maxDepth:options.maxDepth,compact:options.compact}),mergedTree=tree,mergedRefs={...refs};if(options.cursorInteractive){let cursorEntries=await findCursorInteractiveElements(context.page,options.selector||null);if(cursorEntries.length>0){let maxNum=Object.keys(mergedRefs).reduce((m,k)=>{let n=parseInt(k.replace(/^e/,""),10)||0;return n>m?n:m},0),lines=[];cursorEntries.forEach((entry,i)=>{let ref=`e${maxNum+1+i}`;mergedRefs[ref]={role:entry.role,name:entry.name,selector:entry.selector,nth:entry.nth};let line=`- ${entry.role}`;entry.name&&(line+=` "${entry.name}"`),line+=` [ref=${ref}]`,entry.nth!==void 0&&entry.nth>0&&(line+=` [nth=${entry.nth}]`),lines.push(line)}),mergedTree=mergedTree+(mergedTree?`
|
|
6
|
+
`);return options.compact&&(tree=compactTree(tree)),{tree,refs}}var NATIVE_INTERACTIVE_TAGS=new Set(["BUTTON","A","INPUT","SELECT","TEXTAREA"]),INTERACTIVE_ARIA_ROLES=new Set(["button","link","textbox","checkbox","radio","combobox","listbox","menuitem","menuitemcheckbox","menuitemradio","option","searchbox","slider","spinbutton","switch","tab","treeitem"]);async function findCursorInteractiveElements(page,rootSelector){let interactiveRolesList=[...INTERACTIVE_ARIA_ROLES],nativeTagsList=[...NATIVE_INTERACTIVE_TAGS],rootSel=rootSelector??null,result=await page.evaluate(args=>{let root=args.rootSel!=null?document.querySelector(args.rootSel):document.body;if(!root)return[];let interactiveRoles=new Set(args.interactiveRoles.map(r=>r.toLowerCase())),nativeTags=new Set(args.nativeTags.map(t=>t.toUpperCase())),candidates=[];function isCursorInteractive(el){let style=getComputedStyle(el);if(style.visibility==="hidden"||style.display==="none")return!1;let tag=el.tagName.toUpperCase();if(nativeTags.has(tag))return!1;let role=(el.getAttribute("role")||"").toLowerCase();if(role&&interactiveRoles.has(role))return!1;if(style.cursor==="pointer"||el.hasAttribute("onclick")||typeof el.onclick=="function")return!0;let tabindex=el.getAttribute("tabindex");return tabindex!=null&&parseInt(tabindex,10)>=0}function buildSelector(el){let tid=el.getAttribute("data-testid");if(tid&&tid.trim())try{return`[data-testid="${CSS.escape(tid)}"]`}catch{return`[data-testid="${tid.replace(/"/g,"\\22 ")}"]`}let id=el.id;if(id&&typeof document.querySelectorAll=="function")try{let escaped=CSS.escape(id);if(document.querySelectorAll(`#${escaped}`).length===1)return`#${escaped}`}catch{}let tag=el.tagName.toLowerCase(),cn=el.className&&typeof el.className=="string"?el.className.trim().split(/\s+/).filter(Boolean).slice(0,3).map(c=>"."+CSS.escape(c)).join(""):"";return tag+cn||tag}function getName(el){return(el.getAttribute("aria-label")||el.getAttribute("title")||el.textContent||"").trim().slice(0,80)||void 0}let all=root.querySelectorAll("*");for(let i=0;i<all.length;i++){let el=all[i];if(!isCursorInteractive(el))continue;let rect=el.getBoundingClientRect();if(rect.width===0&&rect.height===0)continue;let role=getComputedStyle(el).cursor==="pointer"||el.onclick!=null||el.hasAttribute("onclick")?"clickable":"focusable";candidates.push({selector:buildSelector(el),role,name:getName(el)})}let bySelector={};candidates.forEach(c=>{bySelector[c.selector]||(bySelector[c.selector]=[]),bySelector[c.selector].push(c)});let out=[];return candidates.forEach(c=>{let arr=bySelector[c.selector],idx=arr.indexOf(c);out.push({selector:c.selector,role:c.role,name:c.name,nth:arr.length>1?idx:void 0})}),out},{rootSel,interactiveRoles:interactiveRolesList,nativeTags:nativeTagsList});return Array.isArray(result)?result:[]}import{z}from"zod";async function takeAriaSnapshotWithRefs(context,options={}){let rawSnapshot=await context.page.locator(options.selector||"body").first().ariaSnapshot(),{tree,refs}=processAriaTreeWithRefs(rawSnapshot,{interactiveOnly:options.interactiveOnly,maxDepth:options.maxDepth,compact:options.compact}),mergedTree=tree,mergedRefs={...refs};if(options.cursorInteractive){let cursorEntries=await findCursorInteractiveElements(context.page,options.selector||null);if(cursorEntries.length>0){let maxNum=Object.keys(mergedRefs).reduce((m,k)=>{let n=parseInt(k.replace(/^e/,""),10)||0;return n>m?n:m},0),lines=[];cursorEntries.forEach((entry,i)=>{let ref=`e${maxNum+1+i}`;mergedRefs[ref]={role:entry.role,name:entry.name,selector:entry.selector,nth:entry.nth};let line=`- ${entry.role}`;entry.name&&(line+=` "${entry.name}"`),line+=` [ref=${ref}]`,entry.nth!==void 0&&entry.nth>0&&(line+=` [nth=${entry.nth}]`),lines.push(line)}),mergedTree=mergedTree+(mergedTree?`
|
|
7
7
|
`:"")+`# Cursor-interactive elements
|
|
8
8
|
`+lines.join(`
|
|
9
9
|
`)}}return context.setRefMap(mergedRefs),{output:`
|
|
@@ -277,11 +277,11 @@ By default, all <script> tags are removed from the output unless "removeScripts"
|
|
|
277
277
|
`}inputSchema(){return{selector:z3.string().describe("CSS selector to limit the HTML content to a specific container.").optional(),removeScripts:z3.boolean().describe('Remove all script tags from the HTML (default: "true").').optional().default(!0),removeComments:z3.boolean().describe('Remove all HTML comments (default: "false").').optional().default(!1),removeStyles:z3.boolean().describe('Remove all style tags from the HTML (default: "false").').optional().default(!1),removeMeta:z3.boolean().describe('Remove all meta tags from the HTML (default: "false").').optional().default(!1),cleanHtml:z3.boolean().describe('Perform comprehensive HTML cleaning (default: "false").').optional().default(!1),minify:z3.boolean().describe('Minify the HTML output (default: "false").').optional().default(!1),maxLength:z3.number().int().positive().describe(`Maximum number of characters to return (default: "${DEFAULT_MAX_HTML_LENGTH}").`).optional().default(DEFAULT_MAX_HTML_LENGTH)}}outputSchema(){return{output:z3.string().describe("The requested HTML content of the page.")}}async handle(context,args){let{selector,removeScripts,removeComments,removeStyles,removeMeta,minify,cleanHtml,maxLength}=args,htmlContent;if(selector){let element=await context.page.$(selector);if(!element)throw new Error(`Element with selector "${selector}" not found`);htmlContent=await element.evaluate(el=>el.outerHTML)}else htmlContent=await context.page.content();let shouldRemoveScripts=removeScripts||cleanHtml,shouldRemoveComments=removeComments||cleanHtml,shouldRemoveStyles=removeStyles||cleanHtml,shouldRemoveMeta=removeMeta||cleanHtml;(shouldRemoveScripts||shouldRemoveComments||shouldRemoveStyles||shouldRemoveMeta||minify)&&(htmlContent=await context.page.evaluate(params=>{let html=params.html,removeScripts2=params.removeScripts,removeComments2=params.removeComments,removeStyles2=params.removeStyles,removeMeta2=params.removeMeta,minify2=params.minify,template=document.createElement("template");template.innerHTML=html;let root=template.content;if(removeScripts2&&root.querySelectorAll("script").forEach(script=>script.remove()),removeStyles2&&root.querySelectorAll("style").forEach(style=>style.remove()),removeMeta2&&root.querySelectorAll("meta").forEach(meta=>meta.remove()),removeComments2){let removeComments3=node=>{let childNodes=node.childNodes;for(let i=childNodes.length-1;i>=0;i--){let child=childNodes[i];child.nodeType===8?node.removeChild(child):child.nodeType===1&&removeComments3(child)}};removeComments3(root)}let result=template.innerHTML;return minify2&&(result=result.replace(/>\s+</g,"><").trim()),result},{html:htmlContent,removeScripts:shouldRemoveScripts,removeComments:shouldRemoveComments,removeStyles:shouldRemoveStyles,removeMeta:shouldRemoveMeta,minify}));let output=htmlContent;return output.length>maxLength&&(output=output.slice(0,maxLength)+`
|
|
278
278
|
<!-- Output truncated due to size limits -->`),{output}}};import{z as z4}from"zod";var DEFAULT_MAX_TEXT_LENGTH=5e4,GetAsText=class{name(){return"content_get-as-text"}description(){return"Gets the visible text content of the current page."}inputSchema(){return{selector:z4.string().describe("CSS selector to limit the text content to a specific container.").optional(),maxLength:z4.number().int().positive().describe(`Maximum number of characters to return (default: "${DEFAULT_MAX_TEXT_LENGTH}").`).optional().default(DEFAULT_MAX_TEXT_LENGTH)}}outputSchema(){return{output:z4.string().describe("The requested text content of the page.")}}async handle(context,args){let{selector,maxLength}=args,output=await context.page.evaluate(params=>{let selector2=params.selector,root=selector2?document.querySelector(selector2):document.body;if(!root)throw new Error(`Element with selector "${selector2}" not found`);let walker=document.createTreeWalker(root,NodeFilter.SHOW_TEXT,{acceptNode:node2=>{let style=window.getComputedStyle(node2.parentElement);return style.display!=="none"&&style.visibility!=="hidden"?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT}}),text="",node;for(;node=walker.nextNode();){let trimmedText=node.textContent?.trim();trimmedText&&(text+=trimmedText+`
|
|
279
279
|
`)}return text.trim()},{selector});return output.length>maxLength&&(output=output.slice(0,maxLength)+`
|
|
280
|
-
[Output truncated due to size limits]`),{output}}};function getEnumKeyTuples(enumObj){let values=Object.keys(enumObj).filter(key=>isNaN(Number(key))).map(key=>enumObj[key]);if(values.length===0)throw new Error("Enum has no values");return values}function createEnumTransformer(enumObj,opts){let values=Object.keys(enumObj).filter(k=>isNaN(Number(k))).map(k=>enumObj[k]),caseInsensitive=opts?.caseInsensitive??!0,lookup=new Map(values.map(v=>[caseInsensitive?v.toLowerCase():v,v]));return value=>{let key=caseInsensitive?value.toLowerCase():value,found=lookup.get(key);if(found===void 0)throw new Error(`Invalid enum value: "${value}"`);return found}}function formattedTimeForFilename(date=new Date){let pad=n=>String(n).padStart(2,"0");return date.getFullYear()+pad(date.getMonth()+1)+pad(date.getDate())+"-"+pad(date.getHours())+pad(date.getMinutes())+pad(date.getSeconds())}import os from"node:os";import path from"node:path";import{z as z5}from"zod";var SizeUnit=(SizeUnit2=>(SizeUnit2.PIXEL="px",SizeUnit2.INCH="in",SizeUnit2.CENTIMETER="cm",SizeUnit2.MILLIMETER="mm",SizeUnit2))(SizeUnit||{}),PageFormat=(PageFormat2=>(PageFormat2.LETTER="Letter",PageFormat2.LEGAL="Legal",PageFormat2.TABLOID="Tabloid",PageFormat2.LEDGER="Ledger",PageFormat2.A0="A0",PageFormat2.A1="A1",PageFormat2.A2="A2",PageFormat2.A3="A3",PageFormat2.A4="A4",PageFormat2.A5="A5",PageFormat2.A6="A6",PageFormat2))(PageFormat||{}),DEFAULT_NAME="page",DEFAULT_MARGIN="1cm",DEFAULT_FORMAT="A4",DEFAULT_MARGINS={top:DEFAULT_MARGIN,right:DEFAULT_MARGIN,bottom:DEFAULT_MARGIN,left:DEFAULT_MARGIN},SaveAsPdf=class{name(){return"content_save-as-pdf"}description(){return"Saves the current page as a PDF file."}inputSchema(){return{outputPath:z5.string().describe("Directory path where PDF will be saved. By default OS tmp directory is used.").optional().default(os.tmpdir()),name:z5.string().describe(`Name of the save/export. Default value is "${DEFAULT_NAME}". Note that final saved/exported file name is in the "{name}-{time}.pdf" format in which "{time}" is in the "YYYYMMDD-HHmmss" format.`).optional().default(DEFAULT_NAME),format:z5.enum(getEnumKeyTuples(PageFormat)).transform(createEnumTransformer(PageFormat)).describe(`Page format. Valid values are: ${getEnumKeyTuples(PageFormat)}.`).optional().default(DEFAULT_FORMAT),printBackground:z5.boolean().describe('Whether to print background graphics (default: "false").').optional().default(!1),margin:z5.object({top:z5.string().describe("Top margin.").default(DEFAULT_MARGIN),right:z5.string().describe("Right margin.").default(DEFAULT_MARGIN),bottom:z5.string().describe("Bottom margin.").default(DEFAULT_MARGIN),left:z5.string().describe("Left margin.").default(DEFAULT_MARGIN)}).describe(`Page margins. Numeric margin values labeled with units ("100px", "10cm", etc ...). Unlabeled values are treated as pixels. Valid units are: ${getEnumKeyTuples(SizeUnit)}.`).optional()}}outputSchema(){return{filePath:z5.string().describe("Full path of the saved PDF file.")}}async handle(context,args){let filename=`${args.name||DEFAULT_NAME}-${formattedTimeForFilename()}.pdf`,filePath=path.resolve(args.outputPath,filename),options={path:filePath,format:args.format,printBackground:args.printBackground,margin:args.margin||DEFAULT_MARGINS};return await context.page.pdf(options),{filePath}}};var REF_ROLES_INTERACTIVE=new Set(["button","link","textbox","searchbox","checkbox","radio","combobox","listbox","menuitem","menuitemcheckbox","menuitemradio","option","slider","spinbutton","switch","tab","tabpanel","treeitem","listitem","row","cell","gridcell","columnheader","rowheader","separator","dialog","alertdialog","clickable","focusable"]);function parseRef(arg){let s=arg.trim();return s.startsWith("@")?s.slice(1):s.toLowerCase().startsWith("ref=")?s.slice(4):/^e\d+$/.test(s)?s:null}function getLocatorFromRef(page,refMap,ref){let data=refMap[ref];if(!data)return null;if(data.role==="clickable"||data.role==="focusable"){let locator2=page.locator(data.selector);return data.nth!==void 0?locator2.nth(data.nth):locator2}let locator;return data.name!==void 0&&data.name!==""?locator=page.getByRole(data.role,{name:data.name,exact:!0}):locator=page.getByRole(data.role),data.nth!==void 0
|
|
280
|
+
[Output truncated due to size limits]`),{output}}};function getEnumKeyTuples(enumObj){let values=Object.keys(enumObj).filter(key=>isNaN(Number(key))).map(key=>enumObj[key]);if(values.length===0)throw new Error("Enum has no values");return values}function createEnumTransformer(enumObj,opts){let values=Object.keys(enumObj).filter(k=>isNaN(Number(k))).map(k=>enumObj[k]),caseInsensitive=opts?.caseInsensitive??!0,lookup=new Map(values.map(v=>[caseInsensitive?v.toLowerCase():v,v]));return value=>{let key=caseInsensitive?value.toLowerCase():value,found=lookup.get(key);if(found===void 0)throw new Error(`Invalid enum value: "${value}"`);return found}}function formattedTimeForFilename(date=new Date){let pad=n=>String(n).padStart(2,"0");return date.getFullYear()+pad(date.getMonth()+1)+pad(date.getDate())+"-"+pad(date.getHours())+pad(date.getMinutes())+pad(date.getSeconds())}import os from"node:os";import path from"node:path";import{z as z5}from"zod";var SizeUnit=(SizeUnit2=>(SizeUnit2.PIXEL="px",SizeUnit2.INCH="in",SizeUnit2.CENTIMETER="cm",SizeUnit2.MILLIMETER="mm",SizeUnit2))(SizeUnit||{}),PageFormat=(PageFormat2=>(PageFormat2.LETTER="Letter",PageFormat2.LEGAL="Legal",PageFormat2.TABLOID="Tabloid",PageFormat2.LEDGER="Ledger",PageFormat2.A0="A0",PageFormat2.A1="A1",PageFormat2.A2="A2",PageFormat2.A3="A3",PageFormat2.A4="A4",PageFormat2.A5="A5",PageFormat2.A6="A6",PageFormat2))(PageFormat||{}),DEFAULT_NAME="page",DEFAULT_MARGIN="1cm",DEFAULT_FORMAT="A4",DEFAULT_MARGINS={top:DEFAULT_MARGIN,right:DEFAULT_MARGIN,bottom:DEFAULT_MARGIN,left:DEFAULT_MARGIN},SaveAsPdf=class{name(){return"content_save-as-pdf"}description(){return"Saves the current page as a PDF file."}inputSchema(){return{outputPath:z5.string().describe("Directory path where PDF will be saved. By default OS tmp directory is used.").optional().default(os.tmpdir()),name:z5.string().describe(`Name of the save/export. Default value is "${DEFAULT_NAME}". Note that final saved/exported file name is in the "{name}-{time}.pdf" format in which "{time}" is in the "YYYYMMDD-HHmmss" format.`).optional().default(DEFAULT_NAME),format:z5.enum(getEnumKeyTuples(PageFormat)).transform(createEnumTransformer(PageFormat)).describe(`Page format. Valid values are: ${getEnumKeyTuples(PageFormat)}.`).optional().default(DEFAULT_FORMAT),printBackground:z5.boolean().describe('Whether to print background graphics (default: "false").').optional().default(!1),margin:z5.object({top:z5.string().describe("Top margin.").default(DEFAULT_MARGIN),right:z5.string().describe("Right margin.").default(DEFAULT_MARGIN),bottom:z5.string().describe("Bottom margin.").default(DEFAULT_MARGIN),left:z5.string().describe("Left margin.").default(DEFAULT_MARGIN)}).describe(`Page margins. Numeric margin values labeled with units ("100px", "10cm", etc ...). Unlabeled values are treated as pixels. Valid units are: ${getEnumKeyTuples(SizeUnit)}.`).optional()}}outputSchema(){return{filePath:z5.string().describe("Full path of the saved PDF file.")}}async handle(context,args){let filename=`${args.name||DEFAULT_NAME}-${formattedTimeForFilename()}.pdf`,filePath=path.resolve(args.outputPath,filename),options={path:filePath,format:args.format,printBackground:args.printBackground,margin:args.margin||DEFAULT_MARGINS};return await context.page.pdf(options),{filePath}}};var REF_ROLES_INTERACTIVE=new Set(["button","link","textbox","searchbox","checkbox","radio","combobox","listbox","menuitem","menuitemcheckbox","menuitemradio","option","slider","spinbutton","switch","tab","tabpanel","treeitem","listitem","row","cell","gridcell","columnheader","rowheader","separator","dialog","alertdialog","clickable","focusable"]);function parseQuotedString(s,i){let q=s[i];if(q!=="'"&&q!=='"')return null;let j=i+1,parts=[];for(;j<s.length;){let c=s[j];if(c==="\\"){j++,j<s.length&&parts.push(s[j]),j++;continue}if(c===q)return{value:parts.join(""),end:j+1};parts.push(c),j++}return null}function parseRegexLiteral(s,i){if(s[i]!=="/")return null;let j=i+1;for(;j<s.length;){if(s[j]==="\\"){j+=2;continue}if(s[j]==="/")break;j++}if(j>=s.length)return null;let pattern=s.slice(i+1,j);j++;let flags="";for(;j<s.length&&/[gimsuy]/.test(s[j])&&!flags.includes(s[j]);)flags+=s[j],j++;try{return{value:new RegExp(pattern,flags),end:j}}catch{return null}}function parseOptionsObject(s,i){for(;i<s.length&&/\s/.test(s[i]);)i++;if(s[i]!=="{")return null;i++;let obj={};for(;i<s.length;){for(;i<s.length&&/\s/.test(s[i]);)i++;if(i>=s.length)return null;if(s[i]==="}")return{value:obj,end:i+1};let keyMatch=s.slice(i).match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*:/);if(!keyMatch)return null;let key=keyMatch[1];for(i+=keyMatch[0].length;i<s.length&&/\s/.test(s[i]);)i++;if(i>=s.length)return null;if(s[i]==="'"||s[i]==='"'){let parsed=parseQuotedString(s,i);if(!parsed)return null;obj[key]=parsed.value,i=parsed.end}else if(s[i]==="/"){let parsed=parseRegexLiteral(s,i);if(!parsed)return null;obj[key]=parsed.value,i=parsed.end}else if(s.slice(i).startsWith("true"))obj[key]=!0,i+=4;else if(s.slice(i).startsWith("false"))obj[key]=!1,i+=5;else{let numMatch=s.slice(i).match(/^-?\d+/);if(numMatch)obj[key]=parseInt(numMatch[0],10),i+=numMatch[0].length;else return null}for(;i<s.length&&/\s/.test(s[i]);)i++;if(i<s.length&&s[i]===","){i++;continue}break}for(;i<s.length&&/\s/.test(s[i]);)i++;return s[i]!=="}"?null:{value:obj,end:i+1}}function parseGetByArgs(inner){let s=inner.trim(),i=0;for(;i<s.length&&/\s/.test(s[i]);)i++;if(i>=s.length)return null;let first;if(s[i]==="'"||s[i]==='"'){let firstParsed=parseQuotedString(s,i);if(!firstParsed)return null;first=firstParsed.value,i=firstParsed.end}else if(s[i]==="/"){let regexParsed=parseRegexLiteral(s,i);if(!regexParsed)return null;first=regexParsed.value,i=regexParsed.end}else return null;for(;i<s.length&&/\s/.test(s[i]);)i++;if(i>=s.length)return{first};if(s[i]!==",")return{first};i++;let optParsed=parseOptionsObject(s,i);return optParsed?{first,options:optParsed.value}:{first}}function tryParsePlaywrightLocatorExpression(page,selectorOrExpression){let match=selectorOrExpression.trim().match(/^\s*(getByRole|getByLabel|getByText|getByPlaceholder|getByAltText|getByTitle|getByTestId)\s*\(\s*([\s\S]*)\s*\)\s*$/);if(!match)return null;let method=match[1],argsInner=match[2],parsed=parseGetByArgs(argsInner);if(!parsed)return null;let{first,options}=parsed;if(method==="getByTestId")return page.getByTestId(first).first();if(method==="getByRole"){if(typeof first!="string")return null;let opts=options??{},roleOpts={};return opts.name!==void 0&&(roleOpts.name=typeof opts.name=="string"||opts.name instanceof RegExp?opts.name:String(opts.name)),opts.exact!==void 0&&(roleOpts.exact=!!opts.exact),opts.checked!==void 0&&(roleOpts.checked=!!opts.checked),opts.disabled!==void 0&&(roleOpts.disabled=!!opts.disabled),opts.expanded!==void 0&&(roleOpts.expanded=!!opts.expanded),opts.includeHidden!==void 0&&(roleOpts.includeHidden=!!opts.includeHidden),opts.level!==void 0&&(roleOpts.level=Number(opts.level)),opts.pressed!==void 0&&(roleOpts.pressed=!!opts.pressed),opts.selected!==void 0&&(roleOpts.selected=!!opts.selected),page.getByRole(first,Object.keys(roleOpts).length>0?roleOpts:void 0).first()}let exactOpts=options&&options.exact!==void 0?{exact:!!options.exact}:void 0;switch(method){case"getByLabel":return page.getByLabel(first,exactOpts).first();case"getByText":return page.getByText(first,exactOpts).first();case"getByPlaceholder":return page.getByPlaceholder(first,exactOpts).first();case"getByAltText":return page.getByAltText(first,exactOpts).first();case"getByTitle":return page.getByTitle(first,exactOpts).first();default:return null}}function parseRef(arg){let s=arg.trim();return s.startsWith("@")?s.slice(1):s.toLowerCase().startsWith("ref=")?s.slice(4):/^e\d+$/.test(s)?s:null}function getLocatorFromRef(page,refMap,ref){let data=refMap[ref];if(!data)return null;if(data.role==="clickable"||data.role==="focusable"){let locator2=page.locator(data.selector);return data.nth!==void 0?locator2.nth(data.nth):locator2.first()}let locator;return data.name!==void 0&&data.name!==""?locator=page.getByRole(data.role,{name:data.name,exact:!0}):locator=page.getByRole(data.role),data.nth!==void 0?locator.nth(data.nth):locator.first()}function assertRefRole(context,selectorOrRef,allowedRoles,actionLabel,hint){let ref=parseRef(selectorOrRef),refMap=context.getRefMap();if(!ref||!refMap[ref])return;let entry=refMap[ref];if(allowedRoles.has(entry.role))return;let namePart=entry.name?` "${entry.name}"`:"";throw new Error(`Ref ${ref} points to a ${entry.role}${namePart}, which is not valid for ${actionLabel}. ${hint}`)}function resolveSelectorOrRef(context,selectorOrRef){let ref=parseRef(selectorOrRef),refMap=context.getRefMap();if(ref&&Object.keys(refMap).length>0){let locator=getLocatorFromRef(context.page,refMap,ref);if(locator)return locator}let playwrightLocator=tryParsePlaywrightLocatorExpression(context.page,selectorOrRef);return playwrightLocator||context.page.locator(selectorOrRef).first()}import os2 from"node:os";import path2 from"node:path";import jpegjs from"jpeg-js";import{PNG}from"pngjs";import{z as z6}from"zod";var ANNOTATION_OVERLAY_ID="__browser_devtools_mcp_annotations__",ANNOTATE_BOX_TIMEOUT_MS=2e3,ScreenshotType=(ScreenshotType2=>(ScreenshotType2.PNG="png",ScreenshotType2.JPEG="jpeg",ScreenshotType2))(ScreenshotType||{}),DEFAULT_SCREENSHOT_NAME="screenshot",DEFAULT_SCREENSHOT_TYPE="png",DEFAULT_SCREENSHOT_QUALITY=100,TakeScreenshot=class{name(){return"content_take-screenshot"}description(){return`Takes a screenshot of the current page or a specific element.
|
|
281
281
|
|
|
282
282
|
**Do NOT use this tool to understand page structure.** For structure, use the ARIA snapshot from the last navigation (go-to, go-back, go-forward, reload) or call a11y_take-aria-snapshot / a11y_take-ax-tree-snapshot. Use this tool ONLY when you need to verify a visual problem (e.g. design check, visual bug, contrast, layout) \u2014 not to "see" the page. When in doubt, use snapshots first; screenshot only if snapshots cannot answer the visual question.
|
|
283
283
|
|
|
284
|
-
The screenshot is always saved to disk; the file path is returned. Do NOT set includeBase64 to true unless the assistant cannot read the file from the returned path (e.g. remote server, container).`}inputSchema(){return{outputPath:z6.string().describe("Directory path where screenshot will be saved. By default OS tmp directory is used.").optional().default(os2.tmpdir()),name:z6.string().describe(`Name of the screenshot. Default value is "${DEFAULT_SCREENSHOT_NAME}". Note that final saved/exported file name is in the "{name}-{time}.{type}" format in which "{time}" is in the "YYYYMMDD-HHmmss" format.`).optional().default(DEFAULT_SCREENSHOT_NAME),selector:z6.string().describe("CSS selector for element to take screenshot.").optional(),fullPage:z6.boolean().describe('Whether to take a screenshot of the full scrollable page, instead of the currently visible viewport (default: "false").').optional().default(!1),type:z6.enum(getEnumKeyTuples(ScreenshotType)).transform(createEnumTransformer(ScreenshotType)).describe(`Page format. Valid values are: ${getEnumKeyTuples(ScreenshotType)}`).optional().default(DEFAULT_SCREENSHOT_TYPE),quality:z6.number().int().min(0).max(DEFAULT_SCREENSHOT_QUALITY).describe("The quality of the image, between 0-100. Not applicable to png images.").optional(),includeBase64:z6.boolean().describe("If true, includes base64 image data in the response (increases payload size). Default is false. The screenshot is always saved to disk; use the returned file path to read it. Set to true ONLY when the assistant cannot access the MCP server file system (e.g. remote/container). Avoid setting to true otherwise.").optional().default(!1),annotate:z6.boolean().optional().default(!1).describe("When true, overlay numbered labels on interactive elements (from last a11y_take-aria-snapshot refs). Labels [1],[2],... map to refs e1,e2,... When selector is also set, only elements overlapping the scoped element are annotated and returned; annotation box coordinates are relative to that element."),annotateContent:z6.boolean().optional().default(!1).describe("When true with annotate, also include content elements (headings, list items, etc.) in the overlay. Uses interactiveOnly: false when building refs for this screenshot."),annotateCursorInteractive:z6.boolean().optional().default(!1).describe("When true with annotate, also include cursor-interactive elements (clickable/focusable by CSS but no ARIA role) in the overlay. Takes a fresh ARIA snapshot with cursorInteractive for this screenshot.")}}outputSchema(){return{filePath:z6.string().describe("Full path of the saved screenshot file."),image:z6.object({data:z6.any().describe("Base64-encoded image data."),mimeType:z6.string().describe("MIME type of the image.")}).optional().describe('Image data included only when "includeBase64" input parameter is set to true.'),annotations:z6.array(z6.object({ref:z6.string(),number:z6.number(),role:z6.string(),name:z6.string().optional(),box:z6.object({x:z6.number(),y:z6.number(),width:z6.number(),height:z6.number()})})).optional().describe("When annotate is true, list of refs and bounding boxes. When selector is set: only annotations overlapping the element, box relative to that element. When fullPage is true: box is document-relative (matches the full-page image). Otherwise: viewport-relative.")}}_scaleImageToSize(image,size){let{data:src,width:w1,height:h1}=image,w2=Math.max(1,Math.floor(size.width)),h2=Math.max(1,Math.floor(size.height));if(w1===w2&&h1===h2)return image;if(w1<=0||h1<=0)throw new Error("Invalid input image");if(size.width<=0||size.height<=0||!isFinite(size.width)||!isFinite(size.height))throw new Error("Invalid output dimensions");let clamp=(v,lo,hi)=>v<lo?lo:v>hi?hi:v,weights=(t,o)=>{let t2=t*t,t3=t2*t;o[0]=-.5*t+1*t2-.5*t3,o[1]=1-2.5*t2+1.5*t3,o[2]=.5*t+2*t2-1.5*t3,o[3]=-.5*t2+.5*t3},srcRowStride=w1*4,dstRowStride=w2*4,xOff=new Int32Array(w2*4),xW=new Float32Array(w2*4),wx=new Float32Array(4),xScale=w1/w2;for(let x=0;x<w2;x++){let sx=(x+.5)*xScale-.5,sxi=Math.floor(sx),t=sx-sxi;weights(t,wx);let b=x*4,i0=clamp(sxi-1,0,w1-1),i1=clamp(sxi+0,0,w1-1),i2=clamp(sxi+1,0,w1-1),i3=clamp(sxi+2,0,w1-1);xOff[b+0]=i0<<2,xOff[b+1]=i1<<2,xOff[b+2]=i2<<2,xOff[b+3]=i3<<2,xW[b+0]=wx[0],xW[b+1]=wx[1],xW[b+2]=wx[2],xW[b+3]=wx[3]}let yRow=new Int32Array(h2*4),yW=new Float32Array(h2*4),wy=new Float32Array(4),yScale=h1/h2;for(let y=0;y<h2;y++){let sy=(y+.5)*yScale-.5,syi=Math.floor(sy),t=sy-syi;weights(t,wy);let b=y*4,j0=clamp(syi-1,0,h1-1),j1=clamp(syi+0,0,h1-1),j2=clamp(syi+1,0,h1-1),j3=clamp(syi+2,0,h1-1);yRow[b+0]=j0*srcRowStride,yRow[b+1]=j1*srcRowStride,yRow[b+2]=j2*srcRowStride,yRow[b+3]=j3*srcRowStride,yW[b+0]=wy[0],yW[b+1]=wy[1],yW[b+2]=wy[2],yW[b+3]=wy[3]}let dst=new Uint8Array(w2*h2*4);for(let y=0;y<h2;y++){let yb=y*4,rb0=yRow[yb+0],rb1=yRow[yb+1],rb2=yRow[yb+2],rb3=yRow[yb+3],wy0=yW[yb+0],wy1=yW[yb+1],wy2=yW[yb+2],wy3=yW[yb+3],dstBase=y*dstRowStride;for(let x=0;x<w2;x++){let xb=x*4,xo0=xOff[xb+0],xo1=xOff[xb+1],xo2=xOff[xb+2],xo3=xOff[xb+3],wx0=xW[xb+0],wx1=xW[xb+1],wx2=xW[xb+2],wx3=xW[xb+3],di=dstBase+(x<<2);for(let c=0;c<4;c++){let r0=src[rb0+xo0+c]*wx0+src[rb0+xo1+c]*wx1+src[rb0+xo2+c]*wx2+src[rb0+xo3+c]*wx3,r1=src[rb1+xo0+c]*wx0+src[rb1+xo1+c]*wx1+src[rb1+xo2+c]*wx2+src[rb1+xo3+c]*wx3,r2=src[rb2+xo0+c]*wx0+src[rb2+xo1+c]*wx1+src[rb2+xo2+c]*wx2+src[rb2+xo3+c]*wx3,r3=src[rb3+xo0+c]*wx0+src[rb3+xo1+c]*wx1+src[rb3+xo2+c]*wx2+src[rb3+xo3+c]*wx3,v=r0*wy0+r1*wy1+r2*wy2+r3*wy3;dst[di+c]=v<0?0:v>255?255:v|0}}}return{data:Buffer.from(dst.buffer),width:w2,height:h2}}_scaleImageToFitMessage(buffer,screenshotType){let MAX_PIXELS=12058624e-1,MAX_LINEAR_SIZE=1568,image=screenshotType==="png"?PNG.sync.read(buffer):jpegjs.decode(buffer,{maxMemoryUsageInMB:512}),pixels=image.width*image.height,shrink=Math.min(MAX_LINEAR_SIZE/image.width,MAX_LINEAR_SIZE/image.height,Math.sqrt(MAX_PIXELS/pixels));shrink>1&&(shrink=1);let width=image.width*shrink|0,height=image.height*shrink|0,scaledImage=this._scaleImageToSize(image,{width,height}),result,currentType=screenshotType,quality=screenshotType==="png"?75:70;screenshotType==="png"?(result=jpegjs.encode(scaledImage,quality).data,currentType="jpeg"):result=jpegjs.encode(scaledImage,quality).data;let iterations=0,MAX_ITERATIONS=5;for(;result.length>819200&&iterations<MAX_ITERATIONS;)quality=Math.max(50,quality-10),quality<=50&&result.length>819200&&(shrink*=.85,width=Math.max(200,image.width*shrink|0),height=Math.max(200,image.height*shrink|0),scaledImage=this._scaleImageToSize(image,{width,height})),result=jpegjs.encode(scaledImage,quality).data,iterations++;return result}async handle(context,args){let screenshotType=args.type||DEFAULT_SCREENSHOT_TYPE,filename=`${args.name||DEFAULT_SCREENSHOT_NAME}-${formattedTimeForFilename()}.${screenshotType}`,filePath=path2.resolve(args.outputPath,filename),quality=screenshotType==="png"?void 0:args.quality??DEFAULT_SCREENSHOT_QUALITY,overlayInjected=!1,annotations,scopedElement=null;if(args.selector&&(scopedElement=await context.page.$(args.selector),!scopedElement))throw new Error(`Element not found: ${args.selector}`);if(args.annotate){let refMap=context.getRefMap(),wantContent=args.annotateContent===!0,wantCursorInteractive=args.annotateCursorInteractive===!0;if(Object.keys(refMap).length===0||wantCursorInteractive||wantContent){let raw=await context.page.locator("body").ariaSnapshot(),{refs}=processAriaTreeWithRefs(raw,{interactiveOnly:!wantContent}),mergedRefs={...refs};if(wantCursorInteractive){let cursorEntries=await findCursorInteractiveElements(context.page,null);if(cursorEntries.length>0){let maxNum=Object.keys(mergedRefs).reduce((m,k)=>{let n=parseInt(k.replace(/^e/,""),10)||0;return n>m?n:m},0);cursorEntries.forEach((entry,i)=>{let ref=`e${maxNum+1+i}`;mergedRefs[ref]={role:entry.role,name:entry.name,selector:entry.selector,nth:entry.nth}})}}context.setRefMap(mergedRefs),refMap=mergedRefs}let entries=Object.entries(refMap),allBoxes=[];for(let[ref,data]of entries){let locator=getLocatorFromRef(context.page,refMap,ref);if(!locator)continue;let box=await locator.boundingBox({timeout:ANNOTATE_BOX_TIMEOUT_MS}).catch(()=>null);if(!box||box.width===0||box.height===0)continue;let num=parseInt(ref.replace(/^e/,""),10)||0;allBoxes.push({ref,number:num,role:data.role,name:data.name,box:{x:Math.round(box.x),y:Math.round(box.y),width:Math.round(box.width),height:Math.round(box.height)}})}allBoxes.sort((a,b)=>a.number-b.number);let boxes=allBoxes,overlayBoxesViewport=allBoxes;if(scopedElement){let elementBox=await scopedElement.boundingBox();if(elementBox&&elementBox.width>0&&elementBox.height>0){let overlapping=allBoxes.filter(a=>{let b=a.box;return b.x<elementBox.x+elementBox.width&&b.x+b.width>elementBox.x&&b.y<elementBox.y+elementBox.height&&b.y+b.height>elementBox.y});overlayBoxesViewport=overlapping,boxes=overlapping.map(a=>{let b=a.box,relX=Math.max(0,b.x-elementBox.x),relY=Math.max(0,b.y-elementBox.y),relRight=Math.min(b.x+b.width-elementBox.x,elementBox.width),relBottom=Math.min(b.y+b.height-elementBox.y,elementBox.height);return{...a,box:{x:Math.round(relX),y:Math.round(relY),width:Math.round(Math.max(0,relRight-relX)),height:Math.round(Math.max(0,relBottom-relY))}}})}}if(boxes.length>0){let overlayPayload={data:overlayBoxesViewport.map(a=>({number:a.number,x:a.box.x,y:a.box.y,width:a.box.width,height:a.box.height})),id:ANNOTATION_OVERLAY_ID};if(await context.page.evaluate(({data,id})=>{let sx=window.scrollX||0,sy=window.scrollY||0,c=document.createElement("div");c.id=id,c.style.cssText="position:absolute;top:0;left:0;width:0;height:0;pointer-events:none;z-index:2147483647;";for(let it of data){let dx=it.x+sx,dy=it.y+sy,b=document.createElement("div");b.style.cssText=`position:absolute;left:${dx}px;top:${dy}px;width:${it.width}px;height:${it.height}px;border:2px solid rgba(255,0,0,0.8);box-sizing:border-box;pointer-events:none;`;let l=document.createElement("div");l.textContent=String(it.number);let labelTop=dy<14?"2px":"-14px";l.style.cssText=`position:absolute;top:${labelTop};left:-2px;background:rgba(255,0,0,0.9);color:#fff;font:bold 11px/14px monospace;padding:0 4px;border-radius:2px;white-space:nowrap;`,b.appendChild(l),c.appendChild(b)}document.documentElement.appendChild(c)},overlayPayload),overlayInjected=!0,args.fullPage&&!scopedElement&&boxes.length>0){let scroll=await context.page.evaluate(()=>({x:window.scrollX||0,y:window.scrollY||0}));annotations=boxes.map(a=>({...a,box:{x:a.box.x+scroll.x,y:a.box.y+scroll.y,width:a.box.width,height:a.box.height}}))}else annotations=boxes}}let options={path:filePath,type:screenshotType,fullPage:!!args.fullPage,quality};scopedElement&&(options.element=scopedElement);try{let screenshot=await context.page.screenshot(options),result={filePath,...annotations&&annotations.length>0?{annotations}:{}};return args.includeBase64&&(result.image={data:this._scaleImageToFitMessage(screenshot,screenshotType),mimeType:`image/${screenshotType}`}),result}finally{overlayInjected&&await context.page.evaluate(id=>{let el=document.getElementById(id);el&&el.remove()},ANNOTATION_OVERLAY_ID).catch(()=>{})}}};var tools2=[new GetAsHtml,new GetAsText,new SaveAsPdf,new TakeScreenshot];import{z as z7}from"zod";var DEFAULT_DEBUG_CONFIG={maxSnapshots:1e3,maxCallStackDepth:20,maxFramesWithScopes:5,maxAsyncStackSegments:10,maxFramesPerAsyncSegment:10,maxDOMMutations:100,maxDOMHtmlSnippetLength:200,maxPendingRequests:1e3,maxResponseBodyLength:1e4,networkCleanupTimeoutMs:5e3},STORE_BY_CONTEXT=new WeakMap;function _generateId(){let t=Date.now(),r=Math.floor(Math.random()*1e6);return`${t.toString(36)}-${r.toString(36)}`}function _locationKey(urlPattern,lineNumber,columnNumber){return`${urlPattern}:${lineNumber}:${columnNumber}`}function _evaluateHitCondition(hitCondition,hitCount){try{let condition=hitCondition.trim();return/^[=<>!%]/.test(condition)&&(condition=`hitCount ${condition}`),!!new Function("hitCount",`return (${condition});`)(hitCount)}catch{return!1}}async function _evaluateWatchExpressionsOnFrame(v8Api,callFrameId,watchExpressions){let results={};for(let watch of watchExpressions.values())try{let result=await v8Api.evaluateOnCallFrame(callFrameId,watch.expression);if(result.exceptionDetails)results[watch.expression]=`[Error: ${result.exceptionDetails.text||"Evaluation failed"}]`;else{let value=await v8Api.extractValueDeep(result.result,2);results[watch.expression]=value}}catch(e){results[watch.expression]=`[Error: ${e.message||"Unknown error"}]`}return results}function _ensureStore(ctx,page,v8Options,config){let existing=STORE_BY_CONTEXT.get(ctx);if(existing)return existing;let v8Api=new V8Api(page,v8Options),sourceMapResolver=new SourceMapResolver(page),mergedConfig={...DEFAULT_DEBUG_CONFIG,...config},store={v8Api,sourceMapResolver,probes:new Map,locationIndex:new Map,watchExpressions:new Map,domBreakpoints:new Map,networkBreakpoints:new Map,snapshots:[],snapshotSequence:0,config:mergedConfig,enabled:!1,sourceMapsLoaded:!1,exceptionBreakpoint:"none",networkInterceptionEnabled:!1,recentDOMMutations:[]};return STORE_BY_CONTEXT.set(ctx,store),store}function _getStore(ctx){return STORE_BY_CONTEXT.get(ctx)}async function _captureScopes(v8Api,callFrame,maxDepth=3){let scopeSnapshots=[];for(let scope of callFrame.scopeChain)if(!(scope.type==="global"||scope.type==="script"||scope.type==="with"||scope.type==="eval"||scope.type==="wasm-expression-stack")){if(scopeSnapshots.length>=maxDepth)break;try{let variables=await v8Api.getScopeVariables(scope),scopeVariables=[];for(let[name,value]of Object.entries(variables))scopeVariables.push({name,value,type:typeof value});scopeSnapshots.push({type:scope.type,name:scope.name,variables:scopeVariables})}catch{}}return scopeSnapshots}async function _callFrameToSnapshot(v8Api,frame,captureScopes,sourceMapResolver){let scopes=[];captureScopes&&(scopes=await _captureScopes(v8Api,frame));let originalLocation;if(sourceMapResolver){let resolved=sourceMapResolver.generatedToOriginal(frame.location.scriptId,frame.location.lineNumber,frame.location.columnNumber??0);resolved&&(originalLocation={source:resolved.source,line:resolved.line+1,column:resolved.column!==void 0?resolved.column+1:void 0,name:resolved.name})}return{functionName:frame.functionName||"(anonymous)",url:frame.url||"",lineNumber:frame.location.lineNumber+1,columnNumber:frame.location.columnNumber!==void 0?frame.location.columnNumber+1:void 0,scriptId:frame.location.scriptId,scopes,originalLocation}}function _convertAsyncStackTrace(asyncTrace,sourceMapResolver,maxSegments,maxFramesPerSegment){if(!asyncTrace)return;let maxSegs=maxSegments??DEFAULT_DEBUG_CONFIG.maxAsyncStackSegments,maxFrames=maxFramesPerSegment??DEFAULT_DEBUG_CONFIG.maxFramesPerAsyncSegment,segments=[],currentTrace=asyncTrace,segmentCount=0;for(;currentTrace&&segmentCount<maxSegs;){let asyncFrames=[];for(let frame of currentTrace.callFrames.slice(0,maxFrames)){let originalLocation;if(sourceMapResolver){let resolved=sourceMapResolver.generatedToOriginal(frame.location.scriptId,frame.location.lineNumber,frame.location.columnNumber??0);resolved&&(originalLocation={source:resolved.source,line:resolved.line+1,column:resolved.column!==void 0?resolved.column+1:void 0,name:resolved.name})}asyncFrames.push({functionName:frame.functionName||"(anonymous)",url:frame.url||"",lineNumber:frame.location.lineNumber+1,columnNumber:frame.location.columnNumber!==void 0?frame.location.columnNumber+1:void 0,originalLocation})}asyncFrames.length>0&&segments.push({description:currentTrace.description,callFrames:asyncFrames}),currentTrace=currentTrace.parent,segmentCount++}if(segments.length!==0)return{segments}}async function enableDebugging2(ctx,page,options){let store=_ensureStore(ctx,page,options?.v8Options,options?.config);if(!store.enabled){await store.v8Api.enable(),store.v8Api.on("scriptParsed",script=>{store.sourceMapResolver.registerScript(script)});for(let script of store.v8Api.getScripts())store.sourceMapResolver.registerScript(script);store.v8Api.on("paused",async event=>{let startTime=Date.now();try{let isException=event.reason==="exception"||event.reason==="promiseRejection",isDOMBreakpoint=event.reason==="DOM",hitBreakpointIds=event.hitBreakpoints||[],hitProbes=[],hitDOMBreakpoint,domChangeInfo;if(isDOMBreakpoint&&event.data){let domData=event.data;for(let domBp of store.domBreakpoints.values())if(domBp.enabled&&(domBp.nodeId===domData.nodeId||!domData.nodeId)){hitDOMBreakpoint=domBp,domChangeInfo={type:domBp.type,selector:domBp.selector,targetNode:domData.targetNode?`<${domData.targetNode.nodeName?.toLowerCase()||"unknown"}>`:void 0,attributeName:domData.attributeName||domBp.attributeName};break}}if(hitDOMBreakpoint&&domChangeInfo)try{let mutationData=await page.evaluate(breakpointId=>{let win=window;if(!win.__domBreakpointMutations)return null;let mutations=win.__domBreakpointMutations;for(let i=mutations.length-1;i>=0;i--)if(mutations[i].breakpointId===breakpointId)return mutations[i];return null},hitDOMBreakpoint.id);mutationData&&(domChangeInfo.oldValue=mutationData.oldValue,domChangeInfo.newValue=mutationData.newValue,domChangeInfo.targetNode=mutationData.targetOuterHTML,mutationData.attributeName&&(domChangeInfo.attributeName=mutationData.attributeName))}catch{}for(let probe of store.probes.values()){if(!probe.enabled)continue;if(probe.v8BreakpointIds.some(id=>hitBreakpointIds.includes(id))){let conditionMet=!0;probe.hitCondition&&(conditionMet=_evaluateHitCondition(probe.hitCondition,probe.hitCount+1)),hitProbes.push({probe,conditionMet})}}let shouldCaptureBreakpoint=hitProbes.some(p=>p.conditionMet),shouldCaptureException=isException&&store.exceptionBreakpoint!=="none",shouldCaptureDOMBreakpoint=hitDOMBreakpoint!==void 0;for(let{probe}of hitProbes)probe.hitCount++,probe.lastHitAt=Date.now();if(hitDOMBreakpoint&&(hitDOMBreakpoint.hitCount++,hitDOMBreakpoint.lastHitAt=Date.now()),(shouldCaptureBreakpoint||shouldCaptureException||shouldCaptureDOMBreakpoint)&&event.callFrames.length>0){let topFrame=event.callFrames[0],exceptionInfo;if(isException&&event.data){let excData=event.data;exceptionInfo={type:event.reason==="promiseRejection"?"promiseRejection":"exception",message:excData.description||excData.value||String(excData),name:excData.className,stack:excData.description}}let originalLocation,resolvedLoc=store.sourceMapResolver.generatedToOriginal(topFrame.location.scriptId,topFrame.location.lineNumber,topFrame.location.columnNumber??0);resolvedLoc&&(originalLocation={source:resolvedLoc.source,line:resolvedLoc.line+1,column:resolvedLoc.column!==void 0?resolvedLoc.column+1:void 0,name:resolvedLoc.name});let baseSnapshot={url:topFrame.url||"",lineNumber:topFrame.location.lineNumber+1,columnNumber:topFrame.location.columnNumber!==void 0?topFrame.location.columnNumber+1:void 0,originalLocation,exception:exceptionInfo,domChange:domChangeInfo,captureTimeMs:Date.now()-startTime},callStackFull=[],framesToProcess=event.callFrames.slice(0,store.config.maxCallStackDepth);for(let i=0;i<framesToProcess.length;i++){let frame=framesToProcess[i],captureScopes=i<store.config.maxFramesWithScopes;callStackFull.push(await _callFrameToSnapshot(store.v8Api,frame,captureScopes,store.sourceMapResolver))}let asyncStackTraceFull=_convertAsyncStackTrace(event.asyncStackTrace,store.sourceMapResolver,store.config.maxAsyncStackSegments,store.config.maxFramesPerAsyncSegment),probesToCapture=hitProbes.filter(p=>p.conditionMet),hasExceptionOrDOM=shouldCaptureException||shouldCaptureDOMBreakpoint,snapshotCount=probesToCapture.length+(hasExceptionOrDOM?1:0);for(let s=0;s<snapshotCount;s++){let probeId,isLogpoint,logResult,callStack,asyncStackTrace,watchResults;if(s<probesToCapture.length){let{probe}=probesToCapture[s];if(probeId=probe.id,isLogpoint=probe.kind==="logpoint",isLogpoint&&probe.logExpression)try{let evalResult=await store.v8Api.evaluateOnCallFrame(topFrame.callFrameId,probe.logExpression,{returnByValue:!0,generatePreview:!0});logResult=store.v8Api.extractValue(evalResult.result)}catch{logResult="[evaluation error]"}else logResult=void 0;isLogpoint?(callStack=[],asyncStackTrace=void 0,watchResults=void 0):(callStack=callStackFull,asyncStackTrace=asyncStackTraceFull,watchResults=store.watchExpressions.size>0?await _evaluateWatchExpressionsOnFrame(store.v8Api,topFrame.callFrameId,store.watchExpressions):void 0)}else probeId=hitDOMBreakpoint?.id??"__exception__",isLogpoint=!1,logResult=void 0,callStack=callStackFull,asyncStackTrace=asyncStackTraceFull,watchResults=store.watchExpressions.size>0?await _evaluateWatchExpressionsOnFrame(store.v8Api,topFrame.callFrameId,store.watchExpressions):void 0;let snapshot={id:_generateId(),probeId,timestamp:Date.now(),sequenceNumber:++store.snapshotSequence,...baseSnapshot,callStack,asyncStackTrace,logResult,watchResults};store.snapshots.push(snapshot)}store.snapshots.length>store.config.maxSnapshots&&store.snapshots.splice(0,store.snapshots.length-store.config.maxSnapshots)}}finally{await store.v8Api.resume()}}),store.enabled=!0,store.sourceMapResolver.loadAllSourceMaps().then(()=>{store.sourceMapsLoaded=!0}).catch(()=>{})}}function isDebuggingEnabled2(ctx){return _getStore(ctx)?.enabled??!1}async function resolveSourceLocation2(ctx,page,url,line,column=1){let store=_ensureStore(ctx,page);store.enabled||await enableDebugging2(ctx,page);let resolved=await store.sourceMapResolver.resolveLocationByUrl(url,line,column);return resolved?{source:resolved.source,line:resolved.line+1,column:resolved.column+1,name:resolved.name}:null}async function setExceptionBreakpoint2(ctx,state){let store=_getStore(ctx);if(!store||!store.enabled)throw new Error("Debugging is not enabled");await store.v8Api.setPauseOnExceptions(state),store.exceptionBreakpoint=state}function getExceptionBreakpoint2(ctx){return _getStore(ctx)?.exceptionBreakpoint??"none"}function hasSourceMaps2(ctx){return _getStore(ctx)?.sourceMapResolver.hasSourceMaps()??!1}async function createProbe2(ctx,options){let store=_getStore(ctx);if(!store||!store.enabled)throw new Error("Debugging is not enabled");let probeId=_generateId(),columnNormalized=options.columnNumber??1,locationKey=_locationKey(options.urlPattern,options.lineNumber,columnNormalized),existingEntry=store.locationIndex.get(locationKey);if(existingEntry){existingEntry.refCount++;let probe2={id:probeId,kind:options.kind,enabled:!0,urlPattern:options.urlPattern,lineNumber:options.lineNumber,columnNumber:options.columnNumber,condition:options.condition,logExpression:options.logExpression,hitCondition:options.hitCondition,v8BreakpointIds:[existingEntry.breakpointId],resolvedLocations:existingEntry.resolvedLocations,hitCount:0,createdAt:Date.now()};return store.probes.set(probeId,probe2),probe2}let fullCondition;options.condition?fullCondition=`(${options.condition})`:fullCondition="true";let line0based=options.lineNumber-1,column0based=columnNormalized-1,resolved=store.sourceMapResolver.originalToGenerated(options.urlPattern,line0based,column0based),breakpointId,resolvedLocationsCount=0;if(resolved)try{breakpointId=(await store.v8Api.setBreakpoint({scriptId:resolved.scriptId,lineNumber:resolved.location.line,columnNumber:resolved.location.column},fullCondition)).breakpointId,resolvedLocationsCount=1}catch{let scriptUrl=store.sourceMapResolver.getScriptUrl(resolved.scriptId);if(scriptUrl){let result=await store.v8Api.setBreakpointByUrl({url:scriptUrl,lineNumber:resolved.location.line,columnNumber:resolved.location.column,condition:fullCondition});breakpointId=result.breakpointId,resolvedLocationsCount=result.locations.length}else throw new Error("Failed to set breakpoint at resolved location and could not fall back (script URL unknown). A probe may already exist at this line; remove it first or use a different line.")}else{let urlRegex=options.urlPattern.replace(/\\([.*+?^${}()|[\]\\/-])/g,"$1").replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,".*").replace(/\\\?/g,"."),result=await store.v8Api.setBreakpointByUrl({urlRegex,lineNumber:options.lineNumber-1,columnNumber:options.columnNumber?options.columnNumber-1:void 0,condition:fullCondition});breakpointId=result.breakpointId,resolvedLocationsCount=result.locations.length}store.locationIndex.set(locationKey,{breakpointId,resolvedLocations:resolvedLocationsCount,refCount:1});let probe={id:probeId,kind:options.kind,enabled:!0,urlPattern:options.urlPattern,lineNumber:options.lineNumber,columnNumber:options.columnNumber,condition:options.condition,logExpression:options.logExpression,hitCondition:options.hitCondition,v8BreakpointIds:[breakpointId],resolvedLocations:resolvedLocationsCount,hitCount:0,createdAt:Date.now()};return store.probes.set(probeId,probe),probe}async function removeProbe2(ctx,probeId){let store=_getStore(ctx);if(!store)return!1;let probe=store.probes.get(probeId);if(!probe)return!1;let locationKey=_locationKey(probe.urlPattern,probe.lineNumber,probe.columnNumber??1),entry=store.locationIndex.get(locationKey);if(entry&&(entry.refCount--,entry.refCount===0)){try{await store.v8Api.removeBreakpoint(entry.breakpointId)}catch{}store.locationIndex.delete(locationKey)}return store.probes.delete(probeId),!0}function listProbes2(ctx){let store=_getStore(ctx);return store?Array.from(store.probes.values()):[]}function getProbe(ctx,probeId){let store=_getStore(ctx);if(store)return store.probes.get(probeId)}function getSnapshots2(ctx){let store=_getStore(ctx);return store?[...store.snapshots]:[]}function getSnapshotsByProbe2(ctx,probeId){let store=_getStore(ctx);return store?store.snapshots.filter(s=>s.probeId===probeId):[]}function clearSnapshotsByProbe(ctx,probeId){let store=_getStore(ctx);if(!store)return 0;let before=store.snapshots.length;return store.snapshots=store.snapshots.filter(s=>s.probeId!==probeId),before-store.snapshots.length}function getSnapshotStats2(ctx){let store=_getStore(ctx);if(!store||store.snapshots.length===0)return{totalSnapshots:0,snapshotsByProbe:{},averageCaptureTimeMs:0};let snapshotsByProbe={},totalCaptureTime=0;for(let snapshot of store.snapshots)snapshotsByProbe[snapshot.probeId]=(snapshotsByProbe[snapshot.probeId]||0)+1,totalCaptureTime+=snapshot.captureTimeMs;return{totalSnapshots:store.snapshots.length,snapshotsByProbe,oldestTimestamp:store.snapshots[0].timestamp,newestTimestamp:store.snapshots[store.snapshots.length-1].timestamp,averageCaptureTimeMs:totalCaptureTime/store.snapshots.length}}function addWatchExpression2(ctx,expression){let store=_getStore(ctx);if(!store)throw new Error("Debug store not initialized");let id=_generateId(),watchExpr={id,expression,createdAt:Date.now()};return store.watchExpressions.set(id,watchExpr),watchExpr}function removeWatchExpression2(ctx,watchExpressionId){let store=_getStore(ctx);return store?store.watchExpressions.delete(watchExpressionId):!1}function listWatchExpressions2(ctx){let store=_getStore(ctx);return store?Array.from(store.watchExpressions.values()):[]}function clearWatchExpressions2(ctx){let store=_getStore(ctx);if(!store)return 0;let count=store.watchExpressions.size;return store.watchExpressions.clear(),count}async function setDOMBreakpoint(ctx,page,options){let store=_getStore(ctx);if(!store||!store.enabled)throw new Error("Debugging is not enabled");let cdp=await store.v8Api.getCdp();await cdp.send("DOM.enable");let{root}=await cdp.send("DOM.getDocument",{depth:0}),{nodeId}=await cdp.send("DOM.querySelector",{nodeId:root.nodeId,selector:options.selector});if(!nodeId||nodeId===0)throw new Error(`Element not found: ${options.selector}`);let cdpType=options.type==="subtree-modified"?"subtree-modified":options.type==="attribute-modified"?"attribute-modified":"node-removed";await cdp.send("DOMDebugger.setDOMBreakpoint",{nodeId,type:cdpType});let id=_generateId(),domBreakpoint={id,selector:options.selector,type:options.type,attributeName:options.attributeName,enabled:!0,nodeId,hitCount:0,createdAt:Date.now()};return store.domBreakpoints.set(id,domBreakpoint),await page.evaluate(params=>{let selector=params.selector,breakpointId=params.breakpointId,type=params.type,attrName=params.attrName,maxMutations=params.maxMutations,maxHtmlSnippetLength=params.maxHtmlSnippetLength,element=document.querySelector(selector);if(!element)return;let win=window;win.__domBreakpointData=win.__domBreakpointData||{},win.__domBreakpointMutations=win.__domBreakpointMutations||[],win.__domBreakpointData[breakpointId]={selector,type,attrName,currentAttrs:{}};for(let attr of element.attributes)win.__domBreakpointData[breakpointId].currentAttrs[attr.name]=attr.value;let observer=new MutationObserver(mutations=>{for(let mutation of mutations){let target=mutation.target;if(mutation.type==="attributes"){let attrNameChanged=mutation.attributeName||"";if(attrName&&attrName!==attrNameChanged)continue;let mutationRecord={breakpointId,selector,type:"attribute-modified",attributeName:attrNameChanged,oldValue:mutation.oldValue,newValue:target.getAttribute(attrNameChanged),targetOuterHTML:target.outerHTML.substring(0,maxHtmlSnippetLength),timestamp:Date.now()};win.__domBreakpointMutations.push(mutationRecord),win.__domBreakpointMutations.length>maxMutations&&win.__domBreakpointMutations.shift(),win.__domBreakpointData[breakpointId].currentAttrs[attrNameChanged]=target.getAttribute(attrNameChanged)}else if(mutation.type==="childList"){let mutationRecord={breakpointId,selector,type:"subtree-modified",addedNodes:mutation.addedNodes.length,removedNodes:mutation.removedNodes.length,targetOuterHTML:target.outerHTML.substring(0,maxHtmlSnippetLength),timestamp:Date.now()};win.__domBreakpointMutations.push(mutationRecord),win.__domBreakpointMutations.length>maxMutations&&win.__domBreakpointMutations.shift()}}}),config={attributes:type==="attribute-modified",attributeOldValue:type==="attribute-modified",childList:type==="subtree-modified"||type==="node-removed",subtree:type==="subtree-modified"};attrName&&(config.attributeFilter=[attrName]),observer.observe(element,config),win.__domBreakpointObservers=win.__domBreakpointObservers||{},win.__domBreakpointObservers[breakpointId]=observer},{selector:options.selector,breakpointId:id,type:options.type,attrName:options.attributeName,maxMutations:store.config.maxDOMMutations,maxHtmlSnippetLength:store.config.maxDOMHtmlSnippetLength}),domBreakpoint}async function removeDOMBreakpoint(ctx,domBreakpointId,page){let store=_getStore(ctx);if(!store)return!1;let domBreakpoint=store.domBreakpoints.get(domBreakpointId);if(!domBreakpoint||!domBreakpoint.nodeId)return!1;try{let cdp=await store.v8Api.getCdp(),cdpType=domBreakpoint.type==="subtree-modified"?"subtree-modified":domBreakpoint.type==="attribute-modified"?"attribute-modified":"node-removed";await cdp.send("DOMDebugger.removeDOMBreakpoint",{nodeId:domBreakpoint.nodeId,type:cdpType})}catch{}if(page)try{await page.evaluate(breakpointId=>{let win=window;win.__domBreakpointObservers&&win.__domBreakpointObservers[breakpointId]&&(win.__domBreakpointObservers[breakpointId].disconnect(),delete win.__domBreakpointObservers[breakpointId]),win.__domBreakpointData&&delete win.__domBreakpointData[breakpointId],win.__domBreakpointMutations&&(win.__domBreakpointMutations=win.__domBreakpointMutations.filter(m=>m.breakpointId!==breakpointId))},domBreakpointId)}catch{}return store.domBreakpoints.delete(domBreakpointId)}function listDOMBreakpoints(ctx){let store=_getStore(ctx);return store?Array.from(store.domBreakpoints.values()):[]}async function clearDOMBreakpoints(ctx,page){let store=_getStore(ctx);if(!store)return 0;let ids=Array.from(store.domBreakpoints.keys());for(let id of ids)await removeDOMBreakpoint(ctx,id,page);return ids.length}async function _enableNetworkInterception(store,page){if(store.networkInterceptionEnabled)return;let cdp=await store.v8Api.getCdp();await cdp.send("Fetch.enable",{patterns:[{urlPattern:"*",requestStage:"Request"}]}),cdp.on("Fetch.requestPaused",async event=>{let requestId=event.requestId,requestUrl=event.request.url,method=event.request.method;try{let matchedBreakpoint;for(let bp of store.networkBreakpoints.values()){if(!bp.enabled)continue;let unescapedPattern=bp.urlPattern.replace(/\\([.*+?^${}()|[\]\\/-])/g,"$1");if(new RegExp(unescapedPattern.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,".*")).test(requestUrl)&&!(bp.method&&bp.method.toUpperCase()!==method.toUpperCase())&&bp.timing==="request"){matchedBreakpoint=bp;break}}if(matchedBreakpoint&&matchedBreakpoint.timing==="request"){let requestInfo={url:requestUrl,method,requestHeaders:event.request.headers,requestBody:event.request.postData,resourceType:event.resourceType,timing:"request"},snapshot={id:_generateId(),probeId:matchedBreakpoint.id,timestamp:Date.now(),sequenceNumber:++store.snapshotSequence,url:requestUrl,lineNumber:0,networkRequest:requestInfo,callStack:[],captureTimeMs:0};store.watchExpressions.size>0&&(snapshot.watchResults=await _evaluateWatchExpressions(store,page)),store.snapshots.push(snapshot),store.snapshots.length>store.config.maxSnapshots&&store.snapshots.splice(0,store.snapshots.length-store.config.maxSnapshots),matchedBreakpoint.hitCount++,matchedBreakpoint.lastHitAt=Date.now()}await cdp.send("Fetch.continueRequest",{requestId})}catch{try{await cdp.send("Fetch.continueRequest",{requestId})}catch{}}}),await cdp.send("Network.enable");let pendingRequests=new Map;cdp.on("Network.requestWillBeSent",event=>{if(pendingRequests.set(event.requestId,{method:event.request.method,postData:event.request.postData}),pendingRequests.size>store.config.maxPendingRequests){let firstKey=pendingRequests.keys().next().value;firstKey&&pendingRequests.delete(firstKey)}}),cdp.on("Network.responseReceived",async event=>{let requestId=event.requestId,requestUrl=event.response.url,requestInfo=pendingRequests.get(requestId),method=requestInfo?.method||event.type||"GET",status=event.response.status;for(let bp of store.networkBreakpoints.values()){if(!bp.enabled||bp.timing!=="response")continue;let unescapedPattern=bp.urlPattern.replace(/\\([.*+?^${}()|[\]\\/-])/g,"$1");if(!new RegExp(unescapedPattern.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,".*")).test(requestUrl)||bp.method&&bp.method.toUpperCase()!==method.toUpperCase()||bp.onError&&status<400)continue;let responseBody;try{let bodyResult=await cdp.send("Network.getResponseBody",{requestId});bodyResult.base64Encoded?responseBody=Buffer.from(bodyResult.body,"base64").toString("utf-8"):responseBody=bodyResult.body,responseBody&&responseBody.length>store.config.maxResponseBodyLength&&(responseBody=responseBody.substring(0,store.config.maxResponseBodyLength)+"... [truncated]")}catch{}let networkRequestInfo={url:requestUrl,method,requestBody:requestInfo?.postData,status,statusText:event.response.statusText,responseHeaders:event.response.headers,responseBody,resourceType:event.type,timing:"response"},snapshot={id:_generateId(),probeId:bp.id,timestamp:Date.now(),sequenceNumber:++store.snapshotSequence,url:requestUrl,lineNumber:0,networkRequest:networkRequestInfo,callStack:[],captureTimeMs:0};store.watchExpressions.size>0&&(snapshot.watchResults=await _evaluateWatchExpressions(store,page)),store.snapshots.push(snapshot),store.snapshots.length>store.config.maxSnapshots&&store.snapshots.splice(0,store.snapshots.length-store.config.maxSnapshots),bp.hitCount++,bp.lastHitAt=Date.now(),pendingRequests.delete(requestId);break}}),cdp.on("Network.loadingFinished",event=>{setTimeout(()=>{pendingRequests.delete(event.requestId)},store.config.networkCleanupTimeoutMs)}),store.networkInterceptionEnabled=!0}async function _evaluateWatchExpressions(store,page){let results={};for(let watch of store.watchExpressions.values())try{let value=await page.evaluate(expr=>{try{return(0,eval)(expr)}catch(e){return`[Error: ${e.message}]`}},watch.expression);results[watch.expression]=value}catch(e){results[watch.expression]=`[Error: ${e.message}]`}return results}async function setNetworkBreakpoint(ctx,page,options){let store=_getStore(ctx);if(!store||!store.enabled)throw new Error("Debugging is not enabled");await _enableNetworkInterception(store,page);let id=_generateId(),networkBreakpoint={id,urlPattern:options.urlPattern,method:options.method,timing:options.timing||"request",onError:options.onError,enabled:!0,hitCount:0,createdAt:Date.now()};return store.networkBreakpoints.set(id,networkBreakpoint),networkBreakpoint}function removeNetworkBreakpoint(ctx,networkBreakpointId){let store=_getStore(ctx);return store?store.networkBreakpoints.delete(networkBreakpointId):!1}function listNetworkBreakpoints(ctx){let store=_getStore(ctx);return store?Array.from(store.networkBreakpoints.values()):[]}function clearNetworkBreakpoints(ctx){let store=_getStore(ctx);if(!store)return 0;let count=store.networkBreakpoints.size;return store.networkBreakpoints.clear(),count}var Status=class{name(){return"debug_status"}description(){return`
|
|
284
|
+
The screenshot is always saved to disk; the file path is returned. Do NOT set includeBase64 to true unless the assistant cannot read the file from the returned path (e.g. remote server, container).`}inputSchema(){return{outputPath:z6.string().describe("Directory path where screenshot will be saved. By default OS tmp directory is used.").optional().default(os2.tmpdir()),name:z6.string().describe(`Name of the screenshot. Default value is "${DEFAULT_SCREENSHOT_NAME}". Note that final saved/exported file name is in the "{name}-{time}.{type}" format in which "{time}" is in the "YYYYMMDD-HHmmss" format.`).optional().default(DEFAULT_SCREENSHOT_NAME),selector:z6.string().describe("Selector for element: ref (e1, @e1), getByRole/getByLabel/getByText/etc., or CSS selector.").optional(),fullPage:z6.boolean().describe('Whether to take a screenshot of the full scrollable page, instead of the currently visible viewport (default: "false").').optional().default(!1),type:z6.enum(getEnumKeyTuples(ScreenshotType)).transform(createEnumTransformer(ScreenshotType)).describe(`Page format. Valid values are: ${getEnumKeyTuples(ScreenshotType)}`).optional().default(DEFAULT_SCREENSHOT_TYPE),quality:z6.number().int().min(0).max(DEFAULT_SCREENSHOT_QUALITY).describe("The quality of the image, between 0-100. Not applicable to png images.").optional(),includeBase64:z6.boolean().describe("If true, includes base64 image data in the response (increases payload size). Default is false. The screenshot is always saved to disk; use the returned file path to read it. Set to true ONLY when the assistant cannot access the MCP server file system (e.g. remote/container). Avoid setting to true otherwise.").optional().default(!1),annotate:z6.boolean().optional().default(!1).describe("When true, overlay numbered labels on interactive elements (from last a11y_take-aria-snapshot refs). Labels [1],[2],... map to refs e1,e2,... When selector is also set, only elements overlapping the scoped element are annotated and returned; annotation box coordinates are relative to that element."),annotateContent:z6.boolean().optional().default(!1).describe("When true with annotate, also include content elements (headings, list items, etc.) in the overlay. Uses interactiveOnly: false when building refs for this screenshot."),annotateCursorInteractive:z6.boolean().optional().default(!1).describe("When true with annotate, also include cursor-interactive elements (clickable/focusable by CSS but no ARIA role) in the overlay. Takes a fresh ARIA snapshot with cursorInteractive for this screenshot.")}}outputSchema(){return{filePath:z6.string().describe("Full path of the saved screenshot file."),image:z6.object({data:z6.any().describe("Base64-encoded image data."),mimeType:z6.string().describe("MIME type of the image.")}).optional().describe('Image data included only when "includeBase64" input parameter is set to true.'),annotations:z6.array(z6.object({ref:z6.string(),number:z6.number(),role:z6.string(),name:z6.string().optional(),box:z6.object({x:z6.number(),y:z6.number(),width:z6.number(),height:z6.number()})})).optional().describe("When annotate is true, list of refs and bounding boxes. When selector is set: only annotations overlapping the element, box relative to that element. When fullPage is true: box is document-relative (matches the full-page image). Otherwise: viewport-relative.")}}_scaleImageToSize(image,size){let{data:src,width:w1,height:h1}=image,w2=Math.max(1,Math.floor(size.width)),h2=Math.max(1,Math.floor(size.height));if(w1===w2&&h1===h2)return image;if(w1<=0||h1<=0)throw new Error("Invalid input image");if(size.width<=0||size.height<=0||!isFinite(size.width)||!isFinite(size.height))throw new Error("Invalid output dimensions");let clamp=(v,lo,hi)=>v<lo?lo:v>hi?hi:v,weights=(t,o)=>{let t2=t*t,t3=t2*t;o[0]=-.5*t+1*t2-.5*t3,o[1]=1-2.5*t2+1.5*t3,o[2]=.5*t+2*t2-1.5*t3,o[3]=-.5*t2+.5*t3},srcRowStride=w1*4,dstRowStride=w2*4,xOff=new Int32Array(w2*4),xW=new Float32Array(w2*4),wx=new Float32Array(4),xScale=w1/w2;for(let x=0;x<w2;x++){let sx=(x+.5)*xScale-.5,sxi=Math.floor(sx),t=sx-sxi;weights(t,wx);let b=x*4,i0=clamp(sxi-1,0,w1-1),i1=clamp(sxi+0,0,w1-1),i2=clamp(sxi+1,0,w1-1),i3=clamp(sxi+2,0,w1-1);xOff[b+0]=i0<<2,xOff[b+1]=i1<<2,xOff[b+2]=i2<<2,xOff[b+3]=i3<<2,xW[b+0]=wx[0],xW[b+1]=wx[1],xW[b+2]=wx[2],xW[b+3]=wx[3]}let yRow=new Int32Array(h2*4),yW=new Float32Array(h2*4),wy=new Float32Array(4),yScale=h1/h2;for(let y=0;y<h2;y++){let sy=(y+.5)*yScale-.5,syi=Math.floor(sy),t=sy-syi;weights(t,wy);let b=y*4,j0=clamp(syi-1,0,h1-1),j1=clamp(syi+0,0,h1-1),j2=clamp(syi+1,0,h1-1),j3=clamp(syi+2,0,h1-1);yRow[b+0]=j0*srcRowStride,yRow[b+1]=j1*srcRowStride,yRow[b+2]=j2*srcRowStride,yRow[b+3]=j3*srcRowStride,yW[b+0]=wy[0],yW[b+1]=wy[1],yW[b+2]=wy[2],yW[b+3]=wy[3]}let dst=new Uint8Array(w2*h2*4);for(let y=0;y<h2;y++){let yb=y*4,rb0=yRow[yb+0],rb1=yRow[yb+1],rb2=yRow[yb+2],rb3=yRow[yb+3],wy0=yW[yb+0],wy1=yW[yb+1],wy2=yW[yb+2],wy3=yW[yb+3],dstBase=y*dstRowStride;for(let x=0;x<w2;x++){let xb=x*4,xo0=xOff[xb+0],xo1=xOff[xb+1],xo2=xOff[xb+2],xo3=xOff[xb+3],wx0=xW[xb+0],wx1=xW[xb+1],wx2=xW[xb+2],wx3=xW[xb+3],di=dstBase+(x<<2);for(let c=0;c<4;c++){let r0=src[rb0+xo0+c]*wx0+src[rb0+xo1+c]*wx1+src[rb0+xo2+c]*wx2+src[rb0+xo3+c]*wx3,r1=src[rb1+xo0+c]*wx0+src[rb1+xo1+c]*wx1+src[rb1+xo2+c]*wx2+src[rb1+xo3+c]*wx3,r2=src[rb2+xo0+c]*wx0+src[rb2+xo1+c]*wx1+src[rb2+xo2+c]*wx2+src[rb2+xo3+c]*wx3,r3=src[rb3+xo0+c]*wx0+src[rb3+xo1+c]*wx1+src[rb3+xo2+c]*wx2+src[rb3+xo3+c]*wx3,v=r0*wy0+r1*wy1+r2*wy2+r3*wy3;dst[di+c]=v<0?0:v>255?255:v|0}}}return{data:Buffer.from(dst.buffer),width:w2,height:h2}}_scaleImageToFitMessage(buffer,screenshotType){let MAX_PIXELS=12058624e-1,MAX_LINEAR_SIZE=1568,image=screenshotType==="png"?PNG.sync.read(buffer):jpegjs.decode(buffer,{maxMemoryUsageInMB:512}),pixels=image.width*image.height,shrink=Math.min(MAX_LINEAR_SIZE/image.width,MAX_LINEAR_SIZE/image.height,Math.sqrt(MAX_PIXELS/pixels));shrink>1&&(shrink=1);let width=image.width*shrink|0,height=image.height*shrink|0,scaledImage=this._scaleImageToSize(image,{width,height}),result,currentType=screenshotType,quality=screenshotType==="png"?75:70;screenshotType==="png"?(result=jpegjs.encode(scaledImage,quality).data,currentType="jpeg"):result=jpegjs.encode(scaledImage,quality).data;let iterations=0,MAX_ITERATIONS=5;for(;result.length>819200&&iterations<MAX_ITERATIONS;)quality=Math.max(50,quality-10),quality<=50&&result.length>819200&&(shrink*=.85,width=Math.max(200,image.width*shrink|0),height=Math.max(200,image.height*shrink|0),scaledImage=this._scaleImageToSize(image,{width,height})),result=jpegjs.encode(scaledImage,quality).data,iterations++;return result}async handle(context,args){let screenshotType=args.type||DEFAULT_SCREENSHOT_TYPE,filename=`${args.name||DEFAULT_SCREENSHOT_NAME}-${formattedTimeForFilename()}.${screenshotType}`,filePath=path2.resolve(args.outputPath,filename),quality=screenshotType==="png"?void 0:args.quality??DEFAULT_SCREENSHOT_QUALITY,overlayInjected=!1,annotations,scopedElement=null;if(args.selector&&(scopedElement=await resolveSelectorOrRef(context,args.selector).elementHandle({timeout:1e4}),!scopedElement))throw new Error(`Element not found: ${args.selector}`);if(args.annotate){let refMap=context.getRefMap(),wantContent=args.annotateContent===!0,wantCursorInteractive=args.annotateCursorInteractive===!0;if(Object.keys(refMap).length===0||wantCursorInteractive||wantContent){let raw=await context.page.locator("body").ariaSnapshot(),{refs}=processAriaTreeWithRefs(raw,{interactiveOnly:!wantContent}),mergedRefs={...refs};if(wantCursorInteractive){let cursorEntries=await findCursorInteractiveElements(context.page,null);if(cursorEntries.length>0){let maxNum=Object.keys(mergedRefs).reduce((m,k)=>{let n=parseInt(k.replace(/^e/,""),10)||0;return n>m?n:m},0);cursorEntries.forEach((entry,i)=>{let ref=`e${maxNum+1+i}`;mergedRefs[ref]={role:entry.role,name:entry.name,selector:entry.selector,nth:entry.nth}})}}context.setRefMap(mergedRefs),refMap=mergedRefs}let entries=Object.entries(refMap),allBoxes=[];for(let[ref,data]of entries){let locator=getLocatorFromRef(context.page,refMap,ref);if(!locator)continue;let box=await locator.boundingBox({timeout:ANNOTATE_BOX_TIMEOUT_MS}).catch(()=>null);if(!box||box.width===0||box.height===0)continue;let num=parseInt(ref.replace(/^e/,""),10)||0;allBoxes.push({ref,number:num,role:data.role,name:data.name,box:{x:Math.round(box.x),y:Math.round(box.y),width:Math.round(box.width),height:Math.round(box.height)}})}allBoxes.sort((a,b)=>a.number-b.number);let boxes=allBoxes,overlayBoxesViewport=allBoxes;if(scopedElement){let elementBox=await scopedElement.boundingBox();if(elementBox&&elementBox.width>0&&elementBox.height>0){let overlapping=allBoxes.filter(a=>{let b=a.box;return b.x<elementBox.x+elementBox.width&&b.x+b.width>elementBox.x&&b.y<elementBox.y+elementBox.height&&b.y+b.height>elementBox.y});overlayBoxesViewport=overlapping,boxes=overlapping.map(a=>{let b=a.box,relX=Math.max(0,b.x-elementBox.x),relY=Math.max(0,b.y-elementBox.y),relRight=Math.min(b.x+b.width-elementBox.x,elementBox.width),relBottom=Math.min(b.y+b.height-elementBox.y,elementBox.height);return{...a,box:{x:Math.round(relX),y:Math.round(relY),width:Math.round(Math.max(0,relRight-relX)),height:Math.round(Math.max(0,relBottom-relY))}}})}}if(boxes.length>0){let overlayPayload={data:overlayBoxesViewport.map(a=>({number:a.number,x:a.box.x,y:a.box.y,width:a.box.width,height:a.box.height})),id:ANNOTATION_OVERLAY_ID};if(await context.page.evaluate(({data,id})=>{let sx=window.scrollX||0,sy=window.scrollY||0,c=document.createElement("div");c.id=id,c.style.cssText="position:absolute;top:0;left:0;width:0;height:0;pointer-events:none;z-index:2147483647;";for(let it of data){let dx=it.x+sx,dy=it.y+sy,b=document.createElement("div");b.style.cssText=`position:absolute;left:${dx}px;top:${dy}px;width:${it.width}px;height:${it.height}px;border:2px solid rgba(255,0,0,0.8);box-sizing:border-box;pointer-events:none;`;let l=document.createElement("div");l.textContent=String(it.number);let labelTop=dy<14?"2px":"-14px";l.style.cssText=`position:absolute;top:${labelTop};left:-2px;background:rgba(255,0,0,0.9);color:#fff;font:bold 11px/14px monospace;padding:0 4px;border-radius:2px;white-space:nowrap;`,b.appendChild(l),c.appendChild(b)}document.documentElement.appendChild(c)},overlayPayload),overlayInjected=!0,args.fullPage&&!scopedElement&&boxes.length>0){let scroll=await context.page.evaluate(()=>({x:window.scrollX||0,y:window.scrollY||0}));annotations=boxes.map(a=>({...a,box:{x:a.box.x+scroll.x,y:a.box.y+scroll.y,width:a.box.width,height:a.box.height}}))}else annotations=boxes}}let options={path:filePath,type:screenshotType,fullPage:!!args.fullPage,quality};scopedElement&&(options.element=scopedElement);try{let screenshot=await context.page.screenshot(options),result={filePath,...annotations&&annotations.length>0?{annotations}:{}};return args.includeBase64&&(result.image={data:this._scaleImageToFitMessage(screenshot,screenshotType),mimeType:`image/${screenshotType}`}),result}finally{overlayInjected&&await context.page.evaluate(id=>{let el=document.getElementById(id);el&&el.remove()},ANNOTATION_OVERLAY_ID).catch(()=>{})}}};var tools2=[new GetAsHtml,new GetAsText,new SaveAsPdf,new TakeScreenshot];import{z as z7}from"zod";var DEFAULT_DEBUG_CONFIG={maxSnapshots:1e3,maxCallStackDepth:20,maxFramesWithScopes:5,maxAsyncStackSegments:10,maxFramesPerAsyncSegment:10,maxDOMMutations:100,maxDOMHtmlSnippetLength:200,maxPendingRequests:1e3,maxResponseBodyLength:1e4,networkCleanupTimeoutMs:5e3},STORE_BY_CONTEXT=new WeakMap;function _generateId(){let t=Date.now(),r=Math.floor(Math.random()*1e6);return`${t.toString(36)}-${r.toString(36)}`}function _locationKey(urlPattern,lineNumber,columnNumber){return`${urlPattern}:${lineNumber}:${columnNumber}`}function _evaluateHitCondition(hitCondition,hitCount){try{let condition=hitCondition.trim();return/^[=<>!%]/.test(condition)&&(condition=`hitCount ${condition}`),!!new Function("hitCount",`return (${condition});`)(hitCount)}catch{return!1}}async function _evaluateWatchExpressionsOnFrame(v8Api,callFrameId,watchExpressions){let results={};for(let watch of watchExpressions.values())try{let result=await v8Api.evaluateOnCallFrame(callFrameId,watch.expression);if(result.exceptionDetails)results[watch.expression]=`[Error: ${result.exceptionDetails.text||"Evaluation failed"}]`;else{let value=await v8Api.extractValueDeep(result.result,2);results[watch.expression]=value}}catch(e){results[watch.expression]=`[Error: ${e.message||"Unknown error"}]`}return results}function _ensureStore(ctx,page,v8Options,config){let existing=STORE_BY_CONTEXT.get(ctx);if(existing)return existing;let v8Api=new V8Api(page,v8Options),sourceMapResolver=new SourceMapResolver(page),mergedConfig={...DEFAULT_DEBUG_CONFIG,...config},store={v8Api,sourceMapResolver,probes:new Map,locationIndex:new Map,watchExpressions:new Map,domBreakpoints:new Map,networkBreakpoints:new Map,snapshots:[],snapshotSequence:0,config:mergedConfig,enabled:!1,sourceMapsLoaded:!1,exceptionBreakpoint:"none",networkInterceptionEnabled:!1,recentDOMMutations:[]};return STORE_BY_CONTEXT.set(ctx,store),store}function _getStore(ctx){return STORE_BY_CONTEXT.get(ctx)}async function _captureScopes(v8Api,callFrame,maxDepth=3){let scopeSnapshots=[];for(let scope of callFrame.scopeChain)if(!(scope.type==="global"||scope.type==="script"||scope.type==="with"||scope.type==="eval"||scope.type==="wasm-expression-stack")){if(scopeSnapshots.length>=maxDepth)break;try{let variables=await v8Api.getScopeVariables(scope),scopeVariables=[];for(let[name,value]of Object.entries(variables))scopeVariables.push({name,value,type:typeof value});scopeSnapshots.push({type:scope.type,name:scope.name,variables:scopeVariables})}catch{}}return scopeSnapshots}async function _callFrameToSnapshot(v8Api,frame,captureScopes,sourceMapResolver){let scopes=[];captureScopes&&(scopes=await _captureScopes(v8Api,frame));let originalLocation;if(sourceMapResolver){let resolved=sourceMapResolver.generatedToOriginal(frame.location.scriptId,frame.location.lineNumber,frame.location.columnNumber??0);resolved&&(originalLocation={source:resolved.source,line:resolved.line+1,column:resolved.column!==void 0?resolved.column+1:void 0,name:resolved.name})}return{functionName:frame.functionName||"(anonymous)",url:frame.url||"",lineNumber:frame.location.lineNumber+1,columnNumber:frame.location.columnNumber!==void 0?frame.location.columnNumber+1:void 0,scriptId:frame.location.scriptId,scopes,originalLocation}}function _convertAsyncStackTrace(asyncTrace,sourceMapResolver,maxSegments,maxFramesPerSegment){if(!asyncTrace)return;let maxSegs=maxSegments??DEFAULT_DEBUG_CONFIG.maxAsyncStackSegments,maxFrames=maxFramesPerSegment??DEFAULT_DEBUG_CONFIG.maxFramesPerAsyncSegment,segments=[],currentTrace=asyncTrace,segmentCount=0;for(;currentTrace&&segmentCount<maxSegs;){let asyncFrames=[];for(let frame of currentTrace.callFrames.slice(0,maxFrames)){let originalLocation;if(sourceMapResolver){let resolved=sourceMapResolver.generatedToOriginal(frame.location.scriptId,frame.location.lineNumber,frame.location.columnNumber??0);resolved&&(originalLocation={source:resolved.source,line:resolved.line+1,column:resolved.column!==void 0?resolved.column+1:void 0,name:resolved.name})}asyncFrames.push({functionName:frame.functionName||"(anonymous)",url:frame.url||"",lineNumber:frame.location.lineNumber+1,columnNumber:frame.location.columnNumber!==void 0?frame.location.columnNumber+1:void 0,originalLocation})}asyncFrames.length>0&&segments.push({description:currentTrace.description,callFrames:asyncFrames}),currentTrace=currentTrace.parent,segmentCount++}if(segments.length!==0)return{segments}}async function enableDebugging2(ctx,page,options){let store=_ensureStore(ctx,page,options?.v8Options,options?.config);if(!store.enabled){await store.v8Api.enable(),store.v8Api.on("scriptParsed",script=>{store.sourceMapResolver.registerScript(script)});for(let script of store.v8Api.getScripts())store.sourceMapResolver.registerScript(script);store.v8Api.on("paused",async event=>{let startTime=Date.now();try{let isException=event.reason==="exception"||event.reason==="promiseRejection",isDOMBreakpoint=event.reason==="DOM",hitBreakpointIds=event.hitBreakpoints||[],hitProbes=[],hitDOMBreakpoint,domChangeInfo;if(isDOMBreakpoint&&event.data){let domData=event.data;for(let domBp of store.domBreakpoints.values())if(domBp.enabled&&(domBp.nodeId===domData.nodeId||!domData.nodeId)){hitDOMBreakpoint=domBp,domChangeInfo={type:domBp.type,selector:domBp.selector,targetNode:domData.targetNode?`<${domData.targetNode.nodeName?.toLowerCase()||"unknown"}>`:void 0,attributeName:domData.attributeName||domBp.attributeName};break}}if(hitDOMBreakpoint&&domChangeInfo)try{let mutationData=await page.evaluate(breakpointId=>{let win=window;if(!win.__domBreakpointMutations)return null;let mutations=win.__domBreakpointMutations;for(let i=mutations.length-1;i>=0;i--)if(mutations[i].breakpointId===breakpointId)return mutations[i];return null},hitDOMBreakpoint.id);mutationData&&(domChangeInfo.oldValue=mutationData.oldValue,domChangeInfo.newValue=mutationData.newValue,domChangeInfo.targetNode=mutationData.targetOuterHTML,mutationData.attributeName&&(domChangeInfo.attributeName=mutationData.attributeName))}catch{}for(let probe of store.probes.values()){if(!probe.enabled)continue;if(probe.v8BreakpointIds.some(id=>hitBreakpointIds.includes(id))){let conditionMet=!0;probe.hitCondition&&(conditionMet=_evaluateHitCondition(probe.hitCondition,probe.hitCount+1)),hitProbes.push({probe,conditionMet})}}let shouldCaptureBreakpoint=hitProbes.some(p=>p.conditionMet),shouldCaptureException=isException&&store.exceptionBreakpoint!=="none",shouldCaptureDOMBreakpoint=hitDOMBreakpoint!==void 0;for(let{probe}of hitProbes)probe.hitCount++,probe.lastHitAt=Date.now();if(hitDOMBreakpoint&&(hitDOMBreakpoint.hitCount++,hitDOMBreakpoint.lastHitAt=Date.now()),(shouldCaptureBreakpoint||shouldCaptureException||shouldCaptureDOMBreakpoint)&&event.callFrames.length>0){let topFrame=event.callFrames[0],exceptionInfo;if(isException&&event.data){let excData=event.data;exceptionInfo={type:event.reason==="promiseRejection"?"promiseRejection":"exception",message:excData.description||excData.value||String(excData),name:excData.className,stack:excData.description}}let originalLocation,resolvedLoc=store.sourceMapResolver.generatedToOriginal(topFrame.location.scriptId,topFrame.location.lineNumber,topFrame.location.columnNumber??0);resolvedLoc&&(originalLocation={source:resolvedLoc.source,line:resolvedLoc.line+1,column:resolvedLoc.column!==void 0?resolvedLoc.column+1:void 0,name:resolvedLoc.name});let baseSnapshot={url:topFrame.url||"",lineNumber:topFrame.location.lineNumber+1,columnNumber:topFrame.location.columnNumber!==void 0?topFrame.location.columnNumber+1:void 0,originalLocation,exception:exceptionInfo,domChange:domChangeInfo,captureTimeMs:Date.now()-startTime},callStackFull=[],framesToProcess=event.callFrames.slice(0,store.config.maxCallStackDepth);for(let i=0;i<framesToProcess.length;i++){let frame=framesToProcess[i],captureScopes=i<store.config.maxFramesWithScopes;callStackFull.push(await _callFrameToSnapshot(store.v8Api,frame,captureScopes,store.sourceMapResolver))}let asyncStackTraceFull=_convertAsyncStackTrace(event.asyncStackTrace,store.sourceMapResolver,store.config.maxAsyncStackSegments,store.config.maxFramesPerAsyncSegment),probesToCapture=hitProbes.filter(p=>p.conditionMet),hasExceptionOrDOM=shouldCaptureException||shouldCaptureDOMBreakpoint,snapshotCount=probesToCapture.length+(hasExceptionOrDOM?1:0);for(let s=0;s<snapshotCount;s++){let probeId,isLogpoint,logResult,callStack,asyncStackTrace,watchResults;if(s<probesToCapture.length){let{probe}=probesToCapture[s];if(probeId=probe.id,isLogpoint=probe.kind==="logpoint",isLogpoint&&probe.logExpression)try{let evalResult=await store.v8Api.evaluateOnCallFrame(topFrame.callFrameId,probe.logExpression,{returnByValue:!0,generatePreview:!0});logResult=store.v8Api.extractValue(evalResult.result)}catch{logResult="[evaluation error]"}else logResult=void 0;isLogpoint?(callStack=[],asyncStackTrace=void 0,watchResults=void 0):(callStack=callStackFull,asyncStackTrace=asyncStackTraceFull,watchResults=store.watchExpressions.size>0?await _evaluateWatchExpressionsOnFrame(store.v8Api,topFrame.callFrameId,store.watchExpressions):void 0)}else probeId=hitDOMBreakpoint?.id??"__exception__",isLogpoint=!1,logResult=void 0,callStack=callStackFull,asyncStackTrace=asyncStackTraceFull,watchResults=store.watchExpressions.size>0?await _evaluateWatchExpressionsOnFrame(store.v8Api,topFrame.callFrameId,store.watchExpressions):void 0;let snapshot={id:_generateId(),probeId,timestamp:Date.now(),sequenceNumber:++store.snapshotSequence,...baseSnapshot,callStack,asyncStackTrace,logResult,watchResults};store.snapshots.push(snapshot)}store.snapshots.length>store.config.maxSnapshots&&store.snapshots.splice(0,store.snapshots.length-store.config.maxSnapshots)}}finally{await store.v8Api.resume()}}),store.enabled=!0,store.sourceMapResolver.loadAllSourceMaps().then(()=>{store.sourceMapsLoaded=!0}).catch(()=>{})}}function isDebuggingEnabled2(ctx){return _getStore(ctx)?.enabled??!1}async function resolveSourceLocation2(ctx,page,url,line,column=1){let store=_ensureStore(ctx,page);store.enabled||await enableDebugging2(ctx,page);let resolved=await store.sourceMapResolver.resolveLocationByUrl(url,line,column);return resolved?{source:resolved.source,line:resolved.line+1,column:resolved.column+1,name:resolved.name}:null}async function setExceptionBreakpoint2(ctx,state){let store=_getStore(ctx);if(!store||!store.enabled)throw new Error("Debugging is not enabled");await store.v8Api.setPauseOnExceptions(state),store.exceptionBreakpoint=state}function getExceptionBreakpoint2(ctx){return _getStore(ctx)?.exceptionBreakpoint??"none"}function hasSourceMaps2(ctx){return _getStore(ctx)?.sourceMapResolver.hasSourceMaps()??!1}async function createProbe2(ctx,options){let store=_getStore(ctx);if(!store||!store.enabled)throw new Error("Debugging is not enabled");let probeId=_generateId(),columnNormalized=options.columnNumber??1,locationKey=_locationKey(options.urlPattern,options.lineNumber,columnNormalized),existingEntry=store.locationIndex.get(locationKey);if(existingEntry){existingEntry.refCount++;let probe2={id:probeId,kind:options.kind,enabled:!0,urlPattern:options.urlPattern,lineNumber:options.lineNumber,columnNumber:options.columnNumber,condition:options.condition,logExpression:options.logExpression,hitCondition:options.hitCondition,v8BreakpointIds:[existingEntry.breakpointId],resolvedLocations:existingEntry.resolvedLocations,hitCount:0,createdAt:Date.now()};return store.probes.set(probeId,probe2),probe2}let fullCondition;options.condition?fullCondition=`(${options.condition})`:fullCondition="true";let line0based=options.lineNumber-1,column0based=columnNormalized-1,resolved=store.sourceMapResolver.originalToGenerated(options.urlPattern,line0based,column0based),breakpointId,resolvedLocationsCount=0;if(resolved)try{breakpointId=(await store.v8Api.setBreakpoint({scriptId:resolved.scriptId,lineNumber:resolved.location.line,columnNumber:resolved.location.column},fullCondition)).breakpointId,resolvedLocationsCount=1}catch{let scriptUrl=store.sourceMapResolver.getScriptUrl(resolved.scriptId);if(scriptUrl){let result=await store.v8Api.setBreakpointByUrl({url:scriptUrl,lineNumber:resolved.location.line,columnNumber:resolved.location.column,condition:fullCondition});breakpointId=result.breakpointId,resolvedLocationsCount=result.locations.length}else throw new Error("Failed to set breakpoint at resolved location and could not fall back (script URL unknown). A probe may already exist at this line; remove it first or use a different line.")}else{let urlRegex=options.urlPattern.replace(/\\([.*+?^${}()|[\]\\/-])/g,"$1").replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,".*").replace(/\\\?/g,"."),result=await store.v8Api.setBreakpointByUrl({urlRegex,lineNumber:options.lineNumber-1,columnNumber:options.columnNumber?options.columnNumber-1:void 0,condition:fullCondition});breakpointId=result.breakpointId,resolvedLocationsCount=result.locations.length}store.locationIndex.set(locationKey,{breakpointId,resolvedLocations:resolvedLocationsCount,refCount:1});let probe={id:probeId,kind:options.kind,enabled:!0,urlPattern:options.urlPattern,lineNumber:options.lineNumber,columnNumber:options.columnNumber,condition:options.condition,logExpression:options.logExpression,hitCondition:options.hitCondition,v8BreakpointIds:[breakpointId],resolvedLocations:resolvedLocationsCount,hitCount:0,createdAt:Date.now()};return store.probes.set(probeId,probe),probe}async function removeProbe2(ctx,probeId){let store=_getStore(ctx);if(!store)return!1;let probe=store.probes.get(probeId);if(!probe)return!1;let locationKey=_locationKey(probe.urlPattern,probe.lineNumber,probe.columnNumber??1),entry=store.locationIndex.get(locationKey);if(entry&&(entry.refCount--,entry.refCount===0)){try{await store.v8Api.removeBreakpoint(entry.breakpointId)}catch{}store.locationIndex.delete(locationKey)}return store.probes.delete(probeId),!0}function listProbes2(ctx){let store=_getStore(ctx);return store?Array.from(store.probes.values()):[]}function getProbe(ctx,probeId){let store=_getStore(ctx);if(store)return store.probes.get(probeId)}function getSnapshots2(ctx){let store=_getStore(ctx);return store?[...store.snapshots]:[]}function getSnapshotsByProbe2(ctx,probeId){let store=_getStore(ctx);return store?store.snapshots.filter(s=>s.probeId===probeId):[]}function clearSnapshotsByProbe(ctx,probeId){let store=_getStore(ctx);if(!store)return 0;let before=store.snapshots.length;return store.snapshots=store.snapshots.filter(s=>s.probeId!==probeId),before-store.snapshots.length}function getSnapshotStats2(ctx){let store=_getStore(ctx);if(!store||store.snapshots.length===0)return{totalSnapshots:0,snapshotsByProbe:{},averageCaptureTimeMs:0};let snapshotsByProbe={},totalCaptureTime=0;for(let snapshot of store.snapshots)snapshotsByProbe[snapshot.probeId]=(snapshotsByProbe[snapshot.probeId]||0)+1,totalCaptureTime+=snapshot.captureTimeMs;return{totalSnapshots:store.snapshots.length,snapshotsByProbe,oldestTimestamp:store.snapshots[0].timestamp,newestTimestamp:store.snapshots[store.snapshots.length-1].timestamp,averageCaptureTimeMs:totalCaptureTime/store.snapshots.length}}function addWatchExpression2(ctx,expression){let store=_getStore(ctx);if(!store)throw new Error("Debug store not initialized");let id=_generateId(),watchExpr={id,expression,createdAt:Date.now()};return store.watchExpressions.set(id,watchExpr),watchExpr}function removeWatchExpression2(ctx,watchExpressionId){let store=_getStore(ctx);return store?store.watchExpressions.delete(watchExpressionId):!1}function listWatchExpressions2(ctx){let store=_getStore(ctx);return store?Array.from(store.watchExpressions.values()):[]}function clearWatchExpressions2(ctx){let store=_getStore(ctx);if(!store)return 0;let count=store.watchExpressions.size;return store.watchExpressions.clear(),count}async function setDOMBreakpoint(ctx,page,options){let store=_getStore(ctx);if(!store||!store.enabled)throw new Error("Debugging is not enabled");let cdp=await store.v8Api.getCdp();await cdp.send("DOM.enable");let{root}=await cdp.send("DOM.getDocument",{depth:0}),{nodeId}=await cdp.send("DOM.querySelector",{nodeId:root.nodeId,selector:options.selector});if(!nodeId||nodeId===0)throw new Error(`Element not found: ${options.selector}`);let cdpType=options.type==="subtree-modified"?"subtree-modified":options.type==="attribute-modified"?"attribute-modified":"node-removed";await cdp.send("DOMDebugger.setDOMBreakpoint",{nodeId,type:cdpType});let id=_generateId(),domBreakpoint={id,selector:options.selector,type:options.type,attributeName:options.attributeName,enabled:!0,nodeId,hitCount:0,createdAt:Date.now()};return store.domBreakpoints.set(id,domBreakpoint),await page.evaluate(params=>{let selector=params.selector,breakpointId=params.breakpointId,type=params.type,attrName=params.attrName,maxMutations=params.maxMutations,maxHtmlSnippetLength=params.maxHtmlSnippetLength,element=document.querySelector(selector);if(!element)return;let win=window;win.__domBreakpointData=win.__domBreakpointData||{},win.__domBreakpointMutations=win.__domBreakpointMutations||[],win.__domBreakpointData[breakpointId]={selector,type,attrName,currentAttrs:{}};for(let attr of element.attributes)win.__domBreakpointData[breakpointId].currentAttrs[attr.name]=attr.value;let observer=new MutationObserver(mutations=>{for(let mutation of mutations){let target=mutation.target;if(mutation.type==="attributes"){let attrNameChanged=mutation.attributeName||"";if(attrName&&attrName!==attrNameChanged)continue;let mutationRecord={breakpointId,selector,type:"attribute-modified",attributeName:attrNameChanged,oldValue:mutation.oldValue,newValue:target.getAttribute(attrNameChanged),targetOuterHTML:target.outerHTML.substring(0,maxHtmlSnippetLength),timestamp:Date.now()};win.__domBreakpointMutations.push(mutationRecord),win.__domBreakpointMutations.length>maxMutations&&win.__domBreakpointMutations.shift(),win.__domBreakpointData[breakpointId].currentAttrs[attrNameChanged]=target.getAttribute(attrNameChanged)}else if(mutation.type==="childList"){let mutationRecord={breakpointId,selector,type:"subtree-modified",addedNodes:mutation.addedNodes.length,removedNodes:mutation.removedNodes.length,targetOuterHTML:target.outerHTML.substring(0,maxHtmlSnippetLength),timestamp:Date.now()};win.__domBreakpointMutations.push(mutationRecord),win.__domBreakpointMutations.length>maxMutations&&win.__domBreakpointMutations.shift()}}}),config={attributes:type==="attribute-modified",attributeOldValue:type==="attribute-modified",childList:type==="subtree-modified"||type==="node-removed",subtree:type==="subtree-modified"};attrName&&(config.attributeFilter=[attrName]),observer.observe(element,config),win.__domBreakpointObservers=win.__domBreakpointObservers||{},win.__domBreakpointObservers[breakpointId]=observer},{selector:options.selector,breakpointId:id,type:options.type,attrName:options.attributeName,maxMutations:store.config.maxDOMMutations,maxHtmlSnippetLength:store.config.maxDOMHtmlSnippetLength}),domBreakpoint}async function removeDOMBreakpoint(ctx,domBreakpointId,page){let store=_getStore(ctx);if(!store)return!1;let domBreakpoint=store.domBreakpoints.get(domBreakpointId);if(!domBreakpoint||!domBreakpoint.nodeId)return!1;try{let cdp=await store.v8Api.getCdp(),cdpType=domBreakpoint.type==="subtree-modified"?"subtree-modified":domBreakpoint.type==="attribute-modified"?"attribute-modified":"node-removed";await cdp.send("DOMDebugger.removeDOMBreakpoint",{nodeId:domBreakpoint.nodeId,type:cdpType})}catch{}if(page)try{await page.evaluate(breakpointId=>{let win=window;win.__domBreakpointObservers&&win.__domBreakpointObservers[breakpointId]&&(win.__domBreakpointObservers[breakpointId].disconnect(),delete win.__domBreakpointObservers[breakpointId]),win.__domBreakpointData&&delete win.__domBreakpointData[breakpointId],win.__domBreakpointMutations&&(win.__domBreakpointMutations=win.__domBreakpointMutations.filter(m=>m.breakpointId!==breakpointId))},domBreakpointId)}catch{}return store.domBreakpoints.delete(domBreakpointId)}function listDOMBreakpoints(ctx){let store=_getStore(ctx);return store?Array.from(store.domBreakpoints.values()):[]}async function clearDOMBreakpoints(ctx,page){let store=_getStore(ctx);if(!store)return 0;let ids=Array.from(store.domBreakpoints.keys());for(let id of ids)await removeDOMBreakpoint(ctx,id,page);return ids.length}async function _enableNetworkInterception(store,page){if(store.networkInterceptionEnabled)return;let cdp=await store.v8Api.getCdp();await cdp.send("Fetch.enable",{patterns:[{urlPattern:"*",requestStage:"Request"}]}),cdp.on("Fetch.requestPaused",async event=>{let requestId=event.requestId,requestUrl=event.request.url,method=event.request.method;try{let matchedBreakpoint;for(let bp of store.networkBreakpoints.values()){if(!bp.enabled)continue;let unescapedPattern=bp.urlPattern.replace(/\\([.*+?^${}()|[\]\\/-])/g,"$1");if(new RegExp(unescapedPattern.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,".*")).test(requestUrl)&&!(bp.method&&bp.method.toUpperCase()!==method.toUpperCase())&&bp.timing==="request"){matchedBreakpoint=bp;break}}if(matchedBreakpoint&&matchedBreakpoint.timing==="request"){let requestInfo={url:requestUrl,method,requestHeaders:event.request.headers,requestBody:event.request.postData,resourceType:event.resourceType,timing:"request"},snapshot={id:_generateId(),probeId:matchedBreakpoint.id,timestamp:Date.now(),sequenceNumber:++store.snapshotSequence,url:requestUrl,lineNumber:0,networkRequest:requestInfo,callStack:[],captureTimeMs:0};store.watchExpressions.size>0&&(snapshot.watchResults=await _evaluateWatchExpressions(store,page)),store.snapshots.push(snapshot),store.snapshots.length>store.config.maxSnapshots&&store.snapshots.splice(0,store.snapshots.length-store.config.maxSnapshots),matchedBreakpoint.hitCount++,matchedBreakpoint.lastHitAt=Date.now()}await cdp.send("Fetch.continueRequest",{requestId})}catch{try{await cdp.send("Fetch.continueRequest",{requestId})}catch{}}}),await cdp.send("Network.enable");let pendingRequests=new Map;cdp.on("Network.requestWillBeSent",event=>{if(pendingRequests.set(event.requestId,{method:event.request.method,postData:event.request.postData}),pendingRequests.size>store.config.maxPendingRequests){let firstKey=pendingRequests.keys().next().value;firstKey&&pendingRequests.delete(firstKey)}}),cdp.on("Network.responseReceived",async event=>{let requestId=event.requestId,requestUrl=event.response.url,requestInfo=pendingRequests.get(requestId),method=requestInfo?.method||event.type||"GET",status=event.response.status;for(let bp of store.networkBreakpoints.values()){if(!bp.enabled||bp.timing!=="response")continue;let unescapedPattern=bp.urlPattern.replace(/\\([.*+?^${}()|[\]\\/-])/g,"$1");if(!new RegExp(unescapedPattern.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,".*")).test(requestUrl)||bp.method&&bp.method.toUpperCase()!==method.toUpperCase()||bp.onError&&status<400)continue;let responseBody;try{let bodyResult=await cdp.send("Network.getResponseBody",{requestId});bodyResult.base64Encoded?responseBody=Buffer.from(bodyResult.body,"base64").toString("utf-8"):responseBody=bodyResult.body,responseBody&&responseBody.length>store.config.maxResponseBodyLength&&(responseBody=responseBody.substring(0,store.config.maxResponseBodyLength)+"... [truncated]")}catch{}let networkRequestInfo={url:requestUrl,method,requestBody:requestInfo?.postData,status,statusText:event.response.statusText,responseHeaders:event.response.headers,responseBody,resourceType:event.type,timing:"response"},snapshot={id:_generateId(),probeId:bp.id,timestamp:Date.now(),sequenceNumber:++store.snapshotSequence,url:requestUrl,lineNumber:0,networkRequest:networkRequestInfo,callStack:[],captureTimeMs:0};store.watchExpressions.size>0&&(snapshot.watchResults=await _evaluateWatchExpressions(store,page)),store.snapshots.push(snapshot),store.snapshots.length>store.config.maxSnapshots&&store.snapshots.splice(0,store.snapshots.length-store.config.maxSnapshots),bp.hitCount++,bp.lastHitAt=Date.now(),pendingRequests.delete(requestId);break}}),cdp.on("Network.loadingFinished",event=>{setTimeout(()=>{pendingRequests.delete(event.requestId)},store.config.networkCleanupTimeoutMs)}),store.networkInterceptionEnabled=!0}async function _evaluateWatchExpressions(store,page){let results={};for(let watch of store.watchExpressions.values())try{let value=await page.evaluate(expr=>{try{return(0,eval)(expr)}catch(e){return`[Error: ${e.message}]`}},watch.expression);results[watch.expression]=value}catch(e){results[watch.expression]=`[Error: ${e.message}]`}return results}async function setNetworkBreakpoint(ctx,page,options){let store=_getStore(ctx);if(!store||!store.enabled)throw new Error("Debugging is not enabled");await _enableNetworkInterception(store,page);let id=_generateId(),networkBreakpoint={id,urlPattern:options.urlPattern,method:options.method,timing:options.timing||"request",onError:options.onError,enabled:!0,hitCount:0,createdAt:Date.now()};return store.networkBreakpoints.set(id,networkBreakpoint),networkBreakpoint}function removeNetworkBreakpoint(ctx,networkBreakpointId){let store=_getStore(ctx);return store?store.networkBreakpoints.delete(networkBreakpointId):!1}function listNetworkBreakpoints(ctx){let store=_getStore(ctx);return store?Array.from(store.networkBreakpoints.values()):[]}function clearNetworkBreakpoints(ctx){let store=_getStore(ctx);if(!store)return 0;let count=store.networkBreakpoints.size;return store.networkBreakpoints.clear(),count}var Status=class{name(){return"debug_status"}description(){return`
|
|
285
285
|
Returns the current debugging status including:
|
|
286
286
|
- Whether debugging is enabled
|
|
287
287
|
- Source map status
|
|
@@ -816,7 +816,7 @@ similar to existing Playwright and Chrome DevTools\u2013based MCP servers, with
|
|
|
816
816
|
|
|
817
817
|
Take a snapshot first to get real selectors and refs:
|
|
818
818
|
- Call "a11y_take-aria-snapshot", "a11y_take-ax-tree-snapshot", or "content_get-as-html" (e.g. selector "form") to see actual ids, roles, and markup.
|
|
819
|
-
- "a11y_take-aria-snapshot" returns a tree with refs (e1, e2, ...) and stores them in context.
|
|
819
|
+
- "a11y_take-aria-snapshot" returns a tree with refs (e1, e2, ...) and stores them in context. In click, fill, hover, select, drag, scroll use the selector parameter as: a ref ("e1", "@e1", "ref=e1"), a Playwright-style expression (e.g. getByRole('button', { name: 'Login' }), getByLabel('Email'), getByText('Register'), getByPlaceholder('\u2026'), getByTitle('\u2026'), getByAltText('\u2026'), getByTestId('\u2026')), or a CSS selector. Refs are valid until the next snapshot or navigation; re-snapshot after page/DOM changes.
|
|
820
820
|
- Then use the returned selectors or refs for interaction. Guessing (e.g. input[type="email"]) often fails because real markup may use type="text", wrappers, or different attributes.
|
|
821
821
|
|
|
822
822
|
SNAPSHOT FIRST, THEN INTERACT.
|
|
@@ -834,7 +834,7 @@ Core capabilities include:
|
|
|
834
834
|
|
|
835
835
|
**Browser Control & Interaction:**
|
|
836
836
|
- Navigation (go to URL, back, forward)
|
|
837
|
-
- Element interaction (click, fill, hover, select, drag): selector accepts
|
|
837
|
+
- Element interaction (click, fill, hover, select, drag): selector accepts snapshot ref (e1, @e1, ref=e1), Playwright-style expression (getByRole, getByLabel, getByText, getByPlaceholder, getByTitle, getByAltText, getByTestId), or CSS selector; refs come from a11y_take-aria-snapshot and are valid until next snapshot or navigation
|
|
838
838
|
- Keyboard simulation (press-key)
|
|
839
839
|
- Scrolling (viewport or container-based with multiple modes)
|
|
840
840
|
- Viewport emulation and real window resizing
|
|
@@ -954,7 +954,7 @@ When asked to check for UI problems, layout issues, or visual bugs, ALWAYS follo
|
|
|
954
954
|
- If you need layout/occlusion/visibility: call "a11y_take-ax-tree-snapshot" (with "checkOcclusion:true" when relevant).
|
|
955
955
|
- Call "content_take-screenshot" ONLY when you need to verify how something looks visually (e.g. design check, visual bug) or when ARIA/AX are insufficient. Do NOT use screenshot to "see the page" or understand structure.
|
|
956
956
|
|
|
957
|
-
3. **Before any element interaction** (click, fill, hover, select, drag): Take a snapshot first to get real selectors and refs. Call "a11y_take-aria-snapshot" (returns refs e1, e2, ... usable as selector "e1" or "
|
|
957
|
+
3. **Before any element interaction** (click, fill, hover, select, drag): Take a snapshot first to get real selectors and refs. Call "a11y_take-aria-snapshot" (returns refs e1, e2, ... usable as selector "e1", "@e1", or "ref=e1"), "a11y_take-ax-tree-snapshot", or "content_get-as-html" (e.g. selector "form") to see actual ids, roles, and markup. You can also use Playwright-style expressions as selector: getByRole('button', { name: 'Login' }), getByLabel('Email'), getByText('Register'), getByPlaceholder('\u2026'), getByTitle('\u2026'), getByAltText('\u2026'), getByTestId('\u2026'), or CSS. Refs are valid until next snapshot or navigation. Do NOT guess selectors from screenshots\u2014real markup often differs (e.g. type="text" instead of type="email"). Snapshot first, then interact.
|
|
958
958
|
|
|
959
959
|
4. **Screenshot usage**: When you do take a screenshot, do NOT set "includeBase64" to true unless the assistant cannot read the returned file path (e.g. remote/container). The image is always saved to disk.
|
|
960
960
|
|
|
@@ -965,7 +965,7 @@ When asked to check for UI problems, layout issues, or visual bugs, ALWAYS follo
|
|
|
965
965
|
- Set "includeStyles:true" to analyze computed CSS properties
|
|
966
966
|
|
|
967
967
|
6. **ARIA Snapshot**: Call "a11y_take-aria-snapshot" tool (full page or specific selector)
|
|
968
|
-
- Provides semantic structure and accessibility roles; returns refs (e1, e2, ...) for use in interaction tools (selector "e1", "@e1",
|
|
968
|
+
- Provides semantic structure and accessibility roles; returns refs (e1, e2, ...) for use in interaction tools (selector "e1", "@e1", "ref=e1", or getByRole/getByLabel/getByText/getByPlaceholder/getByTitle/getByAltText/getByTestId, or CSS)
|
|
969
969
|
- Set cursorInteractive: true to also get refs for custom clickable elements (e.g. div/span with cursor:pointer or onclick) that have no ARIA role
|
|
970
970
|
- Best for understanding page hierarchy and accessibility issues
|
|
971
971
|
- Refs are valid until next snapshot or navigation; re-snapshot after page/DOM changes
|
|
@@ -1024,7 +1024,7 @@ When asked to check for UI problems, layout issues, or visual bugs, ALWAYS follo
|
|
|
1024
1024
|
|
|
1025
1025
|
**Tool Usage Notes:**
|
|
1026
1026
|
- To understand the page: ARIA snapshot first, then AX tree; do NOT use screenshot for structure\u2014use screenshot only for visual verification when needed.
|
|
1027
|
-
- Before any click/fill/hover/select/drag: take a snapshot first to get selectors; do not guess from screenshots.
|
|
1027
|
+
- Before any click/fill/hover/select/drag: take a snapshot first to get selectors or refs; you can use refs (e1, @e1), getByRole/getByLabel/getByText/etc., or CSS; do not guess from screenshots.
|
|
1028
1028
|
- Screenshot only when you need to verify how the UI looks (e.g. visual bug, design check) or when ARIA/AX are insufficient.
|
|
1029
1029
|
- Do not set includeBase64 on screenshot unless the assistant cannot read the file path.
|
|
1030
1030
|
- AX tree: Technical measurements, occlusion, precise positioning, visual diagnostics
|
|
@@ -1066,7 +1066,7 @@ When MCP runs in a container connecting to another container:
|
|
|
1066
1066
|
|
|
1067
1067
|
Once connected, you can use tracepoints, logpoints, exceptionpoints,
|
|
1068
1068
|
and watch expressions - the same debugging tools available for browser.
|
|
1069
|
-
`}inputSchema(){return{pid:z70.number().int().positive().describe("Process ID to connect to").optional(),processName:z70.string().describe('Process name pattern to search for (e.g., "server.js", "api")').optional(),containerId:z70.string().describe("Docker container ID - process runs inside this container").optional(),containerName:z70.string().describe("Docker container name or pattern (e.g., my-node-app) - resolved via docker ps -f name=").optional(),host:z70.string().describe("Inspector host (default: 127.0.0.1); for containerized MCP use host.docker.internal or container name").optional(),port:z70.number().int().positive().describe("Inspector port (default: 9229); for Docker use host-mapped port").optional(),wsUrl:z70.string().describe("Direct WebSocket URL (e.g., ws://127.0.0.1:9229/abc-123)").optional()}}outputSchema(){return{connected:z70.boolean().describe("Whether connection was successful"),pid:z70.number().describe("Process ID"),command:z70.string().optional().describe("Process command line"),containerId:z70.string().optional().describe("Docker container ID when connected via container"),inspectorHost:z70.string().optional().describe("Inspector host"),inspectorPort:z70.number().optional().describe("Inspector port"),webSocketUrl:z70.string().optional().describe("WebSocket URL"),title:z70.string().describe("Target title")}}async handle(context,args){let result=await context.connect({pid:args.pid,processName:args.processName,containerId:args.containerId,containerName:args.containerName,host:args.host,port:args.port,wsUrl:args.wsUrl,activateIfNeeded:!0});return{connected:!0,pid:result.processInfo.pid,command:result.processInfo.command,containerId:result.processInfo.containerId,inspectorHost:result.processInfo.inspectorHost,inspectorPort:result.processInfo.inspectorPort,webSocketUrl:result.processInfo.webSocketUrl,title:result.target.title}}};import{z as z71}from"zod";var Disconnect=class{name(){return"debug_disconnect"}description(){return"Disconnects from the currently connected Node.js process and cleans up debugging resources."}inputSchema(){return{}}outputSchema(){return{disconnected:z71.boolean().describe("Whether disconnection was successful")}}async handle(context,_args){return await context.disconnect(),{disconnected:!0}}};import{z as z72}from"zod";function _filterSnapshots(storeKey,probeId,fromSequence,limit,kind){let snapshots;if(probeId)snapshots=getSnapshotsByProbe(storeKey,probeId);else if(kind){let probes=listProbes(storeKey),probeIds=new Set(probes.filter(p=>p.kind===kind).map(p=>p.id)),allSnapshots=getSnapshots(storeKey);kind==="tracepoint"?snapshots=allSnapshots.filter(s=>probeIds.has(s.probeId)||s.probeId==="__exception__"):snapshots=allSnapshots.filter(s=>probeIds.has(s.probeId))}else snapshots=getSnapshots(storeKey);return fromSequence!==void 0&&(snapshots=snapshots.filter(s=>s.sequenceNumber>fromSequence)),limit!==void 0&&(snapshots=snapshots.slice(-limit)),snapshots}var GetTracepointSnapshots2=class{name(){return"debug_get-tracepoint-snapshots"}description(){return"Retrieves snapshots captured by tracepoints on the Node.js process. Each snapshot contains call stack with local variables, async stack trace, watch expression results, and traceContext (traceId, spanId) when the process uses @opentelemetry/api."}inputSchema(){return{probeId:z72.string().describe("Filter by specific tracepoint ID").optional(),fromSequence:z72.number().int().nonnegative().describe("Return snapshots with sequence number > fromSequence (for polling)").optional(),limit:z72.number().int().positive().describe("Maximum number of snapshots to return").optional()}}outputSchema(){return{snapshots:z72.array(z72.any()).describe("Captured snapshots"),count:z72.number().describe("Number of snapshots returned")}}async handle(context,args){let snapshots=_filterSnapshots(context.storeKey,args.probeId,args.fromSequence,args.limit,"tracepoint");return{snapshots,count:snapshots.length}}},GetLogpointSnapshots2=class{name(){return"debug_get-logpoint-snapshots"}description(){return"Retrieves snapshots captured by logpoints on the Node.js process. Each snapshot contains the log expression result and traceContext (traceId, spanId) when the process uses @opentelemetry/api."}inputSchema(){return{probeId:z72.string().describe("Filter by specific logpoint ID").optional(),fromSequence:z72.number().int().nonnegative().describe("Return snapshots with sequence number > fromSequence").optional(),limit:z72.number().int().positive().describe("Maximum number of snapshots to return").optional()}}outputSchema(){return{snapshots:z72.array(z72.any()).describe("Captured snapshots"),count:z72.number().describe("Number of snapshots returned")}}async handle(context,args){let snapshots=_filterSnapshots(context.storeKey,args.probeId,args.fromSequence,args.limit,"logpoint");return{snapshots,count:snapshots.length}}},GetExceptionpointSnapshots2=class{name(){return"debug_get-exceptionpoint-snapshots"}description(){return"Retrieves snapshots captured by exception breakpoints on the Node.js process. Snapshots include traceContext (traceId, spanId) when the process uses @opentelemetry/api."}inputSchema(){return{fromSequence:z72.number().int().nonnegative().describe("Return snapshots with sequence number > fromSequence").optional(),limit:z72.number().int().positive().describe("Maximum number of snapshots to return").optional()}}outputSchema(){return{snapshots:z72.array(z72.any()).describe("Captured snapshots"),count:z72.number().describe("Number of snapshots returned")}}async handle(context,args){let snapshots=getSnapshots(context.storeKey).filter(s=>s.probeId==="__exception__");return args.fromSequence!==void 0&&(snapshots=snapshots.filter(s=>s.sequenceNumber>args.fromSequence)),args.limit!==void 0&&(snapshots=snapshots.slice(-args.limit)),{snapshots,count:snapshots.length}}},ClearTracepointSnapshots2=class{name(){return"debug_clear-tracepoint-snapshots"}description(){return"Clears tracepoint snapshots. Optionally filter by specific tracepoint ID."}inputSchema(){return{probeId:z72.string().describe("Clear only snapshots for this tracepoint ID").optional()}}outputSchema(){return{cleared:z72.number().describe("Number of snapshots cleared")}}async handle(context,args){let{clearSnapshots,clearSnapshotsByProbe:clearSnapshotsByProbe2}=await import("./core-QH4KRWJ5.js");return{cleared:args.probeId?clearSnapshotsByProbe2(context.storeKey,args.probeId):clearSnapshots(context.storeKey)}}},ClearLogpointSnapshots2=class{name(){return"debug_clear-logpoint-snapshots"}description(){return"Clears logpoint snapshots. Optionally filter by specific logpoint ID."}inputSchema(){return{probeId:z72.string().describe("Clear only snapshots for this logpoint ID").optional()}}outputSchema(){return{cleared:z72.number().describe("Number of snapshots cleared")}}async handle(context,args){let{clearSnapshotsByProbe:clearSnapshotsByProbe2,clearSnapshots}=await import("./core-QH4KRWJ5.js");return{cleared:args.probeId?clearSnapshotsByProbe2(context.storeKey,args.probeId):clearSnapshots(context.storeKey)}}},ClearExceptionpointSnapshots2=class{name(){return"debug_clear-exceptionpoint-snapshots"}description(){return"Clears all exception snapshots."}inputSchema(){return{}}outputSchema(){return{cleared:z72.number().describe("Number of snapshots cleared")}}async handle(context,_args){let{clearSnapshotsByProbe:clearSnapshotsByProbe2}=await import("./core-QH4KRWJ5.js");return{cleared:clearSnapshotsByProbe2(context.storeKey,"__exception__")}}};import{z as z73}from"zod";var GetLogs=class{name(){return"debug_get-logs"}description(){return"Retrieves console messages/logs from the Node.js process with filtering options."}inputSchema(){return{type:z73.enum(getEnumKeyTuples(ConsoleMessageLevelName)).transform(createEnumTransformer(ConsoleMessageLevelName)).describe(`Type of console messages to retrieve. When specified, messages with equal or higher levels are retrieved. Valid values: ${getEnumKeyTuples(ConsoleMessageLevelName).join(", ")}.`).optional(),search:z73.string().describe("Text to search for in console messages.").optional(),timestamp:z73.number().int().nonnegative().describe("Start time filter as Unix epoch timestamp in milliseconds. If provided, only messages recorded at or after this timestamp will be returned.").optional(),sequenceNumber:z73.number().int().nonnegative().describe("Sequence number for incremental retrieval. If provided, only messages with sequence number greater than this value will be returned.").optional(),limit:z73.object({count:z73.number().int().nonnegative().default(0).describe("Max number of messages. 0 = no limit."),from:z73.enum(["start","end"]).default("end").describe("Which side to keep when truncated.")}).describe("Maximum number of console messages to return.").optional()}}outputSchema(){return{messages:z73.array(z73.object({type:z73.string().describe("Type of the console message."),text:z73.string().describe("Text of the console message."),location:z73.object({url:z73.string().describe("URL of the resource."),lineNumber:z73.number().nonnegative().describe("0-based line number."),columnNumber:z73.number().nonnegative().describe("0-based column number.")}).describe("Location of the console message.").optional(),timestamp:z73.number().int().nonnegative().describe("Unix epoch timestamp (ms)."),sequenceNumber:z73.number().int().nonnegative().describe("Monotonic sequence number.")})).describe("Retrieved console messages.")}}async handle(context,args){let levelCodeThreshold=args.type?ConsoleMessageLevel[args.type]?.code:void 0,filtered=getConsoleMessages(context.storeKey).filter(msg=>!(levelCodeThreshold!==void 0&&msg.level.code<levelCodeThreshold||args.timestamp&&msg.timestamp<args.timestamp||args.sequenceNumber&&msg.sequenceNumber<=args.sequenceNumber||args.search&&!msg.text.includes(args.search)));return{messages:(args.limit?.count?args.limit.from==="start"?filtered.slice(0,args.limit.count):filtered.slice(-args.limit.count):filtered).map(msg=>({type:msg.type,text:msg.text,location:msg.location?{url:msg.location.url,lineNumber:msg.location.lineNumber,columnNumber:msg.location.columnNumber}:void 0,timestamp:msg.timestamp,sequenceNumber:msg.sequenceNumber}))}}};import{z as z74}from"zod";var RemoveTracepoint2=class{name(){return"debug_remove-tracepoint"}description(){return"Removes a tracepoint by its ID."}inputSchema(){return{id:z74.string().describe("Tracepoint ID to remove")}}outputSchema(){return{removed:z74.boolean().describe("Whether the tracepoint was removed")}}async handle(context,args){return{removed:await removeProbe(context.storeKey,args.id)}}},ListTracepoints2=class{name(){return"debug_list-tracepoints"}description(){return"Lists all active tracepoints on the Node.js process."}inputSchema(){return{}}outputSchema(){return{tracepoints:z74.array(z74.any()).describe("Active tracepoints")}}async handle(context,_args){return{tracepoints:listProbes(context.storeKey).filter(p=>p.kind==="tracepoint").map(p=>({id:p.id,urlPattern:p.urlPattern,lineNumber:p.lineNumber,columnNumber:p.columnNumber,condition:p.condition,hitCondition:p.hitCondition,hitCount:p.hitCount,resolvedLocations:p.resolvedLocations,enabled:p.enabled}))}}},ClearTracepoints2=class{name(){return"debug_clear-tracepoints"}description(){return"Removes all tracepoints from the Node.js process."}inputSchema(){return{}}outputSchema(){return{cleared:z74.number().describe("Number of tracepoints cleared")}}async handle(context,_args){let probes=listProbes(context.storeKey).filter(p=>p.kind==="tracepoint"),count=0;for(let p of probes)await removeProbe(context.storeKey,p.id)&&count++;return{cleared:count}}},RemoveLogpoint2=class{name(){return"debug_remove-logpoint"}description(){return"Removes a logpoint by its ID."}inputSchema(){return{id:z74.string().describe("Logpoint ID to remove")}}outputSchema(){return{removed:z74.boolean().describe("Whether the logpoint was removed")}}async handle(context,args){return{removed:await removeProbe(context.storeKey,args.id)}}},ListLogpoints2=class{name(){return"debug_list-logpoints"}description(){return"Lists all active logpoints on the Node.js process."}inputSchema(){return{}}outputSchema(){return{logpoints:z74.array(z74.any()).describe("Active logpoints")}}async handle(context,_args){return{logpoints:listProbes(context.storeKey).filter(p=>p.kind==="logpoint").map(p=>({id:p.id,urlPattern:p.urlPattern,lineNumber:p.lineNumber,logExpression:p.logExpression,condition:p.condition,hitCondition:p.hitCondition,hitCount:p.hitCount,resolvedLocations:p.resolvedLocations,enabled:p.enabled}))}}},ClearLogpoints2=class{name(){return"debug_clear-logpoints"}description(){return"Removes all logpoints from the Node.js process."}inputSchema(){return{}}outputSchema(){return{cleared:z74.number().describe("Number of logpoints cleared")}}async handle(context,_args){let probes=listProbes(context.storeKey).filter(p=>p.kind==="logpoint"),count=0;for(let p of probes)await removeProbe(context.storeKey,p.id)&&count++;return{cleared:count}}};import{z as z75}from"zod";var PutExceptionpoint2=class{name(){return"debug_put-exceptionpoint"}description(){return`
|
|
1069
|
+
`}inputSchema(){return{pid:z70.number().int().positive().describe("Process ID to connect to").optional(),processName:z70.string().describe('Process name pattern to search for (e.g., "server.js", "api")').optional(),containerId:z70.string().describe("Docker container ID - process runs inside this container").optional(),containerName:z70.string().describe("Docker container name or pattern (e.g., my-node-app) - resolved via docker ps -f name=").optional(),host:z70.string().describe("Inspector host (default: 127.0.0.1); for containerized MCP use host.docker.internal or container name").optional(),port:z70.number().int().positive().describe("Inspector port (default: 9229); for Docker use host-mapped port").optional(),wsUrl:z70.string().describe("Direct WebSocket URL (e.g., ws://127.0.0.1:9229/abc-123)").optional()}}outputSchema(){return{connected:z70.boolean().describe("Whether connection was successful"),pid:z70.number().describe("Process ID"),command:z70.string().optional().describe("Process command line"),containerId:z70.string().optional().describe("Docker container ID when connected via container"),inspectorHost:z70.string().optional().describe("Inspector host"),inspectorPort:z70.number().optional().describe("Inspector port"),webSocketUrl:z70.string().optional().describe("WebSocket URL"),title:z70.string().describe("Target title")}}async handle(context,args){let result=await context.connect({pid:args.pid,processName:args.processName,containerId:args.containerId,containerName:args.containerName,host:args.host,port:args.port,wsUrl:args.wsUrl,activateIfNeeded:!0});return{connected:!0,pid:result.processInfo.pid,command:result.processInfo.command,containerId:result.processInfo.containerId,inspectorHost:result.processInfo.inspectorHost,inspectorPort:result.processInfo.inspectorPort,webSocketUrl:result.processInfo.webSocketUrl,title:result.target.title}}};import{z as z71}from"zod";var Disconnect=class{name(){return"debug_disconnect"}description(){return"Disconnects from the currently connected Node.js process and cleans up debugging resources."}inputSchema(){return{}}outputSchema(){return{disconnected:z71.boolean().describe("Whether disconnection was successful")}}async handle(context,_args){return await context.disconnect(),{disconnected:!0}}};import{z as z72}from"zod";function _filterSnapshots(storeKey,probeId,fromSequence,limit,kind){let snapshots;if(probeId)snapshots=getSnapshotsByProbe(storeKey,probeId);else if(kind){let probes=listProbes(storeKey),probeIds=new Set(probes.filter(p=>p.kind===kind).map(p=>p.id)),allSnapshots=getSnapshots(storeKey);kind==="tracepoint"?snapshots=allSnapshots.filter(s=>probeIds.has(s.probeId)||s.probeId==="__exception__"):snapshots=allSnapshots.filter(s=>probeIds.has(s.probeId))}else snapshots=getSnapshots(storeKey);return fromSequence!==void 0&&(snapshots=snapshots.filter(s=>s.sequenceNumber>fromSequence)),limit!==void 0&&(snapshots=snapshots.slice(-limit)),snapshots}var GetTracepointSnapshots2=class{name(){return"debug_get-tracepoint-snapshots"}description(){return"Retrieves snapshots captured by tracepoints on the Node.js process. Each snapshot contains call stack with local variables, async stack trace, watch expression results, and traceContext (traceId, spanId) when the process uses @opentelemetry/api."}inputSchema(){return{probeId:z72.string().describe("Filter by specific tracepoint ID").optional(),fromSequence:z72.number().int().nonnegative().describe("Return snapshots with sequence number > fromSequence (for polling)").optional(),limit:z72.number().int().positive().describe("Maximum number of snapshots to return").optional()}}outputSchema(){return{snapshots:z72.array(z72.any()).describe("Captured snapshots"),count:z72.number().describe("Number of snapshots returned")}}async handle(context,args){let snapshots=_filterSnapshots(context.storeKey,args.probeId,args.fromSequence,args.limit,"tracepoint");return{snapshots,count:snapshots.length}}},GetLogpointSnapshots2=class{name(){return"debug_get-logpoint-snapshots"}description(){return"Retrieves snapshots captured by logpoints on the Node.js process. Each snapshot contains the log expression result and traceContext (traceId, spanId) when the process uses @opentelemetry/api."}inputSchema(){return{probeId:z72.string().describe("Filter by specific logpoint ID").optional(),fromSequence:z72.number().int().nonnegative().describe("Return snapshots with sequence number > fromSequence").optional(),limit:z72.number().int().positive().describe("Maximum number of snapshots to return").optional()}}outputSchema(){return{snapshots:z72.array(z72.any()).describe("Captured snapshots"),count:z72.number().describe("Number of snapshots returned")}}async handle(context,args){let snapshots=_filterSnapshots(context.storeKey,args.probeId,args.fromSequence,args.limit,"logpoint");return{snapshots,count:snapshots.length}}},GetExceptionpointSnapshots2=class{name(){return"debug_get-exceptionpoint-snapshots"}description(){return"Retrieves snapshots captured by exception breakpoints on the Node.js process. Snapshots include traceContext (traceId, spanId) when the process uses @opentelemetry/api."}inputSchema(){return{fromSequence:z72.number().int().nonnegative().describe("Return snapshots with sequence number > fromSequence").optional(),limit:z72.number().int().positive().describe("Maximum number of snapshots to return").optional()}}outputSchema(){return{snapshots:z72.array(z72.any()).describe("Captured snapshots"),count:z72.number().describe("Number of snapshots returned")}}async handle(context,args){let snapshots=getSnapshots(context.storeKey).filter(s=>s.probeId==="__exception__");return args.fromSequence!==void 0&&(snapshots=snapshots.filter(s=>s.sequenceNumber>args.fromSequence)),args.limit!==void 0&&(snapshots=snapshots.slice(-args.limit)),{snapshots,count:snapshots.length}}},ClearTracepointSnapshots2=class{name(){return"debug_clear-tracepoint-snapshots"}description(){return"Clears tracepoint snapshots. Optionally filter by specific tracepoint ID."}inputSchema(){return{probeId:z72.string().describe("Clear only snapshots for this tracepoint ID").optional()}}outputSchema(){return{cleared:z72.number().describe("Number of snapshots cleared")}}async handle(context,args){let{clearSnapshots,clearSnapshotsByProbe:clearSnapshotsByProbe2}=await import("./core-FCPLN2O4.js");return{cleared:args.probeId?clearSnapshotsByProbe2(context.storeKey,args.probeId):clearSnapshots(context.storeKey)}}},ClearLogpointSnapshots2=class{name(){return"debug_clear-logpoint-snapshots"}description(){return"Clears logpoint snapshots. Optionally filter by specific logpoint ID."}inputSchema(){return{probeId:z72.string().describe("Clear only snapshots for this logpoint ID").optional()}}outputSchema(){return{cleared:z72.number().describe("Number of snapshots cleared")}}async handle(context,args){let{clearSnapshotsByProbe:clearSnapshotsByProbe2,clearSnapshots}=await import("./core-FCPLN2O4.js");return{cleared:args.probeId?clearSnapshotsByProbe2(context.storeKey,args.probeId):clearSnapshots(context.storeKey)}}},ClearExceptionpointSnapshots2=class{name(){return"debug_clear-exceptionpoint-snapshots"}description(){return"Clears all exception snapshots."}inputSchema(){return{}}outputSchema(){return{cleared:z72.number().describe("Number of snapshots cleared")}}async handle(context,_args){let{clearSnapshotsByProbe:clearSnapshotsByProbe2}=await import("./core-FCPLN2O4.js");return{cleared:clearSnapshotsByProbe2(context.storeKey,"__exception__")}}};import{z as z73}from"zod";var GetLogs=class{name(){return"debug_get-logs"}description(){return"Retrieves console messages/logs from the Node.js process with filtering options."}inputSchema(){return{type:z73.enum(getEnumKeyTuples(ConsoleMessageLevelName)).transform(createEnumTransformer(ConsoleMessageLevelName)).describe(`Type of console messages to retrieve. When specified, messages with equal or higher levels are retrieved. Valid values: ${getEnumKeyTuples(ConsoleMessageLevelName).join(", ")}.`).optional(),search:z73.string().describe("Text to search for in console messages.").optional(),timestamp:z73.number().int().nonnegative().describe("Start time filter as Unix epoch timestamp in milliseconds. If provided, only messages recorded at or after this timestamp will be returned.").optional(),sequenceNumber:z73.number().int().nonnegative().describe("Sequence number for incremental retrieval. If provided, only messages with sequence number greater than this value will be returned.").optional(),limit:z73.object({count:z73.number().int().nonnegative().default(0).describe("Max number of messages. 0 = no limit."),from:z73.enum(["start","end"]).default("end").describe("Which side to keep when truncated.")}).describe("Maximum number of console messages to return.").optional()}}outputSchema(){return{messages:z73.array(z73.object({type:z73.string().describe("Type of the console message."),text:z73.string().describe("Text of the console message."),location:z73.object({url:z73.string().describe("URL of the resource."),lineNumber:z73.number().nonnegative().describe("0-based line number."),columnNumber:z73.number().nonnegative().describe("0-based column number.")}).describe("Location of the console message.").optional(),timestamp:z73.number().int().nonnegative().describe("Unix epoch timestamp (ms)."),sequenceNumber:z73.number().int().nonnegative().describe("Monotonic sequence number.")})).describe("Retrieved console messages.")}}async handle(context,args){let levelCodeThreshold=args.type?ConsoleMessageLevel[args.type]?.code:void 0,filtered=getConsoleMessages(context.storeKey).filter(msg=>!(levelCodeThreshold!==void 0&&msg.level.code<levelCodeThreshold||args.timestamp&&msg.timestamp<args.timestamp||args.sequenceNumber&&msg.sequenceNumber<=args.sequenceNumber||args.search&&!msg.text.includes(args.search)));return{messages:(args.limit?.count?args.limit.from==="start"?filtered.slice(0,args.limit.count):filtered.slice(-args.limit.count):filtered).map(msg=>({type:msg.type,text:msg.text,location:msg.location?{url:msg.location.url,lineNumber:msg.location.lineNumber,columnNumber:msg.location.columnNumber}:void 0,timestamp:msg.timestamp,sequenceNumber:msg.sequenceNumber}))}}};import{z as z74}from"zod";var RemoveTracepoint2=class{name(){return"debug_remove-tracepoint"}description(){return"Removes a tracepoint by its ID."}inputSchema(){return{id:z74.string().describe("Tracepoint ID to remove")}}outputSchema(){return{removed:z74.boolean().describe("Whether the tracepoint was removed")}}async handle(context,args){return{removed:await removeProbe(context.storeKey,args.id)}}},ListTracepoints2=class{name(){return"debug_list-tracepoints"}description(){return"Lists all active tracepoints on the Node.js process."}inputSchema(){return{}}outputSchema(){return{tracepoints:z74.array(z74.any()).describe("Active tracepoints")}}async handle(context,_args){return{tracepoints:listProbes(context.storeKey).filter(p=>p.kind==="tracepoint").map(p=>({id:p.id,urlPattern:p.urlPattern,lineNumber:p.lineNumber,columnNumber:p.columnNumber,condition:p.condition,hitCondition:p.hitCondition,hitCount:p.hitCount,resolvedLocations:p.resolvedLocations,enabled:p.enabled}))}}},ClearTracepoints2=class{name(){return"debug_clear-tracepoints"}description(){return"Removes all tracepoints from the Node.js process."}inputSchema(){return{}}outputSchema(){return{cleared:z74.number().describe("Number of tracepoints cleared")}}async handle(context,_args){let probes=listProbes(context.storeKey).filter(p=>p.kind==="tracepoint"),count=0;for(let p of probes)await removeProbe(context.storeKey,p.id)&&count++;return{cleared:count}}},RemoveLogpoint2=class{name(){return"debug_remove-logpoint"}description(){return"Removes a logpoint by its ID."}inputSchema(){return{id:z74.string().describe("Logpoint ID to remove")}}outputSchema(){return{removed:z74.boolean().describe("Whether the logpoint was removed")}}async handle(context,args){return{removed:await removeProbe(context.storeKey,args.id)}}},ListLogpoints2=class{name(){return"debug_list-logpoints"}description(){return"Lists all active logpoints on the Node.js process."}inputSchema(){return{}}outputSchema(){return{logpoints:z74.array(z74.any()).describe("Active logpoints")}}async handle(context,_args){return{logpoints:listProbes(context.storeKey).filter(p=>p.kind==="logpoint").map(p=>({id:p.id,urlPattern:p.urlPattern,lineNumber:p.lineNumber,logExpression:p.logExpression,condition:p.condition,hitCondition:p.hitCondition,hitCount:p.hitCount,resolvedLocations:p.resolvedLocations,enabled:p.enabled}))}}},ClearLogpoints2=class{name(){return"debug_clear-logpoints"}description(){return"Removes all logpoints from the Node.js process."}inputSchema(){return{}}outputSchema(){return{cleared:z74.number().describe("Number of logpoints cleared")}}async handle(context,_args){let probes=listProbes(context.storeKey).filter(p=>p.kind==="logpoint"),count=0;for(let p of probes)await removeProbe(context.storeKey,p.id)&&count++;return{cleared:count}}};import{z as z75}from"zod";var PutExceptionpoint2=class{name(){return"debug_put-exceptionpoint"}description(){return`
|
|
1070
1070
|
Sets the exception tracepoint state for a Node.js process:
|
|
1071
1071
|
- "none": Don't capture on exceptions
|
|
1072
1072
|
- "uncaught": Capture only on uncaught exceptions
|
package/dist/daemon-server.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{platformInfo}from"./core-
|
|
1
|
+
import{platformInfo}from"./core-GIHDFCBF.js";import{AVAILABLE_TOOL_DOMAINS,DAEMON_PORT,DAEMON_SESSION_IDLE_CHECK_SECONDS,DAEMON_SESSION_IDLE_SECONDS,debug,enable,error,info,isDebugEnabled}from"./core-247YVH6X.js";import{createRequire}from"node:module";import{Command,Option,InvalidOptionArgumentError}from"commander";import{serve}from"@hono/node-server";import{Hono}from"hono";import{cors}from"hono/cors";import{z}from"zod";var require2=createRequire(import.meta.url),daemonStartTime=0,daemonPort=0,app=new Hono,sessions=new Map,DEFAULT_SESSION_ID="#default",ERRORS={get sessionNotFound(){return _buildErrorResponse(404,"Session Not Found")},get toolNotFound(){return _buildErrorResponse(404,"Tool Not Found")},get internalServerError(){return _buildErrorResponse(500,"Internal Server Error")}};function _buildErrorResponse(code,message){return{error:{code,message}}}async function _closeSession(session){if(session.closed=!0,session.context)try{await session.context.close(),debug("Closed MCP session context")}catch(err){error("Error occurred while closing MCP session context",err)}sessions.delete(session.id)}function _createSession(ctx,sessionId){let now=Date.now(),session={id:sessionId,toolExecutor:platformInfo.toolsInfo.createToolExecutor(()=>sessionId),closed:!1,createdAt:now,lastActiveAt:now};return debug(`Created session with id ${sessionId}`),session}function _getSessionInfo(session){let now=Date.now();return{id:session.id,createdAt:session.createdAt,lastActiveAt:session.lastActiveAt,idleSeconds:Math.floor((now-session.lastActiveAt)/1e3)}}async function _getSession(ctx){let sessionId=ctx.req.header("session-id")||DEFAULT_SESSION_ID;return sessions.get(sessionId)}async function _getOrCreateSession(ctx){let sessionId=ctx.req.header("session-id")||DEFAULT_SESSION_ID,session=sessions.get(sessionId);return session?debug(`Reusing session with id ${sessionId}`):(debug(`No session could be found with id ${sessionId}`),session=_createSession(ctx,sessionId),sessions.set(sessionId,session)),session}function _scheduleIdleSessionCheck(){let noActiveSession=!1;setInterval(()=>{let currentTime=Date.now();noActiveSession&&sessions.size===0&&(info("No active session found, so terminating daemon server"),process.exit(0));for(let[sessionId,session]of sessions)debug(`Checking whether session with id ${sessionId} is idle or not ...`),currentTime-session.lastActiveAt>DAEMON_SESSION_IDLE_SECONDS*1e3&&(debug(`Session with id ${sessionId} is idle, so it will be closing ...`),_closeSession(session).then(()=>{debug(`Session with id ${sessionId} was idle, so it has been closed`)}).catch(err=>{error(`Unable to delete idle session with id ${sessionId}`,err)}));noActiveSession=sessions.size===0},DAEMON_SESSION_IDLE_CHECK_SECONDS*1e3)}async function _logRequest(ctx){let reqClone=ctx.req.raw.clone();debug(`Got request: ${await reqClone.json()}`)}async function startDaemonHTTPServer(port){let allowedDomains=AVAILABLE_TOOL_DOMAINS,toolsToExpose=allowedDomains===void 0?platformInfo.toolsInfo.tools:platformInfo.toolsInfo.tools.filter(tool=>{let domain=tool.name().split("_")[0]?.toLowerCase()??"";return allowedDomains.has(domain)}),toolMap=Object.fromEntries(toolsToExpose.map(tool=>[tool.name(),tool]));app.use("*",cors({origin:"*",allowMethods:["GET","POST","DELETE","OPTIONS"],allowHeaders:["Content-Type","Authorization","session-id"]})),daemonPort=port,daemonStartTime=Date.now();let gracefulShutdown=async signal=>{info(`Received ${signal}, initiating graceful shutdown...`);let closePromises=[];for(let session of sessions.values())closePromises.push(_closeSession(session));await Promise.allSettled(closePromises),info("All sessions closed, exiting..."),process.exit(0)};process.on("SIGTERM",()=>gracefulShutdown("SIGTERM")),process.on("SIGINT",()=>gracefulShutdown("SIGINT")),process.on("uncaughtException",err=>{error("Uncaught exception",err)}),process.on("unhandledRejection",reason=>{error("Unhandled rejection",reason)}),app.get("/health",ctx=>ctx.json({status:"ok"})),app.get("/info",ctx=>{let info2={version:require2("../package.json").version,uptime:Math.floor((Date.now()-daemonStartTime)/1e3),sessionCount:sessions.size,port:daemonPort};return ctx.json(info2)}),app.get("/sessions",ctx=>{let sessionList=[];for(let session of sessions.values())sessionList.push(_getSessionInfo(session));return ctx.json({sessions:sessionList})}),app.get("/session",async ctx=>{let session=await _getSession(ctx);return session?ctx.json(_getSessionInfo(session)):ctx.json(ERRORS.sessionNotFound,404)}),app.post("/shutdown",async ctx=>{info("Shutdown request received, closing all sessions...");let closePromises=[];for(let session of sessions.values())closePromises.push(_closeSession(session));return await Promise.allSettled(closePromises),info("All sessions closed, shutting down daemon server..."),setTimeout(()=>{process.exit(0)},500),ctx.json({status:"shutting_down"},200)}),app.post("/call",async ctx=>{try{isDebugEnabled()&&await _logRequest(ctx);let session=await _getOrCreateSession(ctx);session.lastActiveAt=Date.now();let toolCallRequest=await ctx.req.json(),tool=toolMap[toolCallRequest.toolName];if(!tool)return ctx.json(ERRORS.toolNotFound,404);let toolInput;try{toolInput=z.object(tool.inputSchema()).parse(toolCallRequest.toolInput)}catch(err){let errorMessage=err.errors&&Array.isArray(err.errors)?err.errors.map(e=>`${e.path?.join(".")||"input"}: ${e.message}`).join("; "):"Invalid tool input";return ctx.json(_buildErrorResponse(400,`Invalid Tool Request: ${errorMessage}`),400)}try{let toolCallResponse={toolOutput:await session.toolExecutor.executeTool(tool,toolInput)};return ctx.json(toolCallResponse,200)}catch(err){let toolCallResponse={toolError:{code:err.code,message:err.message}};return ctx.json(toolCallResponse,500)}}catch(err){return error("Error occurred while handling tool call request",err),ctx.json(ERRORS.internalServerError,500)}}),app.delete("/session",async ctx=>{try{let session=await _getSession(ctx);return session?(await _closeSession(session),ctx.json({ok:!0},200)):ctx.json(ERRORS.sessionNotFound,404)}catch(err){return error("Error occurred while deleting session",err),ctx.json(ERRORS.internalServerError,500)}}),app.onError((err,ctx)=>(error("Unhandled error in request handler",err),ctx.json({error:{code:500,message:"Internal Server Error"}},500))),app.notFound(ctx=>ctx.json({error:"Not Found",status:404},404)),serve({fetch:app.fetch,port},()=>info(`Listening on port ${port}`)),_scheduleIdleSessionCheck()}var isMainModule=import.meta.url===`file://${process.argv[1]}`||import.meta.url===`file://${process.argv[1]}.mjs`||process.argv[1]?.endsWith("daemon-server.js")||process.argv[1]?.endsWith("daemon-server.mjs");if(isMainModule){let parsePort=function(value){let n=Number(value);if(!Number.isInteger(n)||n<1||n>65535)throw new InvalidOptionArgumentError("port must be an integer between 1 and 65535");return n};parsePort2=parsePort;let options=new Command().addOption(new Option("--port <number>","port for daemon HTTP server").argParser(parsePort).default(DAEMON_PORT)).allowUnknownOption().parse(process.argv).opts();enable(),info("Starting daemon HTTP server..."),startDaemonHTTPServer(options.port).then(()=>{info("Daemon HTTP server started")}).catch(err=>{error("Failed to start daemon HTTP server",err),process.exit(1)})}var parsePort2;export{startDaemonHTTPServer};
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{platformInfo}from"./core-
|
|
2
|
+
import{platformInfo}from"./core-GIHDFCBF.js";import{AVAILABLE_TOOL_DOMAINS,PORT,SESSION_CLOSE_ON_SOCKET_CLOSE,SESSION_IDLE_CHECK_SECONDS,SESSION_IDLE_SECONDS,TOOL_OUTPUT_SCHEMA_DISABLE,debug,disable,enable,error,info,isDebugEnabled}from"./core-247YVH6X.js";import{createRequire}from"node:module";var require2=createRequire(import.meta.url),SERVER_NAME="browser-devtools-mcp",SERVER_VERSION=require2("../package.json").version;function getServerInstructions(){let parts=[];return parts.push(platformInfo.serverInfo.instructions),parts.join(`
|
|
3
3
|
|
|
4
|
-
`).trim()}function getServerPolicies(){return platformInfo.serverInfo.policies}import crypto from"node:crypto";import{StreamableHTTPTransport}from"@hono/mcp";import{serve}from"@hono/node-server";import{McpServer}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport}from"@modelcontextprotocol/sdk/server/stdio.js";import{Hono}from"hono";import{cors}from"hono/cors";var MCP_TEMPLATE={jsonrpc:"2.0",error:{code:0,message:"N/A"},id:null},MCP_ERRORS={get sessionNotFound(){return _buildMCPErrorResponse(-32001,"Session Not Found")},get unauthorized(){return _buildMCPErrorResponse(-32001,"Unauthorized")},get internalServerError(){return _buildMCPErrorResponse(-32603,"Internal Server Error")}},sessions=new Map;function _buildMCPErrorResponse(code,message){let result={...MCP_TEMPLATE};return result.error.code=code,result.error.message=message,result}function _getImage(response){if("image"in response&&response.image!==null&&typeof response.image=="object"&&"data"in response.image&&"mimeType"in response.image&&Buffer.isBuffer(response.image.data)&&typeof response.image.mimeType=="string"){let image=response.image;return delete response.image,image}}function _toResponse(response){let image=_getImage(response),contents=[];return contents.push({type:"text",text:JSON.stringify(response,null,2)}),image&&(image.mimeType==="image/svg+xml"?contents.push({type:"text",text:image.data.toString(),mimeType:image.mimeType}):contents.push({type:"image",data:image.data.toString("base64"),mimeType:image.mimeType})),{content:contents,structuredContent:response,isError:!1}}function _createServer(opts){let server=new McpServer({name:SERVER_NAME,version:SERVER_VERSION},{capabilities:{resources:{},tools:{}},instructions:getServerInstructions()}),messages=[],policies=getServerPolicies();if(policies)for(let policy of policies)messages.push({role:"user",content:{type:"text",text:policy}});server.registerPrompt("default_system",{title:"Default System Prompt",description:"General behavior for the AI assistant"},async()=>({description:"Defines the assistant's general reasoning and tool usage rules.",messages}));let toolExecutor=platformInfo.toolsInfo.createToolExecutor(()=>opts.sessionIdProvider?opts.sessionIdProvider():""),createToolCallback=tool=>async args=>{try{let response=await toolExecutor.executeTool(tool,args);return _toResponse(response)}catch(error2){return{content:[{type:"text",text:`Error: ${error2.message}`}],isError:!0}}},includeOutputSchema=!TOOL_OUTPUT_SCHEMA_DISABLE;return platformInfo.toolsInfo.tools.forEach(t=>{debug(`Registering tool ${t.name()} ...`);let toolOptions=includeOutputSchema?{description:t.description(),inputSchema:t.inputSchema(),outputSchema:t.outputSchema()}:{description:t.description(),inputSchema:t.inputSchema()};server.registerTool(t.name(),toolOptions,createToolCallback(t))}),server}async function _createAndConnectServer(transport,opts){let server=_createServer({config:opts.config,sessionIdProvider:()=>transport.sessionId});return await server.connect(transport),server}function _getConfig(){return{}}function _createSession(ctx,transport,server){let session={transport,server,closed:!1,lastActiveAt:Date.now()},socket=ctx.env.incoming.socket;return socket._mcpRegistered||(socket._mcpRegistered=!0,socket.on("close",async()=>{debug(`Socket, which is for MCP session with id ${transport.sessionId}, has been closed`),SESSION_CLOSE_ON_SOCKET_CLOSE&&await transport.close()})),_registerMCPSessionClose(transport,session.server),debug(`Created MCP server session with id ${transport.sessionId}`),session}async function _createTransport(ctx){let serverConfig=_getConfig(),holder={},transport=new StreamableHTTPTransport({enableJsonResponse:!0,sessionIdGenerator:()=>crypto.randomUUID(),onsessioninitialized:async sessionId=>{let session=_createSession(ctx,transport,holder.server);sessions.set(sessionId,session),debug(`MCP session initialized with id ${sessionId}`)},onsessionclosed:async sessionId=>{debug(`Closing MCP session closed with id ${sessionId} ...`),await transport.close(),debug(`MCP session closed with id ${sessionId}`)}});return holder.server=await _createAndConnectServer(transport,{config:serverConfig}),transport}async function _getTransport(ctx){let sessionId=ctx.req.header("mcp-session-id");if(sessionId){let session=sessions.get(sessionId);if(session)return debug(`Reusing MCP session with id ${sessionId}`),session.transport}}async function _getOrCreateTransport(ctx){let sessionId=ctx.req.header("mcp-session-id");if(sessionId){let session=sessions.get(sessionId);if(session)return debug(`Reusing MCP session with id ${sessionId}`),session.transport;debug(`No MCP session could be found with id ${sessionId}`);return}return await _createTransport(ctx)}function _registerMCPSessionClose(transport,mcpServer){let closed=!1;transport.onclose=async()=>{if(debug(`Closing MCP session with id ${transport.sessionId} ...`),closed){debug(`MCP session with id ${transport.sessionId} has already been closed`);return}closed=!0;try{await mcpServer.close(),debug("Closed MCP server")}catch(err){error("Error occurred while closing MCP server",err)}if(transport.sessionId){let session=sessions.get(transport.sessionId);if(session&&(session.closed=!0,session.context))try{await session.context.close(),debug("Closed MCP session context")}catch(err){error("Error occurred while closing MCP session context",err)}sessions.delete(transport.sessionId)}debug(`Closing MCP session with id ${transport.sessionId} ...`)}}function _scheduleIdleSessionCheck(){setInterval(()=>{let currentTime=Date.now();for(let[sessionId,session]of sessions)debug(`Checking whether session with id ${sessionId} is idle or not ...`),currentTime-session.lastActiveAt>SESSION_IDLE_SECONDS*1e3&&(debug(`Session with id ${sessionId} is idle, so it will be closing ...`),session.transport.close().then(()=>{debug(`Session with id ${sessionId} was idle, so it has been closed`)}).catch(err=>{error(`Unable to delete idle session with id ${sessionId}`,err)}))},SESSION_IDLE_CHECK_SECONDS*1e3)}async function _logRequest(ctx){let reqClone=ctx.req.raw.clone();debug(`Got request: ${await reqClone.json()}`)}function _markSessionAsActive(ctx){let sessionId=ctx.req.header("mcp-session-id");if(sessionId){let session=sessions.get(sessionId);session&&(session.lastActiveAt=Date.now())}}async function startStdioServer(){let transport=new StdioServerTransport;await _createAndConnectServer(transport,{config:_getConfig()})}var app=new Hono;async function startStreamableHTTPServer(port){app.use("*",cors({origin:"*",allowMethods:["GET","POST","OPTIONS"],allowHeaders:["Content-Type","Authorization","MCP-Protocol-Version"]})),app.get("/health",ctx=>ctx.json({status:"ok"})),app.get("/ping",ctx=>ctx.json({status:"ok",message:"pong"})),app.get("/mcp",ctx=>ctx.json({status:"ok",protocol:"model-context-protocol",version:"1.0"})),app.post("/mcp",async ctx=>{try{isDebugEnabled()&&await _logRequest(ctx);let transport=await _getOrCreateTransport(ctx);return transport?(_markSessionAsActive(ctx),await transport.handleRequest(ctx)):ctx.json(MCP_ERRORS.sessionNotFound,400)}catch(err){return error("Error occurred while handling MCP request",err),ctx.json(MCP_ERRORS.internalServerError,500)}}),app.delete("/mcp",async ctx=>{try{let transport=await _getTransport(ctx);return transport?(await transport.close(),ctx.json({ok:!0},200)):ctx.json(MCP_ERRORS.sessionNotFound,400)}catch(err){return error("Error occurred while deleting MCP session",err),ctx.json(MCP_ERRORS.internalServerError,500)}}),app.notFound(ctx=>ctx.json({error:"Not Found",status:404},404)),serve({fetch:app.fetch,port},()=>info(`Listening on port ${port}`)),_scheduleIdleSessionCheck()}import{Command,Option,InvalidOptionArgumentError}from"commander";function _parsePort(value){let n=Number(value);if(!Number.isInteger(n)||n<1||n>65535)throw new InvalidOptionArgumentError("port must be an integer between 1 and 65535");return n}function _getOptions(){return new Command().addOption(new Option("--transport <type>","transport type").choices(["stdio","streamable-http"]).default("stdio")).addOption(new Option("--port <number>","port for Streamable HTTP transport").argParser(_parsePort).default(PORT)).allowUnknownOption().parse(process.argv).opts()}async function main(){let options=_getOptions();options.transport==="stdio"?(disable(),await startStdioServer()):options.transport==="streamable-http"?(info("Starting MCP server..."),await startStreamableHTTPServer(options.port),info("Started MCP Server")):(error(`Invalid transport: ${options.transport}`),process.exit(1))}main().catch(err=>{enable(),error("MCP server error",err),process.exit(1)});
|
|
4
|
+
`).trim()}function getServerPolicies(){return platformInfo.serverInfo.policies}import crypto from"node:crypto";import{StreamableHTTPTransport}from"@hono/mcp";import{serve}from"@hono/node-server";import{McpServer}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport}from"@modelcontextprotocol/sdk/server/stdio.js";import{Hono}from"hono";import{cors}from"hono/cors";var MCP_TEMPLATE={jsonrpc:"2.0",error:{code:0,message:"N/A"},id:null},MCP_ERRORS={get sessionNotFound(){return _buildMCPErrorResponse(-32001,"Session Not Found")},get unauthorized(){return _buildMCPErrorResponse(-32001,"Unauthorized")},get internalServerError(){return _buildMCPErrorResponse(-32603,"Internal Server Error")}},sessions=new Map;function _buildMCPErrorResponse(code,message){let result={...MCP_TEMPLATE};return result.error.code=code,result.error.message=message,result}function _getImage(response){if("image"in response&&response.image!==null&&typeof response.image=="object"&&"data"in response.image&&"mimeType"in response.image&&Buffer.isBuffer(response.image.data)&&typeof response.image.mimeType=="string"){let image=response.image;return delete response.image,image}}function _toResponse(response){let image=_getImage(response),contents=[];return contents.push({type:"text",text:JSON.stringify(response,null,2)}),image&&(image.mimeType==="image/svg+xml"?contents.push({type:"text",text:image.data.toString(),mimeType:image.mimeType}):contents.push({type:"image",data:image.data.toString("base64"),mimeType:image.mimeType})),{content:contents,structuredContent:response,isError:!1}}function _createServer(opts){let server=new McpServer({name:SERVER_NAME,version:SERVER_VERSION},{capabilities:{resources:{},tools:{}},instructions:getServerInstructions()}),messages=[],policies=getServerPolicies();if(policies)for(let policy of policies)messages.push({role:"user",content:{type:"text",text:policy}});server.registerPrompt("default_system",{title:"Default System Prompt",description:"General behavior for the AI assistant"},async()=>({description:"Defines the assistant's general reasoning and tool usage rules.",messages}));let toolExecutor=platformInfo.toolsInfo.createToolExecutor(()=>opts.sessionIdProvider?opts.sessionIdProvider():""),createToolCallback=tool=>async args=>{try{let response=await toolExecutor.executeTool(tool,args);return _toResponse(response)}catch(error2){return{content:[{type:"text",text:`Error: ${error2.message}`}],isError:!0}}},includeOutputSchema=!TOOL_OUTPUT_SCHEMA_DISABLE,allowedDomains=AVAILABLE_TOOL_DOMAINS;return platformInfo.toolsInfo.tools.forEach(t=>{let domain=t.name().split("_")[0]?.toLowerCase()??"";if(allowedDomains&&!allowedDomains.has(domain)){debug(`Skipping tool ${t.name()} (domain ${domain} not in AVAILABLE_TOOL_DOMAINS)`);return}debug(`Registering tool ${t.name()} ...`);let toolOptions=includeOutputSchema?{description:t.description(),inputSchema:t.inputSchema(),outputSchema:t.outputSchema()}:{description:t.description(),inputSchema:t.inputSchema()};server.registerTool(t.name(),toolOptions,createToolCallback(t))}),server}async function _createAndConnectServer(transport,opts){let server=_createServer({config:opts.config,sessionIdProvider:()=>transport.sessionId});return await server.connect(transport),server}function _getConfig(){return{}}function _createSession(ctx,transport,server){let session={transport,server,closed:!1,lastActiveAt:Date.now()},socket=ctx.env.incoming.socket;return socket._mcpRegistered||(socket._mcpRegistered=!0,socket.on("close",async()=>{debug(`Socket, which is for MCP session with id ${transport.sessionId}, has been closed`),SESSION_CLOSE_ON_SOCKET_CLOSE&&await transport.close()})),_registerMCPSessionClose(transport,session.server),debug(`Created MCP server session with id ${transport.sessionId}`),session}async function _createTransport(ctx){let serverConfig=_getConfig(),holder={},transport=new StreamableHTTPTransport({enableJsonResponse:!0,sessionIdGenerator:()=>crypto.randomUUID(),onsessioninitialized:async sessionId=>{let session=_createSession(ctx,transport,holder.server);sessions.set(sessionId,session),debug(`MCP session initialized with id ${sessionId}`)},onsessionclosed:async sessionId=>{debug(`Closing MCP session closed with id ${sessionId} ...`),await transport.close(),debug(`MCP session closed with id ${sessionId}`)}});return holder.server=await _createAndConnectServer(transport,{config:serverConfig}),transport}async function _getTransport(ctx){let sessionId=ctx.req.header("mcp-session-id");if(sessionId){let session=sessions.get(sessionId);if(session)return debug(`Reusing MCP session with id ${sessionId}`),session.transport}}async function _getOrCreateTransport(ctx){let sessionId=ctx.req.header("mcp-session-id");if(sessionId){let session=sessions.get(sessionId);if(session)return debug(`Reusing MCP session with id ${sessionId}`),session.transport;debug(`No MCP session could be found with id ${sessionId}`);return}return await _createTransport(ctx)}function _registerMCPSessionClose(transport,mcpServer){let closed=!1;transport.onclose=async()=>{if(debug(`Closing MCP session with id ${transport.sessionId} ...`),closed){debug(`MCP session with id ${transport.sessionId} has already been closed`);return}closed=!0;try{await mcpServer.close(),debug("Closed MCP server")}catch(err){error("Error occurred while closing MCP server",err)}if(transport.sessionId){let session=sessions.get(transport.sessionId);if(session&&(session.closed=!0,session.context))try{await session.context.close(),debug("Closed MCP session context")}catch(err){error("Error occurred while closing MCP session context",err)}sessions.delete(transport.sessionId)}debug(`Closing MCP session with id ${transport.sessionId} ...`)}}function _scheduleIdleSessionCheck(){setInterval(()=>{let currentTime=Date.now();for(let[sessionId,session]of sessions)debug(`Checking whether session with id ${sessionId} is idle or not ...`),currentTime-session.lastActiveAt>SESSION_IDLE_SECONDS*1e3&&(debug(`Session with id ${sessionId} is idle, so it will be closing ...`),session.transport.close().then(()=>{debug(`Session with id ${sessionId} was idle, so it has been closed`)}).catch(err=>{error(`Unable to delete idle session with id ${sessionId}`,err)}))},SESSION_IDLE_CHECK_SECONDS*1e3)}async function _logRequest(ctx){let reqClone=ctx.req.raw.clone();debug(`Got request: ${await reqClone.json()}`)}function _markSessionAsActive(ctx){let sessionId=ctx.req.header("mcp-session-id");if(sessionId){let session=sessions.get(sessionId);session&&(session.lastActiveAt=Date.now())}}async function startStdioServer(){let transport=new StdioServerTransport;await _createAndConnectServer(transport,{config:_getConfig()})}var app=new Hono;async function startStreamableHTTPServer(port){app.use("*",cors({origin:"*",allowMethods:["GET","POST","OPTIONS"],allowHeaders:["Content-Type","Authorization","MCP-Protocol-Version"]})),app.get("/health",ctx=>ctx.json({status:"ok"})),app.get("/ping",ctx=>ctx.json({status:"ok",message:"pong"})),app.get("/mcp",ctx=>ctx.json({status:"ok",protocol:"model-context-protocol",version:"1.0"})),app.post("/mcp",async ctx=>{try{isDebugEnabled()&&await _logRequest(ctx);let transport=await _getOrCreateTransport(ctx);return transport?(_markSessionAsActive(ctx),await transport.handleRequest(ctx)):ctx.json(MCP_ERRORS.sessionNotFound,400)}catch(err){return error("Error occurred while handling MCP request",err),ctx.json(MCP_ERRORS.internalServerError,500)}}),app.delete("/mcp",async ctx=>{try{let transport=await _getTransport(ctx);return transport?(await transport.close(),ctx.json({ok:!0},200)):ctx.json(MCP_ERRORS.sessionNotFound,400)}catch(err){return error("Error occurred while deleting MCP session",err),ctx.json(MCP_ERRORS.internalServerError,500)}}),app.notFound(ctx=>ctx.json({error:"Not Found",status:404},404)),serve({fetch:app.fetch,port},()=>info(`Listening on port ${port}`)),_scheduleIdleSessionCheck()}import{Command,Option,InvalidOptionArgumentError}from"commander";function _parsePort(value){let n=Number(value);if(!Number.isInteger(n)||n<1||n>65535)throw new InvalidOptionArgumentError("port must be an integer between 1 and 65535");return n}function _getOptions(){return new Command().addOption(new Option("--transport <type>","transport type").choices(["stdio","streamable-http"]).default("stdio")).addOption(new Option("--port <number>","port for Streamable HTTP transport").argParser(_parsePort).default(PORT)).allowUnknownOption().parse(process.argv).opts()}async function main(){let options=_getOptions();options.transport==="stdio"?(disable(),await startStdioServer()):options.transport==="streamable-http"?(info("Starting MCP server..."),await startStreamableHTTPServer(options.port),info("Started MCP Server")):(error(`Invalid transport: ${options.transport}`),process.exit(1))}main().catch(err=>{enable(),error("MCP server error",err),process.exit(1)});
|