browser-debugger-cli 0.12.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 (224) hide show
  1. package/.claude/skills/bdg/SKILL.md +100 -186
  2. package/README.md +5 -4
  3. package/dist/commands/cdp.d.ts +22 -1
  4. package/dist/commands/cdp.js +100 -43
  5. package/dist/commands/console.d.ts +12 -0
  6. package/dist/commands/console.js +67 -13
  7. package/dist/commands/dom/DomElementResolver.d.ts +3 -1
  8. package/dist/commands/dom/DomElementResolver.js +10 -3
  9. package/dist/commands/dom/a11y.d.ts +1 -1
  10. package/dist/commands/dom/a11y.js +23 -22
  11. package/dist/commands/dom/eval.d.ts +4 -2
  12. package/dist/commands/dom/eval.js +31 -7
  13. package/dist/commands/dom/form.js +10 -9
  14. package/dist/commands/dom/formInteraction.js +9 -8
  15. package/dist/commands/dom/get.js +32 -14
  16. package/dist/commands/dom/helpers/index.d.ts +1 -1
  17. package/dist/commands/dom/helpers/index.js +1 -1
  18. package/dist/commands/dom/helpers/query.d.ts +27 -3
  19. package/dist/commands/dom/helpers/query.js +152 -64
  20. package/dist/commands/dom/helpers/screenshot.js +13 -13
  21. package/dist/commands/dom/index.js +10 -3
  22. package/dist/commands/dom/query.d.ts +20 -2
  23. package/dist/commands/dom/query.js +39 -6
  24. package/dist/commands/dom/screenshot.js +3 -1
  25. package/dist/commands/dom/semanticUtils.d.ts +3 -2
  26. package/dist/commands/dom/semanticUtils.js +40 -9
  27. package/dist/commands/helpJson.d.ts +82 -19
  28. package/dist/commands/helpJson.js +112 -41
  29. package/dist/commands/helpTopic.d.ts +16 -1
  30. package/dist/commands/helpTopic.js +59 -1
  31. package/dist/commands/installSkill.d.ts +15 -5
  32. package/dist/commands/installSkill.js +86 -16
  33. package/dist/commands/network/list.js +65 -12
  34. package/dist/commands/optionBehaviors.d.ts +25 -2
  35. package/dist/commands/optionBehaviors.js +81 -46
  36. package/dist/commands/peek.js +3 -0
  37. package/dist/commands/shared/CommandRunner.js +13 -13
  38. package/dist/commands/shared/daemonErrorHandler.d.ts +5 -2
  39. package/dist/commands/shared/daemonErrorHandler.js +21 -10
  40. package/dist/commands/shared/dataFetcher.d.ts +14 -4
  41. package/dist/commands/shared/dataFetcher.js +20 -4
  42. package/dist/commands/shared/followMode.d.ts +9 -1
  43. package/dist/commands/shared/followMode.js +22 -4
  44. package/dist/commands/shared/handleValidationError.js +3 -3
  45. package/dist/commands/shared/optionTypes.d.ts +17 -3
  46. package/dist/commands/shared/outputFile.js +6 -1
  47. package/dist/commands/shared/startHelpers.js +3 -3
  48. package/dist/commands/start.d.ts +7 -5
  49. package/dist/commands/start.js +65 -21
  50. package/dist/commands/stop.d.ts +11 -0
  51. package/dist/commands/stop.js +24 -1
  52. package/dist/commands.js +1 -1
  53. package/dist/connection/cdp.d.ts +7 -0
  54. package/dist/connection/cdp.js +9 -0
  55. package/dist/connection/chromeIdentity.d.ts +8 -2
  56. package/dist/connection/chromeIdentity.js +85 -13
  57. package/dist/connection/launcher.js +3 -2
  58. package/dist/constants.d.ts +29 -1
  59. package/dist/constants.js +35 -1
  60. package/dist/daemon/SessionController.js +8 -1
  61. package/dist/daemon/launcher.d.ts +3 -2
  62. package/dist/daemon/launcher.js +47 -3
  63. package/dist/daemon/session/Session.d.ts +5 -1
  64. package/dist/daemon/session/Session.js +42 -3
  65. package/dist/daemon/session/TelemetryStore.d.ts +15 -1
  66. package/dist/daemon/session/TelemetryStore.js +19 -1
  67. package/dist/daemon/session/commandRegistry.js +52 -18
  68. package/dist/daemon/session/interactions.d.ts +2 -1
  69. package/dist/daemon/session/interactions.js +13 -1
  70. package/dist/daemon/session/matchedStylesReset.d.ts +26 -0
  71. package/dist/daemon/session/matchedStylesReset.js +46 -0
  72. package/dist/daemon/session/plugins.js +17 -2
  73. package/dist/daemon/session/teardown.js +1 -1
  74. package/dist/daemon/session/triggeredRequests.d.ts +0 -5
  75. package/dist/daemon/session/triggeredRequests.js +13 -7
  76. package/dist/daemon.js +2385 -1229
  77. package/dist/errors/messages.d.ts +62 -11
  78. package/dist/errors/messages.js +119 -22
  79. package/dist/index.js +14995 -9866
  80. package/dist/ipc/client.d.ts +18 -2
  81. package/dist/ipc/client.js +26 -5
  82. package/dist/ipc/protocol/auditTypes.d.ts +8 -2
  83. package/dist/ipc/protocol/commands.d.ts +16 -0
  84. package/dist/ipc/protocol/domTypes.d.ts +12 -0
  85. package/dist/ipc/protocol/inspectTypes.d.ts +7 -2
  86. package/dist/ipc/session/types.d.ts +7 -1
  87. package/dist/program.d.ts +14 -0
  88. package/dist/program.js +53 -0
  89. package/dist/runtime/dom/actionEffects.d.ts +5 -1
  90. package/dist/runtime/dom/actionEffects.js +26 -14
  91. package/dist/runtime/dom/audit.js +3 -2
  92. package/dist/runtime/dom/auditModel.js +6 -1
  93. package/dist/runtime/dom/auditScripts.d.ts +9 -3
  94. package/dist/runtime/dom/auditScripts.js +41 -5
  95. package/dist/runtime/dom/elementGeometry.d.ts +33 -3
  96. package/dist/runtime/dom/elementGeometry.js +44 -19
  97. package/dist/runtime/dom/elementInfo.d.ts +76 -18
  98. package/dist/runtime/dom/elementInfo.js +190 -40
  99. package/dist/runtime/dom/evalHelpers.d.ts +12 -2
  100. package/dist/runtime/dom/evalHelpers.js +67 -7
  101. package/dist/runtime/dom/formDiscovery.d.ts +6 -2
  102. package/dist/runtime/dom/formDiscovery.js +20 -3
  103. package/dist/runtime/dom/formFillHelpers/fill.js +7 -11
  104. package/dist/runtime/dom/formFillHelpers/pressKey.js +2 -2
  105. package/dist/runtime/dom/formFillHelpers/shared.d.ts +16 -10
  106. package/dist/runtime/dom/formFillHelpers/shared.js +19 -52
  107. package/dist/runtime/dom/formSubmitHelpers.js +4 -3
  108. package/dist/runtime/dom/frameLayout.js +1 -0
  109. package/dist/runtime/dom/frameScopedConnection.d.ts +7 -0
  110. package/dist/runtime/dom/frameScopedConnection.js +2 -2
  111. package/dist/runtime/dom/inspect.d.ts +17 -3
  112. package/dist/runtime/dom/inspect.js +45 -32
  113. package/dist/runtime/dom/inspectAllStyles.js +1 -0
  114. package/dist/runtime/dom/inspectHints.d.ts +1 -1
  115. package/dist/runtime/dom/inspectModel.d.ts +5 -4
  116. package/dist/runtime/dom/inspectModel.js +7 -3
  117. package/dist/runtime/dom/inspectPaintModel.d.ts +2 -0
  118. package/dist/runtime/dom/inspectPaintModel.js +3 -1
  119. package/dist/runtime/dom/inspectRules.d.ts +29 -3
  120. package/dist/runtime/dom/inspectRules.js +205 -11
  121. package/dist/runtime/dom/inspectScripts.d.ts +29 -2
  122. package/dist/runtime/dom/inspectScripts.js +49 -10
  123. package/dist/runtime/dom/layout.d.ts +0 -2
  124. package/dist/runtime/dom/layout.js +10 -9
  125. package/dist/runtime/dom/reactEventHelpers.d.ts +17 -4
  126. package/dist/runtime/dom/reactEventHelpers.js +71 -28
  127. package/dist/runtime/dom/targetNode.d.ts +27 -10
  128. package/dist/runtime/dom/targetNode.js +283 -16
  129. package/dist/runtime/dom/wait.js +2 -1
  130. package/dist/runtime/page/bdgWorld.d.ts +57 -0
  131. package/dist/runtime/page/bdgWorld.js +180 -0
  132. package/dist/runtime/page/replacedBuiltins.d.ts +28 -0
  133. package/dist/runtime/page/replacedBuiltins.js +136 -0
  134. package/dist/session/QueryCacheManager.d.ts +4 -1
  135. package/dist/session/QueryCacheManager.js +5 -2
  136. package/dist/session/chrome.d.ts +4 -1
  137. package/dist/session/chrome.js +7 -1
  138. package/dist/session/cleanup/staleSession.d.ts +21 -4
  139. package/dist/session/cleanup/staleSession.js +79 -9
  140. package/dist/session/cleanup/userCommands.d.ts +4 -1
  141. package/dist/session/cleanup/userCommands.js +10 -5
  142. package/dist/session/daemonSocket.d.ts +10 -0
  143. package/dist/session/daemonSocket.js +22 -0
  144. package/dist/session/lastSession.d.ts +6 -3
  145. package/dist/session/lastSession.js +11 -5
  146. package/dist/session/paths.d.ts +3 -1
  147. package/dist/session/paths.js +5 -5
  148. package/dist/session/portClaims.js +4 -3
  149. package/dist/session/sessionList.d.ts +13 -5
  150. package/dist/session/sessionList.js +31 -7
  151. package/dist/telemetry/a11y.d.ts +15 -1
  152. package/dist/telemetry/a11y.js +85 -2
  153. package/dist/telemetry/console.d.ts +2 -1
  154. package/dist/telemetry/console.js +30 -21
  155. package/dist/telemetry/har/builder.js +1 -1
  156. package/dist/telemetry/network.d.ts +13 -16
  157. package/dist/telemetry/network.js +30 -52
  158. package/dist/telemetry/networkRetention.d.ts +83 -0
  159. package/dist/telemetry/networkRetention.js +117 -0
  160. package/dist/telemetry/pageCrash.d.ts +26 -0
  161. package/dist/telemetry/pageCrash.js +53 -0
  162. package/dist/types.d.ts +42 -0
  163. package/dist/ui/OutputBuilder.d.ts +10 -0
  164. package/dist/ui/OutputBuilder.js +12 -0
  165. package/dist/ui/formatters/a11y.d.ts +5 -7
  166. package/dist/ui/formatters/a11y.js +7 -61
  167. package/dist/ui/formatters/audit.js +14 -5
  168. package/dist/ui/formatters/cdp.d.ts +138 -0
  169. package/dist/ui/formatters/cdp.js +131 -0
  170. package/dist/ui/formatters/console/chronological.js +7 -5
  171. package/dist/ui/formatters/console/follow.d.ts +5 -2
  172. package/dist/ui/formatters/console/follow.js +7 -4
  173. package/dist/ui/formatters/console/json.d.ts +4 -7
  174. package/dist/ui/formatters/console/json.js +16 -14
  175. package/dist/ui/formatters/console/shared.d.ts +47 -2
  176. package/dist/ui/formatters/console/shared.js +33 -0
  177. package/dist/ui/formatters/console/summarize.d.ts +9 -2
  178. package/dist/ui/formatters/console/summarize.js +57 -11
  179. package/dist/ui/formatters/console.d.ts +3 -2
  180. package/dist/ui/formatters/console.js +8 -10
  181. package/dist/ui/formatters/details.js +4 -2
  182. package/dist/ui/formatters/dom.d.ts +14 -5
  183. package/dist/ui/formatters/dom.js +30 -13
  184. package/dist/ui/formatters/helpFormatters.js +1 -1
  185. package/dist/ui/formatters/inspect.js +9 -3
  186. package/dist/ui/formatters/installSkill.d.ts +9 -1
  187. package/dist/ui/formatters/installSkill.js +32 -6
  188. package/dist/ui/formatters/layout.js +4 -2
  189. package/dist/ui/formatters/longValues.d.ts +14 -0
  190. package/dist/ui/formatters/longValues.js +23 -0
  191. package/dist/ui/formatters/networkList.d.ts +8 -2
  192. package/dist/ui/formatters/networkList.js +11 -3
  193. package/dist/ui/formatters/preview.d.ts +6 -1
  194. package/dist/ui/formatters/preview.js +67 -15
  195. package/dist/ui/formatters/sessions.d.ts +2 -2
  196. package/dist/ui/formatters/sessions.js +9 -2
  197. package/dist/ui/formatters/status.js +7 -0
  198. package/dist/ui/formatters/triggeredRequests.js +2 -1
  199. package/dist/ui/logging/logger.d.ts +1 -1
  200. package/dist/ui/messages/chrome.d.ts +20 -1
  201. package/dist/ui/messages/chrome.js +29 -3
  202. package/dist/ui/messages/commands.d.ts +153 -12
  203. package/dist/ui/messages/commands.js +198 -15
  204. package/dist/ui/messages/consoleMessages.d.ts +24 -0
  205. package/dist/ui/messages/consoleMessages.js +32 -0
  206. package/dist/ui/messages/networkMessages.d.ts +24 -0
  207. package/dist/ui/messages/networkMessages.js +45 -0
  208. package/dist/ui/messages/preview.d.ts +6 -0
  209. package/dist/ui/messages/preview.js +9 -1
  210. package/dist/ui/messages/session.d.ts +13 -2
  211. package/dist/ui/messages/session.js +22 -3
  212. package/dist/utils/directories.d.ts +34 -0
  213. package/dist/utils/directories.js +88 -0
  214. package/dist/utils/display.d.ts +16 -0
  215. package/dist/utils/display.js +42 -0
  216. package/dist/utils/exitCodes.d.ts +1 -0
  217. package/dist/utils/exitCodes.js +6 -0
  218. package/dist/utils/http.d.ts +9 -2
  219. package/dist/utils/http.js +4 -3
  220. package/dist/utils/process.d.ts +12 -0
  221. package/dist/utils/process.js +25 -0
  222. package/dist/utils/strings.d.ts +19 -0
  223. package/dist/utils/strings.js +16 -0
  224. package/package.json +2 -2
