@narumitw/pi-chrome-devtools 0.52.3 → 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.
Files changed (35) hide show
  1. package/README.md +62 -9
  2. package/dist/chunks/{browser-settings-menu-VWCNG4HB.js → browser-settings-menu-N5O65I7S.js} +81 -7
  3. package/dist/chunks/browser-settings-menu-N5O65I7S.js.map +7 -0
  4. package/dist/chunks/chunk-B7B63PWB.js +465 -0
  5. package/dist/chunks/chunk-B7B63PWB.js.map +7 -0
  6. package/dist/chunks/{chunk-RH6KESL3.js → chunk-GVBXT3FB.js} +369 -514
  7. package/dist/chunks/chunk-GVBXT3FB.js.map +7 -0
  8. package/dist/chunks/chunk-RTECHAEZ.js +373 -0
  9. package/dist/chunks/chunk-RTECHAEZ.js.map +7 -0
  10. package/dist/chunks/{menu-PLD3S3EO.js → menu-UBHW6UP2.js} +72 -39
  11. package/dist/chunks/menu-UBHW6UP2.js.map +7 -0
  12. package/dist/chunks/tools-V7OR5KJ3.js +945 -0
  13. package/dist/chunks/tools-V7OR5KJ3.js.map +7 -0
  14. package/dist/index.ts +158 -195
  15. package/dist/index.ts.map +4 -4
  16. package/package.json +4 -3
  17. package/src/browser-manager.ts +282 -109
  18. package/src/browser-settings-menu.ts +98 -4
  19. package/src/cdp-client.ts +329 -83
  20. package/src/chrome-devtools.ts +51 -11
  21. package/src/lazy-tools.ts +37 -4
  22. package/src/menu.ts +80 -39
  23. package/src/render.ts +12 -1
  24. package/src/runtime.ts +92 -0
  25. package/src/settings.ts +47 -10
  26. package/src/tool-names.ts +16 -1
  27. package/src/tool-selector.ts +67 -30
  28. package/src/tools.ts +86 -10
  29. package/src/webmcp/discovery.ts +235 -0
  30. package/src/webmcp/policy.ts +402 -0
  31. package/src/webmcp/protocol.ts +414 -0
  32. package/src/webmcp/tools.ts +190 -0
  33. package/dist/chunks/browser-settings-menu-VWCNG4HB.js.map +0 -7
  34. package/dist/chunks/chunk-RH6KESL3.js.map +0 -7
  35. package/dist/chunks/menu-PLD3S3EO.js.map +0 -7
package/dist/index.ts CHANGED
@@ -1,199 +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
- CHROME_DEVTOOLS_TOOL_NAMES,
5
- DEFAULT_ENDPOINT_WAIT_MS,
6
- DEFAULT_TIMEOUT_MS,
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
- launchHint,
21
- loadSettings,
22
21
  requireEagerChromeDevtoolsToolExposure,
23
22
  sanitizeChromeDevtoolsDisplay,
24
- shutdownManagedBrowser,
25
- state,
23
+ setChromeDevtoolsSessionOwner,
26
24
  supportsNativeDeferredToolLoading,
27
25
  updateChromeDevtoolsTools,
28
- waitForChromeDevtoolsSettings,
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,
36
+ shutdownManagedBrowser,
37
+ startManagedBrowserSession,
38
+ state,
29
39
  waitForSettingsWrites,
30
- withEndpointRetry
31
- } from "./chunks/chunk-RH6KESL3.js";
40
+ webMcpEnabled
41
+ } from "./chunks/chunk-GVBXT3FB.js";
32
42
 
33
43
  // src/tools.ts
34
44
  import { defineTool } from "@earendil-works/pi-coding-agent";
35
45
  import { Type } from "typebox";
36
46
 
