@narumitw/pi-chrome-devtools 0.53.3 → 0.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -11
- package/dist/chunks/{browser-settings-menu-SR7KLZT6.js → browser-settings-menu-GQAXLWZ7.ts} +25 -3
- package/dist/chunks/browser-settings-menu-GQAXLWZ7.ts.map +7 -0
- package/dist/chunks/{chunk-4KMN4SFF.js → chunk-5T2WEIYN.ts} +2 -2
- package/dist/chunks/{chunk-F5VG35UI.js → chunk-TVVYQ5KM.ts} +55 -7
- package/dist/chunks/chunk-TVVYQ5KM.ts.map +7 -0
- package/dist/chunks/{chunk-MZCGM6D3.js → chunk-WOFI2A72.ts} +337 -88
- package/dist/chunks/chunk-WOFI2A72.ts.map +7 -0
- package/dist/chunks/{menu-YR4VRT7D.js → menu-Z26D6XSI.ts} +7 -7
- package/dist/chunks/{menu-YR4VRT7D.js.map → menu-Z26D6XSI.ts.map} +1 -1
- package/dist/chunks/{tools-6R7Z6HWJ.js → tools-DSYQPFF3.ts} +3 -3
- package/dist/index.ts +45 -21
- package/dist/index.ts.map +2 -2
- package/package.json +3 -3
- package/src/browser-settings-menu.ts +23 -0
- package/src/chrome-devtools.ts +48 -15
- package/src/lazy-tools.ts +350 -26
- package/src/menu.ts +3 -3
- package/src/settings.ts +65 -1
- package/src/tool-selector.ts +95 -40
- package/dist/chunks/browser-settings-menu-SR7KLZT6.js.map +0 -7
- package/dist/chunks/chunk-F5VG35UI.js.map +0 -7
- package/dist/chunks/chunk-MZCGM6D3.js.map +0 -7
- /package/dist/chunks/{chunk-4KMN4SFF.js.map → chunk-5T2WEIYN.ts.map} +0 -0
- /package/dist/chunks/{tools-6R7Z6HWJ.js.map → tools-DSYQPFF3.ts.map} +0 -0
package/dist/index.ts.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/tools.ts", "../src/render.ts", "../src/screenshot.ts", "../src/chrome-devtools.ts"],
|
|
4
|
-
"sourcesContent": ["import { defineTool } from \"@earendil-works/pi-coding-agent\";\nimport { Type } from \"typebox\";\nimport {\n formatPage,\n getPage,\n listPages,\n resolvePage,\n resolvePageForNavigation,\n setActivePageId,\n textResult,\n withCdp,\n} from \"./cdp-client.js\";\nimport { renderScreenshotResult, renderTextResult, renderToolCall, withStatus } from \"./render.js\";\nimport { formatScreenshotText, saveScreenshot, throwIfAborted } from \"./screenshot.js\";\nimport { CHROME_DEVTOOLS_TOOL_NAMES, WEBMCP_TOOL_NAMES } from \"./tool-names.js\";\n\nexport const listPagesTool = defineTool({\n name: CHROME_DEVTOOLS_TOOL_NAMES[0],\n label: \"Chrome DevTools: List Pages\",\n description: \"List Chrome tabs/pages from a running Chrome DevTools Protocol endpoint.\",\n parameters: Type.Object({}),\n renderCall: renderToolCall(\"list pages\"),\n renderResult: renderTextResult,\n async execute(_toolCallId, _params, signal, _onUpdate, ctx) {\n return withStatus(ctx, \"list pages\", async () => {\n const pages = await listPages({ sessionOwner: ctx.sessionManager, signal });\n return textResult(JSON.stringify(pages.map(formatPage), null, 2), { pages });\n });\n },\n});\n\nexport const selectPageTool = defineTool({\n name: CHROME_DEVTOOLS_TOOL_NAMES[1],\n label: \"Chrome DevTools: Select Page\",\n description: \"Select the active Chrome page for later chrome_devtools_* tool calls.\",\n parameters: Type.Object({\n pageId: Type.String({ description: \"Page id from chrome_devtools_list_pages.\" }),\n }),\n renderCall: renderToolCall(\"select page\"),\n renderResult: renderTextResult,\n async execute(_toolCallId, params, signal, _onUpdate, ctx) {\n return withStatus(ctx, \"select page\", async () => {\n const page = await getPage(params.pageId, { sessionOwner: ctx.sessionManager, signal });\n setActivePageId(ctx.sessionManager, page.id);\n return textResult(`Selected page ${page.id}: ${page.title}\\n${page.url}`, {\n page: formatPage(page),\n });\n });\n },\n});\n\nexport const navigateTool = defineTool({\n name: CHROME_DEVTOOLS_TOOL_NAMES[2],\n label: \"Chrome DevTools: Navigate\",\n description:\n \"Navigate a Chrome page to a URL through Chrome DevTools Protocol, creating a page first if none is available.\",\n parameters: Type.Object({\n url: Type.String({ description: \"URL to navigate to.\" }),\n pageId: Type.Optional(Type.String({ description: \"Optional page id. Defaults to selected or first page.\" })),\n }),\n renderCall: renderToolCall(\"navigate\"),\n renderResult: renderTextResult,\n async execute(_toolCallId, params, signal, _onUpdate, ctx) {\n return withStatus(ctx, \"navigate\", async () => {\n const { created, page } = await resolvePageForNavigation(params.pageId, {\n sessionOwner: ctx.sessionManager,\n signal,\n });\n const result = await withCdp(page, async (client) => {\n await client.send(\"Page.enable\");\n return client.send(\"Page.navigate\", { url: params.url });\n });\n\n setActivePageId(ctx.sessionManager, page.id);\n const action = created ? \"Created page and navigated\" : \"Navigated\";\n return textResult(`${action} ${page.id} to ${params.url}`, {\n created,\n page: formatPage(page),\n result,\n });\n });\n },\n});\n\nexport const evaluateTool = defineTool({\n name: CHROME_DEVTOOLS_TOOL_NAMES[3],\n label: \"Chrome DevTools: Evaluate\",\n description: \"Evaluate JavaScript in a Chrome page through Chrome DevTools Protocol.\",\n parameters: Type.Object({\n expression: Type.String({ description: \"JavaScript expression to evaluate.\" }),\n pageId: Type.Optional(Type.String({ description: \"Optional page id. Defaults to selected or first page.\" })),\n awaitPromise: Type.Optional(\n Type.Boolean({ description: \"Whether to await a returned Promise. Defaults to true.\" }),\n ),\n }),\n renderCall: renderToolCall(\"evaluate\"),\n renderResult: renderTextResult,\n async execute(_toolCallId, params, signal, _onUpdate, ctx) {\n return withStatus(ctx, \"evaluate\", async () => {\n const page = await resolvePage(params.pageId, {\n sessionOwner: ctx.sessionManager,\n signal,\n });\n const result = await withCdp(page, (client) =>\n client.send(\"Runtime.evaluate\", {\n expression: params.expression,\n awaitPromise: params.awaitPromise ?? true,\n returnByValue: true,\n }),\n );\n\n setActivePageId(ctx.sessionManager, page.id);\n return textResult(JSON.stringify(result, null, 2), { page: formatPage(page), result });\n });\n },\n});\n\nexport const webMcpListToolsTool = defineTool({\n name: WEBMCP_TOOL_NAMES[0],\n label: \"Chrome DevTools: List WebMCP Tools (Experimental)\",\n description:\n \"List bounded page-provided WebMCP tool descriptors from the selected Chrome page through the experimental CDP WebMCP domain. Definitions remain in this tool result and are never registered as dynamic Pi tools.\",\n parameters: Type.Object({\n pageId: Type.Optional(\n Type.String({\n description: \"Optional page id. Defaults to selected or first page.\",\n maxLength: 512,\n }),\n ),\n }),\n renderCall: renderToolCall(\"list WebMCP tools\"),\n renderResult: renderTextResult,\n async execute(_toolCallId, params, signal, _onUpdate, ctx) {\n return withStatus(ctx, \"list WebMCP tools\", async () => {\n const implementation = await import(\"./webmcp/tools.js\");\n return implementation.executeWebMcpListTool(params, signal, ctx);\n });\n },\n});\n\nexport const webMcpCallTool = defineTool({\n name: WEBMCP_TOOL_NAMES[1],\n label: \"Chrome DevTools: Call WebMCP Tool (Experimental)\",\n description:\n \"Call one previously listed page-provided WebMCP tool after exact page, document, frame, origin, schema, annotation, and session revalidation. Every call requires observable user confirmation and output is bounded to Pi's 50 KB or 2,000-line limit.\",\n parameters: Type.Object({\n sessionGeneration: Type.String({\n description: \"Session generation token returned by chrome_devtools_webmcp_list_tools.\",\n maxLength: 100,\n }),\n pageId: Type.String({ description: \"Page id returned by the list tool.\", maxLength: 512 }),\n documentId: Type.String({\n description: \"Document loader id returned by the list tool.\",\n maxLength: 512,\n }),\n frameId: Type.String({ description: \"Frame id returned by the list tool.\", maxLength: 512 }),\n frameOrigin: Type.String({\n description: \"Exact frame origin returned by the list tool.\",\n maxLength: 2_048,\n }),\n toolName: Type.String({\n description: \"Exact tool name returned by the list tool.\",\n maxLength: 512,\n }),\n schemaDigest: Type.String({\n description: \"Schema and annotation digest returned by the list tool.\",\n minLength: 64,\n maxLength: 64,\n pattern: \"^[a-f0-9]{64}$\",\n }),\n input: Type.Record(Type.String(), Type.Unknown(), {\n description: \"JSON object matching the page-provided input schema.\",\n }),\n }),\n renderCall: renderToolCall(\"call WebMCP tool\"),\n renderResult: renderTextResult,\n async execute(_toolCallId, params, signal, _onUpdate, ctx) {\n return withStatus(ctx, \"call WebMCP tool\", async () => {\n const implementation = await import(\"./webmcp/tools.js\");\n return implementation.executeWebMcpCallTool(params, signal, ctx);\n });\n },\n});\n\nexport const screenshotTool = defineTool({\n name: CHROME_DEVTOOLS_TOOL_NAMES[4],\n label: \"Chrome DevTools: Screenshot\",\n description: \"Capture a PNG screenshot from a Chrome page through Chrome DevTools Protocol.\",\n parameters: Type.Object({\n pageId: Type.Optional(Type.String({ description: \"Optional page id. Defaults to selected or first page.\" })),\n fullPage: Type.Optional(Type.Boolean({ description: \"Capture the full document, not just the viewport.\" })),\n savePath: Type.Optional(\n Type.String({\n description:\n \"Screenshot is always saved as a PNG file. Optional output path; omitted defaults to a unique temp file. Relative paths resolve from the current working directory. A single leading @ is stripped to match Pi file-mention paths. Existing regular files are replaced.\",\n }),\n ),\n }),\n renderCall: renderToolCall(\"screenshot\"),\n renderResult: renderScreenshotResult,\n async execute(_toolCallId, params, signal, _onUpdate, ctx) {\n return withStatus(ctx, \"screenshot\", async () => {\n const page = await resolvePage(params.pageId, {\n sessionOwner: ctx.sessionManager,\n signal,\n });\n const result = await withCdp(page, async (client) => {\n throwIfAborted(signal);\n await client.send(\"Page.enable\");\n\n if (!params.fullPage) {\n return client.send<{ data: string }>(\"Page.captureScreenshot\", { format: \"png\" });\n }\n\n const metrics = await client.send<{\n contentSize: { x: number; y: number; width: number; height: number };\n }>(\"Page.getLayoutMetrics\");\n\n throwIfAborted(signal);\n return client.send<{ data: string }>(\"Page.captureScreenshot\", {\n captureBeyondViewport: true,\n format: \"png\",\n clip: {\n x: metrics.contentSize.x,\n y: metrics.contentSize.y,\n width: metrics.contentSize.width,\n height: metrics.contentSize.height,\n scale: 1,\n },\n });\n });\n\n setActivePageId(ctx.sessionManager, page.id);\n const savedScreenshot = await saveScreenshot(result.data, params.savePath, ctx.cwd, signal);\n return {\n content: [\n {\n type: \"text\",\n text: formatScreenshotText(page, savedScreenshot),\n },\n { type: \"image\", data: result.data, mimeType: \"image/png\" },\n ],\n details: {\n page: formatPage(page),\n bytes: savedScreenshot.bytes,\n savedPath: savedScreenshot.savedPath,\n isDefaultPath: savedScreenshot.isDefaultPath,\n },\n };\n });\n },\n});\n", "import type { AgentToolResult, ToolRenderResultOptions } from \"@earendil-works/pi-coding-agent\";\nimport { truncateToWidth } from \"@earendil-works/pi-tui\";\nimport { sanitizeChromeDevtoolsDisplay } from \"./display.js\";\n\nconst STATUS_KEY = \"chrome-devtools\";\ninterface StatusContext {\n sessionManager: object;\n ui: { setStatus: (key: string, value: string | undefined) => void };\n}\ninterface RenderTheme {\n bold(text: string): string;\n fg(color: string, text: string): string;\n}\nconst activeStatuses = new WeakMap<object, Array<{ status: string; token: symbol }>>();\n\ninterface RenderComponent {\n invalidate(): void;\n render(width: number): string[];\n}\n\nexport function renderToolCall(action: string) {\n return () => new PiTextComponent(`Chrome DevTools: ${action}`);\n}\n\nexport function renderTextResult(\n result: AgentToolResult<unknown>,\n options: ToolRenderResultOptions,\n theme: RenderTheme,\n) {\n const output = formatCollapsibleOutput(textContent(result), options);\n return new PiTextComponent(output.text, theme, output.color);\n}\n\nexport function renderScreenshotResult(\n result: AgentToolResult<unknown>,\n options: ToolRenderResultOptions,\n theme: RenderTheme,\n): RenderComponent {\n const output = formatCollapsibleOutput(screenshotTextContent(result), options);\n return new PiTextComponent(output.text, theme, output.color);\n}\n\nfunction textContent(result: AgentToolResult<unknown>) {\n return result.content.flatMap((content) => (content.type === \"text\" ? [content.text] : [])).join(\"\\n\");\n}\n\nfunction screenshotTextContent(result: AgentToolResult<unknown>) {\n const text = textContent(result);\n if (text.trim()) return text;\n\n const details = result.details as { savedPath?: unknown; bytes?: unknown } | undefined;\n if (typeof details?.savedPath !== \"string\") return text;\n const bytes = typeof details.bytes === \"number\" ? ` (${details.bytes} bytes)` : \"\";\n return `Saved screenshot to ${details.savedPath}${bytes}`;\n}\n\nfunction formatCollapsibleOutput(text: string, options: ToolRenderResultOptions): { text: string; color?: string } {\n if (options.isPartial) return { text: \"Running...\", color: \"warning\" };\n if (options.expanded) return { text, color: \"toolOutput\" };\n\n return { text: \"\" };\n}\n\nclass PiTextComponent implements RenderComponent {\n private text: string;\n private readonly theme?: RenderTheme;\n private readonly color?: string;\n\n constructor(text = \"\", theme?: RenderTheme, color?: string) {\n this.text = text;\n this.theme = theme;\n this.color = color;\n }\n\n setText(text: string) {\n this.text = text;\n }\n\n invalidate() {\n // Stateless renderer: no cached layout to invalidate.\n }\n\n render(width: number) {\n const sanitizedText = sanitizeChromeDevtoolsDisplay(this.text);\n if (!sanitizedText.trim()) return [];\n return sanitizedText\n .replace(/\\t/g, \" \")\n .split(/\\r?\\n/)\n .map((line) => {\n const truncatedLine = truncateToWidth(line, Math.max(0, width), \"\");\n return this.theme && this.color ? this.theme.fg(this.color, truncatedLine) : truncatedLine;\n });\n }\n}\n\nexport async function withStatus<T>(ctx: StatusContext, status: string, callback: () => Promise<T>) {\n const token = Symbol(status);\n const statuses = activeStatuses.get(ctx.sessionManager) ?? [];\n statuses.push({ status, token });\n activeStatuses.set(ctx.sessionManager, statuses);\n ctx.ui.setStatus(STATUS_KEY, status);\n try {\n return await callback();\n } finally {\n const index = statuses.findIndex((entry) => entry.token === token);\n if (index >= 0) statuses.splice(index, 1);\n const remaining = statuses.at(-1)?.status;\n if (statuses.length === 0) activeStatuses.delete(ctx.sessionManager);\n ctx.ui.setStatus(STATUS_KEY, remaining);\n }\n}\n", "import { randomUUID } from \"node:crypto\";\nimport { lstat, mkdir, realpath, rename, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { basename, dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport { withFileMutationQueue } from \"@earendil-works/pi-coding-agent\";\nimport type { DevToolsPage } from \"./runtime.js\";\n\nfunction unique<T>(values: T[]) {\n return Array.from(new Set(values));\n}\n\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error;\n}\n\nexport interface ResolvedScreenshotPath {\n path: string;\n allowedRoots: string[];\n isDefault: boolean;\n}\nexport interface ScreenshotSaveResult {\n savedPath: string;\n bytes: number;\n isDefaultPath: boolean;\n}\n\nexport async function saveScreenshot(\n base64Png: string,\n savePath: string | undefined,\n cwd: string,\n signal: AbortSignal | undefined,\n): Promise<ScreenshotSaveResult> {\n const resolvedPath = resolveScreenshotPath(savePath, cwd);\n const pngBytes = Buffer.from(base64Png, \"base64\");\n\n await withFileMutationQueue(resolvedPath.path, async () => {\n throwIfAborted(signal);\n await ensureSafeScreenshotParent(resolvedPath);\n await assertSafeScreenshotTargetPath(resolvedPath);\n await writeScreenshotFileSafely(resolvedPath, pngBytes, signal);\n });\n\n return {\n savedPath: resolvedPath.path,\n bytes: pngBytes.byteLength,\n isDefaultPath: resolvedPath.isDefault,\n };\n}\n\nexport function resolveScreenshotPath(savePath: string | undefined, cwd: string): ResolvedScreenshotPath {\n const cwdRoot = resolve(cwd);\n const tempRoot = resolve(tmpdir());\n\n if (savePath === undefined) {\n return {\n path: join(tempRoot, `pi-chrome-devtools-screenshot-${randomUUID()}.png`),\n allowedRoots: [tempRoot],\n isDefault: true,\n };\n }\n\n const normalizedPath = stripLeadingAtPath(savePath);\n if (!normalizedPath.trim()) {\n throw new Error(\"Screenshot savePath must not be empty.\");\n }\n if (normalizedPath.includes(\"\\0\")) {\n throw new Error(\"Screenshot savePath must not contain NUL bytes.\");\n }\n if (hasParentPathSegment(normalizedPath)) {\n throw new Error(\"Screenshot savePath must not contain '..' path segments.\");\n }\n\n const isAbsolutePath = isAbsolute(normalizedPath);\n const path = isAbsolutePath ? resolve(normalizedPath) : resolve(cwdRoot, normalizedPath);\n const allowedRoots = isAbsolutePath ? unique([cwdRoot, tempRoot]) : [cwdRoot];\n if (!allowedRoots.some((root) => isPathInsideRoot(path, root))) {\n throw new Error(\n \"Screenshot savePath must be relative to the current working directory, or an absolute path inside the current working directory or OS temp directory.\",\n );\n }\n\n return { path, allowedRoots, isDefault: false };\n}\n\nfunction stripLeadingAtPath(path: string) {\n return path.startsWith(\"@\") ? path.slice(1) : path;\n}\n\nexport function hasParentPathSegment(path: string) {\n return path.split(/[\\\\/]+/).some((part) => part === \"..\");\n}\n\nasync function ensureSafeScreenshotParent(resolvedPath: ResolvedScreenshotPath) {\n const parentPath = dirname(resolvedPath.path);\n const rootPath = selectAllowedRoot(parentPath, resolvedPath.allowedRoots);\n if (!rootPath) {\n throw new Error(\"Screenshot savePath parent must stay inside the current working directory or OS temp directory.\");\n }\n\n const realRootPath = await realpath(rootPath);\n let currentPath = rootPath;\n const parentSegments = relative(rootPath, parentPath)\n .split(/[\\\\/]+/)\n .filter((part) => part.length > 0);\n\n for (const segment of parentSegments) {\n currentPath = join(currentPath, segment);\n await ensureSafeDirectorySegment(currentPath, realRootPath);\n }\n}\n\nexport function selectAllowedRoot(path: string, roots: readonly string[]) {\n const matchingRoots = roots.filter((root) => isPathInsideRoot(path, root));\n matchingRoots.sort(\n (left, right) =>\n normalizePathForComparison(resolve(right)).length - normalizePathForComparison(resolve(left)).length,\n );\n return matchingRoots[0];\n}\n\nasync function ensureSafeDirectorySegment(path: string, realRootPath: string) {\n const existingDirectory = await lstat(path).catch(async (error: unknown) => {\n if (!isNodeError(error) || error.code !== \"ENOENT\") throw error;\n await mkdir(path).catch((mkdirError: unknown) => {\n if (!isNodeError(mkdirError) || mkdirError.code !== \"EEXIST\") throw mkdirError;\n });\n return lstat(path);\n });\n\n if (existingDirectory.isSymbolicLink()) {\n throw new Error(\"Screenshot savePath parent directories must not contain symbolic links.\");\n }\n if (!existingDirectory.isDirectory()) {\n throw new Error(\"Screenshot savePath parent must be a directory.\");\n }\n await assertPathWithinRealRoot(path, realRootPath);\n}\n\nasync function assertSafeScreenshotTargetPath(resolvedPath: ResolvedScreenshotPath) {\n const existingTarget = await lstat(resolvedPath.path).catch((error: unknown) => {\n if (isNodeError(error) && error.code === \"ENOENT\") return undefined;\n throw error;\n });\n if (existingTarget?.isSymbolicLink()) {\n throw new Error(\"Screenshot savePath must not point to a symbolic link.\");\n }\n if (existingTarget?.isDirectory()) {\n throw new Error(\"Screenshot savePath must point to a file, not a directory.\");\n }\n if (existingTarget && !existingTarget.isFile()) {\n throw new Error(\"Screenshot savePath may only replace regular files.\");\n }\n\n const realAllowedRoots = await Promise.all(resolvedPath.allowedRoots.map(realpathOrResolvedPath));\n const realParent = await realpath(dirname(resolvedPath.path));\n const realTargetPath = join(realParent, basename(resolvedPath.path));\n if (!realAllowedRoots.some((root) => isPathInsideRoot(realTargetPath, root))) {\n throw new Error(\"Screenshot savePath resolves outside the current working directory or OS temp directory.\");\n }\n}\n\nasync function assertPathWithinRealRoot(path: string, realRootPath: string) {\n const realPath = await realpath(path);\n if (!isPathInsideRoot(realPath, realRootPath)) {\n throw new Error(\"Screenshot savePath parent resolves outside the current working directory or OS temp directory.\");\n }\n}\n\nasync function writeScreenshotFileSafely(\n resolvedPath: ResolvedScreenshotPath,\n pngBytes: Buffer,\n signal: AbortSignal | undefined,\n) {\n const tempFile = join(\n dirname(resolvedPath.path),\n `.${basename(resolvedPath.path)}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`,\n );\n try {\n await writeFile(tempFile, pngBytes, { flag: \"wx\", signal });\n throwIfAborted(signal);\n await replaceScreenshotFile(resolvedPath, tempFile, signal);\n } catch (error) {\n await rm(tempFile, { force: true }).catch(() => undefined);\n throw error;\n }\n}\n\nasync function replaceScreenshotFile(\n resolvedPath: ResolvedScreenshotPath,\n tempFile: string,\n signal: AbortSignal | undefined,\n) {\n try {\n await rename(tempFile, resolvedPath.path);\n return;\n } catch (error) {\n if (!shouldRetryRenameAfterRemovingDestination(error)) throw error;\n }\n\n // Some Windows filesystems reject renaming over an existing file. Revalidate before\n // removing the destination so the fallback still refuses directories and symlinks.\n await assertSafeScreenshotTargetPath(resolvedPath);\n throwIfAborted(signal);\n await rm(resolvedPath.path, { force: true });\n await rename(tempFile, resolvedPath.path);\n}\n\nfunction shouldRetryRenameAfterRemovingDestination(error: unknown) {\n return process.platform === \"win32\" && isNodeError(error) && [\"EACCES\", \"EEXIST\", \"EPERM\"].includes(error.code ?? \"\");\n}\n\nasync function realpathOrResolvedPath(path: string) {\n return realpath(path).catch(() => resolve(path));\n}\n\nexport function isPathInsideRoot(path: string, root: string) {\n const normalizedPath = normalizePathForComparison(resolve(path));\n const normalizedRoot = normalizePathForComparison(resolve(root));\n if (normalizedPath === normalizedRoot) return true;\n const rootWithSeparator = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;\n return normalizedPath.startsWith(rootWithSeparator);\n}\n\nfunction normalizePathForComparison(path: string) {\n return process.platform === \"win32\" ? path.toLowerCase() : path;\n}\n\nexport function throwIfAborted(signal: AbortSignal | undefined) {\n if (!signal?.aborted) return;\n throw signal.reason instanceof Error ? signal.reason : new Error(\"Screenshot capture cancelled.\");\n}\n\nexport function formatScreenshotText(page: DevToolsPage, screenshot: ScreenshotSaveResult) {\n const pathLabel = screenshot.isDefaultPath ? \"Saved to temp file\" : \"Saved to\";\n return [\n `Captured PNG screenshot from ${page.title || page.url || page.id}.`,\n `${pathLabel}: ${screenshot.savedPath}`,\n `Bytes: ${screenshot.bytes}`,\n `Use read({ path: ${JSON.stringify(screenshot.savedPath)} }) to inspect the saved screenshot if inline image content is not available.`,\n ].join(\"\\n\");\n}\n", "import type { ExtensionAPI, ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { shutdownManagedBrowser, startManagedBrowserSession, syncManagedBrowserSettings } from \"./browser-manager.js\";\nimport { setActivePageId } from \"./cdp-client.js\";\nimport {\n availableChromeDevtoolsTools,\n configureChromeDevtoolsToolExposure,\n createChromeDevtoolsLoadTool,\n initializeAvailableChromeDevtoolsTools,\n requireEagerChromeDevtoolsToolExposure,\n setChromeDevtoolsSessionOwner,\n supportsNativeDeferredToolLoading,\n} from \"./lazy-tools.js\";\nimport {\n applyRuntimeBrowserSettings,\n applyRuntimeWebMcpSetting,\n invalidateWebMcpOperations,\n setWebMcpSessionOwner,\n state,\n webMcpEnabled,\n} from \"./runtime.js\";\nimport { loadSettings, waitForSettingsWrites } from \"./settings.js\";\nimport {\n allChromeDevtoolsTools,\n buildCommandGuide,\n buildQuickstartMessage,\n buildToolStatusMessage,\n sanitizeChromeDevtoolsDisplay,\n updateChromeDevtoolsTools,\n waitForChromeDevtoolsSettings,\n} from \"./tool-selector.js\";\nimport {\n evaluateTool,\n listPagesTool,\n navigateTool,\n screenshotTool,\n selectPageTool,\n webMcpCallTool,\n webMcpListToolsTool,\n} from \"./tools.js\";\n\ntype CommandAction = \"menu\" | \"help\" | \"quickstart\" | \"status\" | \"settings\" | \"tools\" | \"enable\" | \"disable\";\ntype CommandContext = ExtensionCommandContext;\nconst STATUS_KEY = \"chrome-devtools\";\nconst COMMAND_COMPLETIONS = [\n { value: \"help\", label: \"help\", description: \"Show command usage\" },\n { value: \"quickstart\", label: \"quickstart\", description: \"Show endpoint and launch help\" },\n { value: \"status\", label: \"status\", description: \"Show tool and settings status\" },\n { value: \"settings\", label: \"settings\", description: \"Edit browser connection settings\" },\n { value: \"tools\", label: \"tools\", description: \"Choose available Chrome DevTools tools\" },\n { value: \"toggle\", label: \"toggle\", description: \"Alias for tools\" },\n { value: \"select\", label: \"select\", description: \"Compatibility alias for tools\" },\n { value: \"enable\", label: \"enable\", description: \"Make all Chrome DevTools tools available\" },\n { value: \"on\", label: \"on\", description: \"Compatibility alias for enable\" },\n { value: \"disable\", label: \"disable\", description: \"Make all Chrome DevTools tools unavailable\" },\n { value: \"off\", label: \"off\", description: \"Compatibility alias for disable\" },\n];\nexport default function chromeDevtools(pi: ExtensionAPI) {\n pi.registerTool(listPagesTool);\n pi.registerTool(selectPageTool);\n pi.registerTool(navigateTool);\n pi.registerTool(evaluateTool);\n pi.registerTool(screenshotTool);\n pi.registerTool(webMcpListToolsTool);\n pi.registerTool(webMcpCallTool);\n pi.registerTool(createChromeDevtoolsLoadTool(pi));\n\n pi.registerCommand(\"chrome-devtools\", {\n description: \"Open Chrome DevTools help and tool controls\",\n getArgumentCompletions: (prefix) => commandCompletions(prefix),\n handler: async (args, ctx) => {\n setChromeDevtoolsSessionOwner(pi, ctx.sessionManager);\n initializeAvailableChromeDevtoolsTools(pi);\n const generation = state.sessionGeneration;\n await handleChromeDevtoolsCommand(pi, args, ctx, generation);\n },\n });\n\n pi.on(\"session_start\", async (_event, ctx) => {\n const generation = ++state.sessionGeneration;\n setChromeDevtoolsSessionOwner(pi, ctx.sessionManager);\n initializeAvailableChromeDevtoolsTools(pi);\n setWebMcpSessionOwner(ctx.sessionManager);\n replaceSessionController(\"Chrome DevTools session replaced\");\n invalidateWebMcpOperations(ctx.sessionManager, \"Chrome DevTools session replaced\");\n state.shuttingDown = false;\n state.settingsNotice = undefined;\n ctx.ui.setStatus(STATUS_KEY, undefined);\n await shutdownManagedBrowser(undefined, {\n cancelLaunch: true,\n owner: ctx.sessionManager,\n });\n startManagedBrowserSession(ctx.sessionManager);\n if (generation !== state.sessionGeneration) return;\n setActivePageId(ctx.sessionManager, undefined);\n state.activePageId = undefined;\n state.lastLaunchAttempt = undefined;\n const projectTrusted = ctx.isProjectTrusted();\n const settings = await loadSettings({ cwd: ctx.cwd, projectTrusted });\n if (generation !== state.sessionGeneration) return;\n applyRuntimeBrowserSettings(settings.effectiveBrowser, settings.paths, projectTrusted);\n syncManagedBrowserSettings(ctx.sessionManager, settings.effectiveBrowser);\n applyRuntimeWebMcpSetting(settings.effectiveWebMcpEnabled, ctx.sessionManager);\n state.settingsNotice = settings.notice;\n for (const warning of settings.warnings) {\n ctx.ui.notify(sanitizeChromeDevtoolsDisplay(warning), \"warning\");\n }\n if (webMcpEnabled(ctx.sessionManager)) {\n ctx.ui.notify(\n \"Experimental WebMCP is enabled. Page-provided tools use the visible browser session and require confirmation for every call.\",\n \"warning\",\n );\n }\n const availableTools =\n settings.kind === \"loaded\" && settings.settings.tools\n ? settings.settings.tools\n : availableChromeDevtoolsTools(pi);\n configureChromeDevtoolsToolExposure(pi, availableTools, ctx.model);\n });\n\n pi.on(\"model_select\", (event, ctx) => {\n invalidateWebMcpOperations(ctx.sessionManager, \"Chrome DevTools model and tool exposure changed\");\n if (!supportsNativeDeferredToolLoading(event.model)) {\n requireEagerChromeDevtoolsToolExposure(pi);\n }\n });\n\n pi.on(\"session_shutdown\", async (_event, ctx) => {\n state.sessionGeneration += 1;\n replaceSessionController(\"Chrome DevTools session shut down\");\n invalidateWebMcpOperations(ctx.sessionManager, \"Chrome DevTools session shut down\");\n ctx.ui.setStatus(STATUS_KEY, undefined);\n const browserShutdown = shutdownManagedBrowser(undefined, {\n cancelLaunch: true,\n owner: ctx.sessionManager,\n });\n await waitForChromeDevtoolsSettings();\n await waitForSettingsWrites();\n await browserShutdown;\n });\n}\n\nasync function handleChromeDevtoolsCommand(pi: ExtensionAPI, args: string, ctx: CommandContext, generation: number) {\n const command = parseCommand(args);\n switch (command) {\n case \"menu\":\n await showMenu(pi, ctx, generation);\n return;\n case \"help\":\n requireObservableUi(ctx, \"help\");\n ctx.ui.notify(buildCommandGuide(ctx.sessionManager), \"info\");\n return;\n case \"quickstart\":\n requireObservableUi(ctx, \"quickstart\");\n ctx.ui.notify(buildQuickstartMessage(ctx.sessionManager), \"info\");\n return;\n case \"status\": {\n requireObservableUi(ctx, \"status\");\n const status = await buildToolStatusMessage(pi, ctx.sessionManager);\n if (generation !== state.sessionGeneration) return;\n ctx.ui.notify(status, \"info\");\n return;\n }\n case \"settings\": {\n if (!ctx.hasUI || (ctx.mode !== \"tui\" && ctx.mode !== \"rpc\")) {\n throw new Error(\"/chrome-devtools settings requires TUI or RPC mode\");\n }\n const { showChromeDevtoolsBrowserSettings } = await import(\"./browser-settings-menu.js\");\n if (generation !== state.sessionGeneration) return;\n await showChromeDevtoolsBrowserSettings(pi, ctx, generation);\n return;\n }\n case \"tools\": {\n if (!ctx.hasUI || (ctx.mode !== \"tui\" && ctx.mode !== \"rpc\")) {\n throw new Error(\"/chrome-devtools tools requires TUI or RPC mode\");\n }\n const { showChromeDevtoolsToolWorkflow } = await import(\"./menu.js\");\n if (generation !== state.sessionGeneration) return;\n await showChromeDevtoolsToolWorkflow(pi, ctx, generation);\n return;\n }\n case \"enable\":\n await updateChromeDevtoolsTools(pi, ctx, allChromeDevtoolsTools(ctx.sessionManager), \"made all available\");\n return;\n case \"disable\":\n await updateChromeDevtoolsTools(pi, ctx, [], \"made all unavailable\");\n return;\n }\n\n if (!ctx.hasUI || (ctx.mode !== \"tui\" && ctx.mode !== \"rpc\")) {\n throw new Error(`Unknown /chrome-devtools command: ${args.trim()}`);\n }\n ctx.ui.notify(\n `Unknown /chrome-devtools command: ${args.trim()}\n\n${buildCommandGuide(ctx.sessionManager)}`,\n \"warning\",\n );\n}\n\nfunction requireObservableUi(ctx: CommandContext, route: string) {\n if (!ctx.hasUI || (ctx.mode !== \"tui\" && ctx.mode !== \"rpc\")) {\n throw new Error(`/chrome-devtools ${route} requires TUI or RPC mode`);\n }\n}\n\nasync function showMenu(pi: ExtensionAPI, ctx: CommandContext, generation: number) {\n if (!ctx.hasUI || (ctx.mode !== \"tui\" && ctx.mode !== \"rpc\")) {\n throw new Error(\"/chrome-devtools menu requires TUI or RPC mode; use a direct subcommand\");\n }\n const { showChromeDevtoolsMenu } = await import(\"./menu.js\");\n if (generation !== state.sessionGeneration) return;\n await showChromeDevtoolsMenu(pi, ctx, generation);\n}\n\nfunction replaceSessionController(reason: string) {\n state.sessionController.abort(new DOMException(reason, \"AbortError\"));\n state.sessionController = new AbortController();\n}\n\nexport function parseCommand(args: string): CommandAction | \"unknown\" {\n const command = args.trim().toLowerCase();\n if (!command) return \"menu\";\n if (command === \"help\") return \"help\";\n if (command === \"quickstart\") return \"quickstart\";\n if (command === \"status\") return \"status\";\n if (command === \"settings\") return \"settings\";\n if (command === \"tools\" || command === \"select\" || command === \"toggle\") return \"tools\";\n if (command === \"enable\" || command === \"on\") return \"enable\";\n if (command === \"disable\" || command === \"off\") return \"disable\";\n return \"unknown\";\n}\n\nexport function commandCompletions(prefix: string) {\n const normalized = prefix.trimStart().toLowerCase();\n if (/\\s/.test(normalized)) return null;\n\n const matches = COMMAND_COMPLETIONS.filter((completion) => completion.value.startsWith(normalized));\n return matches.length > 0 ? matches : null;\n}\n\nexport {\n formatHostForUrl,\n isLocalDevToolsHost,\n quoteCommandPart,\n} from \"./browser-manager.js\";\nexport { CHROME_DEVTOOLS_LOAD_TOOL_NAME } from \"./lazy-tools.js\";\nexport { parseConfiguredPort } from \"./runtime.js\";\nexport {\n hasParentPathSegment,\n isPathInsideRoot,\n resolveScreenshotPath,\n selectAllowedRoot,\n} from \"./screenshot.js\";\nexport { normalizeChromeDevtoolsSettings } from \"./settings.js\";\nexport {\n orderedChromeDevtoolsTools,\n sanitizeChromeDevtoolsDisplay,\n} from \"./tool-selector.js\";\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { defineTool } from \"@earendil-works/pi-coding-agent\";\nimport { Type } from \"typebox\";\nimport {\n formatPage,\n getPage,\n listPages,\n resolvePage,\n resolvePageForNavigation,\n setActivePageId,\n textResult,\n withCdp,\n} from \"./cdp-client.js\";\nimport { renderScreenshotResult, renderTextResult, renderToolCall, withStatus } from \"./render.js\";\nimport { formatScreenshotText, saveScreenshot, throwIfAborted } from \"./screenshot.js\";\nimport { CHROME_DEVTOOLS_TOOL_NAMES, WEBMCP_TOOL_NAMES } from \"./tool-names.js\";\n\nexport const listPagesTool = defineTool({\n name: CHROME_DEVTOOLS_TOOL_NAMES[0],\n label: \"Chrome DevTools: List Pages\",\n description: \"List Chrome tabs/pages from a running Chrome DevTools Protocol endpoint.\",\n parameters: Type.Object({}),\n renderCall: renderToolCall(\"list pages\"),\n renderResult: renderTextResult,\n async execute(_toolCallId, _params, signal, _onUpdate, ctx) {\n return withStatus(ctx, \"list pages\", async () => {\n const pages = await listPages({ sessionOwner: ctx.sessionManager, signal });\n return textResult(JSON.stringify(pages.map(formatPage), null, 2), { pages });\n });\n },\n});\n\nexport const selectPageTool = defineTool({\n name: CHROME_DEVTOOLS_TOOL_NAMES[1],\n label: \"Chrome DevTools: Select Page\",\n description: \"Select the active Chrome page for later chrome_devtools_* tool calls.\",\n parameters: Type.Object({\n pageId: Type.String({ description: \"Page id from chrome_devtools_list_pages.\" }),\n }),\n renderCall: renderToolCall(\"select page\"),\n renderResult: renderTextResult,\n async execute(_toolCallId, params, signal, _onUpdate, ctx) {\n return withStatus(ctx, \"select page\", async () => {\n const page = await getPage(params.pageId, { sessionOwner: ctx.sessionManager, signal });\n setActivePageId(ctx.sessionManager, page.id);\n return textResult(`Selected page ${page.id}: ${page.title}\\n${page.url}`, {\n page: formatPage(page),\n });\n });\n },\n});\n\nexport const navigateTool = defineTool({\n name: CHROME_DEVTOOLS_TOOL_NAMES[2],\n label: \"Chrome DevTools: Navigate\",\n description:\n \"Navigate a Chrome page to a URL through Chrome DevTools Protocol, creating a page first if none is available.\",\n parameters: Type.Object({\n url: Type.String({ description: \"URL to navigate to.\" }),\n pageId: Type.Optional(Type.String({ description: \"Optional page id. Defaults to selected or first page.\" })),\n }),\n renderCall: renderToolCall(\"navigate\"),\n renderResult: renderTextResult,\n async execute(_toolCallId, params, signal, _onUpdate, ctx) {\n return withStatus(ctx, \"navigate\", async () => {\n const { created, page } = await resolvePageForNavigation(params.pageId, {\n sessionOwner: ctx.sessionManager,\n signal,\n });\n const result = await withCdp(page, async (client) => {\n await client.send(\"Page.enable\");\n return client.send(\"Page.navigate\", { url: params.url });\n });\n\n setActivePageId(ctx.sessionManager, page.id);\n const action = created ? \"Created page and navigated\" : \"Navigated\";\n return textResult(`${action} ${page.id} to ${params.url}`, {\n created,\n page: formatPage(page),\n result,\n });\n });\n },\n});\n\nexport const evaluateTool = defineTool({\n name: CHROME_DEVTOOLS_TOOL_NAMES[3],\n label: \"Chrome DevTools: Evaluate\",\n description: \"Evaluate JavaScript in a Chrome page through Chrome DevTools Protocol.\",\n parameters: Type.Object({\n expression: Type.String({ description: \"JavaScript expression to evaluate.\" }),\n pageId: Type.Optional(Type.String({ description: \"Optional page id. Defaults to selected or first page.\" })),\n awaitPromise: Type.Optional(\n Type.Boolean({ description: \"Whether to await a returned Promise. Defaults to true.\" }),\n ),\n }),\n renderCall: renderToolCall(\"evaluate\"),\n renderResult: renderTextResult,\n async execute(_toolCallId, params, signal, _onUpdate, ctx) {\n return withStatus(ctx, \"evaluate\", async () => {\n const page = await resolvePage(params.pageId, {\n sessionOwner: ctx.sessionManager,\n signal,\n });\n const result = await withCdp(page, (client) =>\n client.send(\"Runtime.evaluate\", {\n expression: params.expression,\n awaitPromise: params.awaitPromise ?? true,\n returnByValue: true,\n }),\n );\n\n setActivePageId(ctx.sessionManager, page.id);\n return textResult(JSON.stringify(result, null, 2), { page: formatPage(page), result });\n });\n },\n});\n\nexport const webMcpListToolsTool = defineTool({\n name: WEBMCP_TOOL_NAMES[0],\n label: \"Chrome DevTools: List WebMCP Tools (Experimental)\",\n description:\n \"List bounded page-provided WebMCP tool descriptors from the selected Chrome page through the experimental CDP WebMCP domain. Definitions remain in this tool result and are never registered as dynamic Pi tools.\",\n parameters: Type.Object({\n pageId: Type.Optional(\n Type.String({\n description: \"Optional page id. Defaults to selected or first page.\",\n maxLength: 512,\n }),\n ),\n }),\n renderCall: renderToolCall(\"list WebMCP tools\"),\n renderResult: renderTextResult,\n async execute(_toolCallId, params, signal, _onUpdate, ctx) {\n return withStatus(ctx, \"list WebMCP tools\", async () => {\n const implementation = await import(\"./webmcp/tools.js\");\n return implementation.executeWebMcpListTool(params, signal, ctx);\n });\n },\n});\n\nexport const webMcpCallTool = defineTool({\n name: WEBMCP_TOOL_NAMES[1],\n label: \"Chrome DevTools: Call WebMCP Tool (Experimental)\",\n description:\n \"Call one previously listed page-provided WebMCP tool after exact page, document, frame, origin, schema, annotation, and session revalidation. Every call requires observable user confirmation and output is bounded to Pi's 50 KB or 2,000-line limit.\",\n parameters: Type.Object({\n sessionGeneration: Type.String({\n description: \"Session generation token returned by chrome_devtools_webmcp_list_tools.\",\n maxLength: 100,\n }),\n pageId: Type.String({ description: \"Page id returned by the list tool.\", maxLength: 512 }),\n documentId: Type.String({\n description: \"Document loader id returned by the list tool.\",\n maxLength: 512,\n }),\n frameId: Type.String({ description: \"Frame id returned by the list tool.\", maxLength: 512 }),\n frameOrigin: Type.String({\n description: \"Exact frame origin returned by the list tool.\",\n maxLength: 2_048,\n }),\n toolName: Type.String({\n description: \"Exact tool name returned by the list tool.\",\n maxLength: 512,\n }),\n schemaDigest: Type.String({\n description: \"Schema and annotation digest returned by the list tool.\",\n minLength: 64,\n maxLength: 64,\n pattern: \"^[a-f0-9]{64}$\",\n }),\n input: Type.Record(Type.String(), Type.Unknown(), {\n description: \"JSON object matching the page-provided input schema.\",\n }),\n }),\n renderCall: renderToolCall(\"call WebMCP tool\"),\n renderResult: renderTextResult,\n async execute(_toolCallId, params, signal, _onUpdate, ctx) {\n return withStatus(ctx, \"call WebMCP tool\", async () => {\n const implementation = await import(\"./webmcp/tools.js\");\n return implementation.executeWebMcpCallTool(params, signal, ctx);\n });\n },\n});\n\nexport const screenshotTool = defineTool({\n name: CHROME_DEVTOOLS_TOOL_NAMES[4],\n label: \"Chrome DevTools: Screenshot\",\n description: \"Capture a PNG screenshot from a Chrome page through Chrome DevTools Protocol.\",\n parameters: Type.Object({\n pageId: Type.Optional(Type.String({ description: \"Optional page id. Defaults to selected or first page.\" })),\n fullPage: Type.Optional(Type.Boolean({ description: \"Capture the full document, not just the viewport.\" })),\n savePath: Type.Optional(\n Type.String({\n description:\n \"Screenshot is always saved as a PNG file. Optional output path; omitted defaults to a unique temp file. Relative paths resolve from the current working directory. A single leading @ is stripped to match Pi file-mention paths. Existing regular files are replaced.\",\n }),\n ),\n }),\n renderCall: renderToolCall(\"screenshot\"),\n renderResult: renderScreenshotResult,\n async execute(_toolCallId, params, signal, _onUpdate, ctx) {\n return withStatus(ctx, \"screenshot\", async () => {\n const page = await resolvePage(params.pageId, {\n sessionOwner: ctx.sessionManager,\n signal,\n });\n const result = await withCdp(page, async (client) => {\n throwIfAborted(signal);\n await client.send(\"Page.enable\");\n\n if (!params.fullPage) {\n return client.send<{ data: string }>(\"Page.captureScreenshot\", { format: \"png\" });\n }\n\n const metrics = await client.send<{\n contentSize: { x: number; y: number; width: number; height: number };\n }>(\"Page.getLayoutMetrics\");\n\n throwIfAborted(signal);\n return client.send<{ data: string }>(\"Page.captureScreenshot\", {\n captureBeyondViewport: true,\n format: \"png\",\n clip: {\n x: metrics.contentSize.x,\n y: metrics.contentSize.y,\n width: metrics.contentSize.width,\n height: metrics.contentSize.height,\n scale: 1,\n },\n });\n });\n\n setActivePageId(ctx.sessionManager, page.id);\n const savedScreenshot = await saveScreenshot(result.data, params.savePath, ctx.cwd, signal);\n return {\n content: [\n {\n type: \"text\",\n text: formatScreenshotText(page, savedScreenshot),\n },\n { type: \"image\", data: result.data, mimeType: \"image/png\" },\n ],\n details: {\n page: formatPage(page),\n bytes: savedScreenshot.bytes,\n savedPath: savedScreenshot.savedPath,\n isDefaultPath: savedScreenshot.isDefaultPath,\n },\n };\n });\n },\n});\n", "import type { AgentToolResult, ToolRenderResultOptions } from \"@earendil-works/pi-coding-agent\";\nimport { truncateToWidth } from \"@earendil-works/pi-tui\";\nimport { sanitizeChromeDevtoolsDisplay } from \"./display.js\";\n\nconst STATUS_KEY = \"chrome-devtools\";\ninterface StatusContext {\n sessionManager: object;\n ui: { setStatus: (key: string, value: string | undefined) => void };\n}\ninterface RenderTheme {\n bold(text: string): string;\n fg(color: string, text: string): string;\n}\nconst activeStatuses = new WeakMap<object, Array<{ status: string; token: symbol }>>();\n\ninterface RenderComponent {\n invalidate(): void;\n render(width: number): string[];\n}\n\nexport function renderToolCall(action: string) {\n return () => new PiTextComponent(`Chrome DevTools: ${action}`);\n}\n\nexport function renderTextResult(\n result: AgentToolResult<unknown>,\n options: ToolRenderResultOptions,\n theme: RenderTheme,\n) {\n const output = formatCollapsibleOutput(textContent(result), options);\n return new PiTextComponent(output.text, theme, output.color);\n}\n\nexport function renderScreenshotResult(\n result: AgentToolResult<unknown>,\n options: ToolRenderResultOptions,\n theme: RenderTheme,\n): RenderComponent {\n const output = formatCollapsibleOutput(screenshotTextContent(result), options);\n return new PiTextComponent(output.text, theme, output.color);\n}\n\nfunction textContent(result: AgentToolResult<unknown>) {\n return result.content.flatMap((content) => (content.type === \"text\" ? [content.text] : [])).join(\"\\n\");\n}\n\nfunction screenshotTextContent(result: AgentToolResult<unknown>) {\n const text = textContent(result);\n if (text.trim()) return text;\n\n const details = result.details as { savedPath?: unknown; bytes?: unknown } | undefined;\n if (typeof details?.savedPath !== \"string\") return text;\n const bytes = typeof details.bytes === \"number\" ? ` (${details.bytes} bytes)` : \"\";\n return `Saved screenshot to ${details.savedPath}${bytes}`;\n}\n\nfunction formatCollapsibleOutput(text: string, options: ToolRenderResultOptions): { text: string; color?: string } {\n if (options.isPartial) return { text: \"Running...\", color: \"warning\" };\n if (options.expanded) return { text, color: \"toolOutput\" };\n\n return { text: \"\" };\n}\n\nclass PiTextComponent implements RenderComponent {\n private text: string;\n private readonly theme?: RenderTheme;\n private readonly color?: string;\n\n constructor(text = \"\", theme?: RenderTheme, color?: string) {\n this.text = text;\n this.theme = theme;\n this.color = color;\n }\n\n setText(text: string) {\n this.text = text;\n }\n\n invalidate() {\n // Stateless renderer: no cached layout to invalidate.\n }\n\n render(width: number) {\n const sanitizedText = sanitizeChromeDevtoolsDisplay(this.text);\n if (!sanitizedText.trim()) return [];\n return sanitizedText\n .replace(/\\t/g, \" \")\n .split(/\\r?\\n/)\n .map((line) => {\n const truncatedLine = truncateToWidth(line, Math.max(0, width), \"\");\n return this.theme && this.color ? this.theme.fg(this.color, truncatedLine) : truncatedLine;\n });\n }\n}\n\nexport async function withStatus<T>(ctx: StatusContext, status: string, callback: () => Promise<T>) {\n const token = Symbol(status);\n const statuses = activeStatuses.get(ctx.sessionManager) ?? [];\n statuses.push({ status, token });\n activeStatuses.set(ctx.sessionManager, statuses);\n ctx.ui.setStatus(STATUS_KEY, status);\n try {\n return await callback();\n } finally {\n const index = statuses.findIndex((entry) => entry.token === token);\n if (index >= 0) statuses.splice(index, 1);\n const remaining = statuses.at(-1)?.status;\n if (statuses.length === 0) activeStatuses.delete(ctx.sessionManager);\n ctx.ui.setStatus(STATUS_KEY, remaining);\n }\n}\n", "import { randomUUID } from \"node:crypto\";\nimport { lstat, mkdir, realpath, rename, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { basename, dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport { withFileMutationQueue } from \"@earendil-works/pi-coding-agent\";\nimport type { DevToolsPage } from \"./runtime.js\";\n\nfunction unique<T>(values: T[]) {\n return Array.from(new Set(values));\n}\n\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error;\n}\n\nexport interface ResolvedScreenshotPath {\n path: string;\n allowedRoots: string[];\n isDefault: boolean;\n}\nexport interface ScreenshotSaveResult {\n savedPath: string;\n bytes: number;\n isDefaultPath: boolean;\n}\n\nexport async function saveScreenshot(\n base64Png: string,\n savePath: string | undefined,\n cwd: string,\n signal: AbortSignal | undefined,\n): Promise<ScreenshotSaveResult> {\n const resolvedPath = resolveScreenshotPath(savePath, cwd);\n const pngBytes = Buffer.from(base64Png, \"base64\");\n\n await withFileMutationQueue(resolvedPath.path, async () => {\n throwIfAborted(signal);\n await ensureSafeScreenshotParent(resolvedPath);\n await assertSafeScreenshotTargetPath(resolvedPath);\n await writeScreenshotFileSafely(resolvedPath, pngBytes, signal);\n });\n\n return {\n savedPath: resolvedPath.path,\n bytes: pngBytes.byteLength,\n isDefaultPath: resolvedPath.isDefault,\n };\n}\n\nexport function resolveScreenshotPath(savePath: string | undefined, cwd: string): ResolvedScreenshotPath {\n const cwdRoot = resolve(cwd);\n const tempRoot = resolve(tmpdir());\n\n if (savePath === undefined) {\n return {\n path: join(tempRoot, `pi-chrome-devtools-screenshot-${randomUUID()}.png`),\n allowedRoots: [tempRoot],\n isDefault: true,\n };\n }\n\n const normalizedPath = stripLeadingAtPath(savePath);\n if (!normalizedPath.trim()) {\n throw new Error(\"Screenshot savePath must not be empty.\");\n }\n if (normalizedPath.includes(\"\\0\")) {\n throw new Error(\"Screenshot savePath must not contain NUL bytes.\");\n }\n if (hasParentPathSegment(normalizedPath)) {\n throw new Error(\"Screenshot savePath must not contain '..' path segments.\");\n }\n\n const isAbsolutePath = isAbsolute(normalizedPath);\n const path = isAbsolutePath ? resolve(normalizedPath) : resolve(cwdRoot, normalizedPath);\n const allowedRoots = isAbsolutePath ? unique([cwdRoot, tempRoot]) : [cwdRoot];\n if (!allowedRoots.some((root) => isPathInsideRoot(path, root))) {\n throw new Error(\n \"Screenshot savePath must be relative to the current working directory, or an absolute path inside the current working directory or OS temp directory.\",\n );\n }\n\n return { path, allowedRoots, isDefault: false };\n}\n\nfunction stripLeadingAtPath(path: string) {\n return path.startsWith(\"@\") ? path.slice(1) : path;\n}\n\nexport function hasParentPathSegment(path: string) {\n return path.split(/[\\\\/]+/).some((part) => part === \"..\");\n}\n\nasync function ensureSafeScreenshotParent(resolvedPath: ResolvedScreenshotPath) {\n const parentPath = dirname(resolvedPath.path);\n const rootPath = selectAllowedRoot(parentPath, resolvedPath.allowedRoots);\n if (!rootPath) {\n throw new Error(\"Screenshot savePath parent must stay inside the current working directory or OS temp directory.\");\n }\n\n const realRootPath = await realpath(rootPath);\n let currentPath = rootPath;\n const parentSegments = relative(rootPath, parentPath)\n .split(/[\\\\/]+/)\n .filter((part) => part.length > 0);\n\n for (const segment of parentSegments) {\n currentPath = join(currentPath, segment);\n await ensureSafeDirectorySegment(currentPath, realRootPath);\n }\n}\n\nexport function selectAllowedRoot(path: string, roots: readonly string[]) {\n const matchingRoots = roots.filter((root) => isPathInsideRoot(path, root));\n matchingRoots.sort(\n (left, right) =>\n normalizePathForComparison(resolve(right)).length - normalizePathForComparison(resolve(left)).length,\n );\n return matchingRoots[0];\n}\n\nasync function ensureSafeDirectorySegment(path: string, realRootPath: string) {\n const existingDirectory = await lstat(path).catch(async (error: unknown) => {\n if (!isNodeError(error) || error.code !== \"ENOENT\") throw error;\n await mkdir(path).catch((mkdirError: unknown) => {\n if (!isNodeError(mkdirError) || mkdirError.code !== \"EEXIST\") throw mkdirError;\n });\n return lstat(path);\n });\n\n if (existingDirectory.isSymbolicLink()) {\n throw new Error(\"Screenshot savePath parent directories must not contain symbolic links.\");\n }\n if (!existingDirectory.isDirectory()) {\n throw new Error(\"Screenshot savePath parent must be a directory.\");\n }\n await assertPathWithinRealRoot(path, realRootPath);\n}\n\nasync function assertSafeScreenshotTargetPath(resolvedPath: ResolvedScreenshotPath) {\n const existingTarget = await lstat(resolvedPath.path).catch((error: unknown) => {\n if (isNodeError(error) && error.code === \"ENOENT\") return undefined;\n throw error;\n });\n if (existingTarget?.isSymbolicLink()) {\n throw new Error(\"Screenshot savePath must not point to a symbolic link.\");\n }\n if (existingTarget?.isDirectory()) {\n throw new Error(\"Screenshot savePath must point to a file, not a directory.\");\n }\n if (existingTarget && !existingTarget.isFile()) {\n throw new Error(\"Screenshot savePath may only replace regular files.\");\n }\n\n const realAllowedRoots = await Promise.all(resolvedPath.allowedRoots.map(realpathOrResolvedPath));\n const realParent = await realpath(dirname(resolvedPath.path));\n const realTargetPath = join(realParent, basename(resolvedPath.path));\n if (!realAllowedRoots.some((root) => isPathInsideRoot(realTargetPath, root))) {\n throw new Error(\"Screenshot savePath resolves outside the current working directory or OS temp directory.\");\n }\n}\n\nasync function assertPathWithinRealRoot(path: string, realRootPath: string) {\n const realPath = await realpath(path);\n if (!isPathInsideRoot(realPath, realRootPath)) {\n throw new Error(\"Screenshot savePath parent resolves outside the current working directory or OS temp directory.\");\n }\n}\n\nasync function writeScreenshotFileSafely(\n resolvedPath: ResolvedScreenshotPath,\n pngBytes: Buffer,\n signal: AbortSignal | undefined,\n) {\n const tempFile = join(\n dirname(resolvedPath.path),\n `.${basename(resolvedPath.path)}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`,\n );\n try {\n await writeFile(tempFile, pngBytes, { flag: \"wx\", signal });\n throwIfAborted(signal);\n await replaceScreenshotFile(resolvedPath, tempFile, signal);\n } catch (error) {\n await rm(tempFile, { force: true }).catch(() => undefined);\n throw error;\n }\n}\n\nasync function replaceScreenshotFile(\n resolvedPath: ResolvedScreenshotPath,\n tempFile: string,\n signal: AbortSignal | undefined,\n) {\n try {\n await rename(tempFile, resolvedPath.path);\n return;\n } catch (error) {\n if (!shouldRetryRenameAfterRemovingDestination(error)) throw error;\n }\n\n // Some Windows filesystems reject renaming over an existing file. Revalidate before\n // removing the destination so the fallback still refuses directories and symlinks.\n await assertSafeScreenshotTargetPath(resolvedPath);\n throwIfAborted(signal);\n await rm(resolvedPath.path, { force: true });\n await rename(tempFile, resolvedPath.path);\n}\n\nfunction shouldRetryRenameAfterRemovingDestination(error: unknown) {\n return process.platform === \"win32\" && isNodeError(error) && [\"EACCES\", \"EEXIST\", \"EPERM\"].includes(error.code ?? \"\");\n}\n\nasync function realpathOrResolvedPath(path: string) {\n return realpath(path).catch(() => resolve(path));\n}\n\nexport function isPathInsideRoot(path: string, root: string) {\n const normalizedPath = normalizePathForComparison(resolve(path));\n const normalizedRoot = normalizePathForComparison(resolve(root));\n if (normalizedPath === normalizedRoot) return true;\n const rootWithSeparator = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;\n return normalizedPath.startsWith(rootWithSeparator);\n}\n\nfunction normalizePathForComparison(path: string) {\n return process.platform === \"win32\" ? path.toLowerCase() : path;\n}\n\nexport function throwIfAborted(signal: AbortSignal | undefined) {\n if (!signal?.aborted) return;\n throw signal.reason instanceof Error ? signal.reason : new Error(\"Screenshot capture cancelled.\");\n}\n\nexport function formatScreenshotText(page: DevToolsPage, screenshot: ScreenshotSaveResult) {\n const pathLabel = screenshot.isDefaultPath ? \"Saved to temp file\" : \"Saved to\";\n return [\n `Captured PNG screenshot from ${page.title || page.url || page.id}.`,\n `${pathLabel}: ${screenshot.savedPath}`,\n `Bytes: ${screenshot.bytes}`,\n `Use read({ path: ${JSON.stringify(screenshot.savedPath)} }) to inspect the saved screenshot if inline image content is not available.`,\n ].join(\"\\n\");\n}\n", "import type { ExtensionAPI, ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { shutdownManagedBrowser, startManagedBrowserSession, syncManagedBrowserSettings } from \"./browser-manager.js\";\nimport { setActivePageId } from \"./cdp-client.js\";\nimport {\n availableChromeDevtoolsTools,\n chromeDevtoolsToolMode,\n configureChromeDevtoolsToolExposure,\n initializeAvailableChromeDevtoolsTools,\n previousChromeDevtoolsTools,\n registerChromeDevtoolsCapabilities,\n requireEagerChromeDevtoolsToolExposure,\n setChromeDevtoolsSessionOwner,\n supportsNativeDeferredToolLoading,\n} from \"./lazy-tools.js\";\nimport {\n applyRuntimeBrowserSettings,\n applyRuntimeWebMcpSetting,\n invalidateWebMcpOperations,\n setWebMcpSessionOwner,\n state,\n webMcpEnabled,\n} from \"./runtime.js\";\nimport { loadSettings, waitForSettingsWrites } from \"./settings.js\";\nimport {\n allChromeDevtoolsTools,\n buildCommandGuide,\n buildQuickstartMessage,\n buildToolStatusMessage,\n sanitizeChromeDevtoolsDisplay,\n updateChromeDevtoolsTools,\n waitForChromeDevtoolsSettings,\n} from \"./tool-selector.js\";\nimport {\n evaluateTool,\n listPagesTool,\n navigateTool,\n screenshotTool,\n selectPageTool,\n webMcpCallTool,\n webMcpListToolsTool,\n} from \"./tools.js\";\n\ntype CommandAction = \"menu\" | \"help\" | \"quickstart\" | \"status\" | \"settings\" | \"tools\" | \"enable\" | \"disable\";\ntype CommandContext = ExtensionCommandContext;\nconst STATUS_KEY = \"chrome-devtools\";\nconst COMMAND_COMPLETIONS = [\n { value: \"help\", label: \"help\", description: \"Show command usage\" },\n { value: \"quickstart\", label: \"quickstart\", description: \"Show endpoint and launch help\" },\n { value: \"status\", label: \"status\", description: \"Show tool and settings status\" },\n { value: \"settings\", label: \"settings\", description: \"Edit browser connection settings\" },\n { value: \"tools\", label: \"tools\", description: \"Choose available Chrome DevTools tools\" },\n { value: \"toggle\", label: \"toggle\", description: \"Alias for tools\" },\n { value: \"select\", label: \"select\", description: \"Compatibility alias for tools\" },\n { value: \"enable\", label: \"enable\", description: \"Make all Chrome DevTools tools available\" },\n { value: \"on\", label: \"on\", description: \"Compatibility alias for enable\" },\n { value: \"disable\", label: \"disable\", description: \"Make all Chrome DevTools tools unavailable\" },\n { value: \"off\", label: \"off\", description: \"Compatibility alias for disable\" },\n];\nexport default function chromeDevtools(pi: ExtensionAPI) {\n registerChromeDevtoolsCapabilities(pi, [\n listPagesTool,\n selectPageTool,\n navigateTool,\n evaluateTool,\n screenshotTool,\n webMcpListToolsTool,\n webMcpCallTool,\n ]);\n\n pi.registerCommand(\"chrome-devtools\", {\n description: \"Open Chrome DevTools help and tool controls\",\n getArgumentCompletions: (prefix) => commandCompletions(prefix),\n handler: async (args, ctx) => {\n setChromeDevtoolsSessionOwner(pi, ctx.sessionManager);\n initializeAvailableChromeDevtoolsTools(pi);\n const generation = state.sessionGeneration;\n await handleChromeDevtoolsCommand(pi, args, ctx, generation);\n },\n });\n\n pi.on(\"session_start\", async (_event, ctx) => {\n const generation = ++state.sessionGeneration;\n setChromeDevtoolsSessionOwner(pi, ctx.sessionManager, ctx.sessionManager.getBranch());\n // Capture before default initialization: unknown invalid files must not\n // broaden availability, while a restored/current policy survives reload.\n const previousAvailableTools = previousChromeDevtoolsTools(pi);\n const previousMode = chromeDevtoolsToolMode(pi);\n initializeAvailableChromeDevtoolsTools(pi);\n setWebMcpSessionOwner(ctx.sessionManager);\n replaceSessionController(\"Chrome DevTools session replaced\");\n invalidateWebMcpOperations(ctx.sessionManager, \"Chrome DevTools session replaced\");\n state.shuttingDown = false;\n state.settingsNotice = undefined;\n ctx.ui.setStatus(STATUS_KEY, undefined);\n await shutdownManagedBrowser(undefined, {\n cancelLaunch: true,\n owner: ctx.sessionManager,\n });\n startManagedBrowserSession(ctx.sessionManager);\n if (generation !== state.sessionGeneration) return;\n setActivePageId(ctx.sessionManager, undefined);\n state.activePageId = undefined;\n state.lastLaunchAttempt = undefined;\n const projectTrusted = ctx.isProjectTrusted();\n await waitForChromeDevtoolsSettings();\n if (generation !== state.sessionGeneration) return;\n const settings = await loadSettings({ cwd: ctx.cwd, projectTrusted });\n if (generation !== state.sessionGeneration) return;\n applyRuntimeBrowserSettings(settings.effectiveBrowser, settings.paths, projectTrusted);\n syncManagedBrowserSettings(ctx.sessionManager, settings.effectiveBrowser);\n applyRuntimeWebMcpSetting(settings.effectiveWebMcpEnabled, ctx.sessionManager);\n state.settingsNotice = settings.notice;\n for (const warning of settings.warnings) {\n ctx.ui.notify(sanitizeChromeDevtoolsDisplay(warning), \"warning\");\n }\n if (webMcpEnabled(ctx.sessionManager)) {\n ctx.ui.notify(\n \"Experimental WebMCP is enabled. Page-provided tools use the visible browser session and require confirmation for every call.\",\n \"warning\",\n );\n }\n // Tool mode/catalog are user-owned; a valid project browser section can\n // make the aggregate result loaded even when its user source is invalid.\n const preserveToolPolicy = settings.userFile.kind === \"invalid\";\n const availableTools = preserveToolPolicy\n ? previousAvailableTools\n : settings.kind === \"loaded\" && settings.settings.tools\n ? settings.settings.tools\n : allChromeDevtoolsTools(ctx.sessionManager);\n const provenanceWarning = configureChromeDevtoolsToolExposure(\n pi,\n availableTools,\n ctx.model,\n preserveToolPolicy ? previousMode : settings.kind === \"loaded\" ? settings.settings.toolMode : \"codemode\",\n );\n if (generation !== state.sessionGeneration) return;\n if (provenanceWarning) ctx.ui.notify(provenanceWarning, \"warning\");\n const active = new Set(pi.getActiveTools());\n if (\n chromeDevtoolsToolMode(pi) === \"codemode\" &&\n !active.has(\"codemode\") &&\n availableChromeDevtoolsTools(pi).some((name) => !active.has(name))\n ) {\n ctx.ui.notify(\n \"Chrome DevTools capabilities require Pi's codemode tool, but it is not active. Add '+codemode' to defaultTools and reload, or choose direct/lazy mode in Chrome DevTools settings. Chrome DevTools does not activate host tools automatically.\",\n \"warning\",\n );\n }\n });\n\n pi.on(\"model_select\", (event, ctx) => {\n const generation = state.sessionGeneration;\n invalidateWebMcpOperations(ctx.sessionManager, \"Chrome DevTools model and tool exposure changed\");\n if (!supportsNativeDeferredToolLoading(event.model)) {\n const provenanceWarning = requireEagerChromeDevtoolsToolExposure(pi);\n if (generation === state.sessionGeneration && provenanceWarning) ctx.ui.notify(provenanceWarning, \"warning\");\n }\n });\n\n pi.on(\"session_shutdown\", async (_event, ctx) => {\n state.sessionGeneration += 1;\n replaceSessionController(\"Chrome DevTools session shut down\");\n invalidateWebMcpOperations(ctx.sessionManager, \"Chrome DevTools session shut down\");\n ctx.ui.setStatus(STATUS_KEY, undefined);\n const browserShutdown = shutdownManagedBrowser(undefined, {\n cancelLaunch: true,\n owner: ctx.sessionManager,\n });\n await waitForChromeDevtoolsSettings();\n await waitForSettingsWrites();\n await browserShutdown;\n });\n}\n\nasync function handleChromeDevtoolsCommand(pi: ExtensionAPI, args: string, ctx: CommandContext, generation: number) {\n const command = parseCommand(args);\n switch (command) {\n case \"menu\":\n await showMenu(pi, ctx, generation);\n return;\n case \"help\":\n requireObservableUi(ctx, \"help\");\n ctx.ui.notify(buildCommandGuide(ctx.sessionManager), \"info\");\n return;\n case \"quickstart\":\n requireObservableUi(ctx, \"quickstart\");\n ctx.ui.notify(buildQuickstartMessage(ctx.sessionManager), \"info\");\n return;\n case \"status\": {\n requireObservableUi(ctx, \"status\");\n const status = await buildToolStatusMessage(pi, ctx.sessionManager);\n if (generation !== state.sessionGeneration) return;\n ctx.ui.notify(status, \"info\");\n return;\n }\n case \"settings\": {\n if (!ctx.hasUI || (ctx.mode !== \"tui\" && ctx.mode !== \"rpc\")) {\n throw new Error(\"/chrome-devtools settings requires TUI or RPC mode\");\n }\n const { showChromeDevtoolsBrowserSettings } = await import(\"./browser-settings-menu.js\");\n if (generation !== state.sessionGeneration) return;\n await showChromeDevtoolsBrowserSettings(pi, ctx, generation);\n return;\n }\n case \"tools\": {\n if (!ctx.hasUI || (ctx.mode !== \"tui\" && ctx.mode !== \"rpc\")) {\n throw new Error(\"/chrome-devtools tools requires TUI or RPC mode\");\n }\n const { showChromeDevtoolsToolWorkflow } = await import(\"./menu.js\");\n if (generation !== state.sessionGeneration) return;\n await showChromeDevtoolsToolWorkflow(pi, ctx, generation);\n return;\n }\n case \"enable\":\n await updateChromeDevtoolsTools(pi, ctx, allChromeDevtoolsTools(ctx.sessionManager), \"made all available\");\n return;\n case \"disable\":\n await updateChromeDevtoolsTools(pi, ctx, [], \"made all unavailable\");\n return;\n }\n\n if (!ctx.hasUI || (ctx.mode !== \"tui\" && ctx.mode !== \"rpc\")) {\n throw new Error(`Unknown /chrome-devtools command: ${args.trim()}`);\n }\n ctx.ui.notify(\n `Unknown /chrome-devtools command: ${args.trim()}\n\n${buildCommandGuide(ctx.sessionManager)}`,\n \"warning\",\n );\n}\n\nfunction requireObservableUi(ctx: CommandContext, route: string) {\n if (!ctx.hasUI || (ctx.mode !== \"tui\" && ctx.mode !== \"rpc\")) {\n throw new Error(`/chrome-devtools ${route} requires TUI or RPC mode`);\n }\n}\n\nasync function showMenu(pi: ExtensionAPI, ctx: CommandContext, generation: number) {\n if (!ctx.hasUI || (ctx.mode !== \"tui\" && ctx.mode !== \"rpc\")) {\n throw new Error(\"/chrome-devtools menu requires TUI or RPC mode; use a direct subcommand\");\n }\n const { showChromeDevtoolsMenu } = await import(\"./menu.js\");\n if (generation !== state.sessionGeneration) return;\n await showChromeDevtoolsMenu(pi, ctx, generation);\n}\n\nfunction replaceSessionController(reason: string) {\n state.sessionController.abort(new DOMException(reason, \"AbortError\"));\n state.sessionController = new AbortController();\n}\n\nexport function parseCommand(args: string): CommandAction | \"unknown\" {\n const command = args.trim().toLowerCase();\n if (!command) return \"menu\";\n if (command === \"help\") return \"help\";\n if (command === \"quickstart\") return \"quickstart\";\n if (command === \"status\") return \"status\";\n if (command === \"settings\") return \"settings\";\n if (command === \"tools\" || command === \"select\" || command === \"toggle\") return \"tools\";\n if (command === \"enable\" || command === \"on\") return \"enable\";\n if (command === \"disable\" || command === \"off\") return \"disable\";\n return \"unknown\";\n}\n\nexport function commandCompletions(prefix: string) {\n const normalized = prefix.trimStart().toLowerCase();\n if (/\\s/.test(normalized)) return null;\n\n const matches = COMMAND_COMPLETIONS.filter((completion) => completion.value.startsWith(normalized));\n return matches.length > 0 ? matches : null;\n}\n\nexport {\n formatHostForUrl,\n isLocalDevToolsHost,\n quoteCommandPart,\n} from \"./browser-manager.js\";\nexport { CHROME_DEVTOOLS_LOAD_TOOL_NAME } from \"./lazy-tools.js\";\nexport { parseConfiguredPort } from \"./runtime.js\";\nexport {\n hasParentPathSegment,\n isPathInsideRoot,\n resolveScreenshotPath,\n selectAllowedRoot,\n} from \"./screenshot.js\";\nexport { normalizeChromeDevtoolsSettings } from \"./settings.js\";\nexport {\n orderedChromeDevtoolsTools,\n sanitizeChromeDevtoolsDisplay,\n} from \"./tool-selector.js\";\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,kBAAkB;AAC3B,SAAS,YAAY;;;ACArB,SAAS,uBAAuB;AAGhC,IAAM,aAAa;AASnB,IAAM,iBAAiB,oBAAI,QAA0D;AAO9E,SAAS,eAAe,QAAgB;AAC7C,SAAO,MAAM,IAAI,gBAAgB,oBAAoB,MAAM,EAAE;AAC/D;AAEO,SAAS,iBACd,QACA,SACA,OACA;AACA,QAAM,SAAS,wBAAwB,YAAY,MAAM,GAAG,OAAO;AACnE,SAAO,IAAI,gBAAgB,OAAO,MAAM,OAAO,OAAO,KAAK;AAC7D;AAEO,SAAS,uBACd,QACA,SACA,OACiB;AACjB,QAAM,SAAS,wBAAwB,sBAAsB,MAAM,GAAG,OAAO;AAC7E,SAAO,IAAI,gBAAgB,OAAO,MAAM,OAAO,OAAO,KAAK;AAC7D;AAEA,SAAS,YAAY,QAAkC;AACrD,SAAO,OAAO,QAAQ,QAAQ,CAAC,YAAa,QAAQ,SAAS,SAAS,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAE,EAAE,KAAK,IAAI;AACvG;AAEA,SAAS,sBAAsB,QAAkC;AAC/D,QAAM,OAAO,YAAY,MAAM;AAC/B,MAAI,KAAK,KAAK,EAAG,QAAO;AAExB,QAAM,UAAU,OAAO;AACvB,MAAI,OAAO,SAAS,cAAc,SAAU,QAAO;AACnD,QAAM,QAAQ,OAAO,QAAQ,UAAU,WAAW,KAAK,QAAQ,KAAK,YAAY;AAChF,SAAO,uBAAuB,QAAQ,SAAS,GAAG,KAAK;AACzD;AAEA,SAAS,wBAAwB,MAAc,SAAoE;AACjH,MAAI,QAAQ,UAAW,QAAO,EAAE,MAAM,cAAc,OAAO,UAAU;AACrE,MAAI,QAAQ,SAAU,QAAO,EAAE,MAAM,OAAO,aAAa;AAEzD,SAAO,EAAE,MAAM,GAAG;AACpB;AAEA,IAAM,kBAAN,MAAiD;AAAA,EACvC;AAAA,EACS;AAAA,EACA;AAAA,EAEjB,YAAY,OAAO,IAAI,OAAqB,OAAgB;AAC1D,SAAK,OAAO;AACZ,SAAK,QAAQ;AACb,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,QAAQ,MAAc;AACpB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,aAAa;AAAA,EAEb;AAAA,EAEA,OAAO,OAAe;AACpB,UAAM,gBAAgB,8BAA8B,KAAK,IAAI;AAC7D,QAAI,CAAC,cAAc,KAAK,EAAG,QAAO,CAAC;AACnC,WAAO,cACJ,QAAQ,OAAO,KAAK,EACpB,MAAM,OAAO,EACb,IAAI,CAAC,SAAS;AACb,YAAM,gBAAgB,gBAAgB,MAAM,KAAK,IAAI,GAAG,KAAK,GAAG,EAAE;AAClE,aAAO,KAAK,SAAS,KAAK,QAAQ,KAAK,MAAM,GAAG,KAAK,OAAO,aAAa,IAAI;AAAA,IAC/E,CAAC;AAAA,EACL;AACF;AAEA,eAAsB,WAAc,KAAoB,QAAgB,UAA4B;AAClG,QAAM,QAAQ,OAAO,MAAM;AAC3B,QAAM,WAAW,eAAe,IAAI,IAAI,cAAc,KAAK,CAAC;AAC5D,WAAS,KAAK,EAAE,QAAQ,MAAM,CAAC;AAC/B,iBAAe,IAAI,IAAI,gBAAgB,QAAQ;AAC/C,MAAI,GAAG,UAAU,YAAY,MAAM;AACnC,MAAI;AACF,WAAO,MAAM,SAAS;AAAA,EACxB,UAAE;AACA,UAAM,QAAQ,SAAS,UAAU,CAAC,UAAU,MAAM,UAAU,KAAK;AACjE,QAAI,SAAS,EAAG,UAAS,OAAO,OAAO,CAAC;AACxC,UAAM,YAAY,SAAS,GAAG,EAAE,GAAG;AACnC,QAAI,SAAS,WAAW,EAAG,gBAAe,OAAO,IAAI,cAAc;AACnE,QAAI,GAAG,UAAU,YAAY,SAAS;AAAA,EACxC;AACF;;;AC9GA,SAAS,kBAAkB;AAC3B,SAAS,OAAO,OAAO,UAAU,QAAQ,IAAI,iBAAiB;AAC9D,SAAS,cAAc;AACvB,SAAS,UAAU,SAAS,YAAY,MAAM,UAAU,SAAS,WAAW;AAC5E,SAAS,6BAA6B;AAGtC,SAAS,OAAU,QAAa;AAC9B,SAAO,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC;AACnC;AAEA,SAAS,YAAY,OAAgD;AACnE,SAAO,iBAAiB,SAAS,UAAU;AAC7C;AAaA,eAAsB,eACpB,WACA,UACA,KACA,QAC+B;AAC/B,QAAM,eAAe,sBAAsB,UAAU,GAAG;AACxD,QAAM,WAAW,OAAO,KAAK,WAAW,QAAQ;AAEhD,QAAM,sBAAsB,aAAa,MAAM,YAAY;AACzD,mBAAe,MAAM;AACrB,UAAM,2BAA2B,YAAY;AAC7C,UAAM,+BAA+B,YAAY;AACjD,UAAM,0BAA0B,cAAc,UAAU,MAAM;AAAA,EAChE,CAAC;AAED,SAAO;AAAA,IACL,WAAW,aAAa;AAAA,IACxB,OAAO,SAAS;AAAA,IAChB,eAAe,aAAa;AAAA,EAC9B;AACF;AAEO,SAAS,sBAAsB,UAA8B,KAAqC;AACvG,QAAM,UAAU,QAAQ,GAAG;AAC3B,QAAM,WAAW,QAAQ,OAAO,CAAC;AAEjC,MAAI,aAAa,QAAW;AAC1B,WAAO;AAAA,MACL,MAAM,KAAK,UAAU,iCAAiC,WAAW,CAAC,MAAM;AAAA,MACxE,cAAc,CAAC,QAAQ;AAAA,MACvB,WAAW;AAAA,IACb;AAAA,EACF;AAEA,QAAM,iBAAiB,mBAAmB,QAAQ;AAClD,MAAI,CAAC,eAAe,KAAK,GAAG;AAC1B,UAAM,IAAI,MAAM,wCAAwC;AAAA,EAC1D;AACA,MAAI,eAAe,SAAS,IAAI,GAAG;AACjC,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AACA,MAAI,qBAAqB,cAAc,GAAG;AACxC,UAAM,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AAEA,QAAM,iBAAiB,WAAW,cAAc;AAChD,QAAM,OAAO,iBAAiB,QAAQ,cAAc,IAAI,QAAQ,SAAS,cAAc;AACvF,QAAM,eAAe,iBAAiB,OAAO,CAAC,SAAS,QAAQ,CAAC,IAAI,CAAC,OAAO;AAC5E,MAAI,CAAC,aAAa,KAAK,CAAC,SAAS,iBAAiB,MAAM,IAAI,CAAC,GAAG;AAC9D,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,cAAc,WAAW,MAAM;AAChD;AAEA,SAAS,mBAAmB,MAAc;AACxC,SAAO,KAAK,WAAW,GAAG,IAAI,KAAK,MAAM,CAAC,IAAI;AAChD;AAEO,SAAS,qBAAqB,MAAc;AACjD,SAAO,KAAK,MAAM,QAAQ,EAAE,KAAK,CAAC,SAAS,SAAS,IAAI;AAC1D;AAEA,eAAe,2BAA2B,cAAsC;AAC9E,QAAM,aAAa,QAAQ,aAAa,IAAI;AAC5C,QAAM,WAAW,kBAAkB,YAAY,aAAa,YAAY;AACxE,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,iGAAiG;AAAA,EACnH;AAEA,QAAM,eAAe,MAAM,SAAS,QAAQ;AAC5C,MAAI,cAAc;AAClB,QAAM,iBAAiB,SAAS,UAAU,UAAU,EACjD,MAAM,QAAQ,EACd,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC;AAEnC,aAAW,WAAW,gBAAgB;AACpC,kBAAc,KAAK,aAAa,OAAO;AACvC,UAAM,2BAA2B,aAAa,YAAY;AAAA,EAC5D;AACF;AAEO,SAAS,kBAAkB,MAAc,OAA0B;AACxE,QAAM,gBAAgB,MAAM,OAAO,CAAC,SAAS,iBAAiB,MAAM,IAAI,CAAC;AACzE,gBAAc;AAAA,IACZ,CAAC,MAAM,UACL,2BAA2B,QAAQ,KAAK,CAAC,EAAE,SAAS,2BAA2B,QAAQ,IAAI,CAAC,EAAE;AAAA,EAClG;AACA,SAAO,cAAc,CAAC;AACxB;AAEA,eAAe,2BAA2B,MAAc,cAAsB;AAC5E,QAAM,oBAAoB,MAAM,MAAM,IAAI,EAAE,MAAM,OAAO,UAAmB;AAC1E,QAAI,CAAC,YAAY,KAAK,KAAK,MAAM,SAAS,SAAU,OAAM;AAC1D,UAAM,MAAM,IAAI,EAAE,MAAM,CAAC,eAAwB;AAC/C,UAAI,CAAC,YAAY,UAAU,KAAK,WAAW,SAAS,SAAU,OAAM;AAAA,IACtE,CAAC;AACD,WAAO,MAAM,IAAI;AAAA,EACnB,CAAC;AAED,MAAI,kBAAkB,eAAe,GAAG;AACtC,UAAM,IAAI,MAAM,yEAAyE;AAAA,EAC3F;AACA,MAAI,CAAC,kBAAkB,YAAY,GAAG;AACpC,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AACA,QAAM,yBAAyB,MAAM,YAAY;AACnD;AAEA,eAAe,+BAA+B,cAAsC;AAClF,QAAM,iBAAiB,MAAM,MAAM,aAAa,IAAI,EAAE,MAAM,CAAC,UAAmB;AAC9E,QAAI,YAAY,KAAK,KAAK,MAAM,SAAS,SAAU,QAAO;AAC1D,UAAM;AAAA,EACR,CAAC;AACD,MAAI,gBAAgB,eAAe,GAAG;AACpC,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,MAAI,gBAAgB,YAAY,GAAG;AACjC,UAAM,IAAI,MAAM,4DAA4D;AAAA,EAC9E;AACA,MAAI,kBAAkB,CAAC,eAAe,OAAO,GAAG;AAC9C,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AAEA,QAAM,mBAAmB,MAAM,QAAQ,IAAI,aAAa,aAAa,IAAI,sBAAsB,CAAC;AAChG,QAAM,aAAa,MAAM,SAAS,QAAQ,aAAa,IAAI,CAAC;AAC5D,QAAM,iBAAiB,KAAK,YAAY,SAAS,aAAa,IAAI,CAAC;AACnE,MAAI,CAAC,iBAAiB,KAAK,CAAC,SAAS,iBAAiB,gBAAgB,IAAI,CAAC,GAAG;AAC5E,UAAM,IAAI,MAAM,0FAA0F;AAAA,EAC5G;AACF;AAEA,eAAe,yBAAyB,MAAc,cAAsB;AAC1E,QAAM,WAAW,MAAM,SAAS,IAAI;AACpC,MAAI,CAAC,iBAAiB,UAAU,YAAY,GAAG;AAC7C,UAAM,IAAI,MAAM,iGAAiG;AAAA,EACnH;AACF;AAEA,eAAe,0BACb,cACA,UACA,QACA;AACA,QAAM,WAAW;AAAA,IACf,QAAQ,aAAa,IAAI;AAAA,IACzB,IAAI,SAAS,aAAa,IAAI,CAAC,IAAI,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC,IAAI,WAAW,CAAC;AAAA,EAC9E;AACA,MAAI;AACF,UAAM,UAAU,UAAU,UAAU,EAAE,MAAM,MAAM,OAAO,CAAC;AAC1D,mBAAe,MAAM;AACrB,UAAM,sBAAsB,cAAc,UAAU,MAAM;AAAA,EAC5D,SAAS,OAAO;AACd,UAAM,GAAG,UAAU,EAAE,OAAO,KAAK,CAAC,EAAE,MAAM,MAAM,MAAS;AACzD,UAAM;AAAA,EACR;AACF;AAEA,eAAe,sBACb,cACA,UACA,QACA;AACA,MAAI;AACF,UAAM,OAAO,UAAU,aAAa,IAAI;AACxC;AAAA,EACF,SAAS,OAAO;AACd,QAAI,CAAC,0CAA0C,KAAK,EAAG,OAAM;AAAA,EAC/D;AAIA,QAAM,+BAA+B,YAAY;AACjD,iBAAe,MAAM;AACrB,QAAM,GAAG,aAAa,MAAM,EAAE,OAAO,KAAK,CAAC;AAC3C,QAAM,OAAO,UAAU,aAAa,IAAI;AAC1C;AAEA,SAAS,0CAA0C,OAAgB;AACjE,SAAO,QAAQ,aAAa,WAAW,YAAY,KAAK,KAAK,CAAC,UAAU,UAAU,OAAO,EAAE,SAAS,MAAM,QAAQ,EAAE;AACtH;AAEA,eAAe,uBAAuB,MAAc;AAClD,SAAO,SAAS,IAAI,EAAE,MAAM,MAAM,QAAQ,IAAI,CAAC;AACjD;AAEO,SAAS,iBAAiB,MAAc,MAAc;AAC3D,QAAM,iBAAiB,2BAA2B,QAAQ,IAAI,CAAC;AAC/D,QAAM,iBAAiB,2BAA2B,QAAQ,IAAI,CAAC;AAC/D,MAAI,mBAAmB,eAAgB,QAAO;AAC9C,QAAM,oBAAoB,eAAe,SAAS,GAAG,IAAI,iBAAiB,GAAG,cAAc,GAAG,GAAG;AACjG,SAAO,eAAe,WAAW,iBAAiB;AACpD;AAEA,SAAS,2BAA2B,MAAc;AAChD,SAAO,QAAQ,aAAa,UAAU,KAAK,YAAY,IAAI;AAC7D;AAEO,SAAS,eAAe,QAAiC;AAC9D,MAAI,CAAC,QAAQ,QAAS;AACtB,QAAM,OAAO,kBAAkB,QAAQ,OAAO,SAAS,IAAI,MAAM,+BAA+B;AAClG;AAEO,SAAS,qBAAqB,MAAoB,YAAkC;AACzF,QAAM,YAAY,WAAW,gBAAgB,uBAAuB;AACpE,SAAO;AAAA,IACL,gCAAgC,KAAK,SAAS,KAAK,OAAO,KAAK,EAAE;AAAA,IACjE,GAAG,SAAS,KAAK,WAAW,SAAS;AAAA,IACrC,UAAU,WAAW,KAAK;AAAA,IAC1B,oBAAoB,KAAK,UAAU,WAAW,SAAS,CAAC;AAAA,EAC1D,EAAE,KAAK,IAAI;AACb;;;AFhOO,IAAM,gBAAgB,WAAW;AAAA,EACtC,MAAM,2BAA2B,CAAC;AAAA,EAClC,OAAO;AAAA,EACP,aAAa;AAAA,EACb,YAAY,KAAK,OAAO,CAAC,CAAC;AAAA,EAC1B,YAAY,eAAe,YAAY;AAAA,EACvC,cAAc;AAAA,EACd,MAAM,QAAQ,aAAa,SAAS,QAAQ,WAAW,KAAK;AAC1D,WAAO,WAAW,KAAK,cAAc,YAAY;AAC/C,YAAM,QAAQ,MAAM,UAAU,EAAE,cAAc,IAAI,gBAAgB,OAAO,CAAC;AAC1E,aAAO,WAAW,KAAK,UAAU,MAAM,IAAI,UAAU,GAAG,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC;AAAA,IAC7E,CAAC;AAAA,EACH;AACF,CAAC;AAEM,IAAM,iBAAiB,WAAW;AAAA,EACvC,MAAM,2BAA2B,CAAC;AAAA,EAClC,OAAO;AAAA,EACP,aAAa;AAAA,EACb,YAAY,KAAK,OAAO;AAAA,IACtB,QAAQ,KAAK,OAAO,EAAE,aAAa,2CAA2C,CAAC;AAAA,EACjF,CAAC;AAAA,EACD,YAAY,eAAe,aAAa;AAAA,EACxC,cAAc;AAAA,EACd,MAAM,QAAQ,aAAa,QAAQ,QAAQ,WAAW,KAAK;AACzD,WAAO,WAAW,KAAK,eAAe,YAAY;AAChD,YAAM,OAAO,MAAM,QAAQ,OAAO,QAAQ,EAAE,cAAc,IAAI,gBAAgB,OAAO,CAAC;AACtF,sBAAgB,IAAI,gBAAgB,KAAK,EAAE;AAC3C,aAAO,WAAW,iBAAiB,KAAK,EAAE,KAAK,KAAK,KAAK;AAAA,EAAK,KAAK,GAAG,IAAI;AAAA,QACxE,MAAM,WAAW,IAAI;AAAA,MACvB,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF,CAAC;AAEM,IAAM,eAAe,WAAW;AAAA,EACrC,MAAM,2BAA2B,CAAC;AAAA,EAClC,OAAO;AAAA,EACP,aACE;AAAA,EACF,YAAY,KAAK,OAAO;AAAA,IACtB,KAAK,KAAK,OAAO,EAAE,aAAa,sBAAsB,CAAC;AAAA,IACvD,QAAQ,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,wDAAwD,CAAC,CAAC;AAAA,EAC7G,CAAC;AAAA,EACD,YAAY,eAAe,UAAU;AAAA,EACrC,cAAc;AAAA,EACd,MAAM,QAAQ,aAAa,QAAQ,QAAQ,WAAW,KAAK;AACzD,WAAO,WAAW,KAAK,YAAY,YAAY;AAC7C,YAAM,EAAE,SAAS,KAAK,IAAI,MAAM,yBAAyB,OAAO,QAAQ;AAAA,QACtE,cAAc,IAAI;AAAA,QAClB;AAAA,MACF,CAAC;AACD,YAAM,SAAS,MAAM,QAAQ,MAAM,OAAO,WAAW;AACnD,cAAM,OAAO,KAAK,aAAa;AAC/B,eAAO,OAAO,KAAK,iBAAiB,EAAE,KAAK,OAAO,IAAI,CAAC;AAAA,MACzD,CAAC;AAED,sBAAgB,IAAI,gBAAgB,KAAK,EAAE;AAC3C,YAAM,SAAS,UAAU,+BAA+B;AACxD,aAAO,WAAW,GAAG,MAAM,IAAI,KAAK,EAAE,OAAO,OAAO,GAAG,IAAI;AAAA,QACzD;AAAA,QACA,MAAM,WAAW,IAAI;AAAA,QACrB;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF,CAAC;AAEM,IAAM,eAAe,WAAW;AAAA,EACrC,MAAM,2BAA2B,CAAC;AAAA,EAClC,OAAO;AAAA,EACP,aAAa;AAAA,EACb,YAAY,KAAK,OAAO;AAAA,IACtB,YAAY,KAAK,OAAO,EAAE,aAAa,qCAAqC,CAAC;AAAA,IAC7E,QAAQ,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,wDAAwD,CAAC,CAAC;AAAA,IAC3G,cAAc,KAAK;AAAA,MACjB,KAAK,QAAQ,EAAE,aAAa,yDAAyD,CAAC;AAAA,IACxF;AAAA,EACF,CAAC;AAAA,EACD,YAAY,eAAe,UAAU;AAAA,EACrC,cAAc;AAAA,EACd,MAAM,QAAQ,aAAa,QAAQ,QAAQ,WAAW,KAAK;AACzD,WAAO,WAAW,KAAK,YAAY,YAAY;AAC7C,YAAM,OAAO,MAAM,YAAY,OAAO,QAAQ;AAAA,QAC5C,cAAc,IAAI;AAAA,QAClB;AAAA,MACF,CAAC;AACD,YAAM,SAAS,MAAM;AAAA,QAAQ;AAAA,QAAM,CAAC,WAClC,OAAO,KAAK,oBAAoB;AAAA,UAC9B,YAAY,OAAO;AAAA,UACnB,cAAc,OAAO,gBAAgB;AAAA,UACrC,eAAe;AAAA,QACjB,CAAC;AAAA,MACH;AAEA,sBAAgB,IAAI,gBAAgB,KAAK,EAAE;AAC3C,aAAO,WAAW,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,EAAE,MAAM,WAAW,IAAI,GAAG,OAAO,CAAC;AAAA,IACvF,CAAC;AAAA,EACH;AACF,CAAC;AAEM,IAAM,sBAAsB,WAAW;AAAA,EAC5C,MAAM,kBAAkB,CAAC;AAAA,EACzB,OAAO;AAAA,EACP,aACE;AAAA,EACF,YAAY,KAAK,OAAO;AAAA,IACtB,QAAQ,KAAK;AAAA,MACX,KAAK,OAAO;AAAA,QACV,aAAa;AAAA,QACb,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAAA,EACD,YAAY,eAAe,mBAAmB;AAAA,EAC9C,cAAc;AAAA,EACd,MAAM,QAAQ,aAAa,QAAQ,QAAQ,WAAW,KAAK;AACzD,WAAO,WAAW,KAAK,qBAAqB,YAAY;AACtD,YAAM,iBAAiB,MAAM,OAAO,4BAAmB;AACvD,aAAO,eAAe,sBAAsB,QAAQ,QAAQ,GAAG;AAAA,IACjE,CAAC;AAAA,EACH;AACF,CAAC;AAEM,IAAM,iBAAiB,WAAW;AAAA,EACvC,MAAM,kBAAkB,CAAC;AAAA,EACzB,OAAO;AAAA,EACP,aACE;AAAA,EACF,YAAY,KAAK,OAAO;AAAA,IACtB,mBAAmB,KAAK,OAAO;AAAA,MAC7B,aAAa;AAAA,MACb,WAAW;AAAA,IACb,CAAC;AAAA,IACD,QAAQ,KAAK,OAAO,EAAE,aAAa,sCAAsC,WAAW,IAAI,CAAC;AAAA,IACzF,YAAY,KAAK,OAAO;AAAA,MACtB,aAAa;AAAA,MACb,WAAW;AAAA,IACb,CAAC;AAAA,IACD,SAAS,KAAK,OAAO,EAAE,aAAa,uCAAuC,WAAW,IAAI,CAAC;AAAA,IAC3F,aAAa,KAAK,OAAO;AAAA,MACvB,aAAa;AAAA,MACb,WAAW;AAAA,IACb,CAAC;AAAA,IACD,UAAU,KAAK,OAAO;AAAA,MACpB,aAAa;AAAA,MACb,WAAW;AAAA,IACb,CAAC;AAAA,IACD,cAAc,KAAK,OAAO;AAAA,MACxB,aAAa;AAAA,MACb,WAAW;AAAA,MACX,WAAW;AAAA,MACX,SAAS;AAAA,IACX,CAAC;AAAA,IACD,OAAO,KAAK,OAAO,KAAK,OAAO,GAAG,KAAK,QAAQ,GAAG;AAAA,MAChD,aAAa;AAAA,IACf,CAAC;AAAA,EACH,CAAC;AAAA,EACD,YAAY,eAAe,kBAAkB;AAAA,EAC7C,cAAc;AAAA,EACd,MAAM,QAAQ,aAAa,QAAQ,QAAQ,WAAW,KAAK;AACzD,WAAO,WAAW,KAAK,oBAAoB,YAAY;AACrD,YAAM,iBAAiB,MAAM,OAAO,4BAAmB;AACvD,aAAO,eAAe,sBAAsB,QAAQ,QAAQ,GAAG;AAAA,IACjE,CAAC;AAAA,EACH;AACF,CAAC;AAEM,IAAM,iBAAiB,WAAW;AAAA,EACvC,MAAM,2BAA2B,CAAC;AAAA,EAClC,OAAO;AAAA,EACP,aAAa;AAAA,EACb,YAAY,KAAK,OAAO;AAAA,IACtB,QAAQ,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,wDAAwD,CAAC,CAAC;AAAA,IAC3G,UAAU,KAAK,SAAS,KAAK,QAAQ,EAAE,aAAa,oDAAoD,CAAC,CAAC;AAAA,IAC1G,UAAU,KAAK;AAAA,MACb,KAAK,OAAO;AAAA,QACV,aACE;AAAA,MACJ,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAAA,EACD,YAAY,eAAe,YAAY;AAAA,EACvC,cAAc;AAAA,EACd,MAAM,QAAQ,aAAa,QAAQ,QAAQ,WAAW,KAAK;AACzD,WAAO,WAAW,KAAK,cAAc,YAAY;AAC/C,YAAM,OAAO,MAAM,YAAY,OAAO,QAAQ;AAAA,QAC5C,cAAc,IAAI;AAAA,QAClB;AAAA,MACF,CAAC;AACD,YAAM,SAAS,MAAM,QAAQ,MAAM,OAAO,WAAW;AACnD,uBAAe,MAAM;AACrB,cAAM,OAAO,KAAK,aAAa;AAE/B,YAAI,CAAC,OAAO,UAAU;AACpB,iBAAO,OAAO,KAAuB,0BAA0B,EAAE,QAAQ,MAAM,CAAC;AAAA,QAClF;AAEA,cAAM,UAAU,MAAM,OAAO,KAE1B,uBAAuB;AAE1B,uBAAe,MAAM;AACrB,eAAO,OAAO,KAAuB,0BAA0B;AAAA,UAC7D,uBAAuB;AAAA,UACvB,QAAQ;AAAA,UACR,MAAM;AAAA,YACJ,GAAG,QAAQ,YAAY;AAAA,YACvB,GAAG,QAAQ,YAAY;AAAA,YACvB,OAAO,QAAQ,YAAY;AAAA,YAC3B,QAAQ,QAAQ,YAAY;AAAA,YAC5B,OAAO;AAAA,UACT;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAED,sBAAgB,IAAI,gBAAgB,KAAK,EAAE;AAC3C,YAAM,kBAAkB,MAAM,eAAe,OAAO,MAAM,OAAO,UAAU,IAAI,KAAK,MAAM;AAC1F,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,qBAAqB,MAAM,eAAe;AAAA,UAClD;AAAA,UACA,EAAE,MAAM,SAAS,MAAM,OAAO,MAAM,UAAU,YAAY;AAAA,QAC5D;AAAA,QACA,SAAS;AAAA,UACP,MAAM,WAAW,IAAI;AAAA,UACrB,OAAO,gBAAgB;AAAA,UACvB,WAAW,gBAAgB;AAAA,UAC3B,eAAe,gBAAgB;AAAA,QACjC;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF,CAAC;;;AG/MD,IAAMA,cAAa;AACnB,IAAM,sBAAsB;AAAA,EAC1B,EAAE,OAAO,QAAQ,OAAO,QAAQ,aAAa,qBAAqB;AAAA,EAClE,EAAE,OAAO,cAAc,OAAO,cAAc,aAAa,gCAAgC;AAAA,EACzF,EAAE,OAAO,UAAU,OAAO,UAAU,aAAa,gCAAgC;AAAA,EACjF,EAAE,OAAO,YAAY,OAAO,YAAY,aAAa,mCAAmC;AAAA,EACxF,EAAE,OAAO,SAAS,OAAO,SAAS,aAAa,yCAAyC;AAAA,EACxF,EAAE,OAAO,UAAU,OAAO,UAAU,aAAa,kBAAkB;AAAA,EACnE,EAAE,OAAO,UAAU,OAAO,UAAU,aAAa,gCAAgC;AAAA,EACjF,EAAE,OAAO,UAAU,OAAO,UAAU,aAAa,2CAA2C;AAAA,EAC5F,EAAE,OAAO,MAAM,OAAO,MAAM,aAAa,iCAAiC;AAAA,EAC1E,EAAE,OAAO,WAAW,OAAO,WAAW,aAAa,6CAA6C;AAAA,EAChG,EAAE,OAAO,OAAO,OAAO,OAAO,aAAa,kCAAkC;AAC/E;AACe,SAAR,eAAgC,IAAkB;AACvD,qCAAmC,IAAI;AAAA,IACrC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,KAAG,gBAAgB,mBAAmB;AAAA,IACpC,aAAa;AAAA,IACb,wBAAwB,CAAC,WAAW,mBAAmB,MAAM;AAAA,IAC7D,SAAS,OAAO,MAAM,QAAQ;AAC5B,oCAA8B,IAAI,IAAI,cAAc;AACpD,6CAAuC,EAAE;AACzC,YAAM,aAAa,MAAM;AACzB,YAAM,4BAA4B,IAAI,MAAM,KAAK,UAAU;AAAA,IAC7D;AAAA,EACF,CAAC;AAED,KAAG,GAAG,iBAAiB,OAAO,QAAQ,QAAQ;AAC5C,UAAM,aAAa,EAAE,MAAM;AAC3B,kCAA8B,IAAI,IAAI,gBAAgB,IAAI,eAAe,UAAU,CAAC;AAGpF,UAAM,yBAAyB,4BAA4B,EAAE;AAC7D,UAAM,eAAe,uBAAuB,EAAE;AAC9C,2CAAuC,EAAE;AACzC,0BAAsB,IAAI,cAAc;AACxC,6BAAyB,kCAAkC;AAC3D,+BAA2B,IAAI,gBAAgB,kCAAkC;AACjF,UAAM,eAAe;AACrB,UAAM,iBAAiB;AACvB,QAAI,GAAG,UAAUA,aAAY,MAAS;AACtC,UAAM,uBAAuB,QAAW;AAAA,MACtC,cAAc;AAAA,MACd,OAAO,IAAI;AAAA,IACb,CAAC;AACD,+BAA2B,IAAI,cAAc;AAC7C,QAAI,eAAe,MAAM,kBAAmB;AAC5C,oBAAgB,IAAI,gBAAgB,MAAS;AAC7C,UAAM,eAAe;AACrB,UAAM,oBAAoB;AAC1B,UAAM,iBAAiB,IAAI,iBAAiB;AAC5C,UAAM,8BAA8B;AACpC,QAAI,eAAe,MAAM,kBAAmB;AAC5C,UAAM,WAAW,MAAM,aAAa,EAAE,KAAK,IAAI,KAAK,eAAe,CAAC;AACpE,QAAI,eAAe,MAAM,kBAAmB;AAC5C,gCAA4B,SAAS,kBAAkB,SAAS,OAAO,cAAc;AACrF,+BAA2B,IAAI,gBAAgB,SAAS,gBAAgB;AACxE,8BAA0B,SAAS,wBAAwB,IAAI,cAAc;AAC7E,UAAM,iBAAiB,SAAS;AAChC,eAAW,WAAW,SAAS,UAAU;AACvC,UAAI,GAAG,OAAO,8BAA8B,OAAO,GAAG,SAAS;AAAA,IACjE;AACA,QAAI,cAAc,IAAI,cAAc,GAAG;AACrC,UAAI,GAAG;AAAA,QACL;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAGA,UAAM,qBAAqB,SAAS,SAAS,SAAS;AACtD,UAAM,iBAAiB,qBACnB,yBACA,SAAS,SAAS,YAAY,SAAS,SAAS,QAC9C,SAAS,SAAS,QAClB,uBAAuB,IAAI,cAAc;AAC/C,UAAM,oBAAoB;AAAA,MACxB;AAAA,MACA;AAAA,MACA,IAAI;AAAA,MACJ,qBAAqB,eAAe,SAAS,SAAS,WAAW,SAAS,SAAS,WAAW;AAAA,IAChG;AACA,QAAI,eAAe,MAAM,kBAAmB;AAC5C,QAAI,kBAAmB,KAAI,GAAG,OAAO,mBAAmB,SAAS;AACjE,UAAM,SAAS,IAAI,IAAI,GAAG,eAAe,CAAC;AAC1C,QACE,uBAAuB,EAAE,MAAM,cAC/B,CAAC,OAAO,IAAI,UAAU,KACtB,6BAA6B,EAAE,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,IAAI,IAAI,CAAC,GACjE;AACA,UAAI,GAAG;AAAA,QACL;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAED,KAAG,GAAG,gBAAgB,CAAC,OAAO,QAAQ;AACpC,UAAM,aAAa,MAAM;AACzB,+BAA2B,IAAI,gBAAgB,iDAAiD;AAChG,QAAI,CAAC,kCAAkC,MAAM,KAAK,GAAG;AACnD,YAAM,oBAAoB,uCAAuC,EAAE;AACnE,UAAI,eAAe,MAAM,qBAAqB,kBAAmB,KAAI,GAAG,OAAO,mBAAmB,SAAS;AAAA,IAC7G;AAAA,EACF,CAAC;AAED,KAAG,GAAG,oBAAoB,OAAO,QAAQ,QAAQ;AAC/C,UAAM,qBAAqB;AAC3B,6BAAyB,mCAAmC;AAC5D,+BAA2B,IAAI,gBAAgB,mCAAmC;AAClF,QAAI,GAAG,UAAUA,aAAY,MAAS;AACtC,UAAM,kBAAkB,uBAAuB,QAAW;AAAA,MACxD,cAAc;AAAA,MACd,OAAO,IAAI;AAAA,IACb,CAAC;AACD,UAAM,8BAA8B;AACpC,UAAM,sBAAsB;AAC5B,UAAM;AAAA,EACR,CAAC;AACH;AAEA,eAAe,4BAA4B,IAAkB,MAAc,KAAqB,YAAoB;AAClH,QAAM,UAAU,aAAa,IAAI;AACjC,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,YAAM,SAAS,IAAI,KAAK,UAAU;AAClC;AAAA,IACF,KAAK;AACH,0BAAoB,KAAK,MAAM;AAC/B,UAAI,GAAG,OAAO,kBAAkB,IAAI,cAAc,GAAG,MAAM;AAC3D;AAAA,IACF,KAAK;AACH,0BAAoB,KAAK,YAAY;AACrC,UAAI,GAAG,OAAO,uBAAuB,IAAI,cAAc,GAAG,MAAM;AAChE;AAAA,IACF,KAAK,UAAU;AACb,0BAAoB,KAAK,QAAQ;AACjC,YAAM,SAAS,MAAM,uBAAuB,IAAI,IAAI,cAAc;AAClE,UAAI,eAAe,MAAM,kBAAmB;AAC5C,UAAI,GAAG,OAAO,QAAQ,MAAM;AAC5B;AAAA,IACF;AAAA,IACA,KAAK,YAAY;AACf,UAAI,CAAC,IAAI,SAAU,IAAI,SAAS,SAAS,IAAI,SAAS,OAAQ;AAC5D,cAAM,IAAI,MAAM,oDAAoD;AAAA,MACtE;AACA,YAAM,EAAE,kCAAkC,IAAI,MAAM,OAAO,4CAA4B;AACvF,UAAI,eAAe,MAAM,kBAAmB;AAC5C,YAAM,kCAAkC,IAAI,KAAK,UAAU;AAC3D;AAAA,IACF;AAAA,IACA,KAAK,SAAS;AACZ,UAAI,CAAC,IAAI,SAAU,IAAI,SAAS,SAAS,IAAI,SAAS,OAAQ;AAC5D,cAAM,IAAI,MAAM,iDAAiD;AAAA,MACnE;AACA,YAAM,EAAE,+BAA+B,IAAI,MAAM,OAAO,2BAAW;AACnE,UAAI,eAAe,MAAM,kBAAmB;AAC5C,YAAM,+BAA+B,IAAI,KAAK,UAAU;AACxD;AAAA,IACF;AAAA,IACA,KAAK;AACH,YAAM,0BAA0B,IAAI,KAAK,uBAAuB,IAAI,cAAc,GAAG,oBAAoB;AACzG;AAAA,IACF,KAAK;AACH,YAAM,0BAA0B,IAAI,KAAK,CAAC,GAAG,sBAAsB;AACnE;AAAA,EACJ;AAEA,MAAI,CAAC,IAAI,SAAU,IAAI,SAAS,SAAS,IAAI,SAAS,OAAQ;AAC5D,UAAM,IAAI,MAAM,qCAAqC,KAAK,KAAK,CAAC,EAAE;AAAA,EACpE;AACA,MAAI,GAAG;AAAA,IACL,qCAAqC,KAAK,KAAK,CAAC;AAAA;AAAA,EAElD,kBAAkB,IAAI,cAAc,CAAC;AAAA,IACnC;AAAA,EACF;AACF;AAEA,SAAS,oBAAoB,KAAqB,OAAe;AAC/D,MAAI,CAAC,IAAI,SAAU,IAAI,SAAS,SAAS,IAAI,SAAS,OAAQ;AAC5D,UAAM,IAAI,MAAM,oBAAoB,KAAK,2BAA2B;AAAA,EACtE;AACF;AAEA,eAAe,SAAS,IAAkB,KAAqB,YAAoB;AACjF,MAAI,CAAC,IAAI,SAAU,IAAI,SAAS,SAAS,IAAI,SAAS,OAAQ;AAC5D,UAAM,IAAI,MAAM,yEAAyE;AAAA,EAC3F;AACA,QAAM,EAAE,uBAAuB,IAAI,MAAM,OAAO,2BAAW;AAC3D,MAAI,eAAe,MAAM,kBAAmB;AAC5C,QAAM,uBAAuB,IAAI,KAAK,UAAU;AAClD;AAEA,SAAS,yBAAyB,QAAgB;AAChD,QAAM,kBAAkB,MAAM,IAAI,aAAa,QAAQ,YAAY,CAAC;AACpE,QAAM,oBAAoB,IAAI,gBAAgB;AAChD;AAEO,SAAS,aAAa,MAAyC;AACpE,QAAM,UAAU,KAAK,KAAK,EAAE,YAAY;AACxC,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,YAAY,OAAQ,QAAO;AAC/B,MAAI,YAAY,aAAc,QAAO;AACrC,MAAI,YAAY,SAAU,QAAO;AACjC,MAAI,YAAY,WAAY,QAAO;AACnC,MAAI,YAAY,WAAW,YAAY,YAAY,YAAY,SAAU,QAAO;AAChF,MAAI,YAAY,YAAY,YAAY,KAAM,QAAO;AACrD,MAAI,YAAY,aAAa,YAAY,MAAO,QAAO;AACvD,SAAO;AACT;AAEO,SAAS,mBAAmB,QAAgB;AACjD,QAAM,aAAa,OAAO,UAAU,EAAE,YAAY;AAClD,MAAI,KAAK,KAAK,UAAU,EAAG,QAAO;AAElC,QAAM,UAAU,oBAAoB,OAAO,CAAC,eAAe,WAAW,MAAM,WAAW,UAAU,CAAC;AAClG,SAAO,QAAQ,SAAS,IAAI,UAAU;AACxC;",
|
|
6
6
|
"names": ["STATUS_KEY"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@narumitw/pi-chrome-devtools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.54.0",
|
|
4
4
|
"description": "Pi extension that exposes Chrome DevTools Protocol tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"typebox": "*"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@earendil-works/pi-coding-agent": "0.
|
|
43
|
-
"@earendil-works/pi-tui": "0.
|
|
42
|
+
"@earendil-works/pi-coding-agent": "1.0.2",
|
|
43
|
+
"@earendil-works/pi-tui": "1.0.2",
|
|
44
44
|
"esbuild": "0.28.2",
|
|
45
45
|
"typebox": "1.3.34",
|
|
46
46
|
"typescript": "7.0.2"
|
|
@@ -17,16 +17,19 @@ import {
|
|
|
17
17
|
import {
|
|
18
18
|
type BrowserSettingsPatch,
|
|
19
19
|
type BrowserSettingsSource,
|
|
20
|
+
isChromeDevtoolsToolMode,
|
|
20
21
|
loadSettings,
|
|
21
22
|
parseBrowserEndpoint,
|
|
22
23
|
type SettingsLoadResult,
|
|
23
24
|
saveBrowserSettings,
|
|
25
|
+
saveToolMode,
|
|
24
26
|
saveWebMcpSettings,
|
|
25
27
|
} from "./settings.js";
|
|
26
28
|
import { sanitizeChromeDevtoolsDisplay } from "./tool-selector.js";
|
|
27
29
|
|
|
28
30
|
type BrowserSettingsScreen = "settings" | "endpoint" | "executable" | "extensions";
|
|
29
31
|
type BrowserSettingsAction =
|
|
32
|
+
| "set-tool-mode"
|
|
30
33
|
| "open-endpoint"
|
|
31
34
|
| "save-endpoint"
|
|
32
35
|
| "set-auto-launch"
|
|
@@ -98,6 +101,14 @@ export async function showChromeDevtoolsBrowserSettings(
|
|
|
98
101
|
currentValue: `${browser.extensionPaths.length} configured`,
|
|
99
102
|
action: "show-extensions",
|
|
100
103
|
},
|
|
104
|
+
{
|
|
105
|
+
id: "tool-mode",
|
|
106
|
+
label: "Tool mode",
|
|
107
|
+
description: "codemode discovery, lazy loading, or direct declarations. Saved changes require /reload.",
|
|
108
|
+
currentValue: current.load.kind === "loaded" ? current.load.settings.toolMode : "codemode",
|
|
109
|
+
values: ["codemode", "lazy", "direct"],
|
|
110
|
+
action: "set-tool-mode",
|
|
111
|
+
},
|
|
101
112
|
],
|
|
102
113
|
};
|
|
103
114
|
},
|
|
@@ -133,6 +144,18 @@ export async function showChromeDevtoolsBrowserSettings(
|
|
|
133
144
|
}),
|
|
134
145
|
},
|
|
135
146
|
actions: {
|
|
147
|
+
"set-tool-mode": async ({ value }) => {
|
|
148
|
+
if (!isChromeDevtoolsToolMode(value) || !isCurrent()) return { kind: "rejected" };
|
|
149
|
+
try {
|
|
150
|
+
await saveToolMode(value);
|
|
151
|
+
if (!isCurrent()) return { kind: "rejected" };
|
|
152
|
+
ctx.ui.notify("Chrome DevTools tool mode saved; /reload required. Running exposure is unchanged.", "info");
|
|
153
|
+
return { kind: "stay" };
|
|
154
|
+
} catch (error) {
|
|
155
|
+
if (isCurrent()) notifySaveFailure(ctx, error);
|
|
156
|
+
return { kind: "rejected" };
|
|
157
|
+
}
|
|
158
|
+
},
|
|
136
159
|
"open-endpoint": () => ({ kind: "to", screen: "endpoint" }),
|
|
137
160
|
"save-endpoint": async ({ value, signal }) => {
|
|
138
161
|
if (value === undefined) return { kind: "rejected" };
|
package/src/chrome-devtools.ts
CHANGED
|
@@ -3,9 +3,11 @@ import { shutdownManagedBrowser, startManagedBrowserSession, syncManagedBrowserS
|
|
|
3
3
|
import { setActivePageId } from "./cdp-client.js";
|
|
4
4
|
import {
|
|
5
5
|
availableChromeDevtoolsTools,
|
|
6
|
+
chromeDevtoolsToolMode,
|
|
6
7
|
configureChromeDevtoolsToolExposure,
|
|
7
|
-
createChromeDevtoolsLoadTool,
|
|
8
8
|
initializeAvailableChromeDevtoolsTools,
|
|
9
|
+
previousChromeDevtoolsTools,
|
|
10
|
+
registerChromeDevtoolsCapabilities,
|
|
9
11
|
requireEagerChromeDevtoolsToolExposure,
|
|
10
12
|
setChromeDevtoolsSessionOwner,
|
|
11
13
|
supportsNativeDeferredToolLoading,
|
|
@@ -55,14 +57,15 @@ const COMMAND_COMPLETIONS = [
|
|
|
55
57
|
{ value: "off", label: "off", description: "Compatibility alias for disable" },
|
|
56
58
|
];
|
|
57
59
|
export default function chromeDevtools(pi: ExtensionAPI) {
|
|
58
|
-
pi
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
registerChromeDevtoolsCapabilities(pi, [
|
|
61
|
+
listPagesTool,
|
|
62
|
+
selectPageTool,
|
|
63
|
+
navigateTool,
|
|
64
|
+
evaluateTool,
|
|
65
|
+
screenshotTool,
|
|
66
|
+
webMcpListToolsTool,
|
|
67
|
+
webMcpCallTool,
|
|
68
|
+
]);
|
|
66
69
|
|
|
67
70
|
pi.registerCommand("chrome-devtools", {
|
|
68
71
|
description: "Open Chrome DevTools help and tool controls",
|
|
@@ -77,7 +80,11 @@ export default function chromeDevtools(pi: ExtensionAPI) {
|
|
|
77
80
|
|
|
78
81
|
pi.on("session_start", async (_event, ctx) => {
|
|
79
82
|
const generation = ++state.sessionGeneration;
|
|
80
|
-
setChromeDevtoolsSessionOwner(pi, ctx.sessionManager);
|
|
83
|
+
setChromeDevtoolsSessionOwner(pi, ctx.sessionManager, ctx.sessionManager.getBranch());
|
|
84
|
+
// Capture before default initialization: unknown invalid files must not
|
|
85
|
+
// broaden availability, while a restored/current policy survives reload.
|
|
86
|
+
const previousAvailableTools = previousChromeDevtoolsTools(pi);
|
|
87
|
+
const previousMode = chromeDevtoolsToolMode(pi);
|
|
81
88
|
initializeAvailableChromeDevtoolsTools(pi);
|
|
82
89
|
setWebMcpSessionOwner(ctx.sessionManager);
|
|
83
90
|
replaceSessionController("Chrome DevTools session replaced");
|
|
@@ -95,6 +102,8 @@ export default function chromeDevtools(pi: ExtensionAPI) {
|
|
|
95
102
|
state.activePageId = undefined;
|
|
96
103
|
state.lastLaunchAttempt = undefined;
|
|
97
104
|
const projectTrusted = ctx.isProjectTrusted();
|
|
105
|
+
await waitForChromeDevtoolsSettings();
|
|
106
|
+
if (generation !== state.sessionGeneration) return;
|
|
98
107
|
const settings = await loadSettings({ cwd: ctx.cwd, projectTrusted });
|
|
99
108
|
if (generation !== state.sessionGeneration) return;
|
|
100
109
|
applyRuntimeBrowserSettings(settings.effectiveBrowser, settings.paths, projectTrusted);
|
|
@@ -110,17 +119,41 @@ export default function chromeDevtools(pi: ExtensionAPI) {
|
|
|
110
119
|
"warning",
|
|
111
120
|
);
|
|
112
121
|
}
|
|
113
|
-
|
|
114
|
-
|
|
122
|
+
// Tool mode/catalog are user-owned; a valid project browser section can
|
|
123
|
+
// make the aggregate result loaded even when its user source is invalid.
|
|
124
|
+
const preserveToolPolicy = settings.userFile.kind === "invalid";
|
|
125
|
+
const availableTools = preserveToolPolicy
|
|
126
|
+
? previousAvailableTools
|
|
127
|
+
: settings.kind === "loaded" && settings.settings.tools
|
|
115
128
|
? settings.settings.tools
|
|
116
|
-
:
|
|
117
|
-
configureChromeDevtoolsToolExposure(
|
|
129
|
+
: allChromeDevtoolsTools(ctx.sessionManager);
|
|
130
|
+
const provenanceWarning = configureChromeDevtoolsToolExposure(
|
|
131
|
+
pi,
|
|
132
|
+
availableTools,
|
|
133
|
+
ctx.model,
|
|
134
|
+
preserveToolPolicy ? previousMode : settings.kind === "loaded" ? settings.settings.toolMode : "codemode",
|
|
135
|
+
);
|
|
136
|
+
if (generation !== state.sessionGeneration) return;
|
|
137
|
+
if (provenanceWarning) ctx.ui.notify(provenanceWarning, "warning");
|
|
138
|
+
const active = new Set(pi.getActiveTools());
|
|
139
|
+
if (
|
|
140
|
+
chromeDevtoolsToolMode(pi) === "codemode" &&
|
|
141
|
+
!active.has("codemode") &&
|
|
142
|
+
availableChromeDevtoolsTools(pi).some((name) => !active.has(name))
|
|
143
|
+
) {
|
|
144
|
+
ctx.ui.notify(
|
|
145
|
+
"Chrome DevTools capabilities require Pi's codemode tool, but it is not active. Add '+codemode' to defaultTools and reload, or choose direct/lazy mode in Chrome DevTools settings. Chrome DevTools does not activate host tools automatically.",
|
|
146
|
+
"warning",
|
|
147
|
+
);
|
|
148
|
+
}
|
|
118
149
|
});
|
|
119
150
|
|
|
120
151
|
pi.on("model_select", (event, ctx) => {
|
|
152
|
+
const generation = state.sessionGeneration;
|
|
121
153
|
invalidateWebMcpOperations(ctx.sessionManager, "Chrome DevTools model and tool exposure changed");
|
|
122
154
|
if (!supportsNativeDeferredToolLoading(event.model)) {
|
|
123
|
-
requireEagerChromeDevtoolsToolExposure(pi);
|
|
155
|
+
const provenanceWarning = requireEagerChromeDevtoolsToolExposure(pi);
|
|
156
|
+
if (generation === state.sessionGeneration && provenanceWarning) ctx.ui.notify(provenanceWarning, "warning");
|
|
124
157
|
}
|
|
125
158
|
});
|
|
126
159
|
|