@@ -26,6 +26,15 @@ export function chromeClosedMessage(pid) {
26
26
  export function orphanedDaemonsCleanedMessage(count) {
27
27
  return `Cleaned up ${count} orphaned daemon process${count === 1 ? '' : 'es'}`;
28
28
  }
29
+ /**
30
+ * Where `bdg install-skill` kept the copy it replaced.
31
+ *
32
+ * @param path - Backup path, as the user would type it
33
+ * @returns One line
34
+ */
35
+ export function skillBackupMessage(path) {
36
+ return `previous copy kept in ${path}`;
37
+ }
29
38
  /**
30
39
  * Warning shown when a click falls back from mouse events to `el.click()`.
31
40
  *
@@ -184,16 +193,53 @@ export function valueMismatchWarning(mismatch) {
184
193
  */
185
194
  export const CLICK_NOT_RECEIVED_WARNING = 'The click may not have reached the element: the page saw no mouse press (the browser may be showing a dialog or bubble that captures input)';
186
195
  /**
187
- * Note under a shortened list of matches.
196
+ * Note under a shortened human list whose JSON output lists more, up to a cap.
188
197
  *
189
- * @param hidden - Matches not listed
190
- * @param jsonLimit - How many JSON output lists, when it leaves some out too
191
- * @returns e.g. "... and 1174 more (use --json for all)",
192
- * "... and 8980 more (--json lists the first 100)"
198
+ * @param hidden - Items not listed
199
+ * @param jsonLimit - Most items the JSON output lists
200
+ * @returns e.g. "... and 8980 more (--json lists up to 100)"
193
201
  */
194
202
  export function moreMatchesNote(hidden, jsonLimit) {
195
- const where = jsonLimit === undefined ? 'use --json for all' : `--json lists the first ${jsonLimit}`;
196
- return `... and ${hidden} more (${where})`;
203
+ return `... and ${hidden} more (--json lists up to ${jsonLimit})`;
204
+ }
205
+ /**
206
+ * Note under `dom query` matches cut by `--limit`.
207
+ *
208
+ * @param omitted - Matches not listed
209
+ * @param indexed - Matches usable by index, when not all of them
210
+ * @returns e.g. `... and 49953 more (--limit 0 lists all; indices 0-999 work with other commands)`
211
+ */
212
+ export function queryMoreMatchesNote(omitted, indexed) {
213
+ const indices = indexed === undefined ? '' : `; indices 0-${indexed - 1} work with other commands`;
214
+ return `... and ${omitted} more (--limit 0 lists all${indices})`;
215
+ }
216
+ /**
217
+ * Note under `dom query` matches listed past those whose viewport position
218
+ * was checked.
219
+ *
220
+ * @param checked - First matches checked
221
+ * @returns e.g. `Visibility is checked for the first 100 matches only; bdg dom layout <index> checks any of them`
222
+ */
223
+ export function queryViewportCheckedNote(checked) {
224
+ return `Visibility is checked for the first ${checked} matches only; ${sessionCommand('bdg dom layout <index>')} checks any of them`;
225
+ }
226
+ /**
227
+ * First line under an accessibility tree cut by `--limit` or `--depth`.
228
+ *
229
+ * @param listed - Nodes listed
230
+ * @returns e.g. "Showing the first 50 nodes (text boxes and repeated text left out)"
231
+ */
232
+ export function a11yTreeShownNote(listed) {
233
+ return `Showing the first ${listed} nodes (text boxes and repeated text left out)`;
234
+ }
235
+ /**
236
+ * How to see the rest of an accessibility tree cut by `--limit` or `--depth`.
237
+ *
238
+ * @param omitted - Nodes left out
239
+ * @returns e.g. "51391 more: --limit 0 lists all, --depth <n> limits the levels, or search with bdg dom a11y query \"role:<role>\""
240
+ */
241
+ export function a11yTreeMoreNote(omitted) {
242
+ return `${omitted} more: --limit 0 lists all, --depth <n> limits the levels, or search with bdg dom a11y query "role:<role>"`;
197
243
  }
198
244
  /**
199
245
  * Note under a list of a11y query matches cut by `--limit`.
@@ -253,6 +299,37 @@ export const LAYOUT_REASONS = {
253
299
  /** Joins an invisible reason to the ancestor causing it */
254
300
  on: ' on ',
255
301
  };
