browser-debugger-cli 0.9.0 → 0.11.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 (139) hide show
  1. package/.claude/skills/bdg/SKILL.md +268 -0
  2. package/README.md +15 -1
  3. package/dist/commands/dom/a11y.js +2 -1
  4. package/dist/commands/dom/formInteraction.js +56 -25
  5. package/dist/commands/dom/helpers/keyAttributes.d.ts +20 -0
  6. package/dist/commands/dom/helpers/keyAttributes.js +54 -0
  7. package/dist/commands/dom/helpers/query.d.ts +1 -1
  8. package/dist/commands/dom/helpers/query.js +66 -19
  9. package/dist/commands/dom/helpers/runElementCommand.js +4 -3
  10. package/dist/commands/dom/helpers/screenshot.js +85 -12
  11. package/dist/commands/dom/index.d.ts +1 -0
  12. package/dist/commands/dom/index.js +8 -3
  13. package/dist/commands/dom/inspect.d.ts +15 -0
  14. package/dist/commands/dom/inspect.js +82 -0
  15. package/dist/commands/dom/layout.js +2 -2
  16. package/dist/commands/dom/listeners.js +2 -2
  17. package/dist/commands/dom/semanticUtils.d.ts +14 -1
  18. package/dist/commands/dom/semanticUtils.js +44 -3
  19. package/dist/commands/installSkill.d.ts +20 -0
  20. package/dist/commands/installSkill.js +87 -0
  21. package/dist/commands/network/list.js +13 -2
  22. package/dist/commands/optionBehaviors.js +48 -6
  23. package/dist/commands/page.d.ts +1 -1
  24. package/dist/commands/page.js +62 -3
  25. package/dist/commands/shared/commonOptions.d.ts +4 -0
  26. package/dist/commands/shared/commonOptions.js +9 -0
  27. package/dist/commands/shared/optionTypes.d.ts +21 -0
  28. package/dist/commands/shared/startHelpers.d.ts +66 -0
  29. package/dist/commands/shared/startHelpers.js +91 -10
  30. package/dist/commands/shared/validation.d.ts +11 -0
  31. package/dist/commands/shared/validation.js +16 -0
  32. package/dist/commands.js +3 -0
  33. package/dist/daemon/launcher.d.ts +8 -1
  34. package/dist/daemon/launcher.js +3 -1
  35. package/dist/daemon/session/Session.d.ts +7 -0
  36. package/dist/daemon/session/Session.js +23 -1
  37. package/dist/daemon/session/commandRegistry.d.ts +14 -1
  38. package/dist/daemon/session/commandRegistry.js +65 -9
  39. package/dist/daemon/session/interactions.d.ts +18 -5
  40. package/dist/daemon/session/interactions.js +22 -12
  41. package/dist/daemon.js +3565 -329
  42. package/dist/errors/messages.d.ts +85 -0
  43. package/dist/errors/messages.js +128 -1
  44. package/dist/index.js +2151 -960
  45. package/dist/ipc/client.d.ts +9 -0
  46. package/dist/ipc/client.js +13 -0
  47. package/dist/ipc/protocol/commands.d.ts +56 -1
  48. package/dist/ipc/protocol/commands.js +2 -0
  49. package/dist/ipc/protocol/domTypes.d.ts +35 -2
  50. package/dist/ipc/protocol/inspectTypes.d.ts +388 -0
  51. package/dist/ipc/protocol/inspectTypes.js +10 -0
  52. package/dist/runtime/dom/actionEffects.d.ts +94 -15
  53. package/dist/runtime/dom/actionEffects.js +173 -27
  54. package/dist/runtime/dom/actionEffectsScripts.d.ts +52 -14
  55. package/dist/runtime/dom/actionEffectsScripts.js +224 -32
  56. package/dist/runtime/dom/elementInfo.d.ts +26 -0
  57. package/dist/runtime/dom/elementInfo.js +65 -0
  58. package/dist/runtime/dom/eventListeners.js +14 -4
  59. package/dist/runtime/dom/formFillHelpers/fill.d.ts +3 -4
  60. package/dist/runtime/dom/formFillHelpers/fill.js +77 -28
  61. package/dist/runtime/dom/frameSelection.d.ts +11 -0
  62. package/dist/runtime/dom/frameSelection.js +20 -1
  63. package/dist/runtime/dom/frames.d.ts +38 -5
  64. package/dist/runtime/dom/frames.js +136 -21
  65. package/dist/runtime/dom/inspect.d.ts +28 -0
  66. package/dist/runtime/dom/inspect.js +557 -0
  67. package/dist/runtime/dom/inspectAllStyles.d.ts +62 -0
  68. package/dist/runtime/dom/inspectAllStyles.js +385 -0
  69. package/dist/runtime/dom/inspectCascade.d.ts +94 -0
  70. package/dist/runtime/dom/inspectCascade.js +371 -0
  71. package/dist/runtime/dom/inspectCascadeModel.d.ts +39 -0
  72. package/dist/runtime/dom/inspectCascadeModel.js +232 -0
  73. package/dist/runtime/dom/inspectHints.d.ts +62 -0
  74. package/dist/runtime/dom/inspectHints.js +305 -0
  75. package/dist/runtime/dom/inspectLayoutModel.d.ts +87 -0
  76. package/dist/runtime/dom/inspectLayoutModel.js +346 -0
  77. package/dist/runtime/dom/inspectModel.d.ts +74 -0
  78. package/dist/runtime/dom/inspectModel.js +184 -0
  79. package/dist/runtime/dom/inspectPaintModel.d.ts +157 -0
  80. package/dist/runtime/dom/inspectPaintModel.js +461 -0
  81. package/dist/runtime/dom/inspectRules.d.ts +37 -0
  82. package/dist/runtime/dom/inspectRules.js +101 -0
  83. package/dist/runtime/dom/inspectScripts.d.ts +132 -0
  84. package/dist/runtime/dom/inspectScripts.js +263 -0
  85. package/dist/runtime/dom/inspectTree.d.ts +40 -0
  86. package/dist/runtime/dom/inspectTree.js +134 -0
  87. package/dist/runtime/dom/inspectVariables.d.ts +33 -0
  88. package/dist/runtime/dom/inspectVariables.js +94 -0
  89. package/dist/runtime/dom/inspectWhyModel.d.ts +20 -0
  90. package/dist/runtime/dom/inspectWhyModel.js +134 -0
  91. package/dist/runtime/dom/layout.d.ts +5 -1
  92. package/dist/runtime/dom/layout.js +10 -3
  93. package/dist/runtime/dom/listenerPageScripts.d.ts +11 -5
  94. package/dist/runtime/dom/listenerPageScripts.js +95 -9
  95. package/dist/runtime/dom/listenerSummary.d.ts +4 -0
  96. package/dist/runtime/dom/listenerSummary.js +26 -9
  97. package/dist/runtime/dom/reactEventHelpers.d.ts +5 -0
  98. package/dist/runtime/dom/reactEventHelpers.js +12 -4
  99. package/dist/runtime/page/emulation.d.ts +20 -0
  100. package/dist/runtime/page/emulation.js +37 -0
  101. package/dist/telemetry/a11y.d.ts +10 -0
  102. package/dist/telemetry/a11y.js +78 -1
  103. package/dist/telemetry/console.d.ts +1 -0
  104. package/dist/telemetry/console.js +100 -5
  105. package/dist/telemetry/network.js +3 -1
  106. package/dist/types.d.ts +40 -0
  107. package/dist/ui/formatters/details.d.ts +8 -0
  108. package/dist/ui/formatters/details.js +59 -3
  109. package/dist/ui/formatters/dom.d.ts +2 -1
  110. package/dist/ui/formatters/dom.js +25 -9
  111. package/dist/ui/formatters/inspect.d.ts +39 -0
  112. package/dist/ui/formatters/inspect.js +596 -0
  113. package/dist/ui/formatters/installSkill.d.ts +11 -0
  114. package/dist/ui/formatters/installSkill.js +31 -0
  115. package/dist/ui/formatters/keyAttributes.d.ts +19 -0
  116. package/dist/ui/formatters/keyAttributes.js +84 -0
  117. package/dist/ui/formatters/layout.js +2 -2
  118. package/dist/ui/formatters/networkHeaders.d.ts +13 -0
  119. package/dist/ui/formatters/networkHeaders.js +23 -3
  120. package/dist/ui/formatters/networkList.d.ts +29 -1
  121. package/dist/ui/formatters/networkList.js +86 -20
  122. package/dist/ui/formatters/status.js +1 -1
  123. package/dist/ui/formatting.d.ts +9 -0
  124. package/dist/ui/formatting.js +6 -3
  125. package/dist/ui/messages/commands.d.ts +123 -7
  126. package/dist/ui/messages/commands.js +181 -10
  127. package/dist/ui/messages/networkMessages.d.ts +14 -0
  128. package/dist/ui/messages/networkMessages.js +18 -0
  129. package/dist/ui/messages/session.d.ts +14 -0
  130. package/dist/ui/messages/session.js +20 -0
  131. package/dist/utils/async.d.ts +9 -0
  132. package/dist/utils/async.js +17 -0
  133. package/dist/utils/color.d.ts +84 -0
  134. package/dist/utils/color.js +376 -0
  135. package/dist/utils/cssValues.d.ts +109 -0
  136. package/dist/utils/cssValues.js +236 -0
  137. package/dist/utils/selectorFilters.d.ts +12 -0
  138. package/dist/utils/selectorFilters.js +29 -0
  139. package/package.json +2 -1
