browser-debugger-cli 0.8.0 → 0.9.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 (251) hide show
  1. package/README.md +4 -1
  2. package/dist/cdp/schema.d.ts +4 -1
  3. package/dist/cdp/schema.js +48 -7
  4. package/dist/commands/cdp.js +3 -2
  5. package/dist/commands/cleanup.d.ts +11 -0
  6. package/dist/commands/cleanup.js +161 -57
  7. package/dist/commands/console.d.ts +20 -1
  8. package/dist/commands/console.js +57 -17
  9. package/dist/commands/details.js +3 -2
  10. package/dist/commands/dom/DomElementResolver.d.ts +10 -3
  11. package/dist/commands/dom/DomElementResolver.js +35 -17
  12. package/dist/commands/dom/a11y.d.ts +10 -0
  13. package/dist/commands/dom/a11y.js +27 -5
  14. package/dist/commands/dom/eval.d.ts +3 -1
  15. package/dist/commands/dom/eval.js +29 -4
  16. package/dist/commands/dom/form.js +16 -62
  17. package/dist/commands/dom/formInteraction.js +152 -113
  18. package/dist/commands/dom/formSummary.d.ts +49 -0
  19. package/dist/commands/dom/formSummary.js +180 -0
  20. package/dist/commands/dom/frames.d.ts +2 -1
  21. package/dist/commands/dom/frames.js +17 -2
  22. package/dist/commands/dom/get.d.ts +6 -5
  23. package/dist/commands/dom/get.js +92 -82
  24. package/dist/commands/dom/helpers/index.d.ts +1 -1
  25. package/dist/commands/dom/helpers/index.js +1 -1
  26. package/dist/commands/dom/helpers/query.d.ts +44 -17
  27. package/dist/commands/dom/helpers/query.js +244 -97
  28. package/dist/commands/dom/helpers/runElementCommand.d.ts +10 -2
  29. package/dist/commands/dom/helpers/runElementCommand.js +97 -30
  30. package/dist/commands/dom/helpers/screenshot.d.ts +4 -1
  31. package/dist/commands/dom/helpers/screenshot.js +164 -49
  32. package/dist/commands/dom/index.d.ts +3 -1
  33. package/dist/commands/dom/index.js +16 -6
  34. package/dist/commands/dom/layout.d.ts +14 -0
  35. package/dist/commands/dom/layout.js +54 -0
  36. package/dist/commands/dom/listeners.d.ts +5 -1
  37. package/dist/commands/dom/listeners.js +13 -3
  38. package/dist/commands/dom/query.js +2 -3
  39. package/dist/commands/dom/screenshot.d.ts +12 -2
  40. package/dist/commands/dom/screenshot.js +27 -3
  41. package/dist/commands/dom/semanticUtils.d.ts +6 -13
  42. package/dist/commands/dom/semanticUtils.js +15 -19
  43. package/dist/commands/dom/wait.d.ts +13 -0
  44. package/dist/commands/dom/wait.js +83 -0
  45. package/dist/commands/helpJson.js +2 -2
  46. package/dist/commands/network/list.js +4 -11
  47. package/dist/commands/optionBehaviors.js +112 -21
  48. package/dist/commands/page.d.ts +2 -1
  49. package/dist/commands/page.js +41 -5
  50. package/dist/commands/peek.js +4 -11
  51. package/dist/commands/sessions.d.ts +8 -0
  52. package/dist/commands/sessions.js +19 -0
  53. package/dist/commands/shared/CommandRunner.js +4 -4
  54. package/dist/commands/shared/dataFetcher.js +2 -2
  55. package/dist/commands/shared/followMode.d.ts +21 -1
  56. package/dist/commands/shared/followMode.js +29 -2
  57. package/dist/commands/shared/handleValidationError.d.ts +2 -2
  58. package/dist/commands/shared/handleValidationError.js +12 -3
  59. package/dist/commands/shared/optionTypes.d.ts +40 -5
  60. package/dist/commands/shared/startHelpers.js +12 -3
  61. package/dist/commands/shared/validation.d.ts +3 -2
  62. package/dist/commands/shared/validation.js +4 -3
  63. package/dist/commands/start.d.ts +63 -0
  64. package/dist/commands/start.js +115 -15
  65. package/dist/commands/status.js +29 -7
  66. package/dist/commands/stop.js +7 -6
  67. package/dist/commands/tail.js +4 -11
  68. package/dist/commands/types.d.ts +2 -0
  69. package/dist/commands.js +2 -0
  70. package/dist/connection/chromeIdentity.d.ts +65 -0
  71. package/dist/connection/chromeIdentity.js +143 -0
  72. package/dist/connection/launcher/profilePreferences.d.ts +47 -0
  73. package/dist/connection/launcher/profilePreferences.js +151 -0
  74. package/dist/connection/launcher.d.ts +21 -2
  75. package/dist/connection/launcher.js +42 -16
  76. package/dist/connection/portReservation.d.ts +14 -4
  77. package/dist/connection/portReservation.js +21 -6
  78. package/dist/connection/startupExit.d.ts +8 -0
  79. package/dist/connection/startupExit.js +15 -6
  80. package/dist/constants.d.ts +6 -2
  81. package/dist/constants.js +9 -2
  82. package/dist/daemon/SessionController.js +23 -7
  83. package/dist/daemon/errors.d.ts +1 -1
  84. package/dist/daemon/errors.js +1 -1
  85. package/dist/daemon/launcher.d.ts +2 -1
  86. package/dist/daemon/launcher.js +5 -6
  87. package/dist/daemon/server/SocketServer.js +1 -2
  88. package/dist/daemon/session/Session.d.ts +13 -0
  89. package/dist/daemon/session/Session.js +57 -8
  90. package/dist/daemon/session/chromeConnection.d.ts +9 -0
  91. package/dist/daemon/session/chromeConnection.js +45 -8
  92. package/dist/daemon/session/commandRegistry.js +52 -62
  93. package/dist/daemon/session/interactions.d.ts +35 -9
  94. package/dist/daemon/session/interactions.js +36 -9
  95. package/dist/daemon/session/triggeredRequests.d.ts +67 -0
  96. package/dist/daemon/session/triggeredRequests.js +157 -0
  97. package/dist/daemon/session/types.d.ts +5 -1
  98. package/dist/daemon.js +5393 -1600
  99. package/dist/errors/messages.d.ts +387 -24
  100. package/dist/errors/messages.js +761 -67
  101. package/dist/index.js +3976 -1558
  102. package/dist/ipc/client.d.ts +12 -1
  103. package/dist/ipc/client.js +22 -3
  104. package/dist/ipc/protocol/commands.d.ts +89 -4
  105. package/dist/ipc/protocol/commands.js +2 -0
  106. package/dist/ipc/protocol/domTypes.d.ts +258 -7
  107. package/dist/ipc/session/lifecycle.d.ts +8 -1
  108. package/dist/ipc/session/queries.d.ts +5 -1
  109. package/dist/ipc/session/types.d.ts +5 -0
  110. package/dist/ipc/transport/index.d.ts +2 -1
  111. package/dist/ipc/transport/index.js +2 -2
  112. package/dist/runtime/dom/actionEffects.d.ts +106 -0
  113. package/dist/runtime/dom/actionEffects.js +256 -0
  114. package/dist/runtime/dom/actionEffectsScripts.d.ts +52 -0
  115. package/dist/runtime/dom/actionEffectsScripts.js +234 -0
  116. package/dist/runtime/dom/elementGeometry.d.ts +170 -0
  117. package/dist/runtime/dom/elementGeometry.js +553 -0
  118. package/dist/runtime/dom/elementInfo.d.ts +77 -0
  119. package/dist/runtime/dom/elementInfo.js +191 -0
  120. package/dist/runtime/dom/evalHelpers.d.ts +51 -6
  121. package/dist/runtime/dom/evalHelpers.js +136 -26
  122. package/dist/runtime/dom/eventListeners.d.ts +2 -1
  123. package/dist/runtime/dom/eventListeners.js +174 -47
  124. package/dist/runtime/dom/formDiscovery.d.ts +1 -1
  125. package/dist/runtime/dom/formDiscovery.js +116 -16
  126. package/dist/runtime/dom/formFillHelpers/fill.d.ts +10 -0
  127. package/dist/runtime/dom/formFillHelpers/fill.js +125 -10
  128. package/dist/runtime/dom/formFillHelpers/index.d.ts +2 -2
  129. package/dist/runtime/dom/formFillHelpers/index.js +2 -2
  130. package/dist/runtime/dom/formFillHelpers/pressKey.js +14 -3
  131. package/dist/runtime/dom/formFillHelpers/scroll.d.ts +3 -0
  132. package/dist/runtime/dom/formFillHelpers/scroll.js +60 -18
  133. package/dist/runtime/dom/formFillHelpers/shared.d.ts +17 -0
  134. package/dist/runtime/dom/formFillHelpers/shared.js +25 -1
  135. package/dist/runtime/dom/formFillHelpers/stability.d.ts +20 -6
  136. package/dist/runtime/dom/formFillHelpers/stability.js +50 -19
  137. package/dist/runtime/dom/formSubmitHelpers.d.ts +3 -0
  138. package/dist/runtime/dom/formSubmitHelpers.js +89 -15
  139. package/dist/runtime/dom/frameLayout.d.ts +60 -0
  140. package/dist/runtime/dom/frameLayout.js +140 -0
  141. package/dist/runtime/dom/frameOrigin.d.ts +50 -0
  142. package/dist/runtime/dom/frameOrigin.js +62 -0
  143. package/dist/runtime/dom/frameScopedConnection.d.ts +92 -0
  144. package/dist/runtime/dom/frameScopedConnection.js +252 -0
  145. package/dist/runtime/dom/frameSelection.d.ts +1 -1
  146. package/dist/runtime/dom/frameSelection.js +2 -2
  147. package/dist/runtime/dom/frames.d.ts +25 -2
  148. package/dist/runtime/dom/frames.js +202 -63
  149. package/dist/runtime/dom/layout.d.ts +67 -0
  150. package/dist/runtime/dom/layout.js +333 -0
  151. package/dist/runtime/dom/listenerPageScripts.d.ts +66 -0
  152. package/dist/runtime/dom/listenerPageScripts.js +279 -0
  153. package/dist/runtime/dom/listenerSummary.d.ts +132 -11
  154. package/dist/runtime/dom/listenerSummary.js +344 -22
  155. package/dist/runtime/dom/pageActivity.d.ts +41 -0
  156. package/dist/runtime/dom/pageActivity.js +123 -0
  157. package/dist/runtime/dom/reactEventHelpers.d.ts +58 -2
  158. package/dist/runtime/dom/reactEventHelpers.js +212 -41
  159. package/dist/runtime/dom/targetNode.d.ts +80 -27
  160. package/dist/runtime/dom/targetNode.js +249 -33
  161. package/dist/runtime/dom/wait.d.ts +25 -0
  162. package/dist/runtime/dom/wait.js +199 -0
  163. package/dist/runtime/dom/waitCondition.d.ts +71 -0
  164. package/dist/runtime/dom/waitCondition.js +75 -0
  165. package/dist/runtime/page/emulation.d.ts +51 -0
  166. package/dist/runtime/page/emulation.js +80 -0
  167. package/dist/runtime/page/loadingState.d.ts +36 -0
  168. package/dist/runtime/page/loadingState.js +86 -0
  169. package/dist/runtime/page/navigation.d.ts +46 -2
  170. package/dist/runtime/page/navigation.js +69 -33
  171. package/dist/session/QueryCacheManager.d.ts +11 -1
  172. package/dist/session/QueryCacheManager.js +25 -3
  173. package/dist/session/chromeOwners.d.ts +34 -0
  174. package/dist/session/chromeOwners.js +51 -0
  175. package/dist/session/cleanup/staleSession.d.ts +11 -1
  176. package/dist/session/cleanup/staleSession.js +17 -6
  177. package/dist/session/cleanup/userCommands.js +2 -4
  178. package/dist/session/metadata.d.ts +5 -1
  179. package/dist/session/metadata.js +2 -1
  180. package/dist/session/paths.d.ts +77 -3
  181. package/dist/session/paths.js +111 -5
  182. package/dist/session/port.d.ts +31 -7
  183. package/dist/session/port.js +50 -43
  184. package/dist/session/portClaims.d.ts +66 -0
  185. package/dist/session/portClaims.js +284 -0
  186. package/dist/session/sessionList.d.ts +58 -0
  187. package/dist/session/sessionList.js +199 -0
  188. package/dist/session/sessionName.d.ts +46 -0
  189. package/dist/session/sessionName.js +97 -0
  190. package/dist/telemetry/a11y.d.ts +8 -3
  191. package/dist/telemetry/a11y.js +92 -28
  192. package/dist/telemetry/requestKinds.d.ts +32 -0
  193. package/dist/telemetry/requestKinds.js +61 -0
  194. package/dist/telemetry/requestState.d.ts +31 -0
  195. package/dist/telemetry/requestState.js +38 -0
  196. package/dist/types.d.ts +80 -3
  197. package/dist/ui/formatters/a11y.js +3 -0
  198. package/dist/ui/formatters/console/chronological.d.ts +8 -0
  199. package/dist/ui/formatters/console/chronological.js +17 -4
  200. package/dist/ui/formatters/console/json.js +3 -4
  201. package/dist/ui/formatters/console/shared.d.ts +12 -0
  202. package/dist/ui/formatters/console.d.ts +2 -2
  203. package/dist/ui/formatters/console.js +1 -1
  204. package/dist/ui/formatters/details.js +2 -1
  205. package/dist/ui/formatters/dom.d.ts +26 -14
  206. package/dist/ui/formatters/dom.js +65 -52
  207. package/dist/ui/formatters/form.js +29 -18
  208. package/dist/ui/formatters/layout.d.ts +31 -0
  209. package/dist/ui/formatters/layout.js +53 -0
  210. package/dist/ui/formatters/listeners.d.ts +3 -2
  211. package/dist/ui/formatters/listeners.js +73 -9
  212. package/dist/ui/formatters/networkHeaders.js +13 -0
  213. package/dist/ui/formatters/preview.js +2 -1
  214. package/dist/ui/formatters/requestStatus.d.ts +1 -17
  215. package/dist/ui/formatters/requestStatus.js +2 -30
  216. package/dist/ui/formatters/sessions.d.ts +12 -0
  217. package/dist/ui/formatters/sessions.js +40 -0
  218. package/dist/ui/formatters/status.d.ts +21 -2
  219. package/dist/ui/formatters/status.js +47 -10
  220. package/dist/ui/formatters/triggeredRequests.d.ts +36 -0
  221. package/dist/ui/formatters/triggeredRequests.js +65 -0
  222. package/dist/ui/formatting.d.ts +10 -0
  223. package/dist/ui/formatting.js +28 -36
  224. package/dist/ui/messages/chrome.d.ts +9 -0
  225. package/dist/ui/messages/chrome.js +17 -5
  226. package/dist/ui/messages/commands.d.ts +388 -14
  227. package/dist/ui/messages/commands.js +664 -21
  228. package/dist/ui/messages/consoleMessages.d.ts +10 -0
  229. package/dist/ui/messages/consoleMessages.js +17 -0
  230. package/dist/ui/messages/hints.js +2 -1
  231. package/dist/ui/messages/preview.js +5 -4
  232. package/dist/ui/messages/session.d.ts +16 -21
  233. package/dist/ui/messages/session.js +28 -26
  234. package/dist/ui/messages/sessionCommand.d.ts +43 -0
  235. package/dist/ui/messages/sessionCommand.js +52 -0
  236. package/dist/utils/async.d.ts +8 -0
  237. package/dist/utils/async.js +19 -0
  238. package/dist/utils/http.d.ts +22 -1
  239. package/dist/utils/http.js +28 -9
  240. package/dist/utils/selectorFilters.d.ts +36 -8
  241. package/dist/utils/selectorFilters.js +267 -53
  242. package/dist/utils/shellDetection.d.ts +8 -2
  243. package/dist/utils/shellDetection.js +120 -33
  244. package/dist/utils/suggestions.d.ts +26 -0
  245. package/dist/utils/suggestions.js +73 -0
  246. package/dist/utils/taskMappings.js +10 -0
  247. package/dist/utils/url.d.ts +12 -2
  248. package/dist/utils/url.js +69 -7
  249. package/package.json +1 -1
  250. package/dist/ui/formatters/sessionFormatters.d.ts +0 -58
  251. package/dist/ui/formatters/sessionFormatters.js +0 -121