302
+ /** Why an out-of-view text's contrast in `dom audit` is approximate: none of its ancestors paints a background */
303
+ export const AUDIT_OUT_OF_VIEW_RISK = 'only its ancestors were checked';
304
+ /**
305
+ * `dom audit contrast` note for text that looks below the level but cannot
306
+ * be measured exactly (over an image, blended, under or over another layer).
307
+ *
308
+ * @param count - How many such texts
309
+ * @returns e.g. `(+12 more may be below it but cannot be measured: text over images or blended layers; check them with bdg dom inspect)`
310
+ */
311
+ export function auditUncertainContrastNote(count) {
312
+ return `(+${count} more may be below it but cannot be measured: text over images or blended layers; check them with ${sessionCommand('bdg dom inspect <element>')})`;
313
+ }
314
+ /**
315
+ * `dom audit animations` note for canvas elements, whose script-drawn
316
+ * animations it cannot see.
317
+ *
318
+ * @param count - Visible canvas elements
319
+ * @returns e.g. `(+ 2 canvas elements: animations drawn by scripts on them are not listed)`
320
+ */
321
+ export function auditCanvasNote(count) {
322
+ return `(+ ${count} canvas ${count === 1 ? 'element' : 'elements'}: animations drawn by scripts on ${count === 1 ? 'it are' : 'them are'} not listed)`;
323
+ }
324
+ /**
325
+ * A mask over an element, for `dom layout` and `dom inspect`.
326
+ *
327
+ * @param masked - The mask, e.g. `mask-image on div.hero`
328
+ * @returns e.g. `masked by mask-image on div.hero`
329
+ */
330
+ export function maskedText(masked) {
331
+ return `masked by ${masked}`;
332
+ }
256
333
  /** Start of the off-screen reason of an element a scroll-locked page hides ({@link scrollLockedReason}) */