@@ -1,9 +1,12 @@
1
1
  import { skippedBodyReason } from '../../telemetry/network.js';
2
2
  import { formatFramePosition, formatTimestamp } from './console/shared.js';
3
+ import { headerValueLines } from './networkHeaders.js';
3
4
  import { formatRequestStatus } from './requestStatus.js';
4
5
  import { OutputFormatter } from '../formatting.js';
6
+ import { localProxyNote } from '../messages/networkMessages.js';
5
7
  import { sessionCommand } from '../messages/sessionCommand.js';
6
8
  import { truncateByLength } from '../../utils/strings.js';
9
+ import { safeParseUrl } from '../../utils/url.js';
7
10
  /** Characters of each WebSocket message shown in human output (`--json` has all) */
8
11
  const MESSAGE_PREVIEW_LENGTH = 200;
9
12
  /** WebSocket opcode of binary messages */
@@ -95,6 +98,58 @@ function formatBytes(bytes) {
95
98
  ? `${(bytes / 1024).toFixed(1)} KB`
96
99
  : `${(bytes / 1024 / 1024).toFixed(1)} MB`;
97
100
  }
101
+ /**
102
+ * Whether an IP address is a loopback address (`127.0.0.0/8`, `::1`).
103
+ *
104
+ * @param ip - Address as CDP reports it (IPv6 may come in brackets)
105
+ * @returns True for loopback
106
+ */
107
+ function isLoopback(ip) {
108
+ const bare = ip.replace(/^\[|\]$/g, '').toLowerCase();
109
+ return /^(::ffff:)?127\./.test(bare) || bare === '::1';
110
+ }
111
+ /** Ports of URLs without one */
112
+ const DEFAULT_PORTS = {
113
+ 'http:': '80',
114
+ 'https:': '443',
115
+ 'ws:': '80',
116
+ 'wss:': '443',
117
+ };
118
+ /**
119
+ * Whether a request probably went through a proxy on this machine: Chrome
120
+ * connected to a loopback address on another port than the URL's (given or
121
+ * the scheme's default), for a host that is not this machine. A loopback
122
+ * host from `/etc/hosts` (`myapp.test`) is connected to on the URL's port,
123
+ * so it is not taken for a proxy. CDP has no proxy flag; this is a guess.
124
+ *
125
+ * @param request - Request with `serverIPAddress` and `serverPort`
126
+ * @returns True when the connection looks like a local proxy
127
+ */
128
+ function looksLikeLocalProxy(request) {
129
+ const url = safeParseUrl(request.url);
130
+ if (!url || request.serverPort === undefined || !isLoopback(request.serverIPAddress ?? '')) {
131
+ return false;
132
+ }
133
+ const hostname = url.hostname.toLowerCase();
134
+ if (hostname === 'localhost' || hostname.endsWith('.localhost') || isLoopback(hostname)) {
135
+ return false;
136
+ }
137
+ const urlPort = url.port || DEFAULT_PORTS[url.protocol];
138
+ return urlPort !== undefined && String(request.serverPort) !== urlPort;
139
+ }
140
+ /**
141
+ * The address Chrome connected to, with its port, noting when it looks like
142
+ * a proxy on this machine ({@link looksLikeLocalProxy}).
143
+ *
144
+ * @param request - Request with `serverIPAddress`
145
+ * @returns e.g. `93.184.215.14:443`, `[2606:4700::1]:443`, `127.0.0.1:9000 (loopback; likely a local proxy)`
146
+ */
147
+ export function remoteAddress(request) {
148
+ const ip = request.serverIPAddress ?? '';
149
+ const host = ip.includes(':') && !ip.startsWith('[') ? `[${ip}]` : ip;
150
+ const address = request.serverPort ? `${host}:${request.serverPort}` : host;
151
+ return looksLikeLocalProxy(request) ? `${address} ${localProxyNote()}` : address;
152
+ }
98
153
  /**
99
154
  * Summary rows of a request: identity, outcome, timing and size.
100
155
  *
@@ -122,13 +177,14 @@ function requestSummaryRows(request) {
122
177
  if (request.fromCache)
123
178
  rows.push(['From Cache', 'yes']);
124
179
  if (request.serverIPAddress)
125
- rows.push(['Remote Address', request.serverIPAddress]);
180
+ rows.push(['Remote Address', remoteAddress(request)]);
126
181
  if (request.blockedReason)
127
182
  rows.push(['Blocked', request.blockedReason]);
128
183
  return rows;
129
184
  }
130
185
  /**
131
- * Add a header block.
186
+ * Add a header block, a header sent several times one value per line
187
+ * ({@link headerValueLines}).
132
188
  *
133
189
  * @param fmt - Formatter
134
190
  * @param title - Block title
@@ -136,7 +192,7 @@ function requestSummaryRows(request) {
136
192
  */
