browxai 0.7.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 (520) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +139 -0
  3. package/THIRD_PARTY_NOTICES.md +45 -0
  4. package/dist/cli/chrome.d.ts +1 -0
  5. package/dist/cli/chrome.js +130 -0
  6. package/dist/cli/command-registry.d.ts +15 -0
  7. package/dist/cli/command-registry.js +35 -0
  8. package/dist/cli/doctor-plugins.d.ts +18 -0
  9. package/dist/cli/doctor-plugins.js +338 -0
  10. package/dist/cli/doctor.d.ts +9 -0
  11. package/dist/cli/doctor.js +407 -0
  12. package/dist/cli/init.d.ts +1 -0
  13. package/dist/cli/init.js +200 -0
  14. package/dist/cli/register-commands.d.ts +1 -0
  15. package/dist/cli/register-commands.js +22 -0
  16. package/dist/cli/serve.d.ts +14 -0
  17. package/dist/cli/serve.js +151 -0
  18. package/dist/cli.d.ts +3 -0
  19. package/dist/cli.js +129 -0
  20. package/dist/engine/adapters/adb.d.ts +72 -0
  21. package/dist/engine/adapters/adb.js +200 -0
  22. package/dist/engine/adapters/android-cdp.d.ts +54 -0
  23. package/dist/engine/adapters/android-cdp.js +110 -0
  24. package/dist/engine/adapters/android.engine.d.ts +1 -0
  25. package/dist/engine/adapters/android.engine.js +31 -0
  26. package/dist/engine/adapters/chromium.engine.d.ts +1 -0
  27. package/dist/engine/adapters/chromium.engine.js +44 -0
  28. package/dist/engine/adapters/firefox.engine.d.ts +1 -0
  29. package/dist/engine/adapters/firefox.engine.js +43 -0
  30. package/dist/engine/adapters/playwright-chromium.d.ts +43 -0
  31. package/dist/engine/adapters/playwright-chromium.js +56 -0
  32. package/dist/engine/adapters/playwright-firefox.d.ts +52 -0
  33. package/dist/engine/adapters/playwright-firefox.js +97 -0
  34. package/dist/engine/adapters/playwright-webkit.d.ts +40 -0
  35. package/dist/engine/adapters/playwright-webkit.js +79 -0
  36. package/dist/engine/adapters/safari/bidi-client.d.ts +46 -0
  37. package/dist/engine/adapters/safari/bidi-client.js +130 -0
  38. package/dist/engine/adapters/safari/launch.d.ts +56 -0
  39. package/dist/engine/adapters/safari/launch.js +104 -0
  40. package/dist/engine/adapters/safari/webdriver-client.d.ts +102 -0
  41. package/dist/engine/adapters/safari/webdriver-client.js +175 -0
  42. package/dist/engine/adapters/safari.engine.d.ts +1 -0
  43. package/dist/engine/adapters/safari.engine.js +52 -0
  44. package/dist/engine/adapters/safaridriver-hybrid.d.ts +56 -0
  45. package/dist/engine/adapters/safaridriver-hybrid.js +127 -0
  46. package/dist/engine/adapters/webkit.engine.d.ts +1 -0
  47. package/dist/engine/adapters/webkit.engine.js +47 -0
  48. package/dist/engine/capabilities.d.ts +53 -0
  49. package/dist/engine/capabilities.js +122 -0
  50. package/dist/engine/capability-registry.d.ts +9 -0
  51. package/dist/engine/capability-registry.js +20 -0
  52. package/dist/engine/index.d.ts +18 -0
  53. package/dist/engine/index.js +14 -0
  54. package/dist/engine/register-engines.d.ts +5 -0
  55. package/dist/engine/register-engines.js +16 -0
  56. package/dist/engine/registry.d.ts +145 -0
  57. package/dist/engine/registry.js +67 -0
  58. package/dist/engine/select.d.ts +48 -0
  59. package/dist/engine/select.js +128 -0
  60. package/dist/engine/session-cdp.d.ts +13 -0
  61. package/dist/engine/session-cdp.js +22 -0
  62. package/dist/engine/tool-gate.d.ts +19 -0
  63. package/dist/engine/tool-gate.js +226 -0
  64. package/dist/engine/types.d.ts +71 -0
  65. package/dist/engine/types.js +16 -0
  66. package/dist/helper/bridge.d.ts +48 -0
  67. package/dist/helper/bridge.js +200 -0
  68. package/dist/helper/browx-page.d.ts +1 -0
  69. package/dist/helper/browx-page.js +47 -0
  70. package/dist/helper/overlay-hide.d.ts +9 -0
  71. package/dist/helper/overlay-hide.js +49 -0
  72. package/dist/helper/stealth.d.ts +10 -0
  73. package/dist/helper/stealth.js +88 -0
  74. package/dist/index.d.ts +7 -0
  75. package/dist/index.js +15 -0
  76. package/dist/page/a11y.d.ts +81 -0
  77. package/dist/page/a11y.js +219 -0
  78. package/dist/page/action-substrate.d.ts +64 -0
  79. package/dist/page/action-substrate.js +118 -0
  80. package/dist/page/actionresult-blocks.d.ts +99 -0
  81. package/dist/page/actionresult-blocks.js +144 -0
  82. package/dist/page/actionresult-shape.d.ts +48 -0
  83. package/dist/page/actionresult-shape.js +155 -0
  84. package/dist/page/actionresult-types.d.ts +368 -0
  85. package/dist/page/actionresult-types.js +4 -0
  86. package/dist/page/actionresult.d.ts +4 -0
  87. package/dist/page/actionresult.js +299 -0
  88. package/dist/page/actions-probe.d.ts +32 -0
  89. package/dist/page/actions-probe.js +294 -0
  90. package/dist/page/actions-scroll.d.ts +40 -0
  91. package/dist/page/actions-scroll.js +53 -0
  92. package/dist/page/actions.d.ts +132 -0
  93. package/dist/page/actions.js +453 -0
  94. package/dist/page/archive-assets.d.ts +39 -0
  95. package/dist/page/archive-assets.js +187 -0
  96. package/dist/page/archive.d.ts +47 -0
  97. package/dist/page/archive.js +349 -0
  98. package/dist/page/asset-export.d.ts +122 -0
  99. package/dist/page/asset-export.js +376 -0
  100. package/dist/page/await_network.d.ts +16 -0
  101. package/dist/page/await_network.js +23 -0
  102. package/dist/page/bbox.d.ts +37 -0
  103. package/dist/page/bbox.js +115 -0
  104. package/dist/page/canvas-capture.d.ts +82 -0
  105. package/dist/page/canvas-capture.js +257 -0
  106. package/dist/page/canvas-diff.d.ts +51 -0
  107. package/dist/page/canvas-diff.js +131 -0
  108. package/dist/page/canvas-gesture.d.ts +53 -0
  109. package/dist/page/canvas-gesture.js +167 -0
  110. package/dist/page/canvas-transform.d.ts +96 -0
  111. package/dist/page/canvas-transform.js +150 -0
  112. package/dist/page/canvas.d.ts +8 -0
  113. package/dist/page/canvas.js +50 -0
  114. package/dist/page/capture-substrate.d.ts +111 -0
  115. package/dist/page/capture-substrate.js +139 -0
  116. package/dist/page/clipboard.d.ts +25 -0
  117. package/dist/page/clipboard.js +50 -0
  118. package/dist/page/clock.d.ts +36 -0
  119. package/dist/page/clock.js +167 -0
  120. package/dist/page/compose.d.ts +55 -0
  121. package/dist/page/compose.js +169 -0
  122. package/dist/page/console.d.ts +39 -0
  123. package/dist/page/console.js +73 -0
  124. package/dist/page/coverage.d.ts +97 -0
  125. package/dist/page/coverage.js +280 -0
  126. package/dist/page/dom-export.d.ts +41 -0
  127. package/dist/page/dom-export.js +193 -0
  128. package/dist/page/dom-walk.d.ts +91 -0
  129. package/dist/page/dom-walk.js +267 -0
  130. package/dist/page/dom_diff.d.ts +48 -0
  131. package/dist/page/dom_diff.js +121 -0
  132. package/dist/page/downloads.d.ts +80 -0
  133. package/dist/page/downloads.js +244 -0
  134. package/dist/page/drop-files.d.ts +78 -0
  135. package/dist/page/drop-files.js +310 -0
  136. package/dist/page/element-export-discovery.d.ts +64 -0
  137. package/dist/page/element-export-discovery.js +346 -0
  138. package/dist/page/element-export.d.ts +46 -0
  139. package/dist/page/element-export.js +251 -0
  140. package/dist/page/emulation-substrate.d.ts +53 -0
  141. package/dist/page/emulation-substrate.js +87 -0
  142. package/dist/page/emulation.d.ts +60 -0
  143. package/dist/page/emulation.js +162 -0
  144. package/dist/page/export-playwright-script.d.ts +47 -0
  145. package/dist/page/export-playwright-script.js +304 -0
  146. package/dist/page/extract-resolve.d.ts +22 -0
  147. package/dist/page/extract-resolve.js +341 -0
  148. package/dist/page/extract-schema.d.ts +20 -0
  149. package/dist/page/extract-schema.js +200 -0
  150. package/dist/page/extract-types.d.ts +127 -0
  151. package/dist/page/extract-types.js +8 -0
  152. package/dist/page/extract-warnings.d.ts +8 -0
  153. package/dist/page/extract-warnings.js +56 -0
  154. package/dist/page/extract.d.ts +9 -0
  155. package/dist/page/extract.js +174 -0
  156. package/dist/page/fill-form.d.ts +58 -0
  157. package/dist/page/fill-form.js +261 -0
  158. package/dist/page/find.d.ts +158 -0
  159. package/dist/page/find.js +470 -0
  160. package/dist/page/frames.d.ts +45 -0
  161. package/dist/page/frames.js +133 -0
  162. package/dist/page/generate-locator.d.ts +57 -0
  163. package/dist/page/generate-locator.js +136 -0
  164. package/dist/page/gestures.d.ts +128 -0
  165. package/dist/page/gestures.js +198 -0
  166. package/dist/page/har.d.ts +91 -0
  167. package/dist/page/har.js +174 -0
  168. package/dist/page/heap.d.ts +97 -0
  169. package/dist/page/heap.js +285 -0
  170. package/dist/page/inspect.d.ts +34 -0
  171. package/dist/page/inspect.js +75 -0
  172. package/dist/page/layout-thrash.d.ts +34 -0
  173. package/dist/page/layout-thrash.js +232 -0
  174. package/dist/page/learning.d.ts +21 -0
  175. package/dist/page/learning.js +84 -0
  176. package/dist/page/locator.d.ts +54 -0
  177. package/dist/page/locator.js +142 -0
  178. package/dist/page/memory-diff.d.ts +48 -0
  179. package/dist/page/memory-diff.js +105 -0
  180. package/dist/page/network-mask.d.ts +8 -0
  181. package/dist/page/network-mask.js +18 -0
  182. package/dist/page/network-playwright.d.ts +96 -0
  183. package/dist/page/network-playwright.js +353 -0
  184. package/dist/page/network-substrate-select.d.ts +18 -0
  185. package/dist/page/network-substrate-select.js +32 -0
  186. package/dist/page/network-substrate.d.ts +109 -0
  187. package/dist/page/network-substrate.js +161 -0
  188. package/dist/page/network-ws.d.ts +46 -0
  189. package/dist/page/network-ws.js +113 -0
  190. package/dist/page/network.d.ts +194 -0
  191. package/dist/page/network.js +415 -0
  192. package/dist/page/overflow-detect.d.ts +102 -0
  193. package/dist/page/overflow-detect.js +449 -0
  194. package/dist/page/pdf.d.ts +69 -0
  195. package/dist/page/pdf.js +109 -0
  196. package/dist/page/perf-audit-analysers.d.ts +40 -0
  197. package/dist/page/perf-audit-analysers.js +369 -0
  198. package/dist/page/perf-audit-runner.d.ts +20 -0
  199. package/dist/page/perf-audit-runner.js +195 -0
  200. package/dist/page/perf-audit-types.d.ts +41 -0
  201. package/dist/page/perf-audit-types.js +5 -0
  202. package/dist/page/perf-audit.d.ts +37 -0
  203. package/dist/page/perf-audit.js +377 -0
  204. package/dist/page/perf.d.ts +127 -0
  205. package/dist/page/perf.js +373 -0
  206. package/dist/page/plan.d.ts +192 -0
  207. package/dist/page/plan.js +308 -0
  208. package/dist/page/point_probe.d.ts +46 -0
  209. package/dist/page/point_probe.js +99 -0
  210. package/dist/page/recording.d.ts +67 -0
  211. package/dist/page/recording.js +172 -0
  212. package/dist/page/refs.d.ts +92 -0
  213. package/dist/page/refs.js +134 -0
  214. package/dist/page/regions.d.ts +23 -0
  215. package/dist/page/regions.js +32 -0
  216. package/dist/page/routes.d.ts +40 -0
  217. package/dist/page/routes.js +87 -0
  218. package/dist/page/safari-actions.d.ts +12 -0
  219. package/dist/page/safari-actions.js +144 -0
  220. package/dist/page/sample.d.ts +64 -0
  221. package/dist/page/sample.js +216 -0
  222. package/dist/page/screenshot-on.d.ts +51 -0
  223. package/dist/page/screenshot-on.js +150 -0
  224. package/dist/page/screenshot-save.d.ts +36 -0
  225. package/dist/page/screenshot-save.js +53 -0
  226. package/dist/page/screenshot-schedule.d.ts +50 -0
  227. package/dist/page/screenshot-schedule.js +155 -0
  228. package/dist/page/script-substrate.d.ts +32 -0
  229. package/dist/page/script-substrate.js +47 -0
  230. package/dist/page/seed-random.d.ts +45 -0
  231. package/dist/page/seed-random.js +144 -0
  232. package/dist/page/set-of-marks.d.ts +96 -0
  233. package/dist/page/set-of-marks.js +245 -0
  234. package/dist/page/shadow.d.ts +136 -0
  235. package/dist/page/shadow.js +400 -0
  236. package/dist/page/shortcut.d.ts +50 -0
  237. package/dist/page/shortcut.js +147 -0
  238. package/dist/page/snapshot-substrate-safari.d.ts +30 -0
  239. package/dist/page/snapshot-substrate-safari.js +84 -0
  240. package/dist/page/snapshot-substrate-select.d.ts +24 -0
  241. package/dist/page/snapshot-substrate-select.js +34 -0
  242. package/dist/page/snapshot-substrate.d.ts +58 -0
  243. package/dist/page/snapshot-substrate.js +135 -0
  244. package/dist/page/snapshot.d.ts +24 -0
  245. package/dist/page/snapshot.js +162 -0
  246. package/dist/page/solve-captcha.d.ts +76 -0
  247. package/dist/page/solve-captcha.js +286 -0
  248. package/dist/page/storage-substrate-types.d.ts +221 -0
  249. package/dist/page/storage-substrate-types.js +6 -0
  250. package/dist/page/storage-substrate.d.ts +215 -0
  251. package/dist/page/storage-substrate.js +280 -0
  252. package/dist/page/structural.d.ts +9 -0
  253. package/dist/page/structural.js +152 -0
  254. package/dist/page/substrate-bundle-safari.d.ts +8 -0
  255. package/dist/page/substrate-bundle-safari.js +42 -0
  256. package/dist/page/substrate-bundle.d.ts +6 -0
  257. package/dist/page/substrate-bundle.js +53 -0
  258. package/dist/page/text_search.d.ts +44 -0
  259. package/dist/page/text_search.js +90 -0
  260. package/dist/page/upload.d.ts +28 -0
  261. package/dist/page/upload.js +62 -0
  262. package/dist/page/verify.d.ts +63 -0
  263. package/dist/page/verify.js +451 -0
  264. package/dist/page/video.d.ts +115 -0
  265. package/dist/page/video.js +169 -0
  266. package/dist/page/visibility.d.ts +22 -0
  267. package/dist/page/visibility.js +94 -0
  268. package/dist/page/watch.d.ts +29 -0
  269. package/dist/page/watch.js +99 -0
  270. package/dist/page/workers.d.ts +126 -0
  271. package/dist/page/workers.js +490 -0
  272. package/dist/page/ws-interactive.d.ts +82 -0
  273. package/dist/page/ws-interactive.js +318 -0
  274. package/dist/plugin/cli.d.ts +45 -0
  275. package/dist/plugin/cli.js +496 -0
  276. package/dist/plugin/command-registry.d.ts +9 -0
  277. package/dist/plugin/command-registry.js +23 -0
  278. package/dist/plugin/depgraph.d.ts +37 -0
  279. package/dist/plugin/depgraph.js +186 -0
  280. package/dist/plugin/manifest.d.ts +182 -0
  281. package/dist/plugin/manifest.js +219 -0
  282. package/dist/plugin/package-manager.d.ts +22 -0
  283. package/dist/plugin/package-manager.js +40 -0
  284. package/dist/plugin/resolver.d.ts +85 -0
  285. package/dist/plugin/resolver.js +166 -0
  286. package/dist/plugin/runtime.d.ts +77 -0
  287. package/dist/plugin/runtime.js +402 -0
  288. package/dist/plugin/types.d.ts +113 -0
  289. package/dist/plugin/types.js +4 -0
  290. package/dist/policy/confirm.d.ts +76 -0
  291. package/dist/policy/confirm.js +162 -0
  292. package/dist/policy/origin.d.ts +17 -0
  293. package/dist/policy/origin.js +79 -0
  294. package/dist/sdk/client.d.ts +21 -0
  295. package/dist/sdk/client.js +174 -0
  296. package/dist/sdk/index.d.ts +32 -0
  297. package/dist/sdk/index.js +61 -0
  298. package/dist/sdk/plugin-types.d.ts +33 -0
  299. package/dist/sdk/plugin-types.js +22 -0
  300. package/dist/sdk/registry.d.ts +17 -0
  301. package/dist/sdk/registry.js +94 -0
  302. package/dist/sdk/socket-transport.d.ts +20 -0
  303. package/dist/sdk/socket-transport.js +90 -0
  304. package/dist/sdk/tool-types.d.ts +634 -0
  305. package/dist/sdk/tool-types.js +28 -0
  306. package/dist/sdk/transport-in-process.d.ts +21 -0
  307. package/dist/sdk/transport-in-process.js +44 -0
  308. package/dist/sdk/transport-registry.d.ts +19 -0
  309. package/dist/sdk/transport-registry.js +31 -0
  310. package/dist/sdk/transport-socket.d.ts +12 -0
  311. package/dist/sdk/transport-socket.js +77 -0
  312. package/dist/sdk/transport-stdio-child.d.ts +10 -0
  313. package/dist/sdk/transport-stdio-child.js +47 -0
  314. package/dist/sdk/transport.d.ts +10 -0
  315. package/dist/sdk/transport.js +35 -0
  316. package/dist/sdk/types.d.ts +176 -0
  317. package/dist/sdk/types.js +10 -0
  318. package/dist/server.d.ts +33 -0
  319. package/dist/server.js +327 -0
  320. package/dist/session/artifacts.d.ts +52 -0
  321. package/dist/session/artifacts.js +177 -0
  322. package/dist/session/byob-attach.d.ts +26 -0
  323. package/dist/session/byob-attach.js +187 -0
  324. package/dist/session/byob.d.ts +8 -0
  325. package/dist/session/byob.js +20 -0
  326. package/dist/session/cache-storage.d.ts +100 -0
  327. package/dist/session/cache-storage.js +166 -0
  328. package/dist/session/device-emu.d.ts +149 -0
  329. package/dist/session/device-emu.js +545 -0
  330. package/dist/session/device.d.ts +14 -0
  331. package/dist/session/device.js +44 -0
  332. package/dist/session/dialog.d.ts +62 -0
  333. package/dist/session/dialog.js +164 -0
  334. package/dist/session/emulation.d.ts +69 -0
  335. package/dist/session/emulation.js +168 -0
  336. package/dist/session/extensions.d.ts +113 -0
  337. package/dist/session/extensions.js +237 -0
  338. package/dist/session/fs-picker.d.ts +144 -0
  339. package/dist/session/fs-picker.js +666 -0
  340. package/dist/session/idb-storage.d.ts +86 -0
  341. package/dist/session/idb-storage.js +229 -0
  342. package/dist/session/incognito.d.ts +3 -0
  343. package/dist/session/incognito.js +20 -0
  344. package/dist/session/launch-options.d.ts +41 -0
  345. package/dist/session/launch-options.js +200 -0
  346. package/dist/session/managed.d.ts +3 -0
  347. package/dist/session/managed.js +16 -0
  348. package/dist/session/metrics.d.ts +45 -0
  349. package/dist/session/metrics.js +75 -0
  350. package/dist/session/notification.d.ts +122 -0
  351. package/dist/session/notification.js +426 -0
  352. package/dist/session/permission.d.ts +144 -0
  353. package/dist/session/permission.js +600 -0
  354. package/dist/session/playwright-post-wire.d.ts +8 -0
  355. package/dist/session/playwright-post-wire.js +148 -0
  356. package/dist/session/policy-buffer.d.ts +21 -0
  357. package/dist/session/policy-buffer.js +47 -0
  358. package/dist/session/profile-snapshot.d.ts +11 -0
  359. package/dist/session/profile-snapshot.js +53 -0
  360. package/dist/session/registry.d.ts +365 -0
  361. package/dist/session/registry.js +98 -0
  362. package/dist/session/safari-post-wire.d.ts +8 -0
  363. package/dist/session/safari-post-wire.js +28 -0
  364. package/dist/session/safari-session.d.ts +10 -0
  365. package/dist/session/safari-session.js +39 -0
  366. package/dist/session/storage.d.ts +148 -0
  367. package/dist/session/storage.js +350 -0
  368. package/dist/session/types.d.ts +113 -0
  369. package/dist/session/types.js +5 -0
  370. package/dist/session/wedge.d.ts +15 -0
  371. package/dist/session/wedge.js +41 -0
  372. package/dist/tools/action-core-tools.d.ts +13 -0
  373. package/dist/tools/action-core-tools.js +156 -0
  374. package/dist/tools/action-form-tools.d.ts +12 -0
  375. package/dist/tools/action-form-tools.js +179 -0
  376. package/dist/tools/action-gesture-tools.d.ts +9 -0
  377. package/dist/tools/action-gesture-tools.js +115 -0
  378. package/dist/tools/action-history-tools.d.ts +8 -0
  379. package/dist/tools/action-history-tools.js +67 -0
  380. package/dist/tools/action-tool.d.ts +42 -0
  381. package/dist/tools/action-tool.js +58 -0
  382. package/dist/tools/action-tools.d.ts +20 -0
  383. package/dist/tools/action-tools.js +28 -0
  384. package/dist/tools/batch-act-tools.d.ts +10 -0
  385. package/dist/tools/batch-act-tools.js +276 -0
  386. package/dist/tools/batch-human-tools.d.ts +8 -0
  387. package/dist/tools/batch-human-tools.js +148 -0
  388. package/dist/tools/canvas-tools.d.ts +40 -0
  389. package/dist/tools/canvas-tools.js +368 -0
  390. package/dist/tools/capture-report-diagnostics-tools.d.ts +7 -0
  391. package/dist/tools/capture-report-diagnostics-tools.js +318 -0
  392. package/dist/tools/capture-report-element-export-tools.d.ts +8 -0
  393. package/dist/tools/capture-report-element-export-tools.js +197 -0
  394. package/dist/tools/capture-report-export-tools.d.ts +8 -0
  395. package/dist/tools/capture-report-export-tools.js +246 -0
  396. package/dist/tools/capture-report-marks-tools.d.ts +9 -0
  397. package/dist/tools/capture-report-marks-tools.js +221 -0
  398. package/dist/tools/capture-report-upload-tools.d.ts +8 -0
  399. package/dist/tools/capture-report-upload-tools.js +277 -0
  400. package/dist/tools/config-approval-tools.d.ts +8 -0
  401. package/dist/tools/config-approval-tools.js +166 -0
  402. package/dist/tools/deep-coverage-tools.d.ts +8 -0
  403. package/dist/tools/deep-coverage-tools.js +325 -0
  404. package/dist/tools/deep-determinism-tools.d.ts +8 -0
  405. package/dist/tools/deep-determinism-tools.js +276 -0
  406. package/dist/tools/deep-perf-tools.d.ts +19 -0
  407. package/dist/tools/deep-perf-tools.js +324 -0
  408. package/dist/tools/device-emulation-tools.d.ts +9 -0
  409. package/dist/tools/device-emulation-tools.js +137 -0
  410. package/dist/tools/extensions-batch-tools.d.ts +18 -0
  411. package/dist/tools/extensions-batch-tools.js +24 -0
  412. package/dist/tools/extensions-rebuild.d.ts +22 -0
  413. package/dist/tools/extensions-rebuild.js +208 -0
  414. package/dist/tools/extensions-tools.d.ts +2 -0
  415. package/dist/tools/extensions-tools.js +331 -0
  416. package/dist/tools/forms-fill-tools.d.ts +8 -0
  417. package/dist/tools/forms-fill-tools.js +109 -0
  418. package/dist/tools/forms-plan-tools.d.ts +7 -0
  419. package/dist/tools/forms-plan-tools.js +159 -0
  420. package/dist/tools/forms-recording-mode-tools.d.ts +8 -0
  421. package/dist/tools/forms-recording-mode-tools.js +71 -0
  422. package/dist/tools/forms-recording-tools.d.ts +14 -0
  423. package/dist/tools/forms-recording-tools.js +22 -0
  424. package/dist/tools/forms-refs-tools.d.ts +8 -0
  425. package/dist/tools/forms-refs-tools.js +90 -0
  426. package/dist/tools/gesture-coord-tools.d.ts +8 -0
  427. package/dist/tools/gesture-coord-tools.js +168 -0
  428. package/dist/tools/gesture-emulation-tools.d.ts +8 -0
  429. package/dist/tools/gesture-emulation-tools.js +135 -0
  430. package/dist/tools/gesture-network-tools.d.ts +17 -0
  431. package/dist/tools/gesture-network-tools.js +27 -0
  432. package/dist/tools/gesture-route-tools.d.ts +8 -0
  433. package/dist/tools/gesture-route-tools.js +142 -0
  434. package/dist/tools/gesture-websocket-tools.d.ts +8 -0
  435. package/dist/tools/gesture-websocket-tools.js +122 -0
  436. package/dist/tools/gesture-worker-tools.d.ts +9 -0
  437. package/dist/tools/gesture-worker-tools.js +200 -0
  438. package/dist/tools/host-build.d.ts +76 -0
  439. package/dist/tools/host-build.js +516 -0
  440. package/dist/tools/host.d.ts +287 -0
  441. package/dist/tools/host.js +1 -0
  442. package/dist/tools/input-tools.d.ts +10 -0
  443. package/dist/tools/input-tools.js +176 -0
  444. package/dist/tools/live-emulation-tools.d.ts +9 -0
  445. package/dist/tools/live-emulation-tools.js +353 -0
  446. package/dist/tools/plugin-runtime.d.ts +36 -0
  447. package/dist/tools/plugin-runtime.js +274 -0
  448. package/dist/tools/read-observe-buffer-tools.d.ts +9 -0
  449. package/dist/tools/read-observe-buffer-tools.js +385 -0
  450. package/dist/tools/read-observe-capture-tools.d.ts +12 -0
  451. package/dist/tools/read-observe-capture-tools.js +376 -0
  452. package/dist/tools/read-observe-dom-tools.d.ts +8 -0
  453. package/dist/tools/read-observe-dom-tools.js +308 -0
  454. package/dist/tools/read-observe-extract-tools.d.ts +8 -0
  455. package/dist/tools/read-observe-extract-tools.js +232 -0
  456. package/dist/tools/read-observe-verify-tools.d.ts +8 -0
  457. package/dist/tools/read-observe-verify-tools.js +316 -0
  458. package/dist/tools/schemas.d.ts +29 -0
  459. package/dist/tools/schemas.js +58 -0
  460. package/dist/tools/secrets-captcha-tools.d.ts +9 -0
  461. package/dist/tools/secrets-captcha-tools.js +231 -0
  462. package/dist/tools/session-dialog-permission-tools.d.ts +9 -0
  463. package/dist/tools/session-dialog-permission-tools.js +287 -0
  464. package/dist/tools/session-lifecycle-tools.d.ts +8 -0
  465. package/dist/tools/session-lifecycle-tools.js +314 -0
  466. package/dist/tools/session-notification-device-tools.d.ts +9 -0
  467. package/dist/tools/session-notification-device-tools.js +156 -0
  468. package/dist/tools/session-policy-tools.d.ts +16 -0
  469. package/dist/tools/session-policy-tools.js +22 -0
  470. package/dist/tools/session-registry.d.ts +28 -0
  471. package/dist/tools/session-registry.js +427 -0
  472. package/dist/tools/storage-artifact-har-video-tools.d.ts +8 -0
  473. package/dist/tools/storage-artifact-har-video-tools.js +311 -0
  474. package/dist/tools/storage-cache-idb-tools.d.ts +8 -0
  475. package/dist/tools/storage-cache-idb-tools.js +347 -0
  476. package/dist/tools/storage-state-cookies-tools.d.ts +8 -0
  477. package/dist/tools/storage-state-cookies-tools.js +223 -0
  478. package/dist/tools/storage-tools.d.ts +17 -0
  479. package/dist/tools/storage-tools.js +25 -0
  480. package/dist/tools/storage-web-auth-tools.d.ts +10 -0
  481. package/dist/tools/storage-web-auth-tools.js +230 -0
  482. package/dist/tools/tool-metadata.d.ts +8 -0
  483. package/dist/tools/tool-metadata.js +185 -0
  484. package/dist/util/batch.d.ts +83 -0
  485. package/dist/util/batch.js +191 -0
  486. package/dist/util/capabilities.d.ts +504 -0
  487. package/dist/util/capabilities.js +254 -0
  488. package/dist/util/config-store.d.ts +103 -0
  489. package/dist/util/config-store.js +206 -0
  490. package/dist/util/config.d.ts +11 -0
  491. package/dist/util/config.js +28 -0
  492. package/dist/util/credentials.d.ts +136 -0
  493. package/dist/util/credentials.js +622 -0
  494. package/dist/util/deadline.d.ts +22 -0
  495. package/dist/util/deadline.js +62 -0
  496. package/dist/util/diagnostics.d.ts +161 -0
  497. package/dist/util/diagnostics.js +579 -0
  498. package/dist/util/egress-sanitiser.d.ts +29 -0
  499. package/dist/util/egress-sanitiser.js +52 -0
  500. package/dist/util/failure.d.ts +8 -0
  501. package/dist/util/failure.js +50 -0
  502. package/dist/util/flake-check.d.ts +109 -0
  503. package/dist/util/flake-check.js +342 -0
  504. package/dist/util/invariant.d.ts +25 -0
  505. package/dist/util/invariant.js +66 -0
  506. package/dist/util/logging.d.ts +6 -0
  507. package/dist/util/logging.js +12 -0
  508. package/dist/util/predicates.d.ts +62 -0
  509. package/dist/util/predicates.js +340 -0
  510. package/dist/util/secrets.d.ts +104 -0
  511. package/dist/util/secrets.js +219 -0
  512. package/dist/util/tokens.d.ts +6 -0
  513. package/dist/util/tokens.js +24 -0
  514. package/dist/util/url-sanitizer.d.ts +19 -0
  515. package/dist/util/url-sanitizer.js +70 -0
  516. package/dist/util/version.d.ts +2 -0
  517. package/dist/util/version.js +21 -0
  518. package/dist/util/workspace.d.ts +7 -0
  519. package/dist/util/workspace.js +22 -0
  520. package/package.json +120 -0
