@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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/display.ts", "../../src/lazy-tools.ts", "../../src/tool-selector.ts"],
4
+ "sourcesContent": ["const MAX_SANITIZER_INPUT_CODE_UNITS = 50_000;\nconst graphemeSegmenter = new Intl.Segmenter(undefined, { granularity: \"grapheme\" });\n\nexport function sanitizeChromeDevtoolsDisplay(value: string, maxCharacters = 50_000) {\n const inputWasTruncated = value.length > MAX_SANITIZER_INPUT_CODE_UNITS;\n const boundedInput = inputWasTruncated ? truncateAtGraphemeBoundary(value, MAX_SANITIZER_INPUT_CODE_UNITS) : value;\n const normalizedLineEndings = boundedInput.replace(/\\r\\n/g, \"\\n\");\n // Neutralize controls without parsing untrusted terminal sequences; keep printable payload visible.\n const sanitized = Array.from(normalizedLineEndings, (character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n const unsafeControl =\n (codePoint >= 0 && codePoint <= 8) ||\n (codePoint >= 11 && codePoint <= 31) ||\n (codePoint >= 127 && codePoint <= 159);\n const unsafeBidi = (codePoint >= 0x202a && codePoint <= 0x202e) || (codePoint >= 0x2066 && codePoint <= 0x2069);\n const loneSurrogate = character.length === 1 && codePoint >= 0xd800 && codePoint <= 0xdfff;\n return unsafeControl || unsafeBidi || loneSurrogate ? \"\uFFFD\" : character;\n }).join(\"\");\n const outputLimit = Math.min(maxCharacters, MAX_SANITIZER_INPUT_CODE_UNITS);\n if (!inputWasTruncated && sanitized.length <= outputLimit) return sanitized;\n\n return `${truncateAtGraphemeBoundary(sanitized, Math.max(0, outputLimit - 1))}\u2026`;\n}\n\nfunction truncateAtGraphemeBoundary(value: string, maxCodeUnits: number) {\n if (value.length <= maxCodeUnits) return value;\n const boundedLookahead = value.slice(0, Math.max(0, maxCodeUnits) + 2);\n let safeEnd = 0;\n for (const { index, segment } of graphemeSegmenter.segment(boundedLookahead)) {\n const segmentEnd = index + segment.length;\n if (segmentEnd > maxCodeUnits) break;\n safeEnd = segmentEnd;\n }\n return value.slice(0, safeEnd);\n}\n", "import {\n defineTool,\n type ExtensionAPI,\n type ExtensionContext,\n type ToolDefinition,\n} from \"@earendil-works/pi-coding-agent\";\nimport { Type } from \"typebox\";\nimport { sanitizeChromeDevtoolsDisplay } from \"./display.js\";\nimport { webMcpEnabled } from \"./runtime.js\";\nimport type { ChromeDevToolsToolMode } from \"./settings.js\";\nimport { CHROME_DEVTOOLS_TOOL_NAMES, type ChromeDevToolsToolName, isWebMcpToolName } from \"./tool-names.js\";\n\nexport const CHROME_DEVTOOLS_LOAD_TOOL_NAME = \"chrome_devtools_load\";\n\nconst AVAILABLE_TOOLS_STORE = Symbol.for(\"@narumitw/pi-chrome-devtools.available-tools-store\");\ntype ChromeDevtoolsGlobal = typeof globalThis & {\n [AVAILABLE_TOOLS_STORE]?: WeakMap<ExtensionAPI, Set<ChromeDevToolsToolName>>;\n};\nconst sharedGlobal = globalThis as ChromeDevtoolsGlobal;\nconst existingAvailableToolsStore = sharedGlobal[AVAILABLE_TOOLS_STORE];\nconst availableToolsByApi = existingAvailableToolsStore ?? new WeakMap<ExtensionAPI, Set<ChromeDevToolsToolName>>();\nif (!existingAvailableToolsStore) sharedGlobal[AVAILABLE_TOOLS_STORE] = availableToolsByApi;\nconst lazyExposureByApi = new WeakMap<ExtensionAPI, boolean>();\nconst sessionOwnerByApi = new WeakMap<ExtensionAPI, object>();\n// Public sessionManager identity survives factory/API rebuilds during /reload.\n// A redundant host selection of an already-owned active name has no public\n// provenance signal; keep known ownership rather than treating carryover as intent.\nconst PROVENANCE_STORE = Symbol.for(\"@narumitw/pi-chrome-devtools.activation-provenance\");\nconst PROVENANCE_ENTRY = \"chrome-devtools.activation-provenance\";\ntype ActivationOwnership = {\n explicit: Set<string>;\n owned: Set<string>;\n available?: Set<ChromeDevToolsToolName>;\n mode?: ChromeDevToolsToolMode;\n published?: Set<ChromeDevToolsToolName>;\n serialized?: string;\n};\nconst provenanceGlobal = globalThis as typeof globalThis & {\n [PROVENANCE_STORE]?: WeakMap<object, ActivationOwnership>;\n};\nconst ownedBySession = provenanceGlobal[PROVENANCE_STORE] ?? new WeakMap<object, ActivationOwnership>();\nprovenanceGlobal[PROVENANCE_STORE] = ownedBySession;\nconst modeByApi = new WeakMap<ExtensionAPI, ChromeDevToolsToolMode>();\nconst loaderRegistered = new WeakSet<ExtensionAPI>();\n\nfunction retainedExplicitTools(pi: ExtensionAPI, before: readonly string[]) {\n const owner = sessionOwnerByApi.get(pi);\n const ownership = owner ? ownedBySession.get(owner) : undefined;\n const observed = new Set(before);\n // Only our own last publication can prove suppression rather than withdrawal.\n return CHROME_DEVTOOLS_TOOL_NAMES.filter(\n (name) => ownership?.explicit.has(name) && (observed.has(name) || ownership.published?.has(name) === false),\n );\n}\n\nfunction publishActiveTools(pi: ExtensionAPI, names: string[], before: readonly string[]) {\n pi.setActiveTools(names);\n recordOwnership(pi, before);\n}\n\nfunction recordOwnership(pi: ExtensionAPI, before: readonly string[]) {\n const names = pi.getActiveTools();\n const owner = sessionOwnerByApi.get(pi);\n if (!owner) return;\n const ownership: ActivationOwnership = ownedBySession.get(owner) ?? {\n explicit: new Set<string>(),\n owned: new Set<string>(),\n };\n const observed = new Set(before);\n for (const name of ownership.explicit) {\n // Absence after our own suppression is not a host withdrawal. Only a\n // previously published activation disappearing is observable withdrawal.\n if (!observed.has(name) && (ownership.published?.has(name as ChromeDevToolsToolName) ?? true))\n ownership.explicit.delete(name);\n }\n for (const name of before)\n if (CHROME_DEVTOOLS_TOOL_NAMES.includes(name as ChromeDevToolsToolName) && !ownership.owned.has(name))\n ownership.explicit.add(name);\n if (chromeDevtoolsToolMode(pi) !== \"codemode\") {\n for (const name of names)\n if (CHROME_DEVTOOLS_TOOL_NAMES.includes(name as ChromeDevToolsToolName) && !ownership.explicit.has(name))\n ownership.owned.add(name);\n }\n if (chromeDevtoolsToolMode(pi) === \"codemode\") ownership.owned.clear();\n const published = new Set(names);\n ownership.published = new Set(CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => published.has(name)));\n ownedBySession.set(owner, ownership);\n persistOwnership(pi, ownership);\n}\n\nfunction ownershipData(ownership: ActivationOwnership) {\n return {\n version: 1,\n explicit: CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => ownership.explicit.has(name)),\n owned: CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => ownership.owned.has(name)),\n available: ownership.available\n ? CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => ownership.available?.has(name))\n : undefined,\n mode: ownership.mode,\n published: ownership.published\n ? CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => ownership.published?.has(name))\n : undefined,\n };\n}\n\nclass ActivationProvenanceError extends Error {\n constructor(cause: unknown) {\n super(cause instanceof Error ? cause.message : String(cause), { cause });\n }\n}\n\nfunction formatProvenanceWarning(error: ActivationProvenanceError) {\n return sanitizeChromeDevtoolsDisplay(\n `Activation ownership could not be saved: ${error.message}. Activation is not rolled back; durable ownership may be incomplete until a later loader call or lifecycle update retries successfully.`,\n );\n}\n\nfunction publishLifecycleTools(pi: ExtensionAPI, names: string[], before: readonly string[]) {\n try {\n publishActiveTools(pi, names, before);\n } catch (error) {\n if (!(error instanceof ActivationProvenanceError)) throw error;\n // Exposure has already succeeded. Lifecycle events are not rejected saves;\n // keep the accepted policy and let callers warn without stopping setup.\n return formatProvenanceWarning(error);\n }\n}\n\nfunction persistOwnership(pi: ExtensionAPI, ownership: ActivationOwnership) {\n ownership.available = new Set(configuredChromeDevtoolsTools(pi));\n ownership.mode = chromeDevtoolsToolMode(pi);\n const data = ownershipData(ownership);\n const serialized = JSON.stringify(data);\n if (ownership.serialized === serialized) return;\n try {\n pi.appendEntry(PROVENANCE_ENTRY, data);\n ownership.serialized = serialized;\n } catch (error) {\n // Pi can advance its in-memory branch before disk persistence throws. Force\n // recovery to append its policy even when it matches the last saved record.\n ownership.serialized = undefined;\n throw new ActivationProvenanceError(error);\n }\n}\n\nfunction restoredOwnership(\n entries: readonly { type: string; customType?: string; data?: unknown }[],\n): ActivationOwnership | undefined {\n for (let index = entries.length - 1; index >= 0; index--) {\n const entry = entries[index];\n if (entry.type !== \"custom\" || entry.customType !== PROVENANCE_ENTRY) continue;\n const data = entry.data;\n if (typeof data !== \"object\" || data === null || Array.isArray(data)) return undefined;\n const record = data as Record<string, unknown>;\n const validNames = (value: unknown): value is ChromeDevToolsToolName[] =>\n Array.isArray(value) &&\n value.length <= CHROME_DEVTOOLS_TOOL_NAMES.length &&\n value.every((name) => CHROME_DEVTOOLS_TOOL_NAMES.includes(name));\n if (\n record.version !== 1 ||\n !validNames(record.explicit) ||\n !validNames(record.owned) ||\n (record.available !== undefined && !validNames(record.available)) ||\n (record.published !== undefined && !validNames(record.published)) ||\n (record.mode !== undefined && record.mode !== \"codemode\" && record.mode !== \"lazy\" && record.mode !== \"direct\") ||\n record.owned.some((name) => (record.explicit as string[]).includes(name))\n )\n return undefined;\n const restored = {\n explicit: new Set<string>(record.explicit),\n owned: new Set<string>(record.owned),\n available: validNames(record.available) ? new Set(record.available) : undefined,\n mode: record.mode as ChromeDevToolsToolMode | undefined,\n published: validNames(record.published) ? new Set(record.published) : undefined,\n };\n return { ...restored, serialized: JSON.stringify(ownershipData(restored)) };\n }\n return undefined;\n}\nconst definitionsByApi = new WeakMap<ExtensionAPI, ToolDefinition[]>();\n\nexport function registerChromeDevtoolsCapabilities(pi: ExtensionAPI, tools: ToolDefinition[]) {\n definitionsByApi.set(pi, tools);\n for (const tool of tools) pi.registerTool({ ...tool, exposure: \"codemode\", defaultActive: false });\n // Keep a carried-over predecessor loader observable until session_start.\n // Pi drops unregistered/hidden active names while rebuilding on /reload.\n pi.registerTool({\n ...createChromeDevtoolsLoadTool(pi),\n exposure: \"codemode\",\n defaultActive: false,\n promptSnippet: undefined,\n promptGuidelines: undefined,\n });\n loaderRegistered.add(pi);\n}\n\nexport function chromeDevtoolsToolMode(pi: ExtensionAPI): ChromeDevToolsToolMode {\n return modeByApi.get(pi) ?? \"codemode\";\n}\n\nfunction refreshExposure(pi: ExtensionAPI) {\n const available = effectiveAvailableTools(pi);\n const mode = chromeDevtoolsToolMode(pi);\n for (const tool of definitionsByApi.get(pi) ?? []) {\n pi.registerTool({\n ...tool,\n defaultActive: false,\n exposure: available.has(tool.name as ChromeDevToolsToolName)\n ? mode === \"codemode\"\n ? \"codemode\"\n : \"direct\"\n : \"hidden\",\n });\n }\n if (mode === \"lazy\") {\n pi.registerTool({ ...createChromeDevtoolsLoadTool(pi), defaultActive: false });\n loaderRegistered.add(pi);\n } else if (loaderRegistered.has(pi)) {\n pi.registerTool({\n ...createChromeDevtoolsLoadTool(pi),\n exposure: \"hidden\",\n promptSnippet: undefined,\n promptGuidelines: undefined,\n });\n }\n}\n\nconst SEARCH_TEXT: Record<ChromeDevToolsToolName, string> = {\n chrome_devtools_list_pages: \"list open inspectable chrome browser pages tabs targets\",\n chrome_devtools_select_page: \"select choose active chrome browser page tab target\",\n chrome_devtools_navigate: \"navigate open create chrome browser page url website\",\n chrome_devtools_evaluate: \"evaluate run javascript expression dom inspect chrome browser page\",\n chrome_devtools_screenshot: \"capture screenshot png image visual chrome browser page\",\n chrome_devtools_webmcp_list_tools: \"list discover page provided website webmcp tools capabilities experimental\",\n chrome_devtools_webmcp_call_tool: \"call invoke page provided website webmcp tool confirmation experimental\",\n};\n\nexport function setChromeDevtoolsSessionOwner(\n pi: ExtensionAPI,\n owner: object,\n entries?: readonly { type: string; customType?: string; data?: unknown }[],\n) {\n sessionOwnerByApi.set(pi, owner);\n if (entries) {\n const ownership = restoredOwnership(entries);\n if (ownership) {\n const pending = ownedBySession.get(owner);\n // An append can advance this branch before persistence fails. Restoring\n // that same validated policy must not erase its pending retry marker.\n if (\n pending &&\n pending.serialized === undefined &&\n ownership.serialized === JSON.stringify(ownershipData(pending))\n )\n ownership.serialized = undefined;\n ownedBySession.set(owner, ownership);\n } else {\n // Tree navigation can reuse a manager while replacing its active branch.\n // Never lend another branch's activation or policy provenance to it.\n ownedBySession.delete(owner);\n availableToolsByApi.delete(pi);\n modeByApi.delete(pi);\n }\n }\n const ownership = ownedBySession.get(owner);\n if (ownership?.available) setAvailableTools(pi, [...ownership.available]);\n if (ownership?.mode) modeByApi.set(pi, ownership.mode);\n}\n\nexport function initializeAvailableChromeDevtoolsTools(pi: ExtensionAPI) {\n if (availableToolsByApi.has(pi)) return;\n // Availability is configuration, not the provider-visible declaration list.\n // In particular, codemode starts with no active capability names.\n setAvailableTools(pi, CHROME_DEVTOOLS_TOOL_NAMES);\n}\n\nexport function configureChromeDevtoolsToolExposure(\n pi: ExtensionAPI,\n availableTools: readonly ChromeDevToolsToolName[],\n model?: ExtensionContext[\"model\"],\n mode: ChromeDevToolsToolMode = \"codemode\",\n) {\n modeByApi.set(pi, mode);\n setAvailableTools(pi, availableTools);\n const available = effectiveAvailableTools(pi);\n const lazyExposure = mode === \"lazy\" && supportsNativeDeferredToolLoading(model);\n lazyExposureByApi.set(pi, lazyExposure);\n const before = pi.getActiveTools();\n const owner = sessionOwnerByApi.get(pi);\n let ownership = owner ? ownedBySession.get(owner) : undefined;\n if (owner && !ownership && before.includes(CHROME_DEVTOOLS_LOAD_TOOL_NAME)) {\n // The predecessor always activated its loader but had no provenance store.\n // With no public activation-origin API, this loader cohort is migrated as\n // extension-owned; capability-only host selections remain explicit.\n ownership = {\n explicit: new Set(),\n owned: new Set(before.filter((name) => CHROME_DEVTOOLS_TOOL_NAMES.includes(name as ChromeDevToolsToolName))),\n };\n ownedBySession.set(owner, ownership);\n }\n const owned = ownership?.owned;\n const exposedTools =\n mode === \"codemode\"\n ? unique([...before.filter((name) => !owned?.has(name)), ...retainedExplicitTools(pi, before)]).filter((name) =>\n available.has(name as ChromeDevToolsToolName),\n )\n : lazyExposure\n ? []\n : CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => available.has(name));\n const nonCapabilityTools = pi\n .getActiveTools()\n .filter((name) => !CHROME_DEVTOOLS_TOOL_NAMES.includes(name as ChromeDevToolsToolName));\n refreshExposure(pi);\n const target = new Set([\n ...nonCapabilityTools.filter((name) => name !== CHROME_DEVTOOLS_LOAD_TOOL_NAME),\n ...(mode === \"lazy\" ? [CHROME_DEVTOOLS_LOAD_TOOL_NAME] : []),\n ...exposedTools,\n ]);\n return publishLifecycleTools(pi, unique([...before.filter((name) => target.has(name)), ...target]), before);\n}\n\nexport function requireEagerChromeDevtoolsToolExposure(pi: ExtensionAPI) {\n if (chromeDevtoolsToolMode(pi) !== \"lazy\") return;\n lazyExposureByApi.set(pi, false);\n const active = pi.getActiveTools();\n const available = availableChromeDevtoolsTools(pi);\n return publishLifecycleTools(pi, unique([...active, CHROME_DEVTOOLS_LOAD_TOOL_NAME, ...available]), active);\n}\n\nexport function applyAvailableChromeDevtoolsTools(\n pi: ExtensionAPI,\n availableTools: readonly ChromeDevToolsToolName[],\n restoredActiveTools?: readonly string[],\n) {\n setAvailableTools(pi, availableTools);\n const available = effectiveAvailableTools(pi);\n const lazyExposure = lazyExposureByApi.get(pi) === true;\n const before = restoredActiveTools\n ? restoreCapabilityPositions(pi.getActiveTools(), restoredActiveTools, available)\n : pi.getActiveTools();\n const active = before.filter(\n (name) =>\n !CHROME_DEVTOOLS_TOOL_NAMES.includes(name as ChromeDevToolsToolName) ||\n (lazyExposure && available.has(name as ChromeDevToolsToolName)),\n );\n const mode = chromeDevtoolsToolMode(pi);\n const eagerTools =\n mode === \"codemode\"\n ? unique([...before, ...retainedExplicitTools(pi, before)]).filter((name) =>\n available.has(name as ChromeDevToolsToolName),\n )\n : lazyExposure\n ? []\n : CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => available.has(name));\n refreshExposure(pi);\n const target = new Set([\n ...active.filter((name) => name !== CHROME_DEVTOOLS_LOAD_TOOL_NAME),\n ...(mode === \"lazy\" ? [CHROME_DEVTOOLS_LOAD_TOOL_NAME] : []),\n ...eagerTools,\n ]);\n publishActiveTools(pi, unique([...before.filter((name) => target.has(name)), ...target]), before);\n}\n\nexport function chromeDevtoolsToolExposureMode(pi: ExtensionAPI) {\n return chromeDevtoolsToolMode(pi) === \"codemode\"\n ? \"codemode\"\n : lazyExposureByApi.get(pi) === true\n ? \"native deferred\"\n : \"eager\";\n}\n\nexport function supportsNativeDeferredToolLoading(model: ExtensionContext[\"model\"]): boolean {\n if (!model) return false;\n if (model.api === \"anthropic-messages\") {\n // Fireworks Messages requires the canonical ToolSearch/tool_search loader name.\n // chrome_devtools_load stays package-specific so independently installed loaders cannot collide.\n if (model.provider === \"fireworks\") return false;\n const configured = compatBoolean(model.compat, \"supportsToolReferences\");\n if (configured !== undefined) return configured;\n if (model.provider !== \"anthropic\" || model.id.includes(\"haiku\")) return false;\n const version = model.id.match(/^claude-(?:opus|sonnet|fable)-(\\d+)(?:-(\\d+))?(?:-|$)/);\n if (!version) return false;\n const major = Number(version[1]);\n const minor = version[2] && version[2].length < 8 ? Number(version[2]) : 0;\n return major > 4 || (major === 4 && minor >= 5);\n }\n if (model.api === \"openai-completions\") {\n return compatString(model.compat, \"deferredToolsMode\") === \"kimi\";\n }\n if (model.api === \"openai-responses\" || model.api === \"openai-codex-responses\") {\n return (\n compatBoolean(model.compat, \"supportsAdditionalTools\") === true ||\n compatBoolean(model.compat, \"supportsToolSearch\") === true\n );\n }\n return false;\n}\n\nexport function availableChromeDevtoolsTools(pi: ExtensionAPI) {\n const available = effectiveAvailableTools(pi);\n return CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => available.has(name));\n}\n\nexport function previousChromeDevtoolsTools(pi: ExtensionAPI) {\n if (availableToolsByApi.has(pi)) return configuredChromeDevtoolsTools(pi);\n // An unknown catalog cannot authorize new capabilities. Preserve only names\n // already explicitly active; this fallback is used for invalid settings only.\n const active = new Set(pi.getActiveTools());\n return CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => active.has(name));\n}\n\nexport function configuredChromeDevtoolsTools(pi: ExtensionAPI) {\n const available = availableToolsByApi.get(pi) ?? new Set();\n return CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => available.has(name));\n}\n\nexport function createChromeDevtoolsLoadTool(pi: ExtensionAPI) {\n return defineTool({\n name: CHROME_DEVTOOLS_LOAD_TOOL_NAME,\n label: \"Chrome DevTools: Load Tools\",\n description:\n \"Find and enable Chrome DevTools browser tools relevant to a task. Loaded tools remain available for the session.\",\n promptSnippet: \"Load Chrome DevTools browser capabilities on demand\",\n promptGuidelines: [\n \"Use chrome_devtools_load when a task requires inspecting or controlling a Chrome browser and the needed chrome_devtools_* capability is not active.\",\n ],\n parameters: Type.Object({\n query: Type.String({\n description: \"Browser capability or task to find tools for.\",\n maxLength: 500,\n }),\n limit: Type.Optional(\n Type.Integer({\n description: \"Maximum tools to load. Defaults to 3.\",\n minimum: 1,\n maximum: 5,\n }),\n ),\n }),\n async execute(_toolCallId, params, signal, _onUpdate, ctx) {\n signal?.throwIfAborted();\n setChromeDevtoolsSessionOwner(pi, ctx.sessionManager);\n const available = new Set(availableChromeDevtoolsTools(pi));\n const matches = matchChromeDevtoolsTools(params.query, params.limit ?? 3, available);\n const active = pi.getActiveTools();\n const activeSet = new Set(active);\n const added = matches.filter((name) => !activeSet.has(name));\n let provenanceWarning: string | undefined;\n try {\n if (added.length > 0) {\n publishActiveTools(pi, unique([...active, ...added]), active);\n } else {\n const ownership = ownedBySession.get(ctx.sessionManager);\n if (ownership && ownership.serialized === undefined) recordOwnership(pi, active);\n }\n } catch (error) {\n if (!(error instanceof ActivationProvenanceError)) throw error;\n // Native loading must remain additive. Activation succeeded; do not\n // remove tools or claim it failed because its bookkeeping could not save.\n provenanceWarning = formatProvenanceWarning(error);\n }\n\n const text =\n matches.length === 0\n ? \"No available Chrome DevTools tools matched the query.\"\n : added.length > 0\n ? `Loaded Chrome DevTools tools: ${added.join(\", \")}`\n : `Matching Chrome DevTools tools are already loaded: ${matches.join(\", \")}`;\n return {\n content: [{ type: \"text\" as const, text: provenanceWarning ? `${text}\\nWarning: ${provenanceWarning}` : text }],\n details: { matches, added, ...(provenanceWarning ? { provenanceWarning } : {}) },\n };\n },\n });\n}\n\nfunction matchChromeDevtoolsTools(query: string, limit: number, available: ReadonlySet<ChromeDevToolsToolName>) {\n const terms = query\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((term) => term.length >= 2);\n if (terms.length === 0) return [];\n return CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => available.has(name))\n .map((name, index) => ({\n name,\n index,\n score: terms.reduce((score, term) => score + (SEARCH_TEXT[name].includes(term) ? 1 : 0), 0),\n }))\n .filter((match) => match.score > 0)\n .sort((left, right) => right.score - left.score || left.index - right.index)\n .slice(0, limit)\n .map((match) => match.name);\n}\n\nfunction setAvailableTools(pi: ExtensionAPI, availableTools: readonly ChromeDevToolsToolName[]) {\n const available = new Set(availableTools);\n availableToolsByApi.set(pi, available);\n return available;\n}\n\nfunction effectiveAvailableTools(pi: ExtensionAPI) {\n const configured = availableToolsByApi.get(pi) ?? new Set();\n const owner = sessionOwnerByApi.get(pi);\n const enabled = owner !== undefined && webMcpEnabled(owner);\n return new Set(\n CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => configured.has(name) && (enabled || !isWebMcpToolName(name))),\n );\n}\n\nfunction compatBoolean(value: unknown, key: string) {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return undefined;\n const record = value as Record<string, unknown>;\n return typeof record[key] === \"boolean\" ? record[key] : undefined;\n}\n\nfunction compatString(value: unknown, key: string) {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return undefined;\n const record = value as Record<string, unknown>;\n return typeof record[key] === \"string\" ? record[key] : undefined;\n}\n\n// Rollback may reinsert capabilities, but must not undo unrelated additions,\n// removals, or ordering changes made while persistence was awaiting I/O.\nfunction restoreCapabilityPositions(\n current: readonly string[],\n previous: readonly string[],\n available: ReadonlySet<ChromeDevToolsToolName>,\n) {\n const restored = [...current];\n for (const [index, name] of previous.entries()) {\n if (!available.has(name as ChromeDevToolsToolName) || restored.includes(name)) continue;\n const following = previous.slice(index + 1).find((candidate) => restored.includes(candidate));\n const insertion = following === undefined ? restored.length : restored.indexOf(following);\n restored.splice(insertion, 0, name);\n }\n return restored;\n}\n\nfunction unique(values: readonly string[]) {\n return [...new Set(values)];\n}\n", "import type { ExtensionAPI, ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport {\n browserCandidateHint,\n browserLifecycleState,\n browserSettingsForOwner,\n devToolsEndpoint,\n endpointConfigHint,\n endpointSourceLabel,\n launchAttemptLines,\n launchHint,\n launchModeLabel,\n managedBrowserForOwner,\n} from \"./browser-manager.js\";\nimport { sanitizeChromeDevtoolsDisplay } from \"./display.js\";\nimport {\n applyAvailableChromeDevtoolsTools,\n availableChromeDevtoolsTools,\n CHROME_DEVTOOLS_LOAD_TOOL_NAME,\n chromeDevtoolsToolExposureMode,\n chromeDevtoolsToolMode,\n configuredChromeDevtoolsTools,\n} from \"./lazy-tools.js\";\nimport { invalidateWebMcpOperations, state, webMcpEnabled } from \"./runtime.js\";\nimport {\n loadSettings,\n type SettingsLoadResult,\n saveSettings,\n settingsFilePath,\n ToolCatalogApplicationError,\n} from \"./settings.js\";\nimport {\n CHROME_DEVTOOLS_TOOL_NAMES,\n type ChromeDevToolsToolName,\n CORE_CHROME_DEVTOOLS_TOOL_NAMES,\n isWebMcpToolName,\n} from \"./tool-names.js\";\n\nexport { sanitizeChromeDevtoolsDisplay };\n\ntype CommandContext = ExtensionCommandContext;\n\nfunction formatError(error: unknown) {\n return error instanceof Error ? error.message : String(error);\n}\n\ninterface ToolStatusSummary {\n availabilityStatus: \"enabled\" | \"disabled\" | \"partial\";\n availableChromeToolCount: number;\n loadedChromeToolCount: number;\n activeNonChromeToolCount: number;\n capabilityCount: number;\n}\n\ntype ToolSelectionSaveResult = \"saved\" | \"active-tools-changed\" | \"failed\";\n\nexport async function updateChromeDevtoolsTools(\n pi: ExtensionAPI,\n ctx: CommandContext,\n selectedTools: readonly ChromeDevToolsToolName[],\n action: string,\n) {\n const generation = state.sessionGeneration;\n const result = await transactSelectedTools(pi, ctx, selectedTools, generation);\n if (result !== \"saved\" || generation !== state.sessionGeneration) return;\n const status = await buildToolStatusMessage(pi, ctx.sessionManager);\n if (generation !== state.sessionGeneration) return;\n ctx.ui.notify(`Chrome DevTools tool catalog ${action}.\\n\\n${status}`, \"info\");\n}\n\nexport async function setSelectedChromeDevtoolsTools(\n pi: ExtensionAPI,\n ctx: CommandContext,\n selectedTools: readonly ChromeDevToolsToolName[],\n expectedActiveTools: readonly ChromeDevToolsToolName[],\n): Promise<ToolSelectionSaveResult> {\n return transactSelectedTools(pi, ctx, selectedTools, state.sessionGeneration, expectedActiveTools);\n}\n\nlet toolTransactionQueue = Promise.resolve();\n\nexport async function waitForChromeDevtoolsSettings(): Promise<void> {\n await toolTransactionQueue;\n}\n\nfunction transactSelectedTools(\n pi: ExtensionAPI,\n ctx: CommandContext,\n selectedTools: readonly ChromeDevToolsToolName[],\n expectedGeneration: number,\n expectedActiveTools?: readonly ChromeDevToolsToolName[],\n): Promise<ToolSelectionSaveResult> {\n const acceptedTools = [...selectedTools];\n const expectedTools = expectedActiveTools ? [...expectedActiveTools] : undefined;\n const operation = toolTransactionQueue.then(() =>\n transactSelectedToolsNow(pi, ctx, acceptedTools, expectedGeneration, expectedTools),\n );\n toolTransactionQueue = operation.then(\n () => undefined,\n () => undefined,\n );\n return operation;\n}\n\nasync function transactSelectedToolsNow(\n pi: ExtensionAPI,\n ctx: CommandContext,\n selectedTools: readonly ChromeDevToolsToolName[],\n expectedGeneration: number,\n expectedActiveTools?: readonly ChromeDevToolsToolName[],\n): Promise<ToolSelectionSaveResult> {\n if (expectedGeneration !== state.sessionGeneration) {\n // Accepted durable intents outlive their UI/session; never apply to a replacement runtime.\n try {\n if (expectedActiveTools) {\n // Earlier accepted intents can be durable without publishing to this\n // retired API. Compare the policy the replacement will actually load.\n const settings = await loadSettings();\n if (settings.userFile.kind !== \"invalid\") {\n const catalog = new Set(\n settings.kind === \"loaded\" && settings.settings.tools\n ? settings.settings.tools\n : CHROME_DEVTOOLS_TOOL_NAMES,\n );\n const current = CHROME_DEVTOOLS_TOOL_NAMES.filter(\n (name) => catalog.has(name) && (settings.effectiveWebMcpEnabled || !isWebMcpToolName(name)),\n );\n if (!arraysEqual(current, expectedActiveTools)) return \"active-tools-changed\";\n }\n }\n await persistSettings(selectedTools);\n } catch {\n // No live owner remains to notify; storage stays unchanged on failure.\n }\n return \"failed\";\n }\n if (expectedActiveTools && !arraysEqual(availableChromeDevtoolsTools(pi), expectedActiveTools)) {\n ctx.ui.notify(\n \"Browser tool selection changed while review was open. Review the current state, then apply again.\",\n \"warning\",\n );\n return \"active-tools-changed\";\n }\n try {\n await persistSettings(selectedTools, () => {\n if (expectedGeneration !== state.sessionGeneration) return;\n // Capture at publication, not before I/O: host edits during the save are\n // current intent. A persistence failure never touches runtime policy.\n const previousActiveTools = pi.getActiveTools();\n const previousAvailableTools = availableChromeDevtoolsTools(pi);\n const previousConfiguredTools = configuredChromeDevtoolsTools(pi);\n try {\n const previousWebMcpTools = previousAvailableTools.filter(isWebMcpToolName);\n applyChromeDevtoolsTools(pi, selectedTools);\n const publishedWebMcpTools = availableChromeDevtoolsTools(pi).filter(isWebMcpToolName);\n // Abort is irreversible: rejected publication must leave current work\n // alive, and gated configured names are not an effective policy change.\n if (!arraysEqual(previousWebMcpTools, publishedWebMcpTools)) {\n invalidateWebMcpOperations(ctx.sessionManager, \"Chrome DevTools WebMCP gateway availability changed\");\n }\n } catch (error) {\n if (expectedGeneration === state.sessionGeneration) {\n try {\n applyAvailableChromeDevtoolsTools(pi, previousConfiguredTools, previousActiveTools);\n } catch (rollbackError) {\n throw new Error(`${formatError(error)}; active-tool rollback failed: ${formatError(rollbackError)}`, {\n cause: error,\n });\n }\n }\n // The storage queue restores only the tool-owned durable fields before\n // it releases dependent settings reads or replacement session starts.\n throw error;\n }\n });\n return expectedGeneration === state.sessionGeneration ? \"saved\" : \"failed\";\n } catch (error) {\n if (expectedGeneration !== state.sessionGeneration) return \"failed\";\n ctx.ui.notify(\n sanitizeChromeDevtoolsDisplay(\n error instanceof ToolCatalogApplicationError\n ? `Chrome DevTools tool application failed: ${formatError(error)}`\n : `Chrome DevTools settings save failed; active tools unchanged: ${formatError(error)}`,\n ),\n \"warning\",\n );\n return \"failed\";\n }\n}\n\nfunction arraysEqual<T>(left: readonly T[], right: readonly T[]) {\n return left.length === right.length && left.every((value, index) => value === right[index]);\n}\n\nexport function applyChromeDevtoolsTools(pi: ExtensionAPI, selectedTools: readonly ChromeDevToolsToolName[]) {\n applyAvailableChromeDevtoolsTools(pi, selectedTools);\n}\n\nfunction getToolStatusSummary(pi: ExtensionAPI, owner: object): ToolStatusSummary {\n const chromeToolNames = new Set<string>(CHROME_DEVTOOLS_TOOL_NAMES);\n const activeToolNames = new Set(pi.getActiveTools());\n const loadedChromeToolCount = CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => activeToolNames.has(name)).length;\n const availableChromeToolCount = availableChromeDevtoolsTools(pi).length;\n const activeNonChromeToolCount = Array.from(activeToolNames).filter(\n (name) => !chromeToolNames.has(name) && name !== CHROME_DEVTOOLS_LOAD_TOOL_NAME,\n ).length;\n const capabilityCount = effectiveCatalog(owner).length;\n const availabilityStatus =\n availableChromeToolCount === capabilityCount ? \"enabled\" : availableChromeToolCount === 0 ? \"disabled\" : \"partial\";\n\n return {\n availabilityStatus,\n availableChromeToolCount,\n loadedChromeToolCount,\n activeNonChromeToolCount,\n capabilityCount,\n };\n}\n\nexport async function buildToolStatusMessage(pi: ExtensionAPI, owner: object) {\n const generation = state.sessionGeneration;\n await waitForChromeDevtoolsSettings();\n if (generation !== state.sessionGeneration) return \"\";\n const settings = await loadSettings();\n // Command callers discard replaced-session output; avoid retired API reads.\n if (generation !== state.sessionGeneration) return \"\";\n // Do not combine a pre-save runtime summary with a post-save document.\n // All saved labels use this one snapshot; no I/O follows the runtime read.\n const summary = getToolStatusSummary(pi, owner);\n const persistedSetting = persistedSettingLabel(settings);\n const savedMode =\n settings.userFile.kind === \"invalid\"\n ? undefined\n : settings.kind === \"loaded\"\n ? settings.settings.toolMode\n : \"codemode\";\n return sanitizeChromeDevtoolsDisplay(\n [\n `Chrome DevTools tools available: ${formatRuntimeStatus(summary)}`,\n `Running tool mode: ${chromeDevtoolsToolMode(pi)}`,\n `Tool exposure: ${chromeDevtoolsToolExposureMode(pi)}`,\n `Saved tool mode: ${savedMode ?? \"unavailable (invalid user settings)\"}`,\n ...(savedMode !== undefined && savedMode !== chromeDevtoolsToolMode(pi)\n ? [\"Tool mode change pending; /reload or session replacement required.\"]\n : []),\n `Loaded capability tools this session: ${summary.loadedChromeToolCount}/${summary.capabilityCount}`,\n `WebMCP: ${webMcpEnabled(owner) ? \"enabled \u00B7 experimental \u00B7 confirmation required for every call\" : \"disabled \u00B7 experimental\"}`,\n `Loader: ${pi.getActiveTools().includes(CHROME_DEVTOOLS_LOAD_TOOL_NAME) ? \"active\" : \"inactive\"}`,\n `Persisted tool catalog: ${persistedSetting}`,\n ...browserSettingsStatusLines(owner),\n ...(state.settingsNotice ? [`Settings note: ${state.settingsNotice}`] : []),\n `Other active tools preserved: ${summary.activeNonChromeToolCount}`,\n `Endpoint: ${devToolsEndpoint(owner)}`,\n `Endpoint source: ${endpointSourceLabel(owner)}`,\n `Launch mode: ${launchModeLabel(owner)}`,\n ...launchAttemptLines(owner),\n ].join(\"\\n\"),\n );\n}\n\nexport function buildQuickstartMessage(owner: object) {\n return buildSettingsSetupMessage(owner);\n}\n\nexport function buildBrowserStatusMessage(owner?: object) {\n const browser = browserSettingsForOwner(owner);\n const lifecycle = browserLifecycleState(owner);\n const webMcpIsEnabled = owner ? webMcpEnabled(owner) : false;\n const browserState =\n lifecycle === \"starting\"\n ? \"starting managed browser\"\n : lifecycle === \"running\"\n ? \"managed browser running\"\n : lifecycle === \"exited\"\n ? \"managed browser exited\"\n : lifecycle === \"failed\"\n ? \"last launch failed\"\n : \"not started; connection has not been checked\";\n const needsRecovery = lifecycle === \"exited\" || lifecycle === \"failed\";\n return sanitizeChromeDevtoolsDisplay(\n [\n `Browser: ${browserState}`,\n \"Viewing this status does not probe the endpoint or launch Chrome.\",\n `Endpoint: ${devToolsEndpoint(owner)}`,\n `Endpoint source: ${endpointSourceLabel(owner)}`,\n `Launch mode: ${launchModeLabel(owner)}`,\n `Unpacked extensions: ${browser.extensionPaths.length} (${browser.extensionPathsSource})`,\n `WebMCP: ${webMcpIsEnabled ? \"enabled \u00B7 experimental\" : \"disabled \u00B7 experimental\"}`,\n ...(webMcpIsEnabled && !managedBrowserForOwner(owner)?.ready\n ? [\"WebMCP warning: attached browser profiles may contain everyday authenticated sessions and sensitive state.\"]\n : []),\n ...(browser.extensionPaths.length > 0\n ? [\"Unpacked extensions execute trusted browser code in an isolated managed browser.\"]\n : []),\n ...launchAttemptLines(owner),\n ...(needsRecovery ? [launchHint(owner), endpointConfigHint()] : []),\n ].join(\"\\n\"),\n );\n}\n\nexport function buildSettingsSetupMessage(owner: object) {\n return sanitizeChromeDevtoolsDisplay(\n [\n `Chrome DevTools endpoint: ${devToolsEndpoint(owner)}`,\n `Endpoint source: ${endpointSourceLabel(owner)}`,\n `Launch mode: ${launchModeLabel(owner)}`,\n ...browserSettingsStatusLines(owner),\n launchHint(owner),\n browserCandidateHint(owner),\n ...launchAttemptLines(owner),\n endpointConfigHint(),\n ].join(\"\\n\"),\n );\n}\n\nfunction browserSettingsStatusLines(owner: object) {\n const browser = browserSettingsForOwner(owner);\n const extensionPaths = browser.extensionPaths;\n const extensionLines =\n extensionPaths.length > 0 ? extensionPaths.map((extensionPath) => ` - ${extensionPath}`) : [\" - none\"];\n return [\n `Settings file: ${state.settingsFilePath ?? settingsFilePath()} (user)`,\n ...(state.projectSettingsFilePath\n ? [\n `Project settings: ${state.projectSettingsFilePath} (${state.projectSettingsTrusted ? \"trusted\" : \"untrusted; ignored\"})`,\n ]\n : []),\n `Auto-launch: ${browser.autoLaunchEnabled ? \"on\" : \"off\"} (${browser.autoLaunchSource})`,\n `Browser executable: ${browser.executablePath ?? \"automatic discovery\"} (${browser.executablePathSource})`,\n `Unpacked extensions (${browser.extensionPathsSource}):`,\n ...extensionLines,\n `WebMCP: ${webMcpEnabled(owner) ? \"enabled \u00B7 experimental \u00B7 every call requires confirmation\" : \"disabled \u00B7 experimental\"}`,\n \"Confirmed menu settings apply before the next browser connection; manual JSON edits require /reload or session replacement.\",\n ...(extensionPaths.length > 0\n ? [\"Unpacked extensions require Chrome for Testing or Chromium and execute trusted browser code.\"]\n : []),\n ];\n}\n\nexport function buildCommandGuide(owner: object) {\n return [\n \"Chrome DevTools commands:\",\n `WebMCP: ${webMcpEnabled(owner) ? \"enabled\" : \"disabled\"} \u00B7 experimental \u00B7 every page-provided call requires confirmation`,\n \"/chrome-devtools \u2014 open this menu\",\n \"/chrome-devtools help \u2014 show command usage\",\n \"/chrome-devtools quickstart \u2014 show endpoint and launch help\",\n \"/chrome-devtools status \u2014 show tool and settings status\",\n \"/chrome-devtools settings \u2014 edit browser connection settings\",\n \"/chrome-devtools tools \u2014 choose available Chrome DevTools tools\",\n \"/chrome-devtools toggle|select \u2014 compatibility aliases for tools\",\n \"/chrome-devtools enable|on \u2014 make all Chrome DevTools tools available\",\n \"/chrome-devtools disable|off \u2014 make all Chrome DevTools capability tools unavailable\",\n ].join(\"\\n\");\n}\n\nexport function allChromeDevtoolsTools(owner: object) {\n return effectiveCatalog(owner);\n}\n\nexport function orderedChromeDevtoolsTools(selectedTools: ReadonlySet<ChromeDevToolsToolName>) {\n return CHROME_DEVTOOLS_TOOL_NAMES.filter((toolName) => selectedTools.has(toolName));\n}\n\nfunction formatRuntimeStatus(summary: ToolStatusSummary) {\n return `${summary.availabilityStatus} (${summary.availableChromeToolCount}/${summary.capabilityCount} available)`;\n}\n\nfunction persistedSettingLabel(settings: SettingsLoadResult) {\n if (settings.kind === \"loaded\" && settings.settings.tools) {\n return formatPersistedSelection(settings.settings.tools);\n }\n if (settings.kind === \"invalid\") {\n return `none; current active-tool policy preserved (invalid settings ignored: ${settings.reason})`;\n }\n return \"none; default catalog restored on /reload or session replacement\";\n}\n\nfunction formatPersistedSelection(tools: readonly ChromeDevToolsToolName[]) {\n if (tools.length === CHROME_DEVTOOLS_TOOL_NAMES.length) {\n return `all available (${tools.length}/${CHROME_DEVTOOLS_TOOL_NAMES.length} selected)`;\n }\n if (tools.length === 0) return `all unavailable (0/${CHROME_DEVTOOLS_TOOL_NAMES.length} selected)`;\n return `${tools.length}/${CHROME_DEVTOOLS_TOOL_NAMES.length} selected: ${tools.join(\", \")}`;\n}\n\nfunction effectiveCatalog(owner: object): ChromeDevToolsToolName[] {\n return webMcpEnabled(owner) ? [...CHROME_DEVTOOLS_TOOL_NAMES] : [...CORE_CHROME_DEVTOOLS_TOOL_NAMES];\n}\n\nasync function persistSettings(selectedTools: readonly ChromeDevToolsToolName[], applyAfterSave?: () => void) {\n await saveSettings({ tools: [...selectedTools], updatedAt: Date.now() }, {}, applyAfterSave);\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["ownership"]
7
+ }
@@ -6,7 +6,7 @@ import {
6
6
  buildCommandGuide,
7
7
  sanitizeChromeDevtoolsDisplay,
8
8
  setSelectedChromeDevtoolsTools
9
- } from "./chunk-MZCGM6D3.js";
9
+ } from "./chunk-WOFI2A72.ts";
10
10
  import {
11
11
  CHROME_DEVTOOLS_TOOL_NAMES,
12
12
  CORE_CHROME_DEVTOOLS_TOOL_NAMES,
@@ -17,7 +17,7 @@ import {
17
17
  loadSettings,
18
18
  state,
19
19
  webMcpEnabled
20
- } from "./chunk-F5VG35UI.js";
20
+ } from "./chunk-TVVYQ5KM.ts";
21
21
 
