@cydm/pie 2.1.0 → 2.1.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.
Files changed (37) hide show
  1. package/README.md +6 -3
  2. package/dist/builtin/extensions/ask-user/index.js +1 -1
  3. package/dist/builtin/extensions/computer-use/index.js +3993 -107
  4. package/dist/builtin/extensions/plan-mode/index.js +1 -1
  5. package/dist/builtin/extensions/subagent/index.js +2 -2
  6. package/dist/builtin/extensions/todo/index.js +1 -1
  7. package/dist/builtin/skills/chrome-devtools-axi/LICENSE +21 -0
  8. package/dist/builtin/skills/chrome-devtools-axi/SKILL.md +20 -1
  9. package/dist/builtin/skills/chrome-devtools-axi/chrome-devtools-axi-bridge.js +20034 -0
  10. package/dist/builtin/skills/chrome-devtools-axi/chrome-devtools-axi-cli.js +8 -2
  11. package/dist/builtin/skills/chrome-devtools-axi/chrome-devtools-axi-runtime.js +26 -0
  12. package/dist/builtin/skills/chrome-devtools-axi/chunk-42SGITKJ.js +11 -0
  13. package/dist/builtin/skills/chrome-devtools-axi/chunk-OJ6N23UZ.js +47 -0
  14. package/dist/builtin/skills/chrome-devtools-axi/chunk-UPATXALW.js +215 -0
  15. package/dist/builtin/skills/chrome-devtools-axi/cli-F2VCSVL4.js +4424 -0
  16. package/dist/builtin/skills/skill-creator/SKILL.md +5 -2
  17. package/dist/builtin/skills/skill-creator/eval-viewer/generate_review.mjs +7 -20
  18. package/dist/builtin/skills/skill-creator/eval-viewer/viewer.html +15 -15
  19. package/dist/builtin/skills/skill-creator/scripts/aggregate_benchmark.mjs +20 -19
  20. package/dist/builtin/skills/skill-creator/scripts/generate_report.mjs +3 -3
  21. package/dist/builtin/skills/skill-creator/scripts/improve_description.mjs +12 -8
  22. package/dist/builtin/skills/skill-creator/scripts/package_skill.mjs +1 -0
  23. package/dist/builtin/skills/skill-creator/scripts/pie_runner.mjs +77 -31
  24. package/dist/builtin/skills/skill-creator/scripts/run_eval.mjs +38 -11
  25. package/dist/builtin/skills/skill-creator/scripts/run_loop.mjs +12 -6
  26. package/dist/builtin/skills/skill-creator/scripts/skill_metadata.mjs +12 -1
  27. package/dist/builtin/skills/tui-use/LICENSE +21 -0
  28. package/dist/builtin/skills/tui-use/README.md +13 -3
  29. package/dist/builtin/skills/tui-use/SKILL.md +87 -39
  30. package/dist/builtin/skills/tui-use/tui-use-cli.cjs +10608 -0
  31. package/dist/builtin/skills/tui-use/tui-use-cli.js +39 -0
  32. package/dist/builtin/skills/tui-use/tui-use-daemon.cjs +7916 -0
  33. package/dist/chunks/{chunk-PMPD56N2.js → chunk-LU7RKALH.js} +82 -24
  34. package/dist/chunks/{chunk-G2POWIA5.js → chunk-TJ2F4FL5.js} +64 -16
  35. package/dist/cli.js +7503 -87
  36. package/package.json +26 -18
  37. package/scripts/repair-node-pty.mjs +45 -0
