browser-debugger-cli 0.8.0 → 0.10.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 (304) hide show
  1. package/README.md +7 -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 +29 -6
  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 +189 -119
  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/keyAttributes.d.ts +20 -0
  27. package/dist/commands/dom/helpers/keyAttributes.js +54 -0
  28. package/dist/commands/dom/helpers/query.d.ts +44 -17
  29. package/dist/commands/dom/helpers/query.js +300 -106
  30. package/dist/commands/dom/helpers/runElementCommand.d.ts +10 -2
  31. package/dist/commands/dom/helpers/runElementCommand.js +98 -30
  32. package/dist/commands/dom/helpers/screenshot.d.ts +4 -1
  33. package/dist/commands/dom/helpers/screenshot.js +239 -51
  34. package/dist/commands/dom/index.d.ts +4 -1
  35. package/dist/commands/dom/index.js +22 -7
  36. package/dist/commands/dom/inspect.d.ts +15 -0
  37. package/dist/commands/dom/inspect.js +82 -0
  38. package/dist/commands/dom/layout.d.ts +14 -0
  39. package/dist/commands/dom/layout.js +54 -0
  40. package/dist/commands/dom/listeners.d.ts +5 -1
  41. package/dist/commands/dom/listeners.js +15 -5
  42. package/dist/commands/dom/query.js +2 -3
  43. package/dist/commands/dom/screenshot.d.ts +12 -2
  44. package/dist/commands/dom/screenshot.js +27 -3
  45. package/dist/commands/dom/semanticUtils.d.ts +16 -10
  46. package/dist/commands/dom/semanticUtils.js +53 -16
  47. package/dist/commands/dom/wait.d.ts +13 -0
  48. package/dist/commands/dom/wait.js +83 -0
  49. package/dist/commands/helpJson.js +2 -2
  50. package/dist/commands/network/list.js +17 -13
  51. package/dist/commands/optionBehaviors.js +154 -21
  52. package/dist/commands/page.d.ts +3 -2
  53. package/dist/commands/page.js +100 -5
  54. package/dist/commands/peek.js +4 -11
  55. package/dist/commands/sessions.d.ts +8 -0
  56. package/dist/commands/sessions.js +19 -0
  57. package/dist/commands/shared/CommandRunner.js +4 -4
  58. package/dist/commands/shared/commonOptions.d.ts +4 -0
  59. package/dist/commands/shared/commonOptions.js +9 -0
  60. package/dist/commands/shared/dataFetcher.js +2 -2
  61. package/dist/commands/shared/followMode.d.ts +21 -1
  62. package/dist/commands/shared/followMode.js +29 -2
  63. package/dist/commands/shared/handleValidationError.d.ts +2 -2
  64. package/dist/commands/shared/handleValidationError.js +12 -3
  65. package/dist/commands/shared/optionTypes.d.ts +61 -5
  66. package/dist/commands/shared/startHelpers.d.ts +66 -0
  67. package/dist/commands/shared/startHelpers.js +103 -13
  68. package/dist/commands/shared/validation.d.ts +14 -2
  69. package/dist/commands/shared/validation.js +20 -3
  70. package/dist/commands/start.d.ts +63 -0
  71. package/dist/commands/start.js +115 -15
  72. package/dist/commands/status.js +29 -7
  73. package/dist/commands/stop.js +7 -6
  74. package/dist/commands/tail.js +4 -11
  75. package/dist/commands/types.d.ts +2 -0
  76. package/dist/commands.js +2 -0
  77. package/dist/connection/chromeIdentity.d.ts +65 -0
  78. package/dist/connection/chromeIdentity.js +143 -0
  79. package/dist/connection/launcher/profilePreferences.d.ts +47 -0
  80. package/dist/connection/launcher/profilePreferences.js +151 -0
  81. package/dist/connection/launcher.d.ts +21 -2
  82. package/dist/connection/launcher.js +42 -16
  83. package/dist/connection/portReservation.d.ts +14 -4
  84. package/dist/connection/portReservation.js +21 -6
  85. package/dist/connection/startupExit.d.ts +8 -0
  86. package/dist/connection/startupExit.js +15 -6
  87. package/dist/constants.d.ts +6 -2
  88. package/dist/constants.js +9 -2
  89. package/dist/daemon/SessionController.js +23 -7
  90. package/dist/daemon/errors.d.ts +1 -1
  91. package/dist/daemon/errors.js +1 -1
  92. package/dist/daemon/launcher.d.ts +10 -2
  93. package/dist/daemon/launcher.js +8 -7
  94. package/dist/daemon/server/SocketServer.js +1 -2
  95. package/dist/daemon/session/Session.d.ts +20 -0
  96. package/dist/daemon/session/Session.js +80 -9
  97. package/dist/daemon/session/chromeConnection.d.ts +9 -0
  98. package/dist/daemon/session/chromeConnection.js +45 -8
  99. package/dist/daemon/session/commandRegistry.d.ts +14 -1
  100. package/dist/daemon/session/commandRegistry.js +113 -67
  101. package/dist/daemon/session/interactions.d.ts +48 -9
  102. package/dist/daemon/session/interactions.js +46 -9
  103. package/dist/daemon/session/triggeredRequests.d.ts +67 -0
  104. package/dist/daemon/session/triggeredRequests.js +157 -0
  105. package/dist/daemon/session/types.d.ts +5 -1
  106. package/dist/daemon.js +10630 -3601
  107. package/dist/errors/messages.d.ts +456 -24
  108. package/dist/errors/messages.js +862 -67
  109. package/dist/index.js +6915 -3401
  110. package/dist/ipc/client.d.ts +21 -1
  111. package/dist/ipc/client.js +35 -3
  112. package/dist/ipc/protocol/commands.d.ts +145 -5
  113. package/dist/ipc/protocol/commands.js +4 -0
  114. package/dist/ipc/protocol/domTypes.d.ts +291 -7
  115. package/dist/ipc/protocol/inspectTypes.d.ts +388 -0
  116. package/dist/ipc/protocol/inspectTypes.js +10 -0
  117. package/dist/ipc/session/lifecycle.d.ts +8 -1
  118. package/dist/ipc/session/queries.d.ts +5 -1
  119. package/dist/ipc/session/types.d.ts +5 -0
  120. package/dist/ipc/transport/index.d.ts +2 -1
  121. package/dist/ipc/transport/index.js +2 -2
  122. package/dist/runtime/dom/actionEffects.d.ts +185 -0
  123. package/dist/runtime/dom/actionEffects.js +402 -0
  124. package/dist/runtime/dom/actionEffectsScripts.d.ts +90 -0
  125. package/dist/runtime/dom/actionEffectsScripts.js +426 -0
  126. package/dist/runtime/dom/elementGeometry.d.ts +170 -0
  127. package/dist/runtime/dom/elementGeometry.js +553 -0
  128. package/dist/runtime/dom/elementInfo.d.ts +103 -0
  129. package/dist/runtime/dom/elementInfo.js +256 -0
  130. package/dist/runtime/dom/evalHelpers.d.ts +51 -6
  131. package/dist/runtime/dom/evalHelpers.js +136 -26
  132. package/dist/runtime/dom/eventListeners.d.ts +2 -1
  133. package/dist/runtime/dom/eventListeners.js +184 -47
  134. package/dist/runtime/dom/formDiscovery.d.ts +1 -1
  135. package/dist/runtime/dom/formDiscovery.js +116 -16
  136. package/dist/runtime/dom/formFillHelpers/fill.d.ts +9 -0
  137. package/dist/runtime/dom/formFillHelpers/fill.js +178 -14
  138. package/dist/runtime/dom/formFillHelpers/index.d.ts +2 -2
  139. package/dist/runtime/dom/formFillHelpers/index.js +2 -2
  140. package/dist/runtime/dom/formFillHelpers/pressKey.js +14 -3
  141. package/dist/runtime/dom/formFillHelpers/scroll.d.ts +3 -0
  142. package/dist/runtime/dom/formFillHelpers/scroll.js +60 -18
  143. package/dist/runtime/dom/formFillHelpers/shared.d.ts +17 -0
  144. package/dist/runtime/dom/formFillHelpers/shared.js +25 -1
  145. package/dist/runtime/dom/formFillHelpers/stability.d.ts +20 -6
  146. package/dist/runtime/dom/formFillHelpers/stability.js +50 -19
  147. package/dist/runtime/dom/formSubmitHelpers.d.ts +3 -0
  148. package/dist/runtime/dom/formSubmitHelpers.js +89 -15
  149. package/dist/runtime/dom/frameLayout.d.ts +60 -0
  150. package/dist/runtime/dom/frameLayout.js +140 -0
  151. package/dist/runtime/dom/frameOrigin.d.ts +50 -0
  152. package/dist/runtime/dom/frameOrigin.js +62 -0
  153. package/dist/runtime/dom/frameScopedConnection.d.ts +92 -0
  154. package/dist/runtime/dom/frameScopedConnection.js +252 -0
  155. package/dist/runtime/dom/frameSelection.d.ts +12 -1
  156. package/dist/runtime/dom/frameSelection.js +22 -3
  157. package/dist/runtime/dom/frames.d.ts +61 -5
  158. package/dist/runtime/dom/frames.js +329 -75
  159. package/dist/runtime/dom/inspect.d.ts +28 -0
  160. package/dist/runtime/dom/inspect.js +557 -0
  161. package/dist/runtime/dom/inspectAllStyles.d.ts +62 -0
  162. package/dist/runtime/dom/inspectAllStyles.js +385 -0
  163. package/dist/runtime/dom/inspectCascade.d.ts +94 -0
  164. package/dist/runtime/dom/inspectCascade.js +371 -0
  165. package/dist/runtime/dom/inspectCascadeModel.d.ts +39 -0
  166. package/dist/runtime/dom/inspectCascadeModel.js +232 -0
  167. package/dist/runtime/dom/inspectHints.d.ts +62 -0
  168. package/dist/runtime/dom/inspectHints.js +305 -0
  169. package/dist/runtime/dom/inspectLayoutModel.d.ts +87 -0
  170. package/dist/runtime/dom/inspectLayoutModel.js +346 -0
  171. package/dist/runtime/dom/inspectModel.d.ts +74 -0
  172. package/dist/runtime/dom/inspectModel.js +184 -0
  173. package/dist/runtime/dom/inspectPaintModel.d.ts +157 -0
  174. package/dist/runtime/dom/inspectPaintModel.js +461 -0
  175. package/dist/runtime/dom/inspectRules.d.ts +37 -0
  176. package/dist/runtime/dom/inspectRules.js +101 -0
  177. package/dist/runtime/dom/inspectScripts.d.ts +132 -0
  178. package/dist/runtime/dom/inspectScripts.js +263 -0
  179. package/dist/runtime/dom/inspectTree.d.ts +40 -0
  180. package/dist/runtime/dom/inspectTree.js +134 -0
  181. package/dist/runtime/dom/inspectVariables.d.ts +33 -0
  182. package/dist/runtime/dom/inspectVariables.js +94 -0
  183. package/dist/runtime/dom/inspectWhyModel.d.ts +20 -0
  184. package/dist/runtime/dom/inspectWhyModel.js +134 -0
  185. package/dist/runtime/dom/layout.d.ts +71 -0
  186. package/dist/runtime/dom/layout.js +340 -0
  187. package/dist/runtime/dom/listenerPageScripts.d.ts +72 -0
  188. package/dist/runtime/dom/listenerPageScripts.js +365 -0
  189. package/dist/runtime/dom/listenerSummary.d.ts +136 -11
  190. package/dist/runtime/dom/listenerSummary.js +361 -22
  191. package/dist/runtime/dom/pageActivity.d.ts +41 -0
  192. package/dist/runtime/dom/pageActivity.js +123 -0
  193. package/dist/runtime/dom/reactEventHelpers.d.ts +63 -2
  194. package/dist/runtime/dom/reactEventHelpers.js +220 -41
  195. package/dist/runtime/dom/targetNode.d.ts +80 -27
  196. package/dist/runtime/dom/targetNode.js +249 -33
  197. package/dist/runtime/dom/wait.d.ts +25 -0
  198. package/dist/runtime/dom/wait.js +199 -0
  199. package/dist/runtime/dom/waitCondition.d.ts +71 -0
  200. package/dist/runtime/dom/waitCondition.js +75 -0
  201. package/dist/runtime/page/emulation.d.ts +71 -0
  202. package/dist/runtime/page/emulation.js +117 -0
  203. package/dist/runtime/page/loadingState.d.ts +36 -0
  204. package/dist/runtime/page/loadingState.js +86 -0
  205. package/dist/runtime/page/navigation.d.ts +46 -2
  206. package/dist/runtime/page/navigation.js +69 -33
  207. package/dist/session/QueryCacheManager.d.ts +11 -1
  208. package/dist/session/QueryCacheManager.js +25 -3
  209. package/dist/session/chromeOwners.d.ts +34 -0
  210. package/dist/session/chromeOwners.js +51 -0
  211. package/dist/session/cleanup/staleSession.d.ts +11 -1
  212. package/dist/session/cleanup/staleSession.js +17 -6
  213. package/dist/session/cleanup/userCommands.js +2 -4
  214. package/dist/session/metadata.d.ts +5 -1
  215. package/dist/session/metadata.js +2 -1
  216. package/dist/session/paths.d.ts +77 -3
  217. package/dist/session/paths.js +111 -5
  218. package/dist/session/port.d.ts +31 -7
  219. package/dist/session/port.js +50 -43
  220. package/dist/session/portClaims.d.ts +66 -0
  221. package/dist/session/portClaims.js +284 -0
  222. package/dist/session/sessionList.d.ts +58 -0
  223. package/dist/session/sessionList.js +199 -0
  224. package/dist/session/sessionName.d.ts +46 -0
  225. package/dist/session/sessionName.js +97 -0
  226. package/dist/telemetry/a11y.d.ts +18 -3
  227. package/dist/telemetry/a11y.js +170 -29
  228. package/dist/telemetry/console.d.ts +1 -0
  229. package/dist/telemetry/console.js +100 -5
  230. package/dist/telemetry/network.js +3 -1
  231. package/dist/telemetry/requestKinds.d.ts +32 -0
  232. package/dist/telemetry/requestKinds.js +61 -0
  233. package/dist/telemetry/requestState.d.ts +31 -0
  234. package/dist/telemetry/requestState.js +38 -0
  235. package/dist/types.d.ts +112 -3
  236. package/dist/ui/formatters/a11y.js +3 -0
  237. package/dist/ui/formatters/console/chronological.d.ts +8 -0
  238. package/dist/ui/formatters/console/chronological.js +17 -4
  239. package/dist/ui/formatters/console/json.js +3 -4
  240. package/dist/ui/formatters/console/shared.d.ts +12 -0
  241. package/dist/ui/formatters/console.d.ts +2 -2
  242. package/dist/ui/formatters/console.js +1 -1
  243. package/dist/ui/formatters/details.d.ts +8 -0
  244. package/dist/ui/formatters/details.js +61 -4
  245. package/dist/ui/formatters/dom.d.ts +27 -14
  246. package/dist/ui/formatters/dom.js +88 -59
  247. package/dist/ui/formatters/form.js +29 -18
  248. package/dist/ui/formatters/inspect.d.ts +39 -0
  249. package/dist/ui/formatters/inspect.js +596 -0
  250. package/dist/ui/formatters/keyAttributes.d.ts +19 -0
  251. package/dist/ui/formatters/keyAttributes.js +84 -0
  252. package/dist/ui/formatters/layout.d.ts +31 -0
  253. package/dist/ui/formatters/layout.js +53 -0
  254. package/dist/ui/formatters/listeners.d.ts +3 -2
  255. package/dist/ui/formatters/listeners.js +73 -9
  256. package/dist/ui/formatters/networkHeaders.d.ts +13 -0
  257. package/dist/ui/formatters/networkHeaders.js +36 -3
  258. package/dist/ui/formatters/networkList.d.ts +29 -1
  259. package/dist/ui/formatters/networkList.js +86 -20
  260. package/dist/ui/formatters/preview.js +2 -1
  261. package/dist/ui/formatters/requestStatus.d.ts +1 -17
  262. package/dist/ui/formatters/requestStatus.js +2 -30
  263. package/dist/ui/formatters/sessions.d.ts +12 -0
  264. package/dist/ui/formatters/sessions.js +40 -0
  265. package/dist/ui/formatters/status.d.ts +21 -2
  266. package/dist/ui/formatters/status.js +47 -10
  267. package/dist/ui/formatters/triggeredRequests.d.ts +36 -0
  268. package/dist/ui/formatters/triggeredRequests.js +65 -0
  269. package/dist/ui/formatting.d.ts +19 -0
  270. package/dist/ui/formatting.js +31 -36
  271. package/dist/ui/messages/chrome.d.ts +9 -0
  272. package/dist/ui/messages/chrome.js +17 -5
  273. package/dist/ui/messages/commands.d.ts +504 -14
  274. package/dist/ui/messages/commands.js +835 -21
  275. package/dist/ui/messages/consoleMessages.d.ts +10 -0
  276. package/dist/ui/messages/consoleMessages.js +17 -0
  277. package/dist/ui/messages/hints.js +2 -1
  278. package/dist/ui/messages/networkMessages.d.ts +14 -0
  279. package/dist/ui/messages/networkMessages.js +18 -0
  280. package/dist/ui/messages/preview.js +5 -4
  281. package/dist/ui/messages/session.d.ts +30 -21
  282. package/dist/ui/messages/session.js +48 -26
  283. package/dist/ui/messages/sessionCommand.d.ts +43 -0
  284. package/dist/ui/messages/sessionCommand.js +52 -0
  285. package/dist/utils/async.d.ts +17 -0
  286. package/dist/utils/async.js +36 -0
  287. package/dist/utils/color.d.ts +84 -0
  288. package/dist/utils/color.js +376 -0
  289. package/dist/utils/cssValues.d.ts +109 -0
  290. package/dist/utils/cssValues.js +236 -0
  291. package/dist/utils/http.d.ts +22 -1
  292. package/dist/utils/http.js +28 -9
  293. package/dist/utils/selectorFilters.d.ts +48 -8
  294. package/dist/utils/selectorFilters.js +296 -53
  295. package/dist/utils/shellDetection.d.ts +8 -2
  296. package/dist/utils/shellDetection.js +120 -33
  297. package/dist/utils/suggestions.d.ts +26 -0
  298. package/dist/utils/suggestions.js +73 -0
  299. package/dist/utils/taskMappings.js +10 -0
  300. package/dist/utils/url.d.ts +12 -2
  301. package/dist/utils/url.js +69 -7
  302. package/package.json +1 -1
  303. package/dist/ui/formatters/sessionFormatters.d.ts +0 -58
  304. package/dist/ui/formatters/sessionFormatters.js +0 -121