22
22
  // src/menu.ts
23
23
  import { defineMenu, runMenu, runTask } from "@narumitw/pi-tui-kit";
@@ -67,7 +67,7 @@ async function showChromeDevtoolsMenu(pi, ctx, generation) {
67
67
  {
68
68
  id: "tools",
69
69
  label: "Choose available browser tools\u2026",
70
- description: "Choose which capabilities the loader may expose.",
70
+ description: "Choose which browser capabilities are available.",
71
71
  disabled: Boolean(current.mutationBlockedReason),
72
72
  disabledReason: current.mutationBlockedReason,
73
73
  action: "tools"
@@ -137,7 +137,7 @@ async function showChromeDevtoolsMenu(pi, ctx, generation) {
137
137
  return result?.closeParent ? { kind: "close" } : { kind: "stay" };
138
138
  },
139
139
  settings: async ({ state: current }) => {
140
- const { showChromeDevtoolsBrowserSettings } = await import("./browser-settings-menu-SR7KLZT6.js");
140
+ const { showChromeDevtoolsBrowserSettings } = await import("./browser-settings-menu-GQAXLWZ7.ts");
141
141
  if (!isCurrent()) return { kind: "stay" };
142
142
  const result = await showChromeDevtoolsBrowserSettings(pi, ctx, generation);
143
143
  if (!isCurrent()) return { kind: "stay" };
@@ -370,8 +370,8 @@ function buildToolReview(current, owner) {
370
370
  ...unavailable.length > 0 ? unavailable.map((name) => ` - ${TOOL_PRESENTATION[name].label} (${name})`) : [" - none"],
371
371
  "",
372
372
  "Other active Pi tools remain unchanged.",
373
- "Native-capable models defer these tools until chrome_devtools_load selects them.",
374
- "Other models expose available tools eagerly before the next model request.",
373
+ "Enabled capabilities follow the running tool mode; saved mode changes apply on reload.",
374
+ "Disabled capabilities cannot be discovered or called.",
375
375
  "The accepted availability policy is saved for future sessions."
376
376
  ].join("\n")
377
377
  );
@@ -415,4 +415,4 @@ export {
415
415
  showChromeDevtoolsMenu,
416
416
  showChromeDevtoolsToolWorkflow
417
417
  };
418
- //# sourceMappingURL=menu-YR4VRT7D.js.map
418
+ //# sourceMappingURL=menu-Z26D6XSI.ts.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/menu.ts"],
4
- "sourcesContent": ["import type { ExtensionAPI, ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { defineMenu, runMenu, runTask } from \"@narumitw/pi-tui-kit\";\nimport { browserLifecycleState, devToolsEndpoint, launchAttemptLines, launchModeLabel } from \"./browser-manager.js\";\nimport { availableChromeDevtoolsTools } from \"./lazy-tools.js\";\nimport { state, webMcpEnabled } from \"./runtime.js\";\nimport { loadSettings, type SettingsLoadResult } from \"./settings.js\";\nimport {\n CHROME_DEVTOOLS_TOOL_NAMES,\n type ChromeDevToolsToolName,\n CORE_CHROME_DEVTOOLS_TOOL_NAMES,\n} from \"./tool-names.js\";\nimport {\n buildBrowserStatusMessage,\n buildCommandGuide,\n sanitizeChromeDevtoolsDisplay,\n setSelectedChromeDevtoolsTools,\n} from \"./tool-selector.js\";\n\ntype CommandContext = ExtensionCommandContext;\ntype MainScreen = \"main\" | \"browserStatus\" | \"help\";\ntype MainAction = \"tools\" | \"bulk\" | \"settings\";\ntype ToolScreen = \"tools\" | \"review\";\ntype ToolAction = \"toggle\" | \"selectAll\" | \"selectNone\" | \"review\" | \"apply\" | \"cancel\";\n\ninterface MenuSnapshot {\n activeTools: ChromeDevToolsToolName[];\n persistenceLabel: string;\n mutationBlockedReason?: string;\n settingsWarning?: string;\n}\n\ninterface ToolWorkflowState {\n accepted: Set<ChromeDevToolsToolName>;\n draft: Set<ChromeDevToolsToolName>;\n mutationBlockedReason?: string;\n generation: number;\n applied: boolean;\n}\n\nconst TOOL_PRESENTATION: Record<ChromeDevToolsToolName, { label: string; description: string }> = {\n chrome_devtools_list_pages: {\n label: \"List open pages\",\n description: \"List inspectable Chrome tabs and pages (chrome_devtools_list_pages).\",\n },\n chrome_devtools_select_page: {\n label: \"Select the active page\",\n description: \"Choose the page later browser actions use (chrome_devtools_select_page).\",\n },\n chrome_devtools_navigate: {\n label: \"Navigate a page\",\n description: \"Open a URL, creating a page when needed (chrome_devtools_navigate).\",\n },\n chrome_devtools_evaluate: {\n label: \"Run JavaScript\",\n description: \"Evaluate JavaScript in the selected page (chrome_devtools_evaluate).\",\n },\n chrome_devtools_screenshot: {\n label: \"Capture a screenshot\",\n description: \"Save a PNG of the selected page (chrome_devtools_screenshot).\",\n },\n chrome_devtools_webmcp_list_tools: {\n label: \"List page WebMCP tools \u00B7 Experimental\",\n description: \"Discover page-provided WebMCP capabilities (chrome_devtools_webmcp_list_tools).\",\n },\n chrome_devtools_webmcp_call_tool: {\n label: \"Call a page WebMCP tool \u00B7 Experimental\",\n description: \"Invoke a listed page tool after confirmation (chrome_devtools_webmcp_call_tool).\",\n },\n};\n\nexport async function showChromeDevtoolsMenu(pi: ExtensionAPI, ctx: CommandContext, generation: number) {\n const snapshot = await loadSnapshotWithFeedback(pi, ctx, generation);\n if (!snapshot) return;\n const menuSignal = state.sessionController.signal;\n const isCurrent = () => generation === state.sessionGeneration && !menuSignal.aborted;\n const menu = defineMenu<MenuSnapshot, MainScreen, MainAction>({\n start: \"main\",\n screens: {\n main: ({ state: current }) => ({\n kind: \"actions\",\n title: \"Chrome DevTools\",\n lines: mainStateLines(current, ctx.sessionManager),\n items: [\n {\n id: \"tools\",\n label: \"Choose available browser tools\u2026\",\n description: \"Choose which capabilities the loader may expose.\",\n disabled: Boolean(current.mutationBlockedReason),\n disabledReason: current.mutationBlockedReason,\n action: \"tools\",\n },\n {\n id: \"bulk\",\n label:\n current.activeTools.length === availableCatalogNames(ctx.sessionManager).length\n ? \"Make all browser tools unavailable\u2026\"\n : \"Make all browser tools available\u2026\",\n description:\n current.activeTools.length === availableCatalogNames(ctx.sessionManager).length\n ? `Preview 0 of ${availableCatalogNames(ctx.sessionManager).length}; other active tools stay enabled.`\n : `Preview ${availableCatalogNames(ctx.sessionManager).length} of ${availableCatalogNames(ctx.sessionManager).length}; other active tools stay enabled.`,\n disabled: Boolean(current.mutationBlockedReason),\n disabledReason: current.mutationBlockedReason,\n action: \"bulk\",\n },\n {\n id: \"browser-status\",\n label: \"Browser status\",\n description: \"Runtime, endpoint, and last launch attempt.\",\n to: \"browserStatus\",\n },\n {\n id: \"settings\",\n label: \"Browser settings\",\n description: \"Edit endpoint, auto-launch, and browser executable settings.\",\n action: \"settings\",\n },\n {\n id: \"help\",\n label: \"Help\",\n description: \"Commands and usage.\",\n to: \"help\",\n },\n ],\n hint: \"close\",\n }),\n browserStatus: () => ({\n kind: \"review\",\n title: \"Browser status\",\n content: buildBrowserStatusMessage(ctx.sessionManager),\n format: { kind: \"text\" },\n viewportSize: \"adaptive\",\n hint: \"back\",\n }),\n help: () => ({\n kind: \"review\",\n title: \"Chrome DevTools help\",\n content: buildCommandGuide(ctx.sessionManager),\n format: { kind: \"text\" },\n viewportSize: \"adaptive\",\n hint: \"back\",\n }),\n },\n actions: {\n tools: async ({ state: current }) => {\n const result = await showChromeDevtoolsToolWorkflow(pi, ctx, generation, {\n snapshot: current,\n });\n if (result?.applied && isCurrent()) updateSnapshotAfterApply(current, result.selectedTools);\n return result?.closeParent ? { kind: \"close\" } : { kind: \"stay\" };\n },\n bulk: async ({ state: current }) => {\n const selectedTools =\n current.activeTools.length === availableCatalogNames(ctx.sessionManager).length\n ? []\n : availableCatalogNames(ctx.sessionManager);\n const result = await showChromeDevtoolsToolWorkflow(pi, ctx, generation, {\n snapshot: current,\n initialDraft: selectedTools,\n startAtReview: true,\n });\n if (result?.applied && isCurrent()) updateSnapshotAfterApply(current, result.selectedTools);\n return result?.closeParent ? { kind: \"close\" } : { kind: \"stay\" };\n },\n settings: async ({ state: current }) => {\n const { showChromeDevtoolsBrowserSettings } = await import(\"./browser-settings-menu.js\");\n if (!isCurrent()) return { kind: \"stay\" };\n const result = await showChromeDevtoolsBrowserSettings(pi, ctx, generation);\n if (!isCurrent()) return { kind: \"stay\" };\n const refreshed = await loadChromeDevtoolsMenuSnapshot(pi, ctx);\n if (!isCurrent()) return { kind: \"stay\" };\n Object.assign(current, refreshed);\n return result.closeParent ? { kind: \"close\" } : { kind: \"stay\" };\n },\n },\n });\n await runMenu(ctx, menu, {\n getState: () => snapshot,\n signal: menuSignal,\n isCurrent,\n onError: (currentCtx, error) =>\n currentCtx.ui.notify(\n sanitizeChromeDevtoolsDisplay(`Chrome DevTools menu failed: ${formatError(error)}`),\n \"error\",\n ),\n });\n}\n\nexport async function showChromeDevtoolsToolWorkflow(\n pi: ExtensionAPI,\n ctx: CommandContext,\n generation: number,\n options: {\n snapshot?: MenuSnapshot;\n initialDraft?: readonly ChromeDevToolsToolName[];\n startAtReview?: boolean;\n } = {},\n): Promise<{ applied: boolean; closeParent: boolean; selectedTools: ChromeDevToolsToolName[] } | undefined> {\n const snapshot = options.snapshot ?? (await loadSnapshotWithFeedback(pi, ctx, generation));\n if (!snapshot) return undefined;\n const menuSignal = state.sessionController.signal;\n const isCurrent = () => generation === state.sessionGeneration && !menuSignal.aborted;\n const accepted = new Set(snapshot.activeTools);\n const workflow: ToolWorkflowState = {\n accepted,\n draft: new Set(options.initialDraft ?? snapshot.activeTools),\n mutationBlockedReason: snapshot.mutationBlockedReason,\n generation,\n applied: false,\n };\n const menu = defineMenu<ToolWorkflowState, ToolScreen, ToolAction>({\n start: options.startAtReview ? \"review\" : \"tools\",\n screens: {\n tools: ({ state: current }) => ({\n kind: \"multiSelect\",\n title: `Browser tools (${current.draft.size}/${availableCatalogNames(ctx.sessionManager).length})`,\n lines: toolDraftLines(current, ctx.sessionManager),\n items: availableCatalogNames(ctx.sessionManager).map((toolName) => ({\n id: toolName,\n label: TOOL_PRESENTATION[toolName].label,\n description: TOOL_PRESENTATION[toolName].description,\n searchText: `${toolName} ${TOOL_PRESENTATION[toolName].description}`,\n selected: current.draft.has(toolName),\n disabled: Boolean(current.mutationBlockedReason),\n disabledReason: current.mutationBlockedReason,\n })),\n action: \"toggle\",\n actions: [\n {\n id: \"select-all\",\n label: \"Select all\",\n disabled: Boolean(current.mutationBlockedReason),\n disabledReason: current.mutationBlockedReason,\n action: \"selectAll\",\n },\n {\n id: \"select-none\",\n label: \"Select none\",\n disabled: Boolean(current.mutationBlockedReason),\n disabledReason: current.mutationBlockedReason,\n action: \"selectNone\",\n },\n {\n id: \"review\",\n label: \"Review changes\u2026\",\n disabled: Boolean(current.mutationBlockedReason) || setsEqual(current.accepted, current.draft),\n disabledReason:\n current.mutationBlockedReason ??\n (setsEqual(current.accepted, current.draft) ? \"No unapplied changes\" : undefined),\n to: \"review\",\n },\n { id: \"cancel\", label: \"Cancel\", action: \"cancel\" },\n ],\n hint: \"back\",\n }),\n review: ({ state: current }) => ({\n kind: \"review\",\n title: \"Review tool changes\",\n lines: [\n `Currently available: ${current.accepted.size}/${availableCatalogNames(ctx.sessionManager).length}`,\n `Proposed availability: ${current.draft.size}/${availableCatalogNames(ctx.sessionManager).length}`,\n ],\n content: buildToolReview(current, ctx.sessionManager),\n format: { kind: \"text\" },\n viewportSize: \"adaptive\",\n ...(current.mutationBlockedReason || setsEqual(current.accepted, current.draft)\n ? {}\n : {\n confirm: {\n id: \"apply\",\n label: \"Apply tool changes\",\n action: \"apply\" as const,\n },\n }),\n hint: \"back\",\n }),\n },\n actions: {\n toggle: ({ state: current, itemId, selected }) => {\n if (!isChromeDevtoolsToolName(itemId) || selected === undefined) return { kind: \"rejected\" };\n if (selected) current.draft.add(itemId);\n else current.draft.delete(itemId);\n return { kind: \"stay\" };\n },\n selectAll: ({ state: current }) => {\n current.draft = new Set(availableCatalogNames(ctx.sessionManager));\n return { kind: \"stay\" };\n },\n selectNone: ({ state: current }) => {\n current.draft = new Set();\n return { kind: \"stay\" };\n },\n review: () => ({ kind: \"to\", screen: \"review\" }),\n cancel: () => ({ kind: \"back\" }),\n apply: async ({ state: current, signal }) => {\n await ctx.waitForIdle();\n if (signal.aborted || !isCurrent() || current.generation !== state.sessionGeneration) {\n return { kind: \"rejected\" };\n }\n const selectedTools = orderedTools(current.draft);\n const saveResult = await setSelectedChromeDevtoolsTools(pi, ctx, selectedTools, orderedTools(current.accepted));\n if (!isCurrent()) return { kind: \"rejected\" };\n if (saveResult === \"active-tools-changed\") {\n current.accepted = new Set(activeChromeTools(pi));\n }\n if (saveResult !== \"saved\") return { kind: \"rejected\" };\n current.accepted = new Set(selectedTools);\n current.draft = new Set(selectedTools);\n current.applied = true;\n ctx.ui.notify(\n `Saved: ${selectedTools.length} of ${availableCatalogNames(ctx.sessionManager).length} browser tools available.`,\n \"info\",\n );\n return { kind: \"close\" };\n },\n },\n });\n const result = await runMenu(ctx, menu, {\n getState: () => workflow,\n signal: menuSignal,\n isCurrent,\n onError: (currentCtx, error) =>\n currentCtx.ui.notify(\n sanitizeChromeDevtoolsDisplay(`Chrome DevTools tool selection failed: ${formatError(error)}`),\n \"error\",\n ),\n });\n return {\n applied: workflow.applied,\n closeParent: !workflow.applied && result.kind === \"closed\" && result.reason === \"close\",\n selectedTools: orderedTools(workflow.accepted),\n };\n}\n\nasync function loadSnapshotWithFeedback(pi: ExtensionAPI, ctx: CommandContext, generation: number) {\n const menuSignal = state.sessionController.signal;\n const isCurrent = () => generation === state.sessionGeneration && !menuSignal.aborted;\n const result = await runTask(ctx, {\n label: \"Loading Chrome DevTools settings\u2026\",\n signal: menuSignal,\n isCurrent,\n task: async ({ signal }) => {\n signal.throwIfAborted();\n const settings = await loadSettings();\n signal.throwIfAborted();\n return buildMenuSnapshot(pi, settings);\n },\n });\n return result.kind === \"completed\" ? result.value : undefined;\n}\n\nexport async function loadChromeDevtoolsMenuSnapshot(pi: ExtensionAPI, ctx: ExtensionCommandContext) {\n const settings = await loadSettings({\n cwd: ctx.cwd,\n projectTrusted: ctx.isProjectTrusted(),\n });\n return buildMenuSnapshot(pi, settings);\n}\n\nfunction buildMenuSnapshot(pi: ExtensionAPI, settings: SettingsLoadResult): MenuSnapshot {\n const activeTools = activeChromeTools(pi);\n const persistedTools =\n settings.kind === \"loaded\" && settings.settings.tools ? orderedTools(new Set(settings.settings.tools)) : undefined;\n const persistenceLabel =\n settings.kind === \"invalid\"\n ? \"settings need repair\"\n : persistedTools === undefined\n ? \"not saved\"\n : arraysEqual(activeTools, persistedTools)\n ? \"saved\"\n : \"runtime catalog differs from saved catalog\";\n const settingsWarning = [...new Set([settings.notice, state.settingsNotice].filter(Boolean))].join(\"\\n\");\n return {\n activeTools,\n persistenceLabel,\n ...(settings.kind === \"invalid\" ? { mutationBlockedReason: `Repair ${settings.reason} before saving` } : {}),\n ...(settingsWarning ? { settingsWarning } : {}),\n };\n}\n\nfunction mainStateLines(snapshot: MenuSnapshot, owner: object) {\n const launchError = launchAttemptLines(owner).find((line) => line.startsWith(\"Last launch error:\"));\n return sanitizeLines([\n `Tool catalog: ${snapshot.activeTools.length} of ${availableCatalogNames(owner).length} available \u00B7 ${snapshot.persistenceLabel}`,\n `WebMCP: ${webMcpEnabled(owner) ? \"enabled \u00B7 experimental \u00B7 confirmation required for every call\" : \"disabled \u00B7 experimental\"}`,\n `Browser: ${browserLifecycleSummary(owner)}`,\n `Endpoint: ${devToolsEndpoint(owner)}`,\n ...(snapshot.settingsWarning ? [`Settings warning: ${snapshot.settingsWarning}`] : []),\n ...(launchError ? [`Launch warning: ${launchError.slice(\"Last launch error: \".length)}`] : []),\n ]);\n}\n\nfunction browserLifecycleSummary(owner: object) {\n const lifecycle = browserLifecycleState(owner);\n if (lifecycle === \"starting\") return \"starting managed browser\";\n if (lifecycle === \"running\") return \"managed browser running\";\n if (lifecycle === \"exited\") return \"managed browser exited \u00B7 open Browser status to recover\";\n if (lifecycle === \"failed\") return \"last launch failed \u00B7 open Browser status to recover\";\n const launchMode = launchModeLabel(owner);\n return launchMode.startsWith(\"attach first\")\n ? \"not started \u00B7 attaches or launches on first use\"\n : `not started \u00B7 ${launchMode}`;\n}\n\nfunction toolDraftLines(current: ToolWorkflowState, owner: object) {\n if (current.mutationBlockedReason) return sanitizeLines([`Unavailable: ${current.mutationBlockedReason}`]);\n const changes = symmetricDifferenceSize(current.accepted, current.draft);\n return [\n `Currently available: ${current.accepted.size}/${availableCatalogNames(owner).length}`,\n changes === 0\n ? \"No unapplied changes \u00B7 Escape cancels\"\n : `${changes} unapplied ${changes === 1 ? \"change\" : \"changes\"} \u00B7 Escape cancels`,\n `WebMCP gateways: ${webMcpEnabled(owner) ? \"available for selection \u00B7 experimental\" : \"hidden while experimental WebMCP is disabled\"}`,\n \"Changes are not applied until Review changes and Apply tool changes.\",\n ];\n}\n\nfunction buildToolReview(current: ToolWorkflowState, owner: object) {\n const catalog = availableCatalogNames(owner);\n const available = catalog.filter((name) => current.draft.has(name));\n const unavailable = catalog.filter((name) => !current.draft.has(name));\n return sanitizeChromeDevtoolsDisplay(\n [\n `Current available browser tools: ${current.accepted.size}/${catalog.length}`,\n `Proposed available browser tools: ${current.draft.size}/${catalog.length}`,\n \"\",\n \"Available after apply:\",\n ...(available.length > 0\n ? available.map((name) => ` - ${TOOL_PRESENTATION[name].label} (${name})`)\n : [\" - none\"]),\n \"\",\n \"Unavailable after apply:\",\n ...(unavailable.length > 0\n ? unavailable.map((name) => ` - ${TOOL_PRESENTATION[name].label} (${name})`)\n : [\" - none\"]),\n \"\",\n \"Other active Pi tools remain unchanged.\",\n \"Native-capable models defer these tools until chrome_devtools_load selects them.\",\n \"Other models expose available tools eagerly before the next model request.\",\n \"The accepted availability policy is saved for future sessions.\",\n ].join(\"\\n\"),\n );\n}\n\nfunction updateSnapshotAfterApply(snapshot: MenuSnapshot, selectedTools: readonly ChromeDevToolsToolName[]) {\n snapshot.activeTools = [...selectedTools];\n snapshot.persistenceLabel = \"saved\";\n}\n\nfunction activeChromeTools(pi: ExtensionAPI) {\n return availableChromeDevtoolsTools(pi);\n}\n\nfunction orderedTools(tools: ReadonlySet<ChromeDevToolsToolName>) {\n return CHROME_DEVTOOLS_TOOL_NAMES.filter((toolName) => tools.has(toolName));\n}\n\nfunction isChromeDevtoolsToolName(value: string): value is ChromeDevToolsToolName {\n return CHROME_DEVTOOLS_TOOL_NAMES.includes(value as ChromeDevToolsToolName);\n}\n\nfunction setsEqual<T>(left: ReadonlySet<T>, right: ReadonlySet<T>) {\n return left.size === right.size && [...left].every((value) => right.has(value));\n}\n\nfunction symmetricDifferenceSize<T>(left: ReadonlySet<T>, right: ReadonlySet<T>) {\n let changes = 0;\n for (const value of left) if (!right.has(value)) changes += 1;\n for (const value of right) if (!left.has(value)) changes += 1;\n return changes;\n}\n\nfunction arraysEqual<T>(left: readonly T[], right: readonly T[]) {\n return left.length === right.length && left.every((value, index) => value === right[index]);\n}\n\nfunction sanitizeLines(lines: readonly string[]) {\n return sanitizeChromeDevtoolsDisplay(lines.join(\"\\n\")).split(\"\\n\");\n}\n\nfunction availableCatalogNames(owner: object): ChromeDevToolsToolName[] {\n return webMcpEnabled(owner) ? [...CHROME_DEVTOOLS_TOOL_NAMES] : [...CORE_CHROME_DEVTOOLS_TOOL_NAMES];\n}\n\nfunction formatError(error: unknown) {\n return error instanceof Error ? error.message : String(error);\n}\n"],
4
+ "sourcesContent": ["import type { ExtensionAPI, ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { defineMenu, runMenu, runTask } from \"@narumitw/pi-tui-kit\";\nimport { browserLifecycleState, devToolsEndpoint, launchAttemptLines, launchModeLabel } from \"./browser-manager.js\";\nimport { availableChromeDevtoolsTools } from \"./lazy-tools.js\";\nimport { state, webMcpEnabled } from \"./runtime.js\";\nimport { loadSettings, type SettingsLoadResult } from \"./settings.js\";\nimport {\n CHROME_DEVTOOLS_TOOL_NAMES,\n type ChromeDevToolsToolName,\n CORE_CHROME_DEVTOOLS_TOOL_NAMES,\n} from \"./tool-names.js\";\nimport {\n buildBrowserStatusMessage,\n buildCommandGuide,\n sanitizeChromeDevtoolsDisplay,\n setSelectedChromeDevtoolsTools,\n} from \"./tool-selector.js\";\n\ntype CommandContext = ExtensionCommandContext;\ntype MainScreen = \"main\" | \"browserStatus\" | \"help\";\ntype MainAction = \"tools\" | \"bulk\" | \"settings\";\ntype ToolScreen = \"tools\" | \"review\";\ntype ToolAction = \"toggle\" | \"selectAll\" | \"selectNone\" | \"review\" | \"apply\" | \"cancel\";\n\ninterface MenuSnapshot {\n activeTools: ChromeDevToolsToolName[];\n persistenceLabel: string;\n mutationBlockedReason?: string;\n settingsWarning?: string;\n}\n\ninterface ToolWorkflowState {\n accepted: Set<ChromeDevToolsToolName>;\n draft: Set<ChromeDevToolsToolName>;\n mutationBlockedReason?: string;\n generation: number;\n applied: boolean;\n}\n\nconst TOOL_PRESENTATION: Record<ChromeDevToolsToolName, { label: string; description: string }> = {\n chrome_devtools_list_pages: {\n label: \"List open pages\",\n description: \"List inspectable Chrome tabs and pages (chrome_devtools_list_pages).\",\n },\n chrome_devtools_select_page: {\n label: \"Select the active page\",\n description: \"Choose the page later browser actions use (chrome_devtools_select_page).\",\n },\n chrome_devtools_navigate: {\n label: \"Navigate a page\",\n description: \"Open a URL, creating a page when needed (chrome_devtools_navigate).\",\n },\n chrome_devtools_evaluate: {\n label: \"Run JavaScript\",\n description: \"Evaluate JavaScript in the selected page (chrome_devtools_evaluate).\",\n },\n chrome_devtools_screenshot: {\n label: \"Capture a screenshot\",\n description: \"Save a PNG of the selected page (chrome_devtools_screenshot).\",\n },\n chrome_devtools_webmcp_list_tools: {\n label: \"List page WebMCP tools \u00B7 Experimental\",\n description: \"Discover page-provided WebMCP capabilities (chrome_devtools_webmcp_list_tools).\",\n },\n chrome_devtools_webmcp_call_tool: {\n label: \"Call a page WebMCP tool \u00B7 Experimental\",\n description: \"Invoke a listed page tool after confirmation (chrome_devtools_webmcp_call_tool).\",\n },\n};\n\nexport async function showChromeDevtoolsMenu(pi: ExtensionAPI, ctx: CommandContext, generation: number) {\n const snapshot = await loadSnapshotWithFeedback(pi, ctx, generation);\n if (!snapshot) return;\n const menuSignal = state.sessionController.signal;\n const isCurrent = () => generation === state.sessionGeneration && !menuSignal.aborted;\n const menu = defineMenu<MenuSnapshot, MainScreen, MainAction>({\n start: \"main\",\n screens: {\n main: ({ state: current }) => ({\n kind: \"actions\",\n title: \"Chrome DevTools\",\n lines: mainStateLines(current, ctx.sessionManager),\n items: [\n {\n id: \"tools\",\n label: \"Choose available browser tools\u2026\",\n description: \"Choose which browser capabilities are available.\",\n disabled: Boolean(current.mutationBlockedReason),\n disabledReason: current.mutationBlockedReason,\n action: \"tools\",\n },\n {\n id: \"bulk\",\n label:\n current.activeTools.length === availableCatalogNames(ctx.sessionManager).length\n ? \"Make all browser tools unavailable\u2026\"\n : \"Make all browser tools available\u2026\",\n description:\n current.activeTools.length === availableCatalogNames(ctx.sessionManager).length\n ? `Preview 0 of ${availableCatalogNames(ctx.sessionManager).length}; other active tools stay enabled.`\n : `Preview ${availableCatalogNames(ctx.sessionManager).length} of ${availableCatalogNames(ctx.sessionManager).length}; other active tools stay enabled.`,\n disabled: Boolean(current.mutationBlockedReason),\n disabledReason: current.mutationBlockedReason,\n action: \"bulk\",\n },\n {\n id: \"browser-status\",\n label: \"Browser status\",\n description: \"Runtime, endpoint, and last launch attempt.\",\n to: \"browserStatus\",\n },\n {\n id: \"settings\",\n label: \"Browser settings\",\n description: \"Edit endpoint, auto-launch, and browser executable settings.\",\n action: \"settings\",\n },\n {\n id: \"help\",\n label: \"Help\",\n description: \"Commands and usage.\",\n to: \"help\",\n },\n ],\n hint: \"close\",\n }),\n browserStatus: () => ({\n kind: \"review\",\n title: \"Browser status\",\n content: buildBrowserStatusMessage(ctx.sessionManager),\n format: { kind: \"text\" },\n viewportSize: \"adaptive\",\n hint: \"back\",\n }),\n help: () => ({\n kind: \"review\",\n title: \"Chrome DevTools help\",\n content: buildCommandGuide(ctx.sessionManager),\n format: { kind: \"text\" },\n viewportSize: \"adaptive\",\n hint: \"back\",\n }),\n },\n actions: {\n tools: async ({ state: current }) => {\n const result = await showChromeDevtoolsToolWorkflow(pi, ctx, generation, {\n snapshot: current,\n });\n if (result?.applied && isCurrent()) updateSnapshotAfterApply(current, result.selectedTools);\n return result?.closeParent ? { kind: \"close\" } : { kind: \"stay\" };\n },\n bulk: async ({ state: current }) => {\n const selectedTools =\n current.activeTools.length === availableCatalogNames(ctx.sessionManager).length\n ? []\n : availableCatalogNames(ctx.sessionManager);\n const result = await showChromeDevtoolsToolWorkflow(pi, ctx, generation, {\n snapshot: current,\n initialDraft: selectedTools,\n startAtReview: true,\n });\n if (result?.applied && isCurrent()) updateSnapshotAfterApply(current, result.selectedTools);\n return result?.closeParent ? { kind: \"close\" } : { kind: \"stay\" };\n },\n settings: async ({ state: current }) => {\n const { showChromeDevtoolsBrowserSettings } = await import(\"./browser-settings-menu.js\");\n if (!isCurrent()) return { kind: \"stay\" };\n const result = await showChromeDevtoolsBrowserSettings(pi, ctx, generation);\n if (!isCurrent()) return { kind: \"stay\" };\n const refreshed = await loadChromeDevtoolsMenuSnapshot(pi, ctx);\n if (!isCurrent()) return { kind: \"stay\" };\n Object.assign(current, refreshed);\n return result.closeParent ? { kind: \"close\" } : { kind: \"stay\" };\n },\n },\n });\n await runMenu(ctx, menu, {\n getState: () => snapshot,\n signal: menuSignal,\n isCurrent,\n onError: (currentCtx, error) =>\n currentCtx.ui.notify(\n sanitizeChromeDevtoolsDisplay(`Chrome DevTools menu failed: ${formatError(error)}`),\n \"error\",\n ),\n });\n}\n\nexport async function showChromeDevtoolsToolWorkflow(\n pi: ExtensionAPI,\n ctx: CommandContext,\n generation: number,\n options: {\n snapshot?: MenuSnapshot;\n initialDraft?: readonly ChromeDevToolsToolName[];\n startAtReview?: boolean;\n } = {},\n): Promise<{ applied: boolean; closeParent: boolean; selectedTools: ChromeDevToolsToolName[] } | undefined> {\n const snapshot = options.snapshot ?? (await loadSnapshotWithFeedback(pi, ctx, generation));\n if (!snapshot) return undefined;\n const menuSignal = state.sessionController.signal;\n const isCurrent = () => generation === state.sessionGeneration && !menuSignal.aborted;\n const accepted = new Set(snapshot.activeTools);\n const workflow: ToolWorkflowState = {\n accepted,\n draft: new Set(options.initialDraft ?? snapshot.activeTools),\n mutationBlockedReason: snapshot.mutationBlockedReason,\n generation,\n applied: false,\n };\n const menu = defineMenu<ToolWorkflowState, ToolScreen, ToolAction>({\n start: options.startAtReview ? \"review\" : \"tools\",\n screens: {\n tools: ({ state: current }) => ({\n kind: \"multiSelect\",\n title: `Browser tools (${current.draft.size}/${availableCatalogNames(ctx.sessionManager).length})`,\n lines: toolDraftLines(current, ctx.sessionManager),\n items: availableCatalogNames(ctx.sessionManager).map((toolName) => ({\n id: toolName,\n label: TOOL_PRESENTATION[toolName].label,\n description: TOOL_PRESENTATION[toolName].description,\n searchText: `${toolName} ${TOOL_PRESENTATION[toolName].description}`,\n selected: current.draft.has(toolName),\n disabled: Boolean(current.mutationBlockedReason),\n disabledReason: current.mutationBlockedReason,\n })),\n action: \"toggle\",\n actions: [\n {\n id: \"select-all\",\n label: \"Select all\",\n disabled: Boolean(current.mutationBlockedReason),\n disabledReason: current.mutationBlockedReason,\n action: \"selectAll\",\n },\n {\n id: \"select-none\",\n label: \"Select none\",\n disabled: Boolean(current.mutationBlockedReason),\n disabledReason: current.mutationBlockedReason,\n action: \"selectNone\",\n },\n {\n id: \"review\",\n label: \"Review changes\u2026\",\n disabled: Boolean(current.mutationBlockedReason) || setsEqual(current.accepted, current.draft),\n disabledReason:\n current.mutationBlockedReason ??\n (setsEqual(current.accepted, current.draft) ? \"No unapplied changes\" : undefined),\n to: \"review\",\n },\n { id: \"cancel\", label: \"Cancel\", action: \"cancel\" },\n ],\n hint: \"back\",\n }),\n review: ({ state: current }) => ({\n kind: \"review\",\n title: \"Review tool changes\",\n lines: [\n `Currently available: ${current.accepted.size}/${availableCatalogNames(ctx.sessionManager).length}`,\n `Proposed availability: ${current.draft.size}/${availableCatalogNames(ctx.sessionManager).length}`,\n ],\n content: buildToolReview(current, ctx.sessionManager),\n format: { kind: \"text\" },\n viewportSize: \"adaptive\",\n ...(current.mutationBlockedReason || setsEqual(current.accepted, current.draft)\n ? {}\n : {\n confirm: {\n id: \"apply\",\n label: \"Apply tool changes\",\n action: \"apply\" as const,\n },\n }),\n hint: \"back\",\n }),\n },\n actions: {\n toggle: ({ state: current, itemId, selected }) => {\n if (!isChromeDevtoolsToolName(itemId) || selected === undefined) return { kind: \"rejected\" };\n if (selected) current.draft.add(itemId);\n else current.draft.delete(itemId);\n return { kind: \"stay\" };\n },\n selectAll: ({ state: current }) => {\n current.draft = new Set(availableCatalogNames(ctx.sessionManager));\n return { kind: \"stay\" };\n },\n selectNone: ({ state: current }) => {\n current.draft = new Set();\n return { kind: \"stay\" };\n },\n review: () => ({ kind: \"to\", screen: \"review\" }),\n cancel: () => ({ kind: \"back\" }),\n apply: async ({ state: current, signal }) => {\n await ctx.waitForIdle();\n if (signal.aborted || !isCurrent() || current.generation !== state.sessionGeneration) {\n return { kind: \"rejected\" };\n }\n const selectedTools = orderedTools(current.draft);\n const saveResult = await setSelectedChromeDevtoolsTools(pi, ctx, selectedTools, orderedTools(current.accepted));\n if (!isCurrent()) return { kind: \"rejected\" };\n if (saveResult === \"active-tools-changed\") {\n current.accepted = new Set(activeChromeTools(pi));\n }\n if (saveResult !== \"saved\") return { kind: \"rejected\" };\n current.accepted = new Set(selectedTools);\n current.draft = new Set(selectedTools);\n current.applied = true;\n ctx.ui.notify(\n `Saved: ${selectedTools.length} of ${availableCatalogNames(ctx.sessionManager).length} browser tools available.`,\n \"info\",\n );\n return { kind: \"close\" };\n },\n },\n });\n const result = await runMenu(ctx, menu, {\n getState: () => workflow,\n signal: menuSignal,\n isCurrent,\n onError: (currentCtx, error) =>\n currentCtx.ui.notify(\n sanitizeChromeDevtoolsDisplay(`Chrome DevTools tool selection failed: ${formatError(error)}`),\n \"error\",\n ),\n });\n return {\n applied: workflow.applied,\n closeParent: !workflow.applied && result.kind === \"closed\" && result.reason === \"close\",\n selectedTools: orderedTools(workflow.accepted),\n };\n}\n\nasync function loadSnapshotWithFeedback(pi: ExtensionAPI, ctx: CommandContext, generation: number) {\n const menuSignal = state.sessionController.signal;\n const isCurrent = () => generation === state.sessionGeneration && !menuSignal.aborted;\n const result = await runTask(ctx, {\n label: \"Loading Chrome DevTools settings\u2026\",\n signal: menuSignal,\n isCurrent,\n task: async ({ signal }) => {\n signal.throwIfAborted();\n const settings = await loadSettings();\n signal.throwIfAborted();\n return buildMenuSnapshot(pi, settings);\n },\n });\n return result.kind === \"completed\" ? result.value : undefined;\n}\n\nexport async function loadChromeDevtoolsMenuSnapshot(pi: ExtensionAPI, ctx: ExtensionCommandContext) {\n const settings = await loadSettings({\n cwd: ctx.cwd,\n projectTrusted: ctx.isProjectTrusted(),\n });\n return buildMenuSnapshot(pi, settings);\n}\n\nfunction buildMenuSnapshot(pi: ExtensionAPI, settings: SettingsLoadResult): MenuSnapshot {\n const activeTools = activeChromeTools(pi);\n const persistedTools =\n settings.kind === \"loaded\" && settings.settings.tools ? orderedTools(new Set(settings.settings.tools)) : undefined;\n const persistenceLabel =\n settings.kind === \"invalid\"\n ? \"settings need repair\"\n : persistedTools === undefined\n ? \"not saved\"\n : arraysEqual(activeTools, persistedTools)\n ? \"saved\"\n : \"runtime catalog differs from saved catalog\";\n const settingsWarning = [...new Set([settings.notice, state.settingsNotice].filter(Boolean))].join(\"\\n\");\n return {\n activeTools,\n persistenceLabel,\n ...(settings.kind === \"invalid\" ? { mutationBlockedReason: `Repair ${settings.reason} before saving` } : {}),\n ...(settingsWarning ? { settingsWarning } : {}),\n };\n}\n\nfunction mainStateLines(snapshot: MenuSnapshot, owner: object) {\n const launchError = launchAttemptLines(owner).find((line) => line.startsWith(\"Last launch error:\"));\n return sanitizeLines([\n `Tool catalog: ${snapshot.activeTools.length} of ${availableCatalogNames(owner).length} available \u00B7 ${snapshot.persistenceLabel}`,\n `WebMCP: ${webMcpEnabled(owner) ? \"enabled \u00B7 experimental \u00B7 confirmation required for every call\" : \"disabled \u00B7 experimental\"}`,\n `Browser: ${browserLifecycleSummary(owner)}`,\n `Endpoint: ${devToolsEndpoint(owner)}`,\n ...(snapshot.settingsWarning ? [`Settings warning: ${snapshot.settingsWarning}`] : []),\n ...(launchError ? [`Launch warning: ${launchError.slice(\"Last launch error: \".length)}`] : []),\n ]);\n}\n\nfunction browserLifecycleSummary(owner: object) {\n const lifecycle = browserLifecycleState(owner);\n if (lifecycle === \"starting\") return \"starting managed browser\";\n if (lifecycle === \"running\") return \"managed browser running\";\n if (lifecycle === \"exited\") return \"managed browser exited \u00B7 open Browser status to recover\";\n if (lifecycle === \"failed\") return \"last launch failed \u00B7 open Browser status to recover\";\n const launchMode = launchModeLabel(owner);\n return launchMode.startsWith(\"attach first\")\n ? \"not started \u00B7 attaches or launches on first use\"\n : `not started \u00B7 ${launchMode}`;\n}\n\nfunction toolDraftLines(current: ToolWorkflowState, owner: object) {\n if (current.mutationBlockedReason) return sanitizeLines([`Unavailable: ${current.mutationBlockedReason}`]);\n const changes = symmetricDifferenceSize(current.accepted, current.draft);\n return [\n `Currently available: ${current.accepted.size}/${availableCatalogNames(owner).length}`,\n changes === 0\n ? \"No unapplied changes \u00B7 Escape cancels\"\n : `${changes} unapplied ${changes === 1 ? \"change\" : \"changes\"} \u00B7 Escape cancels`,\n `WebMCP gateways: ${webMcpEnabled(owner) ? \"available for selection \u00B7 experimental\" : \"hidden while experimental WebMCP is disabled\"}`,\n \"Changes are not applied until Review changes and Apply tool changes.\",\n ];\n}\n\nfunction buildToolReview(current: ToolWorkflowState, owner: object) {\n const catalog = availableCatalogNames(owner);\n const available = catalog.filter((name) => current.draft.has(name));\n const unavailable = catalog.filter((name) => !current.draft.has(name));\n return sanitizeChromeDevtoolsDisplay(\n [\n `Current available browser tools: ${current.accepted.size}/${catalog.length}`,\n `Proposed available browser tools: ${current.draft.size}/${catalog.length}`,\n \"\",\n \"Available after apply:\",\n ...(available.length > 0\n ? available.map((name) => ` - ${TOOL_PRESENTATION[name].label} (${name})`)\n : [\" - none\"]),\n \"\",\n \"Unavailable after apply:\",\n ...(unavailable.length > 0\n ? unavailable.map((name) => ` - ${TOOL_PRESENTATION[name].label} (${name})`)\n : [\" - none\"]),\n \"\",\n \"Other active Pi tools remain unchanged.\",\n \"Enabled capabilities follow the running tool mode; saved mode changes apply on reload.\",\n \"Disabled capabilities cannot be discovered or called.\",\n \"The accepted availability policy is saved for future sessions.\",\n ].join(\"\\n\"),\n );\n}\n\nfunction updateSnapshotAfterApply(snapshot: MenuSnapshot, selectedTools: readonly ChromeDevToolsToolName[]) {\n snapshot.activeTools = [...selectedTools];\n snapshot.persistenceLabel = \"saved\";\n}\n\nfunction activeChromeTools(pi: ExtensionAPI) {\n return availableChromeDevtoolsTools(pi);\n}\n\nfunction orderedTools(tools: ReadonlySet<ChromeDevToolsToolName>) {\n return CHROME_DEVTOOLS_TOOL_NAMES.filter((toolName) => tools.has(toolName));\n}\n\nfunction isChromeDevtoolsToolName(value: string): value is ChromeDevToolsToolName {\n return CHROME_DEVTOOLS_TOOL_NAMES.includes(value as ChromeDevToolsToolName);\n}\n\nfunction setsEqual<T>(left: ReadonlySet<T>, right: ReadonlySet<T>) {\n return left.size === right.size && [...left].every((value) => right.has(value));\n}\n\nfunction symmetricDifferenceSize<T>(left: ReadonlySet<T>, right: ReadonlySet<T>) {\n let changes = 0;\n for (const value of left) if (!right.has(value)) changes += 1;\n for (const value of right) if (!left.has(value)) changes += 1;\n return changes;\n}\n\nfunction arraysEqual<T>(left: readonly T[], right: readonly T[]) {\n return left.length === right.length && left.every((value, index) => value === right[index]);\n}\n\nfunction sanitizeLines(lines: readonly string[]) {\n return sanitizeChromeDevtoolsDisplay(lines.join(\"\\n\")).split(\"\\n\");\n}\n\nfunction availableCatalogNames(owner: object): ChromeDevToolsToolName[] {\n return webMcpEnabled(owner) ? [...CHROME_DEVTOOLS_TOOL_NAMES] : [...CORE_CHROME_DEVTOOLS_TOOL_NAMES];\n}\n\nfunction formatError(error: unknown) {\n return error instanceof Error ? error.message : String(error);\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -5,7 +5,7 @@ import {
5
5
  getPage,
6
6
  resolvePage,
7
7
  textResult
8
- } from "./chunk-4KMN4SFF.js";
8
+ } from "./chunk-5T2WEIYN.ts";
9
9
  import {
10
10
  DEFAULT_TIMEOUT_MS,
11
11
  beginWebMcpOperation,
@@ -15,7 +15,7 @@ import {
15
15
  webMcpEnabled,
16
16
  webMcpOperationIsCurrent,
17
17
  webMcpSessionSignal
18
- } from "./chunk-F5VG35UI.js";
18
+ } from "./chunk-TVVYQ5KM.ts";
19
19
 
20
20
  // src/webmcp/policy.ts
21
21
  import { createHash } from "node:crypto";
@@ -919,4 +919,4 @@ export {
919
919
  executeWebMcpCallTool,
920
920
  executeWebMcpListTool
921
921
  };
922
- //# sourceMappingURL=tools-6R7Z6HWJ.js.map
922
+ //# sourceMappingURL=tools-DSYQPFF3.ts.map
package/dist/index.ts CHANGED
@@ -9,23 +9,25 @@ import {
9
9
  setActivePageId,
10
10
  textResult,
11
11
  withCdp
12
- } from "./chunks/chunk-4KMN4SFF.js";
12
+ } from "./chunks/chunk-5T2WEIYN.ts";
13
13
  import {
14
14
  allChromeDevtoolsTools,
15
15
  availableChromeDevtoolsTools,
16
16
  buildCommandGuide,
17
17
  buildQuickstartMessage,
18
18
  buildToolStatusMessage,
19
+ chromeDevtoolsToolMode,
19
20
  configureChromeDevtoolsToolExposure,
20
- createChromeDevtoolsLoadTool,
21
21
  initializeAvailableChromeDevtoolsTools,
22
+ previousChromeDevtoolsTools,
23
+ registerChromeDevtoolsCapabilities,
22
24
  requireEagerChromeDevtoolsToolExposure,
23
25
  sanitizeChromeDevtoolsDisplay,
24
26
  setChromeDevtoolsSessionOwner,
25
27
  supportsNativeDeferredToolLoading,
26
28
  updateChromeDevtoolsTools,
27
29
  waitForChromeDevtoolsSettings
28
- } from "./chunks/chunk-MZCGM6D3.js";
30
+ } from "./chunks/chunk-WOFI2A72.ts";
29
31
  import {
30
32
  CHROME_DEVTOOLS_TOOL_NAMES,
31
33
  WEBMCP_TOOL_NAMES,
@@ -40,7 +42,7 @@ import {
40
42
  syncManagedBrowserSettings,
41
43
  waitForSettingsWrites,
42
44
  webMcpEnabled
43
- } from "./chunks/chunk-F5VG35UI.js";
45
+ } from "./chunks/chunk-TVVYQ5KM.ts";
44
46
 