@@ -0,0 +1,4424 @@
1
+ import { createRequire as __axiRequire } from "node:module"; const require = __axiRequire(import.meta.url);
2
+ import {
3
+ VERSION
4
+ } from "./chunk-42SGITKJ.js";
5
+ import {
6
+ BRIDGE_PORT_IN_USE_EXIT_CODE,
7
+ PAGE_IDENTITY_CHANGED_ERROR,
8
+ clearSelectedPageId,
9
+ getSelectedPageId,
10
+ overlaySessionSelected,
11
+ rememberToolRouting,
12
+ resolveBridgeScript,
13
+ resolveSessionName,
14
+ resolveSessionPidFile,
15
+ resolveSessionPort,
16
+ resolveSessionStateDir
17
+ } from "./chunk-UPATXALW.js";
18
+ import "./chunk-OJ6N23UZ.js";
19
+
20
+ // ../../node_modules/chrome-devtools-axi/node_modules/@toon-format/toon/dist/index.mjs
21
+ var NULL_LITERAL = "null";
22
+ var DELIMITERS = {
23
+ comma: ",",
24
+ tab: " ",
25
+ pipe: "|"
26
+ };
27
+ var DEFAULT_DELIMITER = DELIMITERS.comma;
28
+ function escapeString(value) {
29
+ return value.replace(/\\/g, `\\\\`).replace(/"/g, `\\"`).replace(/\n/g, `\\n`).replace(/\r/g, `\\r`).replace(/\t/g, `\\t`).replace(/[\u0000-\u001F]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
30
+ }
31
+ function isBooleanOrNullLiteral(token) {
32
+ return token === "true" || token === "false" || token === "null";
33
+ }
34
+ function setOwnProperty(target, key, value) {
35
+ if (key === "__proto__") {
36
+ Object.defineProperty(target, key, {
37
+ value,
38
+ enumerable: true,
39
+ writable: true,
40
+ configurable: true
41
+ });
42
+ return;
43
+ }
44
+ target[key] = value;
45
+ }
46
+ function normalizeValue(value) {
47
+ if (value === null) return null;
48
+ if (typeof value === "object" && value !== null && "toJSON" in value && typeof value.toJSON === "function") {
49
+ const next = value.toJSON();
50
+ if (next !== value) return normalizeValue(next);
51
+ }
52
+ if (typeof value === "string" || typeof value === "boolean") return value;
53
+ if (typeof value === "number") {
54
+ if (Object.is(value, -0)) return 0;
55
+ if (!Number.isFinite(value)) return null;
56
+ return value;
57
+ }
58
+ if (typeof value === "bigint") {
59
+ if (value >= Number.MIN_SAFE_INTEGER && value <= Number.MAX_SAFE_INTEGER) return Number(value);
60
+ return value.toString();
61
+ }
62
+ if (value instanceof Date) return value.toISOString();
63
+ if (Array.isArray(value)) return value.map(normalizeValue);
64
+ if (value instanceof Set) return Array.from(value).map(normalizeValue);
65
+ if (value instanceof Map) return Object.fromEntries(Array.from(value, ([k, v]) => [String(k), normalizeValue(v)]));
66
+ if (isPlainObject(value)) {
67
+ const encodedValues = {};
68
+ for (const key in value) if (Object.hasOwn(value, key)) setOwnProperty(encodedValues, key, normalizeValue(value[key]));
69
+ return encodedValues;
70
+ }
71
+ return null;
72
+ }
73
+ function isJsonPrimitive(value) {
74
+ return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
75
+ }
76
+ function isJsonArray(value) {
77
+ return Array.isArray(value);
78
+ }
79
+ function isJsonObject(value) {
80
+ return value !== null && typeof value === "object" && !Array.isArray(value);
81
+ }
82
+ function isEmptyObject(value) {
83
+ return Object.keys(value).length === 0;
84
+ }
85
+ function isPlainObject(value) {
86
+ if (value === null || typeof value !== "object") return false;
87
+ const prototype = Object.getPrototypeOf(value);
88
+ return prototype === null || prototype === Object.prototype;
89
+ }
90
+ function isArrayOfPrimitives(value) {
91
+ return value.length === 0 || value.every((item) => isJsonPrimitive(item));
92
+ }
93
+ function isArrayOfArrays(value) {
94
+ return value.length === 0 || value.every((item) => isJsonArray(item));
95
+ }
96
+ function isArrayOfObjects(value) {
97
+ return value.length === 0 || value.every((item) => isJsonObject(item));
98
+ }
99
+ var NUMERIC_LIKE_PATTERN = /^-?\d+(?:\.\d+)?(?:e[+-]?\d+)?$/i;
100
+ var LEADING_ZERO_PATTERN = /^0\d+$/;
101
+ function isValidUnquotedKey(key) {
102
+ return /^[A-Z_][\w.]*$/i.test(key);
103
+ }
104
+ function isIdentifierSegment(key) {
105
+ return /^[A-Z_]\w*$/i.test(key);
106
+ }
107
+ function isSafeUnquoted(value, delimiter2 = DEFAULT_DELIMITER) {
108
+ if (!value) return false;
109
+ if (value !== value.trim()) return false;
110
+ if (isBooleanOrNullLiteral(value) || isNumericLike(value)) return false;
111
+ if (value.includes(":")) return false;
112
+ if (value.includes('"') || value.includes("\\")) return false;
113
+ if (/[[\]{}]/.test(value)) return false;
114
+ if (/[\u0000-\u001F]/.test(value)) return false;
115
+ if (value.includes(delimiter2)) return false;
116
+ if (value.startsWith("-")) return false;
117
+ return true;
118
+ }
119
+ function isNumericLike(value) {
120
+ return NUMERIC_LIKE_PATTERN.test(value) || LEADING_ZERO_PATTERN.test(value);
121
+ }
122
+ function tryFoldKeyChain(key, value, siblings, options, rootLiteralKeys, pathPrefix, flattenDepth) {
123
+ if (options.keyFolding !== "safe") return;
124
+ if (!isJsonObject(value)) return;
125
+ const { segments, tail, leafValue } = collectSingleKeyChain(key, value, flattenDepth ?? options.flattenDepth);
126
+ if (segments.length < 2) return;
127
+ if (!segments.every((seg) => isIdentifierSegment(seg))) return;
128
+ const foldedKey = buildFoldedKey(segments);
129
+ const absolutePath = pathPrefix ? `${pathPrefix}.${foldedKey}` : foldedKey;
130
+ if (siblings.includes(foldedKey)) return;
131
+ if (rootLiteralKeys && rootLiteralKeys.has(absolutePath)) return;
132
+ return {
133
+ foldedKey,
134
+ remainder: tail,
135
+ leafValue,
136
+ segmentCount: segments.length
137
+ };
138
+ }
139
+ function collectSingleKeyChain(startKey, startValue, maxDepth) {
140
+ const segments = [startKey];
141
+ let currentValue = startValue;
142
+ while (segments.length < maxDepth) {
143
+ if (!isJsonObject(currentValue)) break;
144
+ const keys = Object.keys(currentValue);
145
+ if (keys.length !== 1) break;
146
+ const nextKey = keys[0];
147
+ const nextValue = currentValue[nextKey];
148
+ segments.push(nextKey);
149
+ currentValue = nextValue;
150
+ }
151
+ if (!isJsonObject(currentValue) || isEmptyObject(currentValue)) return {
152
+ segments,
153
+ tail: void 0,
154
+ leafValue: currentValue
155
+ };
156
+ return {
157
+ segments,
158
+ tail: currentValue,
159
+ leafValue: currentValue
160
+ };
161
+ }
162
+ function buildFoldedKey(segments) {
163
+ return segments.join(".");
164
+ }
165
+ function encodePrimitive(value, delimiter2) {
166
+ if (value === null) return NULL_LITERAL;
167
+ if (typeof value === "boolean") return String(value);
168
+ if (typeof value === "number") return String(value);
169
+ return encodeStringLiteral(value, delimiter2);
170
+ }
171
+ function encodeStringLiteral(value, delimiter2 = DEFAULT_DELIMITER) {
172
+ if (isSafeUnquoted(value, delimiter2)) return value;
173
+ return `"${escapeString(value)}"`;
174
+ }
175
+ function encodeKey(key) {
176
+ if (isValidUnquotedKey(key)) return key;
177
+ return `"${escapeString(key)}"`;
178
+ }
179
+ function encodeAndJoinPrimitives(values, delimiter2 = DEFAULT_DELIMITER) {
180
+ return values.map((v) => encodePrimitive(v, delimiter2)).join(delimiter2);
181
+ }
182
+ function formatHeader(length, options) {
183
+ const key = options?.key;
184
+ const fields = options?.fields;
185
+ const delimiter2 = options?.delimiter ?? ",";
186
+ let header = "";
187
+ if (key != null) header += encodeKey(key);
188
+ header += `[${length}${delimiter2 !== DEFAULT_DELIMITER ? delimiter2 : ""}]`;
189
+ if (fields) {
190
+ const quotedFields = fields.map((f) => encodeKey(f));
191
+ header += `{${quotedFields.join(delimiter2)}}`;
192
+ }
193
+ header += ":";
194
+ return header;
195
+ }
196
+ function* encodeJsonValue(value, options, depth) {
197
+ if (isJsonPrimitive(value)) {
198
+ const encodedPrimitive = encodePrimitive(value, options.delimiter);
199
+ if (encodedPrimitive !== "") yield encodedPrimitive;
200
+ return;
201
+ }
202
+ if (isJsonArray(value)) yield* encodeArrayLines(void 0, value, depth, options);
203
+ else if (isJsonObject(value)) yield* encodeObjectLines(value, depth, options);
204
+ }
205
+ function* encodeObjectLines(value, depth, options, rootLiteralKeys, pathPrefix, remainingDepth) {
206
+ const keys = Object.keys(value);
207
+ if (depth === 0 && !rootLiteralKeys) rootLiteralKeys = new Set(keys.filter((k) => k.includes(".")));
208
+ const effectiveFlattenDepth = remainingDepth ?? options.flattenDepth;
209
+ for (const [key, val] of Object.entries(value)) yield* encodeKeyValuePairLines(key, val, depth, options, keys, rootLiteralKeys, pathPrefix, effectiveFlattenDepth);
210
+ }
211
+ function* encodeKeyValuePairLines(key, value, depth, options, siblings, rootLiteralKeys, pathPrefix, flattenDepth) {
212
+ const currentPath = pathPrefix ? `${pathPrefix}.${key}` : key;
213
+ const effectiveFlattenDepth = flattenDepth ?? options.flattenDepth;
214
+ if (options.keyFolding === "safe" && siblings) {
215
+ const foldResult = tryFoldKeyChain(key, value, siblings, options, rootLiteralKeys, pathPrefix, effectiveFlattenDepth);
216
+ if (foldResult) {
217
+ const { foldedKey, remainder, leafValue, segmentCount } = foldResult;
218
+ const encodedFoldedKey = encodeKey(foldedKey);
219
+ if (remainder === void 0) {
220
+ if (isJsonPrimitive(leafValue)) {
221
+ yield indentedLine(depth, `${encodedFoldedKey}: ${encodePrimitive(leafValue, options.delimiter)}`, options.indent);
222
+ return;
223
+ } else if (isJsonArray(leafValue)) {
224
+ yield* encodeArrayLines(foldedKey, leafValue, depth, options);
225
+ return;
226
+ } else if (isJsonObject(leafValue) && isEmptyObject(leafValue)) {
227
+ yield indentedLine(depth, `${encodedFoldedKey}:`, options.indent);
228
+ return;
229
+ }
230
+ }
231
+ if (isJsonObject(remainder)) {
232
+ yield indentedLine(depth, `${encodedFoldedKey}:`, options.indent);
233
+ const remainingDepth = effectiveFlattenDepth - segmentCount;
234
+ const foldedPath = pathPrefix ? `${pathPrefix}.${foldedKey}` : foldedKey;
235
+ yield* encodeObjectLines(remainder, depth + 1, options, rootLiteralKeys, foldedPath, remainingDepth);
236
+ return;
237
+ }
238
+ }
239
+ }
240
+ const encodedKey = encodeKey(key);
241
+ if (isJsonPrimitive(value)) yield indentedLine(depth, `${encodedKey}: ${encodePrimitive(value, options.delimiter)}`, options.indent);
242
+ else if (isJsonArray(value)) yield* encodeArrayLines(key, value, depth, options);
243
+ else if (isJsonObject(value)) {
244
+ yield indentedLine(depth, `${encodedKey}:`, options.indent);
245
+ if (!isEmptyObject(value)) yield* encodeObjectLines(value, depth + 1, options, rootLiteralKeys, currentPath, effectiveFlattenDepth);
246
+ }
247
+ }
248
+ function* encodeArrayLines(key, value, depth, options) {
249
+ if (value.length === 0) {
250
+ yield indentedLine(depth, key != null ? `${encodeKey(key)}: []` : "[]", options.indent);
251
+ return;
252
+ }
253
+ if (isArrayOfPrimitives(value)) {
254
+ yield indentedLine(depth, encodeInlineArrayLine(value, options.delimiter, key), options.indent);
255
+ return;
256
+ }
257
+ if (isArrayOfArrays(value)) {
258
+ if (value.every((arr) => isArrayOfPrimitives(arr))) {
259
+ yield* encodeArrayOfArraysAsListItemsLines(key, value, depth, options);
260
+ return;
261
+ }
262
+ }
263
+ if (isArrayOfObjects(value)) {
264
+ const header = extractTabularHeader(value);
265
+ if (header) yield* encodeArrayOfObjectsAsTabularLines(key, value, header, depth, options);
266
+ else yield* encodeMixedArrayAsListItemsLines(key, value, depth, options);
267
+ return;
268
+ }
269
+ yield* encodeMixedArrayAsListItemsLines(key, value, depth, options);
270
+ }
271
+ function* encodeArrayOfArraysAsListItemsLines(prefix, values, depth, options) {
272
+ yield indentedLine(depth, formatHeader(values.length, {
273
+ key: prefix,
274
+ delimiter: options.delimiter
275
+ }), options.indent);
276
+ for (const arr of values) if (isArrayOfPrimitives(arr)) {
277
+ const arrayLine = encodeInlineArrayLine(arr, options.delimiter);
278
+ yield indentedListItem(depth + 1, arrayLine, options.indent);
279
+ }
280
+ }
281
+ function encodeInlineArrayLine(values, delimiter2, prefix) {
282
+ const header = formatHeader(values.length, {
283
+ key: prefix,
284
+ delimiter: delimiter2
285
+ });
286
+ const joinedValue = encodeAndJoinPrimitives(values, delimiter2);
287
+ if (values.length === 0) return header;
288
+ return `${header} ${joinedValue}`;
289
+ }
290
+ function* encodeArrayOfObjectsAsTabularLines(prefix, rows, header, depth, options) {
291
+ yield indentedLine(depth, formatHeader(rows.length, {
292
+ key: prefix,
293
+ fields: header,
294
+ delimiter: options.delimiter
295
+ }), options.indent);
296
+ yield* writeTabularRowsLines(rows, header, depth + 1, options);
297
+ }
298
+ function extractTabularHeader(rows) {
299
+ if (rows.length === 0) return;
300
+ const firstRow = rows[0];
301
+ const firstKeys = Object.keys(firstRow);
302
+ if (firstKeys.length === 0) return;
303
+ if (isTabularArray(rows, firstKeys)) return firstKeys;
304
+ }
305
+ function isTabularArray(rows, header) {
306
+ for (const row of rows) {
307
+ if (Object.keys(row).length !== header.length) return false;
308
+ for (const key of header) {
309
+ if (!Object.hasOwn(row, key)) return false;
310
+ if (!isJsonPrimitive(row[key])) return false;
311
+ }
312
+ }
313
+ return true;
314
+ }
315
+ function* writeTabularRowsLines(rows, header, depth, options) {
316
+ for (const row of rows) yield indentedLine(depth, encodeAndJoinPrimitives(header.map((key) => row[key]), options.delimiter), options.indent);
317
+ }
318
+ function* encodeMixedArrayAsListItemsLines(prefix, items, depth, options) {
319
+ yield indentedLine(depth, formatHeader(items.length, {
320
+ key: prefix,
321
+ delimiter: options.delimiter
322
+ }), options.indent);
323
+ for (const item of items) yield* encodeListItemValueLines(item, depth + 1, options);
324
+ }
325
+ function* encodeObjectAsListItemLines(obj, depth, options) {
326
+ if (isEmptyObject(obj)) {
327
+ yield indentedLine(depth, "-", options.indent);
328
+ return;
329
+ }
330
+ const entries = Object.entries(obj);
331
+ const [firstKey, firstValue] = entries[0];
332
+ const restEntries = entries.slice(1);
333
+ if (isJsonArray(firstValue) && isArrayOfObjects(firstValue)) {
334
+ const header = extractTabularHeader(firstValue);
335
+ if (header) {
336
+ yield indentedListItem(depth, formatHeader(firstValue.length, {
337
+ key: firstKey,
338
+ fields: header,
339
+ delimiter: options.delimiter
340
+ }), options.indent);
341
+ yield* writeTabularRowsLines(firstValue, header, depth + 2, options);
342
+ if (restEntries.length > 0) yield* encodeObjectLines(Object.fromEntries(restEntries), depth + 1, options);
343
+ return;
344
+ }
345
+ }
346
+ const encodedKey = encodeKey(firstKey);
347
+ if (isJsonPrimitive(firstValue)) yield indentedListItem(depth, `${encodedKey}: ${encodePrimitive(firstValue, options.delimiter)}`, options.indent);
348
+ else if (isJsonArray(firstValue)) if (firstValue.length === 0) yield indentedListItem(depth, `${encodedKey}: []`, options.indent);
349
+ else if (isArrayOfPrimitives(firstValue)) yield indentedListItem(depth, `${encodedKey}${encodeInlineArrayLine(firstValue, options.delimiter)}`, options.indent);
350
+ else {
351
+ yield indentedListItem(depth, `${encodedKey}${formatHeader(firstValue.length, { delimiter: options.delimiter })}`, options.indent);
352
+ for (const item of firstValue) yield* encodeListItemValueLines(item, depth + 2, options);
353
+ }
354
+ else if (isJsonObject(firstValue)) {
355
+ yield indentedListItem(depth, `${encodedKey}:`, options.indent);
356
+ if (!isEmptyObject(firstValue)) yield* encodeObjectLines(firstValue, depth + 2, options);
357
+ }
358
+ if (restEntries.length > 0) yield* encodeObjectLines(Object.fromEntries(restEntries), depth + 1, options);
359
+ }
360
+ function* encodeListItemValueLines(value, depth, options) {
361
+ if (isJsonPrimitive(value)) yield indentedListItem(depth, encodePrimitive(value, options.delimiter), options.indent);
362
+ else if (isJsonArray(value)) if (isArrayOfPrimitives(value)) yield indentedListItem(depth, encodeInlineArrayLine(value, options.delimiter), options.indent);
363
+ else {
364
+ yield indentedListItem(depth, formatHeader(value.length, { delimiter: options.delimiter }), options.indent);
365
+ for (const item of value) yield* encodeListItemValueLines(item, depth + 1, options);
366
+ }
367
+ else if (isJsonObject(value)) yield* encodeObjectAsListItemLines(value, depth, options);
368
+ }
369
+ function indentedLine(depth, content, indentSize) {
370
+ return " ".repeat(indentSize * depth) + content;
371
+ }
372
+ function indentedListItem(depth, content, indentSize) {
373
+ return indentedLine(depth, "- " + content, indentSize);
374
+ }
375
+ function applyReplacer(root, replacer) {
376
+ const replacedRoot = replacer("", root, []);
377
+ if (replacedRoot === void 0) return transformChildren(root, replacer, []);
378
+ return transformChildren(normalizeValue(replacedRoot), replacer, []);
379
+ }
380
+ function transformChildren(value, replacer, path) {
381
+ if (isJsonObject(value)) return transformObject(value, replacer, path);
382
+ if (isJsonArray(value)) return transformArray(value, replacer, path);
383
+ return value;
384
+ }
385
+ function transformObject(obj, replacer, path) {
386
+ const result = {};
387
+ for (const [key, value] of Object.entries(obj)) {
388
+ const childPath = [...path, key];
389
+ const replacedValue = replacer(key, value, childPath);
390
+ if (replacedValue === void 0) continue;
391
+ setOwnProperty(result, key, transformChildren(normalizeValue(replacedValue), replacer, childPath));
392
+ }
393
+ return result;
394
+ }
395
+ function transformArray(arr, replacer, path) {
396
+ const result = [];
397
+ for (let i = 0; i < arr.length; i++) {
398
+ const value = arr[i];
399
+ const childPath = [...path, i];
400
+ const replacedValue = replacer(String(i), value, childPath);
401
+ if (replacedValue === void 0) continue;
402
+ const normalizedValue = normalizeValue(replacedValue);
403
+ result.push(transformChildren(normalizedValue, replacer, childPath));
404
+ }
405
+ return result;
406
+ }
407
+ function encode(input, options) {
408
+ return Array.from(encodeLines(input, options)).join("\n");
409
+ }
410
+ function encodeLines(input, options) {
411
+ const normalizedValue = normalizeValue(input);
412
+ const resolvedOptions = resolveOptions(options);
413
+ return encodeJsonValue(resolvedOptions.replacer ? applyReplacer(normalizedValue, resolvedOptions.replacer) : normalizedValue, resolvedOptions, 0);
414
+ }
415
+ function resolveOptions(options) {
416
+ return {
417
+ indent: options?.indent ?? 2,
418
+ delimiter: options?.delimiter ?? DEFAULT_DELIMITER,
419
+ keyFolding: options?.keyFolding ?? "off",
420
+ flattenDepth: options?.flattenDepth ?? Number.POSITIVE_INFINITY,
421
+ replacer: options?.replacer
422
+ };
423
+ }
424
+
425
+ // ../../node_modules/axi-sdk-js/dist/cli.js
426
+ import { basename as basename2 } from "node:path";
427
+
428
+ // ../../node_modules/axi-sdk-js/dist/errors.js
429
+ var AxiError = class extends Error {
430
+ code;
431
+ suggestions;
432
+ constructor(message, code, suggestions = []) {
433
+ super(message);
434
+ this.code = code;
435
+ this.suggestions = suggestions;
436
+ this.name = "AxiError";
437
+ }
438
+ };
439
+ function exitCodeForError(error) {
440
+ if (error instanceof AxiError && error.code === "VALIDATION_ERROR") {
441
+ return 2;
442
+ }
443
+ return 1;
444
+ }
445
+
446
+ // ../../node_modules/axi-sdk-js/dist/output.js
447
+ import { homedir } from "node:os";
448
+ function collapseHomeDirectory(path, homeDir = homedir()) {
449
+ if (!path.startsWith(homeDir)) {
450
+ return path;
451
+ }
452
+ return `~${path.slice(homeDir.length)}`;
453
+ }
454
+ function homeHeaderOutput(options) {
455
+ return {
456
+ bin: collapseHomeDirectory(options.execPath ?? process.argv[1] ?? "", options.homeDir),
457
+ description: options.description
458
+ };
459
+ }
460
+ function errorOutput(message, code, suggestions = []) {
461
+ const output = {
462
+ error: message,
463
+ code
464
+ };
465
+ if (suggestions.length > 0) {
466
+ output.help = suggestions;
467
+ }
468
+ return output;
469
+ }
470
+ function renderOutput(output) {
471
+ if (typeof output === "string") {
472
+ return output;
473
+ }
474
+ return encode(output);
475
+ }
476
+ function renderError(message, code, suggestions = []) {
477
+ return renderOutput(errorOutput(message, code, suggestions));
478
+ }
479
+
480
+ // ../../node_modules/axi-sdk-js/dist/update.js
481
+ import { spawn } from "node:child_process";
482
+ import { execFile } from "node:child_process";
483
+ import { existsSync, readFileSync, realpathSync } from "node:fs";
484
+ import { basename, dirname, join } from "node:path";
485
+ import { promisify } from "node:util";
486
+ var execFileAsync = promisify(execFile);
487
+ var REGISTRY_BASE = "https://registry.npmjs.org";
488
+ var REGISTRY_FETCH_TIMEOUT_MS = 2e4;
489
+ function parseSemver(version) {
490
+ const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-.]+))?(?:\+[0-9A-Za-z-.]+)?$/.exec(version.trim());
491
+ if (!match) {
492
+ return null;
493
+ }
494
+ return {
495
+ major: Number(match[1]),
496
+ minor: Number(match[2]),
497
+ patch: Number(match[3]),
498
+ prerelease: match[4] ? match[4].split(".") : []
499
+ };
500
+ }
501
+ function comparePrerelease(a, b) {
502
+ if (a.length === 0 && b.length === 0)
503
+ return 0;
504
+ if (a.length === 0)
505
+ return 1;
506
+ if (b.length === 0)
507
+ return -1;
508
+ const length = Math.max(a.length, b.length);
509
+ for (let index = 0; index < length; index += 1) {
510
+ if (index >= a.length)
511
+ return -1;
512
+ if (index >= b.length)
513
+ return 1;
514
+ const left = a[index];
515
+ const right = b[index];
516
+ const leftNumeric = /^\d+$/.test(left);
517
+ const rightNumeric = /^\d+$/.test(right);
518
+ if (leftNumeric && rightNumeric) {
519
+ const delta = Number(left) - Number(right);
520
+ if (delta !== 0)
521
+ return delta < 0 ? -1 : 1;
522
+ } else if (leftNumeric) {
523
+ return -1;
524
+ } else if (rightNumeric) {
525
+ return 1;
526
+ } else if (left !== right) {
527
+ return left < right ? -1 : 1;
528
+ }
529
+ }
530
+ return 0;
531
+ }
532
+ function compareSemver(a, b) {
533
+ const parsedA = parseSemver(a);
534
+ const parsedB = parseSemver(b);
535
+ if (!parsedA || !parsedB) {
536
+ if (a === b)
537
+ return 0;
538
+ return a < b ? -1 : 1;
539
+ }
540
+ if (parsedA.major !== parsedB.major) {
541
+ return parsedA.major < parsedB.major ? -1 : 1;
542
+ }
543
+ if (parsedA.minor !== parsedB.minor) {
544
+ return parsedA.minor < parsedB.minor ? -1 : 1;
545
+ }
546
+ if (parsedA.patch !== parsedB.patch) {
547
+ return parsedA.patch < parsedB.patch ? -1 : 1;
548
+ }
549
+ return comparePrerelease(parsedA.prerelease, parsedB.prerelease);
550
+ }
551
+ function isUpdateAvailable(current, latest) {
552
+ return compareSemver(latest, current) > 0;
553
+ }
554
+ var nodeFs = {
555
+ existsSync,
556
+ readFileSync: (path, encoding) => readFileSync(path, encoding)
557
+ };
558
+ function readNearestPackageJson(startPath, fs = nodeFs) {
559
+ let dir = dirname(startPath);
560
+ let previous = "";
561
+ while (dir !== previous) {
562
+ const packageJsonPath = join(dir, "package.json");
563
+ if (fs.existsSync(packageJsonPath)) {
564
+ try {
565
+ const parsed = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
566
+ if (typeof parsed.name === "string" && parsed.name.length > 0) {
567
+ return {
568
+ packageName: parsed.name,
569
+ version: typeof parsed.version === "string" ? parsed.version : void 0,
570
+ packageJsonPath
571
+ };
572
+ }
573
+ } catch {
574
+ }
575
+ }
576
+ previous = dir;
577
+ dir = dirname(dir);
578
+ }
579
+ return {};
580
+ }
581
+ function detectInstallMethod(options) {
582
+ const env = options.env ?? process.env;
583
+ const path = options.entry.replaceAll("\\", "/");
584
+ if (path.includes("/_npx/") || /\/dlx-[^/]+\//.test(path) || path.includes("/pnpm/dlx/") || path.includes("/bun/install/cache/")) {
585
+ return { kind: "npx" };
586
+ }
587
+ const homebrewFormula = homebrewFormulaFromPath(path, env);
588
+ if (homebrewFormula) {
589
+ return { kind: "homebrew", formula: homebrewFormula };
590
+ }
591
+ const pnpmHome = normalizePathRoot(env.PNPM_HOME);
592
+ if (isPathInsideRoot(path, pnpmHome) || isKnownPnpmGlobalStore(path, env)) {
593
+ return { kind: "pnpm-global" };
594
+ }
595
+ if (isKnownNpmGlobalInstall(path, env)) {
596
+ return { kind: "npm-global" };
597
+ }
598
+ return { kind: "unknown" };
599
+ }
600
+ function normalizePathRoot(path) {
601
+ const normalized = path?.replaceAll("\\", "/").replace(/\/+$/, "");
602
+ return normalized && normalized.length > 0 ? normalized : void 0;
603
+ }
604
+ function isPathInsideRoot(path, root) {
605
+ return root !== void 0 && (path === root || path.startsWith(`${root}/`));
606
+ }
607
+ function homebrewFormulaFromPath(path, env) {
608
+ for (const root of homebrewCellarRoots(env)) {
609
+ if (!isPathInsideRoot(path, root)) {
610
+ continue;
611
+ }
612
+ const relative = path.slice(root.length).replace(/^\/+/, "");
613
+ const formula = relative.split("/")[0];
614
+ if (formula) {
615
+ return formula;
616
+ }
617
+ }
618
+ return null;
619
+ }
620
+ function homebrewCellarRoots(env) {
621
+ const roots = [];
622
+ const explicitCellar = normalizePathRoot(env.HOMEBREW_CELLAR);
623
+ if (explicitCellar) {
624
+ roots.push(explicitCellar);
625
+ }
626
+ const prefixes = [
627
+ env.HOMEBREW_PREFIX,
628
+ "/opt/homebrew",
629
+ "/usr/local",
630
+ "/home/linuxbrew/.linuxbrew"
631
+ ];
632
+ for (const prefix of prefixes) {
633
+ const normalized = normalizePathRoot(prefix);
634
+ if (normalized) {
635
+ roots.push(`${normalized}/Cellar`);
636
+ }
637
+ }
638
+ return [...new Set(roots)];
639
+ }
640
+ function isKnownPnpmGlobalStore(path, env) {
641
+ return pnpmGlobalStoreRoots(env).some((root) => {
642
+ if (!isPathInsideRoot(path, root)) {
643
+ return false;
644
+ }
645
+ const relative = path.slice(root.length).replace(/^\/+/, "");
646
+ return /^\d+\/\.pnpm\//.test(relative);
647
+ });
648
+ }
649
+ function pnpmGlobalStoreRoots(env) {
650
+ const roots = [];
651
+ const home = normalizePathRoot(env.HOME ?? env.USERPROFILE);
652
+ if (home) {
653
+ roots.push(`${home}/Library/pnpm/global`);
654
+ roots.push(`${home}/.local/share/pnpm/global`);
655
+ roots.push(`${home}/AppData/Local/pnpm/global`);
656
+ }
657
+ const localAppData = normalizePathRoot(env.LOCALAPPDATA);
658
+ if (localAppData) {
659
+ roots.push(`${localAppData}/pnpm/global`);
660
+ }
661
+ return [...new Set(roots)];
662
+ }
663
+ function isKnownNpmGlobalInstall(path, env) {
664
+ return npmGlobalNodeModulesRoots(env).some((root) => isPathInsideRoot(path, root)) || isKnownVersionManagerNpmGlobal(path, env);
665
+ }
666
+ function npmGlobalNodeModulesRoots(env) {
667
+ const roots = [
668
+ "/usr/local/lib/node_modules",
669
+ "/usr/lib/node_modules",
670
+ "/opt/homebrew/lib/node_modules",
671
+ "/opt/local/lib/node_modules"
672
+ ];
673
+ const prefixes = [env.npm_config_prefix, env.NPM_CONFIG_PREFIX];
674
+ for (const prefix of prefixes) {
675
+ const normalized = normalizePathRoot(prefix);
676
+ if (normalized) {
677
+ roots.push(`${normalized}/lib/node_modules`, `${normalized}/node_modules`);
678
+ }
679
+ }
680
+ const appData = normalizePathRoot(env.APPDATA);
681
+ if (appData) {
682
+ roots.push(`${appData}/npm/node_modules`);
683
+ }
684
+ const home = normalizePathRoot(env.HOME ?? env.USERPROFILE);
685
+ if (home) {
686
+ roots.push(`${home}/.npm-global/lib/node_modules`, `${home}/.npm-packages/lib/node_modules`);
687
+ }
688
+ return [...new Set(roots)];
689
+ }
690
+ function isKnownVersionManagerNpmGlobal(path, env) {
691
+ return versionManagerNodeRoots(env).some((root) => isPathInsideRoot(path, root) && path.includes("/lib/node_modules/"));
692
+ }
693
+ function versionManagerNodeRoots(env) {
694
+ const roots = [];
695
+ const home = normalizePathRoot(env.HOME ?? env.USERPROFILE);
696
+ if (home) {
697
+ roots.push(`${home}/.nvm/versions/node`, `${home}/.local/share/fnm/node-versions`, `${home}/.asdf/installs/nodejs`, `${home}/.nodenv/versions`, `${home}/.local/share/mise/installs/node`, `${home}/.volta/tools/image/node`);
698
+ }
699
+ const nvmDir = normalizePathRoot(env.NVM_DIR);
700
+ if (nvmDir) {
701
+ roots.push(`${nvmDir}/versions/node`);
702
+ }
703
+ const fnmDir = normalizePathRoot(env.FNM_DIR);
704
+ if (fnmDir) {
705
+ roots.push(`${fnmDir}/node-versions`);
706
+ }
707
+ return [...new Set(roots)];
708
+ }
709
+ function planUpgrade(method, packageName) {
710
+ switch (method.kind) {
711
+ case "npm-global":
712
+ return {
713
+ method: method.kind,
714
+ command: `npm install -g ${packageName}@latest`,
715
+ argv: ["npm", "install", "-g", `${packageName}@latest`]
716
+ };
717
+ case "pnpm-global":
718
+ return {
719
+ method: method.kind,
720
+ command: `pnpm add -g ${packageName}@latest`,
721
+ argv: ["pnpm", "add", "-g", `${packageName}@latest`]
722
+ };
723
+ case "homebrew":
724
+ if (method.formula) {
725
+ return {
726
+ method: method.kind,
727
+ command: `brew upgrade ${method.formula}`,
728
+ argv: ["brew", "upgrade", method.formula]
729
+ };
730
+ }
731
+ return {
732
+ method: method.kind,
733
+ command: `brew upgrade ${packageName}`,
734
+ argv: null,
735
+ note: "Could not determine the Homebrew formula automatically"
736
+ };
737
+ case "npx":
738
+ return {
739
+ method: method.kind,
740
+ command: `npx -y ${packageName}@latest`,
741
+ argv: null,
742
+ note: "npx always runs the latest published version, so no install is needed"
743
+ };
744
+ case "unknown":
745
+ return {
746
+ method: method.kind,
747
+ command: `npm install -g ${packageName}@latest`,
748
+ argv: null,
749
+ note: "Could not determine how this tool was installed"
750
+ };
751
+ }
752
+ }
753
+ function packageManagerExecutable(command, platform) {
754
+ if (platform === "win32" && (command === "npm" || command === "pnpm" || command === "npx")) {
755
+ return `${command}.cmd`;
756
+ }
757
+ return command;
758
+ }
759
+ function shouldUseWindowsPackageManagerShell(command, platform) {
760
+ return platform === "win32" && (command === "npm" || command === "pnpm" || command === "npx");
761
+ }
762
+ async function npmViewVersion(packageName, platform = process.platform) {
763
+ try {
764
+ const command = packageManagerExecutable("npm", platform);
765
+ const { stdout } = await execFileAsync(command, ["view", packageName, "version"], {
766
+ timeout: 2e4,
767
+ shell: shouldUseWindowsPackageManagerShell("npm", platform)
768
+ });
769
+ const version = stdout.trim();
770
+ return version.length > 0 ? version : null;
771
+ } catch {
772
+ return null;
773
+ }
774
+ }
775
+ function registryPath(packageName) {
776
+ return packageName.startsWith("@") ? packageName.replace("/", "%2f") : packageName;
777
+ }
778
+ function notPublishedError(packageName) {
779
+ return new AxiError(`${packageName} is not published to the npm registry`, "UPDATE_ERROR", [
780
+ "Confirm the package name is correct",
781
+ `Run \`npm view ${packageName} version\` to check manually`
782
+ ]);
783
+ }
784
+ var RegistryNotFoundError = class extends Error {
785
+ };
786
+ async function withRegistryTimeout(timeoutMs, operation) {
787
+ const controller = new AbortController();
788
+ let timer;
789
+ const timeout = new Promise((_resolve, reject) => {
790
+ timer = setTimeout(() => {
791
+ controller.abort();
792
+ reject(new Error(`Registry fetch timed out after ${timeoutMs}ms`));
793
+ }, timeoutMs);
794
+ timer.unref?.();
795
+ });
796
+ try {
797
+ return await Promise.race([operation(controller.signal), timeout]);
798
+ } finally {
799
+ if (timer) {
800
+ clearTimeout(timer);
801
+ }
802
+ }
803
+ }
804
+ async function fetchRegistryVersion(fetchImpl, packageName, timeoutMs) {
805
+ return withRegistryTimeout(timeoutMs, async (signal) => {
806
+ const response = await fetchImpl(`${REGISTRY_BASE}/${registryPath(packageName)}/latest`, { headers: { accept: "application/json" }, signal });
807
+ if (response.ok) {
808
+ const data = await response.json();
809
+ if (typeof data.version === "string" && data.version.length > 0) {
810
+ return data.version;
811
+ }
812
+ } else if (response.status === 404) {
813
+ throw new RegistryNotFoundError();
814
+ }
815
+ return null;
816
+ });
817
+ }
818
+ async function fetchLatestVersion(packageName, options = {}) {
819
+ const fetchImpl = options.fetchImpl === void 0 ? globalThis.fetch : options.fetchImpl ?? void 0;
820
+ let registryNotFound = false;
821
+ if (typeof fetchImpl === "function") {
822
+ try {
823
+ const version = await fetchRegistryVersion(fetchImpl, packageName, options.fetchTimeoutMs ?? REGISTRY_FETCH_TIMEOUT_MS);
824
+ if (version) {
825
+ return version;
826
+ }
827
+ } catch (error) {
828
+ if (error instanceof RegistryNotFoundError) {
829
+ registryNotFound = true;
830
+ } else if (error instanceof AxiError) {
831
+ throw error;
832
+ }
833
+ }
834
+ }
835
+ const viewed = await (options.npmView ?? ((name) => npmViewVersion(name, options.platform)))(packageName);
836
+ if (viewed) {
837
+ return viewed;
838
+ }
839
+ if (registryNotFound) {
840
+ throw notPublishedError(packageName);
841
+ }
842
+ throw new AxiError(`Could not reach the npm registry to check for updates to ${packageName}`, "UPDATE_ERROR", [
843
+ "Check your network connection and try again",
844
+ `Run \`npm view ${packageName} version\` to check manually`
845
+ ]);
846
+ }
847
+ async function defaultRunInstall(plan, stdout, context) {
848
+ const argv = plan.argv;
849
+ if (!argv || argv.length === 0) {
850
+ return { ok: false, message: "No runnable upgrade command" };
851
+ }
852
+ stdout.write(`running: ${plan.command}
853
+ `);
854
+ return new Promise((resolve3) => {
855
+ const [command, ...args] = argv;
856
+ const child = spawn(packageManagerExecutable(command, context.platform), args, {
857
+ stdio: ["ignore", "pipe", "pipe"],
858
+ shell: shouldUseWindowsPackageManagerShell(command, context.platform)
859
+ });
860
+ child.stdout?.on("data", (chunk) => {
861
+ process.stderr.write(chunk);
862
+ });
863
+ child.stderr?.on("data", (chunk) => {
864
+ process.stderr.write(chunk);
865
+ });
866
+ child.on("error", (error) => {
867
+ resolve3({ ok: false, message: error.message });
868
+ });
869
+ child.on("close", (code) => {
870
+ resolve3(code === 0 ? { ok: true } : { ok: false, message: `${plan.command} exited with code ${code}` });
871
+ });
872
+ });
873
+ }
874
+ function binNameFromArgv(invokedAs) {
875
+ return basename(invokedAs ?? "tool") || "tool";
876
+ }
877
+ function resolveEntry(invokedAs, realpath) {
878
+ if (!invokedAs) {
879
+ return void 0;
880
+ }
881
+ try {
882
+ return realpath(invokedAs);
883
+ } catch {
884
+ return invokedAs;
885
+ }
886
+ }
887
+ function resolveInstalledVersion(invokedAs, realpath, fs) {
888
+ const installedEntry = resolveEntry(invokedAs, realpath);
889
+ return installedEntry ? readNearestPackageJson(installedEntry, fs).version : void 0;
890
+ }
891
+ function homebrewUpgradeOutput(options) {
892
+ const update = {
893
+ package: options.packageName,
894
+ previous: options.current,
895
+ latest: options.latest
896
+ };
897
+ if (options.installedVersion) {
898
+ update.installed = options.installedVersion;
899
+ update.available = isUpdateAvailable(options.installedVersion, options.latest);
900
+ } else {
901
+ update.action = "upgrade-command-ran";
902
+ update.result = "installed version unknown";
903
+ }
904
+ return {
905
+ update,
906
+ command: options.command
907
+ };
908
+ }
909
+ function parseUpdateArgs(args, binName) {
910
+ if (args.length === 0) {
911
+ return "install";
912
+ }
913
+ if (args.length === 1 && (args[0] === "--check" || args[0] === "--dry-run")) {
914
+ return "check";
915
+ }
916
+ const unknown = args.find((arg) => arg !== "--check" && arg !== "--dry-run");
917
+ throw new AxiError(unknown ? `Unknown update option: ${unknown}` : "Invalid update arguments", "VALIDATION_ERROR", [
918
+ `Run \`${binName} update --help\``,
919
+ `Use \`${binName} update --check\` to check without installing`
920
+ ]);
921
+ }
922
+ async function runUpdate(options) {
923
+ const invokedAs = options.invokedAs ?? process.argv[1];
924
+ const binName = binNameFromArgv(invokedAs);
925
+ const mode = parseUpdateArgs(options.args, binName);
926
+ const platform = options.platform ?? process.platform;
927
+ const realpath = options.realpath ?? ((path) => realpathSync(path));
928
+ const entry = resolveEntry(invokedAs, realpath);
929
+ const fs = options.fs ?? nodeFs;
930
+ const fromPackageJson = entry ? readNearestPackageJson(entry, fs) : {};
931
+ const packageName = options.packageName ?? fromPackageJson.packageName;
932
+ const current = options.version ?? fromPackageJson.version;
933
+ if (!packageName) {
934
+ throw new AxiError("Could not determine the package name to update", "UPDATE_ERROR", [
935
+ "Reinstall the tool from npm so its package.json is available",
936
+ "Tool authors can pass `packageName` to runAxiCli()"
937
+ ]);
938
+ }
939
+ if (!current) {
940
+ throw new AxiError(`Could not determine the current version of ${packageName}`, "UPDATE_ERROR", [
941
+ "Reinstall the tool from npm so its version is available",
942
+ "Tool authors can pass `version` to runAxiCli()"
943
+ ]);
944
+ }
945
+ const fetchLatest = options.fetchLatest ?? ((name) => fetchLatestVersion(name, { platform }));
946
+ const latest = await fetchLatest(packageName);
947
+ const available = isUpdateAvailable(current, latest);
948
+ if (mode === "check") {
949
+ const output = {
950
+ update: { package: packageName, current, latest, available }
951
+ };
952
+ if (available) {
953
+ output.help = [`Run \`${binName} update\` to upgrade`];
954
+ }
955
+ return output;
956
+ }
957
+ if (!available) {
958
+ return {
959
+ update: `${packageName} is already on the latest version (${current})`
960
+ };
961
+ }
962
+ const method = entry ? detectInstallMethod({ entry, env: options.env }) : { kind: "unknown" };
963
+ const plan = planUpgrade(method, packageName);
964
+ if (!plan.argv) {
965
+ const help = method.kind === "npx" ? `Re-run with \`${plan.command}\` to use the latest version` : `Run \`${plan.command}\` to upgrade`;
966
+ return {
967
+ update: {
968
+ package: packageName,
969
+ current,
970
+ latest,
971
+ available: true,
972
+ action: "manual",
973
+ ...plan.note ? { reason: plan.note } : {},
974
+ run: plan.command
975
+ },
976
+ help: [help]
977
+ };
978
+ }
979
+ const runInstall = options.runInstall ?? defaultRunInstall;
980
+ const result = await runInstall(plan, options.stdout, { platform });
981
+ if (!result.ok) {
982
+ throw new AxiError(`Failed to upgrade ${packageName}`, "UPDATE_ERROR", [
983
+ `Run \`${plan.command}\` manually`,
984
+ ...result.message ? [result.message] : []
985
+ ]);
986
+ }
987
+ if (method.kind === "homebrew") {
988
+ return homebrewUpgradeOutput({
989
+ packageName,
990
+ current,
991
+ latest,
992
+ installedVersion: resolveInstalledVersion(invokedAs, realpath, fs),
993
+ command: plan.command
994
+ });
995
+ }
996
+ return {
997
+ update: `${packageName} upgraded ${current} -> ${latest}`,
998
+ command: plan.command
999
+ };
1000
+ }
1001
+
1002
+ // ../../node_modules/axi-sdk-js/dist/cli.js
1003
+ var stdoutWithErrorHandler = /* @__PURE__ */ new WeakSet();
1004
+ function defaultFormatError(error) {
1005
+ if (error instanceof AxiError) {
1006
+ return {
1007
+ output: `${renderError(error.message, error.code, error.suggestions)}
1008
+ `,
1009
+ exitCode: exitCodeForError(error)
1010
+ };
1011
+ }
1012
+ const message = error instanceof Error ? error.message : String(error);
1013
+ return {
1014
+ output: `${renderError(message, "UNKNOWN")}
1015
+ `,
1016
+ exitCode: 1
1017
+ };
1018
+ }
1019
+ function defaultUnknownCommand(command) {
1020
+ return `${renderError(`Unknown command: ${command}`, "VALIDATION_ERROR", [
1021
+ "Run `--help` to see available commands"
1022
+ ])}
1023
+ `;
1024
+ }
1025
+ async function runAxiCli(options) {
1026
+ const stdout = options.stdout ?? process.stdout;
1027
+ handleStdoutErrors(stdout);
1028
+ try {
1029
+ await options.initialize?.();
1030
+ } catch (error) {
1031
+ writeFormattedError(error, stdout, options);
1032
+ return;
1033
+ }
1034
+ const argv = options.argv ?? process.argv.slice(2);
1035
+ if (argv.length === 1 && argv[0] === "--help") {
1036
+ stdout.write(options.topLevelHelp);
1037
+ if (!options.commands.update) {
1038
+ if (options.topLevelHelp.length > 0 && !options.topLevelHelp.endsWith("\n")) {
1039
+ stdout.write("\n");
1040
+ }
1041
+ stdout.write(builtinCommandsHelp());
1042
+ }
1043
+ return;
1044
+ }
1045
+ if (argv.length === 1 && isVersionFlag(argv[0])) {
1046
+ if (!options.version) {
1047
+ stdout.write(`${renderError("Version is not configured for this tool", "VALIDATION_ERROR")}
1048
+ `);
1049
+ process.exitCode = 2;
1050
+ return;
1051
+ }
1052
+ stdout.write(`${options.version}
1053
+ `);
1054
+ return;
1055
+ }
1056
+ const command = argv[0];
1057
+ if (!command) {
1058
+ await runHandler(options.home, [], { command: void 0, args: [] }, stdout, options, true);
1059
+ return;
1060
+ }
1061
+ if (command.startsWith("-")) {
1062
+ stdout.write(renderLeadingFlagError(command));
1063
+ process.exitCode = 2;
1064
+ return;
1065
+ }
1066
+ const args = argv.slice(1);
1067
+ if (command === "update" && !options.commands.update) {
1068
+ await runBuiltinUpdate(args, stdout, options);
1069
+ return;
1070
+ }
1071
+ if (args.includes("--help")) {
1072
+ const help = options.getCommandHelp?.(command);
1073
+ if (help) {
1074
+ stdout.write(help);
1075
+ return;
1076
+ }
1077
+ }
1078
+ const handler = options.commands[command];
1079
+ if (!handler) {
1080
+ stdout.write((options.renderUnknownCommand ?? defaultUnknownCommand)(command));
1081
+ process.exitCode = 2;
1082
+ return;
1083
+ }
1084
+ await runHandler(handler, args, { command, args }, stdout, options, false);
1085
+ }
1086
+ function handleStdoutErrors(stdout) {
1087
+ const errorObservable = stdout;
1088
+ if (typeof errorObservable.on !== "function" || stdoutWithErrorHandler.has(stdout)) {
1089
+ return;
1090
+ }
1091
+ stdoutWithErrorHandler.add(stdout);
1092
+ errorObservable.on("error", (error) => {
1093
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "EPIPE") {
1094
+ process.exitCode = 0;
1095
+ return;
1096
+ }
1097
+ throw error;
1098
+ });
1099
+ }
1100
+ async function runHandler(handler, args, contextInput, stdout, options, isHomeView) {
1101
+ try {
1102
+ const context = await options.resolveContext?.(contextInput);
1103
+ const output = await handler(args, context);
1104
+ stdout.write(`${renderCommandOutput(output, options, isHomeView)}
1105
+ `);
1106
+ } catch (error) {
1107
+ writeFormattedError(error, stdout, options);
1108
+ }
1109
+ }
1110
+ async function runBuiltinUpdate(args, stdout, options) {
1111
+ if (args.length === 1 && args[0] === "--help") {
1112
+ stdout.write(builtinUpdateHelp());
1113
+ return;
1114
+ }
1115
+ try {
1116
+ const output = await runUpdate({
1117
+ args,
1118
+ stdout,
1119
+ packageName: options.packageName,
1120
+ version: options.version
1121
+ });
1122
+ stdout.write(`${renderOutput(output)}
1123
+ `);
1124
+ } catch (error) {
1125
+ writeFormattedError(error, stdout, options);
1126
+ }
1127
+ }
1128
+ function writeFormattedError(error, stdout, options) {
1129
+ const formatted = (options.formatError ?? defaultFormatError)(error);
1130
+ stdout.write(formatted.output);
1131
+ process.exitCode = formatted.exitCode;
1132
+ }
1133
+ function resolveBinName() {
1134
+ return basename2(process.argv[1] ?? "tool") || "tool";
1135
+ }
1136
+ function builtinCommandsHelp() {
1137
+ const bin = resolveBinName();
1138
+ return `${renderOutput({
1139
+ "built-in": {
1140
+ update: `Upgrade \`${bin}\` to the latest published version`,
1141
+ "update --check": "Report current vs latest without installing"
1142
+ }
1143
+ })}
1144
+ `;
1145
+ }
1146
+ function builtinUpdateHelp() {
1147
+ const bin = resolveBinName();
1148
+ return `${renderOutput({
1149
+ command: "update",
1150
+ description: `Upgrade \`${bin}\` to the latest published npm version`,
1151
+ flags: {
1152
+ "--check": "Report current vs latest and exit without installing"
1153
+ },
1154
+ examples: [`${bin} update`, `${bin} update --check`]
1155
+ })}
1156
+ `;
1157
+ }
1158
+ function renderLeadingFlagError(flag) {
1159
+ const bin = basename2(process.argv[1] ?? "tool") || "tool";
1160
+ return `${renderError("Flags must come after the command", "VALIDATION_ERROR", [
1161
+ `Run \`${bin} <command> [args] [flags]\``,
1162
+ `Move \`${flag}\` after the command instead of before it`
1163
+ ])}
1164
+ `;
1165
+ }
1166
+ function isVersionFlag(flag) {
1167
+ return flag === "-v" || flag === "-V" || flag === "--version";
1168
+ }
1169
+ function renderCommandOutput(output, options, isHomeView) {
1170
+ if (!isHomeView) {
1171
+ return renderOutput(output);
1172
+ }
1173
+ const header = homeHeaderOutput({ description: options.description });
1174
+ if (typeof output === "string") {
1175
+ return `${renderOutput(header)}
1176
+ ${output}`;
1177
+ }
1178
+ return renderOutput(mergeHomeHeader(header, output));
1179
+ }
1180
+ function mergeHomeHeader(header, output) {
1181
+ const rest = { ...output };
1182
+ delete rest.bin;
1183
+ delete rest.description;
1184
+ return {
1185
+ ...header,
1186
+ ...rest
1187
+ };
1188
+ }
1189
+
1190
+ // ../../node_modules/axi-sdk-js/dist/hooks.js
1191
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, realpathSync as realpathSync2, rmSync, statSync, writeFileSync } from "node:fs";
1192
+ import { homedir as homedir2 } from "node:os";
1193
+ import { basename as basename3, delimiter, dirname as dirname2, join as join2, resolve } from "node:path";
1194
+ var OPENCODE_PLUGIN_MANAGED_PREFIX = "axi-sdk-js managed opencode plugin:";
1195
+ function isManagedHook(hook, marker) {
1196
+ return typeof hook?.command === "string" && hook.command.includes(marker);
1197
+ }
1198
+ function computeSessionStartHookUpdate(settings, spec) {
1199
+ const updated = structuredClone(settings);
1200
+ let changed = false;
1201
+ if (!updated.hooks) {
1202
+ updated.hooks = {};
1203
+ changed = true;
1204
+ }
1205
+ if (Array.isArray(updated.hooks.session_start)) {
1206
+ const legacyHooks = updated.hooks.session_start.filter((hook) => !isManagedHook(hook, spec.marker));
1207
+ if (legacyHooks.length !== updated.hooks.session_start.length) {
1208
+ changed = true;
1209
+ if (legacyHooks.length === 0) {
1210
+ delete updated.hooks.session_start;
1211
+ } else {
1212
+ updated.hooks.session_start = legacyHooks;
1213
+ }
1214
+ }
1215
+ }
1216
+ if (!Array.isArray(updated.hooks.SessionStart)) {
1217
+ updated.hooks.SessionStart = [];
1218
+ changed = true;
1219
+ }
1220
+ for (const group of updated.hooks.SessionStart) {
1221
+ if (!Array.isArray(group.hooks)) {
1222
+ continue;
1223
+ }
1224
+ for (const hook of group.hooks) {
1225
+ if (!isManagedHook(hook, spec.marker)) {
1226
+ continue;
1227
+ }
1228
+ const timeout = spec.timeoutSeconds ?? 10;
1229
+ const isCorrect = hook.command === spec.command && hook.type === "command" && hook.timeout === timeout;
1230
+ if (isCorrect && !changed) {
1231
+ return [settings, false];
1232
+ }
1233
+ hook.command = spec.command;
1234
+ hook.type = "command";
1235
+ hook.timeout = timeout;
1236
+ return [updated, true];
1237
+ }
1238
+ }
1239
+ updated.hooks.SessionStart.push({
1240
+ matcher: "",
1241
+ hooks: [
1242
+ {
1243
+ type: "command",
1244
+ command: spec.command,
1245
+ timeout: spec.timeoutSeconds ?? 10
1246
+ }
1247
+ ]
1248
+ });
1249
+ return [updated, true];
1250
+ }
1251
+ function computeCodexConfigUpdate(content) {
1252
+ const newline = content.includes("\r\n") ? "\r\n" : "\n";
1253
+ const normalized = content.length === 0 ? "" : content;
1254
+ if (normalized.trim().length === 0) {
1255
+ return [`[features]${newline}hooks = true${newline}`, true];
1256
+ }
1257
+ const lines = normalized.split(/\r?\n/);
1258
+ const updated = [...lines];
1259
+ let inFeatures = false;
1260
+ let sawFeatures = false;
1261
+ for (let index = 0; index < updated.length; index++) {
1262
+ const line = updated[index];
1263
+ const section = line.match(/^\s*(\[{1,2})([^\]]+)(\]{1,2})\s*(?:#.*)?$/);
1264
+ if (section) {
1265
+ const isTableHeader = section[1] === "[" && section[3] === "]" || section[1] === "[[" && section[3] === "]]";
1266
+ if (!isTableHeader) {
1267
+ continue;
1268
+ }
1269
+ const sectionName = section[2].trim();
1270
+ if (inFeatures) {
1271
+ updated.splice(index, 0, "hooks = true");
1272
+ return [updated.join(newline), true];
1273
+ }
1274
+ inFeatures = sectionName === "features";
1275
+ sawFeatures ||= inFeatures;
1276
+ continue;
1277
+ }
1278
+ if (!inFeatures) {
1279
+ continue;
1280
+ }
1281
+ const flag = line.match(/^\s*hooks\s*=\s*(true|false)\s*(?:#.*)?$/);
1282
+ if (!flag) {
1283
+ continue;
1284
+ }
1285
+ if (flag[1] === "true") {
1286
+ return [content, false];
1287
+ }
1288
+ updated[index] = line.replace(/false/, "true");
1289
+ return [updated.join(newline), true];
1290
+ }
1291
+ if (sawFeatures) {
1292
+ const suffix = normalized.endsWith(newline) ? "" : newline;
1293
+ return [`${normalized}${suffix}hooks = true${newline}`, true];
1294
+ }
1295
+ const separator = normalized.endsWith(newline) ? newline : `${newline}${newline}`;
1296
+ return [
1297
+ `${normalized}${separator}[features]${newline}hooks = true${newline}`,
1298
+ true
1299
+ ];
1300
+ }
1301
+ function sanitizeOpenCodePluginFilePart(marker) {
1302
+ return marker.replace(/[^A-Za-z0-9._-]+/g, "_");
1303
+ }
1304
+ function sanitizeOpenCodeExportName(marker) {
1305
+ const name = marker.split(/[^A-Za-z0-9]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join("");
1306
+ return `Axi${name || "Plugin"}AmbientContextPlugin`;
1307
+ }
1308
+ function buildOpenCodeAmbientPluginSource(marker, command, timeoutSeconds) {
1309
+ const exportName = sanitizeOpenCodeExportName(marker);
1310
+ const managedMarker = `${OPENCODE_PLUGIN_MANAGED_PREFIX} ${marker}`;
1311
+ return `// ${managedMarker}
1312
+ // This file is generated by axi-sdk-js. It is safe to edit only if you remove the managed marker above.
1313
+ import { spawn } from "node:child_process";
1314
+
1315
+ const command = ${JSON.stringify(command)};
1316
+ const marker = ${JSON.stringify(marker)};
1317
+ const ambientHeader = ${JSON.stringify(`## AXI ambient context: ${marker}`)};
1318
+ const timeoutMs = ${JSON.stringify(timeoutSeconds * 1e3)};
1319
+
1320
+ function runAxiHomeView(cwd) {
1321
+ return new Promise((resolve) => {
1322
+ const child = spawn(command, [], {
1323
+ cwd: directoryOrFallback(cwd),
1324
+ env: process.env,
1325
+ shell: false,
1326
+ stdio: ["ignore", "pipe", "pipe"],
1327
+ });
1328
+
1329
+ let stdout = "";
1330
+ let stderr = "";
1331
+ let settled = false;
1332
+
1333
+ const timer = setTimeout(() => {
1334
+ if (settled) return;
1335
+ settled = true;
1336
+ child.kill("SIGTERM");
1337
+ resolve("error: " + marker + " ambient context timed out after " + timeoutMs + "ms");
1338
+ }, timeoutMs);
1339
+
1340
+ child.stdout?.setEncoding("utf-8");
1341
+ child.stderr?.setEncoding("utf-8");
1342
+ child.stdout?.on("data", (chunk) => {
1343
+ stdout += chunk;
1344
+ });
1345
+ child.stderr?.on("data", (chunk) => {
1346
+ stderr += chunk;
1347
+ });
1348
+ child.on("error", (error) => {
1349
+ if (settled) return;
1350
+ settled = true;
1351
+ clearTimeout(timer);
1352
+ resolve("error: " + marker + " ambient context failed: " + error.message);
1353
+ });
1354
+ child.on("close", (code) => {
1355
+ if (settled) return;
1356
+ settled = true;
1357
+ clearTimeout(timer);
1358
+ if (code === 0) {
1359
+ resolve(stdout.trim());
1360
+ return;
1361
+ }
1362
+ const message = (stderr || stdout || marker + " exited with code " + code).trim();
1363
+ resolve("error: " + marker + " ambient context failed: " + message);
1364
+ });
1365
+ });
1366
+ }
1367
+
1368
+ function directoryOrFallback(directory) {
1369
+ return typeof directory === "string" && directory.length > 0
1370
+ ? directory
1371
+ : process.cwd();
1372
+ }
1373
+
1374
+ export const ${exportName} = async ({ directory }) => {
1375
+ const sessionCache = new Map();
1376
+
1377
+ return {
1378
+ "experimental.chat.system.transform": async (input, output) => {
1379
+ const sessionID = input.sessionID ?? "__global__";
1380
+ let homeView = sessionCache.get(sessionID);
1381
+ if (homeView === undefined) {
1382
+ homeView = await runAxiHomeView(directory);
1383
+ sessionCache.set(sessionID, homeView);
1384
+ }
1385
+
1386
+ if (homeView.length === 0) return;
1387
+ output.system.push(ambientHeader + "\\n" + homeView);
1388
+ },
1389
+ };
1390
+ };
1391
+ `;
1392
+ }
1393
+ function openCodePluginFileName(marker) {
1394
+ return `axi-${sanitizeOpenCodePluginFilePart(marker)}.js`;
1395
+ }
1396
+ function openCodePluginDir(scope, home, root) {
1397
+ return scope === "project" ? join2(root, ".opencode", "plugins") : join2(home, ".config", "opencode", "plugins");
1398
+ }
1399
+ function resolveHookScopeTargets(marker, options) {
1400
+ const home = options.homeDir ?? homedir2();
1401
+ const scope = options.scope ?? "user";
1402
+ const root = scope === "project" ? resolve(options.projectDir ?? process.cwd()) : home;
1403
+ return {
1404
+ scope,
1405
+ home,
1406
+ root,
1407
+ claudeSettingsPath: join2(root, ".claude", "settings.json"),
1408
+ codexHooksPath: join2(root, ".codex", "hooks.json"),
1409
+ codexConfigPath: join2(home, ".codex", "config.toml"),
1410
+ openCodePluginPath: join2(openCodePluginDir(scope, home, root), openCodePluginFileName(marker))
1411
+ };
1412
+ }
1413
+ function installOpenCodeAmbientPlugin(pluginPath, marker, command, timeoutSeconds, onError) {
1414
+ const managedMarker = `${OPENCODE_PLUGIN_MANAGED_PREFIX} ${marker}`;
1415
+ const next = buildOpenCodeAmbientPluginSource(marker, command, timeoutSeconds);
1416
+ try {
1417
+ mkdirSync(dirname2(pluginPath), { recursive: true });
1418
+ const current = existsSync2(pluginPath) ? readFileSync2(pluginPath, "utf-8") : void 0;
1419
+ if (current !== void 0 && !current.includes(managedMarker)) {
1420
+ onError?.(`${pluginPath}: refusing to overwrite unmanaged OpenCode plugin`);
1421
+ return;
1422
+ }
1423
+ if (current !== next) {
1424
+ writeFileSync(pluginPath, next, "utf-8");
1425
+ }
1426
+ } catch (error) {
1427
+ const message = error instanceof Error ? error.message : String(error);
1428
+ onError?.(`${pluginPath}: ${message}`);
1429
+ }
1430
+ }
1431
+ function resolvePortableHookCommand(execPath, binaryNames, marker, context) {
1432
+ if (binaryNames.length === 0) {
1433
+ return execPath;
1434
+ }
1435
+ const resolvedExec = context.resolveRealPath(execPath);
1436
+ if (!resolvedExec) {
1437
+ return execPath;
1438
+ }
1439
+ for (const name of binaryNames) {
1440
+ if (!name.includes(marker)) {
1441
+ continue;
1442
+ }
1443
+ for (const dir of context.pathEntries) {
1444
+ if (!dir)
1445
+ continue;
1446
+ for (const ext of context.pathExtensions) {
1447
+ const candidate = join2(dir, `${name}${ext}`);
1448
+ const resolvedCandidate = context.resolveRealPath(candidate);
1449
+ if (resolvedCandidate && resolvedCandidate === resolvedExec) {
1450
+ return name;
1451
+ }
1452
+ const shimTarget = context.resolveShimTarget?.(candidate);
1453
+ if (shimTarget && shimTarget === resolvedExec) {
1454
+ return name;
1455
+ }
1456
+ }
1457
+ }
1458
+ }
1459
+ return execPath;
1460
+ }
1461
+ var NPM_SHIM_SCRIPT_PATTERNS = [
1462
+ // Git Bash / POSIX shim: exec node "$basedir/node_modules/<pkg>/.../cli.js"
1463
+ /"\$basedir\/([^"]+\.[cm]?js)"/,
1464
+ // Windows .cmd shim: "%dp0%\node_modules\<pkg>\...\cli.js"
1465
+ /%~?dp0%?[\\/]([^"\r\n]+\.[cm]?js)/i
1466
+ ];
1467
+ function extractNpmShimScriptPath(content) {
1468
+ for (const pattern of NPM_SHIM_SCRIPT_PATTERNS) {
1469
+ const match = content.match(pattern);
1470
+ if (match?.[1]) {
1471
+ return match[1];
1472
+ }
1473
+ }
1474
+ return void 0;
1475
+ }
1476
+ function buildDefaultPortableCommandContext() {
1477
+ const rawPath = process.env.PATH ?? process.env.Path ?? "";
1478
+ const pathEntries = rawPath.split(delimiter).filter(Boolean);
1479
+ const pathExtensions = process.platform === "win32" ? (
1480
+ // Git Bash resolves the extensionless shim, which PATHEXT omits.
1481
+ ["", ...(process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";")]
1482
+ ) : [""];
1483
+ return {
1484
+ pathEntries,
1485
+ pathExtensions,
1486
+ resolveRealPath: (absolutePath) => {
1487
+ try {
1488
+ const stat = statSync(absolutePath);
1489
+ if (!stat.isFile()) {
1490
+ return void 0;
1491
+ }
1492
+ return realpathSync2(absolutePath);
1493
+ } catch {
1494
+ return void 0;
1495
+ }
1496
+ },
1497
+ resolveShimTarget: (shimPath) => {
1498
+ try {
1499
+ const relative = extractNpmShimScriptPath(readFileSync2(shimPath, "utf-8"));
1500
+ if (!relative) {
1501
+ return void 0;
1502
+ }
1503
+ return realpathSync2(resolve(dirname2(shimPath), relative));
1504
+ } catch {
1505
+ return void 0;
1506
+ }
1507
+ }
1508
+ };
1509
+ }
1510
+ function shouldInstallHooksForNodeAxiExecPath(execPath, policy) {
1511
+ const normalized = resolve(execPath).replaceAll("\\", "/");
1512
+ if (!normalized.includes(policy.marker) || normalized.endsWith(".ts")) {
1513
+ return false;
1514
+ }
1515
+ const fileName = basename3(normalized);
1516
+ if (policy.binaryNames?.includes(fileName)) {
1517
+ return true;
1518
+ }
1519
+ return policy.distEntrypoints?.some((entrypoint) => normalized.endsWith(entrypoint.replaceAll("\\", "/"))) ?? false;
1520
+ }
1521
+ function inferHookOptions(execPath) {
1522
+ if (!execPath) {
1523
+ return void 0;
1524
+ }
1525
+ const normalized = execPath.replaceAll("\\", "/");
1526
+ const match = normalized.match(/(?:^|\/)dist\/bin\/([^/]+)\.js$/);
1527
+ if (match?.[1]) {
1528
+ const marker = match[1];
1529
+ return {
1530
+ execPath,
1531
+ marker,
1532
+ binaryNames: [marker],
1533
+ distEntrypoints: [`dist/bin/${marker}.js`]
1534
+ };
1535
+ }
1536
+ const fileName = normalized.split("/").pop() ?? "";
1537
+ if (!fileName || fileName.includes(".") || fileName === "node") {
1538
+ return void 0;
1539
+ }
1540
+ return {
1541
+ execPath,
1542
+ marker: fileName,
1543
+ binaryNames: [fileName],
1544
+ distEntrypoints: [`dist/bin/${fileName}.js`]
1545
+ };
1546
+ }
1547
+ function buildInferredHookInstallPolicy(marker, options, inferred) {
1548
+ const binaryNames = options.binaryNames ?? inferred.binaryNames;
1549
+ const distEntrypoints = options.distEntrypoints ?? inferred.distEntrypoints;
1550
+ return (execPath) => shouldInstallHooksForNodeAxiExecPath(execPath, {
1551
+ marker,
1552
+ binaryNames,
1553
+ distEntrypoints
1554
+ });
1555
+ }
1556
+ function installSessionStartHooks(options = {}) {
1557
+ const inferred = inferHookOptions(options.execPath ?? process.argv[1]);
1558
+ const marker = options.marker ?? inferred?.marker;
1559
+ if (!marker) {
1560
+ return;
1561
+ }
1562
+ const execPath = resolve(options.execPath ?? inferred?.execPath ?? process.argv[1] ?? "");
1563
+ if (!execPath) {
1564
+ return;
1565
+ }
1566
+ const defaultPolicyOptions = inferred ?? {
1567
+ execPath,
1568
+ marker,
1569
+ binaryNames: [marker],
1570
+ distEntrypoints: [`dist/bin/${marker}.js`]
1571
+ };
1572
+ const shouldInstall = options.shouldInstall ?? buildInferredHookInstallPolicy(marker, options, defaultPolicyOptions);
1573
+ if (shouldInstall && !shouldInstall(execPath)) {
1574
+ return;
1575
+ }
1576
+ const binaryNames = options.binaryNames ?? inferred?.binaryNames ?? [];
1577
+ const command = resolvePortableHookCommand(execPath, binaryNames, marker, buildDefaultPortableCommandContext());
1578
+ const targets = resolveHookScopeTargets(marker, options);
1579
+ const jsonTargets = [targets.claudeSettingsPath, targets.codexHooksPath];
1580
+ const codexConfigPath = targets.codexConfigPath;
1581
+ installOpenCodeAmbientPlugin(targets.openCodePluginPath, marker, command, options.timeoutSeconds ?? 10, options.onError);
1582
+ for (const target of jsonTargets) {
1583
+ try {
1584
+ mkdirSync(dirname2(target), { recursive: true });
1585
+ const current = existsSync2(target) ? JSON.parse(readFileSync2(target, "utf-8")) : {};
1586
+ const [updated, changed] = computeSessionStartHookUpdate(current, {
1587
+ marker,
1588
+ command,
1589
+ timeoutSeconds: options.timeoutSeconds
1590
+ });
1591
+ if (changed) {
1592
+ writeFileSync(target, `${JSON.stringify(updated, null, 2)}
1593
+ `, "utf-8");
1594
+ }
1595
+ } catch (error) {
1596
+ const message = error instanceof Error ? error.message : String(error);
1597
+ options.onError?.(`${target}: ${message}`);
1598
+ }
1599
+ }
1600
+ try {
1601
+ mkdirSync(dirname2(codexConfigPath), { recursive: true });
1602
+ const current = existsSync2(codexConfigPath) ? readFileSync2(codexConfigPath, "utf-8") : "";
1603
+ const [updated, changed] = computeCodexConfigUpdate(current);
1604
+ if (changed) {
1605
+ writeFileSync(codexConfigPath, updated, "utf-8");
1606
+ }
1607
+ } catch (error) {
1608
+ const message = error instanceof Error ? error.message : String(error);
1609
+ options.onError?.(`${codexConfigPath}: ${message}`);
1610
+ }
1611
+ }
1612
+
1613
+ // vendor/chrome-devtools-axi/src/client.ts
1614
+ import { execFileSync, spawn as spawn2 } from "node:child_process";
1615
+ import { readFileSync as readFileSync3, existsSync as existsSync3 } from "node:fs";
1616
+ import { request } from "node:http";
1617
+ import { dirname as dirname3 } from "node:path";
1618
+
1619
+ // vendor/chrome-devtools-axi/src/pages.ts
1620
+ var PAGE_SCOPED_TOOLS = /* @__PURE__ */ new Set([
1621
+ "click",
1622
+ "drag",
1623
+ "emulate",
1624
+ "evaluate_script",
1625
+ "fill",
1626
+ "fill_form",
1627
+ "get_console_message",
1628
+ "get_network_request",
1629
+ "handle_dialog",
1630
+ "hover",
1631
+ "lighthouse_audit",
1632
+ "list_console_messages",
1633
+ "list_network_requests",
1634
+ "navigate_page",
1635
+ "performance_analyze_insight",
1636
+ "performance_start_trace",
1637
+ "performance_stop_trace",
1638
+ "press_key",
1639
+ "resize_page",
1640
+ "take_heapsnapshot",
1641
+ "take_screenshot",
1642
+ "take_snapshot",
1643
+ "type_text",
1644
+ "upload_file",
1645
+ "wait_for"
1646
+ ]);
1647
+ function needsPageId(name, args = {}) {
1648
+ if (typeof args.pageId === "number") return false;
1649
+ if (name === "evaluate_script" && typeof args.serviceWorkerId === "string" && args.serviceWorkerId.length > 0) {
1650
+ return false;
1651
+ }
1652
+ return PAGE_SCOPED_TOOLS.has(name);
1653
+ }
1654
+ var GENERIC_SCHEME_SLASH_URL = /^[a-z][a-z0-9+.-]*:\/\//i;
1655
+ var COLON_ONLY_SCHEME_URL = /^(?:about:|data:|view-source:|blob:)/i;
1656
+ function isPageSchemeUrl(label) {
1657
+ return GENERIC_SCHEME_SLASH_URL.test(label) || COLON_ONLY_SCHEME_URL.test(label);
1658
+ }
1659
+ var MCP_SECTION_HEADER = /^##\s+(Pages|Extension Pages|Extension Service Workers|Third-party developer tools|WebMCP tools)$/;
1660
+ var PAGE_ID_LINE = /^\d+:(?:\s+|$)/;
1661
+ var OPEN_DIALOG_HEADER = /^# Open dialog$/;
1662
+ var HANDLE_DIALOG_FOOTER = /^Call handle_dialog to handle it before continuing\.$/;
1663
+ function stripTrailingIsolatedContext(label) {
1664
+ const match = label.match(/^(.*)\s+isolatedContext=.*$/);
1665
+ if (!match) return label;
1666
+ const before = match[1];
1667
+ const withoutSelected = before.replace(/\s*\[selected\]\s*$/, "").trimEnd();
1668
+ if (matchTrailingUrl(withoutSelected) !== null) return before;
1669
+ if (isPageSchemeUrl(withoutSelected)) return before;
1670
+ return label;
1671
+ }
1672
+ function stripPageSuffixes(rest) {
1673
+ let label = stripTrailingIsolatedContext(rest);
1674
+ if (/(?:^|\s)\[selected\]\s*$/.test(label)) {
1675
+ label = label.replace(/\s*\[selected\]\s*$/, "").trimEnd();
1676
+ }
1677
+ return label;
1678
+ }
1679
+ function matchTrailingUrl(label) {
1680
+ const trimmed = label.trimEnd();
1681
+ if (!trimmed.endsWith(")")) return null;
1682
+ const close = trimmed.length - 1;
1683
+ let from = close;
1684
+ while (from > 0) {
1685
+ const open = trimmed.lastIndexOf(" (", from - 1);
1686
+ if (open === -1) return null;
1687
+ const url = trimmed.slice(open + 2, close);
1688
+ if (isPageSchemeUrl(url)) {
1689
+ return { title: trimmed.slice(0, open), url };
1690
+ }
1691
+ from = open;
1692
+ }
1693
+ return null;
1694
+ }
1695
+ function hasSchemeUrl(label) {
1696
+ const rest = stripPageSuffixes(label);
1697
+ return matchTrailingUrl(rest) !== null || isPageSchemeUrl(rest);
1698
+ }
1699
+ function isCompletePageRow(row) {
1700
+ return hasSchemeUrl(row.replace(/^\d+:\s*/, ""));
1701
+ }
1702
+ function isTitleContinuationLine(line) {
1703
+ const m = line.match(/^(\d+):\s+(.+)$/);
1704
+ if (!m) return false;
1705
+ const rest = stripPageSuffixes(m[2]);
1706
+ if (matchTrailingUrl(rest) !== null) return false;
1707
+ if (isPageSchemeUrl(rest)) return false;
1708
+ return /(?:^|\s)\[selected\]\s*$/.test(stripTrailingIsolatedContext(m[2]));
1709
+ }
1710
+ function extractPageUrl(label) {
1711
+ const match = matchTrailingUrl(label);
1712
+ return match ? match.url : label.trim();
1713
+ }
1714
+ function pageRowRest(row) {
1715
+ return stripPageSuffixes(row.replace(/^\d+:\s*/, ""));
1716
+ }
1717
+ function stripDialogPreamble(text) {
1718
+ const lines = text.split(/\r?\n/);
1719
+ const kept = [];
1720
+ for (let i = 0; i < lines.length; ) {
1721
+ if (OPEN_DIALOG_HEADER.test(lines[i].trim())) {
1722
+ let end = -1;
1723
+ for (let idx = i + 1; idx < lines.length; idx++) {
1724
+ if (HANDLE_DIALOG_FOOTER.test(lines[idx].trim())) end = idx;
1725
+ }
1726
+ if (end !== -1) {
1727
+ i = end + 1;
1728
+ continue;
1729
+ }
1730
+ }
1731
+ kept.push(lines[i]);
1732
+ i++;
1733
+ }
1734
+ return kept.join("\n");
1735
+ }
1736
+ function followingLinesCompleteTitle(rawLines, headerIndex, currentRow) {
1737
+ let acc = `${currentRow} ## Pages`;
1738
+ for (let i = headerIndex + 1; i < rawLines.length; i++) {
1739
+ const next = rawLines[i].trim();
1740
+ if (next.length === 0) continue;
1741
+ if (next.match(MCP_SECTION_HEADER) !== null) return false;
1742
+ if (PAGE_ID_LINE.test(next)) {
1743
+ const rest = stripPageSuffixes(next.replace(/^\d+:\s*/, ""));
1744
+ if (isPageSchemeUrl(rest) && matchTrailingUrl(rest) === null) {
1745
+ return false;
1746
+ }
1747
+ }
1748
+ acc += ` ${next}`;
1749
+ if (matchTrailingUrl(pageRowRest(acc)) !== null) return true;
1750
+ }
1751
+ return false;
1752
+ }
1753
+ function collapsePageRows(text) {
1754
+ const rows = [];
1755
+ let inPageBlock = false;
1756
+ const rawLines = stripDialogPreamble(text).split(/\r?\n/);
1757
+ for (let index = 0; index < rawLines.length; index++) {
1758
+ const line = rawLines[index].trim();
1759
+ if (line.length === 0) continue;
1760
+ const section = line.match(MCP_SECTION_HEADER)?.[1];
1761
+ if (section !== void 0) {
1762
+ const prev = rows[rows.length - 1];
1763
+ if (section === "Pages" && inPageBlock && prev !== void 0 && !isCompletePageRow(prev) && followingLinesCompleteTitle(rawLines, index, prev)) {
1764
+ rows[rows.length - 1] += ` ${line}`;
1765
+ continue;
1766
+ }
1767
+ if (section === "Pages") {
1768
+ rows.length = 0;
1769
+ inPageBlock = true;
1770
+ } else if (section === "Extension Pages") {
1771
+ inPageBlock = true;
1772
+ } else {
1773
+ inPageBlock = false;
1774
+ }
1775
+ continue;
1776
+ }
1777
+ if (!inPageBlock) continue;
1778
+ if (PAGE_ID_LINE.test(line)) {
1779
+ const prev = rows[rows.length - 1];
1780
+ if (prev !== void 0 && (!isCompletePageRow(prev) || isTitleContinuationLine(line))) {
1781
+ rows[rows.length - 1] += ` ${line}`;
1782
+ } else {
1783
+ rows.push(line);
1784
+ }
1785
+ continue;
1786
+ }
1787
+ if (rows.length > 0) {
1788
+ rows[rows.length - 1] += ` ${line}`;
1789
+ }
1790
+ }
1791
+ return rows.map((row) => row.replace(/\s+/g, " "));
1792
+ }
1793
+ function parsePagesList(text) {
1794
+ const pages = [];
1795
+ for (const line of collapsePageRows(text)) {
1796
+ const m = line.match(/^(\d+):\s+(.+)$/);
1797
+ if (!m) continue;
1798
+ const id = Number.parseInt(m[1], 10);
1799
+ let rest = stripTrailingIsolatedContext(m[2]);
1800
+ const selected = /(?:^|\s)\[selected\]\s*$/.test(rest);
1801
+ if (selected) {
1802
+ rest = rest.replace(/\s*\[selected\]\s*$/, "").trimEnd();
1803
+ }
1804
+ const url = extractPageUrl(rest);
1805
+ pages.push({ id, url, selected });
1806
+ }
1807
+ return pages;
1808
+ }
1809
+
1810
+ // vendor/chrome-devtools-axi/src/client.ts
1811
+ var DEFAULT_BRIDGE_TIMEOUT_MS = 3e4;
1812
+ var MIN_BRIDGE_TIMEOUT_MS = 1e3;
1813
+ var HEALTH_TIMEOUT_MS = 2e3;
1814
+ var DEEP_HEALTH_TIMEOUT_MS = 5e3;
1815
+ function resolveBridgeTimeoutMs() {
1816
+ const raw = process.env.CHROME_DEVTOOLS_AXI_BRIDGE_TIMEOUT_MS;
1817
+ if (!raw) return DEFAULT_BRIDGE_TIMEOUT_MS;
1818
+ const parsed = Number.parseInt(raw, 10);
1819
+ if (Number.isNaN(parsed) || parsed <= 0) return DEFAULT_BRIDGE_TIMEOUT_MS;
1820
+ return Math.max(parsed, MIN_BRIDGE_TIMEOUT_MS);
1821
+ }
1822
+ var CdpError = class extends AxiError {
1823
+ constructor(message, code, suggestions = []) {
1824
+ super(message, code, suggestions);
1825
+ this.code = code;
1826
+ this.suggestions = suggestions;
1827
+ this.name = "CdpError";
1828
+ }
1829
+ code;
1830
+ suggestions;
1831
+ };
1832
+ function readPidFile(pidFile = resolveSessionPidFile()) {
1833
+ try {
1834
+ if (!existsSync3(pidFile)) return null;
1835
+ const data = JSON.parse(readFileSync3(pidFile, "utf-8"));
1836
+ if (typeof data.pid === "number" && typeof data.port === "number") {
1837
+ return data;
1838
+ }
1839
+ return null;
1840
+ } catch {
1841
+ return null;
1842
+ }
1843
+ }
1844
+ function isProcessAlive(pid) {
1845
+ try {
1846
+ process.kill(pid, 0);
1847
+ return true;
1848
+ } catch {
1849
+ return false;
1850
+ }
1851
+ }
1852
+ function httpGet(port, path, timeoutMs = 2e3) {
1853
+ return new Promise((resolve3, reject) => {
1854
+ const req = request(
1855
+ { hostname: "127.0.0.1", port, path, method: "GET", timeout: timeoutMs },
1856
+ (res) => {
1857
+ res.setEncoding("utf8");
1858
+ let data = "";
1859
+ res.on("data", (chunk) => data += chunk);
1860
+ res.on("end", () => resolve3(data));
1861
+ }
1862
+ );
1863
+ req.on("error", reject);
1864
+ req.on("timeout", () => {
1865
+ req.destroy();
1866
+ reject(new Error("timeout"));
1867
+ });
1868
+ req.end();
1869
+ });
1870
+ }
1871
+ function httpPost(port, path, body, timeoutMs = 12e4) {
1872
+ return new Promise((resolve3, reject) => {
1873
+ const payload = JSON.stringify(body);
1874
+ const req = request(
1875
+ {
1876
+ hostname: "127.0.0.1",
1877
+ port,
1878
+ path,
1879
+ method: "POST",
1880
+ timeout: timeoutMs,
1881
+ headers: {
1882
+ "Content-Type": "application/json",
1883
+ "Content-Length": Buffer.byteLength(payload)
1884
+ }
1885
+ },
1886
+ (res) => {
1887
+ res.setEncoding("utf8");
1888
+ let data = "";
1889
+ res.on("data", (chunk) => data += chunk);
1890
+ res.on("end", () => {
1891
+ if (res.statusCode && res.statusCode >= 400) {
1892
+ reject(new Error(data));
1893
+ } else {
1894
+ resolve3(data);
1895
+ }
1896
+ });
1897
+ }
1898
+ );
1899
+ req.on("error", reject);
1900
+ req.on("timeout", () => {
1901
+ req.destroy();
1902
+ reject(new Error("timeout"));
1903
+ });
1904
+ req.write(payload);
1905
+ req.end();
1906
+ });
1907
+ }
1908
+ async function checkBridgeHealth(port, opts = {}) {
1909
+ try {
1910
+ const path = opts.deep ? "/health?deep=1" : "/health";
1911
+ const timeoutMs = opts.deep ? DEEP_HEALTH_TIMEOUT_MS : HEALTH_TIMEOUT_MS;
1912
+ const resp = await httpGet(port, path, timeoutMs);
1913
+ const data = JSON.parse(resp);
1914
+ if (data.status !== "ok") return false;
1915
+ if (opts.expectedSession !== void 0 && typeof data.session === "string" && data.session !== opts.expectedSession) {
1916
+ return false;
1917
+ }
1918
+ if (opts.deep && opts.notice) {
1919
+ opts.notice.pageIdentityChanged = data.pageIdentityChanged === true;
1920
+ }
1921
+ return true;
1922
+ } catch {
1923
+ return false;
1924
+ }
1925
+ }
1926
+ function sleep(ms) {
1927
+ return new Promise((r) => setTimeout(r, ms));
1928
+ }
1929
+ async function waitForProcessExit(pid, timeoutMs) {
1930
+ const deadline = Date.now() + timeoutMs;
1931
+ while (Date.now() < deadline) {
1932
+ if (!isProcessAlive(pid)) return true;
1933
+ await sleep(50);
1934
+ }
1935
+ return !isProcessAlive(pid);
1936
+ }
1937
+ function isBridgeProcess(pid) {
1938
+ try {
1939
+ const command = execFileSync("ps", ["-p", String(pid), "-o", "command="], {
1940
+ encoding: "utf-8",
1941
+ timeout: 1e3
1942
+ });
1943
+ return command.includes("chrome-devtools-axi-bridge");
1944
+ } catch {
1945
+ return false;
1946
+ }
1947
+ }
1948
+ async function terminateBridgeProcess(pid, opts = {}) {
1949
+ if (!isProcessAlive(pid)) return;
1950
+ const killProcessGroup = opts.killProcessGroup === true;
1951
+ try {
1952
+ process.kill(pid, "SIGTERM");
1953
+ } catch {
1954
+ return;
1955
+ }
1956
+ if (await waitForProcessExit(pid, 2e3)) {
1957
+ if (killProcessGroup) {
1958
+ try {
1959
+ process.kill(-pid, "SIGKILL");
1960
+ } catch {
1961
+ }
1962
+ }
1963
+ return;
1964
+ }
1965
+ if (killProcessGroup) {
1966
+ try {
1967
+ process.kill(-pid, "SIGKILL");
1968
+ } catch {
1969
+ try {
1970
+ process.kill(pid, "SIGKILL");
1971
+ } catch {
1972
+ }
1973
+ }
1974
+ } else {
1975
+ try {
1976
+ process.kill(pid, "SIGKILL");
1977
+ } catch {
1978
+ }
1979
+ }
1980
+ await waitForProcessExit(pid, 1e3);
1981
+ }
1982
+ function spawnBridgeProcess(port, sessionName) {
1983
+ const bridgeScript = resolveBridgeScript(import.meta.dirname);
1984
+ const script = existsSync3(bridgeScript.replace(/\.js$/, ".ts")) ? bridgeScript.replace(/\.js$/, ".ts") : bridgeScript;
1985
+ const runner = script.endsWith(".ts") ? "tsx" : "node";
1986
+ const child = spawn2(
1987
+ runner === "tsx" ? "npx" : "node",
1988
+ runner === "tsx" ? ["tsx", script] : [script],
1989
+ {
1990
+ stdio: "ignore",
1991
+ env: {
1992
+ ...process.env,
1993
+ CHROME_DEVTOOLS_AXI_PORT: String(port),
1994
+ CHROME_DEVTOOLS_AXI_SESSION: sessionName
1995
+ },
1996
+ detached: true
1997
+ }
1998
+ );
1999
+ child.unref();
2000
+ return child;
2001
+ }
2002
+ function resolveSharedMcpMode() {
2003
+ const sharedServerUrl = process.env.CHROME_DEVTOOLS_AXI_MCP_SERVER_URL?.trim();
2004
+ if (!sharedServerUrl) return null;
2005
+ return process.env.CHROME_DEVTOOLS_AXI_MCP_PATH?.trim() ? "proxy" : "direct";
2006
+ }
2007
+ function sharedMcpSuggestions(mode) {
2008
+ if (mode === "direct") {
2009
+ return [
2010
+ "Shared MCP direct mode is enabled by CHROME_DEVTOOLS_AXI_MCP_SERVER_URL; AXI connects directly to that Streamable HTTP endpoint without launching a local MCP process.",
2011
+ "Verify CHROME_DEVTOOLS_AXI_MCP_SERVER_URL is an absolute http(s) MCP endpoint and that the service is running and reachable there."
2012
+ ];
2013
+ }
2014
+ return [
2015
+ "Shared MCP proxy mode is enabled by CHROME_DEVTOOLS_AXI_MCP_SERVER_URL; this mode does not launch Chrome locally.",
2016
+ "Set CHROME_DEVTOOLS_AXI_MCP_PATH to a runnable chrome-devtools-mcp build that advertises --serverUrl in --help.",
2017
+ "Use the proxy-capable MCP build from the companion shared-server change, then restart this AXI session."
2018
+ ];
2019
+ }
2020
+ function buildBridgeEarlyExitError(sessionName, port, code, signal) {
2021
+ const how = signal != null ? `was killed by ${signal}` : `exited with code ${code ?? "unknown"}`;
2022
+ const message = `Bridge for session "${sessionName}" ${how} before becoming ready on port ${port}`;
2023
+ if (code === BRIDGE_PORT_IN_USE_EXIT_CODE) {
2024
+ return new CdpError(message, "BRIDGE_NOT_READY", [
2025
+ `Port ${port} is already in use. It may be held by another chrome-devtools-axi session's bridge (a hashed-port collision, or a globally-exported CHROME_DEVTOOLS_AXI_PORT forcing every session onto one port), by a stale or crashed bridge that could not be reused, or by an unrelated process.`,
2026
+ "Set a distinct CHROME_DEVTOOLS_AXI_PORT for this session, unset a global CHROME_DEVTOOLS_AXI_PORT so every session derives its own, or free whatever is holding the port."
2027
+ ]);
2028
+ }
2029
+ const sharedMcpMode = resolveSharedMcpMode();
2030
+ if (sharedMcpMode) {
2031
+ return new CdpError(
2032
+ message,
2033
+ "BRIDGE_NOT_READY",
2034
+ sharedMcpSuggestions(sharedMcpMode)
2035
+ );
2036
+ }
2037
+ const suggestions = [
2038
+ "Check that chrome-devtools-mcp can start: npx chrome-devtools-mcp@latest --help"
2039
+ ];
2040
+ if (process.env.CHROME_DEVTOOLS_AXI_MCP_PATH?.trim()) {
2041
+ suggestions.push(
2042
+ "Verify CHROME_DEVTOOLS_AXI_MCP_PATH points to a valid chrome-devtools-mcp build."
2043
+ );
2044
+ } else {
2045
+ suggestions.push(
2046
+ "`npx -y chrome-devtools-mcp@latest` may have failed to resolve/download the package (offline, or a slow cold first run); install it globally and set:",
2047
+ ' export CHROME_DEVTOOLS_AXI_MCP_PATH="$(npm prefix -g)/lib/node_modules/chrome-devtools-mcp/build/src/bin/chrome-devtools-mcp.js"'
2048
+ );
2049
+ }
2050
+ suggestions.push(
2051
+ "Or Chrome failed to launch; confirm a usable Chrome is installed."
2052
+ );
2053
+ return new CdpError(message, "BRIDGE_NOT_READY", suggestions);
2054
+ }
2055
+ async function ensureBridge(spawnBridge = spawnBridgeProcess, notice) {
2056
+ const sessionName = resolveSessionName();
2057
+ const port = resolveSessionPort(sessionName);
2058
+ const pidFile = resolveSessionPidFile(sessionName);
2059
+ const pidInfo = readPidFile(pidFile);
2060
+ if (pidInfo && isProcessAlive(pidInfo.pid)) {
2061
+ if (await checkBridgeHealth(pidInfo.port, {
2062
+ deep: true,
2063
+ expectedSession: sessionName,
2064
+ notice
2065
+ })) {
2066
+ return pidInfo.port;
2067
+ }
2068
+ await terminateBridgeProcess(pidInfo.pid, {
2069
+ killProcessGroup: isBridgeProcess(pidInfo.pid)
2070
+ });
2071
+ }
2072
+ clearSelectedPageId();
2073
+ const child = spawnBridge(port, sessionName);
2074
+ let childExited = false;
2075
+ let exitCode = null;
2076
+ let exitSignal = null;
2077
+ child.on("exit", (code, signal) => {
2078
+ childExited = true;
2079
+ exitCode = code;
2080
+ exitSignal = signal;
2081
+ });
2082
+ const timeoutMs = resolveBridgeTimeoutMs();
2083
+ const deadline = Date.now() + timeoutMs;
2084
+ let sawShallowReady = false;
2085
+ while (Date.now() < deadline) {
2086
+ if (await checkBridgeHealth(port, {
2087
+ deep: true,
2088
+ expectedSession: sessionName,
2089
+ notice
2090
+ })) {
2091
+ return port;
2092
+ }
2093
+ if (childExited) {
2094
+ if (await checkBridgeHealth(port, {
2095
+ deep: true,
2096
+ expectedSession: sessionName,
2097
+ notice
2098
+ })) {
2099
+ return port;
2100
+ }
2101
+ throw buildBridgeEarlyExitError(sessionName, port, exitCode, exitSignal);
2102
+ }
2103
+ if (!sawShallowReady && await checkBridgeHealth(port, { expectedSession: sessionName })) {
2104
+ sawShallowReady = true;
2105
+ }
2106
+ await sleep(500);
2107
+ }
2108
+ const seconds = Math.round(timeoutMs / 1e3);
2109
+ const sharedMcpMode = resolveSharedMcpMode();
2110
+ if (sawShallowReady) {
2111
+ const suggestions2 = sharedMcpMode ? [
2112
+ ...sharedMcpSuggestions(sharedMcpMode),
2113
+ "The shared MCP service may be reachable while its attached Chrome target is unavailable."
2114
+ ] : [
2115
+ "The Chrome/Electron instance the bridge was attached to may have exited.",
2116
+ "Verify the target is still listening on its remote-debugging port, then re-run the command.",
2117
+ "If the target was restarted, the bridge has already been recycled \u2014 this run will succeed once the target is reachable."
2118
+ ];
2119
+ throw new CdpError(
2120
+ "Bridge is running but the attached CDP target appears to have gone away",
2121
+ "BRIDGE_NOT_READY",
2122
+ suggestions2
2123
+ );
2124
+ }
2125
+ const suggestions = sharedMcpMode === "direct" ? sharedMcpSuggestions("direct") : sharedMcpMode === "proxy" ? sharedMcpSuggestions("proxy") : [
2126
+ "Check that chrome-devtools-mcp is installed: npx chrome-devtools-mcp@latest --help"
2127
+ ];
2128
+ if (!sharedMcpMode && !process.env.CHROME_DEVTOOLS_AXI_MCP_PATH?.trim()) {
2129
+ suggestions.push(
2130
+ "If `npx -y chrome-devtools-mcp@latest` is slow on this machine, install mcp globally and set:",
2131
+ ' export CHROME_DEVTOOLS_AXI_MCP_PATH="$(npm prefix -g)/lib/node_modules/chrome-devtools-mcp/build/src/bin/chrome-devtools-mcp.js"'
2132
+ );
2133
+ }
2134
+ suggestions.push(
2135
+ "Or extend the deadline: export CHROME_DEVTOOLS_AXI_BRIDGE_TIMEOUT_MS=60000"
2136
+ );
2137
+ throw new CdpError(
2138
+ `Bridge failed to start within ${seconds}s`,
2139
+ "BRIDGE_NOT_READY",
2140
+ suggestions
2141
+ );
2142
+ }
2143
+ function parseCallResponse(resp) {
2144
+ const data = JSON.parse(resp);
2145
+ if (data.error) {
2146
+ throw new Error(data.error);
2147
+ }
2148
+ return data.result ?? "";
2149
+ }
2150
+ async function postTool(port, name, args, opts = {}) {
2151
+ const body = { name, args };
2152
+ if (opts.roots && opts.roots.length > 0) body.roots = opts.roots;
2153
+ const resp = await httpPost(port, "/call", body, opts.timeoutMs);
2154
+ return parseCallResponse(resp);
2155
+ }
2156
+ var FILE_OUTPUT_ARGS_BY_TOOL = /* @__PURE__ */ new Map([
2157
+ ["take_screenshot", ["filePath"]],
2158
+ ["get_network_request", ["responseFilePath", "requestFilePath"]],
2159
+ ["performance_start_trace", ["filePath"]],
2160
+ ["performance_stop_trace", ["filePath"]],
2161
+ ["take_heapsnapshot", ["filePath"]]
2162
+ ]);
2163
+ var DIR_OUTPUT_ARGS_BY_TOOL = /* @__PURE__ */ new Map([
2164
+ ["lighthouse_audit", ["outputDirPath"]]
2165
+ ]);
2166
+ function nearestExistingAncestor(path) {
2167
+ let candidate = path;
2168
+ while (!existsSync3(candidate)) {
2169
+ const parent = dirname3(candidate);
2170
+ if (parent === candidate) return candidate;
2171
+ candidate = parent;
2172
+ }
2173
+ return candidate;
2174
+ }
2175
+ function collectRootDirs(name, args) {
2176
+ const dirs = /* @__PURE__ */ new Set([process.cwd()]);
2177
+ for (const key of FILE_OUTPUT_ARGS_BY_TOOL.get(name) ?? []) {
2178
+ const value = args[key];
2179
+ if (typeof value === "string" && value.length > 0) {
2180
+ dirs.add(nearestExistingAncestor(dirname3(value)));
2181
+ }
2182
+ }
2183
+ for (const key of DIR_OUTPUT_ARGS_BY_TOOL.get(name) ?? []) {
2184
+ const value = args[key];
2185
+ if (typeof value === "string" && value.length > 0) {
2186
+ dirs.add(nearestExistingAncestor(value));
2187
+ }
2188
+ }
2189
+ if (name === "upload_file" && Array.isArray(args.filePaths)) {
2190
+ for (const file of args.filePaths) {
2191
+ if (typeof file === "string") dirs.add(dirname3(file));
2192
+ }
2193
+ }
2194
+ return [...dirs];
2195
+ }
2196
+ function resolveSelectedPageId(reconnected) {
2197
+ const pageId = getSelectedPageId();
2198
+ if (pageId === null) {
2199
+ if (reconnected) throw pageIdentityClearedError();
2200
+ throw new CdpError("No page is currently selected", "BROWSER_ERROR", [
2201
+ "Run `chrome-devtools-axi open <url>` to open a page",
2202
+ "Run `chrome-devtools-axi pages` to list tabs",
2203
+ "Run `chrome-devtools-axi selectpage <id>` to select a tab"
2204
+ ]);
2205
+ }
2206
+ return pageId;
2207
+ }
2208
+ function resolveToolArgs(name, args, reconnected) {
2209
+ if (!needsPageId(name, args)) return args;
2210
+ return { ...args, pageId: resolveSelectedPageId(reconnected) };
2211
+ }
2212
+ async function callTool(name, args = {}) {
2213
+ const notice = { pageIdentityChanged: false };
2214
+ const port = await ensureBridge(void 0, notice);
2215
+ let resolved = args;
2216
+ try {
2217
+ resolved = resolveToolArgs(name, args, notice.pageIdentityChanged);
2218
+ const result = await postTool(port, name, resolved, {
2219
+ roots: collectRootDirs(name, resolved)
2220
+ });
2221
+ rememberToolRouting(name, resolved, result);
2222
+ return result;
2223
+ } catch (err) {
2224
+ if (err instanceof CdpError) throw err;
2225
+ const message = err instanceof Error ? err.message : String(err);
2226
+ if (isMissingPageError(message)) {
2227
+ const pageId = typeof resolved.pageId === "number" ? resolved.pageId : null;
2228
+ if (pageId !== null && getSelectedPageId() === pageId) {
2229
+ clearSelectedPageId();
2230
+ }
2231
+ throw missingPageError(pageId);
2232
+ }
2233
+ throw mapErrorMessage(message);
2234
+ }
2235
+ }
2236
+ var MCP_MISSING_PAGE_LINE = "No page found";
2237
+ var MCP_CLOSED_PAGE_LINE_PREFIX = "The selected page has been closed.";
2238
+ function isMissingPageError(message) {
2239
+ const line = lastNonEmptyLine(message).replace(/^Error:\s*/, "");
2240
+ return line === MCP_MISSING_PAGE_LINE || line.startsWith(MCP_CLOSED_PAGE_LINE_PREFIX);
2241
+ }
2242
+ function lastNonEmptyLine(message) {
2243
+ const lines = message.split(/\r?\n/);
2244
+ for (let i = lines.length - 1; i >= 0; i -= 1) {
2245
+ const line = lines[i].trim();
2246
+ if (line) return line;
2247
+ }
2248
+ return "";
2249
+ }
2250
+ function missingPageError(pageId) {
2251
+ return new CdpError(
2252
+ pageId === null ? "The selected page is no longer available" : `Page ${pageId} is no longer available`,
2253
+ "BROWSER_ERROR",
2254
+ [
2255
+ "Run `chrome-devtools-axi pages` to list the remaining tabs",
2256
+ "Run `chrome-devtools-axi selectpage <id>` to select a tab, or `chrome-devtools-axi open <url>` to open one"
2257
+ ]
2258
+ );
2259
+ }
2260
+ var PAGE_IDENTITY_SUGGESTIONS = [
2261
+ "Run `chrome-devtools-axi pages` to list the current tabs and their new ids",
2262
+ "Run `chrome-devtools-axi selectpage <id>` to re-select a tab after the reconnect, then retry"
2263
+ ];
2264
+ function pageIdentityChangedError() {
2265
+ return new CdpError(
2266
+ PAGE_IDENTITY_CHANGED_ERROR,
2267
+ "BROWSER_ERROR",
2268
+ PAGE_IDENTITY_SUGGESTIONS
2269
+ );
2270
+ }
2271
+ function pageIdentityClearedError() {
2272
+ return new CdpError(
2273
+ "The browser reconnected and every page id changed, so no page is currently selected",
2274
+ "BROWSER_ERROR",
2275
+ PAGE_IDENTITY_SUGGESTIONS
2276
+ );
2277
+ }
2278
+ function mapErrorMessage(message) {
2279
+ if (message === PAGE_IDENTITY_CHANGED_ERROR) {
2280
+ return pageIdentityChangedError();
2281
+ }
2282
+ if (isMissingPageError(message)) return missingPageError(null);
2283
+ if (message.includes("ECONNREFUSED") || message.includes("ECONNRESET")) {
2284
+ return new CdpError("Bridge is not running", "BRIDGE_NOT_READY", [
2285
+ "Run `chrome-devtools-axi open <url>` \u2014 the bridge starts automatically"
2286
+ ]);
2287
+ }
2288
+ if ((message.includes("uid") || message.includes("element")) && (message.includes("not found") || message.includes("invalid"))) {
2289
+ return new CdpError(message, "REF_NOT_FOUND", [
2290
+ "Run `chrome-devtools-axi snapshot` to see available elements and their @uid refs"
2291
+ ]);
2292
+ }
2293
+ if (message.includes("timeout") || message.includes("timed out")) {
2294
+ return new CdpError(message, "TIMEOUT", [
2295
+ "Run `chrome-devtools-axi snapshot` to see current page state"
2296
+ ]);
2297
+ }
2298
+ try {
2299
+ const parsed = JSON.parse(message);
2300
+ if (parsed.error) {
2301
+ return new CdpError(parsed.error, "BROWSER_ERROR", [
2302
+ "Run `chrome-devtools-axi snapshot` to see current page state"
2303
+ ]);
2304
+ }
2305
+ } catch {
2306
+ }
2307
+ return new CdpError(message, "UNKNOWN");
2308
+ }
2309
+ async function getSessionSnapshotIfRunning() {
2310
+ let sessionName;
2311
+ let pidInfo;
2312
+ try {
2313
+ sessionName = resolveSessionName();
2314
+ pidInfo = readPidFile(resolveSessionPidFile(sessionName));
2315
+ } catch {
2316
+ return null;
2317
+ }
2318
+ if (!pidInfo || !isProcessAlive(pidInfo.pid)) {
2319
+ return null;
2320
+ }
2321
+ if (!await checkBridgeHealth(pidInfo.port, { expectedSession: sessionName })) {
2322
+ return null;
2323
+ }
2324
+ try {
2325
+ const pageId = getSelectedPageId();
2326
+ if (pageId === null) return null;
2327
+ return await postTool(
2328
+ pidInfo.port,
2329
+ "take_snapshot",
2330
+ { pageId },
2331
+ { timeoutMs: 5e3 }
2332
+ );
2333
+ } catch {
2334
+ return null;
2335
+ }
2336
+ }
2337
+ async function stopBridge() {
2338
+ const pidInfo = readPidFile();
2339
+ if (!pidInfo) return false;
2340
+ if (!isProcessAlive(pidInfo.pid)) return false;
2341
+ await terminateBridgeProcess(pidInfo.pid, {
2342
+ killProcessGroup: isBridgeProcess(pidInfo.pid)
2343
+ });
2344
+ clearSelectedPageId();
2345
+ return true;
2346
+ }
2347
+
2348
+ // vendor/chrome-devtools-axi/src/generation.ts
2349
+ import {
2350
+ existsSync as existsSync4,
2351
+ mkdirSync as mkdirSync2,
2352
+ readFileSync as readFileSync4,
2353
+ unlinkSync,
2354
+ writeFileSync as writeFileSync2
2355
+ } from "node:fs";
2356
+ import { dirname as dirname4, join as join3 } from "node:path";
2357
+ function genFile() {
2358
+ return join3(resolveSessionStateDir(), "snapshot-generation");
2359
+ }
2360
+ function getCurrentGeneration() {
2361
+ const file = genFile();
2362
+ try {
2363
+ if (!existsSync4(file)) return 0;
2364
+ const parsed = Number.parseInt(readFileSync4(file, "utf-8").trim(), 10);
2365
+ return Number.isNaN(parsed) ? 0 : parsed;
2366
+ } catch {
2367
+ return 0;
2368
+ }
2369
+ }
2370
+ function bumpGeneration() {
2371
+ const next = getCurrentGeneration() + 1;
2372
+ const file = genFile();
2373
+ try {
2374
+ mkdirSync2(dirname4(file), { recursive: true });
2375
+ writeFileSync2(file, String(next));
2376
+ } catch {
2377
+ }
2378
+ return next;
2379
+ }
2380
+
2381
+ // vendor/chrome-devtools-axi/src/run.ts
2382
+ import { mkdtempSync, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, rmdirSync } from "node:fs";
2383
+ import { join as join4 } from "node:path";
2384
+ import { tmpdir } from "node:os";
2385
+ import { pathToFileURL } from "node:url";
2386
+
2387
+ // vendor/chrome-devtools-axi/src/snapshot.ts
2388
+ function countRefs(snapshot) {
2389
+ const matches = snapshot.match(/\buid=\S+/g);
2390
+ return matches ? matches.length : 0;
2391
+ }
2392
+ function extractRefs(snapshot) {
2393
+ const refs = [];
2394
+ for (const line of snapshot.split("\n")) {
2395
+ const m = line.match(/\buid=(\S+)\s+(\w+)\s+"([^"]*)"/);
2396
+ if (!m) continue;
2397
+ refs.push({ ref: m[1], type: m[2], label: m[3] });
2398
+ }
2399
+ return refs;
2400
+ }
2401
+ function parseStampedUid(arg) {
2402
+ const stripped = arg.startsWith("@") ? arg.slice(1) : arg;
2403
+ const m = stripped.match(/^g(\d+):(.+)$/);
2404
+ if (m) return { uid: m[2], generation: Number.parseInt(m[1], 10) };
2405
+ return { uid: stripped, generation: null };
2406
+ }
2407
+ function stampSnapshotGeneration(snapshot, generation) {
2408
+ return snapshot.replace(/\buid=(\S+)/g, (match, uid) => {
2409
+ if (/^g\d+:/.test(uid)) return match;
2410
+ return `uid=g${generation}:${uid}`;
2411
+ });
2412
+ }
2413
+ function checkUidGeneration(arg, currentGeneration) {
2414
+ const { uid, generation } = parseStampedUid(arg);
2415
+ return {
2416
+ uid,
2417
+ stale: generation !== null && generation !== currentGeneration,
2418
+ refGeneration: generation
2419
+ };
2420
+ }
2421
+ function extractTitle(snapshot) {
2422
+ const rootMatch = snapshot.match(/RootWebArea\s+"([^"]+)"/);
2423
+ if (rootMatch) return rootMatch[1];
2424
+ const headingMatch = snapshot.match(/\bheading\s+"([^"]+)"/);
2425
+ if (headingMatch) return headingMatch[1];
2426
+ return "";
2427
+ }
2428
+ function truncateSnapshot(snapshot, full, limit = 16e3) {
2429
+ const totalLength = snapshot.length;
2430
+ if (full || totalLength <= limit) {
2431
+ return { text: snapshot, truncated: false, totalLength };
2432
+ }
2433
+ const cut = snapshot.lastIndexOf("\n", limit);
2434
+ const text = cut > 0 ? snapshot.slice(0, cut) : snapshot.slice(0, limit);
2435
+ return { text, truncated: true, totalLength };
2436
+ }
2437
+ var MARKER_OVERHEAD = 50;
2438
+ function truncateText(text, limit = 8e3) {
2439
+ const totalLength = text.length;
2440
+ if (totalLength <= limit) {
2441
+ return { text, truncated: false, totalLength };
2442
+ }
2443
+ if (totalLength <= limit + MARKER_OVERHEAD) {
2444
+ return { text, truncated: false, totalLength };
2445
+ }
2446
+ const headBudget = Math.floor(limit * 0.4);
2447
+ const tailBudget = limit - headBudget;
2448
+ const headCut = text.lastIndexOf("\n", headBudget);
2449
+ const head = headCut > 0 ? text.slice(0, headCut) : text.slice(0, headBudget);
2450
+ const tailStart = text.indexOf("\n", totalLength - tailBudget);
2451
+ const tail = tailStart > 0 && tailStart < totalLength ? text.slice(tailStart + 1) : text.slice(totalLength - tailBudget);
2452
+ const omitted = totalLength - head.length - tail.length;
2453
+ const result = `${head}
2454
+
2455
+ ... (${omitted} chars omitted, ${totalLength} total) ...
2456
+
2457
+ ${tail}`;
2458
+ return { text: result, truncated: true, totalLength };
2459
+ }
2460
+ var INPUT_TYPES = ["textbox", "searchbox", "input", "combobox", "textarea"];
2461
+ function isInputType(type) {
2462
+ return INPUT_TYPES.includes(type);
2463
+ }
2464
+
2465
+ // vendor/chrome-devtools-axi/src/uid-freshness.ts
2466
+ var PAGE_GENERATION_KEY = "__chromeDevtoolsAxiSnapshotGeneration";
2467
+ async function captureFreshSnapshot(caller, capture) {
2468
+ const first = await captureSnapshot(caller, capture);
2469
+ const fresh = first.state?.generation === first.generation && first.state.mutations > 0 ? await captureSnapshot(caller, capture) : first;
2470
+ return stampSnapshotGeneration(fresh.snapshot, fresh.generation);
2471
+ }
2472
+ function throwStaleRef(arg, refGeneration, currentGeneration) {
2473
+ const refRaw = arg.startsWith("@") ? arg.slice(1) : arg;
2474
+ const current = currentGeneration ?? "unavailable";
2475
+ throw new CdpError(
2476
+ `Stale ref @${refRaw}: from snapshot generation ${refGeneration}, current is ${current}. Re-snapshot to get fresh refs.`,
2477
+ "STALE_REF",
2478
+ [
2479
+ "Run `chrome-devtools-axi snapshot` to capture current refs, then retry the action"
2480
+ ]
2481
+ );
2482
+ }
2483
+ async function markPageSnapshotGeneration(generation, caller) {
2484
+ const key = JSON.stringify(PAGE_GENERATION_KEY);
2485
+ try {
2486
+ await caller("evaluate_script", {
2487
+ function: `() => {
2488
+ const key = ${key};
2489
+ const previous = globalThis[key];
2490
+ if (previous && previous.observer) previous.observer.disconnect();
2491
+ const state = { generation: ${generation}, mutations: 0, observer: null };
2492
+ const observer = new MutationObserver(() => { state.mutations += 1; });
2493
+ observer.observe(document.documentElement || document, { childList: true, subtree: true, attributes: true, characterData: true });
2494
+ state.observer = observer;
2495
+ globalThis[key] = state;
2496
+ return state.generation;
2497
+ }`
2498
+ });
2499
+ } catch {
2500
+ }
2501
+ }
2502
+ async function captureSnapshot(caller, capture) {
2503
+ const generation = bumpGeneration();
2504
+ await markPageSnapshotGeneration(generation, caller);
2505
+ const snapshot = await capture();
2506
+ return { generation, snapshot, state: await getPageRefState(caller) };
2507
+ }
2508
+ async function getPageRefState(caller) {
2509
+ const key = JSON.stringify(PAGE_GENERATION_KEY);
2510
+ try {
2511
+ const output = await caller("evaluate_script", {
2512
+ function: `() => {
2513
+ const state = globalThis[${key}];
2514
+ if (!state || typeof state.generation !== 'number' || typeof state.mutations !== 'number' || !state.observer) return null;
2515
+ return { generation: state.generation, mutations: state.mutations };
2516
+ }`
2517
+ });
2518
+ const jsonBlock = output.match(/```json\n([\s\S]*?)\n```/);
2519
+ const raw = jsonBlock?.[1] ?? output.replace(/^Script ran on page and returned:\s*/, "");
2520
+ const parsed = JSON.parse(raw.trim());
2521
+ if (typeof parsed !== "object" || parsed === null || typeof parsed.generation !== "number" || typeof parsed.mutations !== "number") {
2522
+ return null;
2523
+ }
2524
+ return parsed;
2525
+ } catch {
2526
+ return null;
2527
+ }
2528
+ }
2529
+ async function parseUidFresh(arg, caller) {
2530
+ const snapshotGeneration = getCurrentGeneration();
2531
+ const check = checkUidGeneration(arg, snapshotGeneration);
2532
+ if (check.stale) {
2533
+ throwStaleRef(arg, check.refGeneration, snapshotGeneration);
2534
+ }
2535
+ const state = await getPageRefState(caller);
2536
+ if (!state || state.generation !== snapshotGeneration || state.mutations !== 0) {
2537
+ throwStaleRef(
2538
+ arg,
2539
+ parseStampedUid(arg).generation ?? snapshotGeneration,
2540
+ state ? state.generation + state.mutations : null
2541
+ );
2542
+ }
2543
+ return check.uid;
2544
+ }
2545
+
2546
+ // vendor/chrome-devtools-axi/src/run.ts
2547
+ function unwrapNoArgIIFE(s) {
2548
+ const candidate = s.endsWith(";") ? s.slice(0, -1).trimEnd() : s;
2549
+ if (candidate.length < 4 || candidate[0] !== "(" || !candidate.endsWith(")")) {
2550
+ return s;
2551
+ }
2552
+ let depth = 0;
2553
+ let inString = null;
2554
+ let escape = false;
2555
+ let closeIdx = -1;
2556
+ for (let i = 0; i < candidate.length; i++) {
2557
+ const c = candidate[i];
2558
+ if (escape) {
2559
+ escape = false;
2560
+ continue;
2561
+ }
2562
+ if (inString) {
2563
+ if (c === "\\") {
2564
+ escape = true;
2565
+ continue;
2566
+ }
2567
+ if (c === inString) inString = null;
2568
+ continue;
2569
+ }
2570
+ if (c === '"' || c === "'" || c === "`") {
2571
+ inString = c;
2572
+ continue;
2573
+ }
2574
+ if (c === "(") depth++;
2575
+ else if (c === ")") {
2576
+ depth--;
2577
+ if (depth === 0) {
2578
+ closeIdx = i;
2579
+ break;
2580
+ }
2581
+ }
2582
+ }
2583
+ if (closeIdx < 0) return s;
2584
+ const rest = candidate.slice(closeIdx + 1).trim();
2585
+ if (rest !== "()") return s;
2586
+ const inner = candidate.slice(1, closeIdx).trim();
2587
+ if (/^(async\s*)?(\(.*?\)\s*=>|[a-zA-Z_$][a-zA-Z0-9_$]*\s*=>|function[\s*(])/.test(
2588
+ inner
2589
+ )) {
2590
+ return inner;
2591
+ }
2592
+ return s;
2593
+ }
2594
+ function wrapJsExpression(js) {
2595
+ const trimmed = unwrapNoArgIIFE(js.trim());
2596
+ if (/^(async\s*)?(\(.*?\)\s*=>|[a-zA-Z_$][a-zA-Z0-9_$]*\s*=>|function[\s*(])/.test(
2597
+ trimmed
2598
+ )) {
2599
+ return trimmed;
2600
+ }
2601
+ return `() => (${trimmed})`;
2602
+ }
2603
+ function parseEvalOutput(output) {
2604
+ const jsonBlock = output.match(/```json\n([\s\S]*?)\n```/);
2605
+ if (jsonBlock) {
2606
+ try {
2607
+ return JSON.parse(jsonBlock[1].trim());
2608
+ } catch {
2609
+ return jsonBlock[1].trim();
2610
+ }
2611
+ }
2612
+ const preamble = "Script ran on page and returned:";
2613
+ if (output.includes(preamble)) {
2614
+ const raw = output.slice(output.indexOf(preamble) + preamble.length).trim();
2615
+ try {
2616
+ return JSON.parse(raw);
2617
+ } catch {
2618
+ return raw;
2619
+ }
2620
+ }
2621
+ return output.trim();
2622
+ }
2623
+ function stripSnapshotHeader(text) {
2624
+ const lines = text.split("\n");
2625
+ const treeStart = lines.findIndex((l) => /\bRootWebArea\b|\buid=/.test(l));
2626
+ if (treeStart > 0) return lines.slice(treeStart).join("\n");
2627
+ return text.replace(/^[\s\S]*?##\s+Latest page snapshot\s*\n/, "");
2628
+ }
2629
+ function isRecoverableOpenError(error) {
2630
+ if (!(error instanceof CdpError)) return false;
2631
+ if (error.code !== "BROWSER_ERROR") return false;
2632
+ return /not connected|session (?:closed|not found)|no page/i.test(
2633
+ error.message
2634
+ );
2635
+ }
2636
+ var UID_RE = /^@?(?:\d[\d_]*|g\d+:.+)$/;
2637
+ function isUidRef(s) {
2638
+ return UID_RE.test(s);
2639
+ }
2640
+ var DEFAULT_WAIT_TIMEOUT = 3e4;
2641
+ function createPageHelper(callTool2) {
2642
+ function callFunction(code) {
2643
+ return callTool2("evaluate_script", { function: wrapJsExpression(code) });
2644
+ }
2645
+ async function evalJs(code) {
2646
+ return parseEvalOutput(await callFunction(code));
2647
+ }
2648
+ return {
2649
+ async open(url) {
2650
+ if (!url) {
2651
+ throw new CdpError("Missing URL", "VALIDATION_ERROR", [
2652
+ 'Start with `await page.open("https://example.com")`'
2653
+ ]);
2654
+ }
2655
+ try {
2656
+ await callTool2("navigate_page", { type: "url", url });
2657
+ } catch (error) {
2658
+ if (!isRecoverableOpenError(error)) throw error;
2659
+ await callTool2("new_page", { url });
2660
+ }
2661
+ const info = await evalJs(
2662
+ `() => ({ url: location.href, status: performance.getEntriesByType('navigation').pop()?.responseStatus ?? null })`
2663
+ );
2664
+ const result = info;
2665
+ return {
2666
+ url: String(result?.url ?? url),
2667
+ status: typeof result?.status === "number" ? result.status : null
2668
+ };
2669
+ },
2670
+ async eval(jsOrFn) {
2671
+ if (typeof jsOrFn === "function") {
2672
+ return parseEvalOutput(
2673
+ await callTool2("evaluate_script", { function: String(jsOrFn) })
2674
+ );
2675
+ }
2676
+ return evalJs(jsOrFn);
2677
+ },
2678
+ async wait(msOrSelector, timeout) {
2679
+ if (typeof msOrSelector === "number") {
2680
+ await callFunction(`new Promise(r => setTimeout(r, ${msOrSelector}))`);
2681
+ } else {
2682
+ const ms = timeout ?? DEFAULT_WAIT_TIMEOUT;
2683
+ const sel = JSON.stringify(msOrSelector);
2684
+ await callFunction(`new Promise((resolve, reject) => {
2685
+ const sel = ${sel};
2686
+ if (document.querySelector(sel)) { resolve(); return; }
2687
+ const observer = new MutationObserver(() => {
2688
+ if (document.querySelector(sel)) {
2689
+ observer.disconnect();
2690
+ clearTimeout(timer);
2691
+ resolve();
2692
+ }
2693
+ });
2694
+ const timer = setTimeout(() => {
2695
+ observer.disconnect();
2696
+ reject(new Error('Timeout waiting for: ' + sel));
2697
+ }, ${ms});
2698
+ observer.observe(document.body, { childList: true, subtree: true, attributes: true });
2699
+ })`);
2700
+ }
2701
+ },
2702
+ async snapshot() {
2703
+ return captureFreshSnapshot(
2704
+ callTool2,
2705
+ async () => stripSnapshotHeader(await callTool2("take_snapshot"))
2706
+ );
2707
+ },
2708
+ async click(refOrSelector) {
2709
+ if (isUidRef(refOrSelector)) {
2710
+ await callTool2("click", {
2711
+ uid: await parseUidFresh(refOrSelector, callTool2)
2712
+ });
2713
+ } else {
2714
+ const sel = JSON.stringify(refOrSelector);
2715
+ await callFunction(`() => {
2716
+ const el = document.querySelector(${sel});
2717
+ if (!el) throw new Error('Element not found: ' + ${sel});
2718
+ el.scrollIntoView({ block: 'center' });
2719
+ el.click();
2720
+ }`);
2721
+ }
2722
+ },
2723
+ async fill(refOrSelector, text) {
2724
+ if (isUidRef(refOrSelector)) {
2725
+ await callTool2("fill", {
2726
+ uid: await parseUidFresh(refOrSelector, callTool2),
2727
+ value: text
2728
+ });
2729
+ } else {
2730
+ const sel = JSON.stringify(refOrSelector);
2731
+ const val = JSON.stringify(text);
2732
+ await callFunction(`() => {
2733
+ const el = document.querySelector(${sel});
2734
+ if (!el) throw new Error('Element not found: ' + ${sel});
2735
+ el.focus();
2736
+ const proto = el instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype
2737
+ : el instanceof HTMLSelectElement ? HTMLSelectElement.prototype
2738
+ : HTMLInputElement.prototype;
2739
+ Object.getOwnPropertyDescriptor(proto, 'value').set.call(el, ${val});
2740
+ el.dispatchEvent(new Event('input', { bubbles: true }));
2741
+ el.dispatchEvent(new Event('change', { bubbles: true }));
2742
+ }`);
2743
+ }
2744
+ },
2745
+ async type(text) {
2746
+ await callTool2("type_text", { text });
2747
+ },
2748
+ async press(key) {
2749
+ await callTool2("press_key", { key });
2750
+ },
2751
+ async back() {
2752
+ await callTool2("navigate_page", { type: "back" });
2753
+ }
2754
+ };
2755
+ }
2756
+ async function readStdin() {
2757
+ const chunks = [];
2758
+ for await (const chunk of process.stdin) {
2759
+ chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
2760
+ }
2761
+ return Buffer.concat(chunks).toString("utf-8");
2762
+ }
2763
+ async function runScript(content, callTool2) {
2764
+ const page = createPageHelper(callTool2);
2765
+ const tmpDir = mkdtempSync(join4(tmpdir(), "cda-run-"));
2766
+ const tmpFile = join4(tmpDir, "script.mjs");
2767
+ writeFileSync3(tmpFile, content, "utf-8");
2768
+ const lines = [];
2769
+ const origLog = console.log;
2770
+ const captureLog = (...args) => {
2771
+ lines.push(args.map(String).join(" "));
2772
+ };
2773
+ const prevPage = globalThis.page;
2774
+ globalThis.page = page;
2775
+ console.log = captureLog;
2776
+ try {
2777
+ const mod = await import(pathToFileURL(tmpFile).href);
2778
+ if (typeof mod.default === "function") {
2779
+ await mod.default();
2780
+ }
2781
+ } finally {
2782
+ console.log = origLog;
2783
+ if (prevPage === void 0) {
2784
+ delete globalThis.page;
2785
+ } else {
2786
+ globalThis.page = prevPage;
2787
+ }
2788
+ try {
2789
+ unlinkSync2(tmpFile);
2790
+ rmdirSync(tmpDir);
2791
+ } catch {
2792
+ }
2793
+ }
2794
+ const stdout = lines.length > 0 ? lines.join("\n") + "\n" : "";
2795
+ return { stdout };
2796
+ }
2797
+
2798
+ // vendor/chrome-devtools-axi/src/suggestions.ts
2799
+ function getSuggestions(ctx) {
2800
+ if (ctx.command === "wait" || ctx.command === "eval") {
2801
+ return ["Run `chrome-devtools-axi snapshot` to see current page state"];
2802
+ }
2803
+ const refs = ctx.snapshot ? extractRefs(ctx.snapshot) : [];
2804
+ const links = refs.filter((r) => r.type === "link");
2805
+ const buttons = refs.filter((r) => r.type === "button");
2806
+ const inputs = refs.filter((r) => isInputType(r.type));
2807
+ const lines = [];
2808
+ if (ctx.command === "fill") {
2809
+ const submitBtn = buttons.find(
2810
+ (r) => /submit|search|go|send|login|sign|ok/i.test(r.label)
2811
+ );
2812
+ if (submitBtn) {
2813
+ lines.push(
2814
+ `Run \`chrome-devtools-axi click @${submitBtn.ref}\` to click "${submitBtn.label}"`
2815
+ );
2816
+ } else {
2817
+ lines.push("Run `chrome-devtools-axi press Enter` to submit the form");
2818
+ }
2819
+ }
2820
+ if (inputs.length > 0 && ctx.command !== "fill") {
2821
+ const inp = inputs[0];
2822
+ const label = inp.label ? `the "${inp.label}" field` : "the input field";
2823
+ lines.push(
2824
+ `Run \`chrome-devtools-axi fill @${inp.ref} "text"\` to fill ${label}`
2825
+ );
2826
+ }
2827
+ if (buttons.length > 0) {
2828
+ const btn = ctx.command === "fill" ? buttons.find(
2829
+ (r) => !/submit|search|go|send|login|sign|ok/i.test(r.label)
2830
+ ) ?? buttons[0] : buttons[0];
2831
+ if (btn && !lines.some((l) => l.includes(`@${btn.ref}`))) {
2832
+ const label = btn.label ? `"${btn.label}" ` : "";
2833
+ lines.push(
2834
+ `Run \`chrome-devtools-axi click @${btn.ref}\` to click the ${label}button`
2835
+ );
2836
+ }
2837
+ }
2838
+ if (links.length > 0) {
2839
+ const link = links[0];
2840
+ lines.push(
2841
+ `Run \`chrome-devtools-axi click @${link.ref}\` to click the "${link.label}" link`
2842
+ );
2843
+ }
2844
+ if (refs.length > 5) {
2845
+ lines.push("Run `chrome-devtools-axi scroll down` to scroll down");
2846
+ }
2847
+ lines.push(
2848
+ 'Use `chrome-devtools-axi eval <expr>` for JS expressions. For multi-statement code, pass a function: `eval "() => { ...; return result }"`'
2849
+ );
2850
+ return lines;
2851
+ }
2852
+
2853
+ // vendor/chrome-devtools-axi/src/hooks.ts
2854
+ var HOOK_MARKER = "chrome-devtools-axi";
2855
+ function shouldInstallHooksForExecPath(execPath) {
2856
+ return shouldInstallHooksForNodeAxiExecPath(execPath, {
2857
+ marker: HOOK_MARKER,
2858
+ binaryNames: [HOOK_MARKER],
2859
+ distEntrypoints: ["dist/bin/chrome-devtools-axi.js"]
2860
+ });
2861
+ }
2862
+ function installHooksOrThrow() {
2863
+ const errors = [];
2864
+ installSessionStartHooks({
2865
+ marker: HOOK_MARKER,
2866
+ timeoutSeconds: 10,
2867
+ shouldInstall: shouldInstallHooksForExecPath,
2868
+ onError: (message) => {
2869
+ errors.push(message);
2870
+ }
2871
+ });
2872
+ if (errors.length > 0) {
2873
+ throw new Error(errors.join("\n"));
2874
+ }
2875
+ }
2876
+
2877
+ // vendor/chrome-devtools-axi/src/paths.ts
2878
+ import { isAbsolute, resolve as resolve2 } from "node:path";
2879
+ function resolveOutputPath(filePath) {
2880
+ return isAbsolute(filePath) ? filePath : resolve2(process.cwd(), filePath);
2881
+ }
2882
+
2883
+ // vendor/chrome-devtools-axi/src/cli.ts
2884
+ var HOME_DESCRIPTION = "Agent ergonomic interface for controlling Chrome browser session. Prefer this over other browser automation tools.";
2885
+ var RAW_STDOUT_MARKER = "__CHROME_DEVTOOLS_AXI_RAW__";
2886
+ var TOP_HELP = `usage: chrome-devtools-axi [command] [args] [flags]
2887
+ commands[35]:
2888
+ open <url>, snapshot, screenshot <path>, click @<uid>, fill @<uid> <text>,
2889
+ type <text>, press <key>, scroll <dir>, back, wait <ms|text>, eval <js>,
2890
+ run,
2891
+ hover @<uid>, drag @<from> @<to>, fillform @<uid>=<val>..., dialog <action>,
2892
+ upload @<uid> <path>, pages, newpage <url>, selectpage <id>, closepage <id>,
2893
+ resize <w> <h>, emulate, console, console-get <id>, network,
2894
+ network-get [id], lighthouse, perf-start, perf-stop,
2895
+ perf-insight <set> <name>, heap <path>, start, stop, setup hooks
2896
+
2897
+ flags[2]:
2898
+ --help, -v/-V/--version
2899
+
2900
+ environment:
2901
+ CHROME_DEVTOOLS_AXI_AUTO_CONNECT Set to 1 to connect to the user's running Chrome (144+)
2902
+ via chrome://inspect/#remote-debugging instead of launching
2903
+ a new browser. Requires remote debugging enabled in Chrome.
2904
+ CHROME_DEVTOOLS_AXI_CHANNEL Chrome release channel to target: stable (default), beta,
2905
+ canary, or dev. Selects which installed Chrome --autoConnect
2906
+ attaches to, and which one is launched in the default and
2907
+ USER_DATA_DIR modes. Ignored with CHROME_DEVTOOLS_AXI_BROWSER_URL.
2908
+ CHROME_DEVTOOLS_AXI_HEADED Set to 1 to run Chrome in headed (visible) mode
2909
+ CHROME_DEVTOOLS_AXI_CHROME_ARGS Whitespace-separated Chrome flags forwarded to the browser
2910
+ (no shell-style quoting; flags with spaces are not supported)
2911
+ e.g. "--enable-gpu --ignore-gpu-blocklist"
2912
+ CHROME_DEVTOOLS_AXI_PORT Bridge server port (default: 9224)
2913
+ CHROME_DEVTOOLS_AXI_SESSION Named session for concurrent isolation. Each session name gets
2914
+ its own bridge process, port (auto-derived from the name, or set
2915
+ CHROME_DEVTOOLS_AXI_PORT), and on-disk state, so multiple sessions
2916
+ run at once without colliding. Connection mode and profile are
2917
+ unchanged. Defaults to "default" (port 9224, legacy state paths).
2918
+ e.g. CHROME_DEVTOOLS_AXI_SESSION=worker-1
2919
+ CHROME_DEVTOOLS_AXI_BROWSER_URL Connect to an existing Chrome instance instead of launching one.
2920
+ http(s):// uses --browserUrl (fetches /json/version).
2921
+ ws(s):// uses --wsEndpoint (direct WebSocket).
2922
+ e.g. "http://127.0.0.1:9222" or "wss://cluster.example/launch"
2923
+ CHROME_DEVTOOLS_AXI_WS_HEADERS JSON headers for ws(s):// endpoints (only with BROWSER_URL=wss?://)
2924
+ e.g. '{"Authorization":"Bearer token"}'
2925
+ CHROME_DEVTOOLS_AXI_USER_DATA_DIR Persistent Chrome profile directory (skips --isolated mode)
2926
+ e.g. "/path/to/.chrome-profile"
2927
+ CHROME_DEVTOOLS_AXI_MCP_PATH Absolute path to a chrome-devtools-mcp script. When set
2928
+ without a shared URL, the bridge spawns 'node $MCP_PATH'
2929
+ directly instead of 'npx -y chrome-devtools-mcp@latest'.
2930
+ With MCP_SERVER_URL also set, selects stdio proxy mode:
2931
+ the executable must advertise --serverUrl in --help.
2932
+ Local-mode recommendation:
2933
+ npm install -g chrome-devtools-mcp
2934
+ export CHROME_DEVTOOLS_AXI_MCP_PATH="$(npm prefix -g)/lib/node_modules/chrome-devtools-mcp/build/src/bin/chrome-devtools-mcp.js"
2935
+ CHROME_DEVTOOLS_AXI_MCP_SERVER_URL
2936
+ Shared MCP service URL. With MCP_PATH, starts a verified
2937
+ stdio proxy and passes --server-url=<URL>. Without
2938
+ MCP_PATH, connects directly over Streamable HTTP (no
2939
+ local MCP child); use an absolute http(s) MCP endpoint.
2940
+ If unset or blank, the bridge uses standalone stdio mode.
2941
+ CHROME_DEVTOOLS_AXI_BRIDGE_TIMEOUT_MS
2942
+ Bridge readiness deadline in ms (default: 30000, min: 1000)
2943
+
2944
+ gpu:
2945
+ Headless Chrome cannot access hardware GPU on most Linux systems.
2946
+ For GPU-accelerated WebGL, use headed mode with GPU flags:
2947
+ CHROME_DEVTOOLS_AXI_HEADED=1
2948
+ CHROME_DEVTOOLS_AXI_CHROME_ARGS="--enable-gpu --ignore-gpu-blocklist"
2949
+ For WebGPU, Vulkan must also be enabled (required for the Dawn backend):
2950
+ CHROME_DEVTOOLS_AXI_CHROME_ARGS="--enable-gpu --ignore-gpu-blocklist --enable-unsafe-webgpu --enable-features=Vulkan"
2951
+
2952
+ tips:
2953
+ Pipe output through grep/head to extract specific data from large pages.
2954
+ `;
2955
+ var COMMAND_HELP = {
2956
+ open: `usage: chrome-devtools-axi open <url> [--full]
2957
+ Navigate to a URL and capture an accessibility snapshot.
2958
+
2959
+ args:
2960
+ <url> URL to navigate to (required)
2961
+
2962
+ flags:
2963
+ --full Show complete snapshot without truncation
2964
+
2965
+ examples:
2966
+ chrome-devtools-axi open https://example.com
2967
+ chrome-devtools-axi open https://example.com --full`,
2968
+ screenshot: `usage: chrome-devtools-axi screenshot <path> [--uid @<uid>] [--full-page] [--format png|jpeg|webp]
2969
+ Save a screenshot to a file.
2970
+
2971
+ args:
2972
+ <path> File path to save the screenshot (required)
2973
+
2974
+ Relative output paths resolve against the directory where you run the CLI.
2975
+ Output reports the resolved absolute path.
2976
+
2977
+ flags:
2978
+ --uid @<uid> Capture a specific element instead of the full viewport.
2979
+ Refs are generation-tagged (e.g. @g3:12) - pass them back
2980
+ exactly as printed. A stale ref returns STALE_REF.
2981
+ --full-page Capture the entire scrollable page
2982
+ --format <fmt> Image format: png (default), jpeg, or webp
2983
+
2984
+ examples:
2985
+ chrome-devtools-axi screenshot ./page.png
2986
+ chrome-devtools-axi screenshot ./element.png --uid @g1:3
2987
+ chrome-devtools-axi screenshot ./full.png --full-page --format jpeg`,
2988
+ snapshot: `usage: chrome-devtools-axi snapshot [--full]
2989
+ Capture the current page accessibility snapshot.
2990
+
2991
+ flags:
2992
+ --full Show complete snapshot without truncation
2993
+
2994
+ examples:
2995
+ chrome-devtools-axi snapshot
2996
+ chrome-devtools-axi snapshot --full`,
2997
+ click: `usage: chrome-devtools-axi click @<uid> [--full]
2998
+ Click an interactive element by its ref from the snapshot.
2999
+
3000
+ args:
3001
+ @<uid> Element ref from snapshot (required). Refs are generation-tagged
3002
+ (e.g. @g3:12) - pass them back exactly as printed. A stale ref
3003
+ (older generation) returns a STALE_REF error so you know to re-snapshot.
3004
+
3005
+ flags:
3006
+ --full Show complete snapshot without truncation
3007
+
3008
+ examples:
3009
+ chrome-devtools-axi click @g1:1
3010
+ chrome-devtools-axi click @g2:12 --full`,
3011
+ fill: `usage: chrome-devtools-axi fill @<uid> <text> [--full]
3012
+ Fill a form field with text.
3013
+
3014
+ args:
3015
+ @<uid> Element ref from snapshot (required). Refs are generation-tagged
3016
+ (e.g. @g3:12) - pass them back exactly as printed. A stale ref
3017
+ returns a STALE_REF error so you know to re-snapshot.
3018
+ <text> Text to fill (required)
3019
+
3020
+ flags:
3021
+ --full Show complete snapshot without truncation
3022
+
3023
+ examples:
3024
+ chrome-devtools-axi fill @g1:3 "hello world"
3025
+ chrome-devtools-axi fill @g2:3 "search query" --full`,
3026
+ type: `usage: chrome-devtools-axi type <text> [--full]
3027
+ Type text at the currently focused element.
3028
+
3029
+ args:
3030
+ <text> Text to type (required)
3031
+
3032
+ flags:
3033
+ --full Show complete snapshot without truncation
3034
+
3035
+ examples:
3036
+ chrome-devtools-axi type "hello"
3037
+ chrome-devtools-axi type "search query" --full`,
3038
+ press: `usage: chrome-devtools-axi press <key> [--full]
3039
+ Press a keyboard key.
3040
+
3041
+ args:
3042
+ <key> Key name, e.g. Enter, Tab, Escape, ArrowDown (required)
3043
+
3044
+ flags:
3045
+ --full Show complete snapshot without truncation
3046
+
3047
+ examples:
3048
+ chrome-devtools-axi press Enter
3049
+ chrome-devtools-axi press Tab --full`,
3050
+ scroll: `usage: chrome-devtools-axi scroll <direction> [--full]
3051
+ Scroll the page in a direction.
3052
+
3053
+ args:
3054
+ <direction> up, down, top, or bottom (default: down)
3055
+
3056
+ flags:
3057
+ --full Show complete snapshot without truncation
3058
+
3059
+ examples:
3060
+ chrome-devtools-axi scroll down
3061
+ chrome-devtools-axi scroll top --full`,
3062
+ back: `usage: chrome-devtools-axi back [--full]
3063
+ Navigate back in browser history.
3064
+
3065
+ flags:
3066
+ --full Show complete snapshot without truncation
3067
+
3068
+ examples:
3069
+ chrome-devtools-axi back
3070
+ chrome-devtools-axi back --full`,
3071
+ wait: `usage: chrome-devtools-axi wait <ms|text>
3072
+ Wait for a duration or for text to appear on the page.
3073
+
3074
+ args:
3075
+ <ms> Milliseconds to wait (numeric)
3076
+ <text> Text to wait for (string)
3077
+
3078
+ examples:
3079
+ chrome-devtools-axi wait 2000
3080
+ chrome-devtools-axi wait "Submit"`,
3081
+ eval: `usage: chrome-devtools-axi eval <js>
3082
+ Evaluate a JavaScript expression in the page context and return the result.
3083
+ A bare expression is wrapped as () => (<js>); pass a function (arrow or
3084
+ function-keyword) for multi-statement logic. No-arg IIFE form (...)() is
3085
+ also accepted and unwrapped automatically.
3086
+
3087
+ args:
3088
+ <js> JavaScript expression (required)
3089
+
3090
+ examples:
3091
+ chrome-devtools-axi eval "document.title"
3092
+ chrome-devtools-axi eval "document.querySelectorAll('a').length"
3093
+ chrome-devtools-axi eval "() => { const rows = [...document.querySelectorAll('tr')]; return rows.map(r => r.textContent) }"`,
3094
+ run: `usage: chrome-devtools-axi run <<'EOF'
3095
+ ...script...
3096
+ EOF
3097
+
3098
+ Execute a JavaScript script from stdin against the current browser session.
3099
+ The script gets a global \`page\` object. Only the script's stdout is returned.
3100
+ Pipe a script via heredoc or stdin \u2014 no file path needed.
3101
+
3102
+ script API (available as global \`page\`):
3103
+ await page.open(url) Navigate, returns { url, status }
3104
+ await page.eval(jsOrFn) Evaluate JS in the page, returns the value
3105
+ await page.snapshot() Get the generation-tagged accessibility tree
3106
+ await page.wait(ms) Wait by duration
3107
+ await page.wait(selector) Wait for CSS selector (30s timeout)
3108
+ await page.wait(selector, ms) Wait for CSS selector with timeout
3109
+ await page.click("@uid") Click an element by fresh ref
3110
+ await page.click(selector) Click via CSS selector
3111
+ await page.fill("@uid", text) Fill a form field by fresh ref
3112
+ await page.fill(selector, text) Fill via CSS selector, including controlled fields
3113
+ await page.type(text) Type at the focused element
3114
+ await page.press(key) Press a keyboard key
3115
+ await page.back() Navigate back
3116
+
3117
+ click and fill accept either @uid refs (from snapshot) or CSS selectors. UID actions verify that the page has not mutated since the snapshot and fail with STALE_REF when freshness cannot be confirmed, including for legacy untagged refs.
3118
+ page.eval accepts functions, arrow functions, and bare expression strings; no-arg IIFE strings are unwrapped automatically.
3119
+
3120
+ examples:
3121
+ chrome-devtools-axi run <<'EOF'
3122
+ await page.open("https://example.com");
3123
+ console.log(await page.eval(() => document.title));
3124
+ EOF
3125
+
3126
+ chrome-devtools-axi run <<'EOF'
3127
+ await page.open("https://en.wikipedia.org/wiki/Ada_Lovelace");
3128
+ await page.click("a[href='/wiki/Charles_Babbage']");
3129
+ await page.wait(".mw-page-title-main");
3130
+ console.log(await page.eval(() => document.title));
3131
+ EOF
3132
+
3133
+ chrome-devtools-axi run <<'EOF'
3134
+ const { status } = await page.open("https://httpbin.org/status/404");
3135
+ console.log("status:", status);
3136
+ EOF`,
3137
+ start: `usage: chrome-devtools-axi start
3138
+ Start the bridge server (launches headless Chrome).
3139
+
3140
+ examples:
3141
+ chrome-devtools-axi start`,
3142
+ stop: `usage: chrome-devtools-axi stop
3143
+ Stop the bridge server and close the browser.
3144
+
3145
+ examples:
3146
+ chrome-devtools-axi stop`,
3147
+ // Page management
3148
+ pages: `usage: chrome-devtools-axi pages
3149
+ List all open pages/tabs in the browser.
3150
+
3151
+ examples:
3152
+ chrome-devtools-axi pages`,
3153
+ newpage: `usage: chrome-devtools-axi newpage <url> [--background] [--full]
3154
+ Open a new tab and navigate to a URL.
3155
+
3156
+ args:
3157
+ <url> URL to open (required)
3158
+
3159
+ flags:
3160
+ --background Open in background without bringing to front
3161
+ --full Show complete snapshot without truncation
3162
+
3163
+ examples:
3164
+ chrome-devtools-axi newpage https://example.com
3165
+ chrome-devtools-axi newpage https://example.com --background`,
3166
+ selectpage: `usage: chrome-devtools-axi selectpage <id> [--full]
3167
+ Switch to a tab by page ID.
3168
+
3169
+ args:
3170
+ <id> Page ID from the pages command (required)
3171
+
3172
+ flags:
3173
+ --full Show complete snapshot without truncation
3174
+
3175
+ examples:
3176
+ chrome-devtools-axi selectpage 1`,
3177
+ closepage: `usage: chrome-devtools-axi closepage <id>
3178
+ Close a tab by page ID. The last open page cannot be closed.
3179
+
3180
+ args:
3181
+ <id> Page ID from the pages command (required)
3182
+
3183
+ examples:
3184
+ chrome-devtools-axi closepage 2`,
3185
+ resize: `usage: chrome-devtools-axi resize <width> <height>
3186
+ Resize the browser window; report requested and actual page dimensions.
3187
+ For an exact CSS viewport use emulate --viewport "390x844x1".
3188
+
3189
+ args:
3190
+ <width> Width in pixels (required)
3191
+ <height> Height in pixels (required)
3192
+
3193
+ examples:
3194
+ chrome-devtools-axi resize 1280 720
3195
+ chrome-devtools-axi resize 390 844`,
3196
+ // Interaction
3197
+ hover: `usage: chrome-devtools-axi hover @<uid> [--full]
3198
+ Hover over an element to trigger hover states.
3199
+
3200
+ args:
3201
+ @<uid> Element ref from snapshot (required). Refs are generation-tagged
3202
+ (e.g. @g3:12) - pass them back exactly as printed. A stale ref
3203
+ returns a STALE_REF error so you know to re-snapshot.
3204
+
3205
+ flags:
3206
+ --full Show complete snapshot without truncation
3207
+
3208
+ examples:
3209
+ chrome-devtools-axi hover @g1:5`,
3210
+ drag: `usage: chrome-devtools-axi drag @<from> @<to> [--full]
3211
+ Drag an element onto another element.
3212
+
3213
+ args:
3214
+ @<from> Element to drag (required). Use refs from the latest snapshot.
3215
+ @<to> Element to drop onto (required). Stale refs return STALE_REF.
3216
+
3217
+ flags:
3218
+ --full Show complete snapshot without truncation
3219
+
3220
+ examples:
3221
+ chrome-devtools-axi drag @g1:3 @g1:7`,
3222
+ fillform: `usage: chrome-devtools-axi fillform @<uid>=<value>... [--full]
3223
+ Fill multiple form fields at once.
3224
+
3225
+ args:
3226
+ @<uid>=<value> One or more field entries from the latest snapshot (required).
3227
+ Stale refs return STALE_REF.
3228
+
3229
+ flags:
3230
+ --full Show complete snapshot without truncation
3231
+
3232
+ examples:
3233
+ chrome-devtools-axi fillform @g1:1="hello" @g1:2="world"
3234
+ chrome-devtools-axi fillform @g2:3="user@email.com" @g2:4="password123"`,
3235
+ dialog: `usage: chrome-devtools-axi dialog <accept|dismiss> [text]
3236
+ Handle a browser dialog (alert, confirm, prompt).
3237
+
3238
+ args:
3239
+ <action> accept or dismiss (required)
3240
+ [text] Optional text to enter into a prompt dialog
3241
+
3242
+ examples:
3243
+ chrome-devtools-axi dialog accept
3244
+ chrome-devtools-axi dialog dismiss
3245
+ chrome-devtools-axi dialog accept "confirmed"`,
3246
+ upload: `usage: chrome-devtools-axi upload @<uid> <path> [--full]
3247
+ Upload a file through a file input element.
3248
+
3249
+ args:
3250
+ @<uid> File input element ref from snapshot (required). Refs are
3251
+ generation-tagged; stale refs return STALE_REF.
3252
+ <path> Local file path to upload (required)
3253
+
3254
+ flags:
3255
+ --full Show complete snapshot without truncation
3256
+
3257
+ examples:
3258
+ chrome-devtools-axi upload @g1:5 ./photo.jpg`,
3259
+ // Emulation
3260
+ emulate: `usage: chrome-devtools-axi emulate [flags]
3261
+ Emulate device features on the selected page.
3262
+
3263
+ flags:
3264
+ --viewport <spec> Viewport like "390x844x3,mobile,touch"
3265
+ --color-scheme <value> dark | light | auto
3266
+ --network <condition> Offline | Slow 3G | Fast 3G | Slow 4G | Fast 4G
3267
+ --cpu <rate> CPU throttling rate 1-20
3268
+ --geolocation <lat>x<lon> Geolocation like "37.7749x-122.4194"
3269
+ --user-agent <string> Custom user agent string
3270
+
3271
+ examples:
3272
+ chrome-devtools-axi emulate --viewport "390x844x3,mobile" --color-scheme dark
3273
+ chrome-devtools-axi emulate --network "Slow 3G" --cpu 4`,
3274
+ // DevTools debugging
3275
+ console: `usage: chrome-devtools-axi console [--type <type>] [--limit <n>] [--page <n>]
3276
+ List console messages for the current page.
3277
+
3278
+ flags:
3279
+ --type <type> Filter by message type. Valid values:
3280
+ log, debug, info, error, warn, dir, dirxml, table, trace,
3281
+ clear, startGroup, startGroupCollapsed, endGroup, assert,
3282
+ profile, profileEnd, count, timeEnd, verbose, issue, all
3283
+ ("all" or omitted returns every message.)
3284
+ --limit <n> Maximum messages to return
3285
+ --page <n> Page number (0-based)
3286
+
3287
+ examples:
3288
+ chrome-devtools-axi console
3289
+ chrome-devtools-axi console --type error --limit 50
3290
+ chrome-devtools-axi console --type all`,
3291
+ "console-get": `usage: chrome-devtools-axi console-get <id>
3292
+ Get a specific console message by ID.
3293
+
3294
+ args:
3295
+ <id> Message ID from the console command (required)
3296
+
3297
+ examples:
3298
+ chrome-devtools-axi console-get 3`,
3299
+ network: `usage: chrome-devtools-axi network [--type <type>] [--limit <n>] [--page <n>]
3300
+ List network requests for the current page.
3301
+
3302
+ flags:
3303
+ --type <type> Filter by resource type. Valid values:
3304
+ document, stylesheet, image, media, font, script, texttrack,
3305
+ xhr, fetch, prefetch, eventsource, websocket, manifest,
3306
+ signedexchange, ping, cspviolationreport, preflight, fedcm,
3307
+ other, all
3308
+ ("all" or omitted returns every request.)
3309
+ --limit <n> Maximum requests to return
3310
+ --page <n> Page number (0-based)
3311
+
3312
+ examples:
3313
+ chrome-devtools-axi network
3314
+ chrome-devtools-axi network --type fetch --limit 50
3315
+ chrome-devtools-axi network --type all`,
3316
+ "network-get": `usage: chrome-devtools-axi network-get [id] [--response-file <path>] [--request-file <path>]
3317
+ Get a specific network request. If id is omitted, gets the selected request.
3318
+
3319
+ args:
3320
+ [id] Request ID from the network command (optional)
3321
+
3322
+ flags:
3323
+ --response-file <path> Save response body to file
3324
+ --request-file <path> Save request body to file
3325
+
3326
+ Relative output paths resolve against the directory where you run the CLI.
3327
+
3328
+ examples:
3329
+ chrome-devtools-axi network-get 42
3330
+ chrome-devtools-axi network-get 42 --response-file ./response.json`,
3331
+ // Performance
3332
+ lighthouse: `usage: chrome-devtools-axi lighthouse [--device <device>] [--mode <mode>] [--output-dir <path>]
3333
+ Run a Lighthouse audit for accessibility, SEO, and best practices.
3334
+
3335
+ flags:
3336
+ --device <device> desktop (default) or mobile
3337
+ --mode <mode> navigation (default) or snapshot
3338
+ --output-dir <path> Directory for reports
3339
+
3340
+ Relative output paths resolve against the directory where you run the CLI.
3341
+
3342
+ examples:
3343
+ chrome-devtools-axi lighthouse
3344
+ chrome-devtools-axi lighthouse --device mobile --output-dir ./reports`,
3345
+ "perf-start": `usage: chrome-devtools-axi perf-start [--no-reload] [--no-auto-stop] [--file <path>]
3346
+ Start a performance trace recording.
3347
+
3348
+ flags:
3349
+ --no-reload Don't reload the page when starting
3350
+ --no-auto-stop Don't automatically stop the trace
3351
+ --file <path> Save raw trace data to file
3352
+
3353
+ Relative output paths resolve against the directory where you run the CLI.
3354
+ Output reports the resolved absolute path.
3355
+
3356
+ examples:
3357
+ chrome-devtools-axi perf-start
3358
+ chrome-devtools-axi perf-start --no-reload --file trace.json.gz`,
3359
+ "perf-stop": `usage: chrome-devtools-axi perf-stop [--file <path>]
3360
+ Stop the active performance trace recording.
3361
+
3362
+ flags:
3363
+ --file <path> Save raw trace data to file
3364
+
3365
+ Relative output paths resolve against the directory where you run the CLI.
3366
+
3367
+ examples:
3368
+ chrome-devtools-axi perf-stop
3369
+ chrome-devtools-axi perf-stop --file trace.json.gz`,
3370
+ "perf-insight": `usage: chrome-devtools-axi perf-insight <set-id> <insight-name>
3371
+ Analyze a specific performance insight from a trace.
3372
+
3373
+ args:
3374
+ <set-id> Insight set ID from trace results (required)
3375
+ <insight-name> Insight name, e.g. "DocumentLatency" (required)
3376
+
3377
+ examples:
3378
+ chrome-devtools-axi perf-insight set1 DocumentLatency
3379
+ chrome-devtools-axi perf-insight set1 LCPBreakdown`,
3380
+ heap: `usage: chrome-devtools-axi heap <path>
3381
+ Capture a heap snapshot for memory leak debugging.
3382
+
3383
+ args:
3384
+ <path> File path to save the .heapsnapshot file (required)
3385
+
3386
+ Relative output paths resolve against the directory where you run the CLI.
3387
+ Output reports the resolved absolute path.
3388
+
3389
+ examples:
3390
+ chrome-devtools-axi heap ./snapshot.heapsnapshot`,
3391
+ setup: `usage: chrome-devtools-axi setup hooks
3392
+ Install or repair agent SessionStart hooks for chrome-devtools-axi ambient context.
3393
+
3394
+ examples:
3395
+ chrome-devtools-axi setup hooks`
3396
+ };
3397
+ function getCommandHelp(command) {
3398
+ return COMMAND_HELP[command] ?? null;
3399
+ }
3400
+ function parseScreenshotArgs(args) {
3401
+ let filePath = null;
3402
+ let uid;
3403
+ let fullPage = false;
3404
+ let format;
3405
+ for (let i = 0; i < args.length; i++) {
3406
+ const a = args[i];
3407
+ if (a === "--uid" && i + 1 < args.length) {
3408
+ const raw = args[++i];
3409
+ uid = raw.startsWith("@") ? raw.slice(1) : raw;
3410
+ } else if (a === "--full-page") {
3411
+ fullPage = true;
3412
+ } else if (a === "--format" && i + 1 < args.length) {
3413
+ format = args[++i];
3414
+ } else if (!a.startsWith("--")) {
3415
+ filePath = a;
3416
+ }
3417
+ }
3418
+ return { filePath, uid, fullPage, format };
3419
+ }
3420
+ function formatScreenshotOutput(filePath) {
3421
+ return encode({ screenshot: filePath });
3422
+ }
3423
+ function parseScreenshotOutputPath(result) {
3424
+ const match = result.match(/^Saved screenshot to ([^\r\n]+)\.\s*$/m);
3425
+ if (!match) {
3426
+ throw new CdpError(
3427
+ "chrome-devtools-mcp did not report a saved screenshot path",
3428
+ "BROWSER_ERROR"
3429
+ );
3430
+ }
3431
+ return match[1];
3432
+ }
3433
+ function formatMcpResult(label, text, suggestions) {
3434
+ const blocks = [];
3435
+ const tr = truncateSnapshot(text, false, 2e3);
3436
+ blocks.push(`${label}:
3437
+ ${tr.text.trimEnd()}`);
3438
+ if (tr.truncated) {
3439
+ blocks[0] += `
3440
+ ... (truncated, ${tr.totalLength} chars total)`;
3441
+ }
3442
+ if (suggestions.length > 0) {
3443
+ blocks.push(renderHelp(suggestions));
3444
+ }
3445
+ return renderOutput2(blocks);
3446
+ }
3447
+ function parseFillFormArgs(args) {
3448
+ const entries = [];
3449
+ for (const arg of args) {
3450
+ if (arg === "--full") continue;
3451
+ const match = arg.match(/^@([^=]+)=(.+)$/);
3452
+ if (!match) continue;
3453
+ const uid = match[1];
3454
+ let value = match[2];
3455
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
3456
+ value = value.slice(1, -1);
3457
+ }
3458
+ entries.push({ uid, value });
3459
+ }
3460
+ return { entries };
3461
+ }
3462
+ function parseOptionalInteger(value) {
3463
+ if (value === void 0) return void 0;
3464
+ const parsed = Number.parseInt(value, 10);
3465
+ return Number.isNaN(parsed) ? void 0 : parsed;
3466
+ }
3467
+ function parseEmulateArgs(args) {
3468
+ const result = {};
3469
+ let i = 0;
3470
+ while (i < args.length) {
3471
+ switch (args[i]) {
3472
+ case "--viewport":
3473
+ result.viewport = args[++i];
3474
+ break;
3475
+ case "--color-scheme":
3476
+ result.colorScheme = args[++i];
3477
+ break;
3478
+ case "--network":
3479
+ result.networkConditions = args[++i];
3480
+ break;
3481
+ case "--cpu": {
3482
+ const cpuThrottlingRate = parseOptionalInteger(args[++i]);
3483
+ if (cpuThrottlingRate !== void 0) {
3484
+ result.cpuThrottlingRate = cpuThrottlingRate;
3485
+ }
3486
+ break;
3487
+ }
3488
+ case "--geolocation":
3489
+ result.geolocation = args[++i];
3490
+ break;
3491
+ case "--user-agent":
3492
+ result.userAgent = args[++i];
3493
+ break;
3494
+ }
3495
+ i++;
3496
+ }
3497
+ return result;
3498
+ }
3499
+ function parseConsoleArgs(args) {
3500
+ const result = {};
3501
+ for (let i = 0; i < args.length; i++) {
3502
+ if (args[i] === "--type" && i + 1 < args.length) {
3503
+ const value = args[++i];
3504
+ if (value.toLowerCase() === "all") delete result.types;
3505
+ else result.types = [value];
3506
+ } else if (args[i] === "--limit" && i + 1 < args.length) {
3507
+ const pageSize = parseOptionalInteger(args[++i]);
3508
+ if (pageSize !== void 0) result.pageSize = pageSize;
3509
+ } else if (args[i] === "--page" && i + 1 < args.length) {
3510
+ const pageIdx = parseOptionalInteger(args[++i]);
3511
+ if (pageIdx !== void 0) result.pageIdx = pageIdx;
3512
+ }
3513
+ }
3514
+ return result;
3515
+ }
3516
+ function parseNetworkArgs(args) {
3517
+ const result = {};
3518
+ for (let i = 0; i < args.length; i++) {
3519
+ if (args[i] === "--type" && i + 1 < args.length) {
3520
+ const value = args[++i];
3521
+ if (value.toLowerCase() === "all") delete result.resourceTypes;
3522
+ else result.resourceTypes = [value];
3523
+ } else if (args[i] === "--limit" && i + 1 < args.length) {
3524
+ const pageSize = parseOptionalInteger(args[++i]);
3525
+ if (pageSize !== void 0) result.pageSize = pageSize;
3526
+ } else if (args[i] === "--page" && i + 1 < args.length) {
3527
+ const pageIdx = parseOptionalInteger(args[++i]);
3528
+ if (pageIdx !== void 0) result.pageIdx = pageIdx;
3529
+ }
3530
+ }
3531
+ return result;
3532
+ }
3533
+ function parseNetworkGetArgs(args) {
3534
+ const result = {};
3535
+ for (let i = 0; i < args.length; i++) {
3536
+ if (args[i] === "--response-file" && i + 1 < args.length) {
3537
+ result.responseFilePath = args[++i];
3538
+ } else if (args[i] === "--request-file" && i + 1 < args.length) {
3539
+ result.requestFilePath = args[++i];
3540
+ } else if (!args[i].startsWith("--")) {
3541
+ const reqid = parseOptionalInteger(args[i]);
3542
+ if (reqid !== void 0) result.reqid = reqid;
3543
+ }
3544
+ }
3545
+ return result;
3546
+ }
3547
+ function parseLighthouseArgs(args) {
3548
+ const result = {};
3549
+ for (let i = 0; i < args.length; i++) {
3550
+ switch (args[i]) {
3551
+ case "--device":
3552
+ result.device = args[++i];
3553
+ break;
3554
+ case "--mode":
3555
+ result.mode = args[++i];
3556
+ break;
3557
+ case "--output-dir":
3558
+ result.outputDirPath = args[++i];
3559
+ break;
3560
+ }
3561
+ }
3562
+ return result;
3563
+ }
3564
+ function parsePerfStartArgs(args) {
3565
+ const result = {};
3566
+ for (let i = 0; i < args.length; i++) {
3567
+ switch (args[i]) {
3568
+ case "--no-reload":
3569
+ result.reload = false;
3570
+ break;
3571
+ case "--no-auto-stop":
3572
+ result.autoStop = false;
3573
+ break;
3574
+ case "--file":
3575
+ result.filePath = args[++i];
3576
+ break;
3577
+ }
3578
+ }
3579
+ return result;
3580
+ }
3581
+ function renderHelp(lines) {
3582
+ if (lines.length === 0) return "";
3583
+ const indented = lines.map((l) => ` ${l}`).join("\n");
3584
+ return `help[${lines.length}]:
3585
+ ${indented}`;
3586
+ }
3587
+ function renderError2(message, code, suggestions = []) {
3588
+ const blocks = [encode({ error: message, code })];
3589
+ if (suggestions.length > 0) {
3590
+ blocks.push(renderHelp(suggestions));
3591
+ }
3592
+ return blocks.join("\n");
3593
+ }
3594
+ function renderOutput2(blocks) {
3595
+ return blocks.filter(Boolean).join("\n");
3596
+ }
3597
+ function splitFullFlag(args) {
3598
+ return {
3599
+ args: args.filter((arg) => arg !== "--full"),
3600
+ full: args.includes("--full")
3601
+ };
3602
+ }
3603
+ function trimSingleTrailingNewline(text) {
3604
+ return text.endsWith("\n") ? text.slice(0, -1) : text;
3605
+ }
3606
+ function wrapsRawStdout(argv) {
3607
+ return (argv ?? process.argv.slice(2))[0] === "run";
3608
+ }
3609
+ function wrapStdout(stdout, argv) {
3610
+ const target = stdout ?? process.stdout;
3611
+ if (!wrapsRawStdout(argv)) {
3612
+ return stdout;
3613
+ }
3614
+ return {
3615
+ write(chunk) {
3616
+ if (!chunk.startsWith(RAW_STDOUT_MARKER)) {
3617
+ return target.write(chunk);
3618
+ }
3619
+ const raw = chunk.slice(RAW_STDOUT_MARKER.length);
3620
+ if (raw === "\n") {
3621
+ return true;
3622
+ }
3623
+ return target.write(raw);
3624
+ }
3625
+ };
3626
+ }
3627
+ function renderUnknownCommand(command) {
3628
+ return renderError2(`Unknown command: ${command}`, "VALIDATION_ERROR", [
3629
+ "Run `chrome-devtools-axi --help` to see available commands"
3630
+ ]) + "\n";
3631
+ }
3632
+ function normalizeMainOptions(options) {
3633
+ if (Array.isArray(options)) {
3634
+ return { argv: options };
3635
+ }
3636
+ return options ?? {};
3637
+ }
3638
+ function resolveArgv(argv) {
3639
+ return argv ?? process.argv.slice(2);
3640
+ }
3641
+ function shouldRenderFullHome(argv) {
3642
+ return argv.length === 1 && argv[0] === "--full";
3643
+ }
3644
+ function formatPageOutput(snapshot, command, url, full = false) {
3645
+ const title = extractTitle(snapshot);
3646
+ const refs = countRefs(snapshot);
3647
+ const blocks = [];
3648
+ const page = {};
3649
+ if (title) page.title = title;
3650
+ if (url) page.url = url;
3651
+ page.refs = refs;
3652
+ blocks.push(encode({ page }));
3653
+ const tr = truncateSnapshot(snapshot, full);
3654
+ let snapshotBlock = `snapshot:
3655
+ ${tr.text.trimEnd()}`;
3656
+ if (tr.truncated) {
3657
+ snapshotBlock += `
3658
+ ... (truncated, ${tr.totalLength} chars total)`;
3659
+ }
3660
+ blocks.push(snapshotBlock);
3661
+ const suggestions = getSuggestions({ command, url, snapshot });
3662
+ if (tr.truncated) {
3663
+ suggestions.push(
3664
+ `Run \`chrome-devtools-axi ${command}${url ? " " + url : ""} --full\` to see complete snapshot`
3665
+ );
3666
+ }
3667
+ if (suggestions.length > 0) {
3668
+ blocks.push(renderHelp(suggestions));
3669
+ }
3670
+ return renderOutput2(blocks);
3671
+ }
3672
+ function stripSnapshotHeader2(text) {
3673
+ const lines = text.split("\n");
3674
+ const treeStart = lines.findIndex((l) => /\bRootWebArea\b|\buid=/.test(l));
3675
+ if (treeStart > 0) return lines.slice(treeStart).join("\n");
3676
+ return text.replace(/^[\s\S]*?##\s+Latest page snapshot\s*\n/, "");
3677
+ }
3678
+ function parseUid(arg) {
3679
+ const current = getCurrentGeneration();
3680
+ const check = checkUidGeneration(arg, current);
3681
+ if (check.stale) {
3682
+ throwStaleRef2(arg, check.refGeneration, current);
3683
+ }
3684
+ return check.uid;
3685
+ }
3686
+ async function stampFresh() {
3687
+ return captureFreshSnapshot(
3688
+ callTool,
3689
+ async () => stripSnapshotHeader2(await callTool("take_snapshot"))
3690
+ );
3691
+ }
3692
+ function throwStaleRef2(arg, refGeneration, currentGeneration) {
3693
+ const refRaw = arg.startsWith("@") ? arg.slice(1) : arg;
3694
+ throw new CdpError(
3695
+ `Stale ref @${refRaw}: from snapshot generation ${refGeneration}, current is ${currentGeneration}. Re-snapshot to get fresh refs.`,
3696
+ "STALE_REF",
3697
+ [
3698
+ "Run `chrome-devtools-axi snapshot` to capture current refs, then retry the action"
3699
+ ]
3700
+ );
3701
+ }
3702
+ async function parseUidFresh2(arg, caller = callTool) {
3703
+ return parseUidFresh(arg, caller);
3704
+ }
3705
+ function isRecoverableOpenError2(error) {
3706
+ if (!(error instanceof CdpError)) return false;
3707
+ if (error.code !== "BROWSER_ERROR") return false;
3708
+ return /not connected|session (?:closed|not found)|no page/i.test(
3709
+ error.message
3710
+ );
3711
+ }
3712
+ async function callWithSnapshot(name, args) {
3713
+ const result = await callTool(name, args);
3714
+ if (/^# Open dialog\b/m.test(result)) {
3715
+ throw new CdpError("The action opened a dialog. Do not replay it; handle the dialog first.", "DIALOG_PENDING", [
3716
+ "Run `chrome-devtools-axi dialog accept` or `chrome-devtools-axi dialog dismiss` in the same session"
3717
+ ]);
3718
+ }
3719
+ return stampFresh();
3720
+ }
3721
+ var SCROLL_FUNCTIONS = {
3722
+ up: "() => window.scrollBy(0, -500)",
3723
+ down: "() => window.scrollBy(0, 500)",
3724
+ top: "() => window.scrollTo(0, 0)",
3725
+ bottom: "() => window.scrollTo(0, document.body.scrollHeight)"
3726
+ };
3727
+ async function handleOpen(args, full) {
3728
+ const url = args[0];
3729
+ if (!url) {
3730
+ throw new CdpError("Missing URL", "VALIDATION_ERROR", [
3731
+ "Run `chrome-devtools-axi open https://example.com` to navigate to a page"
3732
+ ]);
3733
+ }
3734
+ try {
3735
+ await callTool("navigate_page", { type: "url", url });
3736
+ } catch (error) {
3737
+ if (!isRecoverableOpenError2(error)) {
3738
+ throw error;
3739
+ }
3740
+ await callTool("new_page", { url });
3741
+ }
3742
+ const snapshot = await stampFresh();
3743
+ return formatPageOutput(snapshot, "open", url, full);
3744
+ }
3745
+ async function handleSnapshot(full) {
3746
+ const snapshot = await stampFresh();
3747
+ return formatPageOutput(snapshot, "snapshot", void 0, full);
3748
+ }
3749
+ async function handleScreenshot(args) {
3750
+ const parsed = parseScreenshotArgs(args);
3751
+ if (!parsed.filePath) {
3752
+ throw new CdpError("Missing file path", "VALIDATION_ERROR", [
3753
+ "Run `chrome-devtools-axi screenshot ./page.png` to save a screenshot"
3754
+ ]);
3755
+ }
3756
+ const filePath = resolveOutputPath(parsed.filePath);
3757
+ const toolArgs = { filePath };
3758
+ if (parsed.uid) toolArgs.uid = await parseUidFresh2(parsed.uid);
3759
+ if (parsed.fullPage) toolArgs.fullPage = true;
3760
+ if (parsed.format) toolArgs.format = parsed.format;
3761
+ const result = await callTool("take_screenshot", toolArgs);
3762
+ return formatScreenshotOutput(parseScreenshotOutputPath(result));
3763
+ }
3764
+ async function handleClick(args, full) {
3765
+ const uid = args[0];
3766
+ if (!uid) {
3767
+ throw new CdpError("Missing element ref", "VALIDATION_ERROR", [
3768
+ "Run `chrome-devtools-axi click @<uid>` \u2014 get uid from snapshot"
3769
+ ]);
3770
+ }
3771
+ const snapshot = await callWithSnapshot("click", {
3772
+ uid: await parseUidFresh2(uid)
3773
+ });
3774
+ return formatPageOutput(snapshot, "click", void 0, full);
3775
+ }
3776
+ async function handleFill(args, full) {
3777
+ const uid = args[0];
3778
+ const value = args.slice(1).join(" ");
3779
+ if (!uid) {
3780
+ throw new CdpError("Missing element ref", "VALIDATION_ERROR", [
3781
+ 'Run `chrome-devtools-axi fill @<uid> "text"` \u2014 get uid from snapshot'
3782
+ ]);
3783
+ }
3784
+ if (!value) {
3785
+ throw new CdpError("Missing fill text", "VALIDATION_ERROR", [
3786
+ 'Run `chrome-devtools-axi fill @<uid> "text"` to fill the field'
3787
+ ]);
3788
+ }
3789
+ const snapshot = await callWithSnapshot("fill", {
3790
+ uid: await parseUidFresh2(uid),
3791
+ value
3792
+ });
3793
+ return formatPageOutput(snapshot, "fill", void 0, full);
3794
+ }
3795
+ async function handlePress(args, full) {
3796
+ const key = args[0];
3797
+ if (!key) {
3798
+ throw new CdpError("Missing key name", "VALIDATION_ERROR", [
3799
+ "Run `chrome-devtools-axi press Enter` to press a key"
3800
+ ]);
3801
+ }
3802
+ const snapshot = await callWithSnapshot("press_key", { key });
3803
+ return formatPageOutput(snapshot, "press", void 0, full);
3804
+ }
3805
+ async function handleType(args, full) {
3806
+ const text = args.join(" ");
3807
+ if (!text) {
3808
+ throw new CdpError("Missing text", "VALIDATION_ERROR", [
3809
+ 'Run `chrome-devtools-axi type "hello"` to type text'
3810
+ ]);
3811
+ }
3812
+ await callTool("type_text", { text });
3813
+ const snapshot = await stampFresh();
3814
+ return formatPageOutput(snapshot, "type", void 0, full);
3815
+ }
3816
+ async function handleScroll(args, full) {
3817
+ const dir = (args[0] ?? "down").toLowerCase();
3818
+ const fn = SCROLL_FUNCTIONS[dir];
3819
+ if (!fn) {
3820
+ throw new CdpError(`Unknown scroll direction: ${dir}`, "VALIDATION_ERROR", [
3821
+ "Run `chrome-devtools-axi scroll down` \u2014 directions: up, down, top, bottom"
3822
+ ]);
3823
+ }
3824
+ await callTool("evaluate_script", { function: fn });
3825
+ const snapshot = await stampFresh();
3826
+ return formatPageOutput(snapshot, "scroll", void 0, full);
3827
+ }
3828
+ async function handleBack(full) {
3829
+ await callTool("navigate_page", { type: "back" });
3830
+ const snapshot = await stampFresh();
3831
+ return formatPageOutput(snapshot, "back", void 0, full);
3832
+ }
3833
+ async function handleWait(args) {
3834
+ const target = args[0];
3835
+ if (!target) {
3836
+ throw new CdpError(
3837
+ "Missing wait target (milliseconds or text)",
3838
+ "VALIDATION_ERROR",
3839
+ [
3840
+ "Run `chrome-devtools-axi wait 2000` to wait 2 seconds",
3841
+ 'Run `chrome-devtools-axi wait "Submit"` to wait for text to appear'
3842
+ ]
3843
+ );
3844
+ }
3845
+ const isNumeric = /^\d+$/.test(target);
3846
+ if (isNumeric) {
3847
+ await callTool("evaluate_script", {
3848
+ function: wrapJsExpression(`new Promise(r => setTimeout(r, ${target}))`)
3849
+ });
3850
+ } else {
3851
+ await callTool("wait_for", { text: [target] });
3852
+ }
3853
+ const blocks = [];
3854
+ blocks.push(encode({ waited: target }));
3855
+ const suggestions = getSuggestions({ command: "wait" });
3856
+ if (suggestions.length > 0) blocks.push(renderHelp(suggestions));
3857
+ return renderOutput2(blocks);
3858
+ }
3859
+ function parseEvalResult(output) {
3860
+ const jsonBlock = output.match(/```json\n([\s\S]*?)\n```/);
3861
+ if (jsonBlock) return jsonBlock[1].trim();
3862
+ const preamble = "Script ran on page and returned:";
3863
+ if (output.includes(preamble))
3864
+ return output.slice(output.indexOf(preamble) + preamble.length).trim();
3865
+ return output.trim();
3866
+ }
3867
+ async function handleEval(args, full) {
3868
+ const js = args.join(" ");
3869
+ if (!js) {
3870
+ throw new CdpError("Missing JavaScript expression", "VALIDATION_ERROR", [
3871
+ 'Run `chrome-devtools-axi eval "document.title"` to evaluate JavaScript'
3872
+ ]);
3873
+ }
3874
+ const output = await callTool("evaluate_script", {
3875
+ function: wrapJsExpression(js)
3876
+ });
3877
+ const blocks = [];
3878
+ const raw = parseEvalResult(output);
3879
+ const tr = full ? { text: raw, truncated: false, totalLength: raw.length } : truncateText(raw);
3880
+ blocks.push(encode({ result: tr.text }));
3881
+ const suggestions = getSuggestions({ command: "eval" });
3882
+ if (tr.truncated) {
3883
+ suggestions.push(
3884
+ "Result was truncated \u2014 re-run with --full flag, or use .slice() / filter in your JS expression"
3885
+ );
3886
+ }
3887
+ if (suggestions.length > 0) blocks.push(renderHelp(suggestions));
3888
+ return renderOutput2(blocks);
3889
+ }
3890
+ async function handleStart() {
3891
+ const port = await ensureBridge();
3892
+ return encode({ status: "ready", port });
3893
+ }
3894
+ function formatStopOutput(wasStopped) {
3895
+ return encode({ status: wasStopped ? "stopped" : "stopped (no-op)" });
3896
+ }
3897
+ async function handleStop() {
3898
+ const wasStopped = await stopBridge();
3899
+ return formatStopOutput(wasStopped);
3900
+ }
3901
+ async function handlePages() {
3902
+ const result = await callTool("list_pages");
3903
+ const pages = overlaySessionSelected(parsePagesList(result));
3904
+ if (pages.length === 0) {
3905
+ return "pages: 0 pages open";
3906
+ }
3907
+ const blocks = [];
3908
+ const header = `pages[${pages.length}]{id,url,selected}:`;
3909
+ const rows = pages.map((p) => ` ${p.id},${p.url},${p.selected}`);
3910
+ blocks.push(`${header}
3911
+ ${rows.join("\n")}`);
3912
+ blocks.push(
3913
+ renderHelp([
3914
+ "Run `chrome-devtools-axi selectpage <id>` to switch tabs",
3915
+ "Run `chrome-devtools-axi newpage <url>` to open a new tab"
3916
+ ])
3917
+ );
3918
+ return renderOutput2(blocks);
3919
+ }
3920
+ async function handleNewPage(args, full) {
3921
+ const url = args.filter((a) => !a.startsWith("--"))[0];
3922
+ if (!url) {
3923
+ throw new CdpError("Missing URL", "VALIDATION_ERROR", [
3924
+ "Run `chrome-devtools-axi newpage https://example.com` to open a new tab"
3925
+ ]);
3926
+ }
3927
+ const background = args.includes("--background");
3928
+ const toolArgs = { url };
3929
+ if (background) toolArgs.background = true;
3930
+ await callTool("new_page", toolArgs);
3931
+ const snapshot = await stampFresh();
3932
+ return formatPageOutput(snapshot, "newpage", url, full);
3933
+ }
3934
+ async function handleSelectPage(args, full) {
3935
+ const id = args[0];
3936
+ if (!id) {
3937
+ throw new CdpError("Missing page ID", "VALIDATION_ERROR", [
3938
+ "Run `chrome-devtools-axi selectpage <id>` \u2014 get ID from `pages` command"
3939
+ ]);
3940
+ }
3941
+ const pageId = parseInt(id, 10);
3942
+ if (isNaN(pageId)) {
3943
+ throw new CdpError(`Invalid page ID: ${id}`, "VALIDATION_ERROR", [
3944
+ "Run `chrome-devtools-axi pages` to list available page IDs"
3945
+ ]);
3946
+ }
3947
+ await callTool("select_page", { pageId });
3948
+ const snapshot = await stampFresh();
3949
+ return formatPageOutput(snapshot, "selectpage", void 0, full);
3950
+ }
3951
+ async function handleClosePage(args) {
3952
+ const id = args[0];
3953
+ if (!id) {
3954
+ throw new CdpError("Missing page ID", "VALIDATION_ERROR", [
3955
+ "Run `chrome-devtools-axi closepage <id>` \u2014 get ID from `pages` command"
3956
+ ]);
3957
+ }
3958
+ const pageId = parseInt(id, 10);
3959
+ if (isNaN(pageId)) {
3960
+ throw new CdpError(`Invalid page ID: ${id}`, "VALIDATION_ERROR", [
3961
+ "Run `chrome-devtools-axi pages` to list available page IDs"
3962
+ ]);
3963
+ }
3964
+ const beforeResult = await callTool("list_pages");
3965
+ const pagesBefore = parsePagesList(beforeResult);
3966
+ if (pagesBefore.length <= 1) {
3967
+ const blocks = [
3968
+ encode({ status: "cannot close the last open page (no-op)" })
3969
+ ];
3970
+ blocks.push(
3971
+ renderHelp([
3972
+ "Run `chrome-devtools-axi newpage <url>` to open another tab first",
3973
+ "Run `chrome-devtools-axi stop` to shut down the browser entirely"
3974
+ ])
3975
+ );
3976
+ return renderOutput2(blocks);
3977
+ }
3978
+ await callTool("close_page", { pageId });
3979
+ return encode({ status: "closed", pageId });
3980
+ }
3981
+ async function handleResize(args) {
3982
+ const [widthStr, heightStr] = args;
3983
+ if (!widthStr || !heightStr) {
3984
+ throw new CdpError("Missing width and/or height", "VALIDATION_ERROR", [
3985
+ "Run `chrome-devtools-axi resize 1280 720` to resize the viewport"
3986
+ ]);
3987
+ }
3988
+ const width = parseInt(widthStr, 10);
3989
+ const height = parseInt(heightStr, 10);
3990
+ if (isNaN(width) || isNaN(height)) {
3991
+ throw new CdpError("Width and height must be numbers", "VALIDATION_ERROR", [
3992
+ "Run `chrome-devtools-axi resize 1280 720` to resize the viewport"
3993
+ ]);
3994
+ }
3995
+ await callTool("resize_page", { width, height });
3996
+ const result = await callTool("evaluate_script", {
3997
+ function: "() => ({width: innerWidth, height: innerHeight, devicePixelRatio})"
3998
+ });
3999
+ const match = result.match(/```(?:json)?\s*([\s\S]*?)```/);
4000
+ let actual;
4001
+ try {
4002
+ actual = match ? JSON.parse(match[1]) : void 0;
4003
+ } catch {
4004
+ }
4005
+ return encode({
4006
+ resized: {
4007
+ requested: { width, height },
4008
+ actual: actual ?? null,
4009
+ mode: "window",
4010
+ exact: actual?.width === width && actual?.height === height
4011
+ }
4012
+ });
4013
+ }
4014
+ async function handleHover(args, full) {
4015
+ const uid = args[0];
4016
+ if (!uid) {
4017
+ throw new CdpError("Missing element ref", "VALIDATION_ERROR", [
4018
+ "Run `chrome-devtools-axi hover @<uid>` \u2014 get uid from snapshot"
4019
+ ]);
4020
+ }
4021
+ const snapshot = await callWithSnapshot("hover", {
4022
+ uid: await parseUidFresh2(uid)
4023
+ });
4024
+ return formatPageOutput(snapshot, "hover", void 0, full);
4025
+ }
4026
+ async function handleDrag(args, full) {
4027
+ const from = args[0];
4028
+ const to = args[1];
4029
+ if (!from || !to) {
4030
+ throw new CdpError("Missing element refs", "VALIDATION_ERROR", [
4031
+ "Run `chrome-devtools-axi drag @<from> @<to>` \u2014 get uids from snapshot"
4032
+ ]);
4033
+ }
4034
+ const snapshot = await callWithSnapshot("drag", {
4035
+ from_uid: await parseUidFresh2(from),
4036
+ to_uid: await parseUidFresh2(to)
4037
+ });
4038
+ return formatPageOutput(snapshot, "drag", void 0, full);
4039
+ }
4040
+ async function handleFillForm(args, full) {
4041
+ const { entries } = parseFillFormArgs(args);
4042
+ if (entries.length === 0) {
4043
+ throw new CdpError("No valid field entries", "VALIDATION_ERROR", [
4044
+ 'Run `chrome-devtools-axi fillform @g1:1="hello" @g1:2="world"` to fill multiple fields'
4045
+ ]);
4046
+ }
4047
+ const validated = await Promise.all(
4048
+ entries.map(async (e) => ({
4049
+ uid: await parseUidFresh2(e.uid),
4050
+ value: e.value
4051
+ }))
4052
+ );
4053
+ const snapshot = await callWithSnapshot("fill_form", { elements: validated });
4054
+ return formatPageOutput(snapshot, "fillform", void 0, full);
4055
+ }
4056
+ async function handleDialog(args) {
4057
+ const action = args[0];
4058
+ if (!action || action !== "accept" && action !== "dismiss") {
4059
+ throw new CdpError("Missing or invalid action", "VALIDATION_ERROR", [
4060
+ "Run `chrome-devtools-axi dialog accept` or `chrome-devtools-axi dialog dismiss`"
4061
+ ]);
4062
+ }
4063
+ const params = { action };
4064
+ const promptText = args.slice(1).join(" ");
4065
+ if (promptText) params.promptText = promptText;
4066
+ const snapshot = await callWithSnapshot("handle_dialog", params);
4067
+ return encode({ dialog: action }) + "\n" + formatPageOutput(snapshot, "dialog");
4068
+ }
4069
+ async function handleUpload(args, full) {
4070
+ const uid = args[0];
4071
+ const filePath = args[1];
4072
+ if (!uid) {
4073
+ throw new CdpError("Missing element ref", "VALIDATION_ERROR", [
4074
+ "Run `chrome-devtools-axi upload @<uid> <path>` \u2014 get uid from snapshot"
4075
+ ]);
4076
+ }
4077
+ if (!filePath) {
4078
+ throw new CdpError("Missing file path", "VALIDATION_ERROR", [
4079
+ "Run `chrome-devtools-axi upload @<uid> /path/to/file` to upload a file"
4080
+ ]);
4081
+ }
4082
+ const snapshot = await callWithSnapshot("upload_file", {
4083
+ uid: await parseUidFresh2(uid),
4084
+ filePaths: [resolveOutputPath(filePath)]
4085
+ });
4086
+ return formatPageOutput(snapshot, "upload", void 0, full);
4087
+ }
4088
+ async function handleEmulate(args) {
4089
+ const parsed = parseEmulateArgs(args);
4090
+ await callTool("emulate", parsed);
4091
+ return encode({ emulated: parsed });
4092
+ }
4093
+ async function handleConsole(args) {
4094
+ const parsed = parseConsoleArgs(args);
4095
+ const result = await callTool("list_console_messages", parsed);
4096
+ return formatMcpResult("console", result, [
4097
+ "Run `chrome-devtools-axi console-get <id>` to see a specific message",
4098
+ "Run `chrome-devtools-axi console --type error` to filter by type"
4099
+ ]);
4100
+ }
4101
+ async function handleConsoleGet(args) {
4102
+ const id = args[0];
4103
+ if (!id) {
4104
+ throw new CdpError("Missing console message id", "VALIDATION_ERROR", [
4105
+ "Run `chrome-devtools-axi console-get <id>` \u2014 get id from `chrome-devtools-axi console`"
4106
+ ]);
4107
+ }
4108
+ const msgid = parseOptionalInteger(id);
4109
+ if (msgid === void 0) {
4110
+ throw new CdpError(
4111
+ `Invalid console message id: ${id}`,
4112
+ "VALIDATION_ERROR",
4113
+ ["Run `chrome-devtools-axi console` to list available message ids"]
4114
+ );
4115
+ }
4116
+ const result = await callTool("get_console_message", { msgid });
4117
+ return formatMcpResult("message", result, []);
4118
+ }
4119
+ async function handleNetwork(args) {
4120
+ const parsed = parseNetworkArgs(args);
4121
+ const result = await callTool("list_network_requests", parsed);
4122
+ return formatMcpResult("network", result, [
4123
+ "Run `chrome-devtools-axi network-get <id>` to see request details",
4124
+ "Run `chrome-devtools-axi network --type fetch` to filter by type"
4125
+ ]);
4126
+ }
4127
+ async function handleNetworkGet(args) {
4128
+ const parsed = parseNetworkGetArgs(args);
4129
+ const toolArgs = { ...parsed };
4130
+ if (toolArgs.responseFilePath) {
4131
+ toolArgs.responseFilePath = resolveOutputPath(toolArgs.responseFilePath);
4132
+ }
4133
+ if (toolArgs.requestFilePath) {
4134
+ toolArgs.requestFilePath = resolveOutputPath(toolArgs.requestFilePath);
4135
+ }
4136
+ const result = await callTool("get_network_request", toolArgs);
4137
+ return formatMcpResult("request", result, []);
4138
+ }
4139
+ async function handleLighthouse(args) {
4140
+ const opts = parseLighthouseArgs(args);
4141
+ if (opts.outputDirPath) {
4142
+ opts.outputDirPath = resolveOutputPath(opts.outputDirPath);
4143
+ }
4144
+ const result = await callTool("lighthouse_audit", opts);
4145
+ return formatMcpResult("lighthouse", result, []);
4146
+ }
4147
+ async function handlePerfStart(args) {
4148
+ const opts = parsePerfStartArgs(args);
4149
+ if (opts.filePath) opts.filePath = resolveOutputPath(opts.filePath);
4150
+ await callTool("performance_start_trace", opts);
4151
+ return encode({ trace: "started", ...opts });
4152
+ }
4153
+ async function handlePerfStop(args) {
4154
+ const toolArgs = {};
4155
+ for (let i = 0; i < args.length; i++) {
4156
+ if (args[i] === "--file" && i + 1 < args.length) {
4157
+ toolArgs.filePath = resolveOutputPath(args[++i]);
4158
+ }
4159
+ }
4160
+ const result = await callTool("performance_stop_trace", toolArgs);
4161
+ return formatMcpResult("trace", result, [
4162
+ "Run `chrome-devtools-axi perf-insight <set-id> <insight-name>` to analyze insights"
4163
+ ]);
4164
+ }
4165
+ async function handlePerfInsight(args) {
4166
+ const [setId, insightName] = args;
4167
+ if (!setId || !insightName) {
4168
+ throw new CdpError("Missing required arguments", "VALIDATION_ERROR", [
4169
+ "Run `chrome-devtools-axi perf-insight <set-id> <insight-name>` to analyze an insight"
4170
+ ]);
4171
+ }
4172
+ const result = await callTool("performance_analyze_insight", {
4173
+ insightSetId: setId,
4174
+ insightName
4175
+ });
4176
+ return formatMcpResult("insight", result, []);
4177
+ }
4178
+ async function handleHeap(args) {
4179
+ const rawPath = args[0];
4180
+ if (!rawPath) {
4181
+ throw new CdpError("Missing file path", "VALIDATION_ERROR", [
4182
+ "Run `chrome-devtools-axi heap ./snapshot.heapsnapshot` to take a heap snapshot"
4183
+ ]);
4184
+ }
4185
+ const filePath = resolveOutputPath(rawPath);
4186
+ await callTool("take_heapsnapshot", { filePath });
4187
+ return encode({ heap: filePath });
4188
+ }
4189
+ async function handleRun() {
4190
+ if (process.stdin.isTTY) {
4191
+ throw new CdpError("No script provided on stdin", "VALIDATION_ERROR", [
4192
+ "Pipe a script: chrome-devtools-axi run <<'EOF'\\n...\\nEOF"
4193
+ ]);
4194
+ }
4195
+ const content = await readStdin();
4196
+ if (!content.trim()) {
4197
+ throw new CdpError("Empty script on stdin", "VALIDATION_ERROR", [
4198
+ "Pipe a script: chrome-devtools-axi run <<'EOF'\\n...\\nEOF"
4199
+ ]);
4200
+ }
4201
+ const result = await runScript(content, callTool);
4202
+ return RAW_STDOUT_MARKER + trimSingleTrailingNewline(result.stdout);
4203
+ }
4204
+ async function handleSetup(args) {
4205
+ if (args.length !== 1 || args[0] !== "hooks") {
4206
+ throw new CdpError("Unknown setup action", "VALIDATION_ERROR", [
4207
+ "Run `chrome-devtools-axi setup hooks`"
4208
+ ]);
4209
+ }
4210
+ installHooksOrThrow();
4211
+ return renderOutput2([
4212
+ "hooks:\n status: installed\n integrations: Claude Code, Codex, OpenCode",
4213
+ renderHelp([
4214
+ "Restart your agent session to receive chrome-devtools-axi ambient context"
4215
+ ])
4216
+ ]);
4217
+ }
4218
+ async function handleHome(_full) {
4219
+ const result = await getSessionSnapshotIfRunning();
4220
+ if (!result) {
4221
+ return renderOutput2([
4222
+ encode({ browser: "no active session" }),
4223
+ renderHelp(["Run `chrome-devtools-axi open <url>` to start browsing"])
4224
+ ]);
4225
+ }
4226
+ const snapshot = stripSnapshotHeader2(result);
4227
+ const title = extractTitle(snapshot);
4228
+ const refs = countRefs(snapshot);
4229
+ const page = {};
4230
+ if (title) page.title = title;
4231
+ page.refs = refs;
4232
+ const help = [
4233
+ "Run `chrome-devtools-axi snapshot` to see page content",
4234
+ "Run `chrome-devtools-axi open <url>` to navigate to a URL",
4235
+ "Run `chrome-devtools-axi --help` to see full command list"
4236
+ ];
4237
+ return renderOutput2([encode({ page }), renderHelp(help)]);
4238
+ }
4239
+ function withFullFlag(handler) {
4240
+ return (args) => {
4241
+ const parsed = splitFullFlag(args);
4242
+ return handler(parsed.args, parsed.full);
4243
+ };
4244
+ }
4245
+ function withoutFullFlag(handler) {
4246
+ return (args) => handler(splitFullFlag(args).args);
4247
+ }
4248
+ function validateCommandFlags(command, args, allowedFlags, valueFlags, dashPositionalSlots, positionalArgsBeforeText = args.length) {
4249
+ let positionalArgs = 0;
4250
+ for (let i = 0; i < args.length; i++) {
4251
+ const arg = args[i];
4252
+ if (positionalArgs === positionalArgsBeforeText) return;
4253
+ if (arg === "--help" || allowedFlags.includes(arg)) {
4254
+ if (valueFlags.includes(arg)) i += 1;
4255
+ continue;
4256
+ }
4257
+ if (arg !== "-" && arg.startsWith("-") && (arg.startsWith("--") || !dashPositionalSlots.includes(positionalArgs))) {
4258
+ throw new CdpError(
4259
+ `Unknown flag ${arg} for \`${command}\``,
4260
+ "VALIDATION_ERROR",
4261
+ [`Run \`chrome-devtools-axi ${command} --help\` to see valid flags`]
4262
+ );
4263
+ }
4264
+ positionalArgs += 1;
4265
+ }
4266
+ }
4267
+ var COMMAND_HANDLERS = {
4268
+ open: withFullFlag(handleOpen),
4269
+ snapshot: async (args) => handleSnapshot(splitFullFlag(args).full),
4270
+ screenshot: withoutFullFlag(handleScreenshot),
4271
+ click: withFullFlag(handleClick),
4272
+ fill: withFullFlag(handleFill),
4273
+ type: withFullFlag(handleType),
4274
+ press: withFullFlag(handlePress),
4275
+ scroll: withFullFlag(handleScroll),
4276
+ back: async (args) => handleBack(splitFullFlag(args).full),
4277
+ wait: withoutFullFlag(handleWait),
4278
+ eval: withFullFlag(handleEval),
4279
+ run: async () => handleRun(),
4280
+ hover: withFullFlag(handleHover),
4281
+ drag: withFullFlag(handleDrag),
4282
+ fillform: withFullFlag(handleFillForm),
4283
+ dialog: withoutFullFlag(handleDialog),
4284
+ upload: withFullFlag(handleUpload),
4285
+ pages: async () => handlePages(),
4286
+ newpage: withFullFlag(handleNewPage),
4287
+ selectpage: withFullFlag(handleSelectPage),
4288
+ closepage: withoutFullFlag(handleClosePage),
4289
+ resize: withoutFullFlag(handleResize),
4290
+ emulate: withoutFullFlag(handleEmulate),
4291
+ console: withoutFullFlag(handleConsole),
4292
+ "console-get": withoutFullFlag(handleConsoleGet),
4293
+ network: withoutFullFlag(handleNetwork),
4294
+ "network-get": withoutFullFlag(handleNetworkGet),
4295
+ lighthouse: withoutFullFlag(handleLighthouse),
4296
+ "perf-start": withoutFullFlag(handlePerfStart),
4297
+ "perf-stop": withoutFullFlag(handlePerfStop),
4298
+ "perf-insight": withoutFullFlag(handlePerfInsight),
4299
+ heap: withoutFullFlag(handleHeap),
4300
+ start: async () => handleStart(),
4301
+ stop: async () => handleStop(),
4302
+ setup: withoutFullFlag(handleSetup)
4303
+ };
4304
+ var COMMAND_FLAGS = {
4305
+ open: ["--full"],
4306
+ screenshot: ["--uid", "--full-page", "--format"],
4307
+ snapshot: ["--full"],
4308
+ click: ["--full"],
4309
+ fill: ["--full"],
4310
+ type: ["--full"],
4311
+ press: ["--full"],
4312
+ scroll: ["--full"],
4313
+ back: ["--full"],
4314
+ wait: [],
4315
+ eval: ["--full"],
4316
+ run: [],
4317
+ hover: ["--full"],
4318
+ drag: ["--full"],
4319
+ fillform: ["--full"],
4320
+ dialog: [],
4321
+ upload: ["--full"],
4322
+ pages: [],
4323
+ newpage: ["--background", "--full"],
4324
+ selectpage: ["--full"],
4325
+ closepage: [],
4326
+ resize: [],
4327
+ emulate: [
4328
+ "--viewport",
4329
+ "--color-scheme",
4330
+ "--network",
4331
+ "--cpu",
4332
+ "--geolocation",
4333
+ "--user-agent"
4334
+ ],
4335
+ console: ["--type", "--limit", "--page"],
4336
+ "console-get": [],
4337
+ network: ["--type", "--limit", "--page"],
4338
+ "network-get": ["--response-file", "--request-file"],
4339
+ lighthouse: ["--device", "--mode", "--output-dir"],
4340
+ "perf-start": ["--no-reload", "--no-auto-stop", "--file"],
4341
+ "perf-stop": ["--file"],
4342
+ "perf-insight": [],
4343
+ heap: [],
4344
+ start: [],
4345
+ stop: [],
4346
+ setup: []
4347
+ };
4348
+ var COMMAND_VALUE_FLAGS = {
4349
+ screenshot: ["--uid", "--format"],
4350
+ emulate: COMMAND_FLAGS.emulate,
4351
+ console: COMMAND_FLAGS.console,
4352
+ network: COMMAND_FLAGS.network,
4353
+ "network-get": COMMAND_FLAGS["network-get"],
4354
+ lighthouse: COMMAND_FLAGS.lighthouse,
4355
+ "perf-start": ["--file"],
4356
+ "perf-stop": COMMAND_FLAGS["perf-stop"]
4357
+ };
4358
+ var COMMAND_POSITIONAL_TEXT_START = {
4359
+ fill: 1,
4360
+ type: 0,
4361
+ wait: 0,
4362
+ eval: 0,
4363
+ dialog: 1
4364
+ };
4365
+ var COMMAND_DASH_POSITIONAL_SLOTS = {
4366
+ heap: [0],
4367
+ upload: [1],
4368
+ screenshot: [0]
4369
+ };
4370
+ var COMMANDS = Object.fromEntries(
4371
+ Object.entries(COMMAND_HANDLERS).map(([command, handler]) => [
4372
+ command,
4373
+ (args) => {
4374
+ validateCommandFlags(
4375
+ command,
4376
+ args,
4377
+ COMMAND_FLAGS[command] ?? [],
4378
+ COMMAND_VALUE_FLAGS[command] ?? [],
4379
+ COMMAND_DASH_POSITIONAL_SLOTS[command] ?? [],
4380
+ COMMAND_POSITIONAL_TEXT_START[command]
4381
+ );
4382
+ return handler(args);
4383
+ }
4384
+ ])
4385
+ );
4386
+ async function main(options = {}) {
4387
+ const normalized = normalizeMainOptions(options);
4388
+ const requestedArgv = resolveArgv(normalized.argv);
4389
+ const homeFull = shouldRenderFullHome(requestedArgv);
4390
+ const argv = homeFull ? [] : normalized.argv;
4391
+ const stdout = wrapStdout(normalized.stdout, argv);
4392
+ await runAxiCli({
4393
+ ...argv ? { argv } : {},
4394
+ ...stdout ? { stdout } : {},
4395
+ description: HOME_DESCRIPTION,
4396
+ version: VERSION,
4397
+ topLevelHelp: TOP_HELP,
4398
+ home: async (args) => handleHome(homeFull || splitFullFlag(args).full),
4399
+ commands: COMMANDS,
4400
+ getCommandHelp,
4401
+ renderUnknownCommand
4402
+ });
4403
+ }
4404
+ export {
4405
+ HOME_DESCRIPTION,
4406
+ TOP_HELP,
4407
+ formatMcpResult,
4408
+ formatScreenshotOutput,
4409
+ formatStopOutput,
4410
+ getCommandHelp,
4411
+ main,
4412
+ parseConsoleArgs,
4413
+ parseEmulateArgs,
4414
+ parseFillFormArgs,
4415
+ parseLighthouseArgs,
4416
+ parseNetworkArgs,
4417
+ parseNetworkGetArgs,
4418
+ parsePagesList,
4419
+ parsePerfStartArgs,
4420
+ parseScreenshotArgs,
4421
+ parseUid,
4422
+ parseUidFresh2 as parseUidFresh,
4423
+ wrapJsExpression
4424
+ };