257
334
  const SCROLL_LOCKED_PREFIX = 'page scrolling is locked';
258
335
  /**
@@ -391,16 +468,63 @@ export function colorSchemeLabel(scheme, emulated) {
391
468
  const source = emulated ? 'emulated' : 'from the system setting';
392
469
  return `prefers-color-scheme: ${scheme} (${source})`;
393
470
  }
471
+ /**
472
+ * Suggestion for an action that failed on a page that replaced built-ins
473
+ * bdg's page scripts use.
474
+ *
475
+ * @param replaced - Their dotted names (all are named)
476
+ * @returns Suggestion naming them and a way around
477
+ */
478
+ export function brokenByReplacedBuiltinsSuggestion(replaced) {
479
+ return `The page replaced built-ins bdg's action script uses (${replaced.join(', ')}), which may have broken it; if so, act on the element with ${sessionCommand("bdg dom eval '…'")} instead`;
480
+ }
481
+ /**
482
+ * Warning on an action when the page replaced built-ins bdg's page scripts
483
+ * use (polyfills, old frameworks, anti-bot scripts). Names the first four;
484
+ * the action's `replacedBuiltins` (JSON) lists them all.
485
+ *
486
+ * @param replaced - Their dotted names
487
+ * @returns e.g. `the page replaced built-ins bdg's scripts use (Element.prototype.querySelectorAll); bdg found the element in its own world, but the action runs in the page's and may misbehave`
488
+ */
489
+ export function replacedBuiltinsWarning(replaced) {
490
+ const shown = replaced.slice(0, 4).join(', ') +
491
+ (replaced.length > 4 ? `, +${replaced.length - 4} more (see --json)` : '');
492
+ return `the page replaced built-ins bdg's scripts use (${shown}); bdg found the element in its own world, but the action runs in the page's and may misbehave`;
493
+ }
394
494
  /**
395
495
  * First line of `bdg status` for a running session.
396
496
  *
397
- * @param page - URL and title of the page, when the session reported them
398
- * @returns e.g. `Session active: https://example.com/ — Example Domain`
497
+ * @param page - URL and title of the page, when the session reported them,
498
+ * and when it crashed
499
+ * @returns e.g. `Session active: https://example.com/ — Example Domain`, with
500
+ * a crash warning on a second line
399
501
  */
