@narumitw/pi-chrome-devtools 0.53.3 → 0.54.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 +28 -11
- package/dist/chunks/{browser-settings-menu-SR7KLZT6.js → browser-settings-menu-GQAXLWZ7.ts} +25 -3
- package/dist/chunks/browser-settings-menu-GQAXLWZ7.ts.map +7 -0
- package/dist/chunks/{chunk-4KMN4SFF.js → chunk-5T2WEIYN.ts} +2 -2
- package/dist/chunks/{chunk-F5VG35UI.js → chunk-TVVYQ5KM.ts} +55 -7
- package/dist/chunks/chunk-TVVYQ5KM.ts.map +7 -0
- package/dist/chunks/{chunk-MZCGM6D3.js → chunk-WOFI2A72.ts} +337 -88
- package/dist/chunks/chunk-WOFI2A72.ts.map +7 -0
- package/dist/chunks/{menu-YR4VRT7D.js → menu-Z26D6XSI.ts} +7 -7
- package/dist/chunks/{menu-YR4VRT7D.js.map → menu-Z26D6XSI.ts.map} +1 -1
- package/dist/chunks/{tools-6R7Z6HWJ.js → tools-DSYQPFF3.ts} +3 -3
- package/dist/index.ts +45 -21
- package/dist/index.ts.map +2 -2
- package/package.json +3 -3
- package/src/browser-settings-menu.ts +23 -0
- package/src/chrome-devtools.ts +48 -15
- package/src/lazy-tools.ts +350 -26
- package/src/menu.ts +3 -3
- package/src/settings.ts +65 -1
- package/src/tool-selector.ts +95 -40
- package/dist/chunks/browser-settings-menu-SR7KLZT6.js.map +0 -7
- package/dist/chunks/chunk-F5VG35UI.js.map +0 -7
- package/dist/chunks/chunk-MZCGM6D3.js.map +0 -7
- /package/dist/chunks/{chunk-4KMN4SFF.js.map → chunk-5T2WEIYN.ts.map} +0 -0
- /package/dist/chunks/{tools-6R7Z6HWJ.js.map → tools-DSYQPFF3.ts.map} +0 -0
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import {
|
|
4
4
|
CHROME_DEVTOOLS_TOOL_NAMES,
|
|
5
5
|
CORE_CHROME_DEVTOOLS_TOOL_NAMES,
|
|
6
|
+
ToolCatalogApplicationError,
|
|
6
7
|
browserCandidateHint,
|
|
7
8
|
browserLifecycleState,
|
|
8
9
|
browserSettingsForOwner,
|
|
@@ -20,10 +21,42 @@ import {
|
|
|
20
21
|
settingsFilePath,
|
|
21
22
|
state,
|
|
22
23
|
webMcpEnabled
|
|
23
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-TVVYQ5KM.ts";
|
|
25
|
+
|
|
26
|
+
// src/display.ts
|
|
27
|
+
var MAX_SANITIZER_INPUT_CODE_UNITS = 5e4;
|
|
28
|
+
var graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
29
|
+
function sanitizeChromeDevtoolsDisplay(value, maxCharacters = 5e4) {
|
|
30
|
+
const inputWasTruncated = value.length > MAX_SANITIZER_INPUT_CODE_UNITS;
|
|
31
|
+
const boundedInput = inputWasTruncated ? truncateAtGraphemeBoundary(value, MAX_SANITIZER_INPUT_CODE_UNITS) : value;
|
|
32
|
+
const normalizedLineEndings = boundedInput.replace(/\r\n/g, "\n");
|
|
33
|
+
const sanitized = Array.from(normalizedLineEndings, (character) => {
|
|
34
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
35
|
+
const unsafeControl = codePoint >= 0 && codePoint <= 8 || codePoint >= 11 && codePoint <= 31 || codePoint >= 127 && codePoint <= 159;
|
|
36
|
+
const unsafeBidi = codePoint >= 8234 && codePoint <= 8238 || codePoint >= 8294 && codePoint <= 8297;
|
|
37
|
+
const loneSurrogate = character.length === 1 && codePoint >= 55296 && codePoint <= 57343;
|
|
38
|
+
return unsafeControl || unsafeBidi || loneSurrogate ? "\uFFFD" : character;
|
|
39
|
+
}).join("");
|
|
40
|
+
const outputLimit = Math.min(maxCharacters, MAX_SANITIZER_INPUT_CODE_UNITS);
|
|
41
|
+
if (!inputWasTruncated && sanitized.length <= outputLimit) return sanitized;
|
|
42
|
+
return `${truncateAtGraphemeBoundary(sanitized, Math.max(0, outputLimit - 1))}\u2026`;
|
|
43
|
+
}
|
|
44
|
+
function truncateAtGraphemeBoundary(value, maxCodeUnits) {
|
|
45
|
+
if (value.length <= maxCodeUnits) return value;
|
|
46
|
+
const boundedLookahead = value.slice(0, Math.max(0, maxCodeUnits) + 2);
|
|
47
|
+
let safeEnd = 0;
|
|
48
|
+
for (const { index, segment } of graphemeSegmenter.segment(boundedLookahead)) {
|
|
49
|
+
const segmentEnd = index + segment.length;
|
|
50
|
+
if (segmentEnd > maxCodeUnits) break;
|
|
51
|
+
safeEnd = segmentEnd;
|
|
52
|
+
}
|
|
53
|
+
return value.slice(0, safeEnd);
|
|
54
|
+
}
|
|
24
55
|
|
|
25
56
|
// src/lazy-tools.ts
|
|
26
|
-
import {
|
|
57
|
+
import {
|
|
58
|
+
defineTool
|
|
59
|
+
} from "@earendil-works/pi-coding-agent";
|
|
27
60
|
import { Type } from "typebox";
|
|
28
61
|
var CHROME_DEVTOOLS_LOAD_TOOL_NAME = "chrome_devtools_load";
|
|
29
62
|
var AVAILABLE_TOOLS_STORE = /* @__PURE__ */ Symbol.for("@narumitw/pi-chrome-devtools.available-tools-store");
|
|
@@ -33,6 +66,153 @@ var availableToolsByApi = existingAvailableToolsStore ?? /* @__PURE__ */ new Wea
|
|
|
33
66
|
if (!existingAvailableToolsStore) sharedGlobal[AVAILABLE_TOOLS_STORE] = availableToolsByApi;
|
|
34
67
|
var lazyExposureByApi = /* @__PURE__ */ new WeakMap();
|
|
35
68
|
var sessionOwnerByApi = /* @__PURE__ */ new WeakMap();
|
|
69
|
+
var PROVENANCE_STORE = /* @__PURE__ */ Symbol.for("@narumitw/pi-chrome-devtools.activation-provenance");
|
|
70
|
+
var PROVENANCE_ENTRY = "chrome-devtools.activation-provenance";
|
|
71
|
+
var provenanceGlobal = globalThis;
|
|
72
|
+
var ownedBySession = provenanceGlobal[PROVENANCE_STORE] ?? /* @__PURE__ */ new WeakMap();
|
|
73
|
+
provenanceGlobal[PROVENANCE_STORE] = ownedBySession;
|
|
74
|
+
var modeByApi = /* @__PURE__ */ new WeakMap();
|
|
75
|
+
var loaderRegistered = /* @__PURE__ */ new WeakSet();
|
|
76
|
+
function retainedExplicitTools(pi, before) {
|
|
77
|
+
const owner = sessionOwnerByApi.get(pi);
|
|
78
|
+
const ownership = owner ? ownedBySession.get(owner) : void 0;
|
|
79
|
+
const observed = new Set(before);
|
|
80
|
+
return CHROME_DEVTOOLS_TOOL_NAMES.filter(
|
|
81
|
+
(name) => ownership?.explicit.has(name) && (observed.has(name) || ownership.published?.has(name) === false)
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
function publishActiveTools(pi, names, before) {
|
|
85
|
+
pi.setActiveTools(names);
|
|
86
|
+
recordOwnership(pi, before);
|
|
87
|
+
}
|
|
88
|
+
function recordOwnership(pi, before) {
|
|
89
|
+
const names = pi.getActiveTools();
|
|
90
|
+
const owner = sessionOwnerByApi.get(pi);
|
|
91
|
+
if (!owner) return;
|
|
92
|
+
const ownership = ownedBySession.get(owner) ?? {
|
|
93
|
+
explicit: /* @__PURE__ */ new Set(),
|
|
94
|
+
owned: /* @__PURE__ */ new Set()
|
|
95
|
+
};
|
|
96
|
+
const observed = new Set(before);
|
|
97
|
+
for (const name of ownership.explicit) {
|
|
98
|
+
if (!observed.has(name) && (ownership.published?.has(name) ?? true))
|
|
99
|
+
ownership.explicit.delete(name);
|
|
100
|
+
}
|
|
101
|
+
for (const name of before)
|
|
102
|
+
if (CHROME_DEVTOOLS_TOOL_NAMES.includes(name) && !ownership.owned.has(name))
|
|
103
|
+
ownership.explicit.add(name);
|
|
104
|
+
if (chromeDevtoolsToolMode(pi) !== "codemode") {
|
|
105
|
+
for (const name of names)
|
|
106
|
+
if (CHROME_DEVTOOLS_TOOL_NAMES.includes(name) && !ownership.explicit.has(name))
|
|
107
|
+
ownership.owned.add(name);
|
|
108
|
+
}
|
|
109
|
+
if (chromeDevtoolsToolMode(pi) === "codemode") ownership.owned.clear();
|
|
110
|
+
const published = new Set(names);
|
|
111
|
+
ownership.published = new Set(CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => published.has(name)));
|
|
112
|
+
ownedBySession.set(owner, ownership);
|
|
113
|
+
persistOwnership(pi, ownership);
|
|
114
|
+
}
|
|
115
|
+
function ownershipData(ownership) {
|
|
116
|
+
return {
|
|
117
|
+
version: 1,
|
|
118
|
+
explicit: CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => ownership.explicit.has(name)),
|
|
119
|
+
owned: CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => ownership.owned.has(name)),
|
|
120
|
+
available: ownership.available ? CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => ownership.available?.has(name)) : void 0,
|
|
121
|
+
mode: ownership.mode,
|
|
122
|
+
published: ownership.published ? CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => ownership.published?.has(name)) : void 0
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
var ActivationProvenanceError = class extends Error {
|
|
126
|
+
constructor(cause) {
|
|
127
|
+
super(cause instanceof Error ? cause.message : String(cause), { cause });
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
function formatProvenanceWarning(error) {
|
|
131
|
+
return sanitizeChromeDevtoolsDisplay(
|
|
132
|
+
`Activation ownership could not be saved: ${error.message}. Activation is not rolled back; durable ownership may be incomplete until a later loader call or lifecycle update retries successfully.`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
function publishLifecycleTools(pi, names, before) {
|
|
136
|
+
try {
|
|
137
|
+
publishActiveTools(pi, names, before);
|
|
138
|
+
} catch (error) {
|
|
139
|
+
if (!(error instanceof ActivationProvenanceError)) throw error;
|
|
140
|
+
return formatProvenanceWarning(error);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function persistOwnership(pi, ownership) {
|
|
144
|
+
ownership.available = new Set(configuredChromeDevtoolsTools(pi));
|
|
145
|
+
ownership.mode = chromeDevtoolsToolMode(pi);
|
|
146
|
+
const data = ownershipData(ownership);
|
|
147
|
+
const serialized = JSON.stringify(data);
|
|
148
|
+
if (ownership.serialized === serialized) return;
|
|
149
|
+
try {
|
|
150
|
+
pi.appendEntry(PROVENANCE_ENTRY, data);
|
|
151
|
+
ownership.serialized = serialized;
|
|
152
|
+
} catch (error) {
|
|
153
|
+
ownership.serialized = void 0;
|
|
154
|
+
throw new ActivationProvenanceError(error);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function restoredOwnership(entries) {
|
|
158
|
+
for (let index = entries.length - 1; index >= 0; index--) {
|
|
159
|
+
const entry = entries[index];
|
|
160
|
+
if (entry.type !== "custom" || entry.customType !== PROVENANCE_ENTRY) continue;
|
|
161
|
+
const data = entry.data;
|
|
162
|
+
if (typeof data !== "object" || data === null || Array.isArray(data)) return void 0;
|
|
163
|
+
const record = data;
|
|
164
|
+
const validNames = (value) => Array.isArray(value) && value.length <= CHROME_DEVTOOLS_TOOL_NAMES.length && value.every((name) => CHROME_DEVTOOLS_TOOL_NAMES.includes(name));
|
|
165
|
+
if (record.version !== 1 || !validNames(record.explicit) || !validNames(record.owned) || record.available !== void 0 && !validNames(record.available) || record.published !== void 0 && !validNames(record.published) || record.mode !== void 0 && record.mode !== "codemode" && record.mode !== "lazy" && record.mode !== "direct" || record.owned.some((name) => record.explicit.includes(name)))
|
|
166
|
+
return void 0;
|
|
167
|
+
const restored = {
|
|
168
|
+
explicit: new Set(record.explicit),
|
|
169
|
+
owned: new Set(record.owned),
|
|
170
|
+
available: validNames(record.available) ? new Set(record.available) : void 0,
|
|
171
|
+
mode: record.mode,
|
|
172
|
+
published: validNames(record.published) ? new Set(record.published) : void 0
|
|
173
|
+
};
|
|
174
|
+
return { ...restored, serialized: JSON.stringify(ownershipData(restored)) };
|
|
175
|
+
}
|
|
176
|
+
return void 0;
|
|
177
|
+
}
|
|
178
|
+
var definitionsByApi = /* @__PURE__ */ new WeakMap();
|
|
179
|
+
function registerChromeDevtoolsCapabilities(pi, tools) {
|
|
180
|
+
definitionsByApi.set(pi, tools);
|
|
181
|
+
for (const tool of tools) pi.registerTool({ ...tool, exposure: "codemode", defaultActive: false });
|
|
182
|
+
pi.registerTool({
|
|
183
|
+
...createChromeDevtoolsLoadTool(pi),
|
|
184
|
+
exposure: "codemode",
|
|
185
|
+
defaultActive: false,
|
|
186
|
+
promptSnippet: void 0,
|
|
187
|
+
promptGuidelines: void 0
|
|
188
|
+
});
|
|
189
|
+
loaderRegistered.add(pi);
|
|
190
|
+
}
|
|
191
|
+
function chromeDevtoolsToolMode(pi) {
|
|
192
|
+
return modeByApi.get(pi) ?? "codemode";
|
|
193
|
+
}
|
|
194
|
+
function refreshExposure(pi) {
|
|
195
|
+
const available = effectiveAvailableTools(pi);
|
|
196
|
+
const mode = chromeDevtoolsToolMode(pi);
|
|
197
|
+
for (const tool of definitionsByApi.get(pi) ?? []) {
|
|
198
|
+
pi.registerTool({
|
|
199
|
+
...tool,
|
|
200
|
+
defaultActive: false,
|
|
201
|
+
exposure: available.has(tool.name) ? mode === "codemode" ? "codemode" : "direct" : "hidden"
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
if (mode === "lazy") {
|
|
205
|
+
pi.registerTool({ ...createChromeDevtoolsLoadTool(pi), defaultActive: false });
|
|
206
|
+
loaderRegistered.add(pi);
|
|
207
|
+
} else if (loaderRegistered.has(pi)) {
|
|
208
|
+
pi.registerTool({
|
|
209
|
+
...createChromeDevtoolsLoadTool(pi),
|
|
210
|
+
exposure: "hidden",
|
|
211
|
+
promptSnippet: void 0,
|
|
212
|
+
promptGuidelines: void 0
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
36
216
|
var SEARCH_TEXT = {
|
|
37
217
|
chrome_devtools_list_pages: "list open inspectable chrome browser pages tabs targets",
|
|
38
218
|
chrome_devtools_select_page: "select choose active chrome browser page tab target",
|
|
@@ -42,44 +222,87 @@ var SEARCH_TEXT = {
|
|
|
42
222
|
chrome_devtools_webmcp_list_tools: "list discover page provided website webmcp tools capabilities experimental",
|
|
43
223
|
chrome_devtools_webmcp_call_tool: "call invoke page provided website webmcp tool confirmation experimental"
|
|
44
224
|
};
|
|
45
|
-
function setChromeDevtoolsSessionOwner(pi, owner) {
|
|
225
|
+
function setChromeDevtoolsSessionOwner(pi, owner, entries) {
|
|
46
226
|
sessionOwnerByApi.set(pi, owner);
|
|
227
|
+
if (entries) {
|
|
228
|
+
const ownership2 = restoredOwnership(entries);
|
|
229
|
+
if (ownership2) {
|
|
230
|
+
const pending = ownedBySession.get(owner);
|
|
231
|
+
if (pending && pending.serialized === void 0 && ownership2.serialized === JSON.stringify(ownershipData(pending)))
|
|
232
|
+
ownership2.serialized = void 0;
|
|
233
|
+
ownedBySession.set(owner, ownership2);
|
|
234
|
+
} else {
|
|
235
|
+
ownedBySession.delete(owner);
|
|
236
|
+
availableToolsByApi.delete(pi);
|
|
237
|
+
modeByApi.delete(pi);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const ownership = ownedBySession.get(owner);
|
|
241
|
+
if (ownership?.available) setAvailableTools(pi, [...ownership.available]);
|
|
242
|
+
if (ownership?.mode) modeByApi.set(pi, ownership.mode);
|
|
47
243
|
}
|
|
48
244
|
function initializeAvailableChromeDevtoolsTools(pi) {
|
|
49
245
|
if (availableToolsByApi.has(pi)) return;
|
|
50
|
-
|
|
51
|
-
setAvailableTools(
|
|
52
|
-
pi,
|
|
53
|
-
CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => activeTools.has(name))
|
|
54
|
-
);
|
|
246
|
+
setAvailableTools(pi, CHROME_DEVTOOLS_TOOL_NAMES);
|
|
55
247
|
}
|
|
56
|
-
function configureChromeDevtoolsToolExposure(pi, availableTools, model) {
|
|
248
|
+
function configureChromeDevtoolsToolExposure(pi, availableTools, model, mode = "codemode") {
|
|
249
|
+
modeByApi.set(pi, mode);
|
|
57
250
|
setAvailableTools(pi, availableTools);
|
|
58
251
|
const available = effectiveAvailableTools(pi);
|
|
59
|
-
const lazyExposure = supportsNativeDeferredToolLoading(model);
|
|
252
|
+
const lazyExposure = mode === "lazy" && supportsNativeDeferredToolLoading(model);
|
|
60
253
|
lazyExposureByApi.set(pi, lazyExposure);
|
|
61
|
-
const
|
|
254
|
+
const before = pi.getActiveTools();
|
|
255
|
+
const owner = sessionOwnerByApi.get(pi);
|
|
256
|
+
let ownership = owner ? ownedBySession.get(owner) : void 0;
|
|
257
|
+
if (owner && !ownership && before.includes(CHROME_DEVTOOLS_LOAD_TOOL_NAME)) {
|
|
258
|
+
ownership = {
|
|
259
|
+
explicit: /* @__PURE__ */ new Set(),
|
|
260
|
+
owned: new Set(before.filter((name) => CHROME_DEVTOOLS_TOOL_NAMES.includes(name)))
|
|
261
|
+
};
|
|
262
|
+
ownedBySession.set(owner, ownership);
|
|
263
|
+
}
|
|
264
|
+
const owned = ownership?.owned;
|
|
265
|
+
const exposedTools = mode === "codemode" ? unique([...before.filter((name) => !owned?.has(name)), ...retainedExplicitTools(pi, before)]).filter(
|
|
266
|
+
(name) => available.has(name)
|
|
267
|
+
) : lazyExposure ? [] : CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => available.has(name));
|
|
62
268
|
const nonCapabilityTools = pi.getActiveTools().filter((name) => !CHROME_DEVTOOLS_TOOL_NAMES.includes(name));
|
|
63
|
-
pi
|
|
269
|
+
refreshExposure(pi);
|
|
270
|
+
const target = /* @__PURE__ */ new Set([
|
|
271
|
+
...nonCapabilityTools.filter((name) => name !== CHROME_DEVTOOLS_LOAD_TOOL_NAME),
|
|
272
|
+
...mode === "lazy" ? [CHROME_DEVTOOLS_LOAD_TOOL_NAME] : [],
|
|
273
|
+
...exposedTools
|
|
274
|
+
]);
|
|
275
|
+
return publishLifecycleTools(pi, unique([...before.filter((name) => target.has(name)), ...target]), before);
|
|
64
276
|
}
|
|
65
277
|
function requireEagerChromeDevtoolsToolExposure(pi) {
|
|
278
|
+
if (chromeDevtoolsToolMode(pi) !== "lazy") return;
|
|
66
279
|
lazyExposureByApi.set(pi, false);
|
|
67
280
|
const active = pi.getActiveTools();
|
|
68
281
|
const available = availableChromeDevtoolsTools(pi);
|
|
69
|
-
pi
|
|
282
|
+
return publishLifecycleTools(pi, unique([...active, CHROME_DEVTOOLS_LOAD_TOOL_NAME, ...available]), active);
|
|
70
283
|
}
|
|
71
|
-
function applyAvailableChromeDevtoolsTools(pi, availableTools) {
|
|
284
|
+
function applyAvailableChromeDevtoolsTools(pi, availableTools, restoredActiveTools) {
|
|
72
285
|
setAvailableTools(pi, availableTools);
|
|
73
286
|
const available = effectiveAvailableTools(pi);
|
|
74
287
|
const lazyExposure = lazyExposureByApi.get(pi) === true;
|
|
75
|
-
const
|
|
288
|
+
const before = restoredActiveTools ? restoreCapabilityPositions(pi.getActiveTools(), restoredActiveTools, available) : pi.getActiveTools();
|
|
289
|
+
const active = before.filter(
|
|
76
290
|
(name) => !CHROME_DEVTOOLS_TOOL_NAMES.includes(name) || lazyExposure && available.has(name)
|
|
77
291
|
);
|
|
78
|
-
const
|
|
79
|
-
|
|
292
|
+
const mode = chromeDevtoolsToolMode(pi);
|
|
293
|
+
const eagerTools = mode === "codemode" ? unique([...before, ...retainedExplicitTools(pi, before)]).filter(
|
|
294
|
+
(name) => available.has(name)
|
|
295
|
+
) : lazyExposure ? [] : CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => available.has(name));
|
|
296
|
+
refreshExposure(pi);
|
|
297
|
+
const target = /* @__PURE__ */ new Set([
|
|
298
|
+
...active.filter((name) => name !== CHROME_DEVTOOLS_LOAD_TOOL_NAME),
|
|
299
|
+
...mode === "lazy" ? [CHROME_DEVTOOLS_LOAD_TOOL_NAME] : [],
|
|
300
|
+
...eagerTools
|
|
301
|
+
]);
|
|
302
|
+
publishActiveTools(pi, unique([...before.filter((name) => target.has(name)), ...target]), before);
|
|
80
303
|
}
|
|
81
304
|
function chromeDevtoolsToolExposureMode(pi) {
|
|
82
|
-
return lazyExposureByApi.get(pi) === true ? "native deferred" : "eager";
|
|
305
|
+
return chromeDevtoolsToolMode(pi) === "codemode" ? "codemode" : lazyExposureByApi.get(pi) === true ? "native deferred" : "eager";
|
|
83
306
|
}
|
|
84
307
|
function supportsNativeDeferredToolLoading(model) {
|
|
85
308
|
if (!model) return false;
|
|
@@ -106,6 +329,11 @@ function availableChromeDevtoolsTools(pi) {
|
|
|
106
329
|
const available = effectiveAvailableTools(pi);
|
|
107
330
|
return CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => available.has(name));
|
|
108
331
|
}
|
|
332
|
+
function previousChromeDevtoolsTools(pi) {
|
|
333
|
+
if (availableToolsByApi.has(pi)) return configuredChromeDevtoolsTools(pi);
|
|
334
|
+
const active = new Set(pi.getActiveTools());
|
|
335
|
+
return CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => active.has(name));
|
|
336
|
+
}
|
|
109
337
|
function configuredChromeDevtoolsTools(pi) {
|
|
110
338
|
const available = availableToolsByApi.get(pi) ?? /* @__PURE__ */ new Set();
|
|
111
339
|
return CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => available.has(name));
|
|
@@ -140,13 +368,23 @@ function createChromeDevtoolsLoadTool(pi) {
|
|
|
140
368
|
const active = pi.getActiveTools();
|
|
141
369
|
const activeSet = new Set(active);
|
|
142
370
|
const added = matches.filter((name) => !activeSet.has(name));
|
|
143
|
-
|
|
144
|
-
|
|
371
|
+
let provenanceWarning;
|
|
372
|
+
try {
|
|
373
|
+
if (added.length > 0) {
|
|
374
|
+
publishActiveTools(pi, unique([...active, ...added]), active);
|
|
375
|
+
} else {
|
|
376
|
+
const ownership = ownedBySession.get(ctx.sessionManager);
|
|
377
|
+
if (ownership && ownership.serialized === void 0) recordOwnership(pi, active);
|
|
378
|
+
}
|
|
379
|
+
} catch (error) {
|
|
380
|
+
if (!(error instanceof ActivationProvenanceError)) throw error;
|
|
381
|
+
provenanceWarning = formatProvenanceWarning(error);
|
|
145
382
|
}
|
|
146
383
|
const text = matches.length === 0 ? "No available Chrome DevTools tools matched the query." : added.length > 0 ? `Loaded Chrome DevTools tools: ${added.join(", ")}` : `Matching Chrome DevTools tools are already loaded: ${matches.join(", ")}`;
|
|
147
384
|
return {
|
|
148
|
-
content: [{ type: "text", text }
|
|
149
|
-
|
|
385
|
+
content: [{ type: "text", text: provenanceWarning ? `${text}
|
|
386
|
+
Warning: ${provenanceWarning}` : text }],
|
|
387
|
+
details: { matches, added, ...provenanceWarning ? { provenanceWarning } : {} }
|
|
150
388
|
};
|
|
151
389
|
}
|
|
152
390
|
});
|
|
@@ -183,44 +421,21 @@ function compatString(value, key) {
|
|
|
183
421
|
const record = value;
|
|
184
422
|
return typeof record[key] === "string" ? record[key] : void 0;
|
|
185
423
|
}
|
|
424
|
+
function restoreCapabilityPositions(current, previous, available) {
|
|
425
|
+
const restored = [...current];
|
|
426
|
+
for (const [index, name] of previous.entries()) {
|
|
427
|
+
if (!available.has(name) || restored.includes(name)) continue;
|
|
428
|
+
const following = previous.slice(index + 1).find((candidate) => restored.includes(candidate));
|
|
429
|
+
const insertion = following === void 0 ? restored.length : restored.indexOf(following);
|
|
430
|
+
restored.splice(insertion, 0, name);
|
|
431
|
+
}
|
|
432
|
+
return restored;
|
|
433
|
+
}
|
|
186
434
|
function unique(values) {
|
|
187
435
|
return [...new Set(values)];
|
|
188
436
|
}
|
|
189
437
|
|
|
190
|
-
// src/display.ts
|
|
191
|
-
var MAX_SANITIZER_INPUT_CODE_UNITS = 5e4;
|
|
192
|
-
var graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
193
|
-
function sanitizeChromeDevtoolsDisplay(value, maxCharacters = 5e4) {
|
|
194
|
-
const inputWasTruncated = value.length > MAX_SANITIZER_INPUT_CODE_UNITS;
|
|
195
|
-
const boundedInput = inputWasTruncated ? truncateAtGraphemeBoundary(value, MAX_SANITIZER_INPUT_CODE_UNITS) : value;
|
|
196
|
-
const normalizedLineEndings = boundedInput.replace(/\r\n/g, "\n");
|
|
197
|
-
const sanitized = Array.from(normalizedLineEndings, (character) => {
|
|
198
|
-
const codePoint = character.codePointAt(0) ?? 0;
|
|
199
|
-
const unsafeControl = codePoint >= 0 && codePoint <= 8 || codePoint >= 11 && codePoint <= 31 || codePoint >= 127 && codePoint <= 159;
|
|
200
|
-
const unsafeBidi = codePoint >= 8234 && codePoint <= 8238 || codePoint >= 8294 && codePoint <= 8297;
|
|
201
|
-
const loneSurrogate = character.length === 1 && codePoint >= 55296 && codePoint <= 57343;
|
|
202
|
-
return unsafeControl || unsafeBidi || loneSurrogate ? "\uFFFD" : character;
|
|
203
|
-
}).join("");
|
|
204
|
-
const outputLimit = Math.min(maxCharacters, MAX_SANITIZER_INPUT_CODE_UNITS);
|
|
205
|
-
if (!inputWasTruncated && sanitized.length <= outputLimit) return sanitized;
|
|
206
|
-
return `${truncateAtGraphemeBoundary(sanitized, Math.max(0, outputLimit - 1))}\u2026`;
|
|
207
|
-
}
|
|
208
|
-
function truncateAtGraphemeBoundary(value, maxCodeUnits) {
|
|
209
|
-
if (value.length <= maxCodeUnits) return value;
|
|
210
|
-
const boundedLookahead = value.slice(0, Math.max(0, maxCodeUnits) + 2);
|
|
211
|
-
let safeEnd = 0;
|
|
212
|
-
for (const { index, segment } of graphemeSegmenter.segment(boundedLookahead)) {
|
|
213
|
-
const segmentEnd = index + segment.length;
|
|
214
|
-
if (segmentEnd > maxCodeUnits) break;
|
|
215
|
-
safeEnd = segmentEnd;
|
|
216
|
-
}
|
|
217
|
-
return value.slice(0, safeEnd);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
438
|
// src/tool-selector.ts
|
|
221
|
-
function unique2(values) {
|
|
222
|
-
return Array.from(new Set(values));
|
|
223
|
-
}
|
|
224
439
|
function formatError(error) {
|
|
225
440
|
return error instanceof Error ? error.message : String(error);
|
|
226
441
|
}
|
|
@@ -242,8 +457,10 @@ async function waitForChromeDevtoolsSettings() {
|
|
|
242
457
|
await toolTransactionQueue;
|
|
243
458
|
}
|
|
244
459
|
function transactSelectedTools(pi, ctx, selectedTools, expectedGeneration, expectedActiveTools) {
|
|
460
|
+
const acceptedTools = [...selectedTools];
|
|
461
|
+
const expectedTools = expectedActiveTools ? [...expectedActiveTools] : void 0;
|
|
245
462
|
const operation = toolTransactionQueue.then(
|
|
246
|
-
() => transactSelectedToolsNow(pi, ctx,
|
|
463
|
+
() => transactSelectedToolsNow(pi, ctx, acceptedTools, expectedGeneration, expectedTools)
|
|
247
464
|
);
|
|
248
465
|
toolTransactionQueue = operation.then(
|
|
249
466
|
() => void 0,
|
|
@@ -252,7 +469,25 @@ function transactSelectedTools(pi, ctx, selectedTools, expectedGeneration, expec
|
|
|
252
469
|
return operation;
|
|
253
470
|
}
|
|
254
471
|
async function transactSelectedToolsNow(pi, ctx, selectedTools, expectedGeneration, expectedActiveTools) {
|
|
255
|
-
if (expectedGeneration !== state.sessionGeneration)
|
|
472
|
+
if (expectedGeneration !== state.sessionGeneration) {
|
|
473
|
+
try {
|
|
474
|
+
if (expectedActiveTools) {
|
|
475
|
+
const settings = await loadSettings();
|
|
476
|
+
if (settings.userFile.kind !== "invalid") {
|
|
477
|
+
const catalog = new Set(
|
|
478
|
+
settings.kind === "loaded" && settings.settings.tools ? settings.settings.tools : CHROME_DEVTOOLS_TOOL_NAMES
|
|
479
|
+
);
|
|
480
|
+
const current = CHROME_DEVTOOLS_TOOL_NAMES.filter(
|
|
481
|
+
(name) => catalog.has(name) && (settings.effectiveWebMcpEnabled || !isWebMcpToolName(name))
|
|
482
|
+
);
|
|
483
|
+
if (!arraysEqual(current, expectedActiveTools)) return "active-tools-changed";
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
await persistSettings(selectedTools);
|
|
487
|
+
} catch {
|
|
488
|
+
}
|
|
489
|
+
return "failed";
|
|
490
|
+
}
|
|
256
491
|
if (expectedActiveTools && !arraysEqual(availableChromeDevtoolsTools(pi), expectedActiveTools)) {
|
|
257
492
|
ctx.ui.notify(
|
|
258
493
|
"Browser tool selection changed while review was open. Review the current state, then apply again.",
|
|
@@ -260,34 +495,38 @@ async function transactSelectedToolsNow(pi, ctx, selectedTools, expectedGenerati
|
|
|
260
495
|
);
|
|
261
496
|
return "active-tools-changed";
|
|
262
497
|
}
|
|
263
|
-
const previousActiveTools = pi.getActiveTools();
|
|
264
|
-
const previousAvailableTools = availableChromeDevtoolsTools(pi);
|
|
265
498
|
try {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
499
|
+
await persistSettings(selectedTools, () => {
|
|
500
|
+
if (expectedGeneration !== state.sessionGeneration) return;
|
|
501
|
+
const previousActiveTools = pi.getActiveTools();
|
|
502
|
+
const previousAvailableTools = availableChromeDevtoolsTools(pi);
|
|
503
|
+
const previousConfiguredTools = configuredChromeDevtoolsTools(pi);
|
|
504
|
+
try {
|
|
505
|
+
const previousWebMcpTools = previousAvailableTools.filter(isWebMcpToolName);
|
|
506
|
+
applyChromeDevtoolsTools(pi, selectedTools);
|
|
507
|
+
const publishedWebMcpTools = availableChromeDevtoolsTools(pi).filter(isWebMcpToolName);
|
|
508
|
+
if (!arraysEqual(previousWebMcpTools, publishedWebMcpTools)) {
|
|
509
|
+
invalidateWebMcpOperations(ctx.sessionManager, "Chrome DevTools WebMCP gateway availability changed");
|
|
510
|
+
}
|
|
511
|
+
} catch (error) {
|
|
512
|
+
if (expectedGeneration === state.sessionGeneration) {
|
|
513
|
+
try {
|
|
514
|
+
applyAvailableChromeDevtoolsTools(pi, previousConfiguredTools, previousActiveTools);
|
|
515
|
+
} catch (rollbackError) {
|
|
516
|
+
throw new Error(`${formatError(error)}; active-tool rollback failed: ${formatError(rollbackError)}`, {
|
|
517
|
+
cause: error
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
throw error;
|
|
522
|
+
}
|
|
523
|
+
});
|
|
273
524
|
return expectedGeneration === state.sessionGeneration ? "saved" : "failed";
|
|
274
525
|
} catch (error) {
|
|
275
|
-
let rollbackError;
|
|
276
|
-
try {
|
|
277
|
-
applyAvailableChromeDevtoolsTools(pi, previousAvailableTools);
|
|
278
|
-
const currentNonChromeTools = pi.getActiveTools().filter((name) => !CHROME_DEVTOOLS_TOOL_NAMES.includes(name));
|
|
279
|
-
const previousLoadedChromeTools = previousActiveTools.filter(
|
|
280
|
-
(name) => CHROME_DEVTOOLS_TOOL_NAMES.includes(name)
|
|
281
|
-
);
|
|
282
|
-
const restoredChromeTools = chromeDevtoolsToolExposureMode(pi) === "eager" ? previousAvailableTools : previousLoadedChromeTools;
|
|
283
|
-
pi.setActiveTools(unique2([...currentNonChromeTools, ...restoredChromeTools]));
|
|
284
|
-
} catch (caught) {
|
|
285
|
-
rollbackError = caught;
|
|
286
|
-
}
|
|
287
526
|
if (expectedGeneration !== state.sessionGeneration) return "failed";
|
|
288
527
|
ctx.ui.notify(
|
|
289
528
|
sanitizeChromeDevtoolsDisplay(
|
|
290
|
-
|
|
529
|
+
error instanceof ToolCatalogApplicationError ? `Chrome DevTools tool application failed: ${formatError(error)}` : `Chrome DevTools settings save failed; active tools unchanged: ${formatError(error)}`
|
|
291
530
|
),
|
|
292
531
|
"warning"
|
|
293
532
|
);
|
|
@@ -319,12 +558,21 @@ function getToolStatusSummary(pi, owner) {
|
|
|
319
558
|
};
|
|
320
559
|
}
|
|
321
560
|
async function buildToolStatusMessage(pi, owner) {
|
|
561
|
+
const generation = state.sessionGeneration;
|
|
562
|
+
await waitForChromeDevtoolsSettings();
|
|
563
|
+
if (generation !== state.sessionGeneration) return "";
|
|
564
|
+
const settings = await loadSettings();
|
|
565
|
+
if (generation !== state.sessionGeneration) return "";
|
|
322
566
|
const summary = getToolStatusSummary(pi, owner);
|
|
323
|
-
const persistedSetting =
|
|
567
|
+
const persistedSetting = persistedSettingLabel(settings);
|
|
568
|
+
const savedMode = settings.userFile.kind === "invalid" ? void 0 : settings.kind === "loaded" ? settings.settings.toolMode : "codemode";
|
|
324
569
|
return sanitizeChromeDevtoolsDisplay(
|
|
325
570
|
[
|
|
326
571
|
`Chrome DevTools tools available: ${formatRuntimeStatus(summary)}`,
|
|
572
|
+
`Running tool mode: ${chromeDevtoolsToolMode(pi)}`,
|
|
327
573
|
`Tool exposure: ${chromeDevtoolsToolExposureMode(pi)}`,
|
|
574
|
+
`Saved tool mode: ${savedMode ?? "unavailable (invalid user settings)"}`,
|
|
575
|
+
...savedMode !== void 0 && savedMode !== chromeDevtoolsToolMode(pi) ? ["Tool mode change pending; /reload or session replacement required."] : [],
|
|
328
576
|
`Loaded capability tools this session: ${summary.loadedChromeToolCount}/${summary.capabilityCount}`,
|
|
329
577
|
`WebMCP: ${webMcpEnabled(owner) ? "enabled \xB7 experimental \xB7 confirmation required for every call" : "disabled \xB7 experimental"}`,
|
|
330
578
|
`Loader: ${pi.getActiveTools().includes(CHROME_DEVTOOLS_LOAD_TOOL_NAME) ? "active" : "inactive"}`,
|
|
@@ -417,15 +665,14 @@ function allChromeDevtoolsTools(owner) {
|
|
|
417
665
|
function formatRuntimeStatus(summary) {
|
|
418
666
|
return `${summary.availabilityStatus} (${summary.availableChromeToolCount}/${summary.capabilityCount} available)`;
|
|
419
667
|
}
|
|
420
|
-
|
|
421
|
-
const settings = await loadSettings();
|
|
668
|
+
function persistedSettingLabel(settings) {
|
|
422
669
|
if (settings.kind === "loaded" && settings.settings.tools) {
|
|
423
670
|
return formatPersistedSelection(settings.settings.tools);
|
|
424
671
|
}
|
|
425
672
|
if (settings.kind === "invalid") {
|
|
426
673
|
return `none; current active-tool policy preserved (invalid settings ignored: ${settings.reason})`;
|
|
427
674
|
}
|
|
428
|
-
return "none;
|
|
675
|
+
return "none; default catalog restored on /reload or session replacement";
|
|
429
676
|
}
|
|
430
677
|
function formatPersistedSelection(tools) {
|
|
431
678
|
if (tools.length === CHROME_DEVTOOLS_TOOL_NAMES.length) {
|
|
@@ -437,11 +684,14 @@ function formatPersistedSelection(tools) {
|
|
|
437
684
|
function effectiveCatalog(owner) {
|
|
438
685
|
return webMcpEnabled(owner) ? [...CHROME_DEVTOOLS_TOOL_NAMES] : [...CORE_CHROME_DEVTOOLS_TOOL_NAMES];
|
|
439
686
|
}
|
|
440
|
-
async function persistSettings(selectedTools) {
|
|
441
|
-
await saveSettings({ tools: [...selectedTools], updatedAt: Date.now() });
|
|
687
|
+
async function persistSettings(selectedTools, applyAfterSave) {
|
|
688
|
+
await saveSettings({ tools: [...selectedTools], updatedAt: Date.now() }, {}, applyAfterSave);
|
|
442
689
|
}
|
|
443
690
|
|
|
444
691
|
export {
|
|
692
|
+
sanitizeChromeDevtoolsDisplay,
|
|
693
|
+
registerChromeDevtoolsCapabilities,
|
|
694
|
+
chromeDevtoolsToolMode,
|
|
445
695
|
setChromeDevtoolsSessionOwner,
|
|
446
696
|
initializeAvailableChromeDevtoolsTools,
|
|
447
697
|
configureChromeDevtoolsToolExposure,
|
|
@@ -449,9 +699,8 @@ export {
|
|
|
449
699
|
applyAvailableChromeDevtoolsTools,
|
|
450
700
|
supportsNativeDeferredToolLoading,
|
|
451
701
|
availableChromeDevtoolsTools,
|
|
702
|
+
previousChromeDevtoolsTools,
|
|
452
703
|
configuredChromeDevtoolsTools,
|
|
453
|
-
createChromeDevtoolsLoadTool,
|
|
454
|
-
sanitizeChromeDevtoolsDisplay,
|
|
455
704
|
updateChromeDevtoolsTools,
|
|
456
705
|
setSelectedChromeDevtoolsTools,
|
|
457
706
|
waitForChromeDevtoolsSettings,
|
|
@@ -461,4 +710,4 @@ export {
|
|
|
461
710
|
buildCommandGuide,
|
|
462
711
|
allChromeDevtoolsTools
|
|
463
712
|
};
|
|
464
|
-
//# sourceMappingURL=chunk-
|
|
713
|
+
//# sourceMappingURL=chunk-WOFI2A72.ts.map
|