@narumitw/pi-chrome-devtools 0.53.2 → 0.53.3
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 +1 -0
- package/dist/chunks/{browser-settings-menu-IMB6HXSU.js → browser-settings-menu-SR7KLZT6.js} +16 -42
- package/dist/chunks/browser-settings-menu-SR7KLZT6.js.map +7 -0
- package/dist/chunks/{chunk-GTTYS5GT.js → chunk-4KMN4SFF.js} +2 -2
- package/dist/chunks/chunk-4KMN4SFF.js.map +7 -0
- package/dist/chunks/{chunk-SRT3UUIP.js → chunk-F5VG35UI.js} +23 -74
- package/dist/chunks/chunk-F5VG35UI.js.map +7 -0
- package/dist/chunks/{chunk-LLXOCRNF.js → chunk-MZCGM6D3.js} +12 -33
- package/dist/chunks/chunk-MZCGM6D3.js.map +7 -0
- package/dist/chunks/{menu-UJETYMSB.js → menu-YR4VRT7D.js} +10 -23
- package/dist/chunks/menu-YR4VRT7D.js.map +7 -0
- package/dist/chunks/{tools-6P7EUX37.js → tools-6R7Z6HWJ.js} +17 -59
- package/dist/chunks/tools-6R7Z6HWJ.js.map +7 -0
- package/dist/index.ts +18 -42
- package/dist/index.ts.map +2 -2
- package/package.json +54 -55
- package/src/browser-manager.ts +872 -942
- package/src/browser-settings-menu.ts +315 -350
- package/src/cdp-client.ts +381 -398
- package/src/chrome-devtools.ts +205 -232
- package/src/display.ts +26 -29
- package/src/lazy-tools.ts +158 -181
- package/src/menu.ts +409 -446
- package/src/render.ts +72 -81
- package/src/runtime.ts +137 -140
- package/src/screenshot.ts +170 -186
- package/src/settings.ts +472 -523
- package/src/tool-names.ts +8 -14
- package/src/tool-selector.ts +242 -271
- package/src/tools.ts +218 -226
- package/src/webmcp/discovery.ts +184 -188
- package/src/webmcp/policy.ts +296 -329
- package/src/webmcp/protocol.ts +324 -337
- package/src/webmcp/tools.ts +136 -147
- package/dist/chunks/browser-settings-menu-IMB6HXSU.js.map +0 -7
- package/dist/chunks/chunk-GTTYS5GT.js.map +0 -7
- package/dist/chunks/chunk-LLXOCRNF.js.map +0 -7
- package/dist/chunks/chunk-SRT3UUIP.js.map +0 -7
- package/dist/chunks/menu-UJETYMSB.js.map +0 -7
- package/dist/chunks/tools-6P7EUX37.js.map +0 -7
package/src/tool-names.ts
CHANGED
|
@@ -1,24 +1,18 @@
|
|
|
1
1
|
export const CORE_CHROME_DEVTOOLS_TOOL_NAMES = [
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"chrome_devtools_list_pages",
|
|
3
|
+
"chrome_devtools_select_page",
|
|
4
|
+
"chrome_devtools_navigate",
|
|
5
|
+
"chrome_devtools_evaluate",
|
|
6
|
+
"chrome_devtools_screenshot",
|
|
7
7
|
] as const;
|
|
8
8
|
|
|
9
|
-
export const WEBMCP_TOOL_NAMES = [
|
|
10
|
-
"chrome_devtools_webmcp_list_tools",
|
|
11
|
-
"chrome_devtools_webmcp_call_tool",
|
|
12
|
-
] as const;
|
|
9
|
+
export const WEBMCP_TOOL_NAMES = ["chrome_devtools_webmcp_list_tools", "chrome_devtools_webmcp_call_tool"] as const;
|
|
13
10
|
|
|
14
|
-
export const CHROME_DEVTOOLS_TOOL_NAMES = [
|
|
15
|
-
...CORE_CHROME_DEVTOOLS_TOOL_NAMES,
|
|
16
|
-
...WEBMCP_TOOL_NAMES,
|
|
17
|
-
] as const;
|
|
11
|
+
export const CHROME_DEVTOOLS_TOOL_NAMES = [...CORE_CHROME_DEVTOOLS_TOOL_NAMES, ...WEBMCP_TOOL_NAMES] as const;
|
|
18
12
|
|
|
19
13
|
export type ChromeDevToolsToolName = (typeof CHROME_DEVTOOLS_TOOL_NAMES)[number];
|
|
20
14
|
export type WebMcpToolName = (typeof WEBMCP_TOOL_NAMES)[number];
|
|
21
15
|
|
|
22
16
|
export function isWebMcpToolName(value: string): value is WebMcpToolName {
|
|
23
|
-
|
|
17
|
+
return WEBMCP_TOOL_NAMES.includes(value as WebMcpToolName);
|
|
24
18
|
}
|
package/src/tool-selector.ts
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
browserCandidateHint,
|
|
4
|
+
browserLifecycleState,
|
|
5
|
+
browserSettingsForOwner,
|
|
6
|
+
devToolsEndpoint,
|
|
7
|
+
endpointConfigHint,
|
|
8
|
+
endpointSourceLabel,
|
|
9
|
+
launchAttemptLines,
|
|
10
|
+
launchHint,
|
|
11
|
+
launchModeLabel,
|
|
12
|
+
managedBrowserForOwner,
|
|
13
13
|
} from "./browser-manager.js";
|
|
14
14
|
import { sanitizeChromeDevtoolsDisplay } from "./display.js";
|
|
15
15
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
applyAvailableChromeDevtoolsTools,
|
|
17
|
+
availableChromeDevtoolsTools,
|
|
18
|
+
CHROME_DEVTOOLS_LOAD_TOOL_NAME,
|
|
19
|
+
chromeDevtoolsToolExposureMode,
|
|
20
20
|
} from "./lazy-tools.js";
|
|
21
21
|
import { invalidateWebMcpOperations, state, webMcpEnabled } from "./runtime.js";
|
|
22
22
|
import { loadSettings, saveSettings, settingsFilePath } from "./settings.js";
|
|
23
23
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
CHROME_DEVTOOLS_TOOL_NAMES,
|
|
25
|
+
type ChromeDevToolsToolName,
|
|
26
|
+
CORE_CHROME_DEVTOOLS_TOOL_NAMES,
|
|
27
|
+
isWebMcpToolName,
|
|
28
28
|
} from "./tool-names.js";
|
|
29
29
|
|
|
30
30
|
export { sanitizeChromeDevtoolsDisplay };
|
|
@@ -32,334 +32,305 @@ export { sanitizeChromeDevtoolsDisplay };
|
|
|
32
32
|
type CommandContext = ExtensionCommandContext;
|
|
33
33
|
|
|
34
34
|
function unique<T>(values: T[]) {
|
|
35
|
-
|
|
35
|
+
return Array.from(new Set(values));
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
function formatError(error: unknown) {
|
|
39
|
-
|
|
39
|
+
return error instanceof Error ? error.message : String(error);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
interface ToolStatusSummary {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
availabilityStatus: "enabled" | "disabled" | "partial";
|
|
44
|
+
availableChromeToolCount: number;
|
|
45
|
+
loadedChromeToolCount: number;
|
|
46
|
+
activeNonChromeToolCount: number;
|
|
47
|
+
capabilityCount: number;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
type ToolSelectionSaveResult = "saved" | "active-tools-changed" | "failed";
|
|
51
51
|
|
|
52
52
|
export async function updateChromeDevtoolsTools(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
pi: ExtensionAPI,
|
|
54
|
+
ctx: CommandContext,
|
|
55
|
+
selectedTools: readonly ChromeDevToolsToolName[],
|
|
56
|
+
action: string,
|
|
57
57
|
) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
const generation = state.sessionGeneration;
|
|
59
|
+
const result = await transactSelectedTools(pi, ctx, selectedTools, generation);
|
|
60
|
+
if (result !== "saved" || generation !== state.sessionGeneration) return;
|
|
61
|
+
const status = await buildToolStatusMessage(pi, ctx.sessionManager);
|
|
62
|
+
if (generation !== state.sessionGeneration) return;
|
|
63
|
+
ctx.ui.notify(`Chrome DevTools tool catalog ${action}.\n\n${status}`, "info");
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
export async function setSelectedChromeDevtoolsTools(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
pi: ExtensionAPI,
|
|
68
|
+
ctx: CommandContext,
|
|
69
|
+
selectedTools: readonly ChromeDevToolsToolName[],
|
|
70
|
+
expectedActiveTools: readonly ChromeDevToolsToolName[],
|
|
71
71
|
): Promise<ToolSelectionSaveResult> {
|
|
72
|
-
|
|
73
|
-
pi,
|
|
74
|
-
ctx,
|
|
75
|
-
selectedTools,
|
|
76
|
-
state.sessionGeneration,
|
|
77
|
-
expectedActiveTools,
|
|
78
|
-
);
|
|
72
|
+
return transactSelectedTools(pi, ctx, selectedTools, state.sessionGeneration, expectedActiveTools);
|
|
79
73
|
}
|
|
80
74
|
|
|
81
75
|
let toolTransactionQueue = Promise.resolve();
|
|
82
76
|
|
|
83
77
|
export async function waitForChromeDevtoolsSettings(): Promise<void> {
|
|
84
|
-
|
|
78
|
+
await toolTransactionQueue;
|
|
85
79
|
}
|
|
86
80
|
|
|
87
81
|
function transactSelectedTools(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
82
|
+
pi: ExtensionAPI,
|
|
83
|
+
ctx: CommandContext,
|
|
84
|
+
selectedTools: readonly ChromeDevToolsToolName[],
|
|
85
|
+
expectedGeneration: number,
|
|
86
|
+
expectedActiveTools?: readonly ChromeDevToolsToolName[],
|
|
93
87
|
): Promise<ToolSelectionSaveResult> {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
88
|
+
const operation = toolTransactionQueue.then(() =>
|
|
89
|
+
transactSelectedToolsNow(pi, ctx, selectedTools, expectedGeneration, expectedActiveTools),
|
|
90
|
+
);
|
|
91
|
+
toolTransactionQueue = operation.then(
|
|
92
|
+
() => undefined,
|
|
93
|
+
() => undefined,
|
|
94
|
+
);
|
|
95
|
+
return operation;
|
|
102
96
|
}
|
|
103
97
|
|
|
104
98
|
async function transactSelectedToolsNow(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
99
|
+
pi: ExtensionAPI,
|
|
100
|
+
ctx: CommandContext,
|
|
101
|
+
selectedTools: readonly ChromeDevToolsToolName[],
|
|
102
|
+
expectedGeneration: number,
|
|
103
|
+
expectedActiveTools?: readonly ChromeDevToolsToolName[],
|
|
110
104
|
): Promise<ToolSelectionSaveResult> {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
),
|
|
158
|
-
"warning",
|
|
159
|
-
);
|
|
160
|
-
return "failed";
|
|
161
|
-
}
|
|
105
|
+
if (expectedGeneration !== state.sessionGeneration) return "failed";
|
|
106
|
+
if (expectedActiveTools && !arraysEqual(availableChromeDevtoolsTools(pi), expectedActiveTools)) {
|
|
107
|
+
ctx.ui.notify(
|
|
108
|
+
"Browser tool selection changed while review was open. Review the current state, then apply again.",
|
|
109
|
+
"warning",
|
|
110
|
+
);
|
|
111
|
+
return "active-tools-changed";
|
|
112
|
+
}
|
|
113
|
+
const previousActiveTools = pi.getActiveTools();
|
|
114
|
+
const previousAvailableTools = availableChromeDevtoolsTools(pi);
|
|
115
|
+
try {
|
|
116
|
+
const previousWebMcpTools = previousAvailableTools.filter(isWebMcpToolName);
|
|
117
|
+
const selectedWebMcpTools = selectedTools.filter(isWebMcpToolName);
|
|
118
|
+
if (!arraysEqual(previousWebMcpTools, selectedWebMcpTools)) {
|
|
119
|
+
invalidateWebMcpOperations(ctx.sessionManager, "Chrome DevTools WebMCP gateway availability changed");
|
|
120
|
+
}
|
|
121
|
+
applyChromeDevtoolsTools(pi, selectedTools);
|
|
122
|
+
await persistSettings(selectedTools);
|
|
123
|
+
return expectedGeneration === state.sessionGeneration ? "saved" : "failed";
|
|
124
|
+
} catch (error) {
|
|
125
|
+
let rollbackError: unknown;
|
|
126
|
+
try {
|
|
127
|
+
applyAvailableChromeDevtoolsTools(pi, previousAvailableTools);
|
|
128
|
+
const currentNonChromeTools = pi
|
|
129
|
+
.getActiveTools()
|
|
130
|
+
.filter((name) => !CHROME_DEVTOOLS_TOOL_NAMES.includes(name as ChromeDevToolsToolName));
|
|
131
|
+
const previousLoadedChromeTools = previousActiveTools.filter((name) =>
|
|
132
|
+
CHROME_DEVTOOLS_TOOL_NAMES.includes(name as ChromeDevToolsToolName),
|
|
133
|
+
);
|
|
134
|
+
const restoredChromeTools =
|
|
135
|
+
chromeDevtoolsToolExposureMode(pi) === "eager" ? previousAvailableTools : previousLoadedChromeTools;
|
|
136
|
+
pi.setActiveTools(unique([...currentNonChromeTools, ...restoredChromeTools]));
|
|
137
|
+
} catch (caught) {
|
|
138
|
+
rollbackError = caught;
|
|
139
|
+
}
|
|
140
|
+
if (expectedGeneration !== state.sessionGeneration) return "failed";
|
|
141
|
+
ctx.ui.notify(
|
|
142
|
+
sanitizeChromeDevtoolsDisplay(
|
|
143
|
+
rollbackError
|
|
144
|
+
? `Chrome DevTools settings save failed: ${formatError(error)}; active-tool rollback failed: ${formatError(rollbackError)}`
|
|
145
|
+
: `Chrome DevTools settings save failed; active tools restored: ${formatError(error)}`,
|
|
146
|
+
),
|
|
147
|
+
"warning",
|
|
148
|
+
);
|
|
149
|
+
return "failed";
|
|
150
|
+
}
|
|
162
151
|
}
|
|
163
152
|
|
|
164
153
|
function arraysEqual<T>(left: readonly T[], right: readonly T[]) {
|
|
165
|
-
|
|
154
|
+
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
166
155
|
}
|
|
167
156
|
|
|
168
|
-
export function applyChromeDevtoolsTools(
|
|
169
|
-
|
|
170
|
-
selectedTools: readonly ChromeDevToolsToolName[],
|
|
171
|
-
) {
|
|
172
|
-
applyAvailableChromeDevtoolsTools(pi, selectedTools);
|
|
157
|
+
export function applyChromeDevtoolsTools(pi: ExtensionAPI, selectedTools: readonly ChromeDevToolsToolName[]) {
|
|
158
|
+
applyAvailableChromeDevtoolsTools(pi, selectedTools);
|
|
173
159
|
}
|
|
174
160
|
|
|
175
161
|
function getToolStatusSummary(pi: ExtensionAPI, owner: object): ToolStatusSummary {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const availabilityStatus =
|
|
187
|
-
availableChromeToolCount === capabilityCount
|
|
188
|
-
? "enabled"
|
|
189
|
-
: availableChromeToolCount === 0
|
|
190
|
-
? "disabled"
|
|
191
|
-
: "partial";
|
|
162
|
+
const chromeToolNames = new Set<string>(CHROME_DEVTOOLS_TOOL_NAMES);
|
|
163
|
+
const activeToolNames = new Set(pi.getActiveTools());
|
|
164
|
+
const loadedChromeToolCount = CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => activeToolNames.has(name)).length;
|
|
165
|
+
const availableChromeToolCount = availableChromeDevtoolsTools(pi).length;
|
|
166
|
+
const activeNonChromeToolCount = Array.from(activeToolNames).filter(
|
|
167
|
+
(name) => !chromeToolNames.has(name) && name !== CHROME_DEVTOOLS_LOAD_TOOL_NAME,
|
|
168
|
+
).length;
|
|
169
|
+
const capabilityCount = effectiveCatalog(owner).length;
|
|
170
|
+
const availabilityStatus =
|
|
171
|
+
availableChromeToolCount === capabilityCount ? "enabled" : availableChromeToolCount === 0 ? "disabled" : "partial";
|
|
192
172
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
173
|
+
return {
|
|
174
|
+
availabilityStatus,
|
|
175
|
+
availableChromeToolCount,
|
|
176
|
+
loadedChromeToolCount,
|
|
177
|
+
activeNonChromeToolCount,
|
|
178
|
+
capabilityCount,
|
|
179
|
+
};
|
|
200
180
|
}
|
|
201
181
|
|
|
202
182
|
export async function buildToolStatusMessage(pi: ExtensionAPI, owner: object) {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
183
|
+
const summary = getToolStatusSummary(pi, owner);
|
|
184
|
+
const persistedSetting = await persistedSettingLabel();
|
|
185
|
+
return sanitizeChromeDevtoolsDisplay(
|
|
186
|
+
[
|
|
187
|
+
`Chrome DevTools tools available: ${formatRuntimeStatus(summary)}`,
|
|
188
|
+
`Tool exposure: ${chromeDevtoolsToolExposureMode(pi)}`,
|
|
189
|
+
`Loaded capability tools this session: ${summary.loadedChromeToolCount}/${summary.capabilityCount}`,
|
|
190
|
+
`WebMCP: ${webMcpEnabled(owner) ? "enabled · experimental · confirmation required for every call" : "disabled · experimental"}`,
|
|
191
|
+
`Loader: ${pi.getActiveTools().includes(CHROME_DEVTOOLS_LOAD_TOOL_NAME) ? "active" : "inactive"}`,
|
|
192
|
+
`Persisted tool catalog: ${persistedSetting}`,
|
|
193
|
+
...browserSettingsStatusLines(owner),
|
|
194
|
+
...(state.settingsNotice ? [`Settings note: ${state.settingsNotice}`] : []),
|
|
195
|
+
`Other active tools preserved: ${summary.activeNonChromeToolCount}`,
|
|
196
|
+
`Endpoint: ${devToolsEndpoint(owner)}`,
|
|
197
|
+
`Endpoint source: ${endpointSourceLabel(owner)}`,
|
|
198
|
+
`Launch mode: ${launchModeLabel(owner)}`,
|
|
199
|
+
...launchAttemptLines(owner),
|
|
200
|
+
].join("\n"),
|
|
201
|
+
);
|
|
222
202
|
}
|
|
223
203
|
|
|
224
204
|
export function buildQuickstartMessage(owner: object) {
|
|
225
|
-
|
|
205
|
+
return buildSettingsSetupMessage(owner);
|
|
226
206
|
}
|
|
227
207
|
|
|
228
208
|
export function buildBrowserStatusMessage(owner?: object) {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
].join("\n"),
|
|
263
|
-
);
|
|
209
|
+
const browser = browserSettingsForOwner(owner);
|
|
210
|
+
const lifecycle = browserLifecycleState(owner);
|
|
211
|
+
const webMcpIsEnabled = owner ? webMcpEnabled(owner) : false;
|
|
212
|
+
const browserState =
|
|
213
|
+
lifecycle === "starting"
|
|
214
|
+
? "starting managed browser"
|
|
215
|
+
: lifecycle === "running"
|
|
216
|
+
? "managed browser running"
|
|
217
|
+
: lifecycle === "exited"
|
|
218
|
+
? "managed browser exited"
|
|
219
|
+
: lifecycle === "failed"
|
|
220
|
+
? "last launch failed"
|
|
221
|
+
: "not started; connection has not been checked";
|
|
222
|
+
const needsRecovery = lifecycle === "exited" || lifecycle === "failed";
|
|
223
|
+
return sanitizeChromeDevtoolsDisplay(
|
|
224
|
+
[
|
|
225
|
+
`Browser: ${browserState}`,
|
|
226
|
+
"Viewing this status does not probe the endpoint or launch Chrome.",
|
|
227
|
+
`Endpoint: ${devToolsEndpoint(owner)}`,
|
|
228
|
+
`Endpoint source: ${endpointSourceLabel(owner)}`,
|
|
229
|
+
`Launch mode: ${launchModeLabel(owner)}`,
|
|
230
|
+
`Unpacked extensions: ${browser.extensionPaths.length} (${browser.extensionPathsSource})`,
|
|
231
|
+
`WebMCP: ${webMcpIsEnabled ? "enabled · experimental" : "disabled · experimental"}`,
|
|
232
|
+
...(webMcpIsEnabled && !managedBrowserForOwner(owner)?.ready
|
|
233
|
+
? ["WebMCP warning: attached browser profiles may contain everyday authenticated sessions and sensitive state."]
|
|
234
|
+
: []),
|
|
235
|
+
...(browser.extensionPaths.length > 0
|
|
236
|
+
? ["Unpacked extensions execute trusted browser code in an isolated managed browser."]
|
|
237
|
+
: []),
|
|
238
|
+
...launchAttemptLines(owner),
|
|
239
|
+
...(needsRecovery ? [launchHint(owner), endpointConfigHint()] : []),
|
|
240
|
+
].join("\n"),
|
|
241
|
+
);
|
|
264
242
|
}
|
|
265
243
|
|
|
266
244
|
export function buildSettingsSetupMessage(owner: object) {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
245
|
+
return sanitizeChromeDevtoolsDisplay(
|
|
246
|
+
[
|
|
247
|
+
`Chrome DevTools endpoint: ${devToolsEndpoint(owner)}`,
|
|
248
|
+
`Endpoint source: ${endpointSourceLabel(owner)}`,
|
|
249
|
+
`Launch mode: ${launchModeLabel(owner)}`,
|
|
250
|
+
...browserSettingsStatusLines(owner),
|
|
251
|
+
launchHint(owner),
|
|
252
|
+
browserCandidateHint(owner),
|
|
253
|
+
...launchAttemptLines(owner),
|
|
254
|
+
endpointConfigHint(),
|
|
255
|
+
].join("\n"),
|
|
256
|
+
);
|
|
279
257
|
}
|
|
280
258
|
|
|
281
259
|
function browserSettingsStatusLines(owner: object) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
"Unpacked extensions require Chrome for Testing or Chromium and execute trusted browser code.",
|
|
304
|
-
]
|
|
305
|
-
: []),
|
|
306
|
-
];
|
|
260
|
+
const browser = browserSettingsForOwner(owner);
|
|
261
|
+
const extensionPaths = browser.extensionPaths;
|
|
262
|
+
const extensionLines =
|
|
263
|
+
extensionPaths.length > 0 ? extensionPaths.map((extensionPath) => ` - ${extensionPath}`) : [" - none"];
|
|
264
|
+
return [
|
|
265
|
+
`Settings file: ${state.settingsFilePath ?? settingsFilePath()} (user)`,
|
|
266
|
+
...(state.projectSettingsFilePath
|
|
267
|
+
? [
|
|
268
|
+
`Project settings: ${state.projectSettingsFilePath} (${state.projectSettingsTrusted ? "trusted" : "untrusted; ignored"})`,
|
|
269
|
+
]
|
|
270
|
+
: []),
|
|
271
|
+
`Auto-launch: ${browser.autoLaunchEnabled ? "on" : "off"} (${browser.autoLaunchSource})`,
|
|
272
|
+
`Browser executable: ${browser.executablePath ?? "automatic discovery"} (${browser.executablePathSource})`,
|
|
273
|
+
`Unpacked extensions (${browser.extensionPathsSource}):`,
|
|
274
|
+
...extensionLines,
|
|
275
|
+
`WebMCP: ${webMcpEnabled(owner) ? "enabled · experimental · every call requires confirmation" : "disabled · experimental"}`,
|
|
276
|
+
"Confirmed menu settings apply before the next browser connection; manual JSON edits require /reload or session replacement.",
|
|
277
|
+
...(extensionPaths.length > 0
|
|
278
|
+
? ["Unpacked extensions require Chrome for Testing or Chromium and execute trusted browser code."]
|
|
279
|
+
: []),
|
|
280
|
+
];
|
|
307
281
|
}
|
|
308
282
|
|
|
309
283
|
export function buildCommandGuide(owner: object) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
284
|
+
return [
|
|
285
|
+
"Chrome DevTools commands:",
|
|
286
|
+
`WebMCP: ${webMcpEnabled(owner) ? "enabled" : "disabled"} · experimental · every page-provided call requires confirmation`,
|
|
287
|
+
"/chrome-devtools — open this menu",
|
|
288
|
+
"/chrome-devtools help — show command usage",
|
|
289
|
+
"/chrome-devtools quickstart — show endpoint and launch help",
|
|
290
|
+
"/chrome-devtools status — show tool and settings status",
|
|
291
|
+
"/chrome-devtools settings — edit browser connection settings",
|
|
292
|
+
"/chrome-devtools tools — choose available Chrome DevTools tools",
|
|
293
|
+
"/chrome-devtools toggle|select — compatibility aliases for tools",
|
|
294
|
+
"/chrome-devtools enable|on — make all Chrome DevTools tools available",
|
|
295
|
+
"/chrome-devtools disable|off — make all Chrome DevTools capability tools unavailable",
|
|
296
|
+
].join("\n");
|
|
323
297
|
}
|
|
324
298
|
|
|
325
299
|
export function allChromeDevtoolsTools(owner: object) {
|
|
326
|
-
|
|
300
|
+
return effectiveCatalog(owner);
|
|
327
301
|
}
|
|
328
302
|
|
|
329
303
|
export function orderedChromeDevtoolsTools(selectedTools: ReadonlySet<ChromeDevToolsToolName>) {
|
|
330
|
-
|
|
304
|
+
return CHROME_DEVTOOLS_TOOL_NAMES.filter((toolName) => selectedTools.has(toolName));
|
|
331
305
|
}
|
|
332
306
|
|
|
333
307
|
function formatRuntimeStatus(summary: ToolStatusSummary) {
|
|
334
|
-
|
|
308
|
+
return `${summary.availabilityStatus} (${summary.availableChromeToolCount}/${summary.capabilityCount} available)`;
|
|
335
309
|
}
|
|
336
310
|
|
|
337
311
|
async function persistedSettingLabel() {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
312
|
+
const settings = await loadSettings();
|
|
313
|
+
if (settings.kind === "loaded" && settings.settings.tools) {
|
|
314
|
+
return formatPersistedSelection(settings.settings.tools);
|
|
315
|
+
}
|
|
316
|
+
if (settings.kind === "invalid") {
|
|
317
|
+
return `none; current active-tool policy preserved (invalid settings ignored: ${settings.reason})`;
|
|
318
|
+
}
|
|
319
|
+
return "none; current active-tool policy preserved";
|
|
346
320
|
}
|
|
347
321
|
|
|
348
322
|
function formatPersistedSelection(tools: readonly ChromeDevToolsToolName[]) {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
return `${tools.length}/${CHROME_DEVTOOLS_TOOL_NAMES.length} selected: ${tools.join(", ")}`;
|
|
323
|
+
if (tools.length === CHROME_DEVTOOLS_TOOL_NAMES.length) {
|
|
324
|
+
return `all available (${tools.length}/${CHROME_DEVTOOLS_TOOL_NAMES.length} selected)`;
|
|
325
|
+
}
|
|
326
|
+
if (tools.length === 0) return `all unavailable (0/${CHROME_DEVTOOLS_TOOL_NAMES.length} selected)`;
|
|
327
|
+
return `${tools.length}/${CHROME_DEVTOOLS_TOOL_NAMES.length} selected: ${tools.join(", ")}`;
|
|
355
328
|
}
|
|
356
329
|
|
|
357
330
|
function effectiveCatalog(owner: object): ChromeDevToolsToolName[] {
|
|
358
|
-
|
|
359
|
-
? [...CHROME_DEVTOOLS_TOOL_NAMES]
|
|
360
|
-
: [...CORE_CHROME_DEVTOOLS_TOOL_NAMES];
|
|
331
|
+
return webMcpEnabled(owner) ? [...CHROME_DEVTOOLS_TOOL_NAMES] : [...CORE_CHROME_DEVTOOLS_TOOL_NAMES];
|
|
361
332
|
}
|
|
362
333
|
|
|
363
334
|
async function persistSettings(selectedTools: readonly ChromeDevToolsToolName[]) {
|
|
364
|
-
|
|
335
|
+
await saveSettings({ tools: [...selectedTools], updatedAt: Date.now() });
|
|
365
336
|
}
|