37
- // src/cdp-client.ts
38
- async function listPages(options = {}) {
39
- const waitMs = options.waitMs ?? DEFAULT_ENDPOINT_WAIT_MS;
40
- await ensureDevToolsEndpoint(waitMs);
41
- return withEndpointRetry(async () => {
42
- const pages = await fetchDevToolsJson("/json/list");
43
- return pages.filter((page) => page.type === "page" && page.webSocketDebuggerUrl);
44
- }, waitMs);
45
- }
46
- async function getPage(pageId) {
47
- const pages = await listPages();
48
- return requirePage(pageId, pages);
49
- }
50
- async function resolvePage(pageId) {
51
- const pages = await listPages();
52
- if (pageId) return requirePage(pageId, pages);
53
- const page = resolveDefaultPage(pages);
54
- if (!page) {
55
- throw new Error(
56
- [
57
- `No Chrome pages found at ${devToolsEndpoint()}.`,
58
- "Use chrome_devtools_navigate with a URL to create a page, or open a Chrome tab manually.",
59
- launchHint()
60
- ].join("\n")
61
- );
62
- }
63
- return page;
64
- }
65
- async function resolvePageForNavigation(pageId) {
66
- const pages = await listPages();
67
- if (pageId) return { created: false, page: requirePage(pageId, pages) };
68
- const page = resolveDefaultPage(pages);
69
- if (page) return { created: false, page };
70
- return { created: true, page: await createPage("about:blank") };
71
- }
72
- function resolveDefaultPage(pages) {
73
- if (!state.activePageId) return pages[0];
74
- const activePage = pages.find((candidate) => candidate.id === state.activePageId);
75
- if (activePage) return activePage;
76
- state.activePageId = void 0;
77
- return pages[0];
78
- }
79
- function requirePage(pageId, pages) {
80
- const page = pages.find((candidate) => candidate.id === pageId);
81
- if (page) return page;
82
- const availablePages = pages.map(formatPageListItem).join("\n");
83
- throw new Error(
84
- [
85
- `Chrome DevTools page not found: ${pageId}.`,
86
- availablePages ? `Available pages:
87
- ${availablePages}` : "No inspectable Chrome pages are currently available."
88
- ].join("\n")
89
- );
90
- }
91
- async function createPage(url, options = {}) {
92
- const waitMs = options.waitMs ?? DEFAULT_ENDPOINT_WAIT_MS;
93
- await ensureDevToolsEndpoint(waitMs);
94
- const page = await withEndpointRetry(
95
- () => fetchDevToolsJson(`/json/new?${encodeURIComponent(url)}`, {
96
- method: "PUT"
97
- }),
98
- waitMs
99
- );
100
- if (page.type !== "page" || !page.webSocketDebuggerUrl) {
101
- throw new Error("Chrome DevTools created a target that is not an inspectable page.");
102
- }
103
- return page;
104
- }
105
- function formatPage(page) {
106
- return {
107
- id: page.id,
108
- type: page.type,
109
- title: page.title,
110
- url: page.url
111
- };
112
- }
113
- function textResult(text, details) {
114
- return {
115
- content: [{ type: "text", text }],
116
- details
117
- };
118
- }
119
- async function withCdp(page, callback) {
120
- if (!page.webSocketDebuggerUrl) throw new Error(`Page has no webSocketDebuggerUrl: ${page.id}`);
121
- const client = await CdpClient.connect(page.webSocketDebuggerUrl);
122
- try {
123
- return await callback(client);
124
- } finally {
125
- client.close();
126
- }
127
- }
128
- var CdpClient = class _CdpClient {
129
- #nextId = 1;
130
- #pending = /* @__PURE__ */ new Map();
131
- socket;
132
- constructor(socket) {
133
- this.socket = socket;
134
- socket.addEventListener("message", (event) => {
135
- const response = JSON.parse(String(event.data));
136
- if (typeof response.id !== "number") return;
137
- const pending = this.#pending.get(response.id);
138
- if (!pending) return;
139
- clearTimeout(pending.timeout);
140
- this.#pending.delete(response.id);
141
- if (response.error) {
142
- pending.reject(new Error(`CDP error ${response.error.code}: ${response.error.message}`));
143
- } else {
144
- pending.resolve(response.result);
145
- }
146
- });
147
- socket.addEventListener("close", () => {
148
- this.rejectAll(new Error("Chrome DevTools WebSocket closed"));
149
- });
150
- socket.addEventListener("error", () => {
151
- this.rejectAll(new Error("Chrome DevTools WebSocket error"));
152
- });
153
- }
154
- static connect(url) {
155
- return new Promise((resolve2, reject) => {
156
- const socket = new WebSocket(url);
157
- const timeout = setTimeout(() => {
158
- socket.close();
159
- reject(new Error(`Timed out connecting to Chrome DevTools WebSocket: ${url}`));
160
- }, DEFAULT_TIMEOUT_MS);
161
- socket.addEventListener("open", () => {
162
- clearTimeout(timeout);
163
- resolve2(new _CdpClient(socket));
164
- });
165
- socket.addEventListener("error", () => {
166
- clearTimeout(timeout);
167
- reject(new Error(`Failed to connect to Chrome DevTools WebSocket: ${url}`));
168
- });
169
- });
170
- }
171
- send(method, params) {
172
- const id = this.#nextId;
173
- this.#nextId += 1;
174
- return new Promise((resolve2, reject) => {
175
- const timeout = setTimeout(() => {
176
- this.#pending.delete(id);
177
- reject(new Error(`Timed out waiting for CDP response: ${method}`));
178
- }, DEFAULT_TIMEOUT_MS);
179
- this.#pending.set(id, { resolve: resolve2, reject, timeout });
180
- this.socket.send(JSON.stringify({ id, method, params: params ?? {} }));
181
- });
182
- }
183
- close() {
184
- this.socket.close();
185
- }
186
- rejectAll(error) {
187
- for (const [id, pending] of this.#pending) {
188
- clearTimeout(pending.timeout);
189
- pending.reject(error);
190
- this.#pending.delete(id);
191
- }
192
- }
193
- };
194
-
195
47
  // src/render.ts