400
502
  export function sessionActiveLine(page) {
401
503
  if (!page)
402
504
  return 'Session active';
403
- return `Session active: ${page.url}${page.title ? ` — ${page.title}` : ''}`;
505
+ const line = `Session active: ${page.url}${page.title ? ` — ${page.title}` : ''}`;
506
+ return page.crashedAt === undefined ? line : `${line}\n${pageCrashedNote(page.crashedAt)}`;
507
+ }
508
+ /**
509
+ * Warning that the session's page crashed, for `bdg status`, `bdg peek`,
510
+ * `bdg console` and `bdg network list`.
511
+ *
512
+ * @param crashedAt - When it crashed (epoch ms)
513
+ * @returns e.g. `⚠ The page crashed at 18:42:10 (renderer gone); bdg page reload brings it back`
514
+ */
515
+ export function pageCrashedNote(crashedAt) {
516
+ return `⚠ The page crashed at ${new Date(crashedAt).toLocaleTimeString()} (renderer gone); ${sessionCommand('bdg page reload')} brings it back`;
517
+ }
518
+ /**
519
+ * Put the page-crashed warning before a view of collected data, when the
520
+ * page crashed (what is shown was collected before).
521
+ *
522
+ * @param body - The view
523
+ * @param crashedAt - When the page crashed (epoch ms), if it did
524
+ * @returns The view, after the warning when the page crashed
525
+ */
526
+ export function withPageCrashedNote(body, crashedAt) {
527
+ return crashedAt === undefined ? body : `${pageCrashedNote(crashedAt)}\n\n${body}`;
404
528
  }
405
529
  /**
406
530
  * Page dimensions line of `bdg dom layout`.
@@ -477,10 +601,13 @@ export function coverText(cover, transparent) {
477
601
  * Note when `bdg dom inspect` could not read the element's matched rules, so
478
602
  * no hints, rules or why were computed.
479
603
  *
480
- * @param reason - `timeout` (very large stylesheets) or `failed` (Chrome reported an error)
604
+ * @param reason - `timeout` (very large stylesheets), `failed` (Chrome reported
605
+ * an error) or `skipped` (hints not read: an earlier read on this page timed out)
481
606
  * @returns Note
482
607
  */
483
608
  export function inspectCascadeNote(reason) {
609
+ if (reason === 'skipped')
610
+ return "hints skipped: this page's stylesheets are slow to read (--rules waits 5 s)";
484
611
  return reason === 'timeout'
485
612
  ? "CSS rules not read: the page's stylesheets took too long (hints wait 1 s; --rules and --why 5 s)"
486
613
  : 'CSS rules not read: Chrome could not report the rules matching this element';
@@ -524,6 +651,7 @@ export function inspectVisibilityBadges(visibility) {
524
651
  visibility.hidden && `[hidden: ${visibility.hidden}]`,
525
652
  visibility.offscreen && `[offscreen: ${visibility.offscreen}]`,
526
653
  visibility.coveredBy && `[${coverText(visibility.coveredBy, visibility.coverTransparent)}]`,
654
+ visibility.masked && `[${maskedText(visibility.masked)}]`,
527
655
  ].filter((badge) => Boolean(badge));
528
656
  }
529
657
  /**
@@ -674,6 +802,19 @@ export function dialogConsoleText(dialog) {
674
802
  const kind = dialog.type === 'beforeunload' ? 'beforeunload' : `${dialog.type}()`;
675
803
  return `${kind} dialog accepted${dialog.message ? `: "${dialog.message}"` : ''}`;
676
804
  }
805
+ /**
806
+ * How far a pointer action scrolled the page to reach its element.
807
+ *
808
+ * @param scrolledBy - Page scroll (CSS px)
809
+ * @returns e.g. `page down 1240px to reach it`, `page right 300px, up 80px to reach it`
810
+ */
811
+ export function pointerScrollText(scrolledBy) {
812
+ const parts = [
813
+ scrolledBy.y !== 0 && `${scrolledBy.y > 0 ? 'down' : 'up'} ${Math.abs(scrolledBy.y)}px`,
814
+ scrolledBy.x !== 0 && `${scrolledBy.x > 0 ? 'right' : 'left'} ${Math.abs(scrolledBy.x)}px`,
815
+ ].filter(Boolean);
816
+ return `page ${parts.join(', ')} to reach it`;
817
+ }
677
818
  /** Headline of each pointer action, e.g. "Element Double-clicked" */
