@narumitw/pi-chrome-devtools 0.52.2 → 0.53.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 +78 -17
- package/dist/chunks/{browser-settings-menu-VI2I3TXI.js → browser-settings-menu-N5O65I7S.js} +81 -7
- package/dist/chunks/browser-settings-menu-N5O65I7S.js.map +7 -0
- package/dist/chunks/chunk-B7B63PWB.js +465 -0
- package/dist/chunks/chunk-B7B63PWB.js.map +7 -0
- package/dist/chunks/{chunk-CC37WUUE.js → chunk-GVBXT3FB.js} +369 -461
- package/dist/chunks/chunk-GVBXT3FB.js.map +7 -0
- package/dist/chunks/chunk-RTECHAEZ.js +373 -0
- package/dist/chunks/chunk-RTECHAEZ.js.map +7 -0
- package/dist/chunks/{menu-LLR455UX.js → menu-UBHW6UP2.js} +75 -41
- package/dist/chunks/menu-UBHW6UP2.js.map +7 -0
- package/dist/chunks/tools-V7OR5KJ3.js +945 -0
- package/dist/chunks/tools-V7OR5KJ3.js.map +7 -0
- package/dist/index.ts +166 -196
- package/dist/index.ts.map +4 -4
- package/package.json +4 -3
- package/src/browser-manager.ts +282 -109
- package/src/browser-settings-menu.ts +98 -4
- package/src/cdp-client.ts +329 -83
- package/src/chrome-devtools.ts +61 -13
- package/src/lazy-tools.ts +105 -8
- package/src/menu.ts +83 -41
- package/src/render.ts +12 -1
- package/src/runtime.ts +92 -0
- package/src/settings.ts +47 -10
- package/src/tool-names.ts +16 -1
- package/src/tool-selector.ts +79 -36
- package/src/tools.ts +86 -10
- package/src/webmcp/discovery.ts +235 -0
- package/src/webmcp/policy.ts +402 -0
- package/src/webmcp/protocol.ts +414 -0
- package/src/webmcp/tools.ts +190 -0
- package/dist/chunks/browser-settings-menu-VI2I3TXI.js.map +0 -7
- package/dist/chunks/chunk-CC37WUUE.js.map +0 -7
- package/dist/chunks/menu-LLR455UX.js.map +0 -7
package/README.md
CHANGED
|
@@ -14,9 +14,10 @@ The design is inspired by [`chrome-devtools-mcp`](https://github.com/ChromeDevTo
|
|
|
14
14
|
- Reuses an existing CDP endpoint or lazily launches an isolated Chromium-family browser.
|
|
15
15
|
- Recovers from stale page selections and reports actionable browser startup or endpoint errors.
|
|
16
16
|
- Loads explicitly approved unpacked extensions only in an extension-owned Chrome for Testing or Chromium process.
|
|
17
|
-
-
|
|
17
|
+
- Uses native deferred browser tools when supported and eager exposure otherwise, with availability, setup, status, and help through `/chrome-devtools`.
|
|
18
18
|
- Shows compact expandable results and activity only while browser tools are running.
|
|
19
19
|
- Persists reviewed tool availability while keeping browser connection settings machine-owned.
|
|
20
|
+
- Offers opt-in experimental WebMCP discovery and invocation through two fixed gateway tools without dynamically registering page-provided definitions.
|
|
20
21
|
|
|
21
22
|
## 📦 Install
|
|
22
23
|
|
|
@@ -44,6 +45,7 @@ The package declares `dist/index.ts`, so an unbuilt local checkout must run the
|
|
|
44
45
|
Start Pi and ask the agent to load the Chrome DevTools capability needed for the task.
|
|
45
46
|
The extension first tries `http://127.0.0.1:9222` and otherwise launches an isolated local Chromium-family browser by default.
|
|
46
47
|
Run `/chrome-devtools` to review browser status, settings, help, and available tools.
|
|
48
|
+
Experimental WebMCP remains disabled until the user explicitly enables it.
|
|
47
49
|
|
|
48
50
|
## 🌐 Browser setup
|
|
49
51
|
|
|
@@ -123,6 +125,51 @@ After editing JSON, use `/reload` or replace the session; the old managed browse
|
|
|
123
125
|
Missing files preserve the existing no-extension behavior.
|
|
124
126
|
Invalid JSON, invalid browser values, and missing manifests are left unchanged and ignored with an actionable warning.
|
|
125
127
|
|
|
128
|
+
### Experimental WebMCP
|
|
129
|
+
|
|
130
|
+
> [!WARNING]
|
|
131
|
+
> WebMCP support is experimental, disabled by default, and subject to Chrome protocol changes.
|
|
132
|
+
> Page-provided tools operate the visible page with its current authentication, entitlement, and UI state.
|
|
133
|
+
> Every call requires observable confirmation, including tools that claim to be read-only.
|
|
134
|
+
|
|
135
|
+
Enable WebMCP only in the canonical user settings file:
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"webmcp": {
|
|
140
|
+
"enabled": true
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
A project `pi-chrome-devtools.json` cannot enable WebMCP or weaken confirmation policy.
|
|
146
|
+
The settings menu labels WebMCP as experimental, persists the user-owned boolean atomically, and aborts active WebMCP work before disablement or browser replacement.
|
|
147
|
+
The two gateway tools remain unavailable while the gate is disabled even if an older `tools` array contains their names.
|
|
148
|
+
After enabling the gate, choose whether each gateway is available through `/chrome-devtools tools` or the main menu.
|
|
149
|
+
|
|
150
|
+
WebMCP requires a Chrome build whose `/json/protocol` exposes the experimental `WebMCP` domain.
|
|
151
|
+
Origin-trial sites must meet Chrome's Origin Trial, origin isolation, Permissions Policy, authentication, and browser feature requirements.
|
|
152
|
+
For local pages outside an Origin Trial, open `chrome://flags/#enable-webmcp-testing`, enable **WebMCP for testing**, and relaunch a compatible Chrome build.
|
|
153
|
+
The extension does not automatically add testing flags to a managed browser.
|
|
154
|
+
|
|
155
|
+
`chrome_devtools_webmcp_list_tools` opens an operation-scoped page CDP session, lists frame-aware page tools, and returns bounded metadata with a deterministic schema-and-annotation digest.
|
|
156
|
+
`chrome_devtools_webmcp_call_tool` re-discovers the exact page, document loader, frame, origin, tool, schema, annotations, and session generation before invocation and again after confirmation.
|
|
157
|
+
The call gateway rejects print and JSON modes because they cannot provide observable confirmation.
|
|
158
|
+
TUI and RPC modes use Pi's standard confirmation dialog.
|
|
159
|
+
Cancellation is forwarded to Chrome through `WebMCP.cancelInvocation` after Chrome returns an invocation ID.
|
|
160
|
+
|
|
161
|
+
Page URLs, origins, names, descriptions, schemas, errors, and outputs are untrusted.
|
|
162
|
+
Displayed text strips terminal controls and bidirectional overrides, accepted JSON has explicit byte, depth, and collection limits, and model-visible output is capped at 50 KB or 2,000 lines.
|
|
163
|
+
CDP text messages are capped at 8 MB before JSON parsing.
|
|
164
|
+
Page-controlled `pattern` and `patternProperties` schemas and schemas exceeding 128 combinator branches are rejected because they cannot be evaluated safely on Pi's main thread.
|
|
165
|
+
Annotations are descriptive hints only and never authorize a call.
|
|
166
|
+
WebMCP is not backend MCP, generic browser automation, or a way to bypass browser policy.
|
|
167
|
+
|
|
168
|
+
If listing reports that the WebMCP domain is unavailable, update Chrome and verify `/json/protocol` contains `WebMCP`.
|
|
169
|
+
If a page lists no tools, verify that the site participates in the Origin Trial or that **WebMCP for testing** is enabled for local development.
|
|
170
|
+
If a call reports a stale identity, list tools again after navigation, reload, frame changes, tool registration changes, settings changes, or browser replacement.
|
|
171
|
+
Attached everyday browser profiles receive a stronger confirmation warning than isolated managed profiles.
|
|
172
|
+
|
|
126
173
|
### Deprecated environment overrides and manual endpoints
|
|
127
174
|
|
|
128
175
|
The existing `PI_CHROME_DEVTOOLS_HOST`, `PI_CHROME_DEVTOOLS_PORT`, `PI_CHROME_DEVTOOLS_AUTO_LAUNCH`, and `PI_CHROME_DEVTOOLS_BROWSER` variables remain temporary compatibility overrides.
|
|
@@ -147,22 +194,34 @@ It never closes user-started browsers or remote endpoints.
|
|
|
147
194
|
- `chrome_devtools_navigate` — navigate a page to a URL; if no page exists, create one first.
|
|
148
195
|
- `chrome_devtools_evaluate` — evaluate JavaScript in the selected page.
|
|
149
196
|
- `chrome_devtools_screenshot` — capture a PNG screenshot and save it as a PNG file.
|
|
197
|
+
- `chrome_devtools_webmcp_list_tools` — list bounded frame-aware WebMCP descriptors from the selected page when experimental WebMCP is enabled.
|
|
198
|
+
- `chrome_devtools_webmcp_call_tool` — invoke one listed page tool after exact identity revalidation and user confirmation.
|
|
199
|
+
|
|
200
|
+
### Tool exposure
|
|
150
201
|
|
|
151
|
-
|
|
202
|
+
All eight tools are registered: one loader, five stable DevTools capabilities, and two fixed experimental WebMCP gateways.
|
|
152
203
|
|
|
153
|
-
|
|
204
|
+
On a model/provider with native deferred-tool support, only `chrome_devtools_load` starts active for this extension.
|
|
154
205
|
|
|
155
|
-
The loader accepts a task-oriented `query`, matches it against the five
|
|
206
|
+
The loader accepts a task-oriented `query`, matches it against the five stable capabilities plus enabled WebMCP gateways, and adds matching available tools without removing any active Pi tool.
|
|
156
207
|
|
|
157
208
|
Loaded capability tools remain active for the rest of the session unless the user makes them unavailable through `/chrome-devtools`.
|
|
158
209
|
|
|
159
|
-
Pi uses native deferred tool references on compatible Anthropic and OpenAI models.
|
|
210
|
+
Pi uses native deferred tool references on compatible Anthropic models, native additional-tools or tool-search loading on compatible OpenAI and Codex Responses models, and native Kimi loading on compatible OpenAI Chat Completions models.
|
|
211
|
+
|
|
212
|
+
Kimi-compatible models declare `compat.deferredToolsMode: "kimi"` in Pi's model metadata.
|
|
213
|
+
|
|
214
|
+
`azure-openai-responses` remains eager because Pi's Azure adapter does not implement native deferred tool-search serialization.
|
|
215
|
+
|
|
216
|
+
When the selected model/provider lacks native deferred support, the extension activates every capability allowed by settings before the next model request instead of using Pi's cache-invalidating lazy-loading fallback.
|
|
160
217
|
|
|
161
|
-
|
|
218
|
+
After a session enters eager exposure, it stays eager across later model switches to avoid removing tool definitions within that session.
|
|
162
219
|
|
|
163
|
-
The capability tools omit active-only prompt snippets so
|
|
220
|
+
The capability tools omit active-only prompt snippets so native deferred loading does not rebuild the system-prompt prefix.
|
|
164
221
|
|
|
165
|
-
The saved `tools` array controls which capabilities the
|
|
222
|
+
The saved `tools` array controls which capabilities the extension may expose.
|
|
223
|
+
The `webmcp.enabled` gate is applied before that catalog, so persisted WebMCP names cannot bypass a disabled gate.
|
|
224
|
+
Page-provided tool definitions appear only in list results and never alter Pi's provider-visible tool definitions.
|
|
166
225
|
|
|
167
226
|
An empty array leaves the loader active but makes every browser capability unavailable.
|
|
168
227
|
|
|
@@ -198,13 +257,13 @@ If the model cannot inspect the inline image, ask it to read the saved path, for
|
|
|
198
257
|
/chrome-devtools
|
|
199
258
|
```
|
|
200
259
|
|
|
201
|
-
Opens a menu that shows the
|
|
260
|
+
Opens a menu that shows the tool catalog size, whether that catalog is saved, the configured endpoint, the observed managed-browser state, and any settings or launch warning before you choose an action.
|
|
202
261
|
The five actions stay on one level:
|
|
203
262
|
|
|
204
|
-
- **Choose available browser tools…** — stage any combination of the five capabilities, then review the exact available/unavailable result before selecting **Apply tool changes**.
|
|
263
|
+
- **Choose available browser tools…** — stage any combination of the five stable capabilities and, when enabled, the two experimental WebMCP gateways, then review the exact available/unavailable result before selecting **Apply tool changes**.
|
|
205
264
|
- **Make all browser tools available…** or **Make all browser tools unavailable…** — preview the context-appropriate bulk change before applying it.
|
|
206
265
|
- **Browser status** — inspect runtime, endpoint, launch mode, and the last launch attempt without probing the endpoint or starting Chrome.
|
|
207
|
-
- **Browser settings** — immediately save the endpoint, auto-launch policy, or
|
|
266
|
+
- **Browser settings** — immediately save the endpoint, auto-launch policy, browser executable, or experimental WebMCP gate.
|
|
208
267
|
Inspect unpacked-extension paths and effective sources.
|
|
209
268
|
A deprecated environment override remains effective until removed even when its underlying JSON value changes.
|
|
210
269
|
- **Help** — view command usage and return to the menu.
|
|
@@ -235,8 +294,8 @@ Compatibility aliases remain available: `toggle` and `select` mean `tools`, `on`
|
|
|
235
294
|
- `settings` opens the same immediate-save browser settings flow used by the menu.
|
|
236
295
|
- `tools` opens the same staged, width-safe availability and review flow used by the menu.
|
|
237
296
|
- `toggle` and `select` are compatibility aliases for `tools`.
|
|
238
|
-
- `enable` makes all
|
|
239
|
-
- `disable` makes all
|
|
297
|
+
- `enable` makes all currently gated capability tools available and follows the current native-deferred or eager exposure mode; `on` is a compatibility alias.
|
|
298
|
+
- `disable` makes all capability tools unavailable and saves the empty catalog; `off` is a compatibility alias.
|
|
240
299
|
The slash command and `chrome_devtools_load` remain available.
|
|
241
300
|
|
|
242
301
|
The menu, `settings`, `tools`, `help`, `quickstart`, and `status` require TUI or RPC mode so their result is observable.
|
|
@@ -252,13 +311,13 @@ The available capability names are saved to:
|
|
|
252
311
|
${PI_CODING_AGENT_DIR:-~/.pi/agent}/pi-chrome-devtools.json
|
|
253
312
|
```
|
|
254
313
|
|
|
255
|
-
The same file owns `browser.endpoint`, `browser.autoLaunch`, `browser.executablePath`, and `
|
|
256
|
-
Browser connection fields are machine-owned user settings; trusted project files may replace only `browser.extensionPaths`.
|
|
314
|
+
The same file owns `browser.endpoint`, `browser.autoLaunch`, `browser.executablePath`, `browser.extensionPaths`, and user-only `webmcp.enabled`.
|
|
315
|
+
Browser connection fields and `webmcp.enabled` are machine-owned user settings; trusted project files may replace only `browser.extensionPaths`.
|
|
257
316
|
Confirmed menu changes apply before the next browser connection and close only an extension-owned managed browser.
|
|
258
317
|
Manual JSON edits and unpacked-extension changes apply after `/reload` or session replacement.
|
|
259
318
|
|
|
260
319
|
When the file is missing or invalid, the extension preserves Pi's current Chrome DevTools availability policy instead of replacing it.
|
|
261
|
-
A valid saved catalog is restored on Pi startup and `/reload`,
|
|
320
|
+
A valid saved catalog is restored on Pi startup and `/reload`, with capability definitions exposed natively deferred or eagerly according to model/provider support.
|
|
262
321
|
A missing file is created by the first confirmed browser or tool setting.
|
|
263
322
|
Within one Pi process, all browser and tool saves run in invocation order, reread the latest valid document, publish by temporary-file rename, and preserve unknown fields.
|
|
264
323
|
Malformed JSON or invalid recognized fields make menu mutation unavailable and block direct saves without replacement; a failed save restores the prior displayed and effective state.
|
|
@@ -282,12 +341,14 @@ The legacy filename is deprecated and will be removed in a future major release.
|
|
|
282
341
|
```txt
|
|
283
342
|
packages/pi-chrome-devtools/
|
|
284
343
|
├── dist/ # Generated TypeScript runtime loaded by Jiti
|
|
344
|
+
├── reference/webmcp/ # Non-entrypoint compatibility prototype
|
|
285
345
|
├── scripts/
|
|
286
346
|
│ └── build-runtime.mjs # Deterministic runtime builder and boundary validator
|
|
287
347
|
├── src/
|
|
288
348
|
│ ├── index.ts # Pi package entrypoint
|
|
289
349
|
│ ├── chrome-devtools.ts # Extension registration and command orchestration
|
|
290
350
|
│ ├── lazy-tools.ts # Deferred capability catalog and loader tool
|
|
351
|
+
│ ├── webmcp/ # Lazy CDP protocol, discovery, policy, and invocation implementation
|
|
291
352
|
│ └── *.ts # Package-local browser, CDP, tool, and storage modules
|
|
292
353
|
├── README.md
|
|
293
354
|
├── LICENSE
|
|
@@ -310,7 +371,7 @@ The generated runtime is built from the authoritative `src/index.ts` graph and d
|
|
|
310
371
|
|
|
311
372
|
## 🔎 Keywords
|
|
312
373
|
|
|
313
|
-
Pi extension, Pi coding agent, Chrome DevTools Protocol, CDP, browser automation, web debugging, JavaScript evaluation, screenshot automation, AI coding agent tools.
|
|
374
|
+
Pi extension, Pi coding agent, Chrome DevTools Protocol, CDP, WebMCP, browser automation, web debugging, JavaScript evaluation, screenshot automation, AI coding agent tools.
|
|
314
375
|
|
|
315
376
|
## 📄 License
|
|
316
377
|
|
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
// @generated by scripts/build-runtime.mjs; do not edit.
|
|
2
2
|
// @ts-nocheck -- the generated entry uses a .ts extension for Pi's Jiti loader.
|
|
3
|
+
import {
|
|
4
|
+
applyAvailableChromeDevtoolsTools,
|
|
5
|
+
configuredChromeDevtoolsTools,
|
|
6
|
+
sanitizeChromeDevtoolsDisplay,
|
|
7
|
+
setChromeDevtoolsSessionOwner
|
|
8
|
+
} from "./chunk-B7B63PWB.js";
|
|
3
9
|
import {
|
|
4
10
|
applyRuntimeBrowserSettings,
|
|
11
|
+
applyRuntimeWebMcpSetting,
|
|
12
|
+
invalidateWebMcpOperations,
|
|
5
13
|
loadSettings,
|
|
6
14
|
parseBrowserEndpoint,
|
|
7
|
-
sanitizeChromeDevtoolsDisplay,
|
|
8
15
|
saveBrowserSettings,
|
|
16
|
+
saveWebMcpSettings,
|
|
9
17
|
shutdownManagedBrowser,
|
|
10
|
-
state
|
|
11
|
-
|
|
18
|
+
state,
|
|
19
|
+
webMcpEnabled
|
|
20
|
+
} from "./chunk-GVBXT3FB.js";
|
|
12
21
|
|
|
13
22
|
// src/browser-settings-menu.ts
|
|
14
23
|
import { isAbsolute } from "node:path";
|
|
15
24
|
import { defineMenu, runMenu } from "@narumitw/pi-tui-kit";
|
|
16
|
-
async function showChromeDevtoolsBrowserSettings(ctx, generation) {
|
|
25
|
+
async function showChromeDevtoolsBrowserSettings(pi, ctx, generation) {
|
|
26
|
+
setChromeDevtoolsSessionOwner(pi, ctx.sessionManager);
|
|
17
27
|
const ownerSignal = state.sessionController.signal;
|
|
18
28
|
const isCurrent2 = () => generation === state.sessionGeneration && !ownerSignal.aborted;
|
|
19
29
|
const projectTrusted = ctx.isProjectTrusted();
|
|
@@ -50,6 +60,14 @@ async function showChromeDevtoolsBrowserSettings(ctx, generation) {
|
|
|
50
60
|
currentValue: sanitizeChromeDevtoolsDisplay(browser.executablePath ?? "Automatic"),
|
|
51
61
|
action: "open-executable"
|
|
52
62
|
},
|
|
63
|
+
{
|
|
64
|
+
id: "webmcp",
|
|
65
|
+
label: "WebMCP \xB7 Experimental",
|
|
66
|
+
description: "Allow user-confirmed calls to page-provided WebMCP tools in this browser session.",
|
|
67
|
+
currentValue: current.load.effectiveWebMcpEnabled ? "On" : "Off",
|
|
68
|
+
values: ["On", "Off"],
|
|
69
|
+
action: "set-webmcp"
|
|
70
|
+
},
|
|
53
71
|
{
|
|
54
72
|
id: "extensions",
|
|
55
73
|
label: "Unpacked extensions",
|
|
@@ -141,6 +159,24 @@ async function showChromeDevtoolsBrowserSettings(ctx, generation) {
|
|
|
141
159
|
);
|
|
142
160
|
return { kind: "stay" };
|
|
143
161
|
},
|
|
162
|
+
"set-webmcp": async ({ value, signal }) => {
|
|
163
|
+
if (value !== "On" && value !== "Off") return { kind: "rejected" };
|
|
164
|
+
const saved = await saveAndApplyWebMcpSetting(
|
|
165
|
+
pi,
|
|
166
|
+
ctx,
|
|
167
|
+
generation,
|
|
168
|
+
ownerSignal,
|
|
169
|
+
signal,
|
|
170
|
+
projectTrusted,
|
|
171
|
+
value === "On"
|
|
172
|
+
);
|
|
173
|
+
if (!saved) return { kind: "rejected" };
|
|
174
|
+
ctx.ui.notify(
|
|
175
|
+
saved.effectiveWebMcpEnabled ? "Experimental WebMCP enabled. Every page-provided tool call requires confirmation. Choose gateway availability under Browser tools." : "Experimental WebMCP disabled. Active WebMCP work was aborted and both gateway tools are unavailable.",
|
|
176
|
+
"warning"
|
|
177
|
+
);
|
|
178
|
+
return { kind: "stay" };
|
|
179
|
+
},
|
|
144
180
|
"open-executable": () => ({ kind: "to", screen: "executable" }),
|
|
145
181
|
"save-executable": async ({ value, signal }) => {
|
|
146
182
|
if (value === void 0) return { kind: "rejected" };
|
|
@@ -195,7 +231,8 @@ async function saveAndApplyBrowserPatch(ctx, generation, ownerSignal, actionSign
|
|
|
195
231
|
if (!isCurrent(generation, ownerSignal, actionSignal)) return false;
|
|
196
232
|
await saveBrowserSettings(patch);
|
|
197
233
|
if (!isCurrent(generation, ownerSignal, actionSignal)) return false;
|
|
198
|
-
|
|
234
|
+
invalidateWebMcpOperations(ctx.sessionManager, "Chrome DevTools browser configuration changed");
|
|
235
|
+
await shutdownManagedBrowser(void 0, { owner: ctx.sessionManager });
|
|
199
236
|
if (!isCurrent(generation, ownerSignal, actionSignal)) return false;
|
|
200
237
|
const loaded = await loadSettings({ cwd: ctx.cwd, projectTrusted });
|
|
201
238
|
if (!isCurrent(generation, ownerSignal, actionSignal)) return false;
|
|
@@ -207,8 +244,45 @@ async function saveAndApplyBrowserPatch(ctx, generation, ownerSignal, actionSign
|
|
|
207
244
|
return false;
|
|
208
245
|
}
|
|
209
246
|
}
|
|
247
|
+
async function saveAndApplyWebMcpSetting(pi, ctx, generation, ownerSignal, actionSignal, projectTrusted, enabled) {
|
|
248
|
+
const previousEnabled = webMcpEnabled(ctx.sessionManager);
|
|
249
|
+
const previousTools = configuredChromeDevtoolsTools(pi);
|
|
250
|
+
try {
|
|
251
|
+
await ctx.waitForIdle();
|
|
252
|
+
if (!isCurrent(generation, ownerSignal, actionSignal)) return false;
|
|
253
|
+
applyRuntimeWebMcpSetting(enabled, ctx.sessionManager);
|
|
254
|
+
applyAvailableChromeDevtoolsTools(pi, previousTools);
|
|
255
|
+
await saveWebMcpSettings(enabled);
|
|
256
|
+
if (!isOwnerCurrent(generation, ownerSignal)) return false;
|
|
257
|
+
const loaded = await loadSettings({ cwd: ctx.cwd, projectTrusted });
|
|
258
|
+
if (!isOwnerCurrent(generation, ownerSignal)) return false;
|
|
259
|
+
state.settingsNotice = loaded.notice;
|
|
260
|
+
return loaded;
|
|
261
|
+
} catch (error) {
|
|
262
|
+
if (!isOwnerCurrent(generation, ownerSignal)) return false;
|
|
263
|
+
let rollbackError;
|
|
264
|
+
try {
|
|
265
|
+
applyRuntimeWebMcpSetting(previousEnabled, ctx.sessionManager);
|
|
266
|
+
applyAvailableChromeDevtoolsTools(pi, previousTools);
|
|
267
|
+
} catch (caught) {
|
|
268
|
+
rollbackError = caught;
|
|
269
|
+
}
|
|
270
|
+
if (isCurrent(generation, ownerSignal, actionSignal)) {
|
|
271
|
+
notifySaveFailure(
|
|
272
|
+
ctx,
|
|
273
|
+
rollbackError ? new Error(
|
|
274
|
+
`${formatError(error)}; WebMCP rollback failed: ${formatError(rollbackError)}`
|
|
275
|
+
) : error
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function isOwnerCurrent(generation, ownerSignal) {
|
|
282
|
+
return generation === state.sessionGeneration && !ownerSignal.aborted;
|
|
283
|
+
}
|
|
210
284
|
function isCurrent(generation, ownerSignal, actionSignal) {
|
|
211
|
-
return generation
|
|
285
|
+
return isOwnerCurrent(generation, ownerSignal) && !actionSignal.aborted;
|
|
212
286
|
}
|
|
213
287
|
function invalidSettingsScreen(load) {
|
|
214
288
|
const reason = load.userFile.kind === "invalid" ? load.userFile.reason : "The user settings file is unavailable.";
|
|
@@ -263,4 +337,4 @@ function formatError(error) {
|
|
|
263
337
|
export {
|
|
264
338
|
showChromeDevtoolsBrowserSettings
|
|
265
339
|
};
|
|
266
|
-
//# sourceMappingURL=browser-settings-menu-
|
|
340
|
+
//# sourceMappingURL=browser-settings-menu-N5O65I7S.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/browser-settings-menu.ts"],
|
|
4
|
+
"sourcesContent": ["import { isAbsolute } from \"node:path\";\nimport type { ExtensionAPI, ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { defineMenu, runMenu } from \"@narumitw/pi-tui-kit\";\nimport { shutdownManagedBrowser } from \"./browser-manager.js\";\nimport {\n\tapplyAvailableChromeDevtoolsTools,\n\tconfiguredChromeDevtoolsTools,\n\tsetChromeDevtoolsSessionOwner,\n} from \"./lazy-tools.js\";\nimport {\n\tapplyRuntimeBrowserSettings,\n\tapplyRuntimeWebMcpSetting,\n\tinvalidateWebMcpOperations,\n\tstate,\n\twebMcpEnabled,\n} from \"./runtime.js\";\nimport {\n\ttype BrowserSettingsPatch,\n\ttype BrowserSettingsSource,\n\tloadSettings,\n\tparseBrowserEndpoint,\n\ttype SettingsLoadResult,\n\tsaveBrowserSettings,\n\tsaveWebMcpSettings,\n} from \"./settings.js\";\nimport { sanitizeChromeDevtoolsDisplay } from \"./tool-selector.js\";\n\ntype BrowserSettingsScreen = \"settings\" | \"endpoint\" | \"executable\" | \"extensions\";\ntype BrowserSettingsAction =\n\t| \"open-endpoint\"\n\t| \"save-endpoint\"\n\t| \"set-auto-launch\"\n\t| \"set-webmcp\"\n\t| \"open-executable\"\n\t| \"save-executable\"\n\t| \"show-extensions\";\n\ninterface BrowserSettingsMenuState {\n\tload: SettingsLoadResult;\n}\n\ntype CommandContext = ExtensionCommandContext;\n\nexport async function showChromeDevtoolsBrowserSettings(\n\tpi: ExtensionAPI,\n\tctx: CommandContext,\n\tgeneration: number,\n): Promise<{ closeParent: boolean }> {\n\tsetChromeDevtoolsSessionOwner(pi, ctx.sessionManager);\n\tconst ownerSignal = state.sessionController.signal;\n\tconst isCurrent = () => generation === state.sessionGeneration && !ownerSignal.aborted;\n\tconst projectTrusted = ctx.isProjectTrusted();\n\tconst menu = defineMenu<BrowserSettingsMenuState, BrowserSettingsScreen, BrowserSettingsAction>({\n\t\tstart: \"settings\",\n\t\tscreens: {\n\t\t\tsettings: ({ state: current }) => {\n\t\t\t\tif (current.load.userFile.kind === \"invalid\") return invalidSettingsScreen(current.load);\n\t\t\t\tconst browser = current.load.effectiveBrowser;\n\t\t\t\treturn {\n\t\t\t\t\tkind: \"settings\",\n\t\t\t\t\ttitle: \"Chrome DevTools Browser settings\",\n\t\t\t\t\tlines: settingsContextLines(current.load),\n\t\t\t\t\titems: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid: \"endpoint\",\n\t\t\t\t\t\t\tlabel: \"DevTools endpoint\",\n\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t'HTTP origin with an explicit port; enter \"default\" to restore 127.0.0.1:9222.',\n\t\t\t\t\t\t\tcurrentValue: sanitizeChromeDevtoolsDisplay(browser.endpoint),\n\t\t\t\t\t\t\taction: \"open-endpoint\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid: \"auto-launch\",\n\t\t\t\t\t\t\tlabel: \"Auto-launch\",\n\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\"Launch an isolated managed browser when a local endpoint is unavailable.\",\n\t\t\t\t\t\t\tcurrentValue: browser.autoLaunchEnabled ? \"On\" : \"Off\",\n\t\t\t\t\t\t\tvalues: [\"On\", \"Off\"],\n\t\t\t\t\t\t\taction: \"set-auto-launch\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid: \"executable\",\n\t\t\t\t\t\t\tlabel: \"Browser executable\",\n\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t'Absolute executable path; enter \"automatic\" to restore browser discovery.',\n\t\t\t\t\t\t\tcurrentValue: sanitizeChromeDevtoolsDisplay(browser.executablePath ?? \"Automatic\"),\n\t\t\t\t\t\t\taction: \"open-executable\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid: \"webmcp\",\n\t\t\t\t\t\t\tlabel: \"WebMCP \u00B7 Experimental\",\n\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\"Allow user-confirmed calls to page-provided WebMCP tools in this browser session.\",\n\t\t\t\t\t\t\tcurrentValue: current.load.effectiveWebMcpEnabled ? \"On\" : \"Off\",\n\t\t\t\t\t\t\tvalues: [\"On\", \"Off\"],\n\t\t\t\t\t\t\taction: \"set-webmcp\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tid: \"extensions\",\n\t\t\t\t\t\t\tlabel: \"Unpacked extensions\",\n\t\t\t\t\t\t\tdescription: \"Inspect trusted extension paths configured in user or project JSON.\",\n\t\t\t\t\t\t\tcurrentValue: `${browser.extensionPaths.length} configured`,\n\t\t\t\t\t\t\taction: \"show-extensions\",\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t};\n\t\t\t},\n\t\t\tendpoint: ({ state: current }) => ({\n\t\t\t\tkind: \"input\",\n\t\t\t\ttitle: \"DevTools endpoint\",\n\t\t\t\tlines: [\n\t\t\t\t\tsanitizeChromeDevtoolsDisplay(\n\t\t\t\t\t\t`Current effective endpoint: ${current.load.effectiveBrowser.endpoint}`,\n\t\t\t\t\t),\n\t\t\t\t\t'Enter an HTTP origin with an explicit port, or \"default\".',\n\t\t\t\t],\n\t\t\t\tplaceholder: \"http://127.0.0.1:9222\",\n\t\t\t\taction: \"save-endpoint\",\n\t\t\t\thint: \"back\",\n\t\t\t}),\n\t\t\texecutable: ({ state: current }) => ({\n\t\t\t\tkind: \"input\",\n\t\t\t\ttitle: \"Browser executable\",\n\t\t\t\tlines: [\n\t\t\t\t\tsanitizeChromeDevtoolsDisplay(\n\t\t\t\t\t\t`Current effective executable: ${current.load.effectiveBrowser.executablePath ?? \"automatic discovery\"}`,\n\t\t\t\t\t),\n\t\t\t\t\t'Enter an absolute path, or \"automatic\".',\n\t\t\t\t],\n\t\t\t\tplaceholder: \"absolute browser executable path\",\n\t\t\t\taction: \"save-executable\",\n\t\t\t\thint: \"back\",\n\t\t\t}),\n\t\t\textensions: ({ state: current }) => ({\n\t\t\t\tkind: \"detail\",\n\t\t\t\ttitle: \"Unpacked extensions\",\n\t\t\t\tlines: extensionDetailLines(current.load),\n\t\t\t\thint: \"back\",\n\t\t\t}),\n\t\t},\n\t\tactions: {\n\t\t\t\"open-endpoint\": () => ({ kind: \"to\", screen: \"endpoint\" }),\n\t\t\t\"save-endpoint\": async ({ value, signal }) => {\n\t\t\t\tif (value === undefined) return { kind: \"rejected\" };\n\t\t\t\tlet endpoint: string | null;\n\t\t\t\ttry {\n\t\t\t\t\tconst trimmed = value.trim();\n\t\t\t\t\tendpoint =\n\t\t\t\t\t\ttrimmed.toLowerCase() === \"default\" ? null : parseBrowserEndpoint(trimmed).endpoint;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tnotifySaveFailure(ctx, error);\n\t\t\t\t\treturn { kind: \"rejected\" };\n\t\t\t\t}\n\t\t\t\tconst saved = await saveAndApplyBrowserPatch(\n\t\t\t\t\tctx,\n\t\t\t\t\tgeneration,\n\t\t\t\t\townerSignal,\n\t\t\t\t\tsignal,\n\t\t\t\t\tprojectTrusted,\n\t\t\t\t\t{ endpoint },\n\t\t\t\t);\n\t\t\t\tif (!saved) return { kind: \"rejected\" };\n\t\t\t\tnotifyEffectiveSave(\n\t\t\t\t\tctx,\n\t\t\t\t\t\"endpoint\",\n\t\t\t\t\tsaved.effectiveBrowser.endpoint,\n\t\t\t\t\tsaved.effectiveBrowser.endpointSource,\n\t\t\t\t);\n\t\t\t\treturn { kind: \"back\" };\n\t\t\t},\n\t\t\t\"set-auto-launch\": async ({ value, signal }) => {\n\t\t\t\tif (value !== \"On\" && value !== \"Off\") return { kind: \"rejected\" };\n\t\t\t\tconst saved = await saveAndApplyBrowserPatch(\n\t\t\t\t\tctx,\n\t\t\t\t\tgeneration,\n\t\t\t\t\townerSignal,\n\t\t\t\t\tsignal,\n\t\t\t\t\tprojectTrusted,\n\t\t\t\t\t{ autoLaunch: value === \"On\" },\n\t\t\t\t);\n\t\t\t\tif (!saved) return { kind: \"rejected\" };\n\t\t\t\tnotifyEffectiveSave(\n\t\t\t\t\tctx,\n\t\t\t\t\t\"auto-launch\",\n\t\t\t\t\tsaved.effectiveBrowser.autoLaunchEnabled ? \"On\" : \"Off\",\n\t\t\t\t\tsaved.effectiveBrowser.autoLaunchSource,\n\t\t\t\t);\n\t\t\t\treturn { kind: \"stay\" };\n\t\t\t},\n\t\t\t\"set-webmcp\": async ({ value, signal }) => {\n\t\t\t\tif (value !== \"On\" && value !== \"Off\") return { kind: \"rejected\" };\n\t\t\t\tconst saved = await saveAndApplyWebMcpSetting(\n\t\t\t\t\tpi,\n\t\t\t\t\tctx,\n\t\t\t\t\tgeneration,\n\t\t\t\t\townerSignal,\n\t\t\t\t\tsignal,\n\t\t\t\t\tprojectTrusted,\n\t\t\t\t\tvalue === \"On\",\n\t\t\t\t);\n\t\t\t\tif (!saved) return { kind: \"rejected\" };\n\t\t\t\tctx.ui.notify(\n\t\t\t\t\tsaved.effectiveWebMcpEnabled\n\t\t\t\t\t\t? \"Experimental WebMCP enabled. Every page-provided tool call requires confirmation. Choose gateway availability under Browser tools.\"\n\t\t\t\t\t\t: \"Experimental WebMCP disabled. Active WebMCP work was aborted and both gateway tools are unavailable.\",\n\t\t\t\t\t\"warning\",\n\t\t\t\t);\n\t\t\t\treturn { kind: \"stay\" };\n\t\t\t},\n\t\t\t\"open-executable\": () => ({ kind: \"to\", screen: \"executable\" }),\n\t\t\t\"save-executable\": async ({ value, signal }) => {\n\t\t\t\tif (value === undefined) return { kind: \"rejected\" };\n\t\t\t\tconst trimmed = value.trim();\n\t\t\t\tconst reset = [\"automatic\", \"default\", \"none\"].includes(trimmed.toLowerCase());\n\t\t\t\tif (!reset && (!trimmed || !isAbsolute(trimmed))) {\n\t\t\t\t\tnotifySaveFailure(ctx, new Error('Enter an absolute path or \"automatic\".'));\n\t\t\t\t\treturn { kind: \"rejected\" };\n\t\t\t\t}\n\t\t\t\tconst executablePath = reset ? null : trimmed;\n\t\t\t\tconst saved = await saveAndApplyBrowserPatch(\n\t\t\t\t\tctx,\n\t\t\t\t\tgeneration,\n\t\t\t\t\townerSignal,\n\t\t\t\t\tsignal,\n\t\t\t\t\tprojectTrusted,\n\t\t\t\t\t{ executablePath },\n\t\t\t\t);\n\t\t\t\tif (!saved) return { kind: \"rejected\" };\n\t\t\t\tnotifyEffectiveSave(\n\t\t\t\t\tctx,\n\t\t\t\t\t\"browser executable\",\n\t\t\t\t\tsaved.effectiveBrowser.executablePath ?? \"automatic discovery\",\n\t\t\t\t\tsaved.effectiveBrowser.executablePathSource,\n\t\t\t\t);\n\t\t\t\treturn { kind: \"back\" };\n\t\t\t},\n\t\t\t\"show-extensions\": () => ({ kind: \"to\", screen: \"extensions\" }),\n\t\t},\n\t});\n\tconst result = await runMenu(ctx, menu, {\n\t\tgetState: async ({ signal }) => {\n\t\t\tsignal.throwIfAborted();\n\t\t\tconst load = await loadSettings({ cwd: ctx.cwd, projectTrusted });\n\t\t\tsignal.throwIfAborted();\n\t\t\treturn { load };\n\t\t},\n\t\tsignal: ownerSignal,\n\t\tisCurrent,\n\t\tonError: (currentCtx, error) =>\n\t\t\tcurrentCtx.ui.notify(\n\t\t\t\tsanitizeChromeDevtoolsDisplay(\n\t\t\t\t\t`Chrome DevTools browser settings failed: ${formatError(error)}`,\n\t\t\t\t),\n\t\t\t\t\"error\",\n\t\t\t),\n\t});\n\treturn { closeParent: result.kind === \"closed\" && result.reason === \"close\" };\n}\n\nasync function saveAndApplyBrowserPatch(\n\tctx: CommandContext,\n\tgeneration: number,\n\townerSignal: AbortSignal,\n\tactionSignal: AbortSignal,\n\tprojectTrusted: boolean,\n\tpatch: BrowserSettingsPatch,\n) {\n\ttry {\n\t\tawait ctx.waitForIdle();\n\t\tif (!isCurrent(generation, ownerSignal, actionSignal)) return false;\n\t\tawait saveBrowserSettings(patch);\n\t\tif (!isCurrent(generation, ownerSignal, actionSignal)) return false;\n\t\tinvalidateWebMcpOperations(ctx.sessionManager, \"Chrome DevTools browser configuration changed\");\n\t\tawait shutdownManagedBrowser(undefined, { owner: ctx.sessionManager });\n\t\tif (!isCurrent(generation, ownerSignal, actionSignal)) return false;\n\t\tconst loaded = await loadSettings({ cwd: ctx.cwd, projectTrusted });\n\t\tif (!isCurrent(generation, ownerSignal, actionSignal)) return false;\n\t\tapplyRuntimeBrowserSettings(loaded.effectiveBrowser, loaded.paths, projectTrusted);\n\t\tstate.settingsNotice = loaded.notice;\n\t\treturn loaded;\n\t} catch (error) {\n\t\tif (isCurrent(generation, ownerSignal, actionSignal)) notifySaveFailure(ctx, error);\n\t\treturn false;\n\t}\n}\n\nasync function saveAndApplyWebMcpSetting(\n\tpi: ExtensionAPI,\n\tctx: CommandContext,\n\tgeneration: number,\n\townerSignal: AbortSignal,\n\tactionSignal: AbortSignal,\n\tprojectTrusted: boolean,\n\tenabled: boolean,\n) {\n\tconst previousEnabled = webMcpEnabled(ctx.sessionManager);\n\tconst previousTools = configuredChromeDevtoolsTools(pi);\n\ttry {\n\t\tawait ctx.waitForIdle();\n\t\tif (!isCurrent(generation, ownerSignal, actionSignal)) return false;\n\t\tapplyRuntimeWebMcpSetting(enabled, ctx.sessionManager);\n\t\tapplyAvailableChromeDevtoolsTools(pi, previousTools);\n\t\tawait saveWebMcpSettings(enabled);\n\t\tif (!isOwnerCurrent(generation, ownerSignal)) return false;\n\t\tconst loaded = await loadSettings({ cwd: ctx.cwd, projectTrusted });\n\t\tif (!isOwnerCurrent(generation, ownerSignal)) return false;\n\t\tstate.settingsNotice = loaded.notice;\n\t\treturn loaded;\n\t} catch (error) {\n\t\tif (!isOwnerCurrent(generation, ownerSignal)) return false;\n\t\tlet rollbackError: unknown;\n\t\ttry {\n\t\t\tapplyRuntimeWebMcpSetting(previousEnabled, ctx.sessionManager);\n\t\t\tapplyAvailableChromeDevtoolsTools(pi, previousTools);\n\t\t} catch (caught) {\n\t\t\trollbackError = caught;\n\t\t}\n\t\tif (isCurrent(generation, ownerSignal, actionSignal)) {\n\t\t\tnotifySaveFailure(\n\t\t\t\tctx,\n\t\t\t\trollbackError\n\t\t\t\t\t? new Error(\n\t\t\t\t\t\t\t`${formatError(error)}; WebMCP rollback failed: ${formatError(rollbackError)}`,\n\t\t\t\t\t\t)\n\t\t\t\t\t: error,\n\t\t\t);\n\t\t}\n\t\treturn false;\n\t}\n}\n\nfunction isOwnerCurrent(generation: number, ownerSignal: AbortSignal) {\n\treturn generation === state.sessionGeneration && !ownerSignal.aborted;\n}\n\nfunction isCurrent(generation: number, ownerSignal: AbortSignal, actionSignal: AbortSignal) {\n\treturn isOwnerCurrent(generation, ownerSignal) && !actionSignal.aborted;\n}\n\nfunction invalidSettingsScreen(load: SettingsLoadResult) {\n\tconst reason =\n\t\tload.userFile.kind === \"invalid\"\n\t\t\t? load.userFile.reason\n\t\t\t: \"The user settings file is unavailable.\";\n\treturn {\n\t\tkind: \"detail\" as const,\n\t\ttitle: \"Chrome DevTools Browser settings \u00B7 Read only\",\n\t\tlines: [\n\t\t\tsanitizeChromeDevtoolsDisplay(\n\t\t\t\t`Fix the active user settings before saving; the file will not be overwritten. ${reason}`,\n\t\t\t),\n\t\t],\n\t\thint: \"back\" as const,\n\t};\n}\n\nfunction settingsContextLines(load: SettingsLoadResult) {\n\tconst browser = load.effectiveBrowser;\n\treturn [\n\t\t`User settings \u00B7 ${load.paths.user}`,\n\t\t`Effective sources: endpoint ${browser.endpointSource} \u00B7 auto-launch ${browser.autoLaunchSource} \u00B7 executable ${browser.executablePathSource}`,\n\t\t...(load.notice ? [`Warning: ${load.notice}`] : []),\n\t].map((line) => sanitizeChromeDevtoolsDisplay(line));\n}\n\nfunction extensionDetailLines(load: SettingsLoadResult) {\n\tconst browser = load.effectiveBrowser;\n\treturn [\n\t\t`Effective source: ${browser.extensionPathsSource}`,\n\t\t...(browser.extensionPaths.length > 0\n\t\t\t? browser.extensionPaths.map((extensionPath) => `- ${extensionPath}`)\n\t\t\t: [\"No unpacked extensions are configured.\"]),\n\t\t\"Edit browser.extensionPaths in the user JSON or a trusted project JSON, then run /reload.\",\n\t\t\"Unpacked extensions execute privileged browser code; load only paths you trust.\",\n\t].map((line) => sanitizeChromeDevtoolsDisplay(line));\n}\n\nfunction notifyEffectiveSave(\n\tctx: CommandContext,\n\tsetting: string,\n\teffectiveValue: string,\n\tsource: BrowserSettingsSource,\n) {\n\tconst overrideNotice =\n\t\tsource === \"environment\" ? \" The deprecated environment override remains effective.\" : \"\";\n\tctx.ui.notify(\n\t\tsanitizeChromeDevtoolsDisplay(\n\t\t\t`Chrome DevTools ${setting} saved. Effective ${setting}: ${effectiveValue} (${source}).${overrideNotice}`,\n\t\t),\n\t\t\"info\",\n\t);\n}\n\nfunction notifySaveFailure(ctx: CommandContext, error: unknown) {\n\tctx.ui.notify(\n\t\tsanitizeChromeDevtoolsDisplay(\n\t\t\t`Chrome DevTools browser settings save failed; previous settings remain active: ${formatError(error)}`,\n\t\t),\n\t\t\"warning\",\n\t);\n}\n\nfunction formatError(error: unknown) {\n\treturn error instanceof Error ? error.message : String(error);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["isCurrent"]
|
|
7
|
+
}
|