137
193
  function addHeaders(fmt, title, headers) {
138
194
  fmt.text(title).separator('━', 70);
139
- Object.entries(headers).forEach(([key, value]) => fmt.text(` ${key}: ${value}`));
195
+ Object.entries(headers).forEach(([key, value]) => headerValueLines(key, value).forEach((line) => fmt.text(` ${key}: ${line}`)));
140
196
  fmt.blank();
141
197
  }
142
198
  /**
@@ -3,7 +3,8 @@ import type { DomQueryResult, DomGetResult, ScreenshotResult } from '../../types
3
3
  /**
4
4
  * Format DOM query results for human-readable output.
5
5
  *
6
- * Displays found nodes with their index, tag, classes, and preview text
6
+ * Displays found nodes with their index, tag, identifying attributes
7
+ * ({@link queryTagAttributes}), classes, and preview text
7
8
  * (plus where they are when outside the viewport or hidden, e.g.
8
9
  * `(below fold)`), up to {@link QUERY_DISPLAY_LIMIT} of them (no match is an error, exit 83).
9
10
  * One line of next commands follows; they take the match's index, so they
@@ -1,3 +1,4 @@
1
+ import { keyAttributeItems } from './keyAttributes.js';
1
2
  import { OutputFormatter } from '../formatting.js';
2
3
  import { frameLabel, moreMatchesNote, framesStillLoadingNote, noFramesMessage, queryNextSteps, screenshotGrownNote, viewportPositionHint, } from '../messages/commands.js';
3
4
  /** Matches listed in human output (JSON has all of them) */