@@ -11,17 +11,17 @@
11
11
  * ```typescript
12
12
  * const resolver = DomElementResolver.getInstance();
13
13
  *
14
- * const target = await resolver.resolve('0');
14
+ * const target = await resolver.resolve('0', undefined, 'click');
15
15
  * // { success: true, selector: '.cached-selector', backendNodeId: 42 }
16
16
  *
17
- * const target = await resolver.resolve('button.submit');
17
+ * const target = await resolver.resolve('button.submit', undefined, 'click');
18
18
  * // { success: true, selector: 'button.submit' }
19
19
  * ```
20
20
  */
21
21
  import { noActiveSessionError } from '../shared/CommandRunner.js';
22
22
  import { CommandError } from '../../errors/index.js';
23
- import { indexOutOfRangeError, indexWithIndexOptionError, staleNodeError, } from '../../errors/messages.js';
24
- import { QueryCacheManager } from '../../session/QueryCacheManager.js';
23
+ import { cachedIndexOutOfRangeError, indexWithIndexOptionError, staleNodeError, } from '../../errors/messages.js';
24
+ import { QueryCacheManager, indexSourceOf, } from '../../session/QueryCacheManager.js';
25
25
  import { isDaemonAlive } from '../../session/daemonSocket.js';
26
26
  import { EXIT_CODES } from '../../utils/exitCodes.js';