196
48
  var STATUS_KEY = "chrome-devtools";
49
+ var activeStatuses = /* @__PURE__ */ new WeakMap();
197
50
  function renderToolCall(action) {
198
51
  return () => new PiTextComponent(`Chrome DevTools: ${action}`);
199
52
  }
@@ -247,11 +100,19 @@ function truncateLine(line, maxWidth) {
247
100
  return Array.from(line).slice(0, maxWidth).join("");
248
101
  }
249
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);
250
107
  ctx.ui.setStatus(STATUS_KEY, status);
251
108
  try {
252
109
  return await callback();
253
110
  } finally {
254
- ctx.ui.setStatus(STATUS_KEY, void 0);
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);
255
116
  }
256
117
  }
257
118
 
@@ -452,9 +313,9 @@ var listPagesTool = defineTool({
452
313
  parameters: Type.Object({}),
453
314
  renderCall: renderToolCall("list pages"),
454
315
  renderResult: renderTextResult,
455
- async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
316
+ async execute(_toolCallId, _params, signal, _onUpdate, ctx) {
456
317
  return withStatus(ctx, "list pages", async () => {
457
- const pages = await listPages();
318
+ const pages = await listPages({ sessionOwner: ctx.sessionManager, signal });
458
319
  return textResult(JSON.stringify(pages.map(formatPage), null, 2), { pages });
459
320
  });
460
321
  }
@@ -468,9 +329,9 @@ var selectPageTool = defineTool({
468
329
  }),
469
330
  renderCall: renderToolCall("select page"),
470
331
  renderResult: renderTextResult,
471
- async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
332
+ async execute(_toolCallId, params, signal, _onUpdate, ctx) {
472
333
  return withStatus(ctx, "select page", async () => {
473
- const page = await getPage(params.pageId);
334
+ const page = await getPage(params.pageId, { sessionOwner: ctx.sessionManager, signal });
474
335
  state.activePageId = page.id;
475
336
  return textResult(`Selected page ${page.id}: ${page.title}
476
337
  ${page.url}`, {
@@ -491,9 +352,12 @@ var navigateTool = defineTool({
491
352
  }),
492
353
  renderCall: renderToolCall("navigate"),
493
354
  renderResult: renderTextResult,
494
- async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
355
+ async execute(_toolCallId, params, signal, _onUpdate, ctx) {
495
356
  return withStatus(ctx, "navigate", async () => {
496
- const { created, page } = await resolvePageForNavigation(params.pageId);
357
+ const { created, page } = await resolvePageForNavigation(params.pageId, {
358
+ sessionOwner: ctx.sessionManager,
359
+ signal
360
+ });
497
361
  const result = await withCdp(page, async (client) => {
498
362
  await client.send("Page.enable");
499
363
  return client.send("Page.navigate", { url: params.url });
@@ -523,9 +387,12 @@ var evaluateTool = defineTool({
523
387
  }),
524
388
  renderCall: renderToolCall("evaluate"),
525
389
  renderResult: renderTextResult,
526
- async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
390
+ async execute(_toolCallId, params, signal, _onUpdate, ctx) {
527
391
  return withStatus(ctx, "evaluate", async () => {
528
- const page = await resolvePage(params.pageId);
392
+ const page = await resolvePage(params.pageId, {
393
+ sessionOwner: ctx.sessionManager,
394
+ signal
395
+ });
529
396
  const result = await withCdp(
530
397
  page,
531
398
  (client) => client.send("Runtime.evaluate", {
@@ -539,6 +406,69 @@ var evaluateTool = defineTool({
539
406
  });
540
407
  }
541
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
+ });
542
472
  var screenshotTool = defineTool({
543
473
  name: CHROME_DEVTOOLS_TOOL_NAMES[4],
544
474
  label: "Chrome DevTools: Screenshot",
@@ -560,7 +490,10 @@ var screenshotTool = defineTool({
560
490
  renderResult: renderScreenshotResult,
561
491
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
562
492
  return withStatus(ctx, "screenshot", async () => {
563
- const page = await resolvePage(params.pageId);
493
+ const page = await resolvePage(params.pageId, {
494
+ sessionOwner: ctx.sessionManager,
495
+ signal
496
+ });
564
497
  const result = await withCdp(page, async (client) => {
565
498
  throwIfAborted(signal);
566
499
  await client.send("Page.enable");
@@ -623,11 +556,14 @@ function chromeDevtools(pi) {
623
556
  pi.registerTool(navigateTool);
624
557
  pi.registerTool(evaluateTool);
625
558
  pi.registerTool(screenshotTool);
559
+ pi.registerTool(webMcpListToolsTool);
560
+ pi.registerTool(webMcpCallTool);
626
561
  pi.registerTool(createChromeDevtoolsLoadTool(pi));
627
562
  pi.registerCommand("chrome-devtools", {
628
563
  description: "Open Chrome DevTools help and tool controls",
629
564
  getArgumentCompletions: (prefix) => commandCompletions(prefix),
630
565
  handler: async (args, ctx) => {
566
+ setChromeDevtoolsSessionOwner(pi, ctx.sessionManager);
631
567
  initializeAvailableChromeDevtoolsTools(pi);
632
568
  const generation = state.sessionGeneration;
633
569
  await handleChromeDevtoolsCommand(pi, args, ctx, generation);
@@ -635,12 +571,19 @@ function chromeDevtools(pi) {
635
571
  });
636
572
  pi.on("session_start", async (_event, ctx) => {
637
573
  const generation = ++state.sessionGeneration;
574
+ setChromeDevtoolsSessionOwner(pi, ctx.sessionManager);
638
575
  initializeAvailableChromeDevtoolsTools(pi);
576
+ setWebMcpSessionOwner(ctx.sessionManager);
639
577
  replaceSessionController("Chrome DevTools session replaced");
578
+ invalidateWebMcpOperations(ctx.sessionManager, "Chrome DevTools session replaced");
640
579
  state.shuttingDown = false;
641
580
  state.settingsNotice = void 0;
642
581
  ctx.ui.setStatus(STATUS_KEY2, void 0);
643
- await shutdownManagedBrowser();
582
+ await shutdownManagedBrowser(void 0, {
583
+ cancelLaunch: true,
584
+ owner: ctx.sessionManager
585
+ });
586
+ startManagedBrowserSession(ctx.sessionManager);
644
587
  if (generation !== state.sessionGeneration) return;
645
588
  state.activePageId = void 0;
646
589
  state.lastLaunchAttempt = void 0;
@@ -648,14 +591,25 @@ function chromeDevtools(pi) {
648
591
  const settings = await loadSettings({ cwd: ctx.cwd, projectTrusted });
649
592
  if (generation !== state.sessionGeneration) return;
650
593
  applyRuntimeBrowserSettings(settings.effectiveBrowser, settings.paths, projectTrusted);
594
+ applyRuntimeWebMcpSetting(settings.effectiveWebMcpEnabled, ctx.sessionManager);
651
595
  state.settingsNotice = settings.notice;
652
596
  for (const warning of settings.warnings) {
653
597
  ctx.ui.notify(sanitizeChromeDevtoolsDisplay(warning), "warning");
654
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
+ }
655
605
  const availableTools = settings.kind === "loaded" && settings.settings.tools ? settings.settings.tools : availableChromeDevtoolsTools(pi);
656
606
  configureChromeDevtoolsToolExposure(pi, availableTools, ctx.model);
657
607
  });
658
- pi.on("model_select", (event) => {
608
+ pi.on("model_select", (event, ctx) => {
609
+ invalidateWebMcpOperations(
610
+ ctx.sessionManager,
611
+ "Chrome DevTools model and tool exposure changed"
612
+ );
659
613
  if (!supportsNativeDeferredToolLoading(event.model)) {
660
614
  requireEagerChromeDevtoolsToolExposure(pi);
661
615
  }
@@ -663,8 +617,12 @@ function chromeDevtools(pi) {
663
617
  pi.on("session_shutdown", async (_event, ctx) => {
664
618
  state.sessionGeneration += 1;
665
619
  replaceSessionController("Chrome DevTools session shut down");
620
+ invalidateWebMcpOperations(ctx.sessionManager, "Chrome DevTools session shut down");
666
621
  ctx.ui.setStatus(STATUS_KEY2, void 0);
667
- const browserShutdown = shutdownManagedBrowser(void 0, { cancelLaunch: true });
622
+ const browserShutdown = shutdownManagedBrowser(void 0, {
623
+ cancelLaunch: true,
624
+ owner: ctx.sessionManager
625
+ });
668
626
  await waitForChromeDevtoolsSettings();
669
627
  await waitForSettingsWrites();
670
628
  await browserShutdown;
@@ -678,15 +636,15 @@ async function handleChromeDevtoolsCommand(pi, args, ctx, generation) {
678
636
  return;
679
637
  case "help":
680
638
  requireObservableUi(ctx, "help");
681
- ctx.ui.notify(buildCommandGuide(), "info");
639
+ ctx.ui.notify(buildCommandGuide(ctx.sessionManager), "info");
682
640
  return;
683
641
  case "quickstart":
684
642
  requireObservableUi(ctx, "quickstart");
685
- ctx.ui.notify(buildQuickstartMessage(), "info");
643
+ ctx.ui.notify(buildQuickstartMessage(ctx.sessionManager), "info");
686
644
  return;
687
645
  case "status": {
688
646
  requireObservableUi(ctx, "status");
689
- const status = await buildToolStatusMessage(pi);
647
+ const status = await buildToolStatusMessage(pi, ctx.sessionManager);
690
648
  if (generation !== state.sessionGeneration) return;
691
649
  ctx.ui.notify(status, "info");
692
650
  return;
@@ -695,22 +653,27 @@ async function handleChromeDevtoolsCommand(pi, args, ctx, generation) {
695
653
  if (!ctx.hasUI || ctx.mode !== "tui" && ctx.mode !== "rpc") {
696
654
  throw new Error("/chrome-devtools settings requires TUI or RPC mode");
697
655
  }
698
- const { showChromeDevtoolsBrowserSettings } = await import("./chunks/browser-settings-menu-VWCNG4HB.js");
656
+ const { showChromeDevtoolsBrowserSettings } = await import("./chunks/browser-settings-menu-N5O65I7S.js");
699
657
  if (generation !== state.sessionGeneration) return;
700
- await showChromeDevtoolsBrowserSettings(ctx, generation);
658
+ await showChromeDevtoolsBrowserSettings(pi, ctx, generation);
701
659
  return;
702
660
  }
703
661
  case "tools": {
704
662
  if (!ctx.hasUI || ctx.mode !== "tui" && ctx.mode !== "rpc") {
705
663
  throw new Error("/chrome-devtools tools requires TUI or RPC mode");
706
664
  }
707
- const { showChromeDevtoolsToolWorkflow } = await import("./chunks/menu-PLD3S3EO.js");
665
+ const { showChromeDevtoolsToolWorkflow } = await import("./chunks/menu-UBHW6UP2.js");
708
666
  if (generation !== state.sessionGeneration) return;
709
667
  await showChromeDevtoolsToolWorkflow(pi, ctx, generation);
710
668
  return;
711
669
  }
712
670
  case "enable":
713
- await updateChromeDevtoolsTools(pi, ctx, allChromeDevtoolsTools(), "made all available");
671
+ await updateChromeDevtoolsTools(
672
+ pi,
673
+ ctx,
674
+ allChromeDevtoolsTools(ctx.sessionManager),
675
+ "made all available"
676
+ );
714
677
  return;
715
678
  case "disable":
716
679
  await updateChromeDevtoolsTools(pi, ctx, [], "made all unavailable");
@@ -722,7 +685,7 @@ async function handleChromeDevtoolsCommand(pi, args, ctx, generation) {
722
685
  ctx.ui.notify(
723
686
  `Unknown /chrome-devtools command: ${args.trim()}
724
687
 
725
- ${buildCommandGuide()}`,
688
+ ${buildCommandGuide(ctx.sessionManager)}`,
726
689
  "warning"
727
690
  );
728
691
  }
@@ -735,7 +698,7 @@ async function showMenu(pi, ctx, generation) {
735
698
  if (!ctx.hasUI || ctx.mode !== "tui" && ctx.mode !== "rpc") {
736
699
  throw new Error("/chrome-devtools menu requires TUI or RPC mode; use a direct subcommand");
737
700
  }
738
- const { showChromeDevtoolsMenu } = await import("./chunks/menu-PLD3S3EO.js");
701
+ const { showChromeDevtoolsMenu } = await import("./chunks/menu-UBHW6UP2.js");
739
702
  if (generation !== state.sessionGeneration) return;
740
703
  await showChromeDevtoolsMenu(pi, ctx, generation);
741
704
  }