@narumitw/pi-chrome-devtools 0.53.4 → 0.54.1
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/CHANGELOG.md +109 -0
- package/README.md +34 -16
- package/dist/chunks/{browser-settings-menu-FVMCCUPM.ts → browser-settings-menu-7M3VM7QN.ts} +25 -3
- package/dist/chunks/browser-settings-menu-7M3VM7QN.ts.map +7 -0
- package/dist/chunks/{chunk-V7N3WI5B.ts → chunk-JKPJYUVG.ts} +340 -108
- package/dist/chunks/chunk-JKPJYUVG.ts.map +7 -0
- package/dist/chunks/{chunk-4B3EQHOH.ts → chunk-JLEJ6WFO.ts} +2 -2
- package/dist/chunks/{chunk-LSJSDY2M.ts → chunk-WTMZID3G.ts} +382 -246
- package/dist/chunks/chunk-WTMZID3G.ts.map +7 -0
- package/dist/chunks/{menu-MTPSLDHZ.ts → menu-HGG26E3X.ts} +7 -7
- package/dist/chunks/{menu-MTPSLDHZ.ts.map → menu-HGG26E3X.ts.map} +1 -1
- package/dist/chunks/{tools-OVNH45IJ.ts → tools-O5N4KIAK.ts} +3 -3
- package/dist/index.ts +45 -21
- package/dist/index.ts.map +2 -2
- package/docs/browser-setup.md +7 -1
- package/package.json +6 -5
- package/src/browser-candidates.ts +184 -0
- package/src/browser-manager.ts +93 -276
- package/src/browser-settings-menu.ts +23 -0
- package/src/browser-startup.ts +122 -0
- package/src/chrome-devtools.ts +48 -15
- package/src/lazy-tools.ts +358 -48
- package/src/menu.ts +3 -3
- package/src/runtime.ts +2 -2
- package/src/settings.ts +65 -1
- package/src/tool-selector.ts +95 -40
- package/dist/chunks/browser-settings-menu-FVMCCUPM.ts.map +0 -7
- package/dist/chunks/chunk-LSJSDY2M.ts.map +0 -7
- package/dist/chunks/chunk-V7N3WI5B.ts.map +0 -7
- /package/dist/chunks/{chunk-4B3EQHOH.ts.map → chunk-JLEJ6WFO.ts.map} +0 -0
- /package/dist/chunks/{tools-OVNH45IJ.ts.map → tools-O5N4KIAK.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-WTMZID3G.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,62 +222,93 @@ 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
|
-
if (!model) return false;
|
|
86
|
-
if (model.api === "anthropic-messages")
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (configured !== void 0) return configured;
|
|
90
|
-
if (model.provider !== "anthropic" || model.id.includes("haiku")) return false;
|
|
91
|
-
const version = model.id.match(/^claude-(?:opus|sonnet|fable)-(\d+)(?:-(\d+))?(?:-|$)/);
|
|
92
|
-
if (!version) return false;
|
|
93
|
-
const major = Number(version[1]);
|
|
94
|
-
const minor = version[2] && version[2].length < 8 ? Number(version[2]) : 0;
|
|
95
|
-
return major > 4 || major === 4 && minor >= 5;
|
|
96
|
-
}
|
|
97
|
-
if (model.api === "openai-completions") {
|
|
98
|
-
return compatString(model.compat, "deferredToolsMode") === "kimi";
|
|
99
|
-
}
|
|
100
|
-
if (model.api === "openai-responses" || model.api === "openai-codex-responses") {
|
|
308
|
+
if (!model || compatBoolean(model.compat, "supportsMidConvoSystemMessages") !== true) return false;
|
|
309
|
+
if (model.api === "anthropic-messages") return compatBoolean(model.compat, "supportsMidConvoToolChanges") === true;
|
|
310
|
+
if (model.api === "openai-completions") return compatBoolean(model.compat, "supportsMidConvoToolAdditions") === true;
|
|
311
|
+
if (model.api === "openai-responses" || model.api === "openai-codex-responses" || model.api === "azure-openai-responses") {
|
|
101
312
|
return compatBoolean(model.compat, "supportsAdditionalTools") === true || compatBoolean(model.compat, "supportsToolSearch") === true;
|
|
102
313
|
}
|
|
103
314
|
return false;
|
|
@@ -106,6 +317,11 @@ function availableChromeDevtoolsTools(pi) {
|
|
|
106
317
|
const available = effectiveAvailableTools(pi);
|
|
107
318
|
return CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => available.has(name));
|
|
108
319
|
}
|
|
320
|
+
function previousChromeDevtoolsTools(pi) {
|
|
321
|
+
if (availableToolsByApi.has(pi)) return configuredChromeDevtoolsTools(pi);
|
|
322
|
+
const active = new Set(pi.getActiveTools());
|
|
323
|
+
return CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => active.has(name));
|
|
324
|
+
}
|
|
109
325
|
function configuredChromeDevtoolsTools(pi) {
|
|
110
326
|
const available = availableToolsByApi.get(pi) ?? /* @__PURE__ */ new Set();
|
|
111
327
|
return CHROME_DEVTOOLS_TOOL_NAMES.filter((name) => available.has(name));
|
|
@@ -140,13 +356,23 @@ function createChromeDevtoolsLoadTool(pi) {
|
|
|
140
356
|
const active = pi.getActiveTools();
|
|
141
357
|
const activeSet = new Set(active);
|
|
142
358
|
const added = matches.filter((name) => !activeSet.has(name));
|
|
143
|
-
|
|
144
|
-
|
|
359
|
+
let provenanceWarning;
|
|
360
|
+
try {
|
|
361
|
+
if (added.length > 0) {
|
|
362
|
+
publishActiveTools(pi, unique([...active, ...added]), active);
|
|
363
|
+
} else {
|
|
364
|
+
const ownership = ownedBySession.get(ctx.sessionManager);
|
|
365
|
+
if (ownership && ownership.serialized === void 0) recordOwnership(pi, active);
|
|
366
|
+
}
|
|
367
|
+
} catch (error) {
|
|
368
|
+
if (!(error instanceof ActivationProvenanceError)) throw error;
|
|
369
|
+
provenanceWarning = formatProvenanceWarning(error);
|
|
145
370
|
}
|
|
146
371
|
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
372
|
return {
|
|
148
|
-
content: [{ type: "text", text }
|
|
149
|
-
|
|
373
|
+
content: [{ type: "text", text: provenanceWarning ? `${text}
|
|
374
|
+
Warning: ${provenanceWarning}` : text }],
|
|
375
|
+
details: { matches, added, ...provenanceWarning ? { provenanceWarning } : {} }
|
|
150
376
|
};
|
|
151
377
|
}
|
|
152
378
|
});
|
|
@@ -178,49 +404,21 @@ function compatBoolean(value, key) {
|
|
|
178
404
|
const record = value;
|
|
179
405
|
return typeof record[key] === "boolean" ? record[key] : void 0;
|
|
180
406
|
}
|
|
181
|
-
function
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
|
|
407
|
+
function restoreCapabilityPositions(current, previous, available) {
|
|
408
|
+
const restored = [...current];
|
|
409
|
+
for (const [index, name] of previous.entries()) {
|
|
410
|
+
if (!available.has(name) || restored.includes(name)) continue;
|
|
411
|
+
const following = previous.slice(index + 1).find((candidate) => restored.includes(candidate));
|
|
412
|
+
const insertion = following === void 0 ? restored.length : restored.indexOf(following);
|
|
413
|
+
restored.splice(insertion, 0, name);
|
|
414
|
+
}
|
|
415
|
+
return restored;
|
|
185
416
|
}
|
|
186
417
|
function unique(values) {
|
|
187
418
|
return [...new Set(values)];
|
|
188
419
|
}
|
|
189
420
|
|
|
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
421
|
// src/tool-selector.ts
|
|
221
|
-
function unique2(values) {
|
|
222
|
-
return Array.from(new Set(values));
|
|
223
|
-
}
|
|
224
422
|
function formatError(error) {
|
|
225
423
|
return error instanceof Error ? error.message : String(error);
|
|
226
424
|
}
|
|
@@ -242,8 +440,10 @@ async function waitForChromeDevtoolsSettings() {
|
|
|
242
440
|
await toolTransactionQueue;
|
|
243
441
|
}
|
|
244
442
|
function transactSelectedTools(pi, ctx, selectedTools, expectedGeneration, expectedActiveTools) {
|
|
443
|
+
const acceptedTools = [...selectedTools];
|
|
444
|
+
const expectedTools = expectedActiveTools ? [...expectedActiveTools] : void 0;
|
|
245
445
|
const operation = toolTransactionQueue.then(
|
|
246
|
-
() => transactSelectedToolsNow(pi, ctx,
|
|
446
|
+
() => transactSelectedToolsNow(pi, ctx, acceptedTools, expectedGeneration, expectedTools)
|
|
247
447
|
);
|
|
248
448
|
toolTransactionQueue = operation.then(
|
|
249
449
|
() => void 0,
|
|
@@ -252,7 +452,25 @@ function transactSelectedTools(pi, ctx, selectedTools, expectedGeneration, expec
|
|
|
252
452
|
return operation;
|
|
253
453
|
}
|
|
254
454
|
async function transactSelectedToolsNow(pi, ctx, selectedTools, expectedGeneration, expectedActiveTools) {
|
|
255
|
-
if (expectedGeneration !== state.sessionGeneration)
|
|
455
|
+
if (expectedGeneration !== state.sessionGeneration) {
|
|
456
|
+
try {
|
|
457
|
+
if (expectedActiveTools) {
|
|
458
|
+
const settings = await loadSettings();
|
|
459
|
+
if (settings.userFile.kind !== "invalid") {
|
|
460
|
+
const catalog = new Set(
|
|
461
|
+
settings.kind === "loaded" && settings.settings.tools ? settings.settings.tools : CHROME_DEVTOOLS_TOOL_NAMES
|
|
462
|
+
);
|
|
463
|
+
const current = CHROME_DEVTOOLS_TOOL_NAMES.filter(
|
|
464
|
+
(name) => catalog.has(name) && (settings.effectiveWebMcpEnabled || !isWebMcpToolName(name))
|
|
465
|
+
);
|
|
466
|
+
if (!arraysEqual(current, expectedActiveTools)) return "active-tools-changed";
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
await persistSettings(selectedTools);
|
|
470
|
+
} catch {
|
|
471
|
+
}
|
|
472
|
+
return "failed";
|
|
473
|
+
}
|
|
256
474
|
if (expectedActiveTools && !arraysEqual(availableChromeDevtoolsTools(pi), expectedActiveTools)) {
|
|
257
475
|
ctx.ui.notify(
|
|
258
476
|
"Browser tool selection changed while review was open. Review the current state, then apply again.",
|
|
@@ -260,34 +478,38 @@ async function transactSelectedToolsNow(pi, ctx, selectedTools, expectedGenerati
|
|
|
260
478
|
);
|
|
261
479
|
return "active-tools-changed";
|
|
262
480
|
}
|
|
263
|
-
const previousActiveTools = pi.getActiveTools();
|
|
264
|
-
const previousAvailableTools = availableChromeDevtoolsTools(pi);
|
|
265
481
|
try {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
482
|
+
await persistSettings(selectedTools, () => {
|
|
483
|
+
if (expectedGeneration !== state.sessionGeneration) return;
|
|
484
|
+
const previousActiveTools = pi.getActiveTools();
|
|
485
|
+
const previousAvailableTools = availableChromeDevtoolsTools(pi);
|
|
486
|
+
const previousConfiguredTools = configuredChromeDevtoolsTools(pi);
|
|
487
|
+
try {
|
|
488
|
+
const previousWebMcpTools = previousAvailableTools.filter(isWebMcpToolName);
|
|
489
|
+
applyChromeDevtoolsTools(pi, selectedTools);
|
|
490
|
+
const publishedWebMcpTools = availableChromeDevtoolsTools(pi).filter(isWebMcpToolName);
|
|
491
|
+
if (!arraysEqual(previousWebMcpTools, publishedWebMcpTools)) {
|
|
492
|
+
invalidateWebMcpOperations(ctx.sessionManager, "Chrome DevTools WebMCP gateway availability changed");
|
|
493
|
+
}
|
|
494
|
+
} catch (error) {
|
|
495
|
+
if (expectedGeneration === state.sessionGeneration) {
|
|
496
|
+
try {
|
|
497
|
+
applyAvailableChromeDevtoolsTools(pi, previousConfiguredTools, previousActiveTools);
|
|
498
|
+
} catch (rollbackError) {
|
|
499
|
+
throw new Error(`${formatError(error)}; active-tool rollback failed: ${formatError(rollbackError)}`, {
|
|
500
|
+
cause: error
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
throw error;
|
|
505
|
+
}
|
|
506
|
+
});
|
|
273
507
|
return expectedGeneration === state.sessionGeneration ? "saved" : "failed";
|
|
274
508
|
} 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
509
|
if (expectedGeneration !== state.sessionGeneration) return "failed";
|
|
288
510
|
ctx.ui.notify(
|
|
289
511
|
sanitizeChromeDevtoolsDisplay(
|
|
290
|
-
|
|
512
|
+
error instanceof ToolCatalogApplicationError ? `Chrome DevTools tool application failed: ${formatError(error)}` : `Chrome DevTools settings save failed; active tools unchanged: ${formatError(error)}`
|
|
291
513
|
),
|
|
292
514
|
"warning"
|
|
293
515
|
);
|
|
@@ -319,12 +541,21 @@ function getToolStatusSummary(pi, owner) {
|
|
|
319
541
|
};
|
|
320
542
|
}
|
|
321
543
|
async function buildToolStatusMessage(pi, owner) {
|
|
544
|
+
const generation = state.sessionGeneration;
|
|
545
|
+
await waitForChromeDevtoolsSettings();
|
|
546
|
+
if (generation !== state.sessionGeneration) return "";
|
|
547
|
+
const settings = await loadSettings();
|
|
548
|
+
if (generation !== state.sessionGeneration) return "";
|
|
322
549
|
const summary = getToolStatusSummary(pi, owner);
|
|
323
|
-
const persistedSetting =
|
|
550
|
+
const persistedSetting = persistedSettingLabel(settings);
|
|
551
|
+
const savedMode = settings.userFile.kind === "invalid" ? void 0 : settings.kind === "loaded" ? settings.settings.toolMode : "codemode";
|
|
324
552
|
return sanitizeChromeDevtoolsDisplay(
|
|
325
553
|
[
|
|
326
554
|
`Chrome DevTools tools available: ${formatRuntimeStatus(summary)}`,
|
|
555
|
+
`Running tool mode: ${chromeDevtoolsToolMode(pi)}`,
|
|
327
556
|
`Tool exposure: ${chromeDevtoolsToolExposureMode(pi)}`,
|
|
557
|
+
`Saved tool mode: ${savedMode ?? "unavailable (invalid user settings)"}`,
|
|
558
|
+
...savedMode !== void 0 && savedMode !== chromeDevtoolsToolMode(pi) ? ["Tool mode change pending; /reload or session replacement required."] : [],
|
|
328
559
|
`Loaded capability tools this session: ${summary.loadedChromeToolCount}/${summary.capabilityCount}`,
|
|
329
560
|
`WebMCP: ${webMcpEnabled(owner) ? "enabled \xB7 experimental \xB7 confirmation required for every call" : "disabled \xB7 experimental"}`,
|
|
330
561
|
`Loader: ${pi.getActiveTools().includes(CHROME_DEVTOOLS_LOAD_TOOL_NAME) ? "active" : "inactive"}`,
|
|
@@ -417,15 +648,14 @@ function allChromeDevtoolsTools(owner) {
|
|
|
417
648
|
function formatRuntimeStatus(summary) {
|
|
418
649
|
return `${summary.availabilityStatus} (${summary.availableChromeToolCount}/${summary.capabilityCount} available)`;
|
|
419
650
|
}
|
|
420
|
-
|
|
421
|
-
const settings = await loadSettings();
|
|
651
|
+
function persistedSettingLabel(settings) {
|
|
422
652
|
if (settings.kind === "loaded" && settings.settings.tools) {
|
|
423
653
|
return formatPersistedSelection(settings.settings.tools);
|
|
424
654
|
}
|
|
425
655
|
if (settings.kind === "invalid") {
|
|
426
656
|
return `none; current active-tool policy preserved (invalid settings ignored: ${settings.reason})`;
|
|
427
657
|
}
|
|
428
|
-
return "none;
|
|
658
|
+
return "none; default catalog restored on /reload or session replacement";
|
|
429
659
|
}
|
|
430
660
|
function formatPersistedSelection(tools) {
|
|
431
661
|
if (tools.length === CHROME_DEVTOOLS_TOOL_NAMES.length) {
|
|
@@ -437,11 +667,14 @@ function formatPersistedSelection(tools) {
|
|
|
437
667
|
function effectiveCatalog(owner) {
|
|
438
668
|
return webMcpEnabled(owner) ? [...CHROME_DEVTOOLS_TOOL_NAMES] : [...CORE_CHROME_DEVTOOLS_TOOL_NAMES];
|
|
439
669
|
}
|
|
440
|
-
async function persistSettings(selectedTools) {
|
|
441
|
-
await saveSettings({ tools: [...selectedTools], updatedAt: Date.now() });
|
|
670
|
+
async function persistSettings(selectedTools, applyAfterSave) {
|
|
671
|
+
await saveSettings({ tools: [...selectedTools], updatedAt: Date.now() }, {}, applyAfterSave);
|
|
442
672
|
}
|
|
443
673
|
|
|
444
674
|
export {
|
|
675
|
+
sanitizeChromeDevtoolsDisplay,
|
|
676
|
+
registerChromeDevtoolsCapabilities,
|
|
677
|
+
chromeDevtoolsToolMode,
|
|
445
678
|
setChromeDevtoolsSessionOwner,
|
|
446
679
|
initializeAvailableChromeDevtoolsTools,
|
|
447
680
|
configureChromeDevtoolsToolExposure,
|
|
@@ -449,9 +682,8 @@ export {
|
|
|
449
682
|
applyAvailableChromeDevtoolsTools,
|
|
450
683
|
supportsNativeDeferredToolLoading,
|
|
451
684
|
availableChromeDevtoolsTools,
|
|
685
|
+
previousChromeDevtoolsTools,
|
|
452
686
|
configuredChromeDevtoolsTools,
|
|
453
|
-
createChromeDevtoolsLoadTool,
|
|
454
|
-
sanitizeChromeDevtoolsDisplay,
|
|
455
687
|
updateChromeDevtoolsTools,
|
|
456
688
|
setSelectedChromeDevtoolsTools,
|
|
457
689
|
waitForChromeDevtoolsSettings,
|
|
@@ -461,4 +693,4 @@ export {
|
|
|
461
693
|
buildCommandGuide,
|
|
462
694
|
allChromeDevtoolsTools
|
|
463
695
|
};
|
|
464
|
-
//# sourceMappingURL=chunk-
|
|
696
|
+
//# sourceMappingURL=chunk-JKPJYUVG.ts.map
|