@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/dist/index.ts
CHANGED
|
@@ -1,197 +1,52 @@
|
|
|
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
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
formatPage,
|
|
5
|
+
getPage,
|
|
6
|
+
listPages,
|
|
7
|
+
resolvePage,
|
|
8
|
+
resolvePageForNavigation,
|
|
9
|
+
textResult,
|
|
10
|
+
withCdp
|
|
11
|
+
} from "./chunks/chunk-RTECHAEZ.js";
|
|
12
|
+
import {
|
|
7
13
|
allChromeDevtoolsTools,
|
|
8
|
-
applyRuntimeBrowserSettings,
|
|
9
14
|
availableChromeDevtoolsTools,
|
|
10
15
|
buildCommandGuide,
|
|
11
16
|
buildQuickstartMessage,
|
|
12
17
|
buildToolStatusMessage,
|
|
13
|
-
|
|
18
|
+
configureChromeDevtoolsToolExposure,
|
|
14
19
|
createChromeDevtoolsLoadTool,
|
|
15
|
-
devToolsEndpoint,
|
|
16
|
-
ensureDevToolsEndpoint,
|
|
17
|
-
fetchDevToolsJson,
|
|
18
|
-
formatPageListItem,
|
|
19
20
|
initializeAvailableChromeDevtoolsTools,
|
|
20
|
-
|
|
21
|
-
loadSettings,
|
|
21
|
+
requireEagerChromeDevtoolsToolExposure,
|
|
22
22
|
sanitizeChromeDevtoolsDisplay,
|
|
23
|
+
setChromeDevtoolsSessionOwner,
|
|
24
|
+
supportsNativeDeferredToolLoading,
|
|
25
|
+
updateChromeDevtoolsTools,
|
|
26
|
+
waitForChromeDevtoolsSettings
|
|
27
|
+
} from "./chunks/chunk-B7B63PWB.js";
|
|
28
|
+
import {
|
|
29
|
+
CHROME_DEVTOOLS_TOOL_NAMES,
|
|
30
|
+
WEBMCP_TOOL_NAMES,
|
|
31
|
+
applyRuntimeBrowserSettings,
|
|
32
|
+
applyRuntimeWebMcpSetting,
|
|
33
|
+
invalidateWebMcpOperations,
|
|
34
|
+
loadSettings,
|
|
35
|
+
setWebMcpSessionOwner,
|
|
23
36
|
shutdownManagedBrowser,
|
|
37
|
+
startManagedBrowserSession,
|
|
24
38
|
state,
|
|
25
|
-
updateChromeDevtoolsTools,
|
|
26
|
-
waitForChromeDevtoolsSettings,
|
|
27
39
|
waitForSettingsWrites,
|
|
28
|
-
|
|
29
|
-
} from "./chunks/chunk-
|
|
40
|
+
webMcpEnabled
|
|
41
|
+
} from "./chunks/chunk-GVBXT3FB.js";
|
|
30
42
|
|
|
31
43
|
// src/tools.ts
|
|
32
44
|
import { defineTool } from "@earendil-works/pi-coding-agent";
|
|
33
45
|
import { Type } from "typebox";
|
|
34
46
|
|
|
35
|
-
// src/cdp-client.ts
|
|
36
|
-
async function listPages(options = {}) {
|
|
37
|
-
const waitMs = options.waitMs ?? DEFAULT_ENDPOINT_WAIT_MS;
|
|
38
|
-
await ensureDevToolsEndpoint(waitMs);
|
|
39
|
-
return withEndpointRetry(async () => {
|
|
40
|
-
const pages = await fetchDevToolsJson("/json/list");
|
|
41
|
-
return pages.filter((page) => page.type === "page" && page.webSocketDebuggerUrl);
|
|
42
|
-
}, waitMs);
|
|
43
|
-
}
|
|
44
|
-
async function getPage(pageId) {
|
|
45
|
-
const pages = await listPages();
|
|
46
|
-
return requirePage(pageId, pages);
|
|
47
|
-
}
|
|
48
|
-
async function resolvePage(pageId) {
|
|
49
|
-
const pages = await listPages();
|
|
50
|
-
if (pageId) return requirePage(pageId, pages);
|
|
51
|
-
const page = resolveDefaultPage(pages);
|
|
52
|
-
if (!page) {
|
|
53
|
-
throw new Error(
|
|
54
|
-
[
|
|
55
|
-
`No Chrome pages found at ${devToolsEndpoint()}.`,
|
|
56
|
-
"Use chrome_devtools_navigate with a URL to create a page, or open a Chrome tab manually.",
|
|
57
|
-
launchHint()
|
|
58
|
-
].join("\n")
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
return page;
|
|
62
|
-
}
|
|
63
|
-
async function resolvePageForNavigation(pageId) {
|
|
64
|
-
const pages = await listPages();
|
|
65
|
-
if (pageId) return { created: false, page: requirePage(pageId, pages) };
|
|
66
|
-
const page = resolveDefaultPage(pages);
|
|
67
|
-
if (page) return { created: false, page };
|
|
68
|
-
return { created: true, page: await createPage("about:blank") };
|
|
69
|
-
}
|
|
70
|
-
function resolveDefaultPage(pages) {
|
|
71
|
-
if (!state.activePageId) return pages[0];
|
|
72
|
-
const activePage = pages.find((candidate) => candidate.id === state.activePageId);
|
|
73
|
-
if (activePage) return activePage;
|
|
74
|
-
state.activePageId = void 0;
|
|
75
|
-
return pages[0];
|
|
76
|
-
}
|
|
77
|
-
function requirePage(pageId, pages) {
|
|
78
|
-
const page = pages.find((candidate) => candidate.id === pageId);
|
|
79
|
-
if (page) return page;
|
|
80
|
-
const availablePages = pages.map(formatPageListItem).join("\n");
|
|
81
|
-
throw new Error(
|
|
82
|
-
[
|
|
83
|
-
`Chrome DevTools page not found: ${pageId}.`,
|
|
84
|
-
availablePages ? `Available pages:
|
|
85
|
-
${availablePages}` : "No inspectable Chrome pages are currently available."
|
|
86
|
-
].join("\n")
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
async function createPage(url, options = {}) {
|
|
90
|
-
const waitMs = options.waitMs ?? DEFAULT_ENDPOINT_WAIT_MS;
|
|
91
|
-
await ensureDevToolsEndpoint(waitMs);
|
|
92
|
-
const page = await withEndpointRetry(
|
|
93
|
-
() => fetchDevToolsJson(`/json/new?${encodeURIComponent(url)}`, {
|
|
94
|
-
method: "PUT"
|
|
95
|
-
}),
|
|
96
|
-
waitMs
|
|
97
|
-
);
|
|
98
|
-
if (page.type !== "page" || !page.webSocketDebuggerUrl) {
|
|
99
|
-
throw new Error("Chrome DevTools created a target that is not an inspectable page.");
|
|
100
|
-
}
|
|
101
|
-
return page;
|
|
102
|
-
}
|
|
103
|
-
function formatPage(page) {
|
|
104
|
-
return {
|
|
105
|
-
id: page.id,
|
|
106
|
-
type: page.type,
|
|
107
|
-
title: page.title,
|
|
108
|
-
url: page.url
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
function textResult(text, details) {
|
|
112
|
-
return {
|
|
113
|
-
content: [{ type: "text", text }],
|
|
114
|
-
details
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
async function withCdp(page, callback) {
|
|
118
|
-
if (!page.webSocketDebuggerUrl) throw new Error(`Page has no webSocketDebuggerUrl: ${page.id}`);
|
|
119
|
-
const client = await CdpClient.connect(page.webSocketDebuggerUrl);
|
|
120
|
-
try {
|
|
121
|
-
return await callback(client);
|
|
122
|
-
} finally {
|
|
123
|
-
client.close();
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
var CdpClient = class _CdpClient {
|
|
127
|
-
#nextId = 1;
|
|
128
|
-
#pending = /* @__PURE__ */ new Map();
|
|
129
|
-
socket;
|
|
130
|
-
constructor(socket) {
|
|
131
|
-
this.socket = socket;
|
|
132
|
-
socket.addEventListener("message", (event) => {
|
|
133
|
-
const response = JSON.parse(String(event.data));
|
|
134
|
-
if (typeof response.id !== "number") return;
|
|
135
|
-
const pending = this.#pending.get(response.id);
|
|
136
|
-
if (!pending) return;
|
|
137
|
-
clearTimeout(pending.timeout);
|
|
138
|
-
this.#pending.delete(response.id);
|
|
139
|
-
if (response.error) {
|
|
140
|
-
pending.reject(new Error(`CDP error ${response.error.code}: ${response.error.message}`));
|
|
141
|
-
} else {
|
|
142
|
-
pending.resolve(response.result);
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
socket.addEventListener("close", () => {
|
|
146
|
-
this.rejectAll(new Error("Chrome DevTools WebSocket closed"));
|
|
147
|
-
});
|
|
148
|
-
socket.addEventListener("error", () => {
|
|
149
|
-
this.rejectAll(new Error("Chrome DevTools WebSocket error"));
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
static connect(url) {
|
|
153
|
-
return new Promise((resolve2, reject) => {
|
|
154
|
-
const socket = new WebSocket(url);
|
|
155
|
-
const timeout = setTimeout(() => {
|
|
156
|
-
socket.close();
|
|
157
|
-
reject(new Error(`Timed out connecting to Chrome DevTools WebSocket: ${url}`));
|
|
158
|
-
}, DEFAULT_TIMEOUT_MS);
|
|
159
|
-
socket.addEventListener("open", () => {
|
|
160
|
-
clearTimeout(timeout);
|
|
161
|
-
resolve2(new _CdpClient(socket));
|
|
162
|
-
});
|
|
163
|
-
socket.addEventListener("error", () => {
|
|
164
|
-
clearTimeout(timeout);
|
|
165
|
-
reject(new Error(`Failed to connect to Chrome DevTools WebSocket: ${url}`));
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
send(method, params) {
|
|
170
|
-
const id = this.#nextId;
|
|
171
|
-
this.#nextId += 1;
|
|
172
|
-
return new Promise((resolve2, reject) => {
|
|
173
|
-
const timeout = setTimeout(() => {
|
|
174
|
-
this.#pending.delete(id);
|
|
175
|
-
reject(new Error(`Timed out waiting for CDP response: ${method}`));
|
|
176
|
-
}, DEFAULT_TIMEOUT_MS);
|
|
177
|
-
this.#pending.set(id, { resolve: resolve2, reject, timeout });
|
|
178
|
-
this.socket.send(JSON.stringify({ id, method, params: params ?? {} }));
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
close() {
|
|
182
|
-
this.socket.close();
|
|
183
|
-
}
|
|
184
|
-
rejectAll(error) {
|
|
185
|
-
for (const [id, pending] of this.#pending) {
|
|
186
|
-
clearTimeout(pending.timeout);
|
|
187
|
-
pending.reject(error);
|
|
188
|
-
this.#pending.delete(id);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
|
|
193
47
|
// src/render.ts
|
|
194
48
|
var STATUS_KEY = "chrome-devtools";
|
|
49
|
+
var activeStatuses = /* @__PURE__ */ new WeakMap();
|
|
195
50
|
function renderToolCall(action) {
|
|
196
51
|
return () => new PiTextComponent(`Chrome DevTools: ${action}`);
|
|
197
52
|
}
|
|
@@ -245,11 +100,19 @@ function truncateLine(line, maxWidth) {
|
|
|
245
100
|
return Array.from(line).slice(0, maxWidth).join("");
|
|
246
101
|
}
|
|
247
102
|
async function withStatus(ctx, status, callback) {
|
|
103
|
+
const token = Symbol(status);
|
|
104
|
+
const statuses = activeStatuses.get(ctx.sessionManager) ?? [];
|
|
105
|
+
statuses.push({ status, token });
|
|
106
|
+
activeStatuses.set(ctx.sessionManager, statuses);
|
|
248
107
|
ctx.ui.setStatus(STATUS_KEY, status);
|
|
249
108
|
try {
|
|
250
109
|
return await callback();
|
|
251
110
|
} finally {
|
|
252
|
-
|
|
111
|
+
const index = statuses.findIndex((entry) => entry.token === token);
|
|
112
|
+
if (index >= 0) statuses.splice(index, 1);
|
|
113
|
+
const remaining = statuses.at(-1)?.status;
|
|
114
|
+
if (statuses.length === 0) activeStatuses.delete(ctx.sessionManager);
|
|
115
|
+
ctx.ui.setStatus(STATUS_KEY, remaining);
|
|
253
116
|
}
|
|
254
117
|
}
|
|
255
118
|
|
|
@@ -450,9 +313,9 @@ var listPagesTool = defineTool({
|
|
|
450
313
|
parameters: Type.Object({}),
|
|
451
314
|
renderCall: renderToolCall("list pages"),
|
|
452
315
|
renderResult: renderTextResult,
|
|
453
|
-
async execute(_toolCallId, _params,
|
|
316
|
+
async execute(_toolCallId, _params, signal, _onUpdate, ctx) {
|
|
454
317
|
return withStatus(ctx, "list pages", async () => {
|
|
455
|
-
const pages = await listPages();
|
|
318
|
+
const pages = await listPages({ sessionOwner: ctx.sessionManager, signal });
|
|
456
319
|
return textResult(JSON.stringify(pages.map(formatPage), null, 2), { pages });
|
|
457
320
|
});
|
|
458
321
|
}
|
|
@@ -466,9 +329,9 @@ var selectPageTool = defineTool({
|
|
|
466
329
|
}),
|
|
467
330
|
renderCall: renderToolCall("select page"),
|
|
468
331
|
renderResult: renderTextResult,
|
|
469
|
-
async execute(_toolCallId, params,
|
|
332
|
+
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
470
333
|
return withStatus(ctx, "select page", async () => {
|
|
471
|
-
const page = await getPage(params.pageId);
|
|
334
|
+
const page = await getPage(params.pageId, { sessionOwner: ctx.sessionManager, signal });
|
|
472
335
|
state.activePageId = page.id;
|
|
473
336
|
return textResult(`Selected page ${page.id}: ${page.title}
|
|
474
337
|
${page.url}`, {
|
|
@@ -489,9 +352,12 @@ var navigateTool = defineTool({
|
|
|
489
352
|
}),
|
|
490
353
|
renderCall: renderToolCall("navigate"),
|
|
491
354
|
renderResult: renderTextResult,
|
|
492
|
-
async execute(_toolCallId, params,
|
|
355
|
+
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
493
356
|
return withStatus(ctx, "navigate", async () => {
|
|
494
|
-
const { created, page } = await resolvePageForNavigation(params.pageId
|
|
357
|
+
const { created, page } = await resolvePageForNavigation(params.pageId, {
|
|
358
|
+
sessionOwner: ctx.sessionManager,
|
|
359
|
+
signal
|
|
360
|
+
});
|
|
495
361
|
const result = await withCdp(page, async (client) => {
|
|
496
362
|
await client.send("Page.enable");
|
|
497
363
|
return client.send("Page.navigate", { url: params.url });
|
|
@@ -521,9 +387,12 @@ var evaluateTool = defineTool({
|
|
|
521
387
|
}),
|
|
522
388
|
renderCall: renderToolCall("evaluate"),
|
|
523
389
|
renderResult: renderTextResult,
|
|
524
|
-
async execute(_toolCallId, params,
|
|
390
|
+
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
525
391
|
return withStatus(ctx, "evaluate", async () => {
|
|
526
|
-
const page = await resolvePage(params.pageId
|
|
392
|
+
const page = await resolvePage(params.pageId, {
|
|
393
|
+
sessionOwner: ctx.sessionManager,
|
|
394
|
+
signal
|
|
395
|
+
});
|
|
527
396
|
const result = await withCdp(
|
|
528
397
|
page,
|
|
529
398
|
(client) => client.send("Runtime.evaluate", {
|
|
@@ -537,6 +406,69 @@ var evaluateTool = defineTool({
|
|
|
537
406
|
});
|
|
538
407
|
}
|
|
539
408
|
});
|
|
409
|
+
var webMcpListToolsTool = defineTool({
|
|
410
|
+
name: WEBMCP_TOOL_NAMES[0],
|
|
411
|
+
label: "Chrome DevTools: List WebMCP Tools (Experimental)",
|
|
412
|
+
description: "List bounded page-provided WebMCP tool descriptors from the selected Chrome page through the experimental CDP WebMCP domain. Definitions remain in this tool result and are never registered as dynamic Pi tools.",
|
|
413
|
+
parameters: Type.Object({
|
|
414
|
+
pageId: Type.Optional(
|
|
415
|
+
Type.String({
|
|
416
|
+
description: "Optional page id. Defaults to selected or first page.",
|
|
417
|
+
maxLength: 512
|
|
418
|
+
})
|
|
419
|
+
)
|
|
420
|
+
}),
|
|
421
|
+
renderCall: renderToolCall("list WebMCP tools"),
|
|
422
|
+
renderResult: renderTextResult,
|
|
423
|
+
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
424
|
+
return withStatus(ctx, "list WebMCP tools", async () => {
|
|
425
|
+
const implementation = await import("./chunks/tools-V7OR5KJ3.js");
|
|
426
|
+
return implementation.executeWebMcpListTool(params, signal, ctx);
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
var webMcpCallTool = defineTool({
|
|
431
|
+
name: WEBMCP_TOOL_NAMES[1],
|
|
432
|
+
label: "Chrome DevTools: Call WebMCP Tool (Experimental)",
|
|
433
|
+
description: "Call one previously listed page-provided WebMCP tool after exact page, document, frame, origin, schema, annotation, and session revalidation. Every call requires observable user confirmation and output is bounded to Pi's 50 KB or 2,000-line limit.",
|
|
434
|
+
parameters: Type.Object({
|
|
435
|
+
sessionGeneration: Type.String({
|
|
436
|
+
description: "Session generation token returned by chrome_devtools_webmcp_list_tools.",
|
|
437
|
+
maxLength: 100
|
|
438
|
+
}),
|
|
439
|
+
pageId: Type.String({ description: "Page id returned by the list tool.", maxLength: 512 }),
|
|
440
|
+
documentId: Type.String({
|
|
441
|
+
description: "Document loader id returned by the list tool.",
|
|
442
|
+
maxLength: 512
|
|
443
|
+
}),
|
|
444
|
+
frameId: Type.String({ description: "Frame id returned by the list tool.", maxLength: 512 }),
|
|
445
|
+
frameOrigin: Type.String({
|
|
446
|
+
description: "Exact frame origin returned by the list tool.",
|
|
447
|
+
maxLength: 2048
|
|
448
|
+
}),
|
|
449
|
+
toolName: Type.String({
|
|
450
|
+
description: "Exact tool name returned by the list tool.",
|
|
451
|
+
maxLength: 512
|
|
452
|
+
}),
|
|
453
|
+
schemaDigest: Type.String({
|
|
454
|
+
description: "Schema and annotation digest returned by the list tool.",
|
|
455
|
+
minLength: 64,
|
|
456
|
+
maxLength: 64,
|
|
457
|
+
pattern: "^[a-f0-9]{64}$"
|
|
458
|
+
}),
|
|
459
|
+
input: Type.Record(Type.String(), Type.Unknown(), {
|
|
460
|
+
description: "JSON object matching the page-provided input schema."
|
|
461
|
+
})
|
|
462
|
+
}),
|
|
463
|
+
renderCall: renderToolCall("call WebMCP tool"),
|
|
464
|
+
renderResult: renderTextResult,
|
|
465
|
+
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
466
|
+
return withStatus(ctx, "call WebMCP tool", async () => {
|
|
467
|
+
const implementation = await import("./chunks/tools-V7OR5KJ3.js");
|
|
468
|
+
return implementation.executeWebMcpCallTool(params, signal, ctx);
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
});
|
|
540
472
|
var screenshotTool = defineTool({
|
|
541
473
|
name: CHROME_DEVTOOLS_TOOL_NAMES[4],
|
|
542
474
|
label: "Chrome DevTools: Screenshot",
|
|
@@ -558,7 +490,10 @@ var screenshotTool = defineTool({
|
|
|
558
490
|
renderResult: renderScreenshotResult,
|
|
559
491
|
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
560
492
|
return withStatus(ctx, "screenshot", async () => {
|
|
561
|
-
const page = await resolvePage(params.pageId
|
|
493
|
+
const page = await resolvePage(params.pageId, {
|
|
494
|
+
sessionOwner: ctx.sessionManager,
|
|
495
|
+
signal
|
|
496
|
+
});
|
|
562
497
|
const result = await withCdp(page, async (client) => {
|
|
563
498
|
throwIfAborted(signal);
|
|
564
499
|
await client.send("Page.enable");
|
|
@@ -607,7 +542,7 @@ var COMMAND_COMPLETIONS = [
|
|
|
607
542
|
{ value: "quickstart", label: "quickstart", description: "Show endpoint and launch help" },
|
|
608
543
|
{ value: "status", label: "status", description: "Show tool and settings status" },
|
|
609
544
|
{ value: "settings", label: "settings", description: "Edit browser connection settings" },
|
|
610
|
-
{ value: "tools", label: "tools", description: "Choose
|
|
545
|
+
{ value: "tools", label: "tools", description: "Choose available Chrome DevTools tools" },
|
|
611
546
|
{ value: "toggle", label: "toggle", description: "Alias for tools" },
|
|
612
547
|
{ value: "select", label: "select", description: "Compatibility alias for tools" },
|
|
613
548
|
{ value: "enable", label: "enable", description: "Make all Chrome DevTools tools available" },
|
|
@@ -621,11 +556,14 @@ function chromeDevtools(pi) {
|
|
|
621
556
|
pi.registerTool(navigateTool);
|
|
622
557
|
pi.registerTool(evaluateTool);
|
|
623
558
|
pi.registerTool(screenshotTool);
|
|
559
|
+
pi.registerTool(webMcpListToolsTool);
|
|
560
|
+
pi.registerTool(webMcpCallTool);
|
|
624
561
|
pi.registerTool(createChromeDevtoolsLoadTool(pi));
|
|
625
562
|
pi.registerCommand("chrome-devtools", {
|
|
626
563
|
description: "Open Chrome DevTools help and tool controls",
|
|
627
564
|
getArgumentCompletions: (prefix) => commandCompletions(prefix),
|
|
628
565
|
handler: async (args, ctx) => {
|
|
566
|
+
setChromeDevtoolsSessionOwner(pi, ctx.sessionManager);
|
|
629
567
|
initializeAvailableChromeDevtoolsTools(pi);
|
|
630
568
|
const generation = state.sessionGeneration;
|
|
631
569
|
await handleChromeDevtoolsCommand(pi, args, ctx, generation);
|
|
@@ -633,12 +571,19 @@ function chromeDevtools(pi) {
|
|
|
633
571
|
});
|
|
634
572
|
pi.on("session_start", async (_event, ctx) => {
|
|
635
573
|
const generation = ++state.sessionGeneration;
|
|
574
|
+
setChromeDevtoolsSessionOwner(pi, ctx.sessionManager);
|
|
636
575
|
initializeAvailableChromeDevtoolsTools(pi);
|
|
576
|
+
setWebMcpSessionOwner(ctx.sessionManager);
|
|
637
577
|
replaceSessionController("Chrome DevTools session replaced");
|
|
578
|
+
invalidateWebMcpOperations(ctx.sessionManager, "Chrome DevTools session replaced");
|
|
638
579
|
state.shuttingDown = false;
|
|
639
580
|
state.settingsNotice = void 0;
|
|
640
581
|
ctx.ui.setStatus(STATUS_KEY2, void 0);
|
|
641
|
-
await shutdownManagedBrowser(
|
|
582
|
+
await shutdownManagedBrowser(void 0, {
|
|
583
|
+
cancelLaunch: true,
|
|
584
|
+
owner: ctx.sessionManager
|
|
585
|
+
});
|
|
586
|
+
startManagedBrowserSession(ctx.sessionManager);
|
|
642
587
|
if (generation !== state.sessionGeneration) return;
|
|
643
588
|
state.activePageId = void 0;
|
|
644
589
|
state.lastLaunchAttempt = void 0;
|
|
@@ -646,18 +591,38 @@ function chromeDevtools(pi) {
|
|
|
646
591
|
const settings = await loadSettings({ cwd: ctx.cwd, projectTrusted });
|
|
647
592
|
if (generation !== state.sessionGeneration) return;
|
|
648
593
|
applyRuntimeBrowserSettings(settings.effectiveBrowser, settings.paths, projectTrusted);
|
|
594
|
+
applyRuntimeWebMcpSetting(settings.effectiveWebMcpEnabled, ctx.sessionManager);
|
|
649
595
|
state.settingsNotice = settings.notice;
|
|
650
596
|
for (const warning of settings.warnings) {
|
|
651
597
|
ctx.ui.notify(sanitizeChromeDevtoolsDisplay(warning), "warning");
|
|
652
598
|
}
|
|
599
|
+
if (webMcpEnabled(ctx.sessionManager)) {
|
|
600
|
+
ctx.ui.notify(
|
|
601
|
+
"Experimental WebMCP is enabled. Page-provided tools use the visible browser session and require confirmation for every call.",
|
|
602
|
+
"warning"
|
|
603
|
+
);
|
|
604
|
+
}
|
|
653
605
|
const availableTools = settings.kind === "loaded" && settings.settings.tools ? settings.settings.tools : availableChromeDevtoolsTools(pi);
|
|
654
|
-
|
|
606
|
+
configureChromeDevtoolsToolExposure(pi, availableTools, ctx.model);
|
|
607
|
+
});
|
|
608
|
+
pi.on("model_select", (event, ctx) => {
|
|
609
|
+
invalidateWebMcpOperations(
|
|
610
|
+
ctx.sessionManager,
|
|
611
|
+
"Chrome DevTools model and tool exposure changed"
|
|
612
|
+
);
|
|
613
|
+
if (!supportsNativeDeferredToolLoading(event.model)) {
|
|
614
|
+
requireEagerChromeDevtoolsToolExposure(pi);
|
|
615
|
+
}
|
|
655
616
|
});
|
|
656
617
|
pi.on("session_shutdown", async (_event, ctx) => {
|
|
657
618
|
state.sessionGeneration += 1;
|
|
658
619
|
replaceSessionController("Chrome DevTools session shut down");
|
|
620
|
+
invalidateWebMcpOperations(ctx.sessionManager, "Chrome DevTools session shut down");
|
|
659
621
|
ctx.ui.setStatus(STATUS_KEY2, void 0);
|
|
660
|
-
const browserShutdown = shutdownManagedBrowser(void 0, {
|
|
622
|
+
const browserShutdown = shutdownManagedBrowser(void 0, {
|
|
623
|
+
cancelLaunch: true,
|
|
624
|
+
owner: ctx.sessionManager
|
|
625
|
+
});
|
|
661
626
|
await waitForChromeDevtoolsSettings();
|
|
662
627
|
await waitForSettingsWrites();
|
|
663
628
|
await browserShutdown;
|
|
@@ -671,15 +636,15 @@ async function handleChromeDevtoolsCommand(pi, args, ctx, generation) {
|
|
|
671
636
|
return;
|
|
672
637
|
case "help":
|
|
673
638
|
requireObservableUi(ctx, "help");
|
|
674
|
-
ctx.ui.notify(buildCommandGuide(), "info");
|
|
639
|
+
ctx.ui.notify(buildCommandGuide(ctx.sessionManager), "info");
|
|
675
640
|
return;
|
|
676
641
|
case "quickstart":
|
|
677
642
|
requireObservableUi(ctx, "quickstart");
|
|
678
|
-
ctx.ui.notify(buildQuickstartMessage(), "info");
|
|
643
|
+
ctx.ui.notify(buildQuickstartMessage(ctx.sessionManager), "info");
|
|
679
644
|
return;
|
|
680
645
|
case "status": {
|
|
681
646
|
requireObservableUi(ctx, "status");
|
|
682
|
-
const status = await buildToolStatusMessage(pi);
|
|
647
|
+
const status = await buildToolStatusMessage(pi, ctx.sessionManager);
|
|
683
648
|
if (generation !== state.sessionGeneration) return;
|
|
684
649
|
ctx.ui.notify(status, "info");
|
|
685
650
|
return;
|
|
@@ -688,22 +653,27 @@ async function handleChromeDevtoolsCommand(pi, args, ctx, generation) {
|
|
|
688
653
|
if (!ctx.hasUI || ctx.mode !== "tui" && ctx.mode !== "rpc") {
|
|
689
654
|
throw new Error("/chrome-devtools settings requires TUI or RPC mode");
|
|
690
655
|
}
|
|
691
|
-
const { showChromeDevtoolsBrowserSettings } = await import("./chunks/browser-settings-menu-
|
|
656
|
+
const { showChromeDevtoolsBrowserSettings } = await import("./chunks/browser-settings-menu-N5O65I7S.js");
|
|
692
657
|
if (generation !== state.sessionGeneration) return;
|
|
693
|
-
await showChromeDevtoolsBrowserSettings(ctx, generation);
|
|
658
|
+
await showChromeDevtoolsBrowserSettings(pi, ctx, generation);
|
|
694
659
|
return;
|
|
695
660
|
}
|
|
696
661
|
case "tools": {
|
|
697
662
|
if (!ctx.hasUI || ctx.mode !== "tui" && ctx.mode !== "rpc") {
|
|
698
663
|
throw new Error("/chrome-devtools tools requires TUI or RPC mode");
|
|
699
664
|
}
|
|
700
|
-
const { showChromeDevtoolsToolWorkflow } = await import("./chunks/menu-
|
|
665
|
+
const { showChromeDevtoolsToolWorkflow } = await import("./chunks/menu-UBHW6UP2.js");
|
|
701
666
|
if (generation !== state.sessionGeneration) return;
|
|
702
667
|
await showChromeDevtoolsToolWorkflow(pi, ctx, generation);
|
|
703
668
|
return;
|
|
704
669
|
}
|
|
705
670
|
case "enable":
|
|
706
|
-
await updateChromeDevtoolsTools(
|
|
671
|
+
await updateChromeDevtoolsTools(
|
|
672
|
+
pi,
|
|
673
|
+
ctx,
|
|
674
|
+
allChromeDevtoolsTools(ctx.sessionManager),
|
|
675
|
+
"made all available"
|
|
676
|
+
);
|
|
707
677
|
return;
|
|
708
678
|
case "disable":
|
|
709
679
|
await updateChromeDevtoolsTools(pi, ctx, [], "made all unavailable");
|
|
@@ -715,7 +685,7 @@ async function handleChromeDevtoolsCommand(pi, args, ctx, generation) {
|
|
|
715
685
|
ctx.ui.notify(
|
|
716
686
|
`Unknown /chrome-devtools command: ${args.trim()}
|
|
717
687
|
|
|
718
|
-
${buildCommandGuide()}`,
|
|
688
|
+
${buildCommandGuide(ctx.sessionManager)}`,
|
|
719
689
|
"warning"
|
|
720
690
|
);
|
|
721
691
|
}
|
|
@@ -728,7 +698,7 @@ async function showMenu(pi, ctx, generation) {
|
|
|
728
698
|
if (!ctx.hasUI || ctx.mode !== "tui" && ctx.mode !== "rpc") {
|
|
729
699
|
throw new Error("/chrome-devtools menu requires TUI or RPC mode; use a direct subcommand");
|
|
730
700
|
}
|
|
731
|
-
const { showChromeDevtoolsMenu } = await import("./chunks/menu-
|
|
701
|
+
const { showChromeDevtoolsMenu } = await import("./chunks/menu-UBHW6UP2.js");
|
|
732
702
|
if (generation !== state.sessionGeneration) return;
|
|
733
703
|
await showChromeDevtoolsMenu(pi, ctx, generation);
|
|
734
704
|
}
|