browser-debugger-cli 0.12.0 → 0.13.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 (180) hide show
  1. package/.claude/skills/bdg/SKILL.md +4 -4
  2. package/README.md +1 -0
  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 +62 -12
  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.js +3 -2
  10. package/dist/commands/dom/eval.d.ts +3 -2
  11. package/dist/commands/dom/eval.js +11 -5
  12. package/dist/commands/dom/form.js +10 -9
  13. package/dist/commands/dom/formInteraction.js +8 -7
  14. package/dist/commands/dom/get.js +8 -8
  15. package/dist/commands/dom/helpers/index.d.ts +1 -1
  16. package/dist/commands/dom/helpers/index.js +1 -1
  17. package/dist/commands/dom/helpers/query.d.ts +27 -3
  18. package/dist/commands/dom/helpers/query.js +152 -64
  19. package/dist/commands/dom/helpers/screenshot.js +13 -13
  20. package/dist/commands/dom/index.js +4 -2
  21. package/dist/commands/dom/query.d.ts +19 -2
  22. package/dist/commands/dom/query.js +37 -6
  23. package/dist/commands/dom/screenshot.js +2 -1
  24. package/dist/commands/dom/semanticUtils.d.ts +3 -2
  25. package/dist/commands/dom/semanticUtils.js +40 -9
  26. package/dist/commands/helpJson.d.ts +82 -19
  27. package/dist/commands/helpJson.js +111 -40
  28. package/dist/commands/helpTopic.d.ts +16 -1
  29. package/dist/commands/helpTopic.js +59 -1
  30. package/dist/commands/installSkill.d.ts +15 -5
  31. package/dist/commands/installSkill.js +86 -16
  32. package/dist/commands/network/list.js +22 -12
  33. package/dist/commands/optionBehaviors.js +33 -11
  34. package/dist/commands/shared/daemonErrorHandler.d.ts +5 -2
  35. package/dist/commands/shared/daemonErrorHandler.js +20 -9
  36. package/dist/commands/shared/dataFetcher.d.ts +12 -4
  37. package/dist/commands/shared/dataFetcher.js +12 -4
  38. package/dist/commands/shared/followMode.d.ts +9 -1
  39. package/dist/commands/shared/followMode.js +22 -4
  40. package/dist/commands/shared/optionTypes.d.ts +4 -1
  41. package/dist/commands/shared/outputFile.js +6 -1
  42. package/dist/commands/start.d.ts +7 -5
  43. package/dist/commands/start.js +65 -21
  44. package/dist/commands/stop.d.ts +11 -0
  45. package/dist/commands/stop.js +24 -1
  46. package/dist/commands.js +1 -1
  47. package/dist/connection/cdp.d.ts +7 -0
  48. package/dist/connection/cdp.js +9 -0
  49. package/dist/connection/launcher.js +3 -2
  50. package/dist/daemon/SessionController.js +6 -1
  51. package/dist/daemon/launcher.d.ts +3 -2
  52. package/dist/daemon/launcher.js +47 -3
  53. package/dist/daemon/session/Session.d.ts +4 -1
  54. package/dist/daemon/session/Session.js +33 -2
  55. package/dist/daemon/session/TelemetryStore.d.ts +8 -1
  56. package/dist/daemon/session/TelemetryStore.js +13 -1
  57. package/dist/daemon/session/commandRegistry.js +29 -13
  58. package/dist/daemon/session/interactions.d.ts +2 -1
  59. package/dist/daemon/session/interactions.js +13 -1
  60. package/dist/daemon/session/plugins.js +16 -2
  61. package/dist/daemon/session/teardown.js +1 -1
  62. package/dist/daemon.js +1622 -748
  63. package/dist/errors/messages.d.ts +54 -11
  64. package/dist/errors/messages.js +109 -22
  65. package/dist/index.js +13733 -8796
  66. package/dist/ipc/client.d.ts +18 -2
  67. package/dist/ipc/client.js +26 -5
  68. package/dist/ipc/protocol/auditTypes.d.ts +8 -2
  69. package/dist/ipc/protocol/commands.d.ts +12 -0
  70. package/dist/ipc/protocol/domTypes.d.ts +12 -0
  71. package/dist/ipc/protocol/inspectTypes.d.ts +2 -0
  72. package/dist/ipc/session/types.d.ts +2 -0
  73. package/dist/runtime/dom/actionEffects.d.ts +5 -1
  74. package/dist/runtime/dom/actionEffects.js +26 -14
  75. package/dist/runtime/dom/audit.js +3 -2
  76. package/dist/runtime/dom/auditModel.js +6 -1
  77. package/dist/runtime/dom/auditScripts.d.ts +9 -3
  78. package/dist/runtime/dom/auditScripts.js +41 -5
  79. package/dist/runtime/dom/elementGeometry.d.ts +10 -3
  80. package/dist/runtime/dom/elementGeometry.js +27 -4
  81. package/dist/runtime/dom/elementInfo.d.ts +74 -18
  82. package/dist/runtime/dom/elementInfo.js +187 -40
  83. package/dist/runtime/dom/evalHelpers.d.ts +12 -2
  84. package/dist/runtime/dom/evalHelpers.js +67 -7
  85. package/dist/runtime/dom/formDiscovery.d.ts +6 -2
  86. package/dist/runtime/dom/formDiscovery.js +20 -3
  87. package/dist/runtime/dom/formFillHelpers/fill.js +7 -11
  88. package/dist/runtime/dom/formFillHelpers/pressKey.js +2 -2
  89. package/dist/runtime/dom/formFillHelpers/shared.d.ts +16 -10
  90. package/dist/runtime/dom/formFillHelpers/shared.js +19 -52
  91. package/dist/runtime/dom/formSubmitHelpers.js +4 -3
  92. package/dist/runtime/dom/frameLayout.js +1 -0
  93. package/dist/runtime/dom/inspect.js +5 -6
  94. package/dist/runtime/dom/inspectAllStyles.js +1 -0
  95. package/dist/runtime/dom/inspectHints.d.ts +1 -1
  96. package/dist/runtime/dom/inspectModel.d.ts +2 -1
  97. package/dist/runtime/dom/inspectModel.js +7 -3
  98. package/dist/runtime/dom/inspectPaintModel.d.ts +2 -0
  99. package/dist/runtime/dom/inspectPaintModel.js +3 -1
  100. package/dist/runtime/dom/inspectScripts.d.ts +29 -2
  101. package/dist/runtime/dom/inspectScripts.js +49 -10
  102. package/dist/runtime/dom/layout.js +9 -7
  103. package/dist/runtime/dom/reactEventHelpers.d.ts +14 -4
  104. package/dist/runtime/dom/reactEventHelpers.js +63 -27
  105. package/dist/runtime/dom/targetNode.d.ts +18 -5
  106. package/dist/runtime/dom/targetNode.js +268 -8
  107. package/dist/runtime/dom/wait.js +2 -1
  108. package/dist/runtime/page/bdgWorld.d.ts +57 -0
  109. package/dist/runtime/page/bdgWorld.js +180 -0
  110. package/dist/runtime/page/replacedBuiltins.d.ts +28 -0
  111. package/dist/runtime/page/replacedBuiltins.js +136 -0
  112. package/dist/session/QueryCacheManager.d.ts +4 -1
  113. package/dist/session/QueryCacheManager.js +5 -2
  114. package/dist/session/chrome.d.ts +4 -1
  115. package/dist/session/chrome.js +7 -1
  116. package/dist/session/cleanup/staleSession.d.ts +21 -4
  117. package/dist/session/cleanup/staleSession.js +79 -9
  118. package/dist/session/cleanup/userCommands.d.ts +4 -1
  119. package/dist/session/cleanup/userCommands.js +10 -5
  120. package/dist/session/daemonSocket.d.ts +10 -0
  121. package/dist/session/daemonSocket.js +22 -0
  122. package/dist/session/lastSession.d.ts +6 -3
  123. package/dist/session/lastSession.js +11 -5
  124. package/dist/session/paths.d.ts +3 -1
  125. package/dist/session/paths.js +5 -5
  126. package/dist/session/portClaims.js +4 -3
  127. package/dist/session/sessionList.d.ts +13 -5
  128. package/dist/session/sessionList.js +31 -7
  129. package/dist/telemetry/a11y.js +2 -2
  130. package/dist/telemetry/console.d.ts +2 -1
  131. package/dist/telemetry/console.js +30 -21
  132. package/dist/telemetry/pageCrash.d.ts +26 -0
  133. package/dist/telemetry/pageCrash.js +53 -0
  134. package/dist/types.d.ts +16 -0
  135. package/dist/ui/formatters/audit.js +14 -5
  136. package/dist/ui/formatters/cdp.d.ts +138 -0
  137. package/dist/ui/formatters/cdp.js +131 -0
  138. package/dist/ui/formatters/console/chronological.js +3 -1
  139. package/dist/ui/formatters/console/follow.d.ts +2 -1
  140. package/dist/ui/formatters/console/follow.js +2 -2
  141. package/dist/ui/formatters/console/json.d.ts +2 -2
  142. package/dist/ui/formatters/console/json.js +11 -5
  143. package/dist/ui/formatters/console/shared.d.ts +30 -0
  144. package/dist/ui/formatters/console/shared.js +16 -0
  145. package/dist/ui/formatters/console/summarize.d.ts +9 -2
  146. package/dist/ui/formatters/console/summarize.js +40 -9
  147. package/dist/ui/formatters/console.d.ts +2 -1
  148. package/dist/ui/formatters/console.js +7 -5
  149. package/dist/ui/formatters/details.js +3 -1
  150. package/dist/ui/formatters/dom.d.ts +1 -1
  151. package/dist/ui/formatters/dom.js +5 -6
  152. package/dist/ui/formatters/helpFormatters.js +1 -1
  153. package/dist/ui/formatters/inspect.js +9 -3
  154. package/dist/ui/formatters/installSkill.d.ts +9 -1
  155. package/dist/ui/formatters/installSkill.js +32 -6
  156. package/dist/ui/formatters/layout.js +2 -1
  157. package/dist/ui/formatters/networkList.d.ts +1 -1
  158. package/dist/ui/formatters/networkList.js +1 -2
  159. package/dist/ui/formatters/preview.d.ts +2 -0
  160. package/dist/ui/formatters/preview.js +17 -7
  161. package/dist/ui/formatters/sessions.d.ts +2 -2
  162. package/dist/ui/formatters/sessions.js +9 -2
  163. package/dist/ui/logging/logger.d.ts +1 -1
  164. package/dist/ui/messages/commands.d.ts +124 -4
  165. package/dist/ui/messages/commands.js +162 -7
  166. package/dist/ui/messages/consoleMessages.d.ts +24 -0
  167. package/dist/ui/messages/consoleMessages.js +32 -0
  168. package/dist/ui/messages/preview.d.ts +6 -0
  169. package/dist/ui/messages/preview.js +9 -1
  170. package/dist/ui/messages/session.d.ts +13 -2
  171. package/dist/ui/messages/session.js +22 -3
  172. package/dist/utils/directories.d.ts +34 -0
  173. package/dist/utils/directories.js +88 -0
  174. package/dist/utils/display.d.ts +16 -0
  175. package/dist/utils/display.js +42 -0
  176. package/dist/utils/exitCodes.d.ts +1 -0
  177. package/dist/utils/exitCodes.js +6 -0
  178. package/dist/utils/process.d.ts +12 -0
  179. package/dist/utils/process.js +25 -0
  180. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Human output of `bdg dom audit` and `bdg css search`.
