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
@@ -1,10 +1,15 @@
1
- import { RESOURCE_TYPE_ABBREVIATIONS, MIME_TYPE_RULES } from '../../constants.js';
2
- import { buildSuccessResponse } from '../OutputBuilder.js';
3
- import { formatTimestamp } from './console/shared.js';
1
+ import { MAX_CONSOLE_TEXT_LENGTH, MIME_TYPE_RULES, RESOURCE_TYPE_ABBREVIATIONS, } from '../../constants.js';
2
+ import { buildSuccessResponse, stringifyEnvelope } from '../OutputBuilder.js';
3
+ import { capMessageText, formatTimestamp } from './console/shared.js';
4
+ import { capForDisplay } from './longValues.js';
4
5
  import { failureReason, formatRequestStatus, getRequestState, } from './requestStatus.js';
5
6
  import { OutputFormatter, truncateUrl, truncateText } from '../formatting.js';
7
+ import { moreCharsNote, withPageCrashedNote } from '../messages/commands.js';
8
+ import { consoleDroppedNote } from '../messages/consoleMessages.js';
9
+ import { networkEvictedNote } from '../messages/networkMessages.js';
6
10
  import { PREVIEW_EMPTY_STATES, PREVIEW_HEADERS, compactTipsMessage, verboseCommandsMessage, } from '../messages/preview.js';
7
11
  import { sessionCommand } from '../messages/sessionCommand.js';
12
+ import { capLength } from '../../utils/strings.js';
8
13
  /**
9
14
  * Infer resource type from MIME type when CDP doesn't provide it.
10
15
  *
@@ -53,7 +58,8 @@ export function formatPreview(output, options) {
53
58
  return formatPreviewHumanReadable(output, options);
54
59
  }
55
60
  /**
56
- * Build the JSON payload for a preview, honoring the section and `--last` filters.
61
+ * Build the JSON payload for a preview, honoring the section and `--last`
62
+ * filters; console texts are cut with `truncatedFrom` unless `--full`.
57
63
  *
58
64
  * @param output - Preview output from the daemon
59
65
  * @param options - Preview options (section filters, last N)
@@ -69,8 +75,12 @@ export function buildPreviewJsonData(output, options) {
69
75
  target: output.target,
70
76
  ...(output.partial !== undefined && { partial: output.partial }),
71
77
  ...(output.totals && { totals: output.totals }),
78
+ ...(output.pageCrashedAt !== undefined && { pageCrashedAt: output.pageCrashedAt }),
72
79
  ...(pick('network') && output.data.network && { network: last(output.data.network) }),
73
- ...(pick('console') && output.data.console && { console: last(output.data.console) }),
80
+ ...(pick('console') &&
81
+ output.data.console && {
82
+ console: last(output.data.console)?.map((message) => capMessageText(message, options.full)),
83
+ }),
74
84
  };
75
85
  }
76
86
  /**
@@ -78,19 +88,40 @@ export function buildPreviewJsonData(output, options) {
78
88
  *
79
89
  * @param output - Preview output
80
90
  * @param options - Preview options
81
- * @returns Pretty-printed `{ version, success, data }` envelope
91
+ * @returns `{ version, success, data }` envelope, indented on a terminal, and
92
+ * always on one line in follow mode (one object per line, NDJSON)
82
93
  */
83
94
  function formatPreviewAsJson(output, options) {
84
- return JSON.stringify(buildSuccessResponse(buildPreviewJsonData(output, options)), null, 2);
95
+ const envelope = buildSuccessResponse(buildPreviewJsonData(output, options));
96
+ return options.follow ? JSON.stringify(envelope) : stringifyEnvelope(envelope);
85
97
  }
86
98
  /**
87
- * Format preview as human-readable output
99
+ * Format preview as human-readable output, after a warning when the page
100
+ * crashed (what is shown was collected before).
88
101
  */