@@ -5,15 +5,18 @@
5
5
  * Keeps individual command handlers focused on option wiring and output formatting.
6
6
  */
7
7
  import { DomElementResolver } from '../DomElementResolver.js';
8
- import { UNREACHABLE_ELEMENTS_HINT, staleNodeError } from '../../../errors/messages.js';
8
+ import { noMatchContext } from './query.js';
9
+ import { otherIndexSourceNote, staleNodeError, shadowBoundaryLine, unreachableElementsNote, withLoadingHint, } from '../../../errors/messages.js';
10
+ import { joinLines } from '../../../ui/formatting.js';
9
11
  import { EXIT_CODES } from '../../../utils/exitCodes.js';
10
12
  /**
11
13
  * Resolve an element target, invoke the IPC call, and normalize failures
12
- * into the structured `CommandRunner` result shape.
14
+ * into the structured `CommandRunner` result shape. A numeric index names the
15
+ * list it refers to (`indexSource` in the data, and in errors).
13
16
  */
14
17
  export async function runElementCommand(options) {
15
- const { selectorOrIndex, index, buildRequest, call, action, failureSuggestion } = options;
16
- const target = await DomElementResolver.getInstance().resolve(selectorOrIndex, index);
18
+ const { selectorOrIndex, index, command, buildRequest, call } = options;
19
+ const target = await DomElementResolver.getInstance().resolve(selectorOrIndex, index, command);
17
20
  if (!target.success) {
18
21
  return {
19
22
  success: false,
@@ -28,36 +31,101 @@ export async function runElementCommand(options) {
28
31
  ...(target.backendNodeId !== undefined && { backendNodeId: target.backendNodeId }),
29
32
  });
30
33
  const response = await call(request);
31
- if (response.status === 'error' || !response.data) {
32
- const staleIndex = response.exitCode === EXIT_CODES.STALE_CACHE && /^\d+$/.test(selectorOrIndex)
33
- ? staleNodeError(Number(selectorOrIndex)).message
34
- : undefined;
35
- return {
36
- success: false,
37
- error: staleIndex ?? response.error ?? `Failed to ${action}`,
38
- exitCode: response.exitCode ?? EXIT_CODES.INVALID_ARGUMENTS,
39
- ...(response.suggestion && { errorContext: { suggestion: response.suggestion } }),
40
- };
34
+ const failure = response.status === 'error' || !response.data
35
+ ? errorResponseFailure(response, options)
36
+ : response.data.success
37
+ ? undefined
38
+ : failedResultFailure(response.data, options);
39
+ if (failure && target.source) {
40
+ return indexFailure(failure, target.source, target.preview, response.data);
41
41
  }
42
- const result = response.data;
43
- if (!result.success) {
44
- const exitCode = result.exitCode ??
45
- (result.error?.includes('not found')
46
- ? EXIT_CODES.RESOURCE_NOT_FOUND
47
- : EXIT_CODES.INVALID_ARGUMENTS);
48
- const suggestion = result.suggestion ?? failureSuggestion;
42
+ if (failure)
43
+ return withNotFoundContext(failure, target.selector, response.status !== 'error');
44
+ const { success: _success, ...data } = response.data;
45
+ return { success: true, data: { ...data, ...(target.source && { indexSource: target.source }) } };
46
+ }
47
+ /**
48
+ * A failure on a cached index, told in terms of the index: a stale element
49
+ * (87) names the index and the command that refreshes it, and an element a
50
+ * form command cannot act on, from the results of another command, gets a
51
+ * note on which list the index refers to.
52
+ *
53
+ * @param failure - Failed command result
54
+ * @param source - The index and the list it refers to
55
+ * @param preview - What the cached element was when listed
56
+ * @param result - Action result, when the daemon answered
57
+ * @returns The failure in terms of the index
58
+ */
59
+ function indexFailure(failure, source, preview, result) {
60
+ if (failure.exitCode === EXIT_CODES.STALE_CACHE) {
61
+ const err = staleNodeError(source.index, source);
49
62
  return {
50
63
  success: false,
51
- error: result.error ?? `Failed to ${action}`,
52
- exitCode,
53
- errorContext: {
54
- suggestion: exitCode === EXIT_CODES.RESOURCE_NOT_FOUND
55
- ? `${suggestion} (${UNREACHABLE_ELEMENTS_HINT})`
56
- : suggestion,
57
- },
64
+ error: err.message,
65
+ exitCode: EXIT_CODES.STALE_CACHE,
66
+ errorContext: { suggestion: err.suggestion },
58
67
  };
59
68
  }
60
- const { success: _success, ...data } = result;
61
- return { success: true, data };
69
+ if (!result?.unsuitableElement || source.command === 'dom form')
70
+ return failure;
71
+ const note = otherIndexSourceNote(source, preview);
72
+ return {
73
+ ...failure,
74
+ errorContext: { suggestion: joinLines(failure.errorContext?.suggestion, note) },
75
+ };
76
+ }
77
+ /**
78
+ * Failure for an error response of the daemon.
79
+ *
80
+ * @param response - Error response
81
+ * @param options - Command options (selector or index, action)
82
+ * @returns Failed command result
83
+ */
84
+ function errorResponseFailure(response, options) {
85
+ return {
86
+ success: false,
87
+ error: response.error ?? `Failed to ${options.action}`,
88
+ exitCode: response.exitCode ?? EXIT_CODES.INVALID_ARGUMENTS,
89
+ ...(response.suggestion && { errorContext: { suggestion: response.suggestion } }),
90
+ };
91
+ }
92
+ /**
93
+ * Failure for an action whose page script reported failure.
94
+ *
95
+ * @param result - Action result
96
+ * @param options - Command options (action, fallback suggestion)
97
+ * @returns Failed command result
98
+ */
99
+ function failedResultFailure(result, options) {
100
+ const exitCode = result.exitCode ??
101
+ (result.error?.includes('not found')
102
+ ? EXIT_CODES.RESOURCE_NOT_FOUND
103
+ : EXIT_CODES.INVALID_ARGUMENTS);
104
+ return {
105
+ success: false,
106
+ error: result.error ?? `Failed to ${options.action}`,
107
+ exitCode,
108
+ errorContext: { suggestion: result.suggestion ?? options.failureSuggestion },
109
+ };
110
+ }
111
+ /**
112
+ * Add what the page says to a "not found" failure (one page evaluation, on
113
+ * this failure path only, {@link noMatchContext}): similar ids or classes, a
114
+ * shadow host the selector tries to cross,
115
+ * the places selectors do not search (for a page script that found nothing)
116
+ * and the still-loading hint while the page loads.
117
+ *
118
+ * @param failure - Failed command result
119
+ * @param selector - Selector that was looked for (the cached query's for an index)
120
+ * @param searched - The page script searched the page (the daemon did not fail first)
121
+ * @returns The failure, with the context in its suggestion
122
+ */
123
+ async function withNotFoundContext(failure, selector, searched) {
124
+ if (failure.exitCode !== EXIT_CODES.RESOURCE_NOT_FOUND)
125
+ return failure;
126
+ const context = await noMatchContext(selector);
127
+ const note = searched ? unreachableElementsNote(selector, context.unsearched) : '';
128
+ const suggestion = withLoadingHint(joinLines(context.similar, context.shadowHost && shadowBoundaryLine(context.shadowHost), failure.errorContext?.suggestion, note ? note : undefined), context.readyState, selector);
129
+ return suggestion ? { ...failure, errorContext: { suggestion } } : failure;
62
130
  }
63
131
  //# sourceMappingURL=runElementCommand.js.map
@@ -20,7 +20,10 @@ export declare function getElementBounds(ref: NodeRef): Promise<ElementBounds>;
20
20
  */
21
21
  export declare function capturePageScreenshot(outputPath: string, options?: ScreenshotOptions): Promise<ScreenshotResult>;
22
22
  /**
23
- * Capture a screenshot of a single element, clipped to its bounding box.
23
+ * Capture a screenshot of a single element: its border box, grown to include
24
+ * content overflowing it ({@link captureArea}). The box model is relative to
25
+ * the viewport and the capture clip to the page, so the page scroll is added
26
+ * (the reported bounds are page coordinates, like `dom layout`'s).
24
27
  */
25
28
  export declare function captureElementScreenshot(outputPath: string, ref: NodeRef, options?: {
26
29
  format?: 'png' | 'jpeg';
@@ -11,6 +11,8 @@ import { CommandError } from '../../../errors/index.js';
11
11
  import { noNodesFoundError, elementNotVisibleError, elementZeroDimensionsError, } from '../../../errors/messages.js';
12
12
  import { callCDP } from '../../../ipc/client.js';
13
13
  import { DEEP_QUERY_JS, selectorArgsJS } from '../../../runtime/dom/targetNode.js';
14
+ import { viewportOverride } from '../../../runtime/page/emulation.js';
15
+ import { readSessionMetadata } from '../../../session/metadata.js';
14
16
  import { createLogger } from '../../../ui/logging/index.js';
15
17
  import { EXIT_CODES } from '../../../utils/exitCodes.js';
16
18
  const log = createLogger('dom');
@@ -136,6 +138,52 @@ async function restoreScrollPosition(position) {
136
138
  returnByValue: true,
137
139
  });
138
140
  }
141
+ /**
142
+ * The window's size with its scrollbars (`innerWidth`/`innerHeight`): an
143
+ * override at this size keeps the page's layout, where the visible size
144
+ * (without scrollbars) would narrow it and move centered content.
145
+ *
146
+ * @param viewport - Visible viewport size, used when the page does not answer
147
+ * @returns Width and height in CSS px
148
+ */
149
+ async function windowSize(viewport) {
150
+ const response = await callCDP('Runtime.evaluate', {
151
+ expression: '[window.innerWidth, window.innerHeight]',
152
+ returnByValue: true,
153
+ });
154
+ const value = response.data?.result?.result?.value;
155
+ const [width, height] = Array.isArray(value) ? value : [];
156
+ return {
157
+ width: Math.round(width ?? viewport.clientWidth),
158
+ height: Math.round(height ?? viewport.clientHeight),
159
+ };
160
+ }
161
+ /**
162
+ * Capture at a pixel ratio of 1 (CSS px = image px) on a high-DPI display:
163
+ * the viewport is overridden at the window's size (the session's
164
+ * `--viewport`, else the window with its scrollbars, so the layout does not
165
+ * change) until the returned function puts back what was there before, the
166
+ * session's viewport or none.
167
+ *
168
+ * @param devicePixelRatio - Page's pixel ratio
169
+ * @param viewport - Visible viewport size
170
+ * @returns Function restoring the device metrics
171
+ */
172
+ async function useUnitPixelRatio(devicePixelRatio, viewport) {
173
+ if (devicePixelRatio === 1)
174
+ return () => Promise.resolve();
175
+ const sessionViewport = readSessionMetadata()?.viewport;
176
+ const size = sessionViewport ?? (await windowSize(viewport));
177
+ await callCDP('Emulation.setDeviceMetricsOverride', viewportOverride(size, 1));
178
+ return async () => {
179
+ if (sessionViewport) {
180
+ await callCDP('Emulation.setDeviceMetricsOverride', viewportOverride(sessionViewport));
181
+ }
182
+ else {
183
+ await callCDP('Emulation.clearDeviceMetricsOverride', {});
184
+ }
185
+ };
186
+ }
139
187
  /**
140
188
  * Get the bounding box (border box, so padding and border are included) of an
141
189
  * element via CDP DOM.getBoxModel.
@@ -161,6 +209,20 @@ export async function getElementBounds(ref) {
161
209
  }
162
210
  return { x, y, width, height };
163
211
  }
212
+ /**
213
+ * Page coordinates of the visible area's top-left corner. A capture clip is
214
+ * in page coordinates, so a viewport capture must start at the scroll
215
+ * position, not at the page origin (which shows nothing once scrolled). Read
216
+ * after any metrics override, which can move the scroll position.
217
+ *
218
+ * @returns Scroll offset of the visual viewport in CSS pixels
219
+ */
220
+ async function visibleAreaOrigin() {
221
+ const response = await callCDP('Page.getLayoutMetrics', {});
222
+ const metrics = response.data?.result;
223
+ const viewport = metrics?.cssVisualViewport;
224
+ return { x: viewport?.pageX ?? 0, y: viewport?.pageY ?? 0 };
225
+ }
164
226
  /**
165
227
  * Capture a screenshot of the page. Auto-resizes oversized pages by default
166
228
  * to keep Claude Vision token cost bounded; falls back to viewport capture
@@ -193,13 +255,8 @@ export async function capturePageScreenshot(outputPath, options = {}) {
193
255
  const scale = resized ? calculateResizeScale(captureWidth, captureHeight) : 1;
194
256
  const finalWidth = Math.round(captureWidth * scale);
195
257
  const finalHeight = Math.round(captureHeight * scale);
258
+ const restoreMetrics = await useUnitPixelRatio(devicePixelRatio, viewport);
196
259
  if (devicePixelRatio !== 1) {
197
- await callCDP('Emulation.setDeviceMetricsOverride', {
198
- width: Math.round(viewport.clientWidth),
199
- height: Math.round(viewport.clientHeight),
200
- deviceScaleFactor: 1,
201
- mobile: false,
202
- });
203
260
  if (options.scroll) {
204
261
  await callCDP('Runtime.evaluate', {
205
262
  expression: `(${DEEP_QUERY_JS})(${selectorArgsJS(options.scroll)})[0]?.scrollIntoView({ block: 'center', behavior: 'instant' })`,
@@ -207,18 +264,7 @@ export async function capturePageScreenshot(outputPath, options = {}) {
207
264
  });
208
265
  }
209
266
  }
210
- let clipX = 0;
211
- let clipY = 0;
212
- if (useScroll && !effectiveFullPage) {
213
- const scrollResponse = await callCDP('Runtime.evaluate', {
214
- expression: 'JSON.stringify({ x: window.scrollX, y: window.scrollY })',
215
- returnByValue: true,
216
- });
217
- const scrollPos = JSON.parse(scrollResponse.data?.result?.result?.value ??
218
- '{"x":0,"y":0}');
219
- clipX = scrollPos.x;
220
- clipY = scrollPos.y;
221
- }
267
+ const clipOrigin = effectiveFullPage ? { x: 0, y: 0 } : await visibleAreaOrigin();
222
268
  let screenshotResult;
223
269
  try {
224
270
  const screenshotResponse = await callCDP('Page.captureScreenshot', {
@@ -226,8 +272,8 @@ export async function capturePageScreenshot(outputPath, options = {}) {
226
272
  ...(quality !== undefined && { quality }),
227
273
  captureBeyondViewport: effectiveFullPage,
228
274
  clip: {
229
- x: clipX,
230
- y: clipY,
275
+ x: clipOrigin.x,
276
+ y: clipOrigin.y,
231
277
  width: captureWidth,
232
278
  height: captureHeight,
233
279
  scale,
@@ -236,9 +282,7 @@ export async function capturePageScreenshot(outputPath, options = {}) {
236
282
  screenshotResult = screenshotResponse.data?.result;
237
283
  }
238
284
  finally {
239
- if (devicePixelRatio !== 1) {
240
- await callCDP('Emulation.clearDeviceMetricsOverride', {});
241
- }
285
+ await restoreMetrics();
242
286
  }
243
287
  if (!screenshotResult?.data) {
244
288
  throw new CDPConnectionError('No screenshot data returned', new Error('Empty response'));
@@ -287,11 +331,143 @@ export async function capturePageScreenshot(outputPath, options = {}) {
287
331
  }
288
332
  return result;
289
333
  }
334
+ /** Descendants {@link CONTENT_OVERFLOW_JS} looks at, so a huge element stays cheap */
335
+ const OVERFLOW_SCAN_LIMIT = 2000;
336
+ /**
337
+ * Page-side distances (CSS px, never negative) by which an element's rendered
338
+ * descendants reach beyond its border box on each side: uncleared floats,
339
+ * absolutely positioned and transformed children. Descendants of an element
340
+ * that clips its overflow (`overflow` other than `visible`) are cut off by it
341
+ * and not counted, nor are fixed ones (they belong to the viewport) or what
342
+ * lies outside the document (skip links at -9999px). Zero everywhere when the
343
+ * element clips its own overflow.
344
+ */
345
+ const CONTENT_OVERFLOW_JS = `function () {
346
+ const view = this.ownerDocument.defaultView;
347
+ const scroller = this.ownerDocument.scrollingElement || this.ownerDocument.documentElement;
348
+ const own = this.getBoundingClientRect();
349
+ const reach = { left: own.left, top: own.top, right: own.right, bottom: own.bottom };
350
+ const page = { left: -view.scrollX, top: -view.scrollY, right: scroller.scrollWidth - view.scrollX, bottom: scroller.scrollHeight - view.scrollY };
351
+ const clips = (style) => style.overflowX !== 'visible' || style.overflowY !== 'visible';
352
+ let budget = ${OVERFLOW_SCAN_LIMIT};
353
+ const walk = (el) => {
354
+ for (const child of el.children) {
355
+ if (--budget < 0) return;
356
+ const style = view.getComputedStyle(child);
357
+ if (style.display === 'none' || style.position === 'fixed') continue;
358
+ const r = child.getBoundingClientRect();
359
+ if (r.width > 0 && r.height > 0 && style.visibility === 'visible') {
360
+ reach.left = Math.min(reach.left, Math.max(r.left, page.left));
361
+ reach.top = Math.min(reach.top, Math.max(r.top, page.top));
362
+ reach.right = Math.max(reach.right, Math.min(r.right, page.right));
363
+ reach.bottom = Math.max(reach.bottom, Math.min(r.bottom, page.bottom));
364
+ }
365
+ if (!clips(style)) walk(child);
366
+ }
367
+ };
368
+ if (!clips(view.getComputedStyle(this))) walk(this);
369
+ return { left: own.left - reach.left, top: own.top - reach.top, right: reach.right - own.right, bottom: reach.bottom - own.bottom };
370
+ }`;
371
+ /**
372
+ * The visible viewport (without scrollbars) in CSS px.
373
+ *
374
+ * @returns Width and height
375
+ */
376
+ async function visibleViewport() {
377
+ const metrics = (await callCDP('Page.getLayoutMetrics', {})).data?.result;
378
+ const view = metrics?.cssVisualViewport ?? metrics?.visualViewport;
379
+ return { width: view?.clientWidth ?? 0, height: view?.clientHeight ?? 0 };
380
+ }
290
381
  /**
291
- * Capture a screenshot of a single element, clipped to its bounding box.
382
+ * Whether an area (viewport coordinates) lies inside the viewport.
383
+ *
384
+ * @param area - Area
385
+ * @param view - Viewport size
386
+ * @returns True when fully inside
387
+ */
388
+ function insideView(area, view) {
389
+ return (area.x >= 0 &&
390
+ area.y >= 0 &&
391
+ area.x + area.width <= view.width &&
392
+ area.y + area.height <= view.height);
393
+ }
394
+ /**
395
+ * Measure the area to capture and, when it fits in the viewport but is not
396
+ * in view, scroll it to the middle first. A capture inside the viewport
397
+ * keeps the page as it is; one beyond it makes Chrome lay the page out
398
+ * without its scrollbar, which moves centered content by half the
399
+ * scrollbar's width, so it is used only for areas larger than the viewport.
400
+ *
401
+ * @param ref - Node reference
402
+ * @returns Border box, area to capture (viewport coordinates) and whether it is in view
403
+ */
404
+ async function measureInView(ref) {
405
+ const view = await visibleViewport();
406
+ let box = await getElementBounds(ref);
407
+ let bounds = await captureArea(ref, box);
408
+ const fits = bounds.width <= view.width && bounds.height <= view.height;
409
+ if (fits && !insideView(bounds, view)) {
410
+ const dx = bounds.x + bounds.width / 2 - view.width / 2;
411
+ const dy = bounds.y + bounds.height / 2 - view.height / 2;
412
+ await callCDP('Runtime.evaluate', { expression: `window.scrollBy(${dx}, ${dy})` });
413
+ box = await getElementBounds(ref);
414
+ bounds = await captureArea(ref, box);
415
+ }
416
+ return { box, bounds, inView: insideView(bounds, view) };
417
+ }
418
+ /** Overflow (px) below which the capture keeps to the border box (subpixel rounding) */
419
+ const OVERFLOW_SLACK = 1;
420
+ /**
421
+ * Area an element screenshot captures: the border box, grown to the content
422
+ * that overflows it ({@link CONTENT_OVERFLOW_JS}), so floated children are
423
+ * not cropped away.
424
+ *
425
+ * @param ref - Node reference
426
+ * @param bounds - Border box (DOM.getBoxModel coordinates)
427
+ * @returns The area, or the border box when nothing overflows (or the page cannot be asked)
428
+ */
429
+ async function captureArea(ref, bounds) {
430
+ const objectGroup = `bdg-shot-${process.pid}`;
431
+ try {
432
+ const resolved = await callCDP('DOM.resolveNode', { ...ref, objectGroup });
433
+ const objectId = resolved.data?.result?.object
434
+ .objectId;
435
+ if (!objectId)
436
+ return bounds;
437
+ const response = await callCDP('Runtime.callFunctionOn', {
438
+ objectId,
439
+ functionDeclaration: CONTENT_OVERFLOW_JS,
440
+ returnByValue: true,
441
+ });
442
+ const overflow = response.data?.result
443
+ ?.result?.value;
444
+ if (!overflow)
445
+ return bounds;
446
+ const [left, top, right, bottom] = ['left', 'top', 'right', 'bottom'].map((side) => Math.max(0, overflow[side] ?? 0));
447
+ if (Math.max(left, top, right, bottom) <= OVERFLOW_SLACK)
448
+ return bounds;
449
+ return {
450
+ x: bounds.x - left,
451
+ y: bounds.y - top,
452
+ width: bounds.width + left + right,
453
+ height: bounds.height + top + bottom,
454
+ };
455
+ }
456
+ catch (error) {
457
+ log.debug(`Could not measure overflowing content: ${String(error)}`);
458
+ return bounds;
459
+ }
460
+ finally {
461
+ await callCDP('Runtime.releaseObjectGroup', { objectGroup }).catch(() => undefined);
462
+ }
463
+ }
464
+ /**
465
+ * Capture a screenshot of a single element: its border box, grown to include
466
+ * content overflowing it ({@link captureArea}). The box model is relative to
467
+ * the viewport and the capture clip to the page, so the page scroll is added
468
+ * (the reported bounds are page coordinates, like `dom layout`'s).
292
469
  */
293
470
  export async function captureElementScreenshot(outputPath, ref, options = {}) {
294
- const bounds = await getElementBounds(ref);
295
471
  const format = options.format ?? 'png';
296
472
  const quality = format === 'jpeg' ? (options.quality ?? 90) : undefined;
297
473
  const noResize = options.noResize ?? false;
@@ -300,6 +476,18 @@ export async function captureElementScreenshot(outputPath, ref, options = {}) {
300
476
  returnByValue: true,
301
477
  });
302
478
  const devicePixelRatio = dprResponse.data?.result?.result?.value ?? 1;
479
+ const before = (await callCDP('Page.getLayoutMetrics', {})).data?.result;
480
+ const restoreMetrics = await useUnitPixelRatio(devicePixelRatio, before?.visualViewport ?? { clientWidth: 800, clientHeight: 600 });
481
+ let box;
482
+ let bounds;
483
+ let inView;
484
+ try {
485
+ ({ box, bounds, inView } = await measureInView(ref));
486
+ }
487
+ catch (error) {
488
+ await restoreMetrics();
489
+ throw error;
490
+ }
303
491
  const originalWidth = bounds.width;
304
492
  const originalHeight = bounds.height;
305
493
  const resized = shouldResize(originalWidth, originalHeight, noResize);
@@ -308,35 +496,25 @@ export async function captureElementScreenshot(outputPath, ref, options = {}) {
308
496
  const finalHeight = Math.round(originalHeight * scale);
309
497
  const metricsResponse = await callCDP('Page.getLayoutMetrics', {});
310
498
  const metricsResult = metricsResponse.data?.result;
311
- const viewport = metricsResult?.visualViewport ?? { clientWidth: 800, clientHeight: 600 };
312
- if (devicePixelRatio !== 1) {
313
- await callCDP('Emulation.setDeviceMetricsOverride', {
314
- width: Math.round(viewport.clientWidth),
315
- height: Math.round(viewport.clientHeight),
316
- deviceScaleFactor: 1,
317
- mobile: false,
318
- });
319
- }
499
+ const scroll = metricsResult?.cssLayoutViewport ?? { pageX: 0, pageY: 0 };
500
+ const onPage = (area) => ({
501
+ ...area,
502
+ x: area.x + scroll.pageX,
503
+ y: area.y + scroll.pageY,
504
+ });
505
+ const clip = onPage(bounds);
320
506
  let screenshotResult;
321
507
  try {
322
508
  const screenshotResponse = await callCDP('Page.captureScreenshot', {
323
509
  format,
324
510
  ...(quality !== undefined && { quality }),
325
- clip: {
326
- x: bounds.x,
327
- y: bounds.y,
328
- width: bounds.width,
329
- height: bounds.height,
330
- scale,
331
- },
332
- captureBeyondViewport: true,
511
+ clip: { ...clip, scale },
512
+ captureBeyondViewport: !inView,
333
513
  });
334
514
  screenshotResult = screenshotResponse.data?.result;
335
515
  }
336
516
  finally {
337
- if (devicePixelRatio !== 1) {
338
- await callCDP('Emulation.clearDeviceMetricsOverride', {});
339
- }
517
+ await restoreMetrics();
340
518
  }
341
519
  if (!screenshotResult?.data) {
342
520
  throw new CDPConnectionError('No screenshot data returned', new Error('Empty response'));
@@ -352,12 +530,8 @@ export async function captureElementScreenshot(outputPath, ref, options = {}) {
352
530
  fullPage: false,
353
531
  finalTokens: calculateImageTokens(finalWidth, finalHeight),
354
532
  element: {
355
- bounds: {
356
- x: Math.round(bounds.x),
357
- y: Math.round(bounds.y),
358
- width: Math.round(bounds.width),
359
- height: Math.round(bounds.height),
360
- },
533
+ bounds: roundBounds(onPage(box)),
534
+ ...(bounds !== box && { captured: roundBounds(clip) }),
361
535
  },
362
536
  };
363
537
  if (quality !== undefined) {
@@ -371,4 +545,18 @@ export async function captureElementScreenshot(outputPath, ref, options = {}) {
371
545
  }
372
546
  return result;
373
547
  }
548
+ /**
549
+ * Bounds in whole pixels.
550
+ *
551
+ * @param bounds - Bounds
552
+ * @returns Rounded bounds
553
+ */
554
+ function roundBounds(bounds) {
555
+ return {
556
+ x: Math.round(bounds.x),
557
+ y: Math.round(bounds.y),
558
+ width: Math.round(bounds.width),
559
+ height: Math.round(bounds.height),
560
+ };
561
+ }
374
562
  //# sourceMappingURL=screenshot.js.map
@@ -8,11 +8,14 @@
8
8
  * - `eval.ts` — evaluate JavaScript in the page (or an iframe)
9
9
  * - `frames.ts` — list the page's iframes
10
10
  * - `listeners.ts` — list event listeners that run for an element
11
+ * - `layout.ts` — positions, sizes and visibility of elements
12
+ * - `inspect.ts` — what one element looks like (styles, box, layout, child tree)
13
+ * - `wait.ts` — wait for elements to appear, show, contain a text or go away
11
14
  *
12
15
  * Form-related commands register via `form.ts` and `formInteraction.ts`.
13
16
  * Accessibility commands register via `a11y.ts`.
14
17
  */
15
- import type { Command } from 'commander';
18
+ import { type Command } from 'commander';
16
19
  /**
17
20
  * Register DOM telemetry commands on the root Commander program.
18
21
  */
@@ -8,18 +8,26 @@
8
8
  * - `eval.ts` — evaluate JavaScript in the page (or an iframe)
9
9
  * - `frames.ts` — list the page's iframes
10
10
  * - `listeners.ts` — list event listeners that run for an element
11
+ * - `layout.ts` — positions, sizes and visibility of elements
12
+ * - `inspect.ts` — what one element looks like (styles, box, layout, child tree)
13
+ * - `wait.ts` — wait for elements to appear, show, contain a text or go away
11
14
  *
12
15
  * Form-related commands register via `form.ts` and `formInteraction.ts`.
13
16
  * Accessibility commands register via `a11y.ts`.
14
17
  */
18
+ import { Option } from 'commander';
15
19
  import { registerA11yCommands } from './a11y.js';
16
20
  import { handleDomEval } from './eval.js';
17
21
  import { registerFormCommand } from './form.js';
18
22
  import { handleDomFrames } from './frames.js';
19
- import { handleDomGet } from './get.js';
23
+ import { DOM_GET_DEFAULT_SELECTOR, handleDomGet } from './get.js';
24
+ import { registerInspectCommand } from './inspect.js';
25
+ import { registerLayoutCommand } from './layout.js';
20
26
  import { registerListenersCommand } from './listeners.js';
21
27
  import { handleDomQuery } from './query.js';
22
28
  import { handleDomScreenshot } from './screenshot.js';
29
+ import { registerWaitCommand } from './wait.js';
30
+ import { SELECTOR_OR_INDEX_ARGUMENT, SELECTOR_SCOPE_HELP, } from '../shared/commonOptions.js';
23
31
  import { integerOption, screenshotFormatOption } from '../shared/validation.js';
24
32
  /**
25
33
  * Register DOM telemetry commands on the root Commander program.
@@ -32,11 +40,15 @@ export function registerDomCommands(program) {
32
40
  registerA11yCommands(dom);
33
41
  registerFormCommand(dom);
34
42
  registerListenersCommand(dom);
43
+ registerLayoutCommand(dom);
44
+ registerInspectCommand(dom);
45
+ registerWaitCommand(dom);
35
46
  dom
36
47
  .command('query')
37
48
  .description('Find elements by CSS selector')
38
49
  .argument('<selector>', 'CSS selector (e.g., ".error", "#app", "button")')
39
50
  .option('-j, --json', 'Output as JSON')
51
+ .addHelpText('after', SELECTOR_SCOPE_HELP)
40
52
  .action(async (selector, options) => {
41
53
  await handleDomQuery(selector, options);
42
54
  });
@@ -44,7 +56,7 @@ export function registerDomCommands(program) {
44
56
  .command('eval')
45
57
  .description('Evaluate JavaScript expression in the page context')
46
58
  .argument('<script>', 'JavaScript to execute (e.g., "document.title", "window.location.href")')
47
- .option('--frame <frame>', 'Evaluate in an iframe, cross-origin ones included: index, name/id attribute, or part of the URL (see dom frames)')
59
+ .option('--frame <frame>', 'Evaluate in an iframe, cross-origin ones included: index (from dom frames; 87 when stale), name/id attribute, or part of the name, id or URL')
48
60
  .option('-j, --json', 'Output as JSON')
49
61
  .action(async (script, options) => {
50
62
  await handleDomEval(script, options);
@@ -60,7 +72,7 @@ export function registerDomCommands(program) {
60
72
  });
61
73
  dom
62
74
  .command('frames')
63
- .description("List the page's iframes (nested and cross-origin ones included) for eval --frame")
75
+ .description("List the page's iframes in document order (nested and cross-origin ones included) for eval --frame")
64
76
  .option('-j, --json', 'Output as JSON')
65
77
  .action(async (options) => {
66
78
  await handleDomFrames(options);
@@ -68,10 +80,12 @@ export function registerDomCommands(program) {
68
80
  dom
69
81
  .command('get')
70
82
  .description('Get semantic accessibility structure (default) or raw HTML (--raw)')
71
- .argument('[selector]', 'CSS selector or index from query results (e.g., ".error", "#app", 0); optional with --node-id')
83
+ .argument('[selectorOrIndex]', `${SELECTOR_OR_INDEX_ARGUMENT} (e.g. ".error", "#app", 0); default: ${DOM_GET_DEFAULT_SELECTOR}`)
72
84
  .option('--raw', 'Output raw HTML with all filtering options')
85
+ .option('--full', 'Show all of the element text (default: the first 500 characters)')
73
86
  .option('--all', 'Get all matches (only with --raw)')
74
- .option('--nth <n>', 'Get the nth match, 0-based (only with --raw)', integerOption(0))
87
+ .option('--index <n>', 'Element index if selector matches multiple (0-based)', integerOption(0))
88
+ .addOption(new Option('--nth <n>', 'Alias of --index').argParser(integerOption(0)).hideHelp())
75
89
  .option('--node-id <id>', 'Get the element with this node id (from dom query/get --raw or a11y describe; implies --raw)', integerOption(1))
76
90
  .option('-j, --json', 'Output as JSON')
77
91
  .action(async (selector, options) => {
@@ -81,6 +95,7 @@ export function registerDomCommands(program) {
81
95
  .command('screenshot')
82
96
  .description('Capture page or element screenshot')
83
97
  .argument('<path>', 'Output file path, or directory for --follow mode')
98
+ .argument('[selector]', 'Element to capture: CSS selector or index from a query (same as --selector / --index)')
84
99
  .option('--selector <selector>', 'CSS selector for element capture')
85
100
  .option('--index <number>', 'Cached element index (0-based) from previous query', integerOption(0))
86
101
  .option('--format <format>', 'Image format: png or jpeg/jpg (default: from the file extension, else png)', screenshotFormatOption)
@@ -92,8 +107,8 @@ export function registerDomCommands(program) {
92
107
  .option('--interval <ms>', 'Capture interval for --follow (default: 1000)')
93
108
  .option('--limit <count>', 'Max frames for --follow')
94
109
  .option('-j, --json', 'Output as JSON')
95
- .action(async (path, options) => {
96
- await handleDomScreenshot(path, options);
110
+ .action(async (path, target, options) => {
111
+ await handleDomScreenshot(path, target, options);
97
112
  });
98
113
  }
99
114
  //# sourceMappingURL=index.js.map