3
3
  */
4
+ import { auditCanvasNote, auditUncertainContrastNote } from '../messages/commands.js';
4
5
  import { truncateByLength } from '../../utils/strings.js';
5
6
  /** Width of the text quoted in a finding */
6
7
  const TEXT_WIDTH = 50;
@@ -15,7 +16,7 @@ export function formatAudit(data) {
15
16
  data.contrast && contrastSection(data.contrast),
16
17
  data.overflow && overflowSection(data.overflow),
17
18
  data.layers && layersSection(data.layers),
18
- data.animations && animationsSection(data.animations),
19
+ data.animations && animationsSection(data.animations, data.canvases),
19
20
  ].filter((section) => section !== undefined);
20
21
  const capped = data.capped ? [`(stopped after ${data.walked} elements; the page has more)`] : [];
21
22
  return [...sections.flatMap((lines) => [...lines, '']), ...capped].join('\n').trimEnd();
@@ -28,9 +29,14 @@ export function formatAudit(data) {
28
29
  */
29
30
  function contrastSection(contrast) {
30
31
  const head = `Contrast (${contrast.level}): ${contrast.failing} of ${contrast.checked} text elements below`;
31
- const rows = contrast.items.map((item) => ` ${item.ratio.toFixed(2).padStart(5)} ${item.color} on ${item.background} ${item.element} "${truncateByLength(item.text, TEXT_WIDTH)}" ${item.size}px${item.weight >= 700 ? ' bold' : ''}${item.inView ? '' : ' (out of view)'}${item.approximate ? ` (approximate: ${item.approximate.join(', ')})` : ''}`);
32
+ const rows = contrast.items.map((item) => ` ${item.ratio.toFixed(2).padStart(5)} ${item.color} on ${item.background} ${item.element} "${truncateByLength(item.text, TEXT_WIDTH)}" ${item.size}px${item.weight >= 700 ? ' bold' : ''}${item.opacity !== undefined ? ` (faded: opacity ${item.opacity})` : ''}${item.inView ? '' : ' (out of view)'}`);
32
33
  const more = contrast.failing - contrast.items.length;
33
- return [head, ...rows, ...(more > 0 ? [` (+${more} more; --limit to list them)`] : [])];
34
+ return [
35
+ head,
36
+ ...rows,
37
+ ...(more > 0 ? [` (+${more} more; --limit to list them)`] : []),
38
+ ...(contrast.uncertain ? [` ${auditUncertainContrastNote(contrast.uncertain)}`] : []),
39
+ ];
34
40
  }
35
41
  /**
36
42
  * The overflow section.
@@ -77,14 +83,17 @@ function layersSection(layers) {
77
83
  * The animations section.
78
84
  *
79
85
  * @param animations - Running animations
86
+ * @param canvases - Visible canvas elements
80
87
  * @returns Lines
81
88
  */
82
- function animationsSection(animations) {
89
+ function animationsSection(animations, canvases) {
90
+ const note = canvases ? [` ${auditCanvasNote(canvases)}`] : [];
83
91
  if (animations.length === 0)
84
- return ['Animations: none running'];
92
+ return ['Animations: none running', ...note];
85
93
  return [
86
94
  `Animations: ${animations.length} running`,
87
95
  ...animations.map((animation) => ` ${animation.name} on ${animation.element}${times(animation.count)} (${animation.type}, ${typeof animation.duration === 'number' ? `${animation.duration}ms` : animation.duration}, ${animation.iterations === 'infinite' ? 'infinite' : `${animation.iterations}x`}${animation.scrollDriven ? ', scroll-driven' : ''})`),
96
+ ...note,
88
97
  ];
89
98
  }
90
99
  /**
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Human-readable output of `bdg cdp`: search results, domain and method
3
+ * lists, method schemas and method results (`--json` prints the data as is).
4
+ */
5
+ import type { ParameterSchema, ReturnSchema } from '../../cdp/schema.js';
6
+ /** Protocol description and flags shared by domains and methods */
7
+ interface ProtocolEntry {
8
+ description?: string | undefined;
9
+ experimental?: boolean | undefined;
10
+ deprecated?: boolean | undefined;
11
+ }
12
+ /** A method in `bdg cdp --search` results */
13
+ interface CdpSearchMethod extends ProtocolEntry {
14
+ name: string;
15
+ domain: string;
16
+ method: string;
17
+ parameterCount: number;
18
+ example?: string | undefined;
19
+ }
20
+ /** `bdg cdp --search <query>` result */
21
+ export interface CdpSearchData {
22
+ query: string;
23
+ count: number;
24
+ methods: CdpSearchMethod[];
25
+ }
26
+ /** A domain in `bdg cdp --list` */
27
+ interface CdpDomainEntry extends ProtocolEntry {
28
+ name: string;
29
+ commands: number;
30
+ events: number;
31
+ dependencies?: string[] | undefined;
32
+ }
33
+ /** `bdg cdp --list` result */
34
+ export interface CdpDomainListData {
35
+ count: number;
36
+ domains: CdpDomainEntry[];
37
+ }
38
+ /** A method in `bdg cdp <Domain> --list` */
39
+ interface CdpDomainMethod extends ProtocolEntry {
40
+ name: string;
41
+ fullName: string;
42
+ parameterCount: number;
43
+ parameters: Pick<ParameterSchema, 'name' | 'type' | 'required'>[];
44
+ returns: Pick<ReturnSchema, 'name' | 'type'>[];
45
+ example?: string | undefined;
46
+ }
47
+ /** `bdg cdp <Domain> --list` result */
48
+ export interface CdpDomainMethodsData {
49
+ domain: string;
50
+ description?: string | undefined;
51
+ count: number;
52
+ methods: CdpDomainMethod[];
53
+ }
54
+ /** `bdg cdp <Domain> --describe` result */
55
+ export interface CdpDomainDescription extends ProtocolEntry {
56
+ type: 'domain';
57
+ domain: string;
58
+ commands: number;
59
+ events: number;
60
+ note?: string | undefined;
61
+ nextStep: string;
62
+ }
63
+ /** A parameter or return value in `bdg cdp <Domain.method> --describe` */
64
+ interface CdpField {
65
+ name: string;
66
+ type: string;
67
+ description?: string | undefined;
68
+ items?: string | undefined;
69
+ }
70
+ /** `bdg cdp <Domain.method> --describe` result */
71
+ export interface CdpMethodDescription extends ProtocolEntry {
72
+ type: 'method';
73
+ name: string;
74
+ domain: string;
75
+ method: string;
76
+ note?: string | undefined;
77
+ parameters: (CdpField & {
78
+ required: boolean;
79
+ enum?: string[] | undefined;
80
+ deprecated?: boolean | undefined;
81
+ })[];
82
+ returns: (CdpField & {
83
+ optional: boolean;
84
+ })[];
85
+ example?: {
86
+ command: string;
87
+ params?: Record<string, unknown> | undefined;
88
+ } | undefined;
89
+ }
90
+ /** `bdg cdp <Domain.method>` result */
91
+ export interface CdpExecuteData {
92
+ method: string;
93
+ result: unknown;
94
+ }
95
+ /**
96
+ * Format `bdg cdp --search <query>`.
97
+ *
98
+ * @param data - Search result
99
+ * @returns Matching methods with their first description sentence
100
+ */
101
+ export declare function formatCdpSearch(data: CdpSearchData): string;
102
+ /**
103
+ * Format `bdg cdp --list`.
104
+ *
105
+ * @param data - All domains
106
+ * @returns One line per domain with its method and event counts
107
+ */
108
+ export declare function formatCdpDomains(data: CdpDomainListData): string;
109
+ /**
110
+ * Format `bdg cdp <Domain> --list`.
111
+ *
112
+ * @param data - The domain's methods
113
+ * @returns One line per method with the first sentence of its description
114
+ */
115
+ export declare function formatCdpDomainMethods(data: CdpDomainMethodsData): string;
116
+ /**
117
+ * Format `bdg cdp <Domain.method> --describe` or `bdg cdp <Domain> --describe`.
118
+ *
119
+ * @param data - Method or domain description
120
+ * @returns Description, parameters (`?` = optional), returns, note and example
121
+ */
122
+ export declare function formatCdpDescription(data: CdpMethodDescription | CdpDomainDescription): string;
123
+ /**
124
+ * Whether a CDP method returned nothing (null, undefined or an empty object).
125
+ *
126
+ * @param result - Method result
127
+ * @returns True for an empty result
128
+ */
129
+ export declare function isEmptyCdpResult(result: unknown): boolean;
130
+ /**
131
+ * Format a CDP method's result: the result object as indented JSON.
132
+ *
133
+ * @param data - Method and its result
134
+ * @returns The result, or a line saying the method returned nothing
135
+ */
136
+ export declare function formatCdpResult(data: CdpExecuteData): string;
137
+ export {};
138
+ //# sourceMappingURL=cdp.d.ts.map
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Human-readable output of `bdg cdp`: search results, domain and method
3
+ * lists, method schemas and method results (`--json` prints the data as is).
4
+ */
5
+ import { joinLines, pluralize } from '../formatting.js';
6
+ /**
7
+ * First sentence (or line) of a protocol description.
8
+ *
9
+ * @param description - Description, possibly multi-line
10
+ * @returns Its first sentence, or an empty string
11
+ */
12
+ function firstSentence(description) {
13
+ const [line = ''] = (description ?? '').split('\n');
14
+ const end = line.indexOf('. ');
15
+ return end === -1 ? line : line.slice(0, end + 1);
16
+ }
17
+ /**
18
+ * `(experimental, deprecated)` tags, or nothing.
19
+ *
20
+ * @param flags - Protocol flags
21
+ * @returns Tag text with a leading space, or an empty string
22
+ */
23
+ function tags(flags) {
24
+ const names = [flags.experimental && 'experimental', flags.deprecated && 'deprecated'].filter(Boolean);
25
+ return names.length > 0 ? ` (${names.join(', ')})` : '';
26
+ }
27
+ /**
28
+ * Rows of a name column padded to one width, then the rest.
29
+ *
30
+ * @param rows - Name and text of each row
31
+ * @returns Indented lines
32
+ */
33
+ function columns(rows) {
34
+ const width = Math.max(0, ...rows.map(([name]) => name.length));
35
+ return rows.map(([name, text]) => ` ${name.padEnd(width)} ${text.trim()}`.trimEnd());
36
+ }
37
+ /**
38
+ * A type as written in the schema, e.g. "array<Cookie>".
39
+ *
40
+ * @param field - Parameter or return value
41
+ * @returns Type text
42
+ */
43
+ function typeText(field) {
44
+ return field.items ? `${field.type}<${field.items}>` : field.type;
45
+ }
46
+ /**
47
+ * Format `bdg cdp --search <query>`.
48
+ *
49
+ * @param data - Search result
50
+ * @returns Matching methods with their first description sentence
51
+ */
52
+ export function formatCdpSearch(data) {
53
+ if (data.count === 0) {
54
+ return joinLines(`No CDP method matches "${data.query}"`, 'List the domains: bdg cdp --list');
55
+ }
56
+ return joinLines(`${pluralize(data.count, 'method')} ${data.count === 1 ? 'matches' : 'match'} "${data.query}":`, ...columns(data.methods.map((m) => [m.name, `${firstSentence(m.description)}${tags(m)}`])), 'Parameters and an example: bdg cdp <Domain.method> --describe');
57
+ }
58
+ /**
59
+ * Format `bdg cdp --list`.
60
+ *
61
+ * @param data - All domains
62
+ * @returns One line per domain with its method and event counts
63
+ */
64
+ export function formatCdpDomains(data) {
65
+ return joinLines(`${pluralize(data.count, 'CDP domain')}:`, ...columns(data.domains.map((d) => [
66
+ d.name,
67
+ `${pluralize(d.commands, 'method')}, ${pluralize(d.events, 'event')}${tags(d)}`,
68
+ ])), 'Methods of a domain: bdg cdp <Domain> --list');
69
+ }
70
+ /**
71
+ * Format `bdg cdp <Domain> --list`.
72
+ *
73
+ * @param data - The domain's methods
74
+ * @returns One line per method with the first sentence of its description
75
+ */
76
+ export function formatCdpDomainMethods(data) {
77
+ return joinLines(`${data.domain}: ${pluralize(data.count, 'method')}`, firstSentence(data.description) || undefined, ...columns(data.methods.map((m) => [m.name, `${firstSentence(m.description)}${tags(m)}`])), `Parameters and an example: bdg cdp ${data.domain}.<method> --describe`);
78
+ }
79
+ /**
80
+ * Lines of a parameter or return value list.
81
+ *
82
+ * @param title - Section title
83
+ * @param fields - Parameters or return values
84
+ * @returns Title and one line per field, or nothing for an empty list
85
+ */
86
+ function fieldSection(title, fields) {
87
+ if (fields.length === 0)
88
+ return [];
89
+ return [
90
+ `${title}:`,
91
+ ...columns(fields.map((f) => [
92
+ `${f.name}${f.optional ? '?' : ''}: ${typeText(f)}`,
93
+ (f.description ?? '').replace(/\s*\n\s*/g, ' '),
94
+ ])),
95
+ ];
96
+ }
97
+ /**
98
+ * Format `bdg cdp <Domain.method> --describe` or `bdg cdp <Domain> --describe`.
99
+ *
100
+ * @param data - Method or domain description
101
+ * @returns Description, parameters (`?` = optional), returns, note and example
102
+ */
103
+ export function formatCdpDescription(data) {
104
+ if (data.type === 'domain') {
105
+ return joinLines(`${data.domain}: ${pluralize(data.commands, 'method')}, ${pluralize(data.events, 'event')}${tags(data)}`, data.description, data.note, data.nextStep);
106
+ }
107
+ return joinLines(`${data.name}${tags(data)}`, data.description, ...fieldSection('Parameters', data.parameters.map((p) => ({ ...p, optional: !p.required }))), ...fieldSection('Returns', data.returns), data.note && `Note: ${data.note}`, data.example && `Example: ${data.example.command}`);
108
+ }
109
+ /**
110
+ * Whether a CDP method returned nothing (null, undefined or an empty object).
111
+ *
112
+ * @param result - Method result
113
+ * @returns True for an empty result
114
+ */
115
+ export function isEmptyCdpResult(result) {
116
+ return (result === null ||
117
+ result === undefined ||
118
+ (typeof result === 'object' && Object.keys(result).length === 0));
119
+ }
120
+ /**
121
+ * Format a CDP method's result: the result object as indented JSON.
122
+ *
123
+ * @param data - Method and its result
124
+ * @returns The result, or a line saying the method returned nothing
125
+ */
126
+ export function formatCdpResult(data) {
127
+ return isEmptyCdpResult(data.result)
128
+ ? `${data.method}: done (no result data)`
129
+ : JSON.stringify(data.result, null, 2);
130
+ }
131
+ //# sourceMappingURL=cdp.js.map
@@ -3,7 +3,7 @@
3
3
  * level prefixes, and navigation reload markers.
4
4
  */
5
5
  import { OutputFormatter } from '../../formatting.js';
6
- import { consoleIndexGapNote } from '../../messages/consoleMessages.js';
6
+ import { consoleDroppedNote, consoleIndexGapNote } from '../../messages/consoleMessages.js';
7
7
  import { truncateByLength } from '../../../utils/strings.js';
8
8
  import { formatSourceLocation, formatTimestamp } from './shared.js';
9
9
  const MAX_LIST_TEXT_LENGTH = 200;
@@ -22,6 +22,8 @@ export function formatConsoleChronological(messages, options) {
22
22
  : `Console Messages (last ${displayMessages.length} of ${messages.length})${headerSuffix}`;
23
23
  fmt.text(header);
24
24
  fmt.separator('━', 50);
25
+ if (options.dropped)
26
+ fmt.text(consoleDroppedNote(options.dropped));
25
27
  if (displayMessages.length === 0) {
26
28
  fmt.text('No console messages');
27
29
  return fmt.build();
@@ -5,7 +5,8 @@
5
5
  import type { ConsoleMessage } from '../../../types.js';
6
6
  /**
7
7
  * Lines of the console stream: the new messages since the last poll, with
8
- * the stream header the first time and a separator after a navigation.
8
+ * a rule the first time (the stream banner is on stderr) and a separator
9
+ * after a navigation.
9
10
  *
10
11
  * @param messages - New messages
11
12
  * @param options - `header` the first time; `navigationId` when the page changed
@@ -6,7 +6,8 @@ import { OutputFormatter } from '../../formatting.js';
6
6
  import { formatSourceLocation, formatTimestamp } from './shared.js';
7
7
  /**
8
8
  * Lines of the console stream: the new messages since the last poll, with
9
- * the stream header the first time and a separator after a navigation.
9
+ * a rule the first time (the stream banner is on stderr) and a separator
10
+ * after a navigation.
10
11
  *
11
12
  * @param messages - New messages
12
13
  * @param options - `header` the first time; `navigationId` when the page changed
@@ -15,7 +16,6 @@ import { formatSourceLocation, formatTimestamp } from './shared.js';
15
16
  export function formatConsoleFollowLines(messages, options = {}) {
16
17
  const fmt = new OutputFormatter();
17
18
  if (options.header) {
18
- fmt.text('Streaming console... (Ctrl+C to stop)');
19
19
  fmt.separator('━', 40);
20
20
  if (messages.length === 0)
21
21
  fmt.text('Waiting for messages...');
@@ -6,8 +6,8 @@
6
6
  import type { ConsoleMessage } from '../../../types.js';
7
7
  import { type ConsoleFormatOptions, type ConsoleJsonOutput } from './shared.js';
8
8
  /**
9
- * Build the rich JSON output shape (summary + deduped errors/warnings, plus
10
- * the full message list when --list is requested).
9
+ * Build the rich JSON output shape (summary + the newest deduped
10
+ * errors/warnings, plus the message list when --list is requested).
11
11
  *
12
12
  * Returns a plain object so callers (e.g. runCommand's JSON envelope) can
13
13
  * embed it without re-parsing a stringified payload.
@@ -4,7 +4,7 @@
4
4
  * --list is set.
5
5
  */
6
6
  import { lastMessages } from './chronological.js';
7
- import { analyzeMessages, } from './shared.js';
7
+ import { analyzeMessages, newestGroups, } from './shared.js';
8
8
  function toJsonError(dedup, includeStackTrace) {
9
9
  const source = dedup.message.stackTrace?.[0];
10
10
  return {
@@ -25,18 +25,24 @@ function toJsonError(dedup, includeStackTrace) {
25
25
  };
26
26
  }
27
27
  /**
28
- * Build the rich JSON output shape (summary + deduped errors/warnings, plus
29
- * the full message list when --list is requested).
28
+ * Build the rich JSON output shape (summary + the newest deduped
29
+ * errors/warnings, plus the message list when --list is requested).
30
30
  *
31
31
  * Returns a plain object so callers (e.g. runCommand's JSON envelope) can
32
32
  * embed it without re-parsing a stringified payload.
33
33
  */
34
34
  export function buildConsoleJsonOutput(messages, options) {
35
35
  const { grouped, summary } = analyzeMessages(messages);
36
+ const errors = newestGroups(grouped.errors, options.groupLimit);
37
+ const warnings = newestGroups(grouped.warnings, options.groupLimit);
36
38
  const output = {
37
39
  summary,
38
- errors: grouped.errors.map((d) => toJsonError(d, true)),
39
- warnings: grouped.warnings.map((d) => toJsonError(d, false)),
40
+ errors: errors.shown.map((d) => toJsonError(d, true)),
41
+ warnings: warnings.shown.map((d) => toJsonError(d, false)),
42
+ ...(errors.more > 0 && { moreErrors: errors.more }),
43
+ ...(warnings.more > 0 && { moreWarnings: warnings.more }),
44
+ ...(options.dropped && { dropped: options.dropped }),
45
+ ...(options.pageCrashedAt !== undefined && { pageCrashedAt: options.pageCrashedAt }),
40
46
  };
41
47
  if (options.list)
42
48
  output.messages = lastMessages(messages, options.last);
@@ -57,7 +57,27 @@ export interface ConsoleFormatOptions {
57
57
  level?: ConsoleLevel | undefined;
58
58
  /** Messages between the first and last listed index that the filters left out */
59
59
  skipped?: ConsoleSkipped | undefined;
60
+ /** Distinct errors and warnings listed, the newest (0 = all; default {@link DEFAULT_GROUP_LIMIT}) */
61
+ groupLimit?: number | undefined;
62
+ /** Oldest messages the session dropped at its limit */
63
+ dropped?: number | undefined;
64
+ /** When the page crashed (epoch ms), while it is not loaded again */
65
+ pageCrashedAt?: number | undefined;
60
66
  }
67
+ /** Distinct errors and warnings the summary lists without `--last` */
68
+ export declare const DEFAULT_GROUP_LIMIT = 50;
69
+ /**
70
+ * The newest distinct messages of a level, and how many earlier ones are not
71
+ * listed.
72
+ *
73
+ * @param groups - Distinct messages, in order of first appearance
74
+ * @param limit - How many to keep (0 = all; undefined: {@link DEFAULT_GROUP_LIMIT})
75
+ * @returns Groups to list and the count left out
76
+ */
77
+ export declare function newestGroups(groups: DeduplicatedMessage[], limit: number | undefined): {
78
+ shown: DeduplicatedMessage[];
79
+ more: number;
80
+ };
61
81
  /**
62
82
  * Messages the page and level filters left out between the first and last
63
83
  * listed index (session indices then skip numbers).
@@ -90,8 +110,18 @@ export interface JsonErrorEntry {
90
110
  */
91
111
  export interface ConsoleJsonOutput {
92
112
  summary: ConsoleSummary;
113
+ /** The newest distinct errors (see `moreErrors`) */
93
114
  errors: JsonErrorEntry[];
115
+ /** The newest distinct warnings (see `moreWarnings`) */
94
116
  warnings: Omit<JsonErrorEntry, 'stackTrace'>[];
117
+ /** Earlier distinct errors not in `errors` (`--last 0` lists all) */
118
+ moreErrors?: number;
119
+ /** Earlier distinct warnings not in `warnings` */
120
+ moreWarnings?: number;
121
+ /** Oldest messages the session dropped at its limit (10000 are kept) */
122
+ dropped?: number;
123
+ /** When the page crashed (epoch ms), while it is not loaded again */
124
+ pageCrashedAt?: number;
95
125
  messages?: ConsoleMessage[];
96
126
  }
97
127
  /**
@@ -1,6 +1,22 @@
1
1
  /**
2
2
  * Shared types, constants, and helpers used by every console formatter.
3
3
  */
4
+ /** Distinct errors and warnings the summary lists without `--last` */
5
+ export const DEFAULT_GROUP_LIMIT = 50;
6
+ /**
7
+ * The newest distinct messages of a level, and how many earlier ones are not
8
+ * listed.
9
+ *
10
+ * @param groups - Distinct messages, in order of first appearance
11
+ * @param limit - How many to keep (0 = all; undefined: {@link DEFAULT_GROUP_LIMIT})
12
+ * @returns Groups to list and the count left out
13
+ */
14
+ export function newestGroups(groups, limit) {
15
+ const keep = limit ?? DEFAULT_GROUP_LIMIT;
16
+ if (keep === 0 || groups.length <= keep)
17
+ return { shown: groups, more: 0 };
18
+ return { shown: groups.slice(-keep), more: groups.length - keep };
19
+ }
4
20
  /**
5
21
  * Mapping from console message types to level categories.
6
22
  * Exported for use by console command filtering.
@@ -3,8 +3,15 @@
3
3
  * and shows info/debug/other as count-only footer entries.
4
4
  */
5
5
  import type { ConsoleMessage } from '../../../types.js';
6
+ import { type ConsoleFormatOptions } from './shared.js';
6
7
  /**
7
- * Format console output as smart summary (default mode).
8
+ * Format console output as smart summary (default mode): the newest distinct
9
+ * errors and warnings, counts of the rest, and a note when the session
10
+ * dropped its oldest messages.
11
+ *
12
+ * @param messages - Messages to summarise
13
+ * @param options - Distinct messages listed and messages dropped
14
+ * @returns Summary
8
15
  */
9
- export declare function formatConsoleSummary(messages: ConsoleMessage[]): string;
16
+ export declare function formatConsoleSummary(messages: ConsoleMessage[], options?: Pick<ConsoleFormatOptions, 'groupLimit' | 'dropped'>): string;
10
17
  //# sourceMappingURL=summarize.d.ts.map
@@ -3,13 +3,25 @@
3
3
  * and shows info/debug/other as count-only footer entries.
4
4
  */
5
5
  import { OutputFormatter, pluralize } from '../../formatting.js';
6
- import { analyzeMessages, formatCountPrefix, formatSectionHeader, formatSourceLocation, } from './shared.js';
7
- function renderErrorSection(fmt, errors, total) {
6
+ import { consoleDroppedNote, consoleMoreGroupsNote } from '../../messages/consoleMessages.js';
7
+ import { analyzeMessages, formatCountPrefix, formatSectionHeader, formatSourceLocation, newestGroups, } from './shared.js';
8
+ /**
9
+ * The errors: the newest distinct ones, with a note for the earlier ones.
10
+ *
11
+ * @param fmt - Output
12
+ * @param errors - Distinct errors in order of first appearance
13
+ * @param total - Errors logged
14
+ * @param limit - Distinct errors listed (0 = all)
15
+ */
16
+ function renderErrorSection(fmt, errors, total, limit) {
8
17
  if (errors.length === 0)
9
18
  return;
19
+ const { shown, more } = newestGroups(errors, limit);
10
20
  fmt.text(formatSectionHeader('Errors', errors.length, total));
11
21
  fmt.separator('─', 30);
12
- for (const { message, count } of errors) {
22
+ if (more > 0)
23
+ fmt.text(consoleMoreGroupsNote(more, 'error')).blank();
24
+ for (const { message, count } of shown) {
13
25
  fmt.text(`${formatCountPrefix(count)}${message.text}`);
14
26
  const source = formatSourceLocation(message.stackTrace);
15
27
  if (source) {
@@ -18,12 +30,23 @@ function renderErrorSection(fmt, errors, total) {
18
30
  fmt.blank();
19
31
  }
20
32
  }
21
- function renderWarningSection(fmt, warnings, total) {
33
+ /**
34
+ * The warnings: the newest distinct ones, with a note for the earlier ones.
35
+ *
36
+ * @param fmt - Output
37
+ * @param warnings - Distinct warnings in order of first appearance
38
+ * @param total - Warnings logged
39
+ * @param limit - Distinct warnings listed (0 = all)
40
+ */
41
+ function renderWarningSection(fmt, warnings, total, limit) {
22
42
  if (warnings.length === 0)
23
43
  return;
44
+ const { shown, more } = newestGroups(warnings, limit);
24
45
  fmt.text(formatSectionHeader('Warnings', warnings.length, total));
25
46
  fmt.separator('─', 30);
26
- for (const { message, count } of warnings) {
47
+ if (more > 0)
48
+ fmt.text(consoleMoreGroupsNote(more, 'warning'));
49
+ for (const { message, count } of shown) {
27
50
  fmt.text(`• ${formatCountPrefix(count)}${message.text}`);
28
51
  const source = formatSourceLocation(message.stackTrace);
29
52
  if (source)
@@ -43,16 +66,24 @@ function renderOtherSummary(fmt, summary) {
43
66
  }
44
67
  }
45
68
  /**
46
- * Format console output as smart summary (default mode).
69
+ * Format console output as smart summary (default mode): the newest distinct
70
+ * errors and warnings, counts of the rest, and a note when the session
71
+ * dropped its oldest messages.
72
+ *
73
+ * @param messages - Messages to summarise
74
+ * @param options - Distinct messages listed and messages dropped
75
+ * @returns Summary
47
76
  */
48
- export function formatConsoleSummary(messages) {
77
+ export function formatConsoleSummary(messages, options = {}) {
49
78
  const fmt = new OutputFormatter();
50
79
  const { grouped, summary } = analyzeMessages(messages);
51
80
  fmt.text('Console Summary');
52
81
  fmt.separator('━', 60);
82
+ if (options.dropped)
83
+ fmt.text(consoleDroppedNote(options.dropped));
53
84
  fmt.blank();
54
- renderErrorSection(fmt, grouped.errors, summary.errors.total);
55
- renderWarningSection(fmt, grouped.warnings, summary.warnings.total);
85
+ renderErrorSection(fmt, grouped.errors, summary.errors.total, options.groupLimit);
86
+ renderWarningSection(fmt, grouped.warnings, summary.warnings.total, options.groupLimit);
56
87
  if (grouped.errors.length === 0 && grouped.warnings.length === 0) {
57
88
  fmt.text('No errors or warnings found');
58
89
  fmt.blank();
@@ -16,7 +16,8 @@ export { formatConsoleSummary } from './console/summarize.js';
16
16
  /**
17
17
  * Format console output based on options. Routes to the per-mode formatter:
18
18
  * a `--level` filter lists the matching messages (the summary only shows
19
- * errors and warnings, so it would hide e.g. `--level info`).
19
+ * errors and warnings, so it would hide e.g. `--level info`). The text
20
+ * starts with a warning when the page crashed.
20
21
  */
21
22
  export declare function formatConsole(messages: ConsoleMessage[], options: ConsoleFormatOptions): string;
22
23
  //# sourceMappingURL=console.d.ts.map
@@ -5,6 +5,7 @@
5
5
  * the `formatConsole` dispatcher. The per-mode implementations live in
6
6
  * `./console/`.
7
7
  */
8
+ import { withPageCrashedNote } from '../messages/commands.js';
8
9
  import { formatConsoleChronological } from './console/chronological.js';
9
10
  import { formatConsoleJson } from './console/json.js';
10
11
  import { formatConsoleSummary } from './console/summarize.js';
@@ -16,15 +17,16 @@ export { formatConsoleSummary } from './console/summarize.js';
16
17
  /**
17
18
  * Format console output based on options. Routes to the per-mode formatter:
18
19
  * a `--level` filter lists the matching messages (the summary only shows
19
- * errors and warnings, so it would hide e.g. `--level info`).
20
+ * errors and warnings, so it would hide e.g. `--level info`). The text
21
+ * starts with a warning when the page crashed.
20
22
  */
21
23
  export function formatConsole(messages, options) {
22
24
  if (options.json) {
23
25
  return formatConsoleJson(messages, options);
24
26
  }
25
- if (options.list || options.level) {
26
- return formatConsoleChronological(messages, options);
27
- }
28
- return formatConsoleSummary(messages);
27
+ const body = options.list || options.level
28
+ ? formatConsoleChronological(messages, options)
29
+ : formatConsoleSummary(messages, options);
30
+ return withPageCrashedNote(body, options.pageCrashedAt);
29
31
  }
30
32
  //# sourceMappingURL=console.js.map
@@ -184,13 +184,15 @@ function requestSummaryRows(request) {
184
184
  }
185
185
  /**
186
186
  * Add a header block, a header sent several times one value per line
187
- * ({@link headerValueLines}).
187
+ * ({@link headerValueLines}); nothing when there are no headers.
188
188
  *
189
189
  * @param fmt - Formatter
190
190
  * @param title - Block title
191
191
  * @param headers - Headers to list
192
192
  */
193
193
  function addHeaders(fmt, title, headers) {
194
+ if (Object.keys(headers).length === 0)
195
+ return;
194
196
  fmt.text(title).separator('━', 70);
195
197
  Object.entries(headers).forEach(([key, value]) => headerValueLines(key, value).forEach((line) => fmt.text(` ${key}: ${line}`)));
196
198
  fmt.blank();
@@ -6,7 +6,7 @@ import type { DomQueryResult, DomGetResult, ScreenshotResult } from '../../types
6
6
  * Displays found nodes with their index, tag, identifying attributes
7
7
  * ({@link queryTagAttributes}), classes, and preview text
8
8
  * (plus where they are when outside the viewport or hidden, e.g.
9
- * `(below fold)`), up to {@link QUERY_DISPLAY_LIMIT} of them (no match is an error, exit 83).
9
+ * `(below fold)`), as many as `--limit` listed, with a note for the rest (no match is an error, exit 83).
10
10
  * One line of next commands follows; they take the match's index, so they
11
11
  * work for matches in shadow roots and iframes too.
12
12
  *