89
102
  function formatPreviewHumanReadable(output, options) {
90
- if (options.verbose) {
91
- return formatPreviewVerbose(output, options);
92
- }
93
- return formatPreviewCompact(output, options);
103
+ const body = options.verbose
104
+ ? formatPreviewVerbose(output, options)
105
+ : formatPreviewCompact(output, options);
106
+ return withPageCrashedNote(body, output.pageCrashedAt);
107
+ }
108
+ /**
109
+ * A console message text in the compact preview: cut like `console --list`
110
+ * cuts it and to its first two lines, or whole with `--full`. The pointer
111
+ * naming `--full` comes after the line cut, so it is always shown.
112
+ *
113
+ * @param text - Message text
114
+ * @param full - `--full`
115
+ * @returns Text to print
116
+ */
117
+ function compactConsoleText(text, full) {
118
+ if (full)
119
+ return text;
120
+ const capped = capLength(text, MAX_CONSOLE_TEXT_LENGTH);
121
+ const shown = truncateText(capped.text, 2);
122
+ return capped.truncatedFrom === undefined
123
+ ? shown
124
+ : `${shown}${moreCharsNote(capped.truncatedFrom - capped.text.length)}`;
94
125
  }
95
126
  /**
96
127
  * Format preview in compact format (default)
@@ -113,6 +144,9 @@ function formatPreviewCompact(output, options) {
113
144
  const totalCount = output.totals?.network ?? output.data.network.length;
114
145
  const limitHint = formatLimitHint(showingCount, totalCount);
115
146
  fmt.text(`NETWORK (${showingCount}/${totalCount})${limitHint}:`);
147
+ const evictedNote = previewEvictedNote(output);
148
+ if (evictedNote)
149
+ fmt.text(` ${evictedNote}`);
116
150
  if (requests.length === 0) {
117
151
  if (options.filteredTypes &&
118
152
  options.filteredTypes.length > 0 &&
@@ -145,14 +179,15 @@ function formatPreviewCompact(output, options) {
145
179
  const totalCount = output.totals?.console ?? output.data.console.length;
146
180
  const limitHint = formatLimitHint(showingCount, totalCount);
147
181
  fmt.text(`CONSOLE (${showingCount}/${totalCount})${limitHint}:`);
182
+ if (output.totals?.consoleDropped)
183
+ fmt.text(` ${consoleDroppedNote(output.totals.consoleDropped)}`);
148
184
  if (messages.length === 0) {
149
185
  fmt.text(` ${PREVIEW_EMPTY_STATES.NO_DATA}`);
150
186
  }
151
187
  else {
152
188
  const consoleLines = messages.map((msg) => {
153
189
  const prefix = msg.type.toUpperCase().padEnd(5);
154
- const text = truncateText(msg.text, 2);
155
- return `${prefix} ${text}`;
190
+ return `${prefix} ${compactConsoleText(msg.text, options.full)}`;
156
191
  });
157
192
  fmt.list(consoleLines, 2);
158
193
  }
@@ -164,6 +199,18 @@ function formatPreviewCompact(output, options) {
164
199
  }
165
200
  return fmt.build();
166
201
  }
202
+ /**
203
+ * Note that the session dropped requests or evicted bodies at its capture limits.
204
+ *
205
+ * @param output - Preview output with its totals
206
+ * @returns Note text, or undefined when nothing was let go
207
+ */
208
+ function previewEvictedNote(output) {
209
+ return networkEvictedNote({
210
+ requestsDropped: output.totals?.networkDropped ?? 0,
211
+ bodiesEvicted: output.totals?.networkBodiesEvicted ?? 0,
212
+ });
213
+ }
167
214
  /**
168
215
  * Format preview in verbose format (opt-in with --verbose)
169
216
  * Original human-friendly output with Unicode formatting
@@ -190,6 +237,9 @@ function formatPreviewVerbose(output, options) {
190
237
  ? `Network Requests (all ${requests.length})`
191
238
  : `Network Requests (last ${requests.length} of ${output.totals?.network ?? output.data.network.length})`;
192
239
  fmt.text(title).separator('━', 50);
240
+ const evictedNote = previewEvictedNote(output);
241
+ if (evictedNote)
242
+ fmt.text(evictedNote);
193
243
  if (requests.length === 0) {
194
244
  if (options.filteredTypes &&
195
245
  options.filteredTypes.length > 0 &&
@@ -232,13 +282,15 @@ function formatPreviewVerbose(output, options) {
232
282
  ? `Console Messages (all ${messages.length})`
233
283
  : `Console Messages (last ${messages.length} of ${output.totals?.console ?? output.data.console.length})`;
234
284
  fmt.text(title).separator('━', 50);
285
+ if (output.totals?.consoleDropped)
286
+ fmt.text(consoleDroppedNote(output.totals.consoleDropped));
235
287
  if (messages.length === 0) {
236
288
  fmt.text(PREVIEW_EMPTY_STATES.NO_CONSOLE_MESSAGES);
237
289
  }
238
290
  else {
239
291
  messages.forEach((msg) => {
240
292
  const icon = msg.type === 'error' ? 'ERR' : msg.type === 'warning' ? 'WARN' : 'INFO';
241
- fmt.text(`${icon} [${msg.type}] ${msg.text}`);
293
+ fmt.text(`${icon} [${msg.type}] ${capForDisplay(msg.text, MAX_CONSOLE_TEXT_LENGTH, options.full)}`);
242
294
  });
243
295
  }
244
296
  fmt.blank();
@@ -1,7 +1,7 @@
1
1
  import type { RunningSessionInfo } from '../../session/sessionList.js';
2
2
  /**
3
- * Format the sessions as a table, followed by the cleanup commands of
4
- * crashed and stale sessions.
3
+ * Format the sessions as a table, followed by why ended sessions ended and
4
+ * the cleanup commands of crashed and stale sessions.
5
5
  *
6
6
  * @param data - Sessions
7
7
  * @returns Human-readable list
@@ -1,9 +1,10 @@
1
1
  import { OutputFormatter } from '../formatting.js';
2
+ import { endedSessionText } from '../messages/session.js';
2
3
  /** Label of the default session in the list */
