@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.
Files changed (35) hide show
  1. package/README.md +78 -17
  2. package/dist/chunks/{browser-settings-menu-VI2I3TXI.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-CC37WUUE.js → chunk-GVBXT3FB.js} +369 -461
  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-LLR455UX.js → menu-UBHW6UP2.js} +75 -41
  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 +166 -196
  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 +61 -13
  21. package/src/lazy-tools.ts +105 -8
  22. package/src/menu.ts +83 -41
  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 +79 -36
  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-VI2I3TXI.js.map +0 -7
  34. package/dist/chunks/chunk-CC37WUUE.js.map +0 -7
  35. 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
- 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
- configureLazyChromeDevtoolsTools,
18
+ configureChromeDevtoolsToolExposure,
14
19
  createChromeDevtoolsLoadTool,
15
- devToolsEndpoint,
16
- ensureDevToolsEndpoint,
17
- fetchDevToolsJson,
18
- formatPageListItem,
19
20
  initializeAvailableChromeDevtoolsTools,
20
- launchHint,
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
- withEndpointRetry
29
- } from "./chunks/chunk-CC37WUUE.js";
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
- 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);
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, _signal, _onUpdate, ctx) {
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, _signal, _onUpdate, ctx) {
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, _signal, _onUpdate, ctx) {
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, _signal, _onUpdate, ctx) {
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 lazy-loadable Chrome DevTools tools" },
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
- configureLazyChromeDevtoolsTools(pi, availableTools);
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, { cancelLaunch: true });
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-VI2I3TXI.js");
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-LLR455UX.js");
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(pi, ctx, allChromeDevtoolsTools(), "made all available");
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-LLR455UX.js");
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
  }