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
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Normalization of computed CSS values for `bdg dom inspect`: px as numbers
3
+ * rounded to one decimal (no unit), colors as hex, 1-4 value shorthands,
4
+ * shadow layers, grid tracks with `repeat()`, transforms decomposed from the
5
+ * matrices Chrome computes, and the first font family.
6
+ */
7
+ import { hexColor, hexColorsIn } from './color.js';
8
+ /** px lengths inside a value */
9
+ const PX_IN_VALUE = /(-?\d*\.?\d+(?:e-?\d+)?)px\b/g;
10
+ /**
11
+ * Round to one decimal (and drop `-0`).
12
+ *
13
+ * @param value - Number
14
+ * @returns e.g. 12.5, 0
15
+ */
16
+ export function round1(value) {
17
+ const rounded = Math.round(value * 10) / 10;
18
+ return Object.is(rounded, -0) ? 0 : rounded;
19
+ }
20
+ /**
21
+ * A px value as a number.
22
+ *
23
+ * @param value - Computed value, e.g. `12.5px`
24
+ * @returns Rounded number, or undefined when the value is not a single px length
25
+ */
26
+ export function pxNumber(value) {
27
+ const match = /^(-?\d*\.?\d+(?:e-?\d+)?)px$/.exec((value ?? '').trim());
28
+ return match ? round1(Number(match[1])) : undefined;
29
+ }
30
+ /**
31
+ * A length as {@link CssLength}.
32
+ *
33
+ * @param value - Computed value
34
+ * @returns Number for px, else the value as text
35
+ */
36
+ export function cssLength(value) {
37
+ return pxNumber(value) ?? normalizeCssValue(value ?? '');
38
+ }
39
+ /**
40
+ * A computed value with px lengths as rounded unitless numbers and colors as
41
+ * hex, e.g. `rgba(0, 0, 0, 0.2) 0px 1.25px 2px` → `#00000033 0 1.3 2`.
42
+ *
43
+ * @param value - Computed value
44
+ * @returns Normalized value
45
+ */
46
+ export function normalizeCssValue(value) {
47
+ return hexColorsIn(value)
48
+ .replace(PX_IN_VALUE, (_match, number) => String(round1(Number(number))))
49
+ .replace(/\s+/g, ' ')
50
+ .trim();
51
+ }
52
+ /**
53
+ * 1-4 values the way CSS shorthands write them (top, right, bottom, left).
54
+ *
55
+ * @param sides - Top, right, bottom, left
56
+ * @returns e.g. `10`, `10 0`, `10 0 1`, `1 2 3 4`
57
+ */
58
+ export function sidesShorthand(sides) {
59
+ const [top, right, bottom, left] = sides.map(String);
60
+ if (top === right && right === bottom && bottom === left)
61
+ return `${top}`;
62
+ if (top === bottom && right === left)
63
+ return `${top} ${right}`;
64
+ if (right === left)
65
+ return `${top} ${right} ${bottom}`;
66
+ return `${top} ${right} ${bottom} ${left}`;
67
+ }
68
+ /**
69
+ * Split a value at commas (or another separator) outside parentheses.
70
+ *
71
+ * @param value - e.g. `rgb(0, 0, 0) 0px 1px, rgb(1, 1, 1) 0px 2px`
72
+ * @param separator - Character to split at
73
+ * @returns Parts, trimmed
74
+ */
75
+ export function splitTopLevel(value, separator = ',') {
76
+ const parts = [];
77
+ let depth = 0;
78
+ let current = '';
79
+ for (const char of value) {
80
+ if (char === '(' || char === '[')
81
+ depth++;
82
+ if (char === ')' || char === ']')
83
+ depth--;
84
+ if (char === separator && depth === 0) {
85
+ parts.push(current.trim());
86
+ current = '';
87
+ }
88
+ else {
89
+ current += char;
90
+ }
91
+ }
92
+ if (current.trim())
93
+ parts.push(current.trim());
94
+ return parts;
95
+ }
96
+ /**
97
+ * The first family of a `font-family` list, without quotes.
98
+ *
99
+ * @param fontFamily - e.g. `"DM Sans", Arial, sans-serif`
100
+ * @returns e.g. `DM Sans`
101
+ */
102
+ export function firstFontFamily(fontFamily) {
103
+ const first = splitTopLevel(fontFamily)[0] ?? '';
104
+ return first.replace(/^["']|["']$/g, '');
105
+ }
106
+ /**
107
+ * Parse one shadow layer as Chrome computes it (`<color> <x> <y> <blur> [<spread>] [inset]`).
108
+ *
109
+ * @param layer - e.g. `rgba(0, 0, 0, 0.2) 0px 1px 2px 0px`
110
+ * @returns The layer, or undefined when it does not parse
111
+ */
112
+ function parseShadowLayer(layer) {
113
+ const color = /^((?:rgba?|lab|lch|oklab|oklch|color)\([^()]*\)|#[0-9a-f]{3,8}|[a-z]+)\s+/i.exec(layer);
114
+ const rest = (color ? layer.slice(color[0].length) : layer).split(/\s+/);
115
+ const lengths = rest.map(pxNumber).filter((n) => n !== undefined);
116
+ if (lengths.length < 2)
117
+ return undefined;
118
+ return {
119
+ x: lengths[0] ?? 0,
120
+ y: lengths[1] ?? 0,
121
+ blur: lengths[2] ?? 0,
122
+ spread: lengths[3] ?? 0,
123
+ color: hexColor(color?.[1] ?? 'currentcolor'),
124
+ inset: rest.includes('inset'),
125
+ };
126
+ }
127
+ /**
128
+ * The visible layers of a shadow: transparent layers and layers with no
129
+ * offset, blur or spread (Tailwind's ring placeholders) are left out.
130
+ *
131
+ * @param value - Computed `box-shadow` or `text-shadow`
132
+ * @returns Layers, outermost first
133
+ */
134
+ export function parseShadows(value) {
135
+ if (!value || value === 'none')
136
+ return [];
137
+ return splitTopLevel(value)
138
+ .map(parseShadowLayer)
139
+ .filter((layer) => layer !== undefined)
140
+ .filter((layer) => layer.color !== 'transparent' &&
141
+ (layer.x !== 0 || layer.y !== 0 || layer.blur !== 0 || layer.spread !== 0));
142
+ }
143
+ /**
144
+ * A shadow layer as text, e.g. `#00000033 0 1 2 0`, `inset #000 0 0 0 1`.
145
+ *
146
+ * @param layer - Shadow layer
147
+ * @param withSpread - Include the spread (box shadows)
148
+ * @returns Text
149
+ */
150
+ export function shadowText(layer, withSpread = true) {
151
+ const lengths = [layer.x, layer.y, layer.blur, ...(withSpread ? [layer.spread] : [])];
152
+ return `${layer.inset ? 'inset ' : ''}${layer.color} ${lengths.join(' ')}`;
153
+ }
154
+ /**
155
+ * Grid tracks with runs of equal sizes written as `repeat()`.
156
+ *
157
+ * @param value - Computed `grid-template-columns`/`rows`, e.g. `100px 100px 100px 50px`
158
+ * @returns e.g. `repeat(3,100) 50`; `none` stays `none`
159
+ */
160
+ export function compressTracks(value) {
161
+ if (!value || value === 'none')
162
+ return value;
163
+ const tracks = splitTopLevel(value, ' ').map((token) => normalizeCssValue(token));
164
+ const parts = [];
165
+ for (let i = 0; i < tracks.length;) {
166
+ let run = 1;
167
+ while (tracks[i + run] === tracks[i])
168
+ run++;
169
+ parts.push(run > 1 ? `repeat(${run},${tracks[i]})` : `${tracks[i]}`);
170
+ i += run;
171
+ }
172
+ return parts.join(' ');
173
+ }
174
+ /**
175
+ * Round a number for a transform (3 decimals at most).
176
+ *
177
+ * @param value - Number
178
+ * @returns Rounded number
179
+ */
180
+ function round3(value) {
181
+ const rounded = Math.round(value * 1000) / 1000;
182
+ return Object.is(rounded, -0) ? 0 : rounded;
183
+ }
184
+ /**
185
+ * A 2D matrix as translate/rotate/scale when it is one (no skew).
186
+ *
187
+ * @param m - a, b, c, d, e, f
188
+ * @returns e.g. `translate(10,20) rotate(45deg)`, or undefined for a skew
189
+ */
190
+ function decomposeMatrix([a = 1, b = 0, c = 0, d = 1, e = 0, f = 0]) {
191
+ if (Math.abs(a * c + b * d) > 1e-6)
192
+ return undefined;
193
+ const scaleX = Math.hypot(a, b);
194
+ const scaleY = scaleX === 0 ? 0 : (a * d - b * c) / scaleX;
195
+ const angle = round3((Math.atan2(b, a) * 180) / Math.PI);
196
+ const parts = [];
197
+ if (e !== 0 || f !== 0)
198
+ parts.push(`translate(${round1(e)},${round1(f)})`);
199
+ if (angle !== 0)
200
+ parts.push(`rotate(${angle}deg)`);
201
+ const [sx, sy] = [round3(scaleX), round3(scaleY)];
202
+ if (sx !== 1 || sy !== 1)
203
+ parts.push(sx === sy ? `scale(${sx})` : `scale(${sx},${sy})`);
204
+ return parts.length > 0 ? parts.join(' ') : 'none';
205
+ }
206
+ /**
207
+ * A computed transform in readable form: a 2D matrix as
208
+ * translate/rotate/scale, other matrices with rounded numbers.
209
+ *
210
+ * @param value - Computed `transform`, e.g. `matrix(1, 0, 0, 1, 10, 20)`
211
+ * @returns e.g. `translate(10,20)`; `none` when it does nothing
212
+ */
213
+ export function readableTransform(value) {
214
+ const match = /^(matrix|matrix3d)\((.*)\)$/.exec(value.trim());
215
+ if (!match)
216
+ return normalizeCssValue(value);
217
+ const numbers = (match[2] ?? '').split(',').map((n) => Number(n.trim()));
218
+ const decomposed = match[1] === 'matrix' ? decomposeMatrix(numbers) : undefined;
219
+ return decomposed ?? `${match[1]}(${numbers.map(round3).join(',')})`;
220
+ }
221
+ /**
222
+ * The file name of a URL in a CSS value: `url("https://x.com/a/b.png?v=1")` → `url(b.png)`;
223
+ * `data:` URLs become `url(data:…)`.
224
+ *
225
+ * @param value - Computed value with `url()`s
226
+ * @returns The value with short URLs
227
+ */
228
+ export function shortUrls(value) {
229
+ return value.replace(/url\((["']?)(.*?)\1\)/g, (_match, _quote, url) => {
230
+ if (url.startsWith('data:'))
231
+ return 'url(data:…)';
232
+ const name = url.split(/[?#]/)[0]?.split('/').filter(Boolean).pop() ?? url;
233
+ return `url(${name})`;
234
+ });
235
+ }
236
+ //# sourceMappingURL=cssValues.js.map
@@ -70,4 +70,16 @@ export declare function withoutVisibleFilters(parts: SelectorPart[]): SelectorPa
70
70
  * @returns The selectors, untrimmed
71
71
  */
72
72
  export declare function splitSelectorList(selector: string): string[];
73
+ /**
74
+ * The compounds of a complex selector before its last one, with the rest
75
+ * after each (`mdn-search-modal form` gives `mdn-search-modal` with `form`):
76
+ * the ancestors a selector would have to cross shadow roots through.
77
+ *
78
+ * @param selector - One selector (a list gives nothing)
79
+ * @returns Leading compounds and the selector after each
80
+ */
81
+ export declare function leadingCompounds(selector: string): Array<{
82
+ compound: string;
83
+ rest: string;
84
+ }>;
73
85
  //# sourceMappingURL=selectorFilters.d.ts.map
@@ -76,6 +76,35 @@ export function splitSelectorList(selector) {
76
76
  parts.push(selector.slice(partStart));
77
77
  return parts;
78
78
  }
79
+ /**
80
+ * The compounds of a complex selector before its last one, with the rest
81
+ * after each (`mdn-search-modal form` gives `mdn-search-modal` with `form`):
82
+ * the ancestors a selector would have to cross shadow roots through.
83
+ *
84
+ * @param selector - One selector (a list gives nothing)
85
+ * @returns Leading compounds and the selector after each
86
+ */
87
+ export function leadingCompounds(selector) {
88
+ if (splitSelectorList(selector).length > 1)
89
+ return [];
90
+ const text = selector.trim();
91
+ const found = [];
92
+ let start = 0;
93
+ scan(text, (index, depth) => {
94
+ const char = text[index] ?? '';
95
+ if (depth > 0 || !/[\s>+~]/.test(char))
96
+ return index;
97
+ const compound = text.slice(start, index).trim();
98
+ let next = index;
99
+ while (next + 1 < text.length && /[\s>+~]/.test(text[next + 1] ?? ''))
100
+ next++;
101
+ if (compound)
102
+ found.push({ compound, rest: text.slice(next + 1).trim() });
103
+ start = next + 1;
104
+ return next;
105
+ });
106
+ return found;
107
+ }
79
108
  /**
80
109
  * Walk a selector, calling `visit` at every token start outside quoted
81
110
  * strings, escapes and attribute brackets (whose insides are skipped), with
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browser-debugger-cli",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "DevTools telemetry in your terminal. For humans and agents. Direct WebSocket to Chrome's debugging port.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -90,6 +90,7 @@
90
90
  },
91
91
  "files": [
92
92
  "dist",
93
+ ".claude/skills/bdg/SKILL.md",
93
94
  "!dist/**/__tests__",
94
95
  "!dist/__testutils__",
95
96
  "!dist/__testfixtures__",