45
47
  // src/tools.ts
46
48
  import { defineTool } from "@earendil-works/pi-coding-agent";
@@ -413,7 +415,7 @@ var webMcpListToolsTool = defineTool({
413
415
  renderResult: renderTextResult,
414
416
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
415
417
  return withStatus(ctx, "list WebMCP tools", async () => {
416
- const implementation = await import("./chunks/tools-6R7Z6HWJ.js");
418
+ const implementation = await import("./chunks/tools-DSYQPFF3.ts");
417
419
  return implementation.executeWebMcpListTool(params, signal, ctx);
418
420
  });
419
421
  }
@@ -455,7 +457,7 @@ var webMcpCallTool = defineTool({
455
457
  renderResult: renderTextResult,
456
458
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
457
459
  return withStatus(ctx, "call WebMCP tool", async () => {
458
- const implementation = await import("./chunks/tools-6R7Z6HWJ.js");
460
+ const implementation = await import("./chunks/tools-DSYQPFF3.ts");
459
461
  return implementation.executeWebMcpCallTool(params, signal, ctx);
460
462
  });
461
463
  }
@@ -538,14 +540,15 @@ var COMMAND_COMPLETIONS = [
538
540
  { value: "off", label: "off", description: "Compatibility alias for disable" }
539
541
  ];
540
542
  function chromeDevtools(pi) {
541
- pi.registerTool(listPagesTool);
542
- pi.registerTool(selectPageTool);
543
- pi.registerTool(navigateTool);
544
- pi.registerTool(evaluateTool);
545
- pi.registerTool(screenshotTool);
546
- pi.registerTool(webMcpListToolsTool);
547
- pi.registerTool(webMcpCallTool);
548
- pi.registerTool(createChromeDevtoolsLoadTool(pi));
543
+ registerChromeDevtoolsCapabilities(pi, [
544
+ listPagesTool,
545
+ selectPageTool,
546
+ navigateTool,
547
+ evaluateTool,
548
+ screenshotTool,
549
+ webMcpListToolsTool,
550
+ webMcpCallTool
551
+ ]);
549
552
  pi.registerCommand("chrome-devtools", {
550
553
  description: "Open Chrome DevTools help and tool controls",
551
554
  getArgumentCompletions: (prefix) => commandCompletions(prefix),
@@ -558,7 +561,9 @@ function chromeDevtools(pi) {
558
561
  });
559
562
  pi.on("session_start", async (_event, ctx) => {
560
563
  const generation = ++state.sessionGeneration;
561
- setChromeDevtoolsSessionOwner(pi, ctx.sessionManager);
564
+ setChromeDevtoolsSessionOwner(pi, ctx.sessionManager, ctx.sessionManager.getBranch());
565
+ const previousAvailableTools = previousChromeDevtoolsTools(pi);
566
+ const previousMode = chromeDevtoolsToolMode(pi);
562
567
  initializeAvailableChromeDevtoolsTools(pi);
563
568
  setWebMcpSessionOwner(ctx.sessionManager);
564
569
  replaceSessionController("Chrome DevTools session replaced");
@@ -576,6 +581,8 @@ function chromeDevtools(pi) {
576
581
  state.activePageId = void 0;
577
582
  state.lastLaunchAttempt = void 0;
578
583
  const projectTrusted = ctx.isProjectTrusted();
584
+ await waitForChromeDevtoolsSettings();
585
+ if (generation !== state.sessionGeneration) return;
579
586
  const settings = await loadSettings({ cwd: ctx.cwd, projectTrusted });
580
587
  if (generation !== state.sessionGeneration) return;
581
588
  applyRuntimeBrowserSettings(settings.effectiveBrowser, settings.paths, projectTrusted);
@@ -591,13 +598,30 @@ function chromeDevtools(pi) {
591
598
  "warning"
592
599
  );
593
600
  }
594
- const availableTools = settings.kind === "loaded" && settings.settings.tools ? settings.settings.tools : availableChromeDevtoolsTools(pi);
595
- configureChromeDevtoolsToolExposure(pi, availableTools, ctx.model);
601
+ const preserveToolPolicy = settings.userFile.kind === "invalid";
602
+ const availableTools = preserveToolPolicy ? previousAvailableTools : settings.kind === "loaded" && settings.settings.tools ? settings.settings.tools : allChromeDevtoolsTools(ctx.sessionManager);
603
+ const provenanceWarning = configureChromeDevtoolsToolExposure(
604
+ pi,
605
+ availableTools,
606
+ ctx.model,
607
+ preserveToolPolicy ? previousMode : settings.kind === "loaded" ? settings.settings.toolMode : "codemode"
608
+ );
609
+ if (generation !== state.sessionGeneration) return;
610
+ if (provenanceWarning) ctx.ui.notify(provenanceWarning, "warning");
611
+ const active = new Set(pi.getActiveTools());
612
+ if (chromeDevtoolsToolMode(pi) === "codemode" && !active.has("codemode") && availableChromeDevtoolsTools(pi).some((name) => !active.has(name))) {
613
+ ctx.ui.notify(
614
+ "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.",
615
+ "warning"
616
+ );
617
+ }
596
618
  });
597
619
  pi.on("model_select", (event, ctx) => {
620
+ const generation = state.sessionGeneration;
598
621
  invalidateWebMcpOperations(ctx.sessionManager, "Chrome DevTools model and tool exposure changed");
599
622
  if (!supportsNativeDeferredToolLoading(event.model)) {
600
- requireEagerChromeDevtoolsToolExposure(pi);
623
+ const provenanceWarning = requireEagerChromeDevtoolsToolExposure(pi);
624
+ if (generation === state.sessionGeneration && provenanceWarning) ctx.ui.notify(provenanceWarning, "warning");
601
625
  }
602
626
  });
603
627
  pi.on("session_shutdown", async (_event, ctx) => {
@@ -639,7 +663,7 @@ async function handleChromeDevtoolsCommand(pi, args, ctx, generation) {
639
663
  if (!ctx.hasUI || ctx.mode !== "tui" && ctx.mode !== "rpc") {
640
664
  throw new Error("/chrome-devtools settings requires TUI or RPC mode");
641
665
  }
642
- const { showChromeDevtoolsBrowserSettings } = await import("./chunks/browser-settings-menu-SR7KLZT6.js");
666
+ const { showChromeDevtoolsBrowserSettings } = await import("./chunks/browser-settings-menu-GQAXLWZ7.ts");
643
667
  if (generation !== state.sessionGeneration) return;
644
668
  await showChromeDevtoolsBrowserSettings(pi, ctx, generation);
645
669
  return;
@@ -648,7 +672,7 @@ async function handleChromeDevtoolsCommand(pi, args, ctx, generation) {
648
672
  if (!ctx.hasUI || ctx.mode !== "tui" && ctx.mode !== "rpc") {
649
673
  throw new Error("/chrome-devtools tools requires TUI or RPC mode");
650
674
  }
651
- const { showChromeDevtoolsToolWorkflow } = await import("./chunks/menu-YR4VRT7D.js");
675
+ const { showChromeDevtoolsToolWorkflow } = await import("./chunks/menu-Z26D6XSI.ts");
652
676
  if (generation !== state.sessionGeneration) return;
653
677
  await showChromeDevtoolsToolWorkflow(pi, ctx, generation);
654
678
  return;
@@ -679,7 +703,7 @@ async function showMenu(pi, ctx, generation) {
679
703
  if (!ctx.hasUI || ctx.mode !== "tui" && ctx.mode !== "rpc") {
680
704
  throw new Error("/chrome-devtools menu requires TUI or RPC mode; use a direct subcommand");
681
705
  }
682
- const { showChromeDevtoolsMenu } = await import("./chunks/menu-YR4VRT7D.js");
706
+ const { showChromeDevtoolsMenu } = await import("./chunks/menu-Z26D6XSI.ts");
683
707
  if (generation !== state.sessionGeneration) return;
684
708
  await showChromeDevtoolsMenu(pi, ctx, generation);
685
709
  }