@@ -5,7 +6,8 @@ const QUERY_DISPLAY_LIMIT = 50;
5
6
  /**
6
7
  * Format DOM query results for human-readable output.
7
8
  *
8
- * Displays found nodes with their index, tag, classes, and preview text
9
+ * Displays found nodes with their index, tag, identifying attributes
10
+ * ({@link queryTagAttributes}), classes, and preview text
9
11
  * (plus where they are when outside the viewport or hidden, e.g.
10
12
  * `(below fold)`), up to {@link QUERY_DISPLAY_LIMIT} of them (no match is an error, exit 83).
11
13
  * One line of next commands follows; they take the match's index, so they
@@ -34,14 +36,8 @@ export function formatDomQuery(data) {
34
36
  const { count, nodes, selector } = data;
35
37
  const fmt = new OutputFormatter();
36
38
  const nodeLines = nodes.slice(0, QUERY_DISPLAY_LIMIT).map((node) => {
37
- const attributes = [
38
- node.id && ` id="${node.id}"`,
39
- node.name && ` name="${node.name}"`,
40
- node.type && ` type="${node.type}"`,
41
- node.value !== undefined && ` value="${node.value}"`,
42
- node.classes?.length && ` class="${node.classes.join(' ')}"`,
43
- ]
44
- .filter(Boolean)
39
+ const attributes = queryTagAttributes(node)
40
+ .map((item) => ` ${item}`)
45
41
  .join('');
46
42
  const context = node.context ? ` (in ${node.context})` : '';
47
43
  const preview = node.preview ? ` ${node.preview}` : '';
@@ -57,6 +53,26 @@ export function formatDomQuery(data) {
57
53
  .tip(queryNextSteps(exampleIndex))
58
54
  .build();
59
55
  }
56
+ /**
57
+ * The attributes shown in a `dom query` match's tag: id, then name, type and
58
+ * the key attributes of its type ({@link keyAttributeItems}: an image's file
59
+ * name and alt, a link's href, a field's placeholder and value), then class.
60
+ *
61
+ * @param node - Query match
62
+ * @returns `name="value"` items
63
+ */
64
+ function queryTagAttributes(node) {
65
+ const identifying = {
66
+ ...(node.name && { name: node.name }),
67
+ ...(node.type && { type: node.type }),
68
+ ...(node.value !== undefined && { value: node.value }),
69
+ };
70
+ return [
71
+ ...(node.id ? [`id="${node.id}"`] : []),
72
+ ...keyAttributeItems(node.tag ?? '', { ...identifying, ...node.attributes }),
73
+ ...(node.classes?.length ? [`class="${node.classes.join(' ')}"`] : []),
74
+ ];
75
+ }
60
76
  /**
61
77
  * Format DOM get results for human-readable output.
62
78
  *
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Human output of `bdg dom inspect`: a header line, then one line per group
3
+ * in Figma's order with DevTools' names (box, layout, parent, text, fill,
4
+ * border, fx, state, pseudo), then the child tree. Fields within a line are
5
+ * separated by ` · `; lengths are CSS px without the unit.
6
+ *
7
+ * ```
8
+ * button#buy.btn "Buy now" 120x41 @20,20 [flex] [prefers light]
9
+ * box p 12 24 · b 1
10
+ * layout inline-flex row · gap 8
11
+ * parent div.card flex column · gap 16 · in-parent l0 t0 r180 b0 · sib b16
12
+ * text Inter (webfont) 600 16/24 · color #fff · contrast 5.17 AA
13
+ * fill bg #1c69e3
14
+ * border 1 solid #32447f · radius 8
15
+ * ```
16
+ */
17
+ import type { InspectResult } from '../../ipc/protocol/inspectTypes.js';
18
+ import type { IndexSource } from '../../types.js';
19
+ /** `bdg dom inspect` data (the `success` flag is implied by the envelope), with the list an index refers to */
20
+ export type InspectOutput = Omit<InspectResult, 'success'> & {
21
+ indexSource?: IndexSource | undefined;
22
+ };
23
+ /**
24
+ * The header: label, text, size and position, layout badge, what keeps it
25
+ * from being seen, where it lives and the color scheme.
26
+ *
27
+ * @param data - Inspect result
28
+ * @returns Header line
29
+ */
30
+ export declare function inspectHeader(data: InspectOutput): string;
31
+ /**
32
+ * Format `bdg dom inspect` output (`--why` answers only its question:
33
+ * the header, hints and the declarations, no style groups or tree).
34
+ *
35
+ * @param data - Inspect result
36
+ * @returns Formatted output
37
+ */
38
+ export declare function formatInspect(data: InspectOutput): string;
39
+ //# sourceMappingURL=inspect.d.ts.map