27
27
  /**
@@ -58,14 +58,15 @@ export class DomElementResolver {
58
58
  *
59
59
  * @param selectorOrIndex - CSS selector or numeric index from query results
60
60
  * @param explicitIndex - Optional explicit --index flag value (0-based, selectors only)
61
+ * @param command - `bdg dom` subcommand being run, e.g. "click" (for suggestions)
61
62
  * @returns Resolution result
62
63
  */
63
- async resolve(selectorOrIndex, explicitIndex) {
64
+ async resolve(selectorOrIndex, explicitIndex, command) {
64
65
  if (!this.isNumericIndex(selectorOrIndex)) {
65
66
  return { success: true, selector: selectorOrIndex, index: explicitIndex };
66
67
  }
67
68
  if (explicitIndex !== undefined) {
68
- const err = indexWithIndexOptionError(selectorOrIndex);
69
+ const err = indexWithIndexOptionError(selectorOrIndex, command);
69
70
  return {
70
71
  success: false,
71
72
  error: err.message,
@@ -74,10 +75,9 @@ export class DomElementResolver {
74
75
  };
75
76
  }
76
77
  try {
77
- const index = parseInt(selectorOrIndex, 10);
78
- const { node, selector } = await this.lookup(index);
78
+ const { node, selector, source } = await this.lookup(parseInt(selectorOrIndex, 10));
79
79
  if (node.nodeId <= 0) {
80
- const err = staleNodeError(index);
80
+ const err = staleNodeError(source.index, source);
81
81
  return {
82
82
  success: false,
83
83
  error: err.message,
@@ -85,7 +85,13 @@ export class DomElementResolver {
85
85
  suggestion: err.suggestion,
86
86
  };
87
87
  }
88
- return { success: true, selector: node.selector ?? selector, backendNodeId: node.nodeId };
88
+ return {
89
+ success: true,
90
+ selector: node.selector ?? selector,
91
+ backendNodeId: node.nodeId,
92
+ source,
93
+ preview: cachedNodePreview(node),
94
+ };
89
95
  }
90
96
  catch (error) {
91
97
  if (!(error instanceof CommandError))
@@ -107,14 +113,14 @@ export class DomElementResolver {
107
113
  * or the element is no longer in the page (87)
108
114
  */
109
115
  async getNodeIdForIndex(index) {
110
- const { node } = await this.lookup(index);
116
+ const { node, source } = await this.lookup(index);
111
117
  if (node.nodeId <= 0) {
112
- const err = staleNodeError(index);
118
+ const err = staleNodeError(index, source);
113
119
  throw new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.STALE_CACHE);
114
120
  }
115
121
  const { assertNodeAttached } = await import('./helpers/index.js');
116
- await assertNodeAttached(node.nodeId, index);
117
- return node;
122
+ await assertNodeAttached(node.nodeId, source);
123
+ return { nodeId: node.nodeId, source };
118
124
  }
119
125
  /**
120
126
  * Check if the argument is a numeric index.
@@ -140,12 +146,24 @@ export class DomElementResolver {
140
146
  throw new CommandError(validation.error ?? 'No cached query results found', validation.suggestion ? { suggestion: validation.suggestion } : {}, EXIT_CODES.INVALID_ARGUMENTS);
141
147
  }
142
148
  const { nodes, selector } = validation.cache;
149
+ const source = indexSourceOf(index, selector);
143
150
  const node = nodes.find((n) => n.index === index);
144
151
  if (!node) {
145
- const err = indexOutOfRangeError(index, nodes.length - 1);
146
- throw new CommandError(`${err.message} in the last query ("${selector}")`, { suggestion: nodes.length > 0 ? err.suggestion : 'Re-run the query' }, EXIT_CODES.STALE_CACHE);
152
+ const err = cachedIndexOutOfRangeError(source, nodes.length);
153
+ throw new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.STALE_CACHE);
147
154
  }
148
- return { node, selector };
155
+ return { node, selector, source };
149
156
  }
150
157
  }
158
+ /**
159
+ * What a cached element was when it was listed.
160
+ *
161
+ * @param node - Cached node
162
+ * @returns e.g. `h3 "Welcome"`, `button`; undefined without a tag
163
+ */
164
+ function cachedNodePreview(node) {
165
+ if (!node.tag)
166
+ return undefined;
167
+ return node.preview ? `${node.tag} "${node.preview}"` : node.tag;
168
+ }
151
169
  //# sourceMappingURL=DomElementResolver.js.map
@@ -9,6 +9,16 @@
9
9
  * Uses IPC/callCDP pattern for consistency with other DOM commands.
10
10
  */
11
11
  import type { Command } from 'commander';
12
+ import type { A11yQueryResult } from '../../types.js';
13
+ /**
14
+ * The matches to list: the first `limit` (all with 0), counting the rest as
15
+ * omitted. All of them are cached, so their indices work either way.
16
+ *
17
+ * @param result - Query result
18
+ * @param limit - Matches to list (0 = all)
19
+ * @returns The result with the listed matches
20
+ */
21
+ export declare function limitMatches(result: A11yQueryResult, limit: number): A11yQueryResult;
12
22
  /**
13
23
  * Register accessibility commands under 'bdg dom a11y'
14
24
  *
@@ -12,12 +12,15 @@ import { DomElementResolver } from './DomElementResolver.js';
12
12
  import { getDomContext, resolveBackendNodeIds } from './helpers/index.js';
13
13
  import { runCommand, runJsonCommand } from '../shared/CommandRunner.js';
14
14
  import { jsonOption } from '../shared/commonOptions.js';
15
+ import { integerOption } from '../shared/validation.js';
15
16
  import { CommandError } from '../../errors/index.js';
16
17
  import { elementNotFoundError, invalidQueryPatternError, noA11yNodesFoundError, notInAccessibilityTreeError, } from '../../errors/messages.js';
17
- import { QueryCacheManager } from '../../session/QueryCacheManager.js';
18
+ import { A11Y_CACHE_SELECTOR_PREFIX, QueryCacheManager } from '../../session/QueryCacheManager.js';
18
19
  import { a11yIgnoredReasons, collectA11yTree, queryA11yTree, parseQueryPattern, resolveA11yNode, } from '../../telemetry/a11y.js';
19
20
  import { formatA11yTree, formatA11yQueryResult, formatA11yNodeWithContext, } from '../../ui/formatters/a11y.js';
20
21
  import { EXIT_CODES } from '../../utils/exitCodes.js';
22
+ /** Matches `dom a11y query` lists by default in human output (a page can have hundreds of links; JSON lists all) */
23
+ const A11Y_QUERY_LIMIT = 50;
21
24
  /**
22
25
  * Handle bdg dom a11y tree command
23
26
  *
@@ -61,7 +64,8 @@ function quoteQueryValue(text) {
61
64
  * Handle bdg dom a11y query <pattern> command
62
65
  *
63
66
  * Queries the accessibility tree using role/name/description patterns via IPC.
64
- * Pattern format: "role:button name:Submit" (space-separated key:value pairs)
67
+ * Pattern format: "role:button name:Submit" (key:value or key=value pairs; a
68
+ * name or description may contain spaces and colons)
65
69
  *
66
70
  * @param pattern - Query pattern string
67
71
  * @param options - Command options
@@ -88,17 +92,34 @@ async function handleA11yQuery(pattern, options) {
88
92
  }
89
93
  const indexed = { ...result, nodes: result.nodes.map((node, index) => ({ ...node, index })) };
90
94
  await QueryCacheManager.getInstance().set({
91
- selector: `a11y ${pattern}`,
95
+ selector: `${A11Y_CACHE_SELECTOR_PREFIX}${pattern}`,
92
96
  count: indexed.count,
93
97
  nodes: indexed.nodes.map((node) => ({
94
98
  index: node.index,
95
99
  nodeId: node.backendDOMNodeId ?? 0,
96
100
  tag: node.role,
101
+ ...(node.name && { preview: node.name }),
97
102
  })),
98
103
  });
99
- return { success: true, data: indexed };
104
+ return {
105
+ success: true,
106
+ data: limitMatches(indexed, options.limit ?? (options.json ? 0 : A11Y_QUERY_LIMIT)),
107
+ };
100
108
  }, options, formatA11yQueryResult);
101
109
  }
110
+ /**
111
+ * The matches to list: the first `limit` (all with 0), counting the rest as
112
+ * omitted. All of them are cached, so their indices work either way.
113
+ *
114
+ * @param result - Query result
115
+ * @param limit - Matches to list (0 = all)
116
+ * @returns The result with the listed matches
117
+ */
118
+ export function limitMatches(result, limit) {
119
+ if (limit === 0 || result.nodes.length <= limit)
120
+ return result;
121
+ return { ...result, nodes: result.nodes.slice(0, limit), omitted: result.nodes.length - limit };
122
+ }
102
123
  /**
103
124
  * Handle bdg dom a11y describe <selectorOrIndex> command
104
125
  *
@@ -192,7 +213,8 @@ export function registerA11yCommands(domCmd) {
192
213
  a11y
193
214
  .command('query')
194
215
  .description('Query elements by accessibility properties (e.g., "role:button", "name:Submit")')
195
- .argument('<pattern>', 'Fields role, name, description as key:value or key=value, separated by spaces or commas; * is a wildcard (e.g. "role:button name:Submit", "role=link,name=Google Chrome")')
216
+ .argument('<pattern>', "Fields role, name, description as key:value or key=value, separated by spaces or commas; * is a wildcard. A name or description runs to the next field or the end, so it may contain spaces and colons; quote the whole pattern (e.g. 'role=button name=Sign in', 'name=E-mail address:')")
217
+ .option('--limit <n>', `Matches to list (default: ${A11Y_QUERY_LIMIT}, all with --json; 0 = all); all are indexed`, integerOption(0))
196
218
  .addOption(jsonOption())
197
219
  .action(async (pattern, options) => {
198
220
  await handleA11yQuery(pattern, options);
@@ -7,7 +7,9 @@
7
7
  */
8
8
  import type { DomEvalCommandOptions } from '../shared/optionTypes.js';
9
9
  /**
10
- * Handle `bdg dom eval <script> [--frame <frame>]`.
10
+ * Handle `bdg dom eval <script> [--frame <frame>]`. With `--frame`, the
11
+ * frame the script ran in is a `Frame:` line on stderr (JSON: `frame`), so
12
+ * stdout stays the bare value for pipes.
11
13
  */
12
14
  export declare function handleDomEval(script: string, options: DomEvalCommandOptions): Promise<void>;
13
15
  //# sourceMappingURL=eval.d.ts.map
@@ -5,13 +5,17 @@
5
5
  * CLI-side handler. Actual evaluation happens in the daemon via the
6
6
  * `dom_eval` IPC command so the session's persistent CDP connection is reused.
7
7
  */
8
+ import { documentReadyState } from './helpers/query.js';
8
9
  import { runCommand } from '../shared/CommandRunner.js';
9
- import { emptyScriptError } from '../../errors/messages.js';
10
+ import { emptyScriptError, withLoadingHint } from '../../errors/messages.js';
10
11
  import { domEval } from '../../ipc/client.js';
11
12
  import { formatDomEval } from '../../ui/formatters/dom.js';
13
+ import { evalFrameLine } from '../../ui/messages/commands.js';
12
14
  import { EXIT_CODES } from '../../utils/exitCodes.js';
13
15
  /**
14
- * Handle `bdg dom eval <script> [--frame <frame>]`.
16
+ * Handle `bdg dom eval <script> [--frame <frame>]`. With `--frame`, the
17
+ * frame the script ran in is a `Frame:` line on stderr (JSON: `frame`), so
18
+ * stdout stays the bare value for pipes.
15
19
  */
16
20
  export async function handleDomEval(script, options) {
17
21
  await runCommand(async () => {
@@ -26,18 +30,39 @@ export async function handleDomEval(script, options) {
26
30
  }
27
31
  const response = await domEval(script, options.frame);
28
32
  if (response.status === 'error' || !response.data) {
33
+ const suggestion = await frameErrorSuggestion(response, options.frame);
29
34
  return {
30
35
  success: false,
31
36
  error: response.error ?? 'Failed to evaluate script',
32
37
  exitCode: response.exitCode ?? EXIT_CODES.CDP_CONNECTION_FAILURE,
33
- ...(response.suggestion && { errorContext: { suggestion: response.suggestion } }),
38
+ ...(suggestion && { errorContext: { suggestion } }),
34
39
  };
35
40
  }
36
41
  const { value, type, subtype, frame } = response.data;
37
42
  return {
38
43
  success: true,
39
- data: { result: value, type, ...(subtype && { subtype }), ...(frame && { frame }) },
44
+ data: {
45
+ result: value,
46
+ type,
47
+ ...(subtype && { subtype }),
48
+ ...(frame !== undefined && { frame }),
49
+ },
50
+ ...(frame !== undefined && !options.json && { hint: evalFrameLine(frame) }),
40
51
  };
41
52
  }, options, formatDomEval);
42
53
  }
54
+ /**
55
+ * Suggestion of a failed eval; a frame not found (83) while the page is
56
+ * still loading says so (its iframes may not exist yet).
57
+ *
58
+ * @param response - Error response
59
+ * @param frame - The --frame given, if any
60
+ * @returns Suggestion, if any
61
+ */
62
+ async function frameErrorSuggestion(response, frame) {
63
+ if (frame === undefined || response.exitCode !== EXIT_CODES.RESOURCE_NOT_FOUND) {
64
+ return response.suggestion;
65
+ }
66
+ return withLoadingHint(response.suggestion ?? '', await documentReadyState()) || undefined;
67
+ }
43
68
  //# sourceMappingURL=eval.js.map
@@ -4,6 +4,7 @@
4
4
  * Discovers forms on the page with semantic labels, current values,
5
5
  * validation state, and suggested commands for agent consumption.
6
6
  */
7
+ import { calculateSummary, orderForms, primaryButtonIndex } from './formSummary.js';
7
8
  import { resolveBackendNodeIds } from './helpers/index.js';
8
9
  import { runCommand } from '../shared/CommandRunner.js';
9
10
  import { jsonOption } from '../shared/commonOptions.js';
@@ -177,6 +178,7 @@ function transformField(raw) {
177
178
  name: raw.name,
178
179
  placeholder: raw.placeholder,
179
180
  required: raw.required,
181
+ groupLabel: raw.groupLabel,
180
182
  disabled: raw.disabled,
181
183
  readOnly: raw.readOnly,
182
184
  hidden: raw.hidden,
@@ -195,76 +197,21 @@ function transformField(raw) {
195
197
  * Transform raw button to structured FormButton.
196
198
  *
197
199
  * @param raw - Raw button data
200
+ * @param primaryIndex - Index of the form's primary button, if any
198
201
  * @returns Structured FormButton
199
202
  */
200
- function transformButton(raw) {
203
+ function transformButton(raw, primaryIndex) {
201
204
  return {
202
205
  index: raw.index,
203
206
  selector: raw.selector,
204
207
  label: raw.label,
205
208
  type: raw.type,
206
- primary: raw.isPrimary,
209
+ primary: raw.index === primaryIndex,
207
210
  enabled: !raw.disabled,
208
211
  disabledReason: raw.disabled ? 'Button is disabled' : undefined,
209
212
  command: `bdg dom click ${raw.index}`,
210
213
  };
211
214
  }
212
- /**
213
- * Calculate form summary statistics.
214
- *
215
- * @param fields - Transformed form fields
216
- * @param buttons - Transformed form buttons
217
- * @returns Form summary
218
- */
219
- function calculateSummary(fields, buttons) {
220
- const visibleFields = fields.filter((f) => !f.hidden);
221
- const editableFields = visibleFields.filter((f) => !f.disabled && !f.readOnly);
222
- const requiredFields = editableFields.filter((f) => f.required);
223
- const filledFields = editableFields.filter((f) => f.state === 'filled' || f.state === 'checked');
224
- const validFields = editableFields.filter((f) => f.validation.valid);
225
- const invalidFields = editableFields.filter((f) => !f.validation.valid);
226
- const emptyRequired = requiredFields.filter((f) => f.state === 'empty' || f.state === 'unchecked');
227
- const blockers = [];
228
- for (const field of emptyRequired) {
229
- blockers.push({
230
- index: field.index,
231
- label: field.label,
232
- reason: 'Required field is empty',
233
- command: field.command,
234
- });
235
- }
236
- for (const field of invalidFields) {
237
- if (!emptyRequired.includes(field)) {
238
- blockers.push({
239
- index: field.index,
240
- label: field.label,
241
- reason: field.validation.message ?? 'Validation failed',
242
- command: field.command,
243
- });
244
- }
245
- }
246
- const submitButton = buttons.find((b) => b.type === 'submit' && b.primary);
247
- if (submitButton && !submitButton.enabled) {
248
- blockers.push({
249
- index: submitButton.index,
250
- label: submitButton.label,
251
- reason: submitButton.disabledReason ?? 'Submit button is disabled',
252
- command: submitButton.command,
253
- });
254
- }
255
- return {
256
- totalFields: editableFields.length,
257
- filledFields: filledFields.length,
258
- emptyFields: editableFields.length - filledFields.length,
259
- validFields: validFields.length,
260
- invalidFields: invalidFields.length,
261
- requiredTotal: requiredFields.length,
262
- requiredFilled: requiredFields.length - emptyRequired.length,
263
- requiredRemaining: emptyRequired.length,
264
- readyToSubmit: blockers.length === 0,
265
- blockers,
266
- };
267
- }
268
215
  /**
269
216
  * Transform raw form to structured DiscoveredForm.
270
217
  *
@@ -273,7 +220,8 @@ function calculateSummary(fields, buttons) {
273
220
  */
274
221
  function transformForm(raw) {
275
222
  const fields = raw.fields.map(transformField);
276
- const buttons = raw.buttons.map(transformButton);
223
+ const primaryIndex = primaryButtonIndex(raw.buttons);
224
+ const buttons = raw.buttons.map((button) => transformButton(button, primaryIndex));
277
225
  return {
278
226
  index: raw.index,
279
227
  name: raw.name,
@@ -281,6 +229,8 @@ function transformForm(raw) {
281
229
  method: raw.method,
282
230
  step: raw.step ?? undefined,
283
231
  relevanceScore: raw.relevanceScore,
232
+ hidden: raw.hidden === true,
233
+ inDialog: raw.inDialog === true,
284
234
  fields,
285
235
  buttons,
286
236
  summary: calculateSummary(fields, buttons),
@@ -340,7 +290,7 @@ async function handleFormCommand(options) {
340
290
  };
341
291
  }
342
292
  if (rawData.forms.length === 0) {
343
- const err = noFormsFoundError();
293
+ const err = noFormsFoundError(rawData.readyState);
344
294
  return {
345
295
  success: false,
346
296
  error: err.message,
@@ -358,7 +308,7 @@ async function handleFormCommand(options) {
358
308
  errorContext: { suggestion: err.suggestion },
359
309
  };
360
310
  }
361
- const allForms = rawData.forms.map(transformForm);
311
+ const allForms = orderForms(rawData.forms).map(transformForm);
362
312
  const forms = options.all ? allForms : [allForms[0]];
363
313
  // Cache ALL forms so global indices work with bdg dom fill/click
364
314
  await cacheFormElements(allForms);
@@ -370,7 +320,11 @@ async function handleFormCommand(options) {
370
320
  otherForms: allForms.slice(1).map((form) => ({
371
321
  index: form.index,
372
322
  name: form.name,
373
- fieldCount: form.fields.filter((field) => !field.hidden).length,
323
+ fieldCount: form.hidden
324
+ ? form.fields.length
325
+ : form.fields.filter((field) => !field.hidden).length,
326
+ hidden: form.hidden,
327
+ inDialog: form.inDialog,
374
328
  })),
375
329
  }),
376
330
  brief: options.brief,