3
4
  const DEFAULT_SESSION_LABEL = '(default)';
4
5
  /**
5
- * Format the sessions as a table, followed by the cleanup commands of
6
- * crashed and stale sessions.
6
+ * Format the sessions as a table, followed by why ended sessions ended and
7
+ * the cleanup commands of crashed and stale sessions.
7
8
  *
8
9
  * @param data - Sessions
9
10
  * @returns Human-readable list
@@ -31,6 +32,12 @@ export function formatSessionList(data) {
31
32
  .join(' ')
32
33
  .trimEnd());
33
34
  }
35
+ const ended = data.sessions.flatMap(({ name, endReason, endedAt }) => endReason && endedAt !== undefined
36
+ ? [endedSessionText(name ?? DEFAULT_SESSION_LABEL, { reason: endReason, endedAt })]
37
+ : []);
38
+ if (ended.length > 0) {
39
+ fmt.blank().section('Ended without bdg stop:', ended);
40
+ }
34
41
  const cleanups = data.sessions.flatMap((session) => (session.cleanup ? [session.cleanup] : []));
35
42
  if (cleanups.length > 0) {
36
43
  fmt.hints('Crashed or stale sessions; clean up with:', cleanups);
@@ -2,6 +2,7 @@ import { describeRunningChrome } from '../../session/chrome.js';
2
2
  import { calculateDuration, formatTimeAgo } from '../../session/statusData.js';
3
3
  import { OutputFormatter } from '../formatting.js';
4
4
  import { colorSchemeLabel, sessionActiveLine } from '../messages/commands.js';
5
+ import { networkEvictedNote } from '../messages/networkMessages.js';
5
6
  import { lastSessionEndText } from '../messages/session.js';
6
7
  import { noActiveSessionMessage, sessionCommand } from '../messages/sessionCommand.js';
7
8
  import { isProcessAlive } from '../../utils/process.js';
@@ -51,6 +52,12 @@ export function formatSessionStatus(metadata, pid, activity, pageState, verbose
51
52
  if (activity.lastNetworkRequestAt) {
52
53
  fmt.keyValue(' Last Request', formatTimeAgo(activity.lastNetworkRequestAt), 18);
53
54
  }
55
+ const evictedNote = networkEvictedNote({
56
+ requestsDropped: activity.networkRequestsDropped ?? 0,
57
+ bodiesEvicted: activity.networkBodiesEvicted ?? 0,
58
+ });
59
+ if (evictedNote)
60
+ fmt.text(` ${evictedNote}`);
54
61
  fmt.keyValue('Console Messages', `${activity.consoleMessagesCaptured} captured`, 18);
55
62
  if (activity.lastConsoleMessageAt) {
56
63
  fmt.keyValue(' Last Message', formatTimeAgo(activity.lastConsoleMessageAt), 18);
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Human output of the network requests a DOM action triggered.
3
3
  */
