browser-debugger-cli 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/.claude/skills/bdg/SKILL.md +100 -186
  2. package/README.md +4 -4
  3. package/dist/commands/console.js +5 -1
  4. package/dist/commands/dom/a11y.d.ts +1 -1
  5. package/dist/commands/dom/a11y.js +20 -20
  6. package/dist/commands/dom/eval.d.ts +2 -1
  7. package/dist/commands/dom/eval.js +21 -3
  8. package/dist/commands/dom/formInteraction.js +1 -1
  9. package/dist/commands/dom/get.js +25 -7
  10. package/dist/commands/dom/index.js +7 -2
  11. package/dist/commands/dom/query.d.ts +2 -1
  12. package/dist/commands/dom/query.js +5 -3
  13. package/dist/commands/dom/screenshot.js +1 -0
  14. package/dist/commands/helpJson.js +1 -1
  15. package/dist/commands/network/list.js +46 -3
  16. package/dist/commands/optionBehaviors.d.ts +25 -2
  17. package/dist/commands/optionBehaviors.js +55 -42
  18. package/dist/commands/peek.js +3 -0
  19. package/dist/commands/shared/CommandRunner.js +13 -13
  20. package/dist/commands/shared/daemonErrorHandler.js +2 -2
  21. package/dist/commands/shared/dataFetcher.d.ts +4 -2
  22. package/dist/commands/shared/dataFetcher.js +11 -3
  23. package/dist/commands/shared/handleValidationError.js +3 -3
  24. package/dist/commands/shared/optionTypes.d.ts +14 -3
  25. package/dist/commands/shared/startHelpers.js +3 -3
  26. package/dist/connection/chromeIdentity.d.ts +8 -2
  27. package/dist/connection/chromeIdentity.js +85 -13
  28. package/dist/constants.d.ts +29 -1
  29. package/dist/constants.js +35 -1
  30. package/dist/daemon/SessionController.js +2 -0
  31. package/dist/daemon/session/Session.d.ts +2 -1
  32. package/dist/daemon/session/Session.js +10 -2
  33. package/dist/daemon/session/TelemetryStore.d.ts +7 -0
  34. package/dist/daemon/session/TelemetryStore.js +6 -0
  35. package/dist/daemon/session/commandRegistry.js +23 -5
  36. package/dist/daemon/session/matchedStylesReset.d.ts +26 -0
  37. package/dist/daemon/session/matchedStylesReset.js +46 -0
  38. package/dist/daemon/session/plugins.js +1 -0
  39. package/dist/daemon/session/triggeredRequests.d.ts +0 -5
  40. package/dist/daemon/session/triggeredRequests.js +13 -7
  41. package/dist/daemon.js +742 -460
  42. package/dist/errors/messages.d.ts +8 -0
  43. package/dist/errors/messages.js +10 -0
  44. package/dist/index.js +710 -518
  45. package/dist/ipc/protocol/commands.d.ts +4 -0
  46. package/dist/ipc/protocol/inspectTypes.d.ts +5 -2
  47. package/dist/ipc/session/types.d.ts +5 -1
  48. package/dist/program.d.ts +14 -0
  49. package/dist/program.js +53 -0
  50. package/dist/runtime/dom/elementGeometry.d.ts +23 -0
  51. package/dist/runtime/dom/elementGeometry.js +17 -15
  52. package/dist/runtime/dom/elementInfo.d.ts +6 -4
  53. package/dist/runtime/dom/elementInfo.js +7 -4
  54. package/dist/runtime/dom/frameScopedConnection.d.ts +7 -0
  55. package/dist/runtime/dom/frameScopedConnection.js +2 -2
  56. package/dist/runtime/dom/inspect.d.ts +17 -3
  57. package/dist/runtime/dom/inspect.js +40 -26
  58. package/dist/runtime/dom/inspectModel.d.ts +3 -3
  59. package/dist/runtime/dom/inspectRules.d.ts +29 -3
  60. package/dist/runtime/dom/inspectRules.js +205 -11
  61. package/dist/runtime/dom/layout.d.ts +0 -2
  62. package/dist/runtime/dom/layout.js +1 -2
  63. package/dist/runtime/dom/reactEventHelpers.d.ts +4 -1
  64. package/dist/runtime/dom/reactEventHelpers.js +9 -2
  65. package/dist/runtime/dom/targetNode.d.ts +10 -6
  66. package/dist/runtime/dom/targetNode.js +15 -8
  67. package/dist/telemetry/a11y.d.ts +15 -1
  68. package/dist/telemetry/a11y.js +83 -0
  69. package/dist/telemetry/har/builder.js +1 -1
  70. package/dist/telemetry/network.d.ts +13 -16
  71. package/dist/telemetry/network.js +30 -52
  72. package/dist/telemetry/networkRetention.d.ts +83 -0
  73. package/dist/telemetry/networkRetention.js +117 -0
  74. package/dist/types.d.ts +26 -0
  75. package/dist/ui/OutputBuilder.d.ts +10 -0
  76. package/dist/ui/OutputBuilder.js +12 -0
  77. package/dist/ui/formatters/a11y.d.ts +5 -7
  78. package/dist/ui/formatters/a11y.js +7 -61
  79. package/dist/ui/formatters/console/chronological.js +4 -4
  80. package/dist/ui/formatters/console/follow.d.ts +4 -2
  81. package/dist/ui/formatters/console/follow.js +6 -3
  82. package/dist/ui/formatters/console/json.d.ts +3 -6
  83. package/dist/ui/formatters/console/json.js +9 -13
  84. package/dist/ui/formatters/console/shared.d.ts +17 -2
  85. package/dist/ui/formatters/console/shared.js +17 -0
  86. package/dist/ui/formatters/console/summarize.d.ts +2 -2
  87. package/dist/ui/formatters/console/summarize.js +22 -7
  88. package/dist/ui/formatters/console.d.ts +1 -1
  89. package/dist/ui/formatters/console.js +1 -5
  90. package/dist/ui/formatters/details.js +1 -1
  91. package/dist/ui/formatters/dom.d.ts +13 -4
  92. package/dist/ui/formatters/dom.js +25 -7
  93. package/dist/ui/formatters/layout.js +2 -1
  94. package/dist/ui/formatters/longValues.d.ts +14 -0
  95. package/dist/ui/formatters/longValues.js +23 -0
  96. package/dist/ui/formatters/networkList.d.ts +8 -2
  97. package/dist/ui/formatters/networkList.js +11 -2
  98. package/dist/ui/formatters/preview.d.ts +4 -1
  99. package/dist/ui/formatters/preview.js +55 -13
  100. package/dist/ui/formatters/status.js +7 -0
  101. package/dist/ui/formatters/triggeredRequests.js +2 -1
  102. package/dist/ui/messages/chrome.d.ts +20 -1
  103. package/dist/ui/messages/chrome.js +29 -3
  104. package/dist/ui/messages/commands.d.ts +29 -8
  105. package/dist/ui/messages/commands.js +36 -8
  106. package/dist/ui/messages/networkMessages.d.ts +24 -0
  107. package/dist/ui/messages/networkMessages.js +45 -0
  108. package/dist/utils/http.d.ts +9 -2
  109. package/dist/utils/http.js +4 -3
  110. package/dist/utils/strings.d.ts +19 -0
  111. package/dist/utils/strings.js +16 -0
  112. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -960,7 +960,7 @@ var require_node = __commonJS({
960
960
  var tty2 = __require("tty");
961
961
  var util = __require("util");
962
962
  exports.init = init;
963
- exports.log = log36;
963
+ exports.log = log34;
964
964
  exports.formatArgs = formatArgs;
965
965
  exports.save = save;
966
966
  exports.load = load;
@@ -1095,7 +1095,7 @@ var require_node = __commonJS({
1095
1095
  }
1096
1096
  return (/* @__PURE__ */ new Date()).toISOString() + " ";
1097
1097
  }
1098
- function log36(...args) {
1098
+ function log34(...args) {
1099
1099
  return process.stderr.write(util.formatWithOptions(exports.inspectOpts, ...args) + "\n");
1100
1100
  }
1101
1101
  function save(namespaces) {
@@ -1327,16 +1327,24 @@ function resourceTypeFromName(name) {
1327
1327
  ([type, abbreviation]) => type.toLowerCase() === wanted || abbreviation.toLowerCase() === wanted
1328
1328
  )?.[0];
1329
1329
  }
1330
- var HTTP_LOCALHOST, MAX_CONSOLE_MESSAGES, MAX_RESPONSE_SIZE, CHROME_NETWORK_BUFFER_TOTAL, CHROME_NETWORK_BUFFER_PER_RESOURCE, CHROME_POST_DATA_LIMIT, MAX_JSONL_BUFFER_SIZE, PORT_OPTION_DESCRIPTION, RESOURCE_TYPE_ABBREVIATIONS, MIME_TYPE_RULES;
1330
+ var HTTP_LOCALHOST, MAX_NETWORK_REQUESTS, MAX_CONSOLE_MESSAGES, MAX_RESPONSE_SIZE, MAX_TOTAL_BODY_BYTES, MAX_VALUE_LENGTH, MAX_CONSOLE_TEXT_LENGTH, MAX_CONSOLE_JSON_TEXT_LENGTH, CHROME_NETWORK_BUFFER_TOTAL, CHROME_NETWORK_BUFFER_PER_RESOURCE, CHROME_POST_DATA_LIMIT, QUERY_JSON_LIST_LIMIT, LAYOUT_ELEMENT_LIMIT, MAX_TRIGGERED_REQUESTS, MAX_JSONL_BUFFER_SIZE, PORT_OPTION_DESCRIPTION, RESOURCE_TYPE_ABBREVIATIONS, MIME_TYPE_RULES;
1331
1331
  var init_constants = __esm({
1332
1332
  "src/constants.ts"() {
1333
1333
  "use strict";
1334
1334
  HTTP_LOCALHOST = "127.0.0.1";
1335
+ MAX_NETWORK_REQUESTS = 1e4;
1335
1336
  MAX_CONSOLE_MESSAGES = 1e4;
1336
1337
  MAX_RESPONSE_SIZE = 5 * 1024 * 1024;
1338
+ MAX_TOTAL_BODY_BYTES = 100 * 1024 * 1024;
1339
+ MAX_VALUE_LENGTH = 2e4;
1340
+ MAX_CONSOLE_TEXT_LENGTH = 200;
1341
+ MAX_CONSOLE_JSON_TEXT_LENGTH = 1e4;
1337
1342
  CHROME_NETWORK_BUFFER_TOTAL = 50 * 1024 * 1024;
1338
1343
  CHROME_NETWORK_BUFFER_PER_RESOURCE = 10 * 1024 * 1024;
1339
1344
  CHROME_POST_DATA_LIMIT = 1 * 1024 * 1024;
1345
+ QUERY_JSON_LIST_LIMIT = 100;
1346
+ LAYOUT_ELEMENT_LIMIT = 100;
1347
+ MAX_TRIGGERED_REQUESTS = 50;
1340
1348
  MAX_JSONL_BUFFER_SIZE = 256 * 1024 * 1024;
1341
1349
  PORT_OPTION_DESCRIPTION = "Chrome debugging port";
1342
1350
  RESOURCE_TYPE_ABBREVIATIONS = {
@@ -1413,8 +1421,8 @@ function createLogger(context) {
1413
1421
  logger.debug = (message) => logMessage(message, "debug");
1414
1422
  return logger;
1415
1423
  }
1416
- function logDebugError(log36, context, error) {
1417
- log36.debug(`Failed to ${context}: ${getErrorMessage(error)}`);
1424
+ function logDebugError(log34, context, error) {
1425
+ log34.debug(`Failed to ${context}: ${getErrorMessage(error)}`);
1418
1426
  }
1419
1427
  var debugEnabled;
1420
1428
  var init_logger = __esm({
@@ -2163,6 +2171,12 @@ function truncateByLength(text, maxLength = DEFAULT_MAX_LENGTH) {
2163
2171
  }
2164
2172
  return text.slice(0, maxLength - 1) + "\u2026";
2165
2173
  }
2174
+ function capLength(text, maxLength) {
2175
+ if (text.length <= maxLength) return { text };
2176
+ const lastKept = text.charCodeAt(maxLength - 1);
2177
+ const end = lastKept >= 55296 && lastKept <= 56319 ? maxLength - 1 : maxLength;
2178
+ return { text: text.slice(0, end), truncatedFrom: text.length };
2179
+ }
2166
2180
  var DEFAULT_MAX_LENGTH;
2167
2181
  var init_strings = __esm({
2168
2182
  "src/utils/strings.ts"() {
@@ -2228,8 +2242,7 @@ function newMessageText(message) {
2228
2242
  return `"${message.text}" (${message.element})`;
2229
2243
  }
2230
2244
  function moreMatchesNote(hidden, jsonLimit) {
2231
- const where = jsonLimit === void 0 ? "use --json for all" : `--json lists the first ${jsonLimit}`;
2232
- return `... and ${hidden} more (${where})`;
2245
+ return `... and ${hidden} more (--json lists up to ${jsonLimit})`;
2233
2246
  }
2234
2247
  function queryMoreMatchesNote(omitted, indexed) {
2235
2248
  const indices = indexed === void 0 ? "" : `; indices 0-${indexed - 1} work with other commands`;
@@ -2238,6 +2251,12 @@ function queryMoreMatchesNote(omitted, indexed) {
2238
2251
  function queryViewportCheckedNote(checked) {
2239
2252
  return `Visibility is checked for the first ${checked} matches only; ${sessionCommand("bdg dom layout <index>")} checks any of them`;
2240
2253
  }
2254
+ function a11yTreeShownNote(listed) {
2255
+ return `Showing the first ${listed} nodes (text boxes and repeated text left out)`;
2256
+ }
2257
+ function a11yTreeMoreNote(omitted) {
2258
+ return `${omitted} more: --limit 0 lists all, --depth <n> limits the levels, or search with bdg dom a11y query "role:<role>"`;
2259
+ }
2241
2260
  function a11yMoreMatchesNote(omitted) {
2242
2261
  return `... and ${omitted} more (--limit 0 lists all; their indices work too)`;
2243
2262
  }
@@ -2344,6 +2363,8 @@ function coverText(cover, transparent) {
2344
2363
  return transparent ? `under transparent ${cover} (clicks land on it)` : `covered by ${cover}`;
2345
2364
  }
2346
2365
  function inspectCascadeNote(reason) {
2366
+ if (reason === "skipped")
2367
+ return "hints skipped: this page's stylesheets are slow to read (--rules waits 5 s)";
2347
2368
  return reason === "timeout" ? "CSS rules not read: the page's stylesheets took too long (hints wait 1 s; --rules and --why 5 s)" : "CSS rules not read: Chrome could not report the rules matching this element";
2348
2369
  }
2349
2370
  function inspectPseudoOfNote(pseudo) {
@@ -2574,6 +2595,9 @@ function inspectMidTransitionNote() {
2574
2595
  function helpJsonDetailsNote() {
2575
2596
  return "Option behaviors, defaults, choices and examples: bdg <command> --help --json (e.g. bdg dom query --help --json). Everything at once: bdg --help --json --full";
2576
2597
  }
2598
+ function moreCharsNote(count) {
2599
+ return `\u2026 ${count} more chars (use --full)`;
2600
+ }
2577
2601
  var REQUIRED_FIELD_EMPTY_REASON, NO_VISIBLE_EFFECT, HOVER_OFF_DONE, HOVER_USAGE, LAYOUT_REASONS, SCROLL_LOCKED_PREFIX, VIEWPORT_POSITION_HINTS, INSPECT_OUTPUT_LEGEND, COLLAPSED_LISTENERS_HEADING, NO_LISTENERS_HINT, NOTE_TYPES_SHOWN, POINTER_ACTION_DONE, POINTER_ACTION_NOUN, PAGE_ACTION_DONE, PAGE_INFO_DESCRIPTION, PAGE_EMULATE_DESCRIPTION, PAGE_ACTION_DESCRIPTIONS, CLICK_RESULT_WAIT_HELP, WAIT_HELP_EXAMPLES, FRAME_URL_MAX_LENGTH, AUDIT_HELP_EXAMPLES, CSS_SEARCH_HELP_EXAMPLES;
2578
2602
  var init_commands = __esm({
2579
2603
  "src/ui/messages/commands.ts"() {
@@ -8126,7 +8150,7 @@ var init_elementInfo = __esm({
8126
8150
  while (walker.nextNode()) if (composes(walker.currentNode)) return true;
8127
8151
  return false;
8128
8152
  }`;
8129
- FLAT_TEXT_JS = `(el, limit) => {
8153
+ FLAT_TEXT_JS = `(el, limit, fields) => {
8130
8154
  const composed = ${COMPOSED_JS};
8131
8155
  const view = el.ownerDocument.defaultView;
8132
8156
  let text = '';
@@ -8136,7 +8160,8 @@ var init_elementInfo = __esm({
8136
8160
  if (text.length >= limit) return;
8137
8161
  if (node.nodeType === 3 && visible) text += node.data.replace(/\\s+/g, ' ');
8138
8162
  if (node.nodeType !== 1) return;
8139
- if (/^(input|textarea|select)$/.test(node.localName) || node.isContentEditable) return;
8163
+ if (/^(input|textarea)$/.test(node.localName)) return;
8164
+ if (!fields && (node.localName === 'select' || node.isContentEditable)) return;
8140
8165
  const style = view.getComputedStyle(node);
8141
8166
  if (node.checkVisibility && !node.checkVisibility() && style.display !== 'contents') return;
8142
8167
  if (node.localName === 'br') text += '\\n';
@@ -8544,7 +8569,7 @@ var init_elementGeometry = __esm({
8544
8569
  /transform|filter|perspective/.test(style.willChange) || /paint|layout|strict|content/.test(style.contain)`;
8545
8570
  FIXED_TO_VIEWPORT_JS = `(n) => {
8546
8571
  const holdsFixed = ${HOLDS_FIXED_JS};
8547
- const parentOf = (node) => node.parentElement || (node.parentNode && node.parentNode.host) || null;
8572
+ const parentOf = ${FLAT_PARENT_JS};
8548
8573
  for (let p = parentOf(n); p && p !== n.ownerDocument.documentElement; p = parentOf(p)) {
8549
8574
  if (holdsFixed(p.ownerDocument.defaultView.getComputedStyle(p))) return false;
8550
8575
  }
@@ -8557,7 +8582,7 @@ var init_elementGeometry = __esm({
8557
8582
  const fixedToViewport = ${FIXED_TO_VIEWPORT_JS};
8558
8583
  const reasons = ${JSON.stringify(LAYOUT_REASONS)};
8559
8584
  const styleOf = (n) => n.ownerDocument.defaultView.getComputedStyle(n);
8560
- const parentOf = (n) => n.parentElement || (n.parentNode && n.parentNode.host) || null;
8585
+ const parentOf = ${FLAT_PARENT_JS};
8561
8586
  const doc = node.ownerDocument;
8562
8587
  const rootStyle = styleOf(doc.documentElement);
8563
8588
  const bodyClips = rootStyle.overflowX !== 'visible' || rootStyle.overflowY !== 'visible';
@@ -8771,13 +8796,13 @@ var init_frameScopedConnection = __esm({
8771
8796
  });
8772
8797
 
8773
8798
  // src/runtime/page/bdgWorld.ts
8774
- var log23;
8799
+ var log21;
8775
8800
  var init_bdgWorld = __esm({
8776
8801
  "src/runtime/page/bdgWorld.ts"() {
8777
8802
  "use strict";
8778
8803
  init_logging();
8779
8804
  init_errors();
8780
- log23 = createLogger("cdp");
8805
+ log21 = createLogger("cdp");
8781
8806
  }
8782
8807
  });
8783
8808
 
@@ -9055,12 +9080,13 @@ function selectorArgsJS(selector) {
9055
9080
  }
9056
9081
  return `${JSON.stringify(selector)}, ${JSON.stringify(parseSelectorFilters(selector))}`;
9057
9082
  }
9058
- var BOUND_TARGET_SELECTOR, log24, FILTER_MATCHING_JS, DEEP_QUERY_JS, FIND_ELEMENTS_JS, UNSEARCHED_CONTENT_JS, NAME_SCAN_LIMIT;
9083
+ var BOUND_TARGET_SELECTOR, log22, FILTER_MATCHING_JS, DEEP_QUERY_JS, FIND_ELEMENTS_JS, UNSEARCHED_CONTENT_JS, NAME_SCAN_LIMIT;
9059
9084
  var init_targetNode = __esm({
9060
9085
  "src/runtime/dom/targetNode.ts"() {
9061
9086
  "use strict";
9062
9087
  init_errors3();
9063
9088
  init_messages();
9089
+ init_elementInfo();
9064
9090
  init_shared();
9065
9091
  init_frameScopedConnection();
9066
9092
  init_bdgWorld();
@@ -9071,16 +9097,17 @@ var init_targetNode = __esm({
9071
9097
  init_exitCodes();
9072
9098
  init_selectorFilters();
9073
9099
  BOUND_TARGET_SELECTOR = "__bdg_bound_target__";
9074
- log24 = createLogger("dom");
9100
+ log22 = createLogger("dom");
9075
9101
  FILTER_MATCHING_JS = `(shadowRoots) => {
9102
+ const composed = ${COMPOSED_JS};
9103
+ const flatText = ${FLAT_TEXT_JS};
9076
9104
  const skipped = /^(script|style|noscript|template)$/;
9077
9105
  const hiddenText = (el) => {
9078
- const walker = el.ownerDocument.createTreeWalker(el, 5, {
9079
- acceptNode: (node) => (node.nodeType === 1 && skipped.test(node.localName) ? 2 : 1)
9080
- });
9106
+ const nodes = el.localName === 'slot' ? el.assignedNodes({ flatten: true }) : (el.shadowRoot || el).childNodes;
9081
9107
  let text = '';
9082
- for (let node = walker.nextNode(); node; node = walker.nextNode()) {
9108
+ for (const node of nodes) {
9083
9109
  if (node.nodeType === 3) text += node.data;
9110
+ else if (node.nodeType === 1 && !skipped.test(node.localName)) text += hiddenText(node);
9084
9111
  }
9085
9112
  return text;
9086
9113
  };
@@ -9088,7 +9115,8 @@ var init_targetNode = __esm({
9088
9115
  if (el.localName === 'input' && /^(submit|button|reset)$/i.test(el.type)) return el.value;
9089
9116
  const rendered = typeof el.innerText === 'string' &&
9090
9117
  (typeof el.checkVisibility !== 'function' || el.checkVisibility({ visibilityProperty: true }));
9091
- return (rendered ? el.innerText : hiddenText(el)).replace(/\\s+/g, ' ').trim();
9118
+ const text = !rendered ? hiddenText(el) : composed(el) ? flatText(el, Infinity, true) : el.innerText;
9119
+ return text.replace(/\\s+/g, ' ').trim();
9092
9120
  };
9093
9121
  const passes = (el, filter) => {
9094
9122
  if (filter.kind === 'visible') {
@@ -9345,7 +9373,7 @@ async function noMatchContext(selector) {
9345
9373
  ...typeof value.shadowHost === "number" && compounds[value.shadowHost] && { shadowHost: compounds[value.shadowHost] }
9346
9374
  };
9347
9375
  } catch (error) {
9348
- log25.debug(`Could not read the page after no match: ${getErrorMessage(error)}`);
9376
+ log23.debug(`Could not read the page after no match: ${getErrorMessage(error)}`);
9349
9377
  return {};
9350
9378
  }
9351
9379
  }
@@ -9358,7 +9386,7 @@ async function documentReadyState() {
9358
9386
  const { result } = evaluated.data?.result ?? {};
9359
9387
  return typeof result?.value === "string" ? result.value : void 0;
9360
9388
  } catch (error) {
9361
- log25.debug(`Could not read document.readyState: ${getErrorMessage(error)}`);
9389
+ log23.debug(`Could not read document.readyState: ${getErrorMessage(error)}`);
9362
9390
  return void 0;
9363
9391
  }
9364
9392
  }
@@ -9464,7 +9492,7 @@ async function queryDOMElements(selector, limit = 0) {
9464
9492
  selector,
9465
9493
  (arrayObjectId) => elementsWithDetails(arrayObjectId, described)
9466
9494
  );
9467
- if (total > 20) log25.debug(`Queried ${total} elements with selector: ${selector}`);
9495
+ if (total > 20) log23.debug(`Queried ${total} elements with selector: ${selector}`);
9468
9496
  return { selector, count: total, nodes: elements.map(queryNode) };
9469
9497
  }
9470
9498
  function queryNode(element, index) {
@@ -9521,7 +9549,7 @@ async function getDomContext(ref, options = {}) {
9521
9549
  await callCDP("DOM.enable", {});
9522
9550
  const desc = await describeNode(ref);
9523
9551
  if (!desc) {
9524
- log25.debug(`No DOM context for ${JSON.stringify(ref)}`);
9552
+ log23.debug(`No DOM context for ${JSON.stringify(ref)}`);
9525
9553
  return null;
9526
9554
  }
9527
9555
  const full = options.full === true;
@@ -9681,11 +9709,11 @@ async function pageDocumentId() {
9681
9709
  return typeof result?.value === "string" ? result.value : void 0;
9682
9710
  } catch (error) {
9683
9711
  if (error instanceof CommandError) throw error;
9684
- log25.debug(`Page document not identified: ${getErrorMessage(error)}`);
9712
+ log23.debug(`Page document not identified: ${getErrorMessage(error)}`);
9685
9713
  return void 0;
9686
9714
  }
9687
9715
  }
9688
- var log25, CDP_CONCURRENCY_LIMIT, queryCount, MAX_HOST_COMPOUNDS, VIEWPORT_HINT_LIMIT, QUERY_CACHE_LIMIT, ELEMENT_DETAILS_FUNCTION, SLICE_FUNCTION, CHILDREN_LISTED, UNSHOWN_CHILD;
9716
+ var log23, CDP_CONCURRENCY_LIMIT, queryCount, MAX_HOST_COMPOUNDS, VIEWPORT_HINT_LIMIT, QUERY_CACHE_LIMIT, ELEMENT_DETAILS_FUNCTION, SLICE_FUNCTION, CHILDREN_LISTED, UNSHOWN_CHILD;
9689
9717
  var init_query = __esm({
9690
9718
  "src/commands/dom/helpers/query.ts"() {
9691
9719
  "use strict";
@@ -9703,7 +9731,7 @@ var init_query = __esm({
9703
9731
  init_exitCodes();
9704
9732
  init_selectorFilters();
9705
9733
  init_suggestions();
9706
- log25 = createLogger("dom");
9734
+ log23 = createLogger("dom");
9707
9735
  CDP_CONCURRENCY_LIMIT = 10;
9708
9736
  queryCount = 0;
9709
9737
  MAX_HOST_COMPOUNDS = 4;
@@ -9819,7 +9847,7 @@ function viewportOverride(viewport, deviceScaleFactor = 0) {
9819
9847
  mobile
9820
9848
  };
9821
9849
  }
9822
- var log26, MOBILE_PIXEL_RATIO;
9850
+ var log24, MOBILE_PIXEL_RATIO;
9823
9851
  var init_emulation = __esm({
9824
9852
  "src/runtime/page/emulation.ts"() {
9825
9853
  "use strict";
@@ -9827,7 +9855,7 @@ var init_emulation = __esm({
9827
9855
  init_userAgent();
9828
9856
  init_logging();
9829
9857
  init_errors();
9830
- log26 = createLogger("session");
9858
+ log24 = createLogger("session");
9831
9859
  MOBILE_PIXEL_RATIO = 3;
9832
9860
  }
9833
9861
  });
@@ -9892,12 +9920,12 @@ async function waitForPostScrollStability() {
9892
9920
  const networkIdle = value?.networkIdle ?? 0;
9893
9921
  const domIdle = value?.domIdle ?? 0;
9894
9922
  if (networkIdle >= POST_SCROLL_NETWORK_IDLE_MS && domIdle >= POST_SCROLL_DOM_STABLE_MS) {
9895
- log27.debug(`Post-scroll stable: network ${networkIdle}ms, DOM ${domIdle}ms`);
9923
+ log25.debug(`Post-scroll stable: network ${networkIdle}ms, DOM ${domIdle}ms`);
9896
9924
  return;
9897
9925
  }
9898
9926
  await new Promise((resolve4) => setTimeout(resolve4, STABILITY_CHECK_INTERVAL_MS));
9899
9927
  }
9900
- log27.debug("Post-scroll stability timeout, proceeding anyway");
9928
+ log25.debug("Post-scroll stability timeout, proceeding anyway");
9901
9929
  } finally {
9902
9930
  await callBdgScript("Runtime.evaluate", {
9903
9931
  expression: `
@@ -10196,7 +10224,7 @@ async function paintedArea(ref, bounds) {
10196
10224
  height: bounds.height + top + bottom
10197
10225
  };
10198
10226
  } catch (error) {
10199
- log27.debug(`Could not measure overflowing content: ${String(error)}`);
10227
+ log25.debug(`Could not measure overflowing content: ${String(error)}`);
10200
10228
  return bounds;
10201
10229
  } finally {
10202
10230
  await callCDP("Runtime.releaseObjectGroup", { objectGroup }).catch(() => void 0);
@@ -10293,7 +10321,7 @@ function roundBounds(bounds) {
10293
10321
  height: Math.round(bounds.height)
10294
10322
  };
10295
10323
  }
10296
- var log27, POST_SCROLL_NETWORK_IDLE_MS, POST_SCROLL_DOM_STABLE_MS, POST_SCROLL_MAX_WAIT_MS, STABILITY_CHECK_INTERVAL_MS, OVERFLOW_SCAN_LIMIT, CONTENT_OVERFLOW_JS, OVERFLOW_SLACK;
10324
+ var log25, POST_SCROLL_NETWORK_IDLE_MS, POST_SCROLL_DOM_STABLE_MS, POST_SCROLL_MAX_WAIT_MS, STABILITY_CHECK_INTERVAL_MS, OVERFLOW_SCAN_LIMIT, CONTENT_OVERFLOW_JS, OVERFLOW_SLACK;
10297
10325
  var init_screenshot = __esm({
10298
10326
  "src/commands/dom/helpers/screenshot.ts"() {
10299
10327
  "use strict";
@@ -10308,7 +10336,7 @@ var init_screenshot = __esm({
10308
10336
  init_metadata();
10309
10337
  init_logging();
10310
10338
  init_exitCodes();
10311
- log27 = createLogger("dom");
10339
+ log25 = createLogger("dom");
10312
10340
  POST_SCROLL_NETWORK_IDLE_MS = 150;
10313
10341
  POST_SCROLL_DOM_STABLE_MS = 200;
10314
10342
  POST_SCROLL_MAX_WAIT_MS = 2e3;
@@ -13818,8 +13846,9 @@ var OPTION_BEHAVIORS = {
13818
13846
  },
13819
13847
  "get:--full": {
13820
13848
  default: 'Semantic output shows the element text up to 500 characters (whitespace collapsed; close buttons such as "\xD7" and aria-hidden icons left out)',
13821
- whenEnabled: "Shows all of the element text; cannot be combined with --raw or --node-id",
13822
- tokenImpact: "A page-sized container can add thousands of tokens; target the element you need"
13849
+ whenEnabled: "Shows all of the element text; with --raw (or --node-id) prints the whole outer HTML instead of its first 20000 characters, and JSON outerHTML is whole too (else cut to 20000 with truncatedFrom, the original length)",
13850
+ automaticBehavior: `Without --full, --raw output cuts each element's HTML at 20000 characters and ends it with "\u2026 N more chars (use --full)"`,
13851
+ tokenImpact: "A page-sized container can add thousands of tokens; dom get body --raw --full on Wikipedia is about 3.4 MB. Target the element you need"
13823
13852
  },
13824
13853
  "get:--all": {
13825
13854
  default: "Returns first matching element only",
@@ -13831,30 +13860,42 @@ var OPTION_BEHAVIORS = {
13831
13860
  automaticBehavior: "Past the last match exits 81; a numeric index argument (a cached query index) past the indexed matches, or from an earlier page, exits 87 (re-run dom query)"
13832
13861
  },
13833
13862
  "query:--limit": {
13834
- default: "dom query and dom a11y query list the first 50 matches and say how many more there are; --json returns 1000 (dom query) or all of them (dom a11y query)",
13863
+ default: "dom query and dom a11y query list the first 50 matches and say how many more there are; --json lists the first 100 with count (all matches) and omitted (the rest)",
13835
13864
  whenEnabled: "Lists that many matches (0 = all), in human and JSON output; count is always the total, JSON omitted the rest",
13836
13865
  automaticBehavior: "Matches are cached for index-based access (bdg dom click 55 works even when 50 are listed): all of them for dom a11y query, the first 1000 (or --limit, if higher) for dom query, which describes only those, so a page with 50000 matches answers in under a second; an element the page and frame trees both report is listed once. Indices work with click, fill, hover, pressKey, scroll, submit, layout, get and listeners, also for elements of a cross-origin iframe of the same site (a consent dialog), whose scripts then run in that frame",
13837
- tokenImpact: "About one line per match; a page can have hundreds of links"
13866
+ tokenImpact: 'About one line per match (piped JSON about 160 bytes per dom query match, 230 per a11y match); a page can have thousands of links: on Wikipedia "United States" --limit 0 --json is 1.0 MB (dom query a) and 1.3 MB (dom a11y query role:link), the default 16 KB and 23 KB'
13867
+ },
13868
+ "tree:--limit": {
13869
+ default: "dom a11y tree lists the first 50 meaningful nodes depth-first, in human and JSON output; JSON count is the whole tree = nodes listed + omitted (cut by --limit/--depth) + skipped (never listed)",
13870
+ whenEnabled: "Lists that many nodes; 0 = all listed nodes (text boxes and empty wrappers are always skipped)",
13871
+ automaticBehavior: "Ignored nodes, text boxes, blank text, text repeating its parent name and nameless layout wrappers (generic, none, presentation, layout tables) are never listed (JSON skipped counts them); their children move up a level. For the raw tree with every node use bdg cdp Accessibility.getFullAXTree --json. JSON nodes carry depth (0 = root) instead of childIds; nodes outside the root (frame content) follow the root tree",
13872
+ tokenImpact: 'About 140 bytes per piped JSON node (7 KB by default); the whole tree of a long page is megabytes (Wikipedia "United States": 51k nodes, 20k listed, 2.6 MB with --limit 0 --json), so prefer --depth or dom a11y query "role:<role>"'
13873
+ },
13874
+ "tree:--depth": {
13875
+ default: "dom a11y tree lists every level (up to --limit nodes)",
13876
+ whenEnabled: "Lists nodes down to that level (0 = root only); deeper nodes are counted in omitted",
13877
+ tokenImpact: "An outline of a page (landmarks, headings) in a few levels"
13838
13878
  },
13839
13879
  "eval:--frame": {
13840
13880
  default: "Evaluates in the page's main frame",
13841
13881
  whenEnabled: "Evaluates in one iframe's main world (its own globals), including cross-origin (out-of-process) iframes; output gains a frame field (its URL)",
13842
13882
  automaticBehavior: "The value is matched as: a 0-based index (bdg dom frames order: document order of the <iframe> elements, nested ones depth-first, main page not counted), else an exact name/id attribute, else a case-insensitive part of the name, id or URL. Several matches fail with 81 listing them; none fails with 83 listing all frames. Frames are looked up on every call (a reloaded iframe is found again). An index that names another frame than in the last bdg dom frames listing (iframes added, removed or moved, or the page navigated) fails with 87 STALE_CACHE: re-run bdg dom frames or pick the frame by name."
13843
13883
  },
13844
- "console:-H": {
13845
- default: "Shows messages from current page load only (most recent navigation)",
13846
- whenEnabled: "Shows messages from ALL page loads during the session",
13847
- automaticBehavior: 'Page navigations create new "navigation contexts" - default filters to latest context'
13884
+ "eval:--full": {
13885
+ default: 'Human output prints the first 20000 characters of the value followed by "\u2026 N more chars (use --full)"; in JSON a string result is cut to 20000 characters with truncatedFrom (the original length). Objects and arrays in JSON are not cut',
13886
+ whenEnabled: "Prints the whole value, byte for byte",
13887
+ tokenImpact: "dom eval document.documentElement.outerHTML on Wikipedia is about 3.6 MB with --full; select what you need in the expression instead"
13888
+ },
13889
+ "console:--full": {
13890
+ default: 'Message texts are cut: human output (summary, --list, --follow) at 200 characters followed by "\u2026 N more chars (use --full)"; JSON text at 10000 characters with truncatedFrom (the original length)',
13891
+ whenEnabled: "Message texts are printed whole, in human and JSON output",
13892
+ tokenImpact: "A page that logs a large payload or throws a long error can add megabytes; bdg details console <n> shows one message whole"
13848
13893
  },
13849
13894
  "console:--history": {
13850
13895
  default: "Shows messages from current page load only (most recent navigation)",
13851
13896
  whenEnabled: "Shows messages from ALL page loads during the session",
13852
13897
  automaticBehavior: 'Page navigations create new "navigation contexts" - default filters to latest context'
13853
13898
  },
13854
- "console:-l": {
13855
- default: "Smart summary with errors deduplicated and warnings grouped: the newest 50 distinct errors and warnings, with a note for the earlier ones. The session keeps the newest 10000 messages; dropped ones are counted (dropped in JSON)",
13856
- whenEnabled: "Lists all messages chronologically without deduplication"
13857
- },
13858
13899
  "console:--list": {
13859
13900
  default: "Smart summary with errors deduplicated and warnings grouped: the newest 50 distinct errors and warnings, with a note for the earlier ones. The session keeps the newest 10000 messages; dropped ones are counted (dropped in JSON)",
13860
13901
  whenEnabled: "Lists all messages chronologically without deduplication"
@@ -14006,6 +14047,7 @@ var OPTION_BEHAVIORS = {
14006
14047
  },
14007
14048
  "inspect:--no-hints": {
14008
14049
  default: "Hints at the element's own author declarations that have no effect (flex/grid properties without flex or grid, item properties without a flex or grid parent, offsets on static elements, sizes on inline ones, var() of an unset custom property, form controls in the browser's font), within a 1 s budget; hints none when nothing was found",
14050
+ automaticBehavior: "After a hint read times out, later inspects on the same page skip the hints without waiting (hints skipped: this page's stylesheets are slow to read) until a read is fast again, a stylesheet changes or it navigates; --rules and --why still wait up to 5 s. Matched rules that took over 300 ms are reused for up to 5 s, until a command that may change the page or a stylesheet or DOM change",
14009
14051
  whenEnabled: "Skips the hints and does not read the matched rules"
14010
14052
  },
14011
14053
  "scroll:--down": {
@@ -14046,56 +14088,52 @@ var OPTION_BEHAVIORS = {
14046
14088
  whenEnabled: "Quick scan: field names, types, and required status only",
14047
14089
  tokenImpact: "Reduces output ~50% for initial discovery"
14048
14090
  },
14091
+ "peek:--full": {
14092
+ default: 'Console message texts are cut: human output at 200 characters (compact output also at 2 lines) followed by "\u2026 N more chars (use --full)"; JSON text at 10000 characters with truncatedFrom (the original length)',
14093
+ whenEnabled: "Console message texts are printed whole, in human and JSON output",
14094
+ tokenImpact: "A page that logs a large payload can add megabytes per peek"
14095
+ },
14049
14096
  "peek:--type": {
14050
14097
  whenEnabled: "Filters network requests by CDP resource type. Case-insensitive, comma-separated. Valid: Document, Stylesheet, Image, Media, Font, Script, XHR, Fetch, WebSocket, etc."
14051
14098
  },
14052
- "peek:-f": {
14053
- default: "Shows snapshot of current data",
14054
- whenEnabled: "Continuous monitoring (like tail -f): refreshes every second, or every --interval ms (100-60000). Replaces the deprecated bdg tail",
14055
- automaticBehavior: FOLLOW_BEHAVIOR
14056
- },
14057
14099
  "peek:--follow": {
14058
14100
  default: "Shows snapshot of current data",
14059
14101
  whenEnabled: "Continuous monitoring (like tail -f): refreshes every second, or every --interval ms (100-60000). Replaces the deprecated bdg tail",
14060
14102
  automaticBehavior: FOLLOW_BEHAVIOR
14061
14103
  },
14062
- "console:-f": {
14104
+ "console:--follow": {
14063
14105
  default: "Prints the messages logged so far and exits",
14064
14106
  whenEnabled: "Streams new messages as they come (the last --last at start)",
14065
14107
  automaticBehavior: FOLLOW_BEHAVIOR
14066
14108
  },
14067
- "list:-f": {
14109
+ "list:--follow": {
14068
14110
  default: "Lists the requests captured so far and exits",
14069
14111
  whenEnabled: "Streams requests as they finish",
14070
14112
  automaticBehavior: FOLLOW_BEHAVIOR
14071
14113
  },
14072
- "peek:-v": {
14114
+ "peek:--verbose": {
14073
14115
  default: "Compact output (truncated URLs, no resource types)",
14074
14116
  whenEnabled: "Verbose output with full URLs and resource types"
14075
14117
  },
14076
- "start:--headless": {
14118
+ "bdg:--headless": {
14077
14119
  default: "A window when there is a display: on macOS unless over SSH (SSH_CONNECTION, SSH_TTY) or CI is set; on Linux when DISPLAY or WAYLAND_DISPLAY is set. Servers, containers and CI run headless",
14078
14120
  whenEnabled: "Chrome runs without a window (pass it when running unattended on a Mac)"
14079
14121
  },
14080
- "start:--no-headless": {
14122
+ "bdg:--no-headless": {
14081
14123
  default: "A window when there is a display: on macOS unless over SSH (SSH_CONNECTION, SSH_TTY) or CI is set; on Linux when DISPLAY or WAYLAND_DISPLAY is set",
14082
14124
  whenEnabled: "Chrome shows its window even without a detected display (it fails without one)"
14083
14125
  },
14084
- "start:--all": {
14126
+ "bdg:--all": {
14085
14127
  default: "Tracking/analytics requests and console noise are filtered; bodies of binary responses (images, fonts) are not captured",
14086
14128
  whenEnabled: "Everything is captured, including binary response bodies (base64, flagged by responseBodyBase64, within --max-body-size)",
14087
14129
  tokenImpact: "details network --json and HAR exports can grow considerably on media-heavy pages"
14088
14130
  },
14089
- "peek:--verbose": {
14090
- default: "Compact output (truncated URLs, no resource types)",
14091
- whenEnabled: "Verbose output with full URLs and resource types"
14092
- },
14093
14131
  "bdg:--session": {
14094
14132
  default: "The default session in ~/.bdg (or $BDG_SESSION_DIR); BDG_SESSION=<name> selects a named session like the flag",
14095
14133
  whenEnabled: "Uses the named session in ~/.bdg/sessions/<name>/ (or $BDG_SESSION_DIR/sessions/<name>/) with its own daemon, Chrome, profile and port; every command (status, stop, cleanup, ...) acts on that session only",
14096
14134
  automaticBehavior: 'Accepted before or after any subcommand; --session wins over BDG_SESSION. Names are case-insensitive (lower-cased: ALPHA is alpha). Without --port a named session takes the first free port above 9222 not claimed by another running session, and keeps it in port.txt. Names: 1-40 letters, digits, "-" or "_", starting with a letter or digit (exit 81 otherwise, also when the socket path would be too long). Hints and suggestions in its output carry --session <name>'
14097
14135
  },
14098
- "cleanup:-f": {
14136
+ "cleanup:--force": {
14099
14137
  default: "Refuses to run while a session is active; removes files left by a crashed session",
14100
14138
  whenEnabled: "Kills the running daemon and its Chrome first (use when a session is stuck)"
14101
14139
  },
@@ -14130,23 +14168,16 @@ var OPTION_BEHAVIORS = {
14130
14168
  default: "Chrome launched by bdg is always closed on stop; an attached Chrome (--chrome-ws-url) is left running",
14131
14169
  whenEnabled: "No additional effect; kept for compatibility"
14132
14170
  },
14133
- "status:-v": {
14134
- default: "Basic session status (daemon running, session active, URL)",
14135
- whenEnabled: "Includes Chrome diagnostics and CDP connection details"
14136
- },
14137
14171
  "status:--verbose": {
14138
14172
  default: "Basic session status (daemon running, session active, URL)",
14139
14173
  whenEnabled: "Includes Chrome diagnostics and CDP connection details"
14140
14174
  }
14141
14175
  };
14142
- function buildKey(commandName, flags) {
14143
- const firstFlag = flags.split(",")[0] ?? flags;
14144
- const flagName = firstFlag.trim().split(" ")[0] ?? firstFlag.trim();
14145
- return `${commandName}:${flagName}`;
14176
+ function behaviorKey(commandName, option) {
14177
+ return `${commandName}:${option.long ?? option.short ?? option.flags}`;
14146
14178
  }
14147
- function getOptionBehavior(commandName, flags) {
14148
- const key = buildKey(commandName, flags);
14149
- return OPTION_BEHAVIORS[key];
14179
+ function getOptionBehavior(commandName, option) {
14180
+ return OPTION_BEHAVIORS[behaviorKey(commandName, option)];
14150
14181
  }
14151
14182
 
14152
14183
  // node_modules/chrome-launcher/dist/chrome-finder.js
@@ -14200,25 +14231,25 @@ var loggingBufferColumns = 25;
14200
14231
  var level_;
14201
14232
  var Log = class _Log {
14202
14233
  static _logToStdErr(title, argsArray) {
14203
- const log36 = _Log.loggerfn(title);
14204
- log36(...argsArray);
14234
+ const log34 = _Log.loggerfn(title);
14235
+ log34(...argsArray);
14205
14236
  }
14206
14237
  /**
14207
14238
  * @param {string} title
14208
14239
  */
14209
14240
  static loggerfn(title) {
14210
14241
  title = `LH:${title}`;
14211
- let log36 = loggersByTitle[title];
14212
- if (!log36) {
14213
- log36 = (0, import_debug.default)(title);
14214
- loggersByTitle[title] = log36;
14242
+ let log34 = loggersByTitle[title];
14243
+ if (!log34) {
14244
+ log34 = (0, import_debug.default)(title);
14245
+ loggersByTitle[title] = log34;
14215
14246
  if (title.endsWith("error")) {
14216
- log36.color = colors.red;
14247
+ log34.color = colors.red;
14217
14248
  } else if (title.endsWith("warn")) {
14218
- log36.color = colors.yellow;
14249
+ log34.color = colors.yellow;
14219
14250
  }
14220
14251
  }
14221
- return log36;
14252
+ return log34;
14222
14253
  }
14223
14254
  /**
14224
14255
  * @param {string} level
@@ -14815,12 +14846,12 @@ async function waitUntil(condition, timeoutMs, pollMs = 25) {
14815
14846
  // src/utils/file.ts
14816
14847
  init_logging();
14817
14848
  import * as fs9 from "fs";
14818
- function safeRemoveFile(path7, context, log36) {
14849
+ function safeRemoveFile(path7, context, log34) {
14819
14850
  try {
14820
14851
  fs9.rmSync(path7, { force: true });
14821
14852
  return true;
14822
14853
  } catch (error) {
14823
- logDebugError(log36, `remove ${context}`, error);
14854
+ logDebugError(log34, `remove ${context}`, error);
14824
14855
  return false;
14825
14856
  }
14826
14857
  }
@@ -15258,7 +15289,7 @@ function convertOption(option, commandName) {
15258
15289
  if (option.argChoices) {
15259
15290
  metadata.choices = option.argChoices;
15260
15291
  }
15261
- const behavior = getOptionBehavior(commandName, option.flags);
15292
+ const behavior = getOptionBehavior(commandName, option);
15262
15293
  if (behavior) {
15263
15294
  metadata.behavior = behavior;
15264
15295
  }
@@ -15519,6 +15550,9 @@ var VERSION = getVersion();
15519
15550
  function buildSuccessResponse(data) {
15520
15551
  return { version: VERSION, success: true, data };
15521
15552
  }
15553
+ function stringifyEnvelope(envelope) {
15554
+ return process.stdout.isTTY ? JSON.stringify(envelope, null, 2) : JSON.stringify(envelope);
15555
+ }
15522
15556
  var OutputBuilder = class {
15523
15557
  /**
15524
15558
  * Build an error response envelope.
@@ -15557,9 +15591,7 @@ function handleValidationError(error, json) {
15557
15591
  if (error.metadata.suggestion) {
15558
15592
  errorOptions.suggestion = error.metadata.suggestion;
15559
15593
  }
15560
- console.log(
15561
- JSON.stringify(OutputBuilder.buildJsonError(error.message, errorOptions), null, 2)
15562
- );
15594
+ console.log(stringifyEnvelope(OutputBuilder.buildJsonError(error.message, errorOptions)));
15563
15595
  } else {
15564
15596
  console.error(genericError(error.message));
15565
15597
  if (error.metadata.suggestion) console.error(escapeControlChars(error.metadata.suggestion));
@@ -15571,7 +15603,7 @@ function handleValidationError(error, json) {
15571
15603
  const envelope = OutputBuilder.buildJsonError(message, {
15572
15604
  exitCode: EXIT_CODES.INVALID_ARGUMENTS
15573
15605
  });
15574
- console.log(JSON.stringify(envelope, null, 2));
15606
+ console.log(stringifyEnvelope(envelope));
15575
15607
  } else {
15576
15608
  console.error(genericError(message));
15577
15609
  }
@@ -15597,20 +15629,18 @@ function noActiveSessionError() {
15597
15629
  async function runJsonCommand(fn) {
15598
15630
  try {
15599
15631
  const data = await fn();
15600
- console.log(JSON.stringify(buildSuccessResponse(data), null, 2));
15632
+ console.log(stringifyEnvelope(buildSuccessResponse(data)));
15601
15633
  process.exit(EXIT_CODES.SUCCESS);
15602
15634
  } catch (caught) {
15603
15635
  const error = isDaemonConnectionError(caught) ? noActiveSessionError() : caught instanceof IPCTimeoutError ? timeoutError(caught) : caught;
15604
15636
  const exitCode = getErrorExitCode(error, EXIT_CODES.UNHANDLED_EXCEPTION);
15605
15637
  const suggestion = error instanceof CommandError && typeof error.metadata["suggestion"] === "string" ? error.metadata["suggestion"] : void 0;
15606
15638
  console.log(
15607
- JSON.stringify(
15639
+ stringifyEnvelope(
15608
15640
  OutputBuilder.buildJsonError(getErrorMessage(error), {
15609
15641
  exitCode,
15610
15642
  ...suggestion && { suggestion }
15611
- }),
15612
- null,
15613
- 2
15643
+ })
15614
15644
  )
15615
15645
  );
15616
15646
  process.exit(exitCode);
@@ -15636,13 +15666,11 @@ async function runCommand(handler, options, formatter) {
15636
15666
  const exitCode = result.exitCode ?? EXIT_CODES.UNHANDLED_EXCEPTION;
15637
15667
  if (options.json) {
15638
15668
  console.log(
15639
- JSON.stringify(
15669
+ stringifyEnvelope(
15640
15670
  OutputBuilder.buildJsonError(result.error ?? "Unknown error", {
15641
15671
  ...result.errorContext,
15642
15672
  exitCode
15643
- }),
15644
- null,
15645
- 2
15673
+ })
15646
15674
  )
15647
15675
  );
15648
15676
  } else {
@@ -15663,12 +15691,12 @@ async function runCommand(handler, options, formatter) {
15663
15691
  console.error(escapeControlChars(result.hint));
15664
15692
  }
15665
15693
  if (options.json) {
15666
- console.log(JSON.stringify(buildSuccessResponse(result.data), null, 2));
15694
+ console.log(stringifyEnvelope(buildSuccessResponse(result.data)));
15667
15695
  } else if (formatter) {
15668
15696
  const formattedOutput = formatter(result.data);
15669
15697
  console.log(escapeControlChars(formattedOutput));
15670
15698
  } else {
15671
- console.log(JSON.stringify(buildSuccessResponse(result.data), null, 2));
15699
+ console.log(stringifyEnvelope(buildSuccessResponse(result.data)));
15672
15700
  }
15673
15701
  process.exit(EXIT_CODES.SUCCESS);
15674
15702
  } catch (caught) {
@@ -15676,13 +15704,11 @@ async function runCommand(handler, options, formatter) {
15676
15704
  if (error instanceof CommandError) {
15677
15705
  if (options.json) {
15678
15706
  console.log(
15679
- JSON.stringify(
15707
+ stringifyEnvelope(
15680
15708
  OutputBuilder.buildJsonError(error.message, {
15681
15709
  ...error.metadata,
15682
15710
  exitCode: error.exitCode
15683
- }),
15684
- null,
15685
- 2
15711
+ })
15686
15712
  )
15687
15713
  );
15688
15714
  } else {
@@ -15697,13 +15723,11 @@ async function runCommand(handler, options, formatter) {
15697
15723
  if (isDaemonConnectionError(error)) {
15698
15724
  if (options.json) {
15699
15725
  console.log(
15700
- JSON.stringify(
15726
+ stringifyEnvelope(
15701
15727
  OutputBuilder.buildJsonError(noActiveSessionMessage(), {
15702
15728
  suggestion: startSessionSuggestion(),
15703
15729
  exitCode: EXIT_CODES.RESOURCE_NOT_FOUND
15704
- }),
15705
- null,
15706
- 2
15730
+ })
15707
15731
  )
15708
15732
  );
15709
15733
  } else {
@@ -15713,9 +15737,7 @@ async function runCommand(handler, options, formatter) {
15713
15737
  }
15714
15738
  const exitCode = getErrorExitCode(error, EXIT_CODES.UNHANDLED_EXCEPTION);
15715
15739
  if (options.json) {
15716
- console.log(
15717
- JSON.stringify(OutputBuilder.buildJsonError(errorMessage, { exitCode }), null, 2)
15718
- );
15740
+ console.log(stringifyEnvelope(OutputBuilder.buildJsonError(errorMessage, { exitCode })));
15719
15741
  } else {
15720
15742
  console.error(genericError(errorMessage));
15721
15743
  }
@@ -16262,7 +16284,7 @@ function reportStartOutcome(outcome, options) {
16262
16284
  exitCode: outcome.exitCode,
16263
16285
  ...outcome.details
16264
16286
  });
16265
- console.log(JSON.stringify(envelope, null, 2));
16287
+ console.log(stringifyEnvelope(envelope));
16266
16288
  } else {
16267
16289
  console.error(escapeControlChars(outcome.human));
16268
16290
  }
@@ -16283,7 +16305,7 @@ function reportStartOutcome(outcome, options) {
16283
16305
  daemonPid: data.daemonPid,
16284
16306
  ...autoStopAt && { autoStopAt: autoStopAt.toISOString() }
16285
16307
  };
16286
- console.log(JSON.stringify(buildSuccessResponse(result), null, 2));
16308
+ console.log(stringifyEnvelope(buildSuccessResponse(result)));
16287
16309
  } else {
16288
16310
  const page = {
16289
16311
  url: data.targetUrl,
@@ -16524,9 +16546,10 @@ init_errors();
16524
16546
  var CDP_HTTP_TIMEOUT_MS = 5e3;
16525
16547
  async function probeDevToolsEndpoint(port, logger, options) {
16526
16548
  const url = `${options?.secure ? "https" : "http"}://${options?.host ?? HTTP_LOCALHOST}:${port}/json/version`;
16549
+ const timeoutMs = options?.timeoutMs ?? CDP_HTTP_TIMEOUT_MS;
16527
16550
  let response;
16528
16551
  try {
16529
- response = await fetch(url, { signal: AbortSignal.timeout(CDP_HTTP_TIMEOUT_MS) });
16552
+ response = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });
16530
16553
  } catch (error) {
16531
16554
  logger?.debug(`Chrome version request failed: ${getErrorMessage(error)} (${url})`);
16532
16555
  return { kind: "unreachable" };
@@ -16837,6 +16860,10 @@ function assertValidChromeWsUrl(url) {
16837
16860
  );
16838
16861
  }
16839
16862
 
16863
+ // src/index.ts
16864
+ init_errors3();
16865
+ init_messages();
16866
+
16840
16867
  // src/commands/cdp.ts
16841
16868
  init_protocol();
16842
16869
  init_schema();
@@ -17855,7 +17882,7 @@ function handleDaemonConnectionError(error, options) {
17855
17882
  exitCode,
17856
17883
  ...suggestion && { suggestion }
17857
17884
  });
17858
- console.log(follow ? JSON.stringify(envelope) : JSON.stringify(envelope, null, 2));
17885
+ console.log(follow ? JSON.stringify(envelope) : stringifyEnvelope(envelope));
17859
17886
  } else {
17860
17887
  console.error(genericError(message));
17861
17888
  }
@@ -17941,9 +17968,17 @@ async function fetchPreviewData(query = {}) {
17941
17968
  async function fetchNetworkRequests(withHeaders = false) {
17942
17969
  const result = await fetchPreviewData({ lastN: 0, only: "network", withHeaders });
17943
17970
  if (!result.success) return result;
17971
+ const { totals, pageCrashedAt } = result.data.output;
17944
17972
  return {
17945
17973
  success: true,
17946
- data: { requests: result.data.network, pageCrashedAt: result.data.output.pageCrashedAt }
17974
+ data: {
17975
+ requests: result.data.network,
17976
+ pageCrashedAt,
17977
+ evictions: {
17978
+ requestsDropped: totals?.networkDropped ?? 0,
17979
+ bodiesEvicted: totals?.networkBodiesEvicted ?? 0
17980
+ }
17981
+ }
17947
17982
  };
17948
17983
  }
17949
17984
  async function fetchConsoleMessages() {
@@ -18010,9 +18045,24 @@ async function setupFollowMode(refreshFn, options) {
18010
18045
  process.on("SIGTERM", () => stop2(EXIT_CODES.TERMINATED));
18011
18046
  }
18012
18047
 
18048
+ // src/commands/console.ts
18049
+ init_constants();
18050
+
18013
18051
  // src/ui/formatters/console.ts
18014
18052
  init_commands();
18015
18053
 
18054
+ // src/ui/formatters/console/chronological.ts
18055
+ init_constants();
18056
+
18057
+ // src/ui/formatters/longValues.ts
18058
+ init_commands();
18059
+ init_strings();
18060
+ function capForDisplay(text, maxLength, full) {
18061
+ if (full) return text;
18062
+ const capped = capLength(text, maxLength);
18063
+ return capped.truncatedFrom === void 0 ? text : `${capped.text}${moreCharsNote(capped.truncatedFrom - capped.text.length)}`;
18064
+ }
18065
+
18016
18066
  // src/ui/formatters/console/chronological.ts
18017
18067
  init_formatting();
18018
18068
 
@@ -18040,10 +18090,9 @@ function consoleMoreGroupsNote(more, level) {
18040
18090
  return `(+${more} earlier distinct ${more === 1 ? level : `${level}s`}; ${sessionCommand(`bdg console --level ${level} --last 0`)} lists every one)`;
18041
18091
  }
18042
18092
 
18043
- // src/ui/formatters/console/chronological.ts
18044
- init_strings();
18045
-
18046
18093
  // src/ui/formatters/console/shared.ts
18094
+ init_constants();
18095
+ init_strings();
18047
18096
  var DEFAULT_GROUP_LIMIT = 50;
18048
18097
  function newestGroups(groups, limit) {
18049
18098
  const keep = limit ?? DEFAULT_GROUP_LIMIT;
@@ -18170,9 +18219,13 @@ function formatSectionHeader(label, unique, total) {
18170
18219
  function formatFramePosition(frame) {
18171
18220
  return frame.lineNumber < 0 ? frame.url : `${frame.url}:${frame.lineNumber + 1}:${frame.columnNumber + 1}`;
18172
18221
  }
18222
+ function capMessageText(message, full) {
18223
+ if (full) return message;
18224
+ const { text, truncatedFrom } = capLength(message.text, MAX_CONSOLE_JSON_TEXT_LENGTH);
18225
+ return truncatedFrom === void 0 ? message : { ...message, text, truncatedFrom };
18226
+ }
18173
18227
 
18174
18228
  // src/ui/formatters/console/chronological.ts
18175
- var MAX_LIST_TEXT_LENGTH = 200;
18176
18229
  function formatConsoleChronological(messages, options) {
18177
18230
  const fmt = new OutputFormatter();
18178
18231
  const displayMessages = lastMessages(messages, options.last);
@@ -18203,8 +18256,8 @@ function formatConsoleChronological(messages, options) {
18203
18256
  }
18204
18257
  lastNavigationId = msg.navigationId;
18205
18258
  }
18206
- const truncatedText = truncateByLength(msg.text, MAX_LIST_TEXT_LENGTH);
18207
- fmt.text(`${index} ${level} ${time} ${truncatedText}`);
18259
+ const text = capForDisplay(msg.text, MAX_CONSOLE_TEXT_LENGTH, options.full);
18260
+ fmt.text(`${index} ${level} ${time} ${text}`);
18208
18261
  const source = formatSourceLocation(msg.stackTrace);
18209
18262
  if (source) {
18210
18263
  fmt.text(`${sourceIndent}\u2192 ${source}`);
@@ -18221,56 +18274,20 @@ function lastMessages(messages, last) {
18221
18274
  return last && last > 0 ? messages.slice(-last) : messages;
18222
18275
  }
18223
18276
 
18224
- // src/ui/formatters/console/json.ts
18225
- function toJsonError(dedup, includeStackTrace) {
18226
- const source = dedup.message.stackTrace?.[0];
18227
- return {
18228
- count: dedup.count,
18229
- level: dedup.message.type,
18230
- text: dedup.message.text,
18231
- ...dedup.message.index !== void 0 && { index: dedup.message.index },
18232
- ...source && {
18233
- source: {
18234
- url: source.url,
18235
- ...source.lineNumber >= 0 && {
18236
- line: source.lineNumber + 1,
18237
- column: source.columnNumber + 1
18238
- }
18239
- }
18240
- },
18241
- ...includeStackTrace && dedup.message.stackTrace && { stackTrace: dedup.message.stackTrace }
18242
- };
18243
- }
18244
- function buildConsoleJsonOutput(messages, options) {
18245
- const { grouped, summary } = analyzeMessages(messages);
18246
- const errors = newestGroups(grouped.errors, options.groupLimit);
18247
- const warnings = newestGroups(grouped.warnings, options.groupLimit);
18248
- const output = {
18249
- summary,
18250
- errors: errors.shown.map((d) => toJsonError(d, true)),
18251
- warnings: warnings.shown.map((d) => toJsonError(d, false)),
18252
- ...errors.more > 0 && { moreErrors: errors.more },
18253
- ...warnings.more > 0 && { moreWarnings: warnings.more },
18254
- ...options.dropped && { dropped: options.dropped },
18255
- ...options.pageCrashedAt !== void 0 && { pageCrashedAt: options.pageCrashedAt }
18256
- };
18257
- if (options.list) output.messages = lastMessages(messages, options.last);
18258
- return output;
18259
- }
18260
- function formatConsoleJson(messages, options) {
18261
- return JSON.stringify(buildConsoleJsonOutput(messages, options), null, 2);
18262
- }
18263
-
18264
18277
  // src/ui/formatters/console/summarize.ts
18278
+ init_constants();
18265
18279
  init_formatting();
18266
- function renderErrorSection(fmt, errors, total, limit) {
18280
+ function messageText(message, full) {
18281
+ return capForDisplay(message.text, MAX_CONSOLE_TEXT_LENGTH, full);
18282
+ }
18283
+ function renderErrorSection(fmt, errors, total, limit, full) {
18267
18284
  if (errors.length === 0) return;
18268
18285
  const { shown, more } = newestGroups(errors, limit);
18269
18286
  fmt.text(formatSectionHeader("Errors", errors.length, total));
18270
18287
  fmt.separator("\u2500", 30);
18271
18288
  if (more > 0) fmt.text(consoleMoreGroupsNote(more, "error")).blank();
18272
18289
  for (const { message, count } of shown) {
18273
- fmt.text(`${formatCountPrefix(count)}${message.text}`);
18290
+ fmt.text(`${formatCountPrefix(count)}${messageText(message, full)}`);
18274
18291
  const source = formatSourceLocation(message.stackTrace);
18275
18292
  if (source) {
18276
18293
  fmt.text(` \u2192 ${source}`);
@@ -18278,14 +18295,14 @@ function renderErrorSection(fmt, errors, total, limit) {
18278
18295
  fmt.blank();
18279
18296
  }
18280
18297
  }
18281
- function renderWarningSection(fmt, warnings, total, limit) {
18298
+ function renderWarningSection(fmt, warnings, total, limit, full) {
18282
18299
  if (warnings.length === 0) return;
18283
18300
  const { shown, more } = newestGroups(warnings, limit);
18284
18301
  fmt.text(formatSectionHeader("Warnings", warnings.length, total));
18285
18302
  fmt.separator("\u2500", 30);
18286
18303
  if (more > 0) fmt.text(consoleMoreGroupsNote(more, "warning"));
18287
18304
  for (const { message, count } of shown) {
18288
- fmt.text(`\u2022 ${formatCountPrefix(count)}${message.text}`);
18305
+ fmt.text(`\u2022 ${formatCountPrefix(count)}${messageText(message, full)}`);
18289
18306
  const source = formatSourceLocation(message.stackTrace);
18290
18307
  if (source) fmt.text(` \u2192 ${source}`);
18291
18308
  }
@@ -18309,8 +18326,9 @@ function formatConsoleSummary(messages, options = {}) {
18309
18326
  fmt.separator("\u2501", 60);
18310
18327
  if (options.dropped) fmt.text(consoleDroppedNote(options.dropped));
18311
18328
  fmt.blank();
18312
- renderErrorSection(fmt, grouped.errors, summary.errors.total, options.groupLimit);
18313
- renderWarningSection(fmt, grouped.warnings, summary.warnings.total, options.groupLimit);
18329
+ const { groupLimit, full } = options;
18330
+ renderErrorSection(fmt, grouped.errors, summary.errors.total, groupLimit, full);
18331
+ renderWarningSection(fmt, grouped.warnings, summary.warnings.total, groupLimit, full);
18314
18332
  if (grouped.errors.length === 0 && grouped.warnings.length === 0) {
18315
18333
  fmt.text("No errors or warnings found");
18316
18334
  fmt.blank();
@@ -18320,6 +18338,7 @@ function formatConsoleSummary(messages, options = {}) {
18320
18338
  }
18321
18339
 
18322
18340
  // src/ui/formatters/console/follow.ts
18341
+ init_constants();
18323
18342
  init_formatting();
18324
18343
  function formatConsoleFollowLines(messages, options = {}) {
18325
18344
  const fmt = new OutputFormatter();
@@ -18333,18 +18352,56 @@ function formatConsoleFollowLines(messages, options = {}) {
18333
18352
  for (const msg of messages) {
18334
18353
  const time = formatTimestamp(msg.timestamp);
18335
18354
  const level = msg.type.padEnd(7);
18336
- fmt.text(`${time} ${level} ${msg.text}`);
18355
+ fmt.text(`${time} ${level} ${capForDisplay(msg.text, MAX_CONSOLE_TEXT_LENGTH, options.full)}`);
18337
18356
  const source = formatSourceLocation(msg.stackTrace);
18338
18357
  if (source) fmt.text(` \u2192 ${source}`);
18339
18358
  }
18340
18359
  return fmt.build();
18341
18360
  }
18342
18361
 
18362
+ // src/ui/formatters/console/json.ts
18363
+ function toJsonError(dedup, includeStackTrace) {
18364
+ const source = dedup.message.stackTrace?.[0];
18365
+ return {
18366
+ count: dedup.count,
18367
+ level: dedup.message.type,
18368
+ text: dedup.message.text,
18369
+ ...dedup.message.index !== void 0 && { index: dedup.message.index },
18370
+ ...source && {
18371
+ source: {
18372
+ url: source.url,
18373
+ ...source.lineNumber >= 0 && {
18374
+ line: source.lineNumber + 1,
18375
+ column: source.columnNumber + 1
18376
+ }
18377
+ }
18378
+ },
18379
+ ...includeStackTrace && dedup.message.stackTrace && { stackTrace: dedup.message.stackTrace }
18380
+ };
18381
+ }
18382
+ function buildConsoleJsonOutput(messages, options) {
18383
+ const { grouped, summary } = analyzeMessages(messages);
18384
+ const errors = newestGroups(grouped.errors, options.groupLimit);
18385
+ const warnings = newestGroups(grouped.warnings, options.groupLimit);
18386
+ const output = {
18387
+ summary,
18388
+ errors: errors.shown.map((d) => capMessageText(toJsonError(d, true), options.full)),
18389
+ warnings: warnings.shown.map((d) => capMessageText(toJsonError(d, false), options.full)),
18390
+ ...errors.more > 0 && { moreErrors: errors.more },
18391
+ ...warnings.more > 0 && { moreWarnings: warnings.more },
18392
+ ...options.dropped && { dropped: options.dropped },
18393
+ ...options.pageCrashedAt !== void 0 && { pageCrashedAt: options.pageCrashedAt }
18394
+ };
18395
+ if (options.list) {
18396
+ output.messages = lastMessages(messages, options.last).map(
18397
+ (message) => capMessageText(message, options.full)
18398
+ );
18399
+ }
18400
+ return output;
18401
+ }
18402
+
18343
18403
  // src/ui/formatters/console.ts
18344
18404
  function formatConsole(messages, options) {
18345
- if (options.json) {
18346
- return formatConsoleJson(messages, options);
18347
- }
18348
18405
  const body = options.list || options.level ? formatConsoleChronological(messages, options) : formatConsoleSummary(messages, options);
18349
18406
  return withPageCrashedNote(body, options.pageCrashedAt);
18350
18407
  }
@@ -18402,12 +18459,12 @@ function buildFormatOptions(options, lastN, skipped, dropped, pageCrashedAt) {
18402
18459
  ...options.last !== void 0 && { groupLimit: lastN },
18403
18460
  ...dropped && { dropped },
18404
18461
  ...pageCrashedAt !== void 0 && { pageCrashedAt },
18405
- json: options.json,
18406
18462
  list: listsMessages(options),
18407
18463
  follow: options.follow,
18408
18464
  last: lastN,
18409
18465
  history: options.history,
18410
18466
  level: options.level,
18467
+ full: options.full,
18411
18468
  skipped
18412
18469
  };
18413
18470
  }
@@ -18437,13 +18494,15 @@ async function runFollowMode(options, lastN) {
18437
18494
  const data = buildConsoleJsonOutput(backlog, {
18438
18495
  list: true,
18439
18496
  last: 0,
18440
- pageCrashedAt: crashedAt
18497
+ pageCrashedAt: crashedAt,
18498
+ full: options.full
18441
18499
  });
18442
18500
  console.log(JSON.stringify(buildSuccessResponse(data)));
18443
18501
  }
18444
18502
  } else {
18445
18503
  const text = formatConsoleFollowLines(backlog, {
18446
18504
  header: !started,
18505
+ full: options.full,
18447
18506
  ...navigated && currentNavigationId !== void 0 && { navigationId: currentNavigationId }
18448
18507
  });
18449
18508
  if (text) console.log(text);
@@ -18478,7 +18537,12 @@ function registerConsoleCommand(program2) {
18478
18537
  "--level <level>",
18479
18538
  "Filter by message level: error, warning, info (includes log), debug; any case"
18480
18539
  ).argParser(consoleLevelOption)
18481
- ).addOption(consoleLastOption).addOption(jsonOption()).action(async (options) => {
18540
+ ).addOption(consoleLastOption).addOption(
18541
+ new Option(
18542
+ "--full",
18543
+ `Print message texts whole (default: the first ${MAX_CONSOLE_TEXT_LENGTH} characters, ${MAX_CONSOLE_JSON_TEXT_LENGTH} in JSON)`
18544
+ ).default(false)
18545
+ ).addOption(jsonOption()).action(async (options) => {
18482
18546
  let lastN;
18483
18547
  try {
18484
18548
  lastN = positiveIntRule({
@@ -18644,217 +18708,114 @@ async function search(text, options) {
18644
18708
  // src/commands/details.ts
18645
18709
  init_client();
18646
18710
 
18647
- // src/telemetry/network.ts
18711
+ // src/ui/messages/networkMessages.ts
18648
18712
  init_constants();
18713
+ init_formatting();
18714
+ function megabytes(bytes) {
18715
+ return `${Math.round(bytes / (1024 * 1024))} MB`;
18716
+ }
18717
+ function networkEvictedNote(counts) {
18718
+ const { requestsDropped, bodiesEvicted } = counts;
18719
+ const requests = pluralize(requestsDropped, "older network request");
18720
+ const bodies = pluralize(bodiesEvicted, "older response body", "older response bodies");
18721
+ const budget = megabytes(MAX_TOTAL_BODY_BYTES);
18722
+ if (requestsDropped > 0 && bodiesEvicted > 0) {
18723
+ return `\u26A0 ${requests} dropped, ${bodies} evicted: bdg keeps the newest ${MAX_NETWORK_REQUESTS} requests and ${budget} of bodies`;
18724
+ }
18725
+ if (requestsDropped > 0) {
18726
+ return `\u26A0 ${requests} ${requestsDropped === 1 ? "was" : "were"} dropped: bdg keeps the newest ${MAX_NETWORK_REQUESTS}`;
18727
+ }
18728
+ if (bodiesEvicted > 0) {
18729
+ return `\u26A0 ${bodies} ${bodiesEvicted === 1 ? "was" : "were"} evicted: bdg keeps the newest ${budget} of bodies`;
18730
+ }
18731
+ return void 0;
18732
+ }
18733
+ function followingNetworkMessage() {
18734
+ return "Following network requests... (Ctrl+C to stop)";
18735
+ }
18736
+ function stoppedFollowingNetworkMessage() {
18737
+ return "\nStopped following network requests.";
18738
+ }
18739
+ function headerRepeatedNote(count) {
18740
+ return `(sent ${count} times)`;
18741
+ }
18742
+ function localProxyNote() {
18743
+ return "(loopback; likely a local proxy)";
18744
+ }
18649
18745
 
18650
- // src/telemetry/attachedTargets.ts
18651
- init_logging();
18652
- init_errors();
18653
- var log21 = createLogger("targets");
18746
+ // src/telemetry/networkRetention.ts
18747
+ var SKIPPED_BODY_PATTERN = /^\[SKIPPED: (.*)\]$/s;
18748
+ function skippedBodyReason(body) {
18749
+ return body === void 0 ? void 0 : SKIPPED_BODY_PATTERN.exec(body)?.[1];
18750
+ }
18654
18751
 
18655
- // src/telemetry/network.ts
18656
- init_logging();
18657
- init_errors();
18752
+ // src/telemetry/requestState.ts
18753
+ function getRequestState(request) {
18754
+ if (request.status === void 0) return "pending";
18755
+ return request.status === 0 ? "failed" : "complete";
18756
+ }
18757
+ function failureReason(request) {
18758
+ if (!request.errorText) return void 0;
18759
+ return getRequestState(request) === "complete" && request.errorText === BODY_ABORTED ? void 0 : request.errorText;
18760
+ }
18761
+ var BODY_ABORTED = "net::ERR_ABORTED";
18658
18762
 
18659
- // src/telemetry/filters.ts
18660
- init_url();
18661
- var DEFAULT_EXCLUDED_DOMAINS = [
18662
- "analytics.google.com",
18663
- "googletagmanager.com",
18664
- "googleadservices.com",
18665
- "doubleclick.net",
18666
- "google-analytics.com",
18667
- "clarity.ms",
18668
- "bat.bing.com",
18669
- "facebook.com",
18670
- "connect.facebook.net",
18671
- "tiktok.com",
18672
- "linkedin.com",
18673
- "twitter.com",
18674
- "snapchat.com",
18675
- "mixpanel.com",
18676
- "segment.com",
18677
- "segment.io",
18678
- "amplitude.com",
18679
- "heap.io",
18680
- "fullstory.com",
18681
- "hotjar.com",
18682
- "logrocket.com",
18683
- "smartlook.com",
18684
- "exactag.com",
18685
- "criteo.com",
18686
- "adroll.com",
18687
- "outbrain.com",
18688
- "taboola.com",
18689
- "confirmit.com",
18690
- "newrelic.com",
18691
- "datadoghq.com",
18692
- "sentry.io",
18693
- "googlesyndication.com",
18694
- "googletagservices.com",
18695
- "adservice.google.com",
18696
- "amazon-adsystem.com",
18697
- "adnxs.com",
18698
- "rubiconproject.com",
18699
- "pubmatic.com",
18700
- "casalemedia.com",
18701
- "indexww.com",
18702
- "openx.net",
18703
- "3lift.com",
18704
- "teads.tv",
18705
- "bidswitch.net",
18706
- "sharethrough.com",
18707
- "adsafeprotected.com",
18708
- "moatads.com",
18709
- "doubleverify.com",
18710
- "scorecardresearch.com",
18711
- "imrworldwide.com",
18712
- "chartbeat.com",
18713
- "chartbeat.net",
18714
- "permutive.com",
18715
- "permutive.app",
18716
- "optimizely.com",
18717
- "quantserve.com",
18718
- "quantcount.com",
18719
- "krxd.net",
18720
- "demdex.net",
18721
- "omtrdc.net",
18722
- "everesttech.net",
18723
- "xiti.com",
18724
- "ati-host.net"
18725
- ];
18726
- var EXCLUDED_DOMAINS_SET = new Set(DEFAULT_EXCLUDED_DOMAINS.map((d) => d.toLowerCase()));
18727
- var DEFAULT_SKIP_BODY_MIME_TYPES = [
18728
- "text/css",
18729
- "image/svg+xml",
18730
- "image/png",
18731
- "image/jpeg",
18732
- "image/gif",
18733
- "image/webp",
18734
- "image/avif",
18735
- "image/bmp",
18736
- "image/tiff",
18737
- "font/woff",
18738
- "font/woff2",
18739
- "font/ttf",
18740
- "font/eot",
18741
- "font/otf",
18742
- "application/font-woff",
18743
- "application/font-woff2",
18744
- "video/mp4",
18745
- "video/webm",
18746
- "audio/mpeg",
18747
- "audio/wav"
18748
- ];
18749
- var SKIP_BODY_MIME_TYPES_SET = new Set(DEFAULT_SKIP_BODY_MIME_TYPES.map((m) => m.toLowerCase()));
18750
- function matchesWildcard(str, pattern) {
18751
- const regexPattern = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
18752
- const regex = new RegExp(`^${regexPattern}$`, "i");
18753
- return regex.test(str);
18754
- }
18755
- function filterByResourceType(requests, types) {
18756
- if (types.length === 0) {
18757
- return requests;
18758
- }
18759
- return requests.filter((req) => {
18760
- if (!req.resourceType) {
18761
- return false;
18762
- }
18763
- return types.includes(req.resourceType);
18764
- });
18765
- }
18766
-
18767
- // src/telemetry/network.ts
18768
- var log22 = createLogger("network");
18769
- var SKIPPED_BODY_PATTERN = /^\[SKIPPED: (.*)\]$/s;
18770
- function skippedBodyReason(body) {
18771
- return body === void 0 ? void 0 : SKIPPED_BODY_PATTERN.exec(body)?.[1];
18772
- }
18773
- var MAX_FRAME_PAYLOAD_SIZE = 100 * 1024;
18774
-
18775
- // src/telemetry/requestState.ts
18776
- function getRequestState(request) {
18777
- if (request.status === void 0) return "pending";
18778
- return request.status === 0 ? "failed" : "complete";
18779
- }
18780
- function failureReason(request) {
18781
- if (!request.errorText) return void 0;
18782
- return getRequestState(request) === "complete" && request.errorText === BODY_ABORTED ? void 0 : request.errorText;
18783
- }
18784
- var BODY_ABORTED = "net::ERR_ABORTED";
18785
-
18786
- // src/ui/formatters/requestStatus.ts
18787
- function formatRequestStatus(request) {
18788
- const state = getRequestState(request);
18789
- if (state === "pending") return "pending";
18790
- if (state === "failed") return `FAILED (${request.errorText ?? "no response"})`;
18791
- return request.errorText && request.errorText !== BODY_ABORTED ? `${request.status} (${request.errorText})` : String(request.status);
18792
- }
18793
-
18794
- // src/ui/formatters/networkHeaders.ts
18795
- init_formatting();
18796
-
18797
- // src/ui/messages/networkMessages.ts
18798
- function followingNetworkMessage() {
18799
- return "Following network requests... (Ctrl+C to stop)";
18800
- }
18801
- function stoppedFollowingNetworkMessage() {
18802
- return "\nStopped following network requests.";
18803
- }
18804
- function headerRepeatedNote(count) {
18805
- return `(sent ${count} times)`;
18806
- }
18807
- function localProxyNote() {
18808
- return "(loopback; likely a local proxy)";
18809
- }
18810
-
18811
- // src/ui/formatters/networkHeaders.ts
18812
- function formatNetworkHeaders(data) {
18813
- const fmt = new OutputFormatter();
18814
- fmt.text("Network Request Headers").separator("\u2501", 60).blank();
18815
- fmt.text("URL:").text(` ${data.url}`).blank();
18816
- fmt.text(`Status: ${requestStatusLine(data)}`).blank();
18817
- if (Object.keys(data.responseHeaders).length > 0) {
18818
- fmt.text("Response Headers:");
18819
- formatHeaderSection(fmt, data.responseHeaders);
18820
- fmt.blank();
18821
- }
18822
- if (Object.keys(data.requestHeaders).length > 0) {
18823
- fmt.text("Request Headers:");
18824
- formatHeaderSection(fmt, data.requestHeaders);
18825
- fmt.blank();
18826
- }
18827
- if (Object.keys(data.responseHeaders).length === 0 && Object.keys(data.requestHeaders).length === 0) {
18828
- fmt.text("No headers found").blank();
18829
- }
18830
- fmt.text(`Request ID: ${data.requestId}`);
18831
- return fmt.build();
18832
- }
18833
- function headerValueLines(name, value) {
18834
- if (name.toLowerCase() === "set-cookie") return value.split("\n");
18835
- const counts = /* @__PURE__ */ new Map();
18836
- for (const line of value.split("\n")) counts.set(line, (counts.get(line) ?? 0) + 1);
18837
- return [...counts].map(
18838
- ([line, count]) => count > 1 ? `${line} ${headerRepeatedNote(count)}` : line
18839
- );
18840
- }
18841
- function formatHeaderSection(fmt, headers) {
18842
- const entries = Object.entries(headers).sort(([a], [b]) => a.localeCompare(b));
18843
- const keyWidth = Math.max(...entries.map(([k]) => k.length)) + 4;
18844
- entries.forEach(([key, value]) => {
18845
- headerValueLines(key, value).forEach((line) => fmt.keyValue(` ${key}`, line, keyWidth));
18846
- });
18847
- }
18848
- function requestStatusLine(data) {
18849
- const status = formatRequestStatus(data);
18850
- const text = data.statusText && /^\d+$/.test(status) ? ` ${data.statusText}` : "";
18851
- return [data.method, `${status}${text}`].filter(Boolean).join(" ");
18852
- }
18853
-
18854
- // src/ui/formatters/details.ts
18855
- init_formatting();
18856
- init_sessionCommand();
18857
- init_strings();
18763
+ // src/ui/formatters/requestStatus.ts
18764
+ function formatRequestStatus(request) {
18765
+ const state = getRequestState(request);
18766
+ if (state === "pending") return "pending";
18767
+ if (state === "failed") return `FAILED (${request.errorText ?? "no response"})`;
18768
+ return request.errorText && request.errorText !== BODY_ABORTED ? `${request.status} (${request.errorText})` : String(request.status);
18769
+ }
18770
+
18771
+ // src/ui/formatters/networkHeaders.ts
18772
+ init_formatting();
18773
+ function formatNetworkHeaders(data) {
18774
+ const fmt = new OutputFormatter();
18775
+ fmt.text("Network Request Headers").separator("\u2501", 60).blank();
18776
+ fmt.text("URL:").text(` ${data.url}`).blank();
18777
+ fmt.text(`Status: ${requestStatusLine(data)}`).blank();
18778
+ if (Object.keys(data.responseHeaders).length > 0) {
18779
+ fmt.text("Response Headers:");
18780
+ formatHeaderSection(fmt, data.responseHeaders);
18781
+ fmt.blank();
18782
+ }
18783
+ if (Object.keys(data.requestHeaders).length > 0) {
18784
+ fmt.text("Request Headers:");
18785
+ formatHeaderSection(fmt, data.requestHeaders);
18786
+ fmt.blank();
18787
+ }
18788
+ if (Object.keys(data.responseHeaders).length === 0 && Object.keys(data.requestHeaders).length === 0) {
18789
+ fmt.text("No headers found").blank();
18790
+ }
18791
+ fmt.text(`Request ID: ${data.requestId}`);
18792
+ return fmt.build();
18793
+ }
18794
+ function headerValueLines(name, value) {
18795
+ if (name.toLowerCase() === "set-cookie") return value.split("\n");
18796
+ const counts = /* @__PURE__ */ new Map();
18797
+ for (const line of value.split("\n")) counts.set(line, (counts.get(line) ?? 0) + 1);
18798
+ return [...counts].map(
18799
+ ([line, count]) => count > 1 ? `${line} ${headerRepeatedNote(count)}` : line
18800
+ );
18801
+ }
18802
+ function formatHeaderSection(fmt, headers) {
18803
+ const entries = Object.entries(headers).sort(([a], [b]) => a.localeCompare(b));
18804
+ const keyWidth = Math.max(...entries.map(([k]) => k.length)) + 4;
18805
+ entries.forEach(([key, value]) => {
18806
+ headerValueLines(key, value).forEach((line) => fmt.keyValue(` ${key}`, line, keyWidth));
18807
+ });
18808
+ }
18809
+ function requestStatusLine(data) {
18810
+ const status = formatRequestStatus(data);
18811
+ const text = data.statusText && /^\d+$/.test(status) ? ` ${data.statusText}` : "";
18812
+ return [data.method, `${status}${text}`].filter(Boolean).join(" ");
18813
+ }
18814
+
18815
+ // src/ui/formatters/details.ts
18816
+ init_formatting();
18817
+ init_sessionCommand();
18818
+ init_strings();
18858
18819
  init_url();
18859
18820
  var MESSAGE_PREVIEW_LENGTH = 200;
18860
18821
  var BINARY_OPCODE = 2;
@@ -19435,6 +19396,9 @@ function findUnknownModifiers(modifiers) {
19435
19396
  return modifierNames(modifiers).filter((name) => !(name in MODIFIER_NAMES));
19436
19397
  }
19437
19398
 
19399
+ // src/ui/formatters/triggeredRequests.ts
19400
+ init_constants();
19401
+
19438
19402
  // src/telemetry/requestKinds.ts
19439
19403
  var ACTIVITY_RESOURCE_TYPES = /* @__PURE__ */ new Set([
19440
19404
  "Document",
@@ -19489,7 +19453,10 @@ function formatTriggeredRequestLines(requests, omitted = 0) {
19489
19453
  const assets = requests.filter((request) => !isNotableRequest(request));
19490
19454
  const lines = notable.slice(0, MAX_TRIGGERED_REQUESTS_SHOWN).map(formatTriggeredRequest);
19491
19455
  const hidden = notable.length - lines.length + omitted;
19492
- if (hidden > 0) lines.push(omitted > 0 ? moreRequestsNote(hidden) : moreMatchesNote(hidden));
19456
+ if (hidden > 0)
19457
+ lines.push(
19458
+ omitted > 0 ? moreRequestsNote(hidden) : moreMatchesNote(hidden, MAX_TRIGGERED_REQUESTS)
19459
+ );
19493
19460
  if (assets.length > 0) lines.push(assetRequestsNote(assets.length, assetTypeNames(assets)));
19494
19461
  return lines;
19495
19462
  }
@@ -19513,7 +19480,10 @@ function registerFormInteractionCommands(program2) {
19513
19480
  const err = internalError("DOM command group not found");
19514
19481
  throw new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.SOFTWARE_ERROR);
19515
19482
  }
19516
- domCommand.command("fill").description("Fill a form field with a value (React-compatible, waits for stability)").argument("<selectorOrIndex>", SELECTOR_OR_INDEX_ARGUMENT).argument("<value>", 'Value to fill (file inputs: paths separated by commas, "" clears)').option("--index <n>", "Element index if selector matches multiple (0-based)", integerOption(0)).option("--no-blur", "Do not blur after filling (keeps focus on element)").option("--no-wait", "Skip waiting for network stability after fill").addOption(jsonOption()).action(async (selectorOrIndex, value, options) => {
19483
+ domCommand.command("fill").description("Fill a form field with a value (React-compatible, waits for stability)").argument("<selectorOrIndex>", SELECTOR_OR_INDEX_ARGUMENT).argument(
19484
+ "<value>",
19485
+ 'Value to fill (file inputs: local file paths, separated by commas, that are uploaded to the page; "" clears)'
19486
+ ).option("--index <n>", "Element index if selector matches multiple (0-based)", integerOption(0)).option("--no-blur", "Do not blur after filling (keeps focus on element)").option("--no-wait", "Skip waiting for network stability after fill").addOption(jsonOption()).action(async (selectorOrIndex, value, options) => {
19517
19487
  await runCommand(
19518
19488
  () => runElementCommand({
19519
19489
  selectorOrIndex,
@@ -19939,7 +19909,7 @@ function synthesizeA11yNode(domContext, nodeId) {
19939
19909
  // src/ui/formatters/keyAttributes.ts
19940
19910
  init_formatting();
19941
19911
  init_url();
19942
- var MAX_VALUE_LENGTH = 40;
19912
+ var MAX_VALUE_LENGTH2 = 40;
19943
19913
  function fileName(src) {
19944
19914
  if (/^(data|blob):/i.test(src)) return src;
19945
19915
  const path7 = src.split(/[?#]/)[0] ?? src;
@@ -19953,13 +19923,13 @@ function hostOf(src) {
19953
19923
  return `//${parsed.host}${more}`;
19954
19924
  }
19955
19925
  function shortUrl(url) {
19956
- return /^https?:/i.test(url) ? `//${truncateUrl(url, MAX_VALUE_LENGTH - 2)}` : url;
19926
+ return /^https?:/i.test(url) ? `//${truncateUrl(url, MAX_VALUE_LENGTH2 - 2)}` : url;
19957
19927
  }
19958
19928
  function shortValue(tag, name, value) {
19959
19929
  let short = value;
19960
19930
  if (name === "src") short = tag === "iframe" ? hostOf(value) : fileName(value);
19961
19931
  else if (name === "href" || name === "action") short = shortUrl(value);
19962
- return cutMiddle(escapeControlChars(short.replace(/\s+/g, " ").trim()), MAX_VALUE_LENGTH);
19932
+ return cutMiddle(escapeControlChars(short.replace(/\s+/g, " ").trim()), MAX_VALUE_LENGTH2);
19963
19933
  }
19964
19934
  function keyAttributeItems(tag, attributes, leaveOut = /* @__PURE__ */ new Set()) {
19965
19935
  return Object.entries(attributes ?? {}).flatMap(([name, value]) => {
@@ -20059,6 +20029,7 @@ function withSecretMasked(node, domContext) {
20059
20029
  }
20060
20030
 
20061
20031
  // src/commands/dom/a11y.ts
20032
+ init_constants();
20062
20033
  init_errors3();
20063
20034
  init_messages();
20064
20035
 
@@ -20072,7 +20043,7 @@ init_elementInfo();
20072
20043
  init_frameScopedConnection();
20073
20044
  init_logging();
20074
20045
  init_errors();
20075
- var log28 = createLogger("dom");
20046
+ var log26 = createLogger("dom");
20076
20047
  function childFrameIds(tree) {
20077
20048
  return (tree?.childFrames ?? []).flatMap((child) => [child.frame.id, ...childFrameIds(child)]);
20078
20049
  }
@@ -20109,6 +20080,51 @@ function buildTreeFromRawNodes(rawNodes) {
20109
20080
  const root = nodes.get(rootRaw.nodeId);
20110
20081
  return { root, nodes, count: nodes.size };
20111
20082
  }
20083
+ var LAYOUT_ROLES = /* @__PURE__ */ new Set([
20084
+ "generic",
20085
+ "none",
20086
+ "presentation",
20087
+ "LayoutTable",
20088
+ "LayoutTableRow",
20089
+ "LayoutTableCell"
20090
+ ]);
20091
+ function isTreeNoise(node, parentName) {
20092
+ return node.role === "InlineTextBox" || node.role === "StaticText" && (node.name === parentName || !node.name?.trim()) || LAYOUT_ROLES.has(node.role) && !node.name;
20093
+ }
20094
+ function listA11yTree(tree, limit, maxDepth) {
20095
+ const nodes = [];
20096
+ const visited = /* @__PURE__ */ new Set();
20097
+ let omitted = 0;
20098
+ let skipped = 0;
20099
+ const visit = (node, depth, parentName) => {
20100
+ if (visited.has(node.nodeId)) return;
20101
+ visited.add(node.nodeId);
20102
+ const listable = !isTreeNoise(node, parentName);
20103
+ if (listable) {
20104
+ const fits = (limit === 0 || nodes.length < limit) && (maxDepth ?? depth) >= depth;
20105
+ if (fits) nodes.push(listedNode(node, depth));
20106
+ else omitted++;
20107
+ } else {
20108
+ skipped++;
20109
+ }
20110
+ for (const childId of node.childIds ?? []) {
20111
+ const child = tree.nodes.get(childId);
20112
+ if (child) visit(child, listable ? depth + 1 : depth, node.name ?? parentName);
20113
+ }
20114
+ };
20115
+ visit(tree.root, 0, void 0);
20116
+ for (const node of tree.nodes.values()) visit(node, 0, void 0);
20117
+ return {
20118
+ nodes,
20119
+ count: tree.count,
20120
+ ...omitted > 0 && { omitted },
20121
+ ...skipped > 0 && { skipped }
20122
+ };
20123
+ }
20124
+ function listedNode(node, depth) {
20125
+ const { childIds: _childIds, ...rest } = node;
20126
+ return { ...rest, depth };
20127
+ }
20112
20128
  function visibleChildIds(rawNode, rawById, seen = /* @__PURE__ */ new Set()) {
20113
20129
  return (rawNode.childIds ?? []).flatMap((childId) => {
20114
20130
  const child = rawById.get(childId);
@@ -20398,49 +20414,16 @@ var IGNORED_REASONS = {
20398
20414
  // src/ui/formatters/a11y.ts
20399
20415
  init_formatting();
20400
20416
  init_commands();
20401
- var MAX_TREE_NODES_DISPLAY = 50;
20402
20417
  var SEPARATOR_WIDTH = 50;
20403
20418
  function formatA11yTree(tree) {
20404
20419
  const fmt = new OutputFormatter();
20405
20420
  fmt.text(`Accessibility Tree (${tree.count} nodes)`).separator("\u2500", SEPARATOR_WIDTH).blank();
20406
- const { lines, truncated } = treeLines(tree);
20407
- lines.forEach((line) => fmt.text(line));
20408
- if (truncated) {
20409
- fmt.blank().text(
20410
- `Showing the first ${MAX_TREE_NODES_DISPLAY} nodes (text boxes and repeated text left out)`
20411
- ).text('Use --json flag for complete output, or bdg dom a11y query "role:<role>" to search');
20421
+ tree.nodes.forEach((node) => fmt.text(" ".repeat(node.depth) + formatA11yNodeOneLine(node)));
20422
+ if (tree.omitted) {
20423
+ fmt.blank().text(a11yTreeShownNote(tree.nodes.length)).text(a11yTreeMoreNote(tree.omitted));
20412
20424
  }
20413
20425
  return fmt.build();
20414
20426
  }
20415
- var LAYOUT_ROLES = /* @__PURE__ */ new Set([
20416
- "generic",
20417
- "none",
20418
- "presentation",
20419
- "LayoutTable",
20420
- "LayoutTableRow",
20421
- "LayoutTableCell"
20422
- ]);
20423
- function treeLines(tree) {
20424
- const lines = [];
20425
- const visited = /* @__PURE__ */ new Set();
20426
- let truncated = false;
20427
- const visit = (node, depth, parentName) => {
20428
- if (visited.has(node.nodeId)) return;
20429
- visited.add(node.nodeId);
20430
- if (lines.length >= MAX_TREE_NODES_DISPLAY) {
20431
- truncated = true;
20432
- return;
20433
- }
20434
- const skip = node.role === "InlineTextBox" || node.role === "StaticText" && (node.name === parentName || !node.name?.trim()) || LAYOUT_ROLES.has(node.role) && !node.name;
20435
- if (!skip) lines.push(" ".repeat(depth) + formatA11yNodeOneLine(node));
20436
- for (const childId of node.childIds ?? []) {
20437
- const child = tree.nodes.get(childId);
20438
- if (child) visit(child, skip ? depth : depth + 1, node.name ?? parentName);
20439
- }
20440
- };
20441
- visit(tree.root, 0, void 0);
20442
- return { lines, truncated };
20443
- }
20444
20427
  var FILLABLE_ROLES = /* @__PURE__ */ new Set([
20445
20428
  "textbox",
20446
20429
  "searchbox",
@@ -20571,19 +20554,14 @@ function truncate(str, maxLen) {
20571
20554
  // src/commands/dom/a11y.ts
20572
20555
  init_exitCodes();
20573
20556
  var A11Y_QUERY_LIMIT = 50;
20557
+ var A11Y_TREE_LIMIT = 50;
20574
20558
  async function handleA11yTree(options) {
20559
+ const listTree = async () => listA11yTree(await collectA11yTree(), options.limit ?? A11Y_TREE_LIMIT, options.depth);
20575
20560
  if (options.json) {
20576
- await runJsonCommand(async () => {
20577
- const tree = await collectA11yTree();
20578
- return {
20579
- root: tree.root,
20580
- nodes: Array.from(tree.nodes.values()),
20581
- count: tree.count
20582
- };
20583
- });
20561
+ await runJsonCommand(listTree);
20584
20562
  }
20585
20563
  await runCommand(
20586
- async () => ({ success: true, data: await collectA11yTree() }),
20564
+ async () => ({ success: true, data: await listTree() }),
20587
20565
  options,
20588
20566
  formatA11yTree
20589
20567
  );
@@ -20632,7 +20610,10 @@ async function handleA11yQuery(pattern, options) {
20632
20610
  );
20633
20611
  return {
20634
20612
  success: true,
20635
- data: limitMatches(indexed, options.limit ?? (options.json ? 0 : A11Y_QUERY_LIMIT))
20613
+ data: limitMatches(
20614
+ indexed,
20615
+ options.limit ?? (options.json ? QUERY_JSON_LIST_LIMIT : A11Y_QUERY_LIMIT)
20616
+ )
20636
20617
  };
20637
20618
  },
20638
20619
  options,
@@ -20704,7 +20685,17 @@ function registerA11yCommands(domCmd) {
20704
20685
  await handleA11yQuery(`name:${quoteQueryValue(search2)}`, options);
20705
20686
  }
20706
20687
  });
20707
- a11y.command("tree").description("Dump full accessibility tree (filters ignored nodes)").addOption(jsonOption()).action(async (options) => {
20688
+ a11y.command("tree").description(
20689
+ "List the accessibility tree depth-first (ignored nodes, text boxes, repeated text and nameless wrappers left out)"
20690
+ ).option(
20691
+ "--limit <n>",
20692
+ `Nodes to list (default: ${A11Y_TREE_LIMIT}, also with --json; 0 = all listed nodes (text boxes and empty wrappers are always skipped))`,
20693
+ integerOption(0)
20694
+ ).option(
20695
+ "--depth <n>",
20696
+ "Levels below the root to list (0 = root only; default: all)",
20697
+ integerOption(0)
20698
+ ).addOption(jsonOption()).action(async (options) => {
20708
20699
  await handleA11yTree(options);
20709
20700
  });
20710
20701
  a11y.command("query").description('Query elements by accessibility properties (e.g., "role:button", "name:Submit")').argument(
@@ -20712,7 +20703,7 @@ function registerA11yCommands(domCmd) {
20712
20703
  "Fields role, name, description as key:value or key=value, separated by spaces or commas; * is a wildcard. A name or description runs to the next field or the end, so it may contain spaces and colons; quote the whole pattern (e.g. 'role=button name=Sign in', 'name=E-mail address:')"
20713
20704
  ).option(
20714
20705
  "--limit <n>",
20715
- `Matches to list (default: ${A11Y_QUERY_LIMIT}, all with --json; 0 = all); all are indexed`,
20706
+ `Matches to list (default: ${A11Y_QUERY_LIMIT}, ${QUERY_JSON_LIST_LIMIT} with --json; 0 = all); all are indexed`,
20716
20707
  integerOption(0)
20717
20708
  ).addOption(jsonOption()).action(async (pattern, options) => {
20718
20709
  await handleA11yQuery(pattern, options);
@@ -20776,10 +20767,12 @@ async function audit(checks, options) {
20776
20767
 
20777
20768
  // src/commands/dom/eval.ts
20778
20769
  init_query();
20770
+ init_constants();
20779
20771
  init_messages();
20780
20772
  init_client();
20781
20773
 
20782
20774
  // src/ui/formatters/dom.ts
20775
+ init_constants();
20783
20776
  init_formatting();
20784
20777
  init_commands();
20785
20778
  function formatDomQuery(data) {
@@ -20808,18 +20801,22 @@ function queryTagAttributes(node) {
20808
20801
  ...node.classes?.length ? [`class="${node.classes.join(" ")}"`] : []
20809
20802
  ];
20810
20803
  }
20811
- function formatDomGet(data) {
20804
+ function formatDomGet(data, options = {}) {
20812
20805
  const { nodes } = data;
20806
+ const html = (node) => capForDisplay(node.outerHTML ?? "", MAX_VALUE_LENGTH, options.full);
20813
20807
  if (nodes.length === 1) {
20814
- return nodes[0].outerHTML ?? "";
20808
+ return html(nodes[0]);
20815
20809
  }
20816
20810
  const fmt = new OutputFormatter();
20817
20811
  nodes.forEach((node, i) => {
20818
- fmt.text(`[${i}] ${node.outerHTML}`);
20812
+ fmt.text(`[${i}] ${html(node)}`);
20819
20813
  });
20820
20814
  return fmt.build();
20821
20815
  }
20822
- function formatDomEval(data) {
20816
+ function formatDomEval(data, options = {}) {
20817
+ return capForDisplay(evalResultText(data), MAX_VALUE_LENGTH, options.full);
20818
+ }
20819
+ function evalResultText(data) {
20823
20820
  if (data.type === "undefined") return "undefined";
20824
20821
  const { result } = data;
20825
20822
  if (typeof result === "string" && (data.type !== "string" || !looksLikeOtherValue(result))) {
@@ -20864,6 +20861,7 @@ function formatDomScreenshot(data) {
20864
20861
  // src/commands/dom/eval.ts
20865
20862
  init_commands();
20866
20863
  init_exitCodes();
20864
+ init_strings();
20867
20865
  async function handleDomEval(script, options) {
20868
20866
  await runCommand(
20869
20867
  async () => {
@@ -20894,7 +20892,7 @@ async function handleDomEval(script, options) {
20894
20892
  return {
20895
20893
  success: true,
20896
20894
  data: {
20897
- result: value,
20895
+ ...jsonResult(value, options),
20898
20896
  type,
20899
20897
  ...subtype && { subtype },
20900
20898
  ...frame !== void 0 && { frame },
@@ -20904,9 +20902,14 @@ async function handleDomEval(script, options) {
20904
20902
  };
20905
20903
  },
20906
20904
  options,
20907
- formatDomEval
20905
+ (data) => formatDomEval(data, { full: options.full })
20908
20906
  );
20909
20907
  }
20908
+ function jsonResult(value, options) {
20909
+ if (!options.json || options.full || typeof value !== "string") return { result: value };
20910
+ const { text, truncatedFrom } = capLength(value, MAX_VALUE_LENGTH);
20911
+ return { result: text, ...truncatedFrom !== void 0 && { truncatedFrom } };
20912
+ }
20910
20913
  async function frameErrorSuggestion(response, frame) {
20911
20914
  if (frame === void 0 || response.exitCode !== EXIT_CODES.RESOURCE_NOT_FOUND) {
20912
20915
  return response.suggestion;
@@ -21224,7 +21227,7 @@ function formatFormDiscovery(result) {
21224
21227
  init_logging();
21225
21228
  init_errors();
21226
21229
  init_exitCodes();
21227
- var log29 = createLogger("dom");
21230
+ var log27 = createLogger("dom");
21228
21231
  function buildValidation(raw) {
21229
21232
  const hasNativeError = !raw.isValid && !raw.valueMissing && raw.validationMessage;
21230
21233
  const hasAriaError = raw.ariaInvalid;
@@ -21381,7 +21384,7 @@ async function cacheFormElements(forms, document2) {
21381
21384
  const elements = forms.flatMap((form) => [...form.fields, ...form.buttons]);
21382
21385
  const backendNodeIds = await resolveBackendNodeIds(elements.map((el) => el.selector)).catch(
21383
21386
  (error) => {
21384
- log29.debug(`Form fields not cached by node: ${getErrorMessage(error)}`);
21387
+ log27.debug(`Form fields not cached by node: ${getErrorMessage(error)}`);
21385
21388
  return [];
21386
21389
  }
21387
21390
  );
@@ -21397,7 +21400,7 @@ async function cacheFormElements(forms, document2) {
21397
21400
  },
21398
21401
  document2
21399
21402
  );
21400
- log29.debug(`Cached ${elements.length} form elements`);
21403
+ log27.debug(`Cached ${elements.length} form elements`);
21401
21404
  }
21402
21405
  async function handleFormCommand(options) {
21403
21406
  await runCommand(
@@ -21504,9 +21507,11 @@ async function withReadyState(frames) {
21504
21507
 
21505
21508
  // src/commands/dom/get.ts
21506
21509
  init_helpers();
21510
+ init_constants();
21507
21511
  init_errors3();
21508
21512
  init_messages();
21509
21513
  init_exitCodes();
21514
+ init_strings();
21510
21515
  var DOM_GET_DEFAULT_SELECTOR = "body";
21511
21516
  async function targetNodeId(selectorOrIndex, index) {
21512
21517
  const resolver = DomElementResolver.getInstance();
@@ -21541,12 +21546,21 @@ async function handleRawGet(selectorOrIndex, options) {
21541
21546
  all: options.all,
21542
21547
  nth: matchIndex(options)
21543
21548
  });
21544
- return { success: true, data: await getDOMElements(getOptions) };
21549
+ return { success: true, data: rawGetData(await getDOMElements(getOptions), options) };
21545
21550
  },
21546
21551
  options,
21547
- formatDomGet
21552
+ (data) => formatDomGet(data, { full: options.full })
21548
21553
  );
21549
21554
  }
21555
+ function rawGetData(result, options) {
21556
+ if (!options.json || options.full) return result;
21557
+ return {
21558
+ nodes: result.nodes.map((node) => {
21559
+ const { text, truncatedFrom } = capLength(node.outerHTML ?? "", MAX_VALUE_LENGTH);
21560
+ return truncatedFrom === void 0 ? node : { ...node, outerHTML: text, truncatedFrom };
21561
+ })
21562
+ };
21563
+ }
21550
21564
  async function handleSemanticGet(selectorOrIndex, options) {
21551
21565
  await runCommand(
21552
21566
  async () => {
@@ -21564,9 +21578,6 @@ function getOptionsConflict(selectorOrIndex, options) {
21564
21578
  if (options.nodeId !== void 0 && selectorOrIndex !== void 0) {
21565
21579
  return conflictingOptionsError("--node-id", "a selector or index");
21566
21580
  }
21567
- if (options.full && (options.raw || options.nodeId !== void 0)) {
21568
- return conflictingOptionsError("--full", options.raw ? "--raw" : "--node-id");
21569
- }
21570
21581
  if (options.index !== void 0 && options.nth !== void 0) {
21571
21582
  return conflictingOptionsError("--index", "--nth");
21572
21583
  }
@@ -21588,9 +21599,9 @@ async function handleDomGet(selectorOrIndex, options) {
21588
21599
  const { nodeId } = options;
21589
21600
  if (nodeId !== void 0) {
21590
21601
  await runCommand(
21591
- async () => ({ success: true, data: await getDOMElements({ nodeId }) }),
21602
+ async () => ({ success: true, data: rawGetData(await getDOMElements({ nodeId }), options) }),
21592
21603
  options,
21593
- formatDomGet
21604
+ (data) => formatDomGet(data, { full: options.full })
21594
21605
  );
21595
21606
  return;
21596
21607
  }
@@ -21876,11 +21887,11 @@ function treeRow(node) {
21876
21887
  node.childCount !== void 0 && `(${node.childCount})`
21877
21888
  ].filter(Boolean).join(" ");
21878
21889
  }
21879
- function treeLines2(nodes, hidden, depth) {
21890
+ function treeLines(nodes, hidden, depth) {
21880
21891
  const indent = " ".repeat(depth);
21881
21892
  const lines = nodes.flatMap((node) => [
21882
21893
  `${indent}${treeRow(node)}`,
21883
- ...treeLines2(node.children ?? [], node.hiddenChildren, depth + 1)
21894
+ ...treeLines(node.children ?? [], node.hiddenChildren, depth + 1)
21884
21895
  ]);
21885
21896
  return hidden ? [...lines, `${indent}(+${hidden} not rendered)`] : lines;
21886
21897
  }
@@ -21956,7 +21967,7 @@ function treeBlock(data) {
21956
21967
  if (!data.children && !data.hiddenChildren) return [];
21957
21968
  return [
21958
21969
  "tree",
21959
- ...treeLines2(data.children ?? [], data.hiddenChildren, 1),
21970
+ ...treeLines(data.children ?? [], data.hiddenChildren, 1),
21960
21971
  ...data.moreRows ? [` \u2026 +${data.moreRows} more`] : []
21961
21972
  ];
21962
21973
  }
@@ -22077,6 +22088,7 @@ async function inspectTarget(selectorOrIndex, options) {
22077
22088
  init_client();
22078
22089
 
22079
22090
  // src/ui/formatters/layout.ts
22091
+ init_constants();
22080
22092
  init_messages();
22081
22093
  init_formatting();
22082
22094
  init_commands();
@@ -22099,7 +22111,7 @@ function formatLayout(data) {
22099
22111
  const more = data.elements.length - shown.length + (data.omitted ?? 0);
22100
22112
  return new OutputFormatter().text(pageLayoutLine(data.page)).text(
22101
22113
  data.indexSource ? indexLayoutHeadline(indexSourceText(data.indexSource)) : layoutHeadline(data.count, data.elements.length + (data.omitted ?? 0), data.selector)
22102
- ).list(shown.map((element) => layoutLine2(element, data.page.viewport))).list(more > 0 ? [moreMatchesNote(more, data.omitted ? data.elements.length : void 0)] : []).build();
22114
+ ).list(shown.map((element) => layoutLine2(element, data.page.viewport))).list(more > 0 ? [moreMatchesNote(more, LAYOUT_ELEMENT_LIMIT)] : []).build();
22103
22115
  }
22104
22116
 
22105
22117
  // src/commands/dom/layout.ts
@@ -22326,10 +22338,11 @@ async function listElementListeners(selectorOrIndex, options) {
22326
22338
  // src/commands/dom/query.ts
22327
22339
  init_helpers();
22328
22340
  init_query();
22341
+ init_constants();
22329
22342
  init_exitCodes();
22330
22343
  var QUERY_LIST_LIMIT = 50;
22331
22344
  async function handleDomQuery(selector, options) {
22332
- const limit = options.limit ?? (options.json ? QUERY_CACHE_LIMIT : QUERY_LIST_LIMIT);
22345
+ const limit = options.limit ?? (options.json ? QUERY_JSON_LIST_LIMIT : QUERY_LIST_LIMIT);
22333
22346
  await runCommand(
22334
22347
  async () => {
22335
22348
  const document2 = await pageDocumentId();
@@ -22373,7 +22386,7 @@ init_logging();
22373
22386
  init_directories();
22374
22387
  init_errors();
22375
22388
  init_exitCodes();
22376
- var log30 = createLogger("dom");
22389
+ var log28 = createLogger("dom");
22377
22390
  var EXTENSION_FORMATS = {
22378
22391
  ".png": "png",
22379
22392
  ".jpg": "jpeg",
@@ -22525,7 +22538,7 @@ async function handleSequenceCapture(outputDir, options) {
22525
22538
  if (options.json) {
22526
22539
  console.log(JSON.stringify(buildSuccessResponse({ frame: frameCount, path: outputPath })));
22527
22540
  } else {
22528
- log30.info(`Frame ${frameCount}: ${filename}`);
22541
+ log28.info(`Frame ${frameCount}: ${filename}`);
22529
22542
  }
22530
22543
  if (limit > 0 && frameCount >= limit) break;
22531
22544
  await delay2(interval);
@@ -22647,6 +22660,8 @@ function formatWait(data) {
22647
22660
  }
22648
22661
 
22649
22662
  // src/commands/dom/index.ts
22663
+ init_constants();
22664
+ var EVAL_FULL_HELP = `Print the whole value (default: the first ${MAX_VALUE_LENGTH} characters; a string result in JSON too)`;
22650
22665
  function registerDomCommands(program2) {
22651
22666
  const dom = program2.command("dom").description("DOM inspection and manipulation").enablePositionalOptions();
22652
22667
  registerA11yCommands(dom);
@@ -22658,7 +22673,7 @@ function registerDomCommands(program2) {
22658
22673
  registerWaitCommand(dom);
22659
22674
  dom.command("query").description("Find elements by CSS selector").argument("<selector>", 'CSS selector (e.g., ".error", "#app", "button")').option(
22660
22675
  "--limit <n>",
22661
- `Matches to list (default: ${QUERY_LIST_LIMIT}, ${QUERY_CACHE_LIMIT} with --json; 0 = all); the first ${QUERY_CACHE_LIMIT} (or more with a higher limit) are indexed`,
22676
+ `Matches to list (default: ${QUERY_LIST_LIMIT}, ${QUERY_JSON_LIST_LIMIT} with --json; 0 = all); the first ${QUERY_CACHE_LIMIT} (or more with a higher limit) are indexed`,
22662
22677
  integerOption(0)
22663
22678
  ).option("-j, --json", "Output as JSON").addHelpText("after", SELECTOR_SCOPE_HELP).action(async (selector, options) => {
22664
22679
  await handleDomQuery(selector, options);
@@ -22666,10 +22681,10 @@ function registerDomCommands(program2) {
22666
22681
  dom.command("eval").description("Evaluate JavaScript expression in the page context").argument("<script>", 'JavaScript to execute (e.g., "document.title", "window.location.href")').option(
22667
22682
  "--frame <frame>",
22668
22683
  "Evaluate in an iframe, cross-origin ones included: index (from dom frames; 87 when stale), name/id attribute, or part of the name, id or URL"
22669
- ).option("-j, --json", "Output as JSON").action(async (script, options) => {
22684
+ ).option("--full", EVAL_FULL_HELP).option("-j, --json", "Output as JSON").action(async (script, options) => {
22670
22685
  await handleDomEval(script, options);
22671
22686
  });
22672
- program2.command("eval", { hidden: true }).description("Shortcut for: bdg dom eval").argument("<script>", "JavaScript to execute").option("--frame <frame>", "Evaluate in an iframe (see dom frames)").option("-j, --json", "Output as JSON").action(async (script, options) => {
22687
+ program2.command("eval", { hidden: true }).description("Shortcut for: bdg dom eval").argument("<script>", "JavaScript to execute").option("--frame <frame>", "Evaluate in an iframe (see dom frames)").option("--full", EVAL_FULL_HELP).option("-j, --json", "Output as JSON").action(async (script, options) => {
22673
22688
  await handleDomEval(script, options);
22674
22689
  });
22675
22690
  dom.command("frames").description(
@@ -22680,7 +22695,10 @@ function registerDomCommands(program2) {
22680
22695
  dom.command("get").description("Get semantic accessibility structure (default) or raw HTML (--raw)").argument(
22681
22696
  "[selectorOrIndex]",
22682
22697
  `${SELECTOR_OR_INDEX_ARGUMENT} (e.g. ".error", "#app", 0); default: ${DOM_GET_DEFAULT_SELECTOR}`
22683
- ).option("--raw", "Output raw HTML with all filtering options").option("--full", "Show all of the element text (default: the first 500 characters)").option("--all", "Get all matches (only with --raw)").option("--index <n>", "Element index if selector matches multiple (0-based)", integerOption(0)).addOption(new Option("--nth <n>", "Alias of --index").argParser(integerOption(0)).hideHelp()).option(
22698
+ ).option("--raw", "Output raw HTML with all filtering options").option(
22699
+ "--full",
22700
+ `Show all of the element text (default: the first 500 characters); with --raw, all of the HTML (default: the first ${MAX_VALUE_LENGTH} characters)`
22701
+ ).option("--all", "Get all matches (only with --raw)").option("--index <n>", "Element index if selector matches multiple (0-based)", integerOption(0)).addOption(new Option("--nth <n>", "Alias of --index").argParser(integerOption(0)).hideHelp()).option(
22684
22702
  "--node-id <id>",
22685
22703
  "Get the element with this node id (from dom query/get --raw or a11y describe; implies --raw)",
22686
22704
  integerOption(1)
@@ -22747,7 +22765,7 @@ function formatInstalledSkills(data) {
22747
22765
  init_logging();
22748
22766
  init_errors();
22749
22767
  init_exitCodes();
22750
- var log31 = createLogger("bdg");
22768
+ var log29 = createLogger("bdg");
22751
22769
  var SKILL_SOURCE_PATH = join7(PACKAGE_ROOT, ".claude", "skills", "bdg", "SKILL.md");
22752
22770
  var SKILL_ROOTS = {
22753
22771
  claude: join7(".claude", "skills"),
@@ -22809,7 +22827,7 @@ function writeSkill(target, path7, content) {
22809
22827
  writing = path7;
22810
22828
  renameSync2(temporary, path7);
22811
22829
  } catch (error) {
22812
- safeRemoveFile(temporary, "temporary skill copy", log31);
22830
+ safeRemoveFile(temporary, "temporary skill copy", log29);
22813
22831
  return { target, path: writing, error };
22814
22832
  }
22815
22833
  if (backup === void 0) return { target, path: path7, status: "installed" };
@@ -22851,10 +22869,120 @@ init_paths();
22851
22869
 
22852
22870
  // src/telemetry/filterDsl.ts
22853
22871
  init_constants();
22872
+
22873
+ // src/telemetry/filters.ts
22874
+ init_url();
22875
+ var DEFAULT_EXCLUDED_DOMAINS = [
22876
+ "analytics.google.com",
22877
+ "googletagmanager.com",
22878
+ "googleadservices.com",
22879
+ "doubleclick.net",
22880
+ "google-analytics.com",
22881
+ "clarity.ms",
22882
+ "bat.bing.com",
22883
+ "facebook.com",
22884
+ "connect.facebook.net",
22885
+ "tiktok.com",
22886
+ "linkedin.com",
22887
+ "twitter.com",
22888
+ "snapchat.com",
22889
+ "mixpanel.com",
22890
+ "segment.com",
22891
+ "segment.io",
22892
+ "amplitude.com",
22893
+ "heap.io",
22894
+ "fullstory.com",
22895
+ "hotjar.com",
22896
+ "logrocket.com",
22897
+ "smartlook.com",
22898
+ "exactag.com",
22899
+ "criteo.com",
22900
+ "adroll.com",
22901
+ "outbrain.com",
22902
+ "taboola.com",
22903
+ "confirmit.com",
22904
+ "newrelic.com",
22905
+ "datadoghq.com",
22906
+ "sentry.io",
22907
+ "googlesyndication.com",
22908
+ "googletagservices.com",
22909
+ "adservice.google.com",
22910
+ "amazon-adsystem.com",
22911
+ "adnxs.com",
22912
+ "rubiconproject.com",
22913
+ "pubmatic.com",
22914
+ "casalemedia.com",
22915
+ "indexww.com",
22916
+ "openx.net",
22917
+ "3lift.com",
22918
+ "teads.tv",
22919
+ "bidswitch.net",
22920
+ "sharethrough.com",
22921
+ "adsafeprotected.com",
22922
+ "moatads.com",
22923
+ "doubleverify.com",
22924
+ "scorecardresearch.com",
22925
+ "imrworldwide.com",
22926
+ "chartbeat.com",
22927
+ "chartbeat.net",
22928
+ "permutive.com",
22929
+ "permutive.app",
22930
+ "optimizely.com",
22931
+ "quantserve.com",
22932
+ "quantcount.com",
22933
+ "krxd.net",
22934
+ "demdex.net",
22935
+ "omtrdc.net",
22936
+ "everesttech.net",
22937
+ "xiti.com",
22938
+ "ati-host.net"
22939
+ ];
22940
+ var EXCLUDED_DOMAINS_SET = new Set(DEFAULT_EXCLUDED_DOMAINS.map((d) => d.toLowerCase()));
22941
+ var DEFAULT_SKIP_BODY_MIME_TYPES = [
22942
+ "text/css",
22943
+ "image/svg+xml",
22944
+ "image/png",
22945
+ "image/jpeg",
22946
+ "image/gif",
22947
+ "image/webp",
22948
+ "image/avif",
22949
+ "image/bmp",
22950
+ "image/tiff",
22951
+ "font/woff",
22952
+ "font/woff2",
22953
+ "font/ttf",
22954
+ "font/eot",
22955
+ "font/otf",
22956
+ "application/font-woff",
22957
+ "application/font-woff2",
22958
+ "video/mp4",
22959
+ "video/webm",
22960
+ "audio/mpeg",
22961
+ "audio/wav"
22962
+ ];
22963
+ var SKIP_BODY_MIME_TYPES_SET = new Set(DEFAULT_SKIP_BODY_MIME_TYPES.map((m) => m.toLowerCase()));
22964
+ function matchesWildcard(str, pattern) {
22965
+ const regexPattern = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
22966
+ const regex = new RegExp(`^${regexPattern}$`, "i");
22967
+ return regex.test(str);
22968
+ }
22969
+ function filterByResourceType(requests, types) {
22970
+ if (types.length === 0) {
22971
+ return requests;
22972
+ }
22973
+ return requests.filter((req) => {
22974
+ if (!req.resourceType) {
22975
+ return false;
22976
+ }
22977
+ return types.includes(req.resourceType);
22978
+ });
22979
+ }
22980
+
22981
+ // src/telemetry/filterDsl.ts
22854
22982
  init_logging();
22855
22983
  init_suggestions();
22856
22984
  init_url();
22857
- var log32 = createLogger("network");
22985
+ var log30 = createLogger("network");
22858
22986
  var SIZE_UNITS = {
22859
22987
  b: 1,
22860
22988
  kb: 1024,
@@ -22964,7 +23092,7 @@ function validateSizeValue(value) {
22964
23092
  parseSize(value);
22965
23093
  return null;
22966
23094
  } catch (error) {
22967
- log32.debug(
23095
+ log30.debug(
22968
23096
  `Size parse failed for "${value}": ${error instanceof Error ? error.message : String(error)}`
22969
23097
  );
22970
23098
  return createError(
@@ -23155,7 +23283,7 @@ var UNKNOWN_TIMING = -1;
23155
23283
  var DEFAULT_HTTP_VERSION = "HTTP/1.1";
23156
23284
  function buildHAR(requests, metadata) {
23157
23285
  const entries = [...requests].sort((a, b) => a.timestamp - b.timestamp).map(buildEntry);
23158
- const log36 = {
23286
+ const log34 = {
23159
23287
  version: "1.2",
23160
23288
  creator: {
23161
23289
  name: "bdg",
@@ -23165,12 +23293,12 @@ function buildHAR(requests, metadata) {
23165
23293
  entries
23166
23294
  };
23167
23295
  if (metadata.chromeVersion) {
23168
- log36.browser = {
23296
+ log34.browser = {
23169
23297
  name: "Chrome",
23170
23298
  version: metadata.chromeVersion
23171
23299
  };
23172
23300
  }
23173
- return { log: log36 };
23301
+ return { log: log34 };
23174
23302
  }
23175
23303
  function buildEntry(req) {
23176
23304
  const timings = buildTimings(req);
@@ -23505,6 +23633,11 @@ function formatSessionStatus(metadata, pid, activity, pageState, verbose = false
23505
23633
  if (activity.lastNetworkRequestAt) {
23506
23634
  fmt.keyValue(" Last Request", formatTimeAgo(activity.lastNetworkRequestAt), 18);
23507
23635
  }
23636
+ const evictedNote = networkEvictedNote({
23637
+ requestsDropped: activity.networkRequestsDropped ?? 0,
23638
+ bodiesEvicted: activity.networkBodiesEvicted ?? 0
23639
+ });
23640
+ if (evictedNote) fmt.text(` ${evictedNote}`);
23508
23641
  fmt.keyValue("Console Messages", `${activity.consoleMessagesCaptured} captured`, 18);
23509
23642
  if (activity.lastConsoleMessageAt) {
23510
23643
  fmt.keyValue(" Last Message", formatTimeAgo(activity.lastConsoleMessageAt), 18);
@@ -23614,6 +23747,7 @@ init_constants();
23614
23747
  init_formatting();
23615
23748
  init_commands();
23616
23749
  init_sessionCommand();
23750
+ init_strings();
23617
23751
  function inferResourceTypeFromMime(mimeType) {
23618
23752
  if (!mimeType) return void 0;
23619
23753
  return MIME_TYPE_RULES.find((rule) => rule.match.test(mimeType))?.type;
@@ -23645,17 +23779,25 @@ function buildPreviewJsonData(output, options) {
23645
23779
  ...output.totals && { totals: output.totals },
23646
23780
  ...output.pageCrashedAt !== void 0 && { pageCrashedAt: output.pageCrashedAt },
23647
23781
  ...pick("network") && output.data.network && { network: last(output.data.network) },
23648
- ...pick("console") && output.data.console && { console: last(output.data.console) }
23782
+ ...pick("console") && output.data.console && {
23783
+ console: last(output.data.console)?.map((message) => capMessageText(message, options.full))
23784
+ }
23649
23785
  };
23650
23786
  }
23651
23787
  function formatPreviewAsJson(output, options) {
23652
23788
  const envelope = buildSuccessResponse(buildPreviewJsonData(output, options));
23653
- return options.follow ? JSON.stringify(envelope) : JSON.stringify(envelope, null, 2);
23789
+ return options.follow ? JSON.stringify(envelope) : stringifyEnvelope(envelope);
23654
23790
  }
23655
23791
  function formatPreviewHumanReadable(output, options) {
23656
23792
  const body = options.verbose ? formatPreviewVerbose(output, options) : formatPreviewCompact(output, options);
23657
23793
  return withPageCrashedNote(body, output.pageCrashedAt);
23658
23794
  }
23795
+ function compactConsoleText(text, full) {
23796
+ if (full) return text;
23797
+ const capped = capLength(text, MAX_CONSOLE_TEXT_LENGTH);
23798
+ const shown = truncateText(capped.text, 2);
23799
+ return capped.truncatedFrom === void 0 ? shown : `${shown}${moreCharsNote(capped.truncatedFrom - capped.text.length)}`;
23800
+ }
23659
23801
  function formatPreviewCompact(output, options) {
23660
23802
  const fmt = new OutputFormatter();
23661
23803
  fmt.text(
@@ -23675,6 +23817,8 @@ function formatPreviewCompact(output, options) {
23675
23817
  const totalCount = output.totals?.network ?? output.data.network.length;
23676
23818
  const limitHint = formatLimitHint(showingCount, totalCount);
23677
23819
  fmt.text(`NETWORK (${showingCount}/${totalCount})${limitHint}:`);
23820
+ const evictedNote = previewEvictedNote(output);
23821
+ if (evictedNote) fmt.text(` ${evictedNote}`);
23678
23822
  if (requests.length === 0) {
23679
23823
  if (options.filteredTypes && options.filteredTypes.length > 0 && options.unfilteredNetworkCount && options.unfilteredNetworkCount > 0) {
23680
23824
  const typesStr = options.filteredTypes.join(", ");
@@ -23711,8 +23855,7 @@ function formatPreviewCompact(output, options) {
23711
23855
  } else {
23712
23856
  const consoleLines = messages.map((msg) => {
23713
23857
  const prefix = msg.type.toUpperCase().padEnd(5);
23714
- const text = truncateText(msg.text, 2);
23715
- return `${prefix} ${text}`;
23858
+ return `${prefix} ${compactConsoleText(msg.text, options.full)}`;
23716
23859
  });
23717
23860
  fmt.list(consoleLines, 2);
23718
23861
  }
@@ -23724,6 +23867,12 @@ function formatPreviewCompact(output, options) {
23724
23867
  }
23725
23868
  return fmt.build();
23726
23869
  }
23870
+ function previewEvictedNote(output) {
23871
+ return networkEvictedNote({
23872
+ requestsDropped: output.totals?.networkDropped ?? 0,
23873
+ bodiesEvicted: output.totals?.networkBodiesEvicted ?? 0
23874
+ });
23875
+ }
23727
23876
  function formatPreviewVerbose(output, options) {
23728
23877
  const fmt = new OutputFormatter();
23729
23878
  fmt.text(PREVIEW_HEADERS.LIVE_PREVIEW).separator("\u2501", 50);
@@ -23747,6 +23896,8 @@ function formatPreviewVerbose(output, options) {
23747
23896
  const requests = lastCount === 0 ? output.data.network : output.data.network.slice(-lastCount);
23748
23897
  const title = lastCount === 0 ? `Network Requests (all ${requests.length})` : `Network Requests (last ${requests.length} of ${output.totals?.network ?? output.data.network.length})`;
23749
23898
  fmt.text(title).separator("\u2501", 50);
23899
+ const evictedNote = previewEvictedNote(output);
23900
+ if (evictedNote) fmt.text(evictedNote);
23750
23901
  if (requests.length === 0) {
23751
23902
  if (options.filteredTypes && options.filteredTypes.length > 0 && options.unfilteredNetworkCount && options.unfilteredNetworkCount > 0) {
23752
23903
  const typesStr = options.filteredTypes.join(", ");
@@ -23791,7 +23942,9 @@ function formatPreviewVerbose(output, options) {
23791
23942
  } else {
23792
23943
  messages.forEach((msg) => {
23793
23944
  const icon = msg.type === "error" ? "ERR" : msg.type === "warning" ? "WARN" : "INFO";
23794
- fmt.text(`${icon} [${msg.type}] ${msg.text}`);
23945
+ fmt.text(
23946
+ `${icon} [${msg.type}] ${capForDisplay(msg.text, MAX_CONSOLE_TEXT_LENGTH, options.full)}`
23947
+ );
23795
23948
  });
23796
23949
  }
23797
23950
  fmt.blank();
@@ -23920,7 +24073,7 @@ function registerDocumentCommand(networkCmd) {
23920
24073
  }
23921
24074
 
23922
24075
  // src/commands/network/har.ts
23923
- var log33 = createLogger("network");
24076
+ var log31 = createLogger("network");
23924
24077
  function generateHARFilename() {
23925
24078
  const now = /* @__PURE__ */ new Date();
23926
24079
  const year = now.getFullYear();
@@ -23943,7 +24096,7 @@ async function getChromeVersion() {
23943
24096
  const product = response.data?.result?.product;
23944
24097
  return product?.split("/")[1];
23945
24098
  } catch (error) {
23946
- log33.debug(`Could not read Chrome version: ${getErrorMessage(error)}`);
24099
+ log31.debug(`Could not read Chrome version: ${getErrorMessage(error)}`);
23947
24100
  return void 0;
23948
24101
  }
23949
24102
  }
@@ -24153,6 +24306,8 @@ function formatNetworkListHuman(requests, options) {
24153
24306
  const header = buildHeader(requests.length, options.filteredCount ?? totalCount, totalCount);
24154
24307
  fmt.text(header);
24155
24308
  fmt.separator("\u2500", SEPARATOR_WIDTH2);
24309
+ const evictedNote = options.evictions && networkEvictedNote(options.evictions);
24310
+ if (evictedNote) fmt.text(evictedNote);
24156
24311
  if (requests.length === 0) {
24157
24312
  fmt.text("No matching requests found.");
24158
24313
  return fmt.build();
@@ -24169,6 +24324,8 @@ var FOLLOW_ID_WIDTH = 14;
24169
24324
  function formatNetworkFollowRows(requests, options = {}) {
24170
24325
  const fmt = new OutputFormatter();
24171
24326
  const widths = columnWidths(requests, FOLLOW_ID_WIDTH);
24327
+ const evictedNote = options.evictions && networkEvictedNote(options.evictions);
24328
+ if (evictedNote) fmt.text(evictedNote);
24172
24329
  if (options.header) {
24173
24330
  fmt.text(formatColumnHeader(widths));
24174
24331
  fmt.separator("\u2500", SEPARATOR_WIDTH2);
@@ -24236,12 +24393,35 @@ function buildFormatOptions2(options, result, lastLimit) {
24236
24393
  last: lastLimit,
24237
24394
  totalCount: result.totalCount,
24238
24395
  filteredCount: result.filteredCount,
24239
- ...result.pageStart && { pageStart: result.pageStart }
24396
+ ...result.pageStart && { pageStart: result.pageStart },
24397
+ evictions: {
24398
+ requestsDropped: result.dropped ?? 0,
24399
+ bodiesEvicted: result.bodiesEvicted ?? 0
24400
+ }
24401
+ };
24402
+ }
24403
+ function newEvictionKinds() {
24404
+ let requestsNoted = false;
24405
+ let bodiesNoted = false;
24406
+ return (counts) => {
24407
+ const newRequests = !requestsNoted && counts.requestsDropped > 0;
24408
+ const newBodies = !bodiesNoted && counts.bodiesEvicted > 0;
24409
+ requestsNoted ||= newRequests;
24410
+ bodiesNoted ||= newBodies;
24411
+ return newRequests || newBodies ? counts : void 0;
24412
+ };
24413
+ }
24414
+ function evictionFields(counts) {
24415
+ if (!counts) return {};
24416
+ return {
24417
+ ...counts.requestsDropped > 0 && { dropped: counts.requestsDropped },
24418
+ ...counts.bodiesEvicted > 0 && { bodiesEvicted: counts.bodiesEvicted }
24240
24419
  };
24241
24420
  }
24242
24421
  async function runFollowMode2(options, resourceTypes, lastN) {
24243
24422
  const shown = /* @__PURE__ */ new Set();
24244
24423
  const newCrash = newPageCrashes();
24424
+ const newEviction = newEvictionKinds();
24245
24425
  let started = false;
24246
24426
  const showNetwork = async () => {
24247
24427
  const result = await fetchNetworkRequests(filtersNeedHeaders(options));
@@ -24251,6 +24431,7 @@ async function runFollowMode2(options, resourceTypes, lastN) {
24251
24431
  noteFollowConnected();
24252
24432
  const { requests } = result.data;
24253
24433
  const crashedAt = newCrash(result.data.pageCrashedAt);
24434
+ const evictions = newEviction(result.data.evictions);
24254
24435
  const finished = filterRequests(requests, options, resourceTypes).filter(
24255
24436
  (request) => request.duration !== void 0 && !shown.has(request.requestId)
24256
24437
  );
@@ -24259,12 +24440,13 @@ async function runFollowMode2(options, resourceTypes, lastN) {
24259
24440
  finished.forEach((request) => shown.add(request.requestId));
24260
24441
  const fresh = started || lastN === 0 ? finished : finished.slice(-lastN);
24261
24442
  if (options.json) {
24262
- if (!started || fresh.length > 0 || crashedAt !== void 0) {
24443
+ if (!started || fresh.length > 0 || crashedAt !== void 0 || evictions) {
24263
24444
  const data = {
24264
24445
  requests: fresh,
24265
24446
  totalCount: requests.length,
24266
24447
  filteredCount: fresh.length,
24267
- ...crashedAt !== void 0 && { pageCrashedAt: crashedAt }
24448
+ ...crashedAt !== void 0 && { pageCrashedAt: crashedAt },
24449
+ ...evictionFields(evictions)
24268
24450
  };
24269
24451
  console.log(JSON.stringify(buildSuccessResponse(data)));
24270
24452
  }
@@ -24273,7 +24455,8 @@ async function runFollowMode2(options, resourceTypes, lastN) {
24273
24455
  const text = formatNetworkFollowRows(fresh, {
24274
24456
  header: !started,
24275
24457
  verbose: options.verbose ?? false,
24276
- ...pageStart && { pageStart }
24458
+ ...pageStart && { pageStart },
24459
+ ...evictions && { evictions }
24277
24460
  });
24278
24461
  if (text) console.log(text);
24279
24462
  if (crashedAt !== void 0) console.log(pageCrashedNote(crashedAt));
@@ -24349,7 +24532,7 @@ ${formatPresetHelp()}`
24349
24532
  }
24350
24533
  return createErrorResult(result.error, result.exitCode, result.suggestion);
24351
24534
  }
24352
- const { requests, pageCrashedAt } = result.data;
24535
+ const { requests, pageCrashedAt, evictions } = result.data;
24353
24536
  const filtered = filterRequests(requests, options, resourceTypes);
24354
24537
  const pageStart = pageStartOf(requests);
24355
24538
  return {
@@ -24359,7 +24542,8 @@ ${formatPresetHelp()}`
24359
24542
  totalCount: requests.length,
24360
24543
  filteredCount: filtered.length,
24361
24544
  ...pageStart && { pageStart },
24362
- ...pageCrashedAt !== void 0 && { pageCrashedAt }
24545
+ ...pageCrashedAt !== void 0 && { pageCrashedAt },
24546
+ ...evictionFields(evictions)
24363
24547
  }
24364
24548
  };
24365
24549
  },
@@ -24548,6 +24732,7 @@ function registerPageCommands(program2) {
24548
24732
  }
24549
24733
 
24550
24734
  // src/commands/peek.ts
24735
+ init_constants();
24551
24736
  init_errors3();
24552
24737
  init_messages();
24553
24738
  init_exitCodes();
@@ -24645,7 +24830,8 @@ function previewDisplayOptions(options, lastN) {
24645
24830
  console: options.console,
24646
24831
  last: lastN,
24647
24832
  verbose: options.verbose,
24648
- follow: options.follow
24833
+ follow: options.follow,
24834
+ full: options.full
24649
24835
  };
24650
24836
  }
24651
24837
  async function followPreview(options) {
@@ -24658,6 +24844,10 @@ function registerPeekCommand(program2) {
24658
24844
  program2.command("peek").description("Preview collected data without stopping the session").addOption(jsonOption()).option("-v, --verbose", "Use verbose output with full URLs and formatting", false).option("-n, --network", "Show only network requests", false).option("-c, --console", "Show only console messages", false).option("-f, --follow", "Watch for updates (like tail -f)", false).option("--interval <ms>", "Refresh interval of --follow in ms, 100-60000 (default: 1000)").option("--last <count>", "Show last N items, 0 for all", "10").option(
24659
24845
  "--type <types>",
24660
24846
  "Filter network requests by resource type (comma-separated: Document,XHR,Fetch,etc.)"
24847
+ ).option(
24848
+ "--full",
24849
+ `Print console message texts whole (default: the first ${MAX_CONSOLE_TEXT_LENGTH} characters, ${MAX_CONSOLE_JSON_TEXT_LENGTH} in JSON)`,
24850
+ false
24661
24851
  ).action(async (options) => {
24662
24852
  showBothSectionsWhenBothRequested(options);
24663
24853
  if (options.network && !options.json) {
@@ -24708,13 +24898,13 @@ import * as fs17 from "fs";
24708
24898
  init_paths();
24709
24899
  init_logging();
24710
24900
  init_directories();
24711
- var log34 = createLogger("session");
24901
+ var log32 = createLogger("session");
24712
24902
  function readPortFile(portPath) {
24713
24903
  try {
24714
24904
  const port = parseInt(fs17.readFileSync(portPath, "utf-8").trim(), 10);
24715
24905
  return Number.isInteger(port) && port >= 1 && port <= 65535 ? port : null;
24716
24906
  } catch (error) {
24717
- logDebugError(log34, `read ${portPath}`, error);
24907
+ logDebugError(log32, `read ${portPath}`, error);
24718
24908
  return null;
24719
24909
  }
24720
24910
  }
@@ -24766,7 +24956,7 @@ function selectSession(optionValue) {
24766
24956
  // src/session/sessionList.ts
24767
24957
  init_logging();
24768
24958
  init_sessionCommand();
24769
- var log35 = createLogger("session");
24959
+ var log33 = createLogger("session");
24770
24960
  function toRunningSession(name, data) {
24771
24961
  const meta = data.sessionMetadata;
24772
24962
  const state = meta ? "active" : data.ending ? "ending" : "starting";
@@ -24789,7 +24979,7 @@ async function describeSession(entry) {
24789
24979
  const response = await getStatus(socketPath);
24790
24980
  if (response.status === "ok" && response.data) return toRunningSession(name, response.data);
24791
24981
  } catch (error) {
24792
- logDebugError(log35, `get status of ${dir}`, error);
24982
+ logDebugError(log33, `get status of ${dir}`, error);
24793
24983
  }
24794
24984
  return { name, state: "unresponsive" };
24795
24985
  }
@@ -24828,7 +25018,7 @@ function leftoverPort(dir) {
24828
25018
  const meta = JSON.parse(fs18.readFileSync(sessionFilePathIn(dir, "METADATA"), "utf8"));
24829
25019
  if (typeof meta.port === "number") return meta.port;
24830
25020
  } catch (error) {
24831
- logDebugError(log35, `read the metadata in ${dir}`, error);
25021
+ logDebugError(log33, `read the metadata in ${dir}`, error);
24832
25022
  }
24833
25023
  return readPortFile(sessionFilePathIn(dir, "PORT"));
24834
25024
  }
@@ -24841,7 +25031,7 @@ function isSameDir(a, b) {
24841
25031
  const second = fs18.statSync(b);
24842
25032
  return first.ino === second.ino && first.dev === second.dev;
24843
25033
  } catch (error) {
24844
- logDebugError(log35, `compare ${a} with ${b}`, error);
25034
+ logDebugError(log33, `compare ${a} with ${b}`, error);
24845
25035
  return false;
24846
25036
  }
24847
25037
  }
@@ -25206,18 +25396,38 @@ var commandRegistry = [
25206
25396
  registerInstallSkillCommand
25207
25397
  ];
25208
25398
 
25399
+ // src/program.ts
25400
+ var CLI_NAME = "bdg";
25401
+ var CLI_DESCRIPTION = "Browser telemetry via Chrome DevTools Protocol";
25402
+ var SESSION_OPTION_FLAGS = "--session <name>";
25403
+ var SESSION_OPTION_DESCRIPTION = "Use a named session (own daemon, Chrome and port) instead of the default one; env: BDG_SESSION";
25404
+ function addGlobalOptions(command) {
25405
+ for (const sub of command.commands) {
25406
+ if (!sub.options.some((option) => option.long === "--debug")) {
25407
+ sub.addOption(new Option("--debug", "Enable debug logging").hideHelp());
25408
+ }
25409
+ if (!sub.options.some((option) => option.long === "--quiet")) {
25410
+ sub.addOption(new Option("-q, --quiet", "Hide tips and hints").hideHelp());
25411
+ }
25412
+ if (!sub.options.some((option) => option.long === "--session")) {
25413
+ sub.addOption(new Option(SESSION_OPTION_FLAGS, SESSION_OPTION_DESCRIPTION).hideHelp());
25414
+ }
25415
+ addGlobalOptions(sub);
25416
+ }
25417
+ }
25418
+ function buildProgram(output = {}) {
25419
+ const program2 = new Command().name(CLI_NAME).description(CLI_DESCRIPTION).version(VERSION).option("--debug", "Enable debug logging (verbose output)").option(SESSION_OPTION_FLAGS, SESSION_OPTION_DESCRIPTION).enablePositionalOptions().exitOverride().configureOutput(output);
25420
+ commandRegistry.forEach((register) => register(program2));
25421
+ addGlobalOptions(program2);
25422
+ return program2;
25423
+ }
25424
+
25209
25425
  // src/index.ts
25210
- init_errors3();
25211
- init_messages();
25212
25426
  init_formatting();
25213
25427
  init_logging();
25214
25428
  init_errors();
25215
25429
  init_exitCodes();
25216
- var CLI_NAME = "bdg";
25217
- var CLI_DESCRIPTION = "Browser telemetry via Chrome DevTools Protocol";
25218
- var SESSION_OPTION_FLAGS = "--session <name>";
25219
25430
  var FULL_HELP_FLAG = "--full";
25220
- var SESSION_OPTION_DESCRIPTION = "Use a named session (own daemon, Chrome and port) instead of the default one; env: BDG_SESSION";
25221
25431
  function flagArgs() {
25222
25432
  const args = process.argv.slice(2);
25223
25433
  const end = args.indexOf("--");
@@ -25258,14 +25468,12 @@ async function main() {
25258
25468
  configureStdio();
25259
25469
  const helpTopic = rewriteHelpCommand();
25260
25470
  const jsonMode = isJsonMode();
25261
- const program2 = new Command().name(CLI_NAME).description(CLI_DESCRIPTION).version(VERSION).option("--debug", "Enable debug logging (verbose output)").option(SESSION_OPTION_FLAGS, SESSION_OPTION_DESCRIPTION).enablePositionalOptions().exitOverride().configureOutput({
25471
+ const program2 = buildProgram({
25262
25472
  writeOut: (text) => {
25263
25473
  if (!jsonMode) process.stdout.write(text);
25264
25474
  },
25265
25475
  outputError: () => void 0
25266
25476
  });
25267
- commandRegistry.forEach((register) => register(program2));
25268
- addGlobalOptions(program2);
25269
25477
  program2.hook("preAction", (_root, actionCommand) => applyGlobalOptions(program2, actionCommand));
25270
25478
  assertKnownHelpTopic(program2, helpTopic);
25271
25479
  assertNotMistypedCommand(program2, process.argv);
@@ -25288,20 +25496,6 @@ function helpJson(program2) {
25288
25496
  if (command !== program2) return generateCommandHelp(program2, command);
25289
25497
  return flagArgs().includes(FULL_HELP_FLAG) ? generateMachineReadableHelp(program2) : generateCompactHelp(program2);
25290
25498
  }
25291
- function addGlobalOptions(command) {
25292
- for (const sub of command.commands) {
25293
- if (!sub.options.some((option) => option.long === "--debug")) {
25294
- sub.addOption(new Option("--debug", "Enable debug logging").hideHelp());
25295
- }
25296
- if (!sub.options.some((option) => option.long === "--quiet")) {
25297
- sub.addOption(new Option("-q, --quiet", "Hide tips and hints").hideHelp());
25298
- }
25299
- if (!sub.options.some((option) => option.long === "--session")) {
25300
- sub.addOption(new Option(SESSION_OPTION_FLAGS, SESSION_OPTION_DESCRIPTION).hideHelp());
25301
- }
25302
- addGlobalOptions(sub);
25303
- }
25304
- }
25305
25499
  function sessionFromArgv(argv) {
25306
25500
  let value;
25307
25501
  argv.forEach((arg, i) => {
@@ -25329,7 +25523,7 @@ function applyGlobalOptions(program2, actionCommand) {
25329
25523
  }
25330
25524
  function handleUsageError(error, command, jsonMode) {
25331
25525
  if (error.code === "commander.version") {
25332
- if (jsonMode) console.log(JSON.stringify(buildSuccessResponse({ version: VERSION }), null, 2));
25526
+ if (jsonMode) console.log(stringifyEnvelope(buildSuccessResponse({ version: VERSION })));
25333
25527
  process.exit(EXIT_CODES.SUCCESS);
25334
25528
  }
25335
25529
  if (error.code === "commander.helpDisplayed" || error.code === "commander.help" && error.exitCode === 0) {
@@ -25338,9 +25532,7 @@ function handleUsageError(error, command, jsonMode) {
25338
25532
  const exitCode = EXIT_CODES.INVALID_ARGUMENTS;
25339
25533
  const { message, suggestion } = usageErrorDetails(error, command);
25340
25534
  if (jsonMode) {
25341
- console.log(
25342
- JSON.stringify(OutputBuilder.buildJsonError(message, { exitCode, suggestion }), null, 2)
25343
- );
25535
+ console.log(stringifyEnvelope(OutputBuilder.buildJsonError(message, { exitCode, suggestion })));
25344
25536
  } else if (error.code !== "commander.help") {
25345
25537
  console.error(genericError(message, suggestion));
25346
25538
  }
@@ -25352,7 +25544,7 @@ function handleFatalError(error) {
25352
25544
  const metadata = error instanceof CommandError ? error.metadata : {};
25353
25545
  if (isJsonMode()) {
25354
25546
  console.log(
25355
- JSON.stringify(OutputBuilder.buildJsonError(message, { ...metadata, exitCode }), null, 2)
25547
+ stringifyEnvelope(OutputBuilder.buildJsonError(message, { ...metadata, exitCode }))
25356
25548
  );
25357
25549
  } else {
25358
25550
  console.error(genericError(message));