@@ -0,0 +1,470 @@
1
+ // find(query) — natural-language element description → ranked candidate locators
2
+ // with structured evidence. First-consumer : selectorHint follows a
3
+ // fixed preference order with a stability flag; bbox is the visible-rect.
4
+ import { walk } from "./a11y.js";
5
+ import { composeSnapshotForFrame } from "./compose.js";
6
+ import { visibleRect, locatorBoundingBox } from "./bbox.js";
7
+ import { findByRef } from "./snapshot.js";
8
+ const INTERACTIVE_ROLES = new Set([
9
+ "button",
10
+ "link",
11
+ "textbox",
12
+ "searchbox",
13
+ "combobox",
14
+ "checkbox",
15
+ "radio",
16
+ "switch",
17
+ "slider",
18
+ "spinbutton",
19
+ "menuitem",
20
+ "menuitemcheckbox",
21
+ "menuitemradio",
22
+ "option",
23
+ "tab",
24
+ "treeitem",
25
+ ]);
26
+ /**
27
+ * Per-call cap for the auto-waiting Playwright probes (`boundingBox`,
28
+ * `isEnabled`) used in the candidate-evaluation loop. find() is a probe
29
+ * tool, not an action — a probe must fail fast when its hint doesn't match
30
+ * a live element. The default `actionTimeout` (30 s) is appropriate for
31
+ * acting on a known element; without a cap here, find() against N candidates
32
+ * whose hints don't resolve to a Playwright locator would burn N × 30 s of
33
+ * wall-clock waiting for nothing. 500 ms comfortably covers a real
34
+ * boundingBox resolution on a matched element (typically 1–50 ms) while
35
+ * keeping the per-candidate worst case bounded.
36
+ */
37
+ const PROBE_TIMEOUT_MS = 500;
38
+ // Non-interactive structural / layout / landmark wrappers. These *enclose* the
39
+ // thing an agent wants to act on; they are never themselves the click target.
40
+ // When a query is phrased loosely (a product alias rather than the test-attr
41
+ // tokens) one of these can outscore the actual control it contains, so we
42
+ // demote them below an actionable interactive match. Deliberately
43
+ // conservative — list/listitem/article/section are omitted because they can
44
+ // legitimately be the intended target in some UIs.
45
+ const CONTAINER_ROLES = new Set([
46
+ "generic",
47
+ "group",
48
+ "region",
49
+ "toolbar",
50
+ "none",
51
+ "presentation",
52
+ "navigation",
53
+ "complementary",
54
+ "banner",
55
+ "contentinfo",
56
+ "main",
57
+ "application",
58
+ "document",
59
+ "form",
60
+ "search",
61
+ ]);
62
+ /**
63
+ * Rank candidates against a natural-language query. The query is tokenised on
64
+ * whitespace; each token is matched (case-insensitively, as substring) against
65
+ * a haystack of role + name + testId. Scoring:
66
+ *
67
+ * - exact-name match: +10
68
+ * - name contains query: +5
69
+ * - testId contains query: +5
70
+ * - role contains query: +2
71
+ * - per-token hit anywhere: +1 each
72
+ * - interactive-role bonus: +2 (the agent's usually after a clickable thing)
73
+ *
74
+ * Candidates with score 0 are dropped. Top `maxCandidates` (default 5) returned.
75
+ */
76
+ /** The compose layer's shadow-DOM warnings, surfaced only when `pierce` was
77
+ * explicitly opted into (so a pierce-less caller's find() envelope stays
78
+ * byte-identical to pre-v0.5.0). The `low-content` warning is always skipped —
79
+ * it pre-dates this path and was surfaced through snapshot only. */
80
+ function pierceWarnings(composedWarnings, pierce) {
81
+ if (pierce === undefined)
82
+ return [];
83
+ return composedWarnings.filter((w) => !w.startsWith("low-content"));
84
+ }
85
+ /** Walk the (scoped) tree, scoring each node and applying any feedback bonus;
86
+ * returns the score-descending candidate list. */
87
+ function scoreCandidates(walkRoot, q, qTokens, opts) {
88
+ const scored = [];
89
+ for (const { node } of walk(walkRoot)) {
90
+ let score = scoreNode(node, q, qTokens);
91
+ if (score > 0 && opts.feedback) {
92
+ score += opts.feedback.bonusFor(opts.query, {
93
+ testId: node.testId,
94
+ testIdAttr: node.testIdAttr,
95
+ role: node.role,
96
+ name: node.name,
97
+ });
98
+ }
99
+ if (score > 0)
100
+ scored.push({ node, score });
101
+ }
102
+ scored.sort((a, b) => b.score - a.score);
103
+ return scored;
104
+ }
105
+ /** Probe one candidate against the live page (hint disambiguation → bbox →
106
+ * actionability) into a `FindCandidate`. Each probe is independent so the pool
107
+ * runs in parallel; the steps within stay ordered (actionable needs bbox). */
108
+ async function probeCandidate(node, score, ctx) {
109
+ const { locatorRoot, cdp, frame } = ctx;
110
+ const { hint: bareHint, tier, stability } = buildSelectorHint(node);
111
+ // disambiguate when the bare hint matches multiple DOM nodes (needs a locator
112
+ // root; on safari there is none, so use the bare hint as-is).
113
+ const hint = locatorRoot ? await disambiguateHint(locatorRoot, bareHint) : bareHint;
114
+ // Frame-scoped finds skip the CDP visible-rect path (its backendDOMNodeIds are
115
+ // rooted at the top target and don't resolve into OOPIFs); the portable
116
+ // locator-bounding-box path is identical-behaviour.
117
+ let bbox = frame === undefined && cdp !== undefined && node.backendDOMNodeId !== undefined
118
+ ? await visibleRect(cdp, node.backendDOMNodeId)
119
+ : null;
120
+ // attached/BYOB: the CDP rect path can spuriously null out a rendered DOM-walk
121
+ // node → fall back to Playwright's locator box before a bad signal classifies a
122
+ // visible element off-screen (which `visibleOnly` would then drop entirely).
123
+ if (bbox === null && locatorRoot)
124
+ bbox = await locatorBoundingBox(locatorRoot, hint, { timeoutMs: PROBE_TIMEOUT_MS });
125
+ // No locator root (safari) → actionability can't be locator-probed, but the
126
+ // DOM-walk PAGE_SCRIPT already filtered to VISIBLE interactive elements, so the
127
+ // node is known-visible. Report `true` rather than fabricate a signal we can't
128
+ // measure. bbox stays null (no protocol rect on safari).
129
+ const actionable = locatorRoot ? await probeActionable(locatorRoot, hint, bbox) : true;
130
+ return {
131
+ ref: node.ref,
132
+ role: node.role,
133
+ name: node.name,
134
+ testId: node.testId,
135
+ stability,
136
+ selectorHint: hint,
137
+ selectorTier: tier,
138
+ bbox,
139
+ clipped: bbox === null,
140
+ actionable,
141
+ score,
142
+ ...(node.context ? { context: node.context } : {}),
143
+ };
144
+ }
145
+ export async function find(
146
+ // `null` on the safari engine — it has no Playwright Page, so the locator-based
147
+ // enrichment (disambiguation / bbox / actionability) is skipped and candidates
148
+ // are ranked from the substrate tree alone. Every other engine
149
+ // passes a real Page.
150
+ page, substrate, refs, opts,
151
+ /** Raw CDP handle for the visible-rect bbox fast path — present only on
152
+ * chromium (where a11y nodes carry `backendDOMNodeId`). Off Chromium the
153
+ * walker mints no `backendDOMNodeId`, so this is unused and the portable
154
+ * `locatorBoundingBox` fallback computes the box. Optional so the engine
155
+ * type never enters the find tool path. */
156
+ cdp) {
157
+ // Use the composed tree (a11y + DOM-walk fallback) so we can find candidates that
158
+ // only exist on the DOM-walk side — the #7 win on heavy-SPA targets.
159
+ // when `frame` is set, scope to that frame's DOM-walk-only compose
160
+ // path and bind refs to the frame on the registry so subsequent actions land
161
+ // inside the iframe.
162
+ // `pierce` propagates through to the dom-walk + (when "closed",
163
+ // main-frame only) the CDP pierce path. Omitting `pierce` preserves
164
+ // byte-identical pre-v0.5.0 output.
165
+ const composed = opts.frame && opts.frameId
166
+ ? await composeSnapshotForFrame(opts.frame, refs, opts.testAttributes, opts.frameId, {
167
+ pierce: opts.pierce,
168
+ })
169
+ : await substrate.compose(refs, opts.testAttributes, { pierce: opts.pierce });
170
+ const { tree } = composed;
171
+ if (!tree) {
172
+ return { candidates: [], warnings: pierceWarnings(composed.warnings, opts.pierce) };
173
+ }
174
+ // The locator-resolution root: page for main-frame finds, frame for
175
+ // frame-scoped finds. Probes use this root so they exercise the correct DOM tree.
176
+ const locatorRoot = opts.frame ?? page;
177
+ const q = opts.query.toLowerCase();
178
+ const qTokens = q.split(/\s+/).filter(Boolean);
179
+ const max = opts.maxCandidates ?? 5;
180
+ const warnings = [...pierceWarnings(composed.warnings, opts.pierce)];
181
+ // limit walk to subtree rooted at contextRef.
182
+ let walkRoot = tree;
183
+ if (opts.contextRef) {
184
+ const sub = findByRef(tree, opts.contextRef);
185
+ if (sub)
186
+ walkRoot = sub;
187
+ else
188
+ warnings.push(`contextRef=${opts.contextRef} not found; ranking over the full tree instead.`);
189
+ }
190
+ const scored = scoreCandidates(walkRoot, q, qTokens, opts);
191
+ const top = scored.slice(0, max);
192
+ // Per-candidate probing is independent (each candidate's hint, bbox,
193
+ // and actionability are computed against the live page in isolation), so
194
+ // run the top-N pool in parallel. Sequential probing was the dominant
195
+ // find() cost: on a DOM-walk-sourced candidate whose role-locator doesn't
196
+ // resolve to a real Playwright role, every probe call would auto-wait the
197
+ // full `actionTimeout` window before returning. In default operation
198
+ // find() was already capped by the outer 5 s `actionTimeoutMs` anti-wedge
199
+ // but consumed it in full on pages with fall-through-role candidates;
200
+ // without the cap, the 60 s anti-wedge deadline would clip in pathological
201
+ // cases. The probe steps inside each task remain ordered (hint → bbox →
202
+ // actionable depends on bbox), and `PROBE_TIMEOUT_MS` caps any single
203
+ // probe call so a no-match hint fails fast instead of waiting on auto-wait.
204
+ const candidates = await Promise.all(top.map(({ node, score }) => probeCandidate(node, score, { locatorRoot, cdp, frame: opts.frame })));
205
+ // visibility-aware ranking. Stable-partition actionable candidates ahead of
206
+ // non-actionable ones, preserving score order within each tier.
207
+ const { ranked, visibleCount } = rankByVisibility(candidates, opts.visibleOnly === true);
208
+ appendRankingWarnings(warnings, ranked, candidates, visibleCount, opts);
209
+ return { candidates: ranked, warnings };
210
+ }
211
+ /** Append the confidence-floor + no-visible-candidate diagnostic warnings. */
212
+ function appendRankingWarnings(warnings, ranked, candidates, visibleCount, opts) {
213
+ const floor = opts.confidenceFloor ?? 0;
214
+ if (floor > 0 && (ranked.length === 0 || ranked[0].score < floor)) {
215
+ warnings.push(`no candidate scored confidently above ${floor} (top score: ${ranked[0]?.score ?? 0}). ` +
216
+ `Consider falling through to a snapshot scan + raw selector, or rephrasing the query against the element's accessible name / test-attribute value.`);
217
+ }
218
+ // When there are candidates but none visible, that's a strong "the match is
219
+ // wrong" signal — base it on the pre-filter match + visible count so it still
220
+ // fires under `visibleOnly` (where `ranked` is empty when nothing's visible).
221
+ if (visibleCount === 0 && candidates.length > 0) {
222
+ warnings.push(noVisibleCandidateWarning(candidates.length, opts.fallbackHints));
223
+ }
224
+ }
225
+ /**
226
+ * Stable-partition candidates: actionable ones first (preserving score order),
227
+ * non-actionable (off-screen / clipped / covered / disabled) last — so a
228
+ * slightly-lower-scored *visible* match outranks a high-scored hidden modal.
229
+ * `visibleOnly` drops the hidden tier entirely: an empty result + the
230
+ * "no visible candidate" warning is safer than a confident hidden hit the
231
+ * agent will chase into a coordinate fallback.
232
+ *
233
+ * Within the actionable tier, a second stable partition demotes
234
+ * non-interactive structural/layout containers below interactive controls,
235
+ * but *only* when at least one actionable interactive candidate exists — an
236
+ * aliased query ("the X panel in the right rail") otherwise lets the
237
+ * enclosing wrapper outrank the button/tab the agent actually wants. If no
238
+ * actionable interactive candidate matched, containers are left in place
239
+ * (they may be the best available target). Pure; exported for tests.
240
+ */
241
+ export function rankByVisibility(candidates, visibleOnly) {
242
+ let visible = candidates.filter((c) => c.actionable === true);
243
+ const hidden = candidates.filter((c) => c.actionable !== true);
244
+ const isContainer = (c) => CONTAINER_ROLES.has(c.role) && !INTERACTIVE_ROLES.has(c.role);
245
+ if (visible.some((c) => INTERACTIVE_ROLES.has(c.role))) {
246
+ const leaves = visible.filter((c) => !isContainer(c));
247
+ const containers = visible.filter(isContainer);
248
+ visible = [...leaves, ...containers];
249
+ }
250
+ return {
251
+ ranked: visibleOnly ? visible : [...visible, ...hidden],
252
+ visibleCount: visible.length,
253
+ };
254
+ }
255
+ /**
256
+ * the "all candidates off-screen → probably the wrong match" warning.
257
+ * Capability-aware — only names a fallback tool the caller actually has
258
+ * enabled (`coords` ⇐ `action`, `eval_js` ⇐ `eval`). Pure; exported for tests.
259
+ */
260
+ export function noVisibleCandidateWarning(count, fallbackHints) {
261
+ const suggestions = [];
262
+ if (fallbackHints?.coords)
263
+ suggestions.push("compute the element rect and use `coords` on click/hover");
264
+ if (fallbackHints?.evalJs)
265
+ suggestions.push("read state directly via `eval_js`");
266
+ const tail = suggestions.length ? ` You may want to: ${suggestions.join("; or ")}.` : "";
267
+ return (`no visible candidate — all ${count} match(es) are off-screen / clipped / covered ` +
268
+ `(actionable ≠ true). This usually means the query matched the wrong element ` +
269
+ `(e.g. a hidden modal).${tail}`);
270
+ }
271
+ /**
272
+ * . After find() produces a `selectorHint` for the visible candidate,
273
+ * check whether that bare hint matches multiple DOM nodes; if it does, append a
274
+ * disambiguator (`:visible` first, `:nth-match(..., 1)` last resort) so that a
275
+ * caller who transcribes the hint into a flow-file doesn't re-introduce the
276
+ * hidden-duplicate `boundingBox` hang. Best-effort: any error returns the bare hint.
277
+ */
278
+ async function disambiguateHint(root, hint) {
279
+ try {
280
+ const count = await root.locator(hint).count();
281
+ if (count <= 1)
282
+ return hint;
283
+ const visibleHint = `${hint}:visible`;
284
+ const visibleCount = await root.locator(visibleHint).count();
285
+ if (visibleCount === 1)
286
+ return visibleHint;
287
+ if (visibleCount > 1)
288
+ return `:nth-match(${visibleHint}, 1)`;
289
+ return `:nth-match(${hint}, 1)`;
290
+ }
291
+ catch {
292
+ return hint;
293
+ }
294
+ }
295
+ /**
296
+ * . Returns `true` iff the element is visible + enabled + on-screen.
297
+ * Else returns a single-word reason. Best-effort; on any error returns `true`
298
+ * (don't manufacture false-negatives).
299
+ */
300
+ async function probeActionable(root, hint, bbox) {
301
+ if (bbox === null)
302
+ return "off-screen";
303
+ try {
304
+ const loc = root.locator(hint).first();
305
+ // isEnabled auto-waits to the action-timeout default (30 s) when the
306
+ // locator doesn't resolve; cap it. isVisible is documented as
307
+ // non-waiting (the option is deprecated/ignored) so it costs ~0.
308
+ const [isEnabled, isVisible] = await Promise.all([
309
+ loc.isEnabled({ timeout: PROBE_TIMEOUT_MS }).catch(() => true),
310
+ loc.isVisible().catch(() => true),
311
+ ]);
312
+ if (!isEnabled)
313
+ return "disabled";
314
+ if (!isVisible)
315
+ return "off-screen";
316
+ // "covered" — requires `elementFromPoint` at the bbox center and an
317
+ // identity check. Skipped for now (~+10 LOC + a CDP call; not load-bearing
318
+ // for the headline cases). Leave the union member in place so callers
319
+ // handle it; the value is just never produced yet.
320
+ return true;
321
+ }
322
+ catch {
323
+ return true;
324
+ }
325
+ }
326
+ /** Score a node's match against a tokenised query — also weights testId / testIdAttr
327
+ * hits high so a query like "feature-area language" lands on `data-testid="feature-panel-language-input"`
328
+ * even when the role tree doesn't surface a wrapper. */
329
+ const INPUT_LIKE_ROLES = new Set(["input", "textbox", "searchbox", "combobox", "spinbutton"]);
330
+ /** Direct name / testId / role match scoring (exact + substring). testId hits
331
+ * weigh heavier — `<input>`-shaped roles typically have an empty accessible
332
+ * name, so the testId is the load-bearing signal. */
333
+ function scoreDirect(nameLower, testIdLower, roleLower, q) {
334
+ let s = 0;
335
+ if (nameLower === q)
336
+ s += 10;
337
+ if (nameLower.includes(q))
338
+ s += 5;
339
+ if (testIdLower === q)
340
+ s += 15;
341
+ if (testIdLower.includes(q))
342
+ s += 10;
343
+ if (roleLower.includes(q))
344
+ s += 2;
345
+ return s;
346
+ }
347
+ /** Per-query-token substring scoring on name + testId. testId tokens are
348
+ * amplified for icon-only controls (no accessible name) where the testId is the
349
+ * only signal. */
350
+ function scoreTokens(nameLower, testIdLower, qTokens, isIconOnly) {
351
+ let s = 0;
352
+ for (const t of qTokens) {
353
+ if (t.length < 2)
354
+ continue;
355
+ if (nameLower.includes(t))
356
+ s += 1;
357
+ if (testIdLower.includes(t))
358
+ s += isIconOnly ? 3 : 2;
359
+ }
360
+ return s;
361
+ }
362
+ /** Input-shaped boost: +3 once when the node is input-like AND any testId token
363
+ * matched (the round-3 case). */
364
+ function scoreInputTestIdBoost(node, testIdLower, qTokens) {
365
+ if (!testIdLower || !INPUT_LIKE_ROLES.has(node.role))
366
+ return 0;
367
+ return qTokens.some((t) => t.length >= 2 && testIdLower.includes(t)) ? 3 : 0;
368
+ }
369
+ /** Trimmed text-content scoring (title tooltip / sr-only label / glyph-adjacent
370
+ * text) — often the only human-readable hint on an icon-only control. */
371
+ function scoreText(textLower, q, qTokens, isIconOnly) {
372
+ if (!textLower)
373
+ return 0;
374
+ let s = 0;
375
+ if (textLower === q)
376
+ s += 6;
377
+ else if (textLower.includes(q))
378
+ s += 3;
379
+ for (const t of qTokens) {
380
+ if (t.length < 2)
381
+ continue;
382
+ if (textLower.includes(t))
383
+ s += isIconOnly ? 2 : 1;
384
+ }
385
+ return s;
386
+ }
387
+ export function scoreNode(node, q, qTokens) {
388
+ const nameLower = (node.name ?? "").toLowerCase();
389
+ const testIdLower = (node.testId ?? "").toLowerCase();
390
+ const isIconOnly = !nameLower && !!testIdLower;
391
+ let s = scoreDirect(nameLower, testIdLower, node.role.toLowerCase(), q);
392
+ s += scoreTokens(nameLower, testIdLower, qTokens, isIconOnly);
393
+ if (s > 0 && INTERACTIVE_ROLES.has(node.role))
394
+ s += 2;
395
+ s += scoreInputTestIdBoost(node, testIdLower, qTokens);
396
+ s += scoreText((node.text ?? "").toLowerCase(), q, qTokens, isIconOnly);
397
+ // Active / selected state bonuses an existing match (the live feature area the
398
+ // agent means) — disambiguates the active side-panel tab from inert siblings.
399
+ const isActive = node.selected === true || node.pressed === true || node.checked === true;
400
+ if (s > 0 && isActive)
401
+ s += 3;
402
+ return s;
403
+ }
404
+ /**
405
+ * The five-tier preference order from :
406
+ * 1. `[<test-attr>="…"]` → stability "high" (any configured test-attribute)
407
+ * 2. role + accessible name → stability "medium"
408
+ * 3. stable text on stable role → covered by tier 2 (the DOM-walk's nameFor()
409
+ * computes name from aria-label / labelledby /
410
+ * textContent in that order, so a `<button>Submit</button>`
411
+ * already gets `role=button[name="Submit"]` via tier 2)
412
+ * 4. structural (#id, semantic) → stability "low" (id present + id-shaped stable)
413
+ * 5. positional (last resort) → stability "low"
414
+ *
415
+ * update: tier 4 now fires when the node has an HTML `id` attribute that
416
+ * looks stable (not a numeric/UUID content-keyed id). The id-stability heuristic:
417
+ * reject pure-numeric (`123`), short numeric+letter combos that look generated
418
+ * (e.g. `mui-1234`), or strings matching common content-keyed shapes. Anything
419
+ * with two or more `-`/`_`-separated word segments is treated as stable.
420
+ */
421
+ export function buildSelectorHint(node) {
422
+ if (node.testId) {
423
+ const attr = node.testIdAttr ?? "data-testid";
424
+ return { hint: `[${attr}=${JSON.stringify(node.testId)}]`, tier: 1, stability: "high" };
425
+ }
426
+ if (node.name) {
427
+ return {
428
+ hint: `role=${node.role}[name=${JSON.stringify(node.name)}]`,
429
+ tier: 2,
430
+ stability: "medium",
431
+ };
432
+ }
433
+ if (node.id && isLikelyStableId(node.id)) {
434
+ return { hint: `#${cssEscape(node.id)}`, tier: 4, stability: "low" };
435
+ }
436
+ // Tier 5 fallback — role only. The agent should treat "low" as "ask a human
437
+ // or refuse to transcribe."
438
+ return { hint: `role=${node.role}`, tier: 5, stability: "low" };
439
+ }
440
+ /** Heuristic: is this HTML `id` value likely to survive across page reloads?
441
+ * Rejects content-keyed shapes (pure-numeric, MUI-generated `mui-N`, UUID-shaped).
442
+ * Accepts ids with two or more word segments separated by `-`/`_`/`:`. */
443
+ export function isLikelyStableId(id) {
444
+ // Pure numeric → content-keyed.
445
+ if (/^\d+$/.test(id))
446
+ return false;
447
+ // MUI / Radix / framework-generated short tags.
448
+ if (/^(mui|radix|headlessui|reach|react-aria)[-_]?[a-z0-9]+$/i.test(id))
449
+ return false;
450
+ // UUID-shaped.
451
+ if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id))
452
+ return false;
453
+ // 8+ hex chars only → likely a hash / content-keyed.
454
+ if (/^[0-9a-f]{8,}$/i.test(id) && id.length <= 32)
455
+ return false;
456
+ // Multi-segment (kebab/snake/colon-separated, ≥2 segments, each with letters) → stable.
457
+ const segments = id.split(/[-_:]/).filter((s) => s.length > 0);
458
+ if (segments.length >= 2 && segments.every((s) => /[a-z]/i.test(s)))
459
+ return true;
460
+ // Single-segment, ≥3 chars, has letters → probably stable.
461
+ if (id.length >= 3 && /[a-z]/i.test(id) && !/^\d/.test(id))
462
+ return true;
463
+ return false;
464
+ }
465
+ /** Minimal CSS escape for the id-selector value — covers the common cases
466
+ * (escapes leading digit, special chars). Doesn't aim to be a full CSS.escape() shim. */
467
+ function cssEscape(s) {
468
+ // Escape any character that isn't [A-Za-z0-9_-].
469
+ return s.replace(/([^a-zA-Z0-9_-])/g, "\\$1").replace(/^(\d)/, "\\3$1 ");
470
+ }
@@ -0,0 +1,45 @@
1
+ import type { Frame, Page } from "playwright-core";
2
+ /** Stable sentinel for the page's top-level frame. */
3
+ export declare const MAIN_FRAME_ID = "f0";
4
+ export interface FrameInfo {
5
+ /** Stable per-session ID — pass back to snapshot/find/action via `frame`. */
6
+ frameId: string;
7
+ /** Parent frame's ID. Absent for the main frame. */
8
+ parentFrameId?: string;
9
+ url: string;
10
+ /** `<iframe name="…">` or empty when not set. */
11
+ name: string;
12
+ isMainFrame: boolean;
13
+ /** Origin parsed from `url` (`http://example.com`); empty for non-URL
14
+ * frames (`about:blank`, `data:` URLs). */
15
+ origin: string;
16
+ }
17
+ /** Per-session cache: structural fingerprint → stable frameId. */
18
+ export declare class FrameRegistry {
19
+ private idByFingerprint;
20
+ private frameByFingerprint;
21
+ private counter;
22
+ /** Assign (or look up) a stable ID for `frame`. The main frame always
23
+ * gets `MAIN_FRAME_ID`. Child frames get `f1`, `f2`, … by first-seen
24
+ * order; identical-fingerprint frames across calls keep their ID. */
25
+ idFor(frame: Frame, fingerprint: string): string;
26
+ /** Test/introspection only. */
27
+ size(): number;
28
+ }
29
+ /** Walk the page's frame tree and emit `FrameInfo[]`, depth-first. The
30
+ * main frame is always first. */
31
+ export declare function listFrames(page: Page, registry: FrameRegistry): FrameInfo[];
32
+ /** Structural fingerprint — short hex hash of the inputs that should keep
33
+ * a child frame's identity stable across calls within a session. Includes
34
+ * parent ID + sibling index + name + url origin. Not URL-path-sensitive so
35
+ * intra-iframe navigation doesn't reset the ID; not name-only so two
36
+ * identically-named iframes in the same parent still get distinct IDs via
37
+ * their sibling index. Exported for unit tests. */
38
+ export declare function fingerprintOf(frame: Frame, parentFrameId: string | undefined, siblingIndex: number): string;
39
+ /** Origin of a frame URL — `http://host` or empty for opaque schemes. */
40
+ export declare function originOf(url: string): string;
41
+ /** Resolve a `frameId` back to a Playwright `Frame` handle. Returns the
42
+ * main frame for `MAIN_FRAME_ID`; null for an unknown ID. The walk is
43
+ * cheap (frame trees are small) and avoids needing a reverse Map that
44
+ * could go stale when a frame is detached. */
45
+ export declare function resolveFrameById(page: Page, registry: FrameRegistry, frameId: string): Frame | null;
@@ -0,0 +1,133 @@
1
+ // Frame-scoped observation.
2
+ //
3
+ // Iframes are everywhere on real pages; today's CDP-rooted snapshot/find
4
+ // observe only the top frame. This module exposes the page's frame tree to
5
+ // agents and, for the consumers in this directory (snapshot/find/action),
6
+ // provides stable frame IDs that round-trip back into a Playwright `Frame`
7
+ // for scoped reads and ref-resolution.
8
+ //
9
+ // Frame ID scheme:
10
+ // - The main frame's ID is always `f0` (well-known sentinel — agents
11
+ // can address it explicitly when they want to be unambiguous about
12
+ // "the main frame", though omitting `frame` from snapshot/find keeps
13
+ // the existing main-frame-only behaviour byte-identical for back-compat).
14
+ // - Child frames mint a stable `fN` (N=1..) using a session-local
15
+ // monotonic counter keyed by a structural fingerprint
16
+ // (parent-id + index among siblings + name + url-origin). Same iframe
17
+ // across two `frames_list` calls keeps the same ID.
18
+ //
19
+ // Cross-origin caveat: Playwright's `Frame` handle works for both
20
+ // same-origin and cross-origin iframes — `frame.locator(...)`,
21
+ // `frame.evaluate(...)`, and the action surface all transparently cross
22
+ // the OOPIF boundary. The one observable gap is the CDP
23
+ // `Accessibility.getFullAXTree` path used by main-frame snapshots: per
24
+ // frame, the CDP session is rooted at the top target, so child frames
25
+ // fall back to the DOM-walk pass only (no a11y nodes from CDP). This is
26
+ // surfaced as a warning on frame-scoped snapshots.
27
+ import { createHash } from "node:crypto";
28
+ /** Stable sentinel for the page's top-level frame. */
29
+ export const MAIN_FRAME_ID = "f0";
30
+ /** Per-session cache: structural fingerprint → stable frameId. */
31
+ export class FrameRegistry {
32
+ idByFingerprint = new Map();
33
+ frameByFingerprint = new WeakMap();
34
+ counter = 0;
35
+ /** Assign (or look up) a stable ID for `frame`. The main frame always
36
+ * gets `MAIN_FRAME_ID`. Child frames get `f1`, `f2`, … by first-seen
37
+ * order; identical-fingerprint frames across calls keep their ID. */
38
+ idFor(frame, fingerprint) {
39
+ // Per-instance shortcut: a Playwright Frame handle that we've seen this
40
+ // session keeps the same ID — even if its URL changes mid-navigation.
41
+ const cached = this.frameByFingerprint.get(frame);
42
+ if (cached)
43
+ return cached;
44
+ let id = this.idByFingerprint.get(fingerprint);
45
+ if (!id) {
46
+ id = fingerprint === MAIN_FRAME_FINGERPRINT ? MAIN_FRAME_ID : `f${++this.counter}`;
47
+ this.idByFingerprint.set(fingerprint, id);
48
+ }
49
+ this.frameByFingerprint.set(frame, id);
50
+ return id;
51
+ }
52
+ /** Test/introspection only. */
53
+ size() {
54
+ return this.idByFingerprint.size;
55
+ }
56
+ }
57
+ /** Reserved fingerprint for the main frame. */
58
+ const MAIN_FRAME_FINGERPRINT = "__main__";
59
+ /** Walk the page's frame tree and emit `FrameInfo[]`, depth-first. The
60
+ * main frame is always first. */
61
+ export function listFrames(page, registry) {
62
+ const out = [];
63
+ const main = page.mainFrame();
64
+ visitFrame(main, undefined, undefined, registry, out);
65
+ return out;
66
+ }
67
+ function visitFrame(frame, parentFrameId, siblingIndex, registry, out) {
68
+ const isMain = frame.parentFrame() === null;
69
+ const fingerprint = isMain
70
+ ? MAIN_FRAME_FINGERPRINT
71
+ : fingerprintOf(frame, parentFrameId, siblingIndex ?? 0);
72
+ const frameId = registry.idFor(frame, fingerprint);
73
+ out.push({
74
+ frameId,
75
+ ...(parentFrameId ? { parentFrameId } : {}),
76
+ url: frame.url(),
77
+ name: frame.name(),
78
+ isMainFrame: isMain,
79
+ origin: originOf(frame.url()),
80
+ });
81
+ const children = frame.childFrames();
82
+ for (let i = 0; i < children.length; i++) {
83
+ visitFrame(children[i], frameId, i, registry, out);
84
+ }
85
+ }
86
+ /** Structural fingerprint — short hex hash of the inputs that should keep
87
+ * a child frame's identity stable across calls within a session. Includes
88
+ * parent ID + sibling index + name + url origin. Not URL-path-sensitive so
89
+ * intra-iframe navigation doesn't reset the ID; not name-only so two
90
+ * identically-named iframes in the same parent still get distinct IDs via
91
+ * their sibling index. Exported for unit tests. */
92
+ export function fingerprintOf(frame, parentFrameId, siblingIndex) {
93
+ const raw = [parentFrameId ?? "", String(siblingIndex), frame.name(), originOf(frame.url())].join("|");
94
+ return createHash("sha256").update(raw).digest("hex").slice(0, 12);
95
+ }
96
+ /** Origin of a frame URL — `http://host` or empty for opaque schemes. */
97
+ export function originOf(url) {
98
+ try {
99
+ const u = new URL(url);
100
+ if (u.protocol === "about:" || u.protocol === "data:" || u.protocol === "blob:") {
101
+ return "";
102
+ }
103
+ return u.origin;
104
+ }
105
+ catch {
106
+ return "";
107
+ }
108
+ }
109
+ /** Resolve a `frameId` back to a Playwright `Frame` handle. Returns the
110
+ * main frame for `MAIN_FRAME_ID`; null for an unknown ID. The walk is
111
+ * cheap (frame trees are small) and avoids needing a reverse Map that
112
+ * could go stale when a frame is detached. */
113
+ export function resolveFrameById(page, registry, frameId) {
114
+ if (frameId === MAIN_FRAME_ID)
115
+ return page.mainFrame();
116
+ return findFrame(page.mainFrame(), undefined, undefined, registry, frameId);
117
+ }
118
+ function findFrame(frame, parentFrameId, siblingIndex, registry, target) {
119
+ const isMain = frame.parentFrame() === null;
120
+ const fingerprint = isMain
121
+ ? MAIN_FRAME_FINGERPRINT
122
+ : fingerprintOf(frame, parentFrameId, siblingIndex ?? 0);
123
+ const id = registry.idFor(frame, fingerprint);
124
+ if (id === target)
125
+ return frame;
126
+ const children = frame.childFrames();
127
+ for (let i = 0; i < children.length; i++) {
128
+ const hit = findFrame(children[i], id, i, registry, target);
129
+ if (hit)
130
+ return hit;
131
+ }
132
+ return null;
133
+ }