4
+ import { MAX_TRIGGERED_REQUESTS } from '../../constants.js';
4
5
  import { assetTypeNames, isNotableRequest } from '../../telemetry/requestKinds.js';
5
6
  import { formatRequestStatus } from './requestStatus.js';
6
7
  import { formatDuration, truncateUrl } from '../formatting.js';
@@ -57,7 +58,7 @@ export function formatTriggeredRequestLines(requests, omitted = 0) {
57
58
  const lines = notable.slice(0, MAX_TRIGGERED_REQUESTS_SHOWN).map(formatTriggeredRequest);
58
59
  const hidden = notable.length - lines.length + omitted;
59
60
  if (hidden > 0)
60
- lines.push(omitted > 0 ? moreRequestsNote(hidden) : moreMatchesNote(hidden));
61
+ lines.push(omitted > 0 ? moreRequestsNote(hidden) : moreMatchesNote(hidden, MAX_TRIGGERED_REQUESTS));
61
62
  if (assets.length > 0)
62
63
  lines.push(assetRequestsNote(assets.length, assetTypeNames(assets)));
63
64
  return lines;
@@ -29,7 +29,7 @@ export type LogLevel = 'info' | 'debug';
29
29
  * Log contexts for different components.
30
30
  * Used to prefix log messages with component name.
31
31
  */
32
- export type LogContext = 'bdg' | 'launcher' | 'daemon' | 'client' | 'cleanup' | 'session' | 'chrome' | 'cdp' | 'ipc' | 'http' | 'dialogs' | 'navigation' | 'console' | 'dom' | 'network' | 'diagnostics' | 'readiness' | 'atomic-file' | 'object-expander' | 'fetcher' | 'targets';
32
+ export type LogContext = 'bdg' | 'launcher' | 'daemon' | 'client' | 'cleanup' | 'session' | 'chrome' | 'cdp' | 'ipc' | 'http' | 'dialogs' | 'navigation' | 'page-crash' | 'console' | 'dom' | 'network' | 'diagnostics' | 'readiness' | 'atomic-file' | 'object-expander' | 'fetcher' | 'targets';
33
33
  /**
34
34
  * Logger instance with support for different log levels.
35
35
  */
@@ -158,9 +158,28 @@ export declare function chromeBinaryOverrideIsDirectory(path: string, source: st
158
158
  * Generate error when CDP port is already in use.
159
159
  *
160
160
  * @param port - Port number that is in use
161
+ * @param reason - What was found on the port, when known
161
162
  * @returns Multi-line formatted error message with troubleshooting steps
162
163
  */
163
- export declare function portInUseError(port: number): string;
164
+ export declare function portInUseError(port: number, reason?: string): string;
165
+ /**
166
+ * Why a launched Chrome is not the one answering on 127.0.0.1:<port>.
167
+ *
168
+ * @param answeredBy - What answers there: a different browser, another
169
+ * process, or nothing (the address is held but does not answer)
170
+ * @param chromeHost - Address the launched Chrome listens on
171
+ * @returns Reason for the PORT_IN_USE issue
172
+ */
173
+ export declare function portTakenByReason(answeredBy: 'browser' | 'process' | 'nothing', chromeHost: string): string;
174
+ /**
175
+ * Why a launch failed when Chrome announced its port but did not answer on
176
+ * it in time (a slow start, not a port conflict).
177
+ *
178
+ * @param port - Port Chrome announced
179
+ * @param waitedMs - How long bdg waited
180
+ * @returns Reason for the CHROME_LAUNCH_FAILED issue
181
+ */
182
+ export declare function chromeNotAnsweringReason(port: number, waitedMs: number): string;
164
183
  /**
165
184
  * Warning when bdg's Chrome preferences (password manager and leak check
166
185
  * off, etc.) could not be written into the profile.
@@ -37,7 +37,7 @@ export function formatChromeIssue(issue) {
37
37
  const ctx = issue.context ?? {};
38
38
  switch (issue.code) {
39
39
  case 'PORT_IN_USE':
40
- return portInUseError(ctx['port']);
40
+ return portInUseError(ctx['port'], ctx['reason']);
41
41
  case 'INVALID_PORT':
42
42
  return invalidPortError(ctx['port']);
43
43
  case 'USER_DATA_DIR_CREATE_FAILED':
@@ -274,10 +274,36 @@ export function chromeBinaryOverrideIsDirectory(path, source) {
274
274
  * Generate error when CDP port is already in use.
275
275
  *
276
276
  * @param port - Port number that is in use
277
+ * @param reason - What was found on the port, when known
277
278
  * @returns Multi-line formatted error message with troubleshooting steps
278
279
  */
279
- export function portInUseError(port) {
280
- return joinLines(`Port ${port} is already in use.\n`, 'Another program (or a Chrome left from a previous session) is listening on it.\n', 'Try:', ` - Use a different port: ${sessionCommand(`bdg <url> --port ${port + 1}`)}`, ` - If a bdg session holds it: find it with bdg sessions, then end that one: bdg stop --session <name> (bdg cleanup --force --session <name> if it is stuck)`, ` - See what uses the port: lsof -i :${port}`);
280
+ export function portInUseError(port, reason) {
281
+ return joinLines(reason ? `Port ${port} is already in use: ${reason}.\n` : `Port ${port} is already in use.\n`, 'Another program (or a Chrome left from a previous session) is listening on it.\n', 'Try:', ` - Use a different port: ${sessionCommand(`bdg <url> --port ${port + 1}`)}`, ` - If a bdg session holds it: find it with bdg sessions, then end that one: bdg stop --session <name> (bdg cleanup --force --session <name> if it is stuck)`, ` - See what uses the port: lsof -i :${port}`);
282
+ }
283
+ /**
284
+ * Why a launched Chrome is not the one answering on 127.0.0.1:<port>.
285
+ *
286
+ * @param answeredBy - What answers there: a different browser, another
287
+ * process, or nothing (the address is held but does not answer)
288
+ * @param chromeHost - Address the launched Chrome listens on
289
+ * @returns Reason for the PORT_IN_USE issue
290
+ */
291
+ export function portTakenByReason(answeredBy, chromeHost) {
292
+ if (answeredBy === 'nothing')
293
+ return `something holds 127.0.0.1 (Chrome fell back to ${chromeHost})`;
294
+ const other = answeredBy === 'browser' ? 'another browser' : 'another process';
295
+ return `${other} answers on 127.0.0.1 (Chrome listens on ${chromeHost})`;
296
+ }
297
+ /**
298
+ * Why a launch failed when Chrome announced its port but did not answer on
299
+ * it in time (a slow start, not a port conflict).
300
+ *
301
+ * @param port - Port Chrome announced
302
+ * @param waitedMs - How long bdg waited
303
+ * @returns Reason for the CHROME_LAUNCH_FAILED issue
304
+ */
305
+ export function chromeNotAnsweringReason(port, waitedMs) {
306
+ return `Chrome announced port ${port} but did not answer on 127.0.0.1 within ${(waitedMs / 1000).toFixed(1)}s (slow start)`;
281
307
  }
282
308
  /**
283
309
  * Warning when bdg's Chrome preferences (password manager and leak check
@@ -24,6 +24,13 @@ export declare function chromeClosedMessage(pid?: number): string;
24
24
  * @returns Formatted success message
25
25
  */
26
26
  export declare function orphanedDaemonsCleanedMessage(count: number): string;
27
+ /**
28
+ * Where `bdg install-skill` kept the copy it replaced.
29
+ *
30
+ * @param path - Backup path, as the user would type it
31
+ * @returns One line
32
+ */
33
+ export declare function skillBackupMessage(path: string): string;
27
34
  /**
28
35
  * Warning shown when a click falls back from mouse events to `el.click()`.
29
36
  *
@@ -127,14 +134,43 @@ export declare function valueMismatchWarning(mismatch: FillValueMismatch): strin
127
134
  */
128
135
  export declare 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)";
129
136
  /**
130
- * Note under a shortened list of matches.
137
+ * Note under a shortened human list whose JSON output lists more, up to a cap.
138
+ *
139
+ * @param hidden - Items not listed
140
+ * @param jsonLimit - Most items the JSON output lists
141
+ * @returns e.g. "... and 8980 more (--json lists up to 100)"
142
+ */
143
+ export declare function moreMatchesNote(hidden: number, jsonLimit: number): string;
144
+ /**
145
+ * Note under `dom query` matches cut by `--limit`.
146
+ *
147
+ * @param omitted - Matches not listed
148
+ * @param indexed - Matches usable by index, when not all of them
149
+ * @returns e.g. `... and 49953 more (--limit 0 lists all; indices 0-999 work with other commands)`
150
+ */
151
+ export declare function queryMoreMatchesNote(omitted: number, indexed?: number): string;
152
+ /**
153
+ * Note under `dom query` matches listed past those whose viewport position
154
+ * was checked.
155
+ *
156
+ * @param checked - First matches checked
157
+ * @returns e.g. `Visibility is checked for the first 100 matches only; bdg dom layout <index> checks any of them`
158
+ */
159
+ export declare function queryViewportCheckedNote(checked: number): string;
160
+ /**
161
+ * First line under an accessibility tree cut by `--limit` or `--depth`.
131
162
  *
132
- * @param hidden - Matches not listed
133
- * @param jsonLimit - How many JSON output lists, when it leaves some out too
134
- * @returns e.g. "... and 1174 more (use --json for all)",
135
- * "... and 8980 more (--json lists the first 100)"
163
+ * @param listed - Nodes listed
164
+ * @returns e.g. "Showing the first 50 nodes (text boxes and repeated text left out)"
136
165
  */
137
- export declare function moreMatchesNote(hidden: number, jsonLimit?: number): string;
166
+ export declare function a11yTreeShownNote(listed: number): string;
167
+ /**
168
+ * How to see the rest of an accessibility tree cut by `--limit` or `--depth`.
169
+ *
170
+ * @param omitted - Nodes left out
171
+ * @returns e.g. "51391 more: --limit 0 lists all, --depth <n> limits the levels, or search with bdg dom a11y query \"role:<role>\""
172
+ */
173
+ export declare function a11yTreeMoreNote(omitted: number): string;
138
174
  /**
139
175
  * Note under a list of a11y query matches cut by `--limit`.
140
176
  *
@@ -185,6 +221,31 @@ export declare const LAYOUT_REASONS: {
185
221
  /** Joins an invisible reason to the ancestor causing it */
186
222
  readonly on: " on ";
187
223
  };
224
+ /** Why an out-of-view text's contrast in `dom audit` is approximate: none of its ancestors paints a background */
225
+ export declare const AUDIT_OUT_OF_VIEW_RISK = "only its ancestors were checked";
226
+ /**
227
+ * `dom audit contrast` note for text that looks below the level but cannot
228
+ * be measured exactly (over an image, blended, under or over another layer).
229
+ *
230
+ * @param count - How many such texts
231
+ * @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)`
232
+ */
233
+ export declare function auditUncertainContrastNote(count: number): string;
234
+ /**
235
+ * `dom audit animations` note for canvas elements, whose script-drawn
236
+ * animations it cannot see.
237
+ *
238
+ * @param count - Visible canvas elements
239
+ * @returns e.g. `(+ 2 canvas elements: animations drawn by scripts on them are not listed)`
240
+ */
241
+ export declare function auditCanvasNote(count: number): string;
242
+ /**
243
+ * A mask over an element, for `dom layout` and `dom inspect`.
244
+ *
245
+ * @param masked - The mask, e.g. `mask-image on div.hero`
246
+ * @returns e.g. `masked by mask-image on div.hero`
247
+ */
248
+ export declare function maskedText(masked: string): string;
188
249
  /**
189
250
  * Off-screen reason for an element out of view on a page whose scrolling is
190
251
  * locked, naming the visible dialog that likely locked it when there is one.
@@ -228,16 +289,53 @@ export declare function layoutPositionLabel(element: LabelledLayout, viewport?:
228
289
  * @returns e.g. `prefers-color-scheme: dark (from the system setting)`
229
290
  */
230
291
  export declare function colorSchemeLabel(scheme: string, emulated: boolean): string;
292
+ /**
293
+ * Suggestion for an action that failed on a page that replaced built-ins
294
+ * bdg's page scripts use.
295
+ *
296
+ * @param replaced - Their dotted names (all are named)
297
+ * @returns Suggestion naming them and a way around
298
+ */
299
+ export declare function brokenByReplacedBuiltinsSuggestion(replaced: readonly string[]): string;
300
+ /**
301
+ * Warning on an action when the page replaced built-ins bdg's page scripts
302
+ * use (polyfills, old frameworks, anti-bot scripts). Names the first four;
303
+ * the action's `replacedBuiltins` (JSON) lists them all.
304
+ *
305
+ * @param replaced - Their dotted names
306
+ * @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`
307
+ */
308
+ export declare function replacedBuiltinsWarning(replaced: readonly string[]): string;
231
309
  /**
232
310
  * First line of `bdg status` for a running session.
233
311
  *
234
- * @param page - URL and title of the page, when the session reported them
235
- * @returns e.g. `Session active: https://example.com/ — Example Domain`
312
+ * @param page - URL and title of the page, when the session reported them,
313
+ * and when it crashed
314
+ * @returns e.g. `Session active: https://example.com/ — Example Domain`, with
315
+ * a crash warning on a second line
236
316
  */
237
317
  export declare function sessionActiveLine(page?: {
238
318
  url: string;
239
319
  title: string;
320
+ crashedAt?: number | undefined;
240
321
  }): string;
322
+ /**
323
+ * Warning that the session's page crashed, for `bdg status`, `bdg peek`,
324
+ * `bdg console` and `bdg network list`.
325
+ *
326
+ * @param crashedAt - When it crashed (epoch ms)
327
+ * @returns e.g. `⚠ The page crashed at 18:42:10 (renderer gone); bdg page reload brings it back`
328
+ */
329
+ export declare function pageCrashedNote(crashedAt: number): string;
330
+ /**
331
+ * Put the page-crashed warning before a view of collected data, when the
332
+ * page crashed (what is shown was collected before).
333
+ *
334
+ * @param body - The view
335
+ * @param crashedAt - When the page crashed (epoch ms), if it did
336
+ * @returns The view, after the warning when the page crashed
337
+ */
338
+ export declare function withPageCrashedNote(body: string, crashedAt: number | undefined): string;
241
339
  /**
242
340
  * Page dimensions line of `bdg dom layout`.
243
341
  *
@@ -277,10 +375,11 @@ export declare function coverText(cover: string, transparent: boolean | undefine
277
375
  * Note when `bdg dom inspect` could not read the element's matched rules, so
278
376
  * no hints, rules or why were computed.
279
377
  *
280
- * @param reason - `timeout` (very large stylesheets) or `failed` (Chrome reported an error)
378
+ * @param reason - `timeout` (very large stylesheets), `failed` (Chrome reported
379
+ * an error) or `skipped` (hints not read: an earlier read on this page timed out)
281
380
  * @returns Note
282
381
  */
283
- export declare function inspectCascadeNote(reason: 'timeout' | 'failed'): string;
382
+ export declare function inspectCascadeNote(reason: 'timeout' | 'failed' | 'skipped'): string;
284
383
  /**
285
384
  * Note of `bdg dom inspect` when the selector named a pseudo-element: its
286
385
  * element is inspected and the pseudo-element is on the `pseudo` line.
@@ -405,6 +504,16 @@ export declare function dialogConsoleText(dialog: {
405
504
  type: string;
406
505
  message: string;
407
506
  }): string;
507
+ /**
508
+ * How far a pointer action scrolled the page to reach its element.
509
+ *
510
+ * @param scrolledBy - Page scroll (CSS px)
511
+ * @returns e.g. `page down 1240px to reach it`, `page right 300px, up 80px to reach it`
512
+ */
513
+ export declare function pointerScrollText(scrolledBy: {
514
+ x: number;
515
+ y: number;
516
+ }): string;
408
517
  /** Headline of each pointer action, e.g. "Element Double-clicked" */
409
518
  export declare const POINTER_ACTION_DONE: {
410
519
  readonly click: "Clicked";
@@ -556,9 +665,11 @@ export declare function elementTextLine(text: string): string;
556
665
  *
557
666
  * @param children - First child elements, e.g. `iframe#app`
558
667
  * @param count - Number of child elements
559
- * @returns e.g. `No text; holds 1 element: iframe (see its HTML with --raw)`
668
+ * @param inShadowRoot - The children are those of its shadow root (`--raw` does not show them)
669
+ * @returns e.g. `No text; holds 1 element: iframe (see its HTML with --raw)`,
670
+ * `No text; its shadow root holds 1 element: button "Close" (see it with bdg dom inspect)`
560
671
  */
561
- export declare function emptyElementLine(children: string[], count: number): string;
672
+ export declare function emptyElementLine(children: string[], count: number, inShadowRoot?: boolean): string;
562
673
  /**
563
674
  * Note on a screenshot scaled down to keep its image token cost bounded.
564
675
  *
@@ -600,6 +711,23 @@ export declare function queryNextSteps(index: number): string;
600
711
  * @returns e.g. `Frame: https://pay.example/`
601
712
  */
602
713
  export declare function evalFrameLine(url: string): string;
714
+ /**
715
+ * Warning on a `dom eval` result the browser copied because the page
716
+ * replaced built-ins bdg's own copy uses.
717
+ *
718
+ * @param replaced - Their dotted names (all are named)
719
+ * @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 {}`
720
+ */
721
+ export declare function evalCopiedByBrowserWarning(replaced: readonly string[]): string;
722
+ /**
723
+ * Warning on a `dom eval` result shown as its preview: the page replaced
724
+ * built-ins bdg's copy uses and the browser could not copy it either (a
725
+ * cycle or a BigInt inside).
726
+ *
727
+ * @param replaced - Their dotted names (all are named)
728
+ * @returns Warning that the value is a shortened preview
729
+ */
730
+ export declare function evalPreviewWarning(replaced: readonly string[]): string;
603
731
  /**
604
732
  * Generate warning message.
605
733
  *
@@ -715,5 +843,18 @@ export declare function inspectMidTransitionNote(): string;
715
843
  export declare const AUDIT_HELP_EXAMPLES = "\nExamples:\n bdg dom audit All checks\n bdg dom audit contrast --level AAA Text below WCAG AAA, weakest first\n bdg dom audit overflow What scrolls sideways, cut-off text, scaled images\n bdg dom audit layers animations Fixed/sticky elements and running animations\n\nFollow up on a finding with bdg dom inspect <element> (e.g. --why color).";
716
844
  /** Examples under `bdg css search --help` */
717
845
  export declare const CSS_SEARCH_HELP_EXAMPLES = "\nExamples:\n bdg css search -- --brand Where a custom property is set and used (-- before a text\n that starts with -; options go before it:\n bdg css search --limit 50 -- --brand)\n bdg css search \"oklch(\" Rules that use oklch colors\n bdg css search \".btn-primary\" Rules of a class, in every stylesheet";
846
+ /**
847
+ * `details` field of `bdg --help --json`: where the full help is.
848
+ *
849
+ * @returns Note
850
+ */
851
+ export declare function helpJsonDetailsNote(): string;
852
+ /**
853
+ * Pointer after a value cut for human output.
854
+ *
855
+ * @param count - Characters left out
856
+ * @returns e.g. `… 299800 more chars (use --full)`
857
+ */
858
+ export declare function moreCharsNote(count: number): string;
718
859
  export {};
719
860
  //# sourceMappingURL=commands.d.ts.map