678
819
  export const POINTER_ACTION_DONE = {
679
820
  click: 'Clicked',
@@ -912,13 +1053,17 @@ export function elementTextLine(text) {
912
1053
  *
913
1054
  * @param children - First child elements, e.g. `iframe#app`
914
1055
  * @param count - Number of child elements
915
- * @returns e.g. `No text; holds 1 element: iframe (see its HTML with --raw)`
1056
+ * @param inShadowRoot - The children are those of its shadow root (`--raw` does not show them)
1057
+ * @returns e.g. `No text; holds 1 element: iframe (see its HTML with --raw)`,
1058
+ * `No text; its shadow root holds 1 element: button "Close" (see it with bdg dom inspect)`
916
1059
  */
917
- export function emptyElementLine(children, count) {
1060
+ export function emptyElementLine(children, count, inShadowRoot = false) {
1061
+ const holder = inShadowRoot ? 'its shadow root holds' : 'holds';
918
1062
  if (count === 0)
919
- return 'No text and no child elements';
1063
+ return `No text and no child elements${inShadowRoot ? ' in its shadow root' : ''}`;
920
1064
  const more = count > children.length ? `, … ${count - children.length} more` : '';
921
- return `No text; holds ${pluralize(count, 'element')}: ${children.join(', ')}${more} (see its HTML with --raw)`;
1065
+ const hint = inShadowRoot ? 'see it with bdg dom inspect' : 'see its HTML with --raw';
1066
+ return `No text; ${holder} ${pluralize(count, 'element')}: ${children.join(', ')}${more} (${hint})`;
922
1067
  }
923
1068
  /**
924
1069
  * Note on a screenshot scaled down to keep its image token cost bounded.
@@ -969,6 +1114,27 @@ export function queryNextSteps(index) {
969
1114
  export function evalFrameLine(url) {
970
1115
  return `Frame: ${frameUrlLabel(url)}`;
971
1116
  }
1117
+ /**
1118
+ * Warning on a `dom eval` result the browser copied because the page
1119
+ * replaced built-ins bdg's own copy uses.
1120
+ *
1121
+ * @param replaced - Their dotted names (all are named)
1122
+ * @returns e.g. `the page replaced Object.keys, so the browser copied the result: undefined, NaN, functions, DOM nodes, dates, maps and sets inside it show as null or {}`
1123
+ */
1124
+ export function evalCopiedByBrowserWarning(replaced) {
1125
+ return `the page replaced ${replaced.join(', ')}, so the browser copied the result: undefined, NaN, functions, DOM nodes, dates, maps and sets inside it show as null or {}`;
1126
+ }
1127
+ /**
1128
+ * Warning on a `dom eval` result shown as its preview: the page replaced
1129
+ * built-ins bdg's copy uses and the browser could not copy it either (a
1130
+ * cycle or a BigInt inside).
1131
+ *
1132
+ * @param replaced - Their dotted names (all are named)
1133
+ * @returns Warning that the value is a shortened preview
1134
+ */
1135
+ export function evalPreviewWarning(replaced) {
1136
+ return `the page replaced ${replaced.join(', ')}, and the result could not be copied (it holds a cycle or a BigInt), so it is shown as a shortened preview string; return a JSON-safe value (e.g. pick the fields you need)`;
1137
+ }
972
1138
  /**
973
1139
  * Generate warning message.
974
1140
  *
@@ -1124,4 +1290,21 @@ Examples:
1124
1290
  bdg css search --limit 50 -- --brand)
1125
1291
  bdg css search "oklch(" Rules that use oklch colors
1126
1292
  bdg css search ".btn-primary" Rules of a class, in every stylesheet`;
1293
+ /**
1294
+ * `details` field of `bdg --help --json`: where the full help is.
1295
+ *
1296
+ * @returns Note
1297
+ */
1298
+ export function helpJsonDetailsNote() {
1299
+ 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';
1300
+ }
1301
+ /**
1302
+ * Pointer after a value cut for human output.
1303
+ *
1304
+ * @param count - Characters left out
1305
+ * @returns e.g. `… 299800 more chars (use --full)`
1306
+ */
1307
+ export function moreCharsNote(count) {
1308
+ return `… ${count} more chars (use --full)`;
1309
+ }
1127
1310
  //# sourceMappingURL=commands.js.map
@@ -25,4 +25,28 @@ export declare function stoppedFollowingConsoleMessage(): string;
25
25
  * @returns e.g. `[n] are positions in the session's message list; not listed in between: 1 message from another page load (-H lists all)`
26
26
  */
27
27
  export declare function consoleIndexGapNote(skipped: ConsoleSkipped): string;
28
+ /**
29
+ * Note that the session dropped its oldest console messages at the limit.
30
+ *
31
+ * @param dropped - Messages dropped
32
+ * @returns e.g. `⚠ 2000 older console messages were dropped: bdg keeps the newest 10000`
33
+ */
34
+ export declare function consoleDroppedNote(dropped: number): string;
35
+ /**
36
+ * Error for `bdg details console <n>` with the index of a dropped message.
37
+ *
38
+ * @param index - Index asked for
39
+ * @param dropped - Messages dropped (the first kept has this index)
40
+ * @returns Message
41
+ */
42
+ export declare function consoleMessageDroppedError(index: number, dropped: number): string;
43
+ /**
44
+ * Note under the console summary when it lists only the newest distinct
45
+ * errors or warnings.
46
+ *
47
+ * @param more - Distinct messages not listed
48
+ * @param level - `error` or `warning`
49
+ * @returns e.g. `(+120 earlier distinct errors; bdg console --level error --last 0 lists every one)`
50
+ */
51
+ export declare function consoleMoreGroupsNote(more: number, level: 'error' | 'warning'): string;
28
52
  //# sourceMappingURL=consoleMessages.d.ts.map
@@ -3,7 +3,9 @@
3
3
  *
4
4
  * User-facing messages for the console command output and formatting.
5
5
  */
6
+ import { MAX_CONSOLE_MESSAGES } from '../../constants.js';
6
7
  import { pluralize } from '../formatting.js';
8
+ import { sessionCommand } from './sessionCommand.js';
7
9
  /**
8
10
  * Generate message for following console output.
9
11
  *
@@ -36,4 +38,34 @@ export function consoleIndexGapNote(skipped) {
36
38
  ].filter(Boolean);
37
39
  return `[n] are positions in the session's message list; not listed in between: ${reasons.join(', ')}`;
38
40
  }
41
+ /**
42
+ * Note that the session dropped its oldest console messages at the limit.
43
+ *
44
+ * @param dropped - Messages dropped
45
+ * @returns e.g. `⚠ 2000 older console messages were dropped: bdg keeps the newest 10000`
46
+ */
47
+ export function consoleDroppedNote(dropped) {
48
+ return `⚠ ${pluralize(dropped, 'older console message')} ${dropped === 1 ? 'was' : 'were'} dropped: bdg keeps the newest ${MAX_CONSOLE_MESSAGES}`;
49
+ }
50
+ /**
51
+ * Error for `bdg details console <n>` with the index of a dropped message.
52
+ *
53
+ * @param index - Index asked for
54
+ * @param dropped - Messages dropped (the first kept has this index)
55
+ * @returns Message
56
+ */
57
+ export function consoleMessageDroppedError(index, dropped) {
58
+ return `Console message ${index} was dropped: bdg keeps the newest ${MAX_CONSOLE_MESSAGES} messages (the oldest kept is ${dropped})`;
59
+ }
60
+ /**
61
+ * Note under the console summary when it lists only the newest distinct
62
+ * errors or warnings.
63
+ *
64
+ * @param more - Distinct messages not listed
65
+ * @param level - `error` or `warning`
66
+ * @returns e.g. `(+120 earlier distinct errors; bdg console --level error --last 0 lists every one)`
67
+ */
68
+ export function consoleMoreGroupsNote(more, level) {
69
+ return `(+${more} earlier distinct ${more === 1 ? level : `${level}s`}; ${sessionCommand(`bdg console --level ${level} --last 0`)} lists every one)`;
70
+ }
39
71
  //# sourceMappingURL=consoleMessages.js.map
@@ -3,6 +3,30 @@
3
3
  *
4
4
  * User-facing messages for the network list command output and formatting.
5
5
  */
6
+ /**
7
+ * Why a stored response body was replaced by a placeholder (shown by
8
+ * `bdg details network <id>` as `bodyNotCaptured`).
9
+ *
10
+ * @param budgetBytes - Total body budget of the session
11
+ * @returns e.g. `evicted: total body budget (bdg keeps the newest 100 MB of response bodies)`
12
+ */
13
+ export declare function bodyEvictedReason(budgetBytes: number): string;
14
+ /** What a session's network capture let go at its limits */
15
+ export interface NetworkEvictionCounts {
16
+ /** Oldest finished requests dropped at the request cap */
17
+ requestsDropped: number;
18
+ /** Oldest response bodies evicted at the body budget */
19
+ bodiesEvicted: number;
20
+ }
21
+ /**
22
+ * Note that the session dropped its oldest requests or evicted its oldest
23
+ * response bodies at its limits.
24
+ *
25
+ * @param counts - Requests dropped and bodies evicted
26
+ * @returns e.g. `⚠ 2000 older network requests were dropped: bdg keeps the newest 10000`;
27
+ * undefined when nothing was let go
28
+ */
29
+ export declare function networkEvictedNote(counts: NetworkEvictionCounts): string | undefined;
6
30
  /**
7
31
  * Generate message for following network output.
8
32
  *
@@ -3,6 +3,51 @@
3
3
  *
4
4
  * User-facing messages for the network list command output and formatting.
5
5
  */
6
+ import { MAX_NETWORK_REQUESTS, MAX_TOTAL_BODY_BYTES } from '../../constants.js';
7
+ import { pluralize } from '../formatting.js';
8
+ /**
9
+ * A byte budget in whole megabytes.
10
+ *
11
+ * @param bytes - Budget
12
+ * @returns e.g. `100 MB`
13
+ */
14
+ function megabytes(bytes) {
15
+ return `${Math.round(bytes / (1024 * 1024))} MB`;
16
+ }
17
+ /**
18
+ * Why a stored response body was replaced by a placeholder (shown by
19
+ * `bdg details network <id>` as `bodyNotCaptured`).
20
+ *
21
+ * @param budgetBytes - Total body budget of the session
22
+ * @returns e.g. `evicted: total body budget (bdg keeps the newest 100 MB of response bodies)`
23
+ */
24
+ export function bodyEvictedReason(budgetBytes) {
25
+ return `evicted: total body budget (bdg keeps the newest ${megabytes(budgetBytes)} of response bodies)`;
26
+ }
27
+ /**
28
+ * Note that the session dropped its oldest requests or evicted its oldest
29
+ * response bodies at its limits.
30
+ *
31
+ * @param counts - Requests dropped and bodies evicted
32
+ * @returns e.g. `⚠ 2000 older network requests were dropped: bdg keeps the newest 10000`;
33
+ * undefined when nothing was let go
34
+ */
35
+ export function networkEvictedNote(counts) {
36
+ const { requestsDropped, bodiesEvicted } = counts;
37
+ const requests = pluralize(requestsDropped, 'older network request');
38
+ const bodies = pluralize(bodiesEvicted, 'older response body', 'older response bodies');
39
+ const budget = megabytes(MAX_TOTAL_BODY_BYTES);
40
+ if (requestsDropped > 0 && bodiesEvicted > 0) {
41
+ return `⚠ ${requests} dropped, ${bodies} evicted: bdg keeps the newest ${MAX_NETWORK_REQUESTS} requests and ${budget} of bodies`;
42
+ }
43
+ if (requestsDropped > 0) {
44
+ return `⚠ ${requests} ${requestsDropped === 1 ? 'was' : 'were'} dropped: bdg keeps the newest ${MAX_NETWORK_REQUESTS}`;
45
+ }
46
+ if (bodiesEvicted > 0) {
47
+ return `⚠ ${bodies} ${bodiesEvicted === 1 ? 'was' : 'were'} evicted: bdg keeps the newest ${budget} of bodies`;
48
+ }
49
+ return undefined;
50
+ }
6
51
  /**
7
52
  * Generate message for following network output.
8
53
  *
@@ -55,6 +55,12 @@ export declare function stoppedFollowingPreviewMessage(): string;
55
55
  * @param retryLabel - Human-readable retry interval (e.g. "1s", "500ms")
56
56
  */
57
57
  export declare function connectionLostRetryMessage(timestamp: string, retryLabel: string): string;
58
+ /**
59
+ * Follow mode stops because the session it followed ended.
60
+ *
61
+ * @returns Message
62
+ */
63
+ export declare function followedSessionEndedMessage(): string;
58
64
  /**
59
65
  * Generate follow-mode stop hint.
60
66
  *
@@ -19,7 +19,7 @@ export const PREVIEW_HEADERS = {
19
19
  * @returns Single-line tip for basic peek usage
20
20
  */
21
21
  export function compactTipsMessage() {
22
- return `Tip: ${sessionCommand('bdg peek --last 50')} | ${sessionCommand('bdg peek --verbose')}`;
22
+ return `Tip: ${sessionCommand('bdg peek --last 50')} or ${sessionCommand('bdg peek --verbose')}`;
23
23
  }
24
24
  /**
25
25
  * Generate verbose mode commands section.
@@ -71,6 +71,14 @@ export function stoppedFollowingPreviewMessage() {
71
71
  export function connectionLostRetryMessage(timestamp, retryLabel) {
72
72
  return `\n[${timestamp}] ⚠️ Connection lost, retrying every ${retryLabel}...`;
73
73
  }
74
+ /**
75
+ * Follow mode stops because the session it followed ended.
76
+ *
77
+ * @returns Message
78
+ */
79
+ export function followedSessionEndedMessage() {
80
+ return 'The session ended; stopped following';
81
+ }
74
82
  /**
75
83
  * Generate follow-mode stop hint.
76
84
  *
@@ -78,7 +78,18 @@ export declare function lastSessionEndText(end: {
78
78
  endedAt: number;
79
79
  }): string;
80
80
  /**
81
- * Note after a failed start whose daemon had not exited when bdg stopped waiting.
81
+ * A session that ended without `bdg stop`, for `bdg sessions`.
82
+ *
83
+ * @param label - Session name as listed
84
+ * @param end - How and when it ended
85
+ * @returns One line
86
+ */
87
+ export declare function endedSessionText(label: string, end: {
88
+ reason: string;
89
+ endedAt: number;
90
+ }): string;
91
+ /**
92
+ * Note after a failed start or a stop whose daemon had not exited when bdg stopped waiting.
82
93
  *
83
94
  * @param pid - Daemon PID, when known
84
95
  * @param waitedMs - How long bdg waited
@@ -86,7 +97,7 @@ export declare function lastSessionEndText(end: {
86
97
  */
87
98
  export declare function daemonStillExitingHint(pid: number | undefined, waitedMs: number): string;
88
99
  /**
89
- * What to do about a daemon still shutting down after a failed start.
100
+ * What to do about a daemon still shutting down after a failed start or a stop.
90
101
  *
91
102
  * @returns Suggestion
92
103
  */
@@ -89,16 +89,35 @@ export function stopFailedError(reason) {
89
89
  * @returns One line
90
90
  */
91
91
  export function lastSessionEndText(end) {
92
+ return `The last session ended ${sessionEndText(end)}`;
93
+ }
94
+ /**
95
+ * A session that ended without `bdg stop`, for `bdg sessions`.
96
+ *
97
+ * @param label - Session name as listed
98
+ * @param end - How and when it ended
99
+ * @returns One line
100
+ */
101
+ export function endedSessionText(label, end) {
102
+ return `${label} ended ${sessionEndText(end)}`;
103
+ }
104
+ /**
105
+ * When and why a session ended without `bdg stop`.
106
+ *
107
+ * @param end - How and when it ended
108
+ * @returns `at <time>: <why>`
109
+ */
110
+ function sessionEndText(end) {
92
111
  const why = {
93
112
  crash: 'Chrome crashed or was closed',
94
113
  closed: 'its page was closed',
95
114
  timeout: 'the --timeout was reached',
96
115
  };
97
116
  const at = new Date(end.endedAt).toLocaleTimeString();
98
- return `The last session ended at ${at}: ${why[end.reason] ?? end.reason}`;
117
+ return `at ${at}: ${why[end.reason] ?? end.reason}`;
99
118
  }
100
119
  /**
101
- * Note after a failed start whose daemon had not exited when bdg stopped waiting.
120
+ * Note after a failed start or a stop whose daemon had not exited when bdg stopped waiting.
102
121
  *
103
122
  * @param pid - Daemon PID, when known
104
123
  * @param waitedMs - How long bdg waited
@@ -109,7 +128,7 @@ export function daemonStillExitingHint(pid, waitedMs) {
109
128
  return `${daemon} was still shutting down after ${waitedMs / 1000}s`;
110
129
  }
111
130
  /**
112
- * What to do about a daemon still shutting down after a failed start.
131
+ * What to do about a daemon still shutting down after a failed start or a stop.
113
132
  *
114
133
  * @returns Suggestion
115
134
  */
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Checks for a directory bdg is about to create and write (the session
3
+ * directory, a Chrome profile) before it touches it: `fs.mkdirSync` with
4
+ * `recursive` spins forever on Linux pseudo-filesystems (`/proc/x` kept a
5
+ * start at full CPU until SIGKILL), and a profile Chrome cannot use wedges
6
+ * the session.
7
+ */
8
+ /** Why a directory cannot be used, and whether it is a permission problem */
9
+ export interface DirectoryProblem {
10
+ /** e.g. `/proc is a pseudo-filesystem`, `/tmp/x is a file`, `EACCES` */
11
+ reason: string;
12
+ /** Permission denied (or a read-only file system) rather than a wrong path */
13
+ denied: boolean;
14
+ }
15
+ /**
16
+ * Why `dir` cannot be created or written: it (or the path to it) is on a
17
+ * pseudo-filesystem, a part of it is a file, or its nearest existing
18
+ * directory is not writable.
19
+ *
20
+ * @param dir - Directory path (resolved against the working directory)
21
+ * @returns The problem, or null when the directory can be used
22
+ */
23
+ export declare function directoryProblem(dir: string): DirectoryProblem | null;
24
+ /**
25
+ * Create a directory (and its parents) after {@link directoryProblem} found
26
+ * nothing wrong, so a pseudo-filesystem fails at once instead of spinning.
27
+ *
28
+ * @param dir - Directory to create
29
+ * @param mode - Permissions of the directories created
30
+ * @throws Error with `code` `EPSEUDOFS` (pseudo-filesystem), `ENOTDIR` (a
31
+ * file on the path), `EACCES` (not writable), or the `mkdir` error
32
+ */
33
+ export declare function makeDirectory(dir: string, mode?: number): void;
34
+ //# sourceMappingURL=directories.d.ts.map