tabwright 1.0.0 → 1.0.1

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 (562) hide show
  1. package/dist/aria-snapshot.d.ts +0 -1
  2. package/dist/aria-snapshot.js +9 -1
  3. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts +0 -1
  4. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js +0 -1
  5. package/dist/bippy.js +1 -1
  6. package/dist/browser-config.d.ts +0 -1
  7. package/dist/browser-config.js +0 -1
  8. package/dist/browser-install.d.ts +0 -1
  9. package/dist/browser-install.js +0 -1
  10. package/dist/browser-launch.d.ts +0 -1
  11. package/dist/browser-launch.js +0 -1
  12. package/dist/builtin-capabilities.d.ts +0 -1
  13. package/dist/builtin-capabilities.js +0 -1
  14. package/dist/capability-agent-skill.d.ts +0 -1
  15. package/dist/capability-agent-skill.js +0 -1
  16. package/dist/capability-auth-state.d.ts +0 -1
  17. package/dist/capability-auth-state.js +0 -1
  18. package/dist/capability-auth.d.ts +0 -1
  19. package/dist/capability-auth.js +0 -1
  20. package/dist/capability-options.d.ts +0 -1
  21. package/dist/capability-options.js +0 -1
  22. package/dist/capability-package.d.ts +0 -1
  23. package/dist/capability-package.js +0 -1
  24. package/dist/capability-registry.d.ts +0 -1
  25. package/dist/capability-registry.js +0 -1
  26. package/dist/capability-runner.d.ts +0 -1
  27. package/dist/capability-runner.js +0 -1
  28. package/dist/capability-studio.d.ts +0 -1
  29. package/dist/capability-studio.js +0 -1
  30. package/dist/cdp-log.d.ts +0 -1
  31. package/dist/cdp-log.js +0 -1
  32. package/dist/cdp-relay.d.ts +0 -1
  33. package/dist/cdp-relay.js +0 -1
  34. package/dist/cdp-session.d.ts +0 -1
  35. package/dist/cdp-session.js +0 -1
  36. package/dist/cdp-types.d.ts +0 -1
  37. package/dist/cdp-types.js +0 -1
  38. package/dist/chrome-discovery.d.ts +0 -1
  39. package/dist/chrome-discovery.js +0 -1
  40. package/dist/clean-html.d.ts +0 -1
  41. package/dist/clean-html.js +0 -1
  42. package/dist/cli.d.ts +0 -1
  43. package/dist/cli.js +9 -2
  44. package/dist/cloud-client.d.ts +0 -1
  45. package/dist/cloud-client.js +0 -1
  46. package/dist/create-logger.d.ts +0 -1
  47. package/dist/create-logger.js +0 -1
  48. package/dist/debugger-examples-types.d.ts +0 -1
  49. package/dist/debugger-examples-types.js +0 -1
  50. package/dist/debugger-examples.d.ts +0 -1
  51. package/dist/debugger-examples.js +0 -1
  52. package/dist/debugger.d.ts +0 -1
  53. package/dist/debugger.js +0 -1
  54. package/dist/diff-utils.d.ts +0 -1
  55. package/dist/diff-utils.js +0 -1
  56. package/dist/doctor.d.ts +0 -1
  57. package/dist/doctor.js +5 -7
  58. package/dist/editor-examples.d.ts +0 -1
  59. package/dist/editor-examples.js +0 -1
  60. package/dist/editor.d.ts +0 -1
  61. package/dist/editor.js +0 -1
  62. package/dist/env-compat.d.ts +0 -1
  63. package/dist/env-compat.js +0 -1
  64. package/dist/executor.d.ts +0 -1
  65. package/dist/executor.js +1 -2
  66. package/dist/extension/background.js +7 -3
  67. package/dist/extension/manifest.json +1 -1
  68. package/dist/ghost-browser.d.ts +0 -1
  69. package/dist/ghost-browser.js +0 -1
  70. package/dist/ghost-cursor-controller.d.ts +0 -1
  71. package/dist/ghost-cursor-controller.js +0 -1
  72. package/dist/ghost-cursor.d.ts +0 -1
  73. package/dist/ghost-cursor.js +0 -1
  74. package/dist/htmlrewrite.d.ts +0 -1
  75. package/dist/htmlrewrite.js +0 -1
  76. package/dist/index.d.ts +0 -1
  77. package/dist/index.js +0 -1
  78. package/dist/kill-port.d.ts +0 -1
  79. package/dist/kill-port.js +0 -1
  80. package/dist/kitty-graphics.d.ts +0 -1
  81. package/dist/kitty-graphics.js +0 -1
  82. package/dist/mcp.d.ts +0 -1
  83. package/dist/mcp.js +0 -1
  84. package/dist/package-paths.d.ts +0 -1
  85. package/dist/package-paths.js +0 -1
  86. package/dist/page-markdown.d.ts +0 -1
  87. package/dist/page-markdown.js +0 -1
  88. package/dist/performance-examples.d.ts +0 -1
  89. package/dist/performance-examples.js +0 -1
  90. package/dist/playwright-import.d.ts +0 -1
  91. package/dist/playwright-import.js +0 -1
  92. package/dist/product-paths.d.ts +0 -1
  93. package/dist/product-paths.js +0 -1
  94. package/dist/protocol.d.ts +0 -1
  95. package/dist/protocol.js +0 -1
  96. package/dist/react-source.d.ts +0 -1
  97. package/dist/react-source.js +0 -1
  98. package/dist/readability.js +1 -1
  99. package/dist/relay-client.d.ts +0 -1
  100. package/dist/relay-client.js +0 -1
  101. package/dist/relay-state.d.ts +0 -1
  102. package/dist/relay-state.js +0 -1
  103. package/dist/replay-ai-index.d.ts +0 -1
  104. package/dist/replay-ai-index.js +0 -1
  105. package/dist/replay-eval.d.ts +0 -1
  106. package/dist/replay-eval.js +0 -1
  107. package/dist/replay-handoff.d.ts +0 -1
  108. package/dist/replay-handoff.js +0 -1
  109. package/dist/replay-workflow-compiler.d.ts +0 -1
  110. package/dist/replay-workflow-compiler.js +0 -1
  111. package/dist/rrweb-recording-relay.d.ts +0 -1
  112. package/dist/rrweb-recording-relay.js +0 -1
  113. package/dist/rrweb-recording.d.ts +0 -1
  114. package/dist/rrweb-recording.js +0 -1
  115. package/dist/scoped-fs.d.ts +0 -1
  116. package/dist/scoped-fs.js +0 -1
  117. package/dist/selector-generator.js +1 -1
  118. package/dist/start-relay-server.d.ts +0 -1
  119. package/dist/start-relay-server.js +0 -1
  120. package/dist/styles-examples.d.ts +0 -1
  121. package/dist/styles-examples.js +0 -1
  122. package/dist/styles.d.ts +0 -1
  123. package/dist/styles.js +0 -1
  124. package/dist/tabwright-agent-skill.d.ts +0 -1
  125. package/dist/tabwright-agent-skill.js +0 -1
  126. package/dist/test-declarations.d.ts +0 -1
  127. package/dist/test-declarations.js +0 -1
  128. package/dist/utils.d.ts +0 -1
  129. package/dist/utils.js +2 -2
  130. package/dist/wait-for-page-load.d.ts +0 -1
  131. package/dist/wait-for-page-load.js +0 -1
  132. package/dist/workflow-capability.d.ts +0 -1
  133. package/dist/workflow-capability.js +0 -1
  134. package/package.json +9 -4
  135. package/readme.md +35 -0
  136. package/dist/aria-snapshot.d.ts.map +0 -1
  137. package/dist/aria-snapshot.js.map +0 -1
  138. package/dist/aria-snapshot.test.d.ts +0 -2
  139. package/dist/aria-snapshot.test.d.ts.map +0 -1
  140. package/dist/aria-snapshot.test.js +0 -270
  141. package/dist/aria-snapshot.test.js.map +0 -1
  142. package/dist/aria-snapshot.unit.test.d.ts +0 -2
  143. package/dist/aria-snapshot.unit.test.d.ts.map +0 -1
  144. package/dist/aria-snapshot.unit.test.js +0 -542
  145. package/dist/aria-snapshot.unit.test.js.map +0 -1
  146. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts.map +0 -1
  147. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js.map +0 -1
  148. package/dist/browser-config.d.ts.map +0 -1
  149. package/dist/browser-config.js.map +0 -1
  150. package/dist/browser-install.d.ts.map +0 -1
  151. package/dist/browser-install.js.map +0 -1
  152. package/dist/browser-launch.d.ts.map +0 -1
  153. package/dist/browser-launch.js.map +0 -1
  154. package/dist/builtin-capabilities.d.ts.map +0 -1
  155. package/dist/builtin-capabilities.js.map +0 -1
  156. package/dist/capability-agent-skill.d.ts.map +0 -1
  157. package/dist/capability-agent-skill.js.map +0 -1
  158. package/dist/capability-auth-state.d.ts.map +0 -1
  159. package/dist/capability-auth-state.js.map +0 -1
  160. package/dist/capability-auth.d.ts.map +0 -1
  161. package/dist/capability-auth.js.map +0 -1
  162. package/dist/capability-cli-confirmation.test.d.ts +0 -2
  163. package/dist/capability-cli-confirmation.test.d.ts.map +0 -1
  164. package/dist/capability-cli-confirmation.test.js +0 -79
  165. package/dist/capability-cli-confirmation.test.js.map +0 -1
  166. package/dist/capability-options.d.ts.map +0 -1
  167. package/dist/capability-options.js.map +0 -1
  168. package/dist/capability-options.test.d.ts +0 -2
  169. package/dist/capability-options.test.d.ts.map +0 -1
  170. package/dist/capability-options.test.js +0 -81
  171. package/dist/capability-options.test.js.map +0 -1
  172. package/dist/capability-package.d.ts.map +0 -1
  173. package/dist/capability-package.js.map +0 -1
  174. package/dist/capability-package.test.d.ts +0 -2
  175. package/dist/capability-package.test.d.ts.map +0 -1
  176. package/dist/capability-package.test.js +0 -179
  177. package/dist/capability-package.test.js.map +0 -1
  178. package/dist/capability-registry.d.ts.map +0 -1
  179. package/dist/capability-registry.js.map +0 -1
  180. package/dist/capability-registry.test.d.ts +0 -2
  181. package/dist/capability-registry.test.d.ts.map +0 -1
  182. package/dist/capability-registry.test.js +0 -1683
  183. package/dist/capability-registry.test.js.map +0 -1
  184. package/dist/capability-runner.d.ts.map +0 -1
  185. package/dist/capability-runner.js.map +0 -1
  186. package/dist/capability-search-relevance.test.d.ts +0 -2
  187. package/dist/capability-search-relevance.test.d.ts.map +0 -1
  188. package/dist/capability-search-relevance.test.js +0 -67
  189. package/dist/capability-search-relevance.test.js.map +0 -1
  190. package/dist/capability-studio.d.ts.map +0 -1
  191. package/dist/capability-studio.js.map +0 -1
  192. package/dist/capability-studio.test.d.ts +0 -2
  193. package/dist/capability-studio.test.d.ts.map +0 -1
  194. package/dist/capability-studio.test.js +0 -41
  195. package/dist/capability-studio.test.js.map +0 -1
  196. package/dist/cdp-log.d.ts.map +0 -1
  197. package/dist/cdp-log.js.map +0 -1
  198. package/dist/cdp-log.test.d.ts +0 -2
  199. package/dist/cdp-log.test.d.ts.map +0 -1
  200. package/dist/cdp-log.test.js +0 -109
  201. package/dist/cdp-log.test.js.map +0 -1
  202. package/dist/cdp-relay.d.ts.map +0 -1
  203. package/dist/cdp-relay.js.map +0 -1
  204. package/dist/cdp-session.d.ts.map +0 -1
  205. package/dist/cdp-session.js.map +0 -1
  206. package/dist/cdp-types.d.ts.map +0 -1
  207. package/dist/cdp-types.js.map +0 -1
  208. package/dist/channel-owner-inspect.test.d.ts +0 -2
  209. package/dist/channel-owner-inspect.test.d.ts.map +0 -1
  210. package/dist/channel-owner-inspect.test.js +0 -75
  211. package/dist/channel-owner-inspect.test.js.map +0 -1
  212. package/dist/chrome-discovery.d.ts.map +0 -1
  213. package/dist/chrome-discovery.js.map +0 -1
  214. package/dist/chrome-discovery.test.d.ts +0 -2
  215. package/dist/chrome-discovery.test.d.ts.map +0 -1
  216. package/dist/chrome-discovery.test.js +0 -41
  217. package/dist/chrome-discovery.test.js.map +0 -1
  218. package/dist/clean-html.d.ts.map +0 -1
  219. package/dist/clean-html.js.map +0 -1
  220. package/dist/cli-help.test.d.ts +0 -2
  221. package/dist/cli-help.test.d.ts.map +0 -1
  222. package/dist/cli-help.test.js +0 -98
  223. package/dist/cli-help.test.js.map +0 -1
  224. package/dist/cli.d.ts.map +0 -1
  225. package/dist/cli.js.map +0 -1
  226. package/dist/cloud-client.d.ts.map +0 -1
  227. package/dist/cloud-client.js.map +0 -1
  228. package/dist/create-logger.d.ts.map +0 -1
  229. package/dist/create-logger.js.map +0 -1
  230. package/dist/debugger-examples-types.d.ts.map +0 -1
  231. package/dist/debugger-examples-types.js.map +0 -1
  232. package/dist/debugger-examples.d.ts.map +0 -1
  233. package/dist/debugger-examples.js.map +0 -1
  234. package/dist/debugger.d.ts.map +0 -1
  235. package/dist/debugger.js.map +0 -1
  236. package/dist/diff-utils.d.ts.map +0 -1
  237. package/dist/diff-utils.js.map +0 -1
  238. package/dist/diff-utils.test.d.ts +0 -2
  239. package/dist/diff-utils.test.d.ts.map +0 -1
  240. package/dist/diff-utils.test.js +0 -137
  241. package/dist/diff-utils.test.js.map +0 -1
  242. package/dist/doctor.d.ts.map +0 -1
  243. package/dist/doctor.js.map +0 -1
  244. package/dist/doctor.test.d.ts +0 -2
  245. package/dist/doctor.test.d.ts.map +0 -1
  246. package/dist/doctor.test.js +0 -208
  247. package/dist/doctor.test.js.map +0 -1
  248. package/dist/editor-examples.d.ts.map +0 -1
  249. package/dist/editor-examples.js.map +0 -1
  250. package/dist/editor.d.ts.map +0 -1
  251. package/dist/editor.js.map +0 -1
  252. package/dist/env-compat.d.ts.map +0 -1
  253. package/dist/env-compat.js.map +0 -1
  254. package/dist/executor.d.ts.map +0 -1
  255. package/dist/executor.js.map +0 -1
  256. package/dist/executor.unit.test.d.ts +0 -2
  257. package/dist/executor.unit.test.d.ts.map +0 -1
  258. package/dist/executor.unit.test.js +0 -143
  259. package/dist/executor.unit.test.js.map +0 -1
  260. package/dist/extension-connection.test.d.ts +0 -2
  261. package/dist/extension-connection.test.d.ts.map +0 -1
  262. package/dist/extension-connection.test.js +0 -708
  263. package/dist/extension-connection.test.js.map +0 -1
  264. package/dist/extension-icon-warning.test.d.ts +0 -2
  265. package/dist/extension-icon-warning.test.d.ts.map +0 -1
  266. package/dist/extension-icon-warning.test.js +0 -33
  267. package/dist/extension-icon-warning.test.js.map +0 -1
  268. package/dist/ghost-browser.d.ts.map +0 -1
  269. package/dist/ghost-browser.js.map +0 -1
  270. package/dist/ghost-cursor-controller.d.ts.map +0 -1
  271. package/dist/ghost-cursor-controller.js.map +0 -1
  272. package/dist/ghost-cursor.d.ts.map +0 -1
  273. package/dist/ghost-cursor.js.map +0 -1
  274. package/dist/htmlrewrite.d.ts.map +0 -1
  275. package/dist/htmlrewrite.js.map +0 -1
  276. package/dist/htmlrewrite.test.d.ts +0 -2
  277. package/dist/htmlrewrite.test.d.ts.map +0 -1
  278. package/dist/htmlrewrite.test.js +0 -7975
  279. package/dist/htmlrewrite.test.js.map +0 -1
  280. package/dist/index.d.ts.map +0 -1
  281. package/dist/index.js.map +0 -1
  282. package/dist/kill-port.d.ts.map +0 -1
  283. package/dist/kill-port.js.map +0 -1
  284. package/dist/kitty-graphics.d.ts.map +0 -1
  285. package/dist/kitty-graphics.js.map +0 -1
  286. package/dist/kitty-graphics.test.d.ts +0 -2
  287. package/dist/kitty-graphics.test.d.ts.map +0 -1
  288. package/dist/kitty-graphics.test.js +0 -125
  289. package/dist/kitty-graphics.test.js.map +0 -1
  290. package/dist/locator-selector.test.d.ts +0 -2
  291. package/dist/locator-selector.test.d.ts.map +0 -1
  292. package/dist/locator-selector.test.js +0 -98
  293. package/dist/locator-selector.test.js.map +0 -1
  294. package/dist/mcp-client.d.ts +0 -20
  295. package/dist/mcp-client.d.ts.map +0 -1
  296. package/dist/mcp-client.js +0 -56
  297. package/dist/mcp-client.js.map +0 -1
  298. package/dist/mcp.d.ts.map +0 -1
  299. package/dist/mcp.js.map +0 -1
  300. package/dist/on-mouse-action.test.d.ts +0 -2
  301. package/dist/on-mouse-action.test.d.ts.map +0 -1
  302. package/dist/on-mouse-action.test.js +0 -180
  303. package/dist/on-mouse-action.test.js.map +0 -1
  304. package/dist/options-page.test.d.ts +0 -2
  305. package/dist/options-page.test.d.ts.map +0 -1
  306. package/dist/options-page.test.js +0 -773
  307. package/dist/options-page.test.js.map +0 -1
  308. package/dist/package-paths.d.ts.map +0 -1
  309. package/dist/package-paths.js.map +0 -1
  310. package/dist/page-markdown.d.ts.map +0 -1
  311. package/dist/page-markdown.js.map +0 -1
  312. package/dist/performance-examples.d.ts.map +0 -1
  313. package/dist/performance-examples.js.map +0 -1
  314. package/dist/playwright-import.d.ts.map +0 -1
  315. package/dist/playwright-import.js.map +0 -1
  316. package/dist/popup-relocation.test.d.ts +0 -7
  317. package/dist/popup-relocation.test.d.ts.map +0 -1
  318. package/dist/popup-relocation.test.js +0 -139
  319. package/dist/popup-relocation.test.js.map +0 -1
  320. package/dist/product-paths.d.ts.map +0 -1
  321. package/dist/product-paths.js.map +0 -1
  322. package/dist/product-paths.test.d.ts +0 -2
  323. package/dist/product-paths.test.d.ts.map +0 -1
  324. package/dist/product-paths.test.js +0 -39
  325. package/dist/product-paths.test.js.map +0 -1
  326. package/dist/protocol.d.ts.map +0 -1
  327. package/dist/protocol.js.map +0 -1
  328. package/dist/protocol.test.d.ts +0 -2
  329. package/dist/protocol.test.d.ts.map +0 -1
  330. package/dist/protocol.test.js +0 -31
  331. package/dist/protocol.test.js.map +0 -1
  332. package/dist/react-source.d.ts.map +0 -1
  333. package/dist/react-source.js.map +0 -1
  334. package/dist/relay-client.d.ts.map +0 -1
  335. package/dist/relay-client.js.map +0 -1
  336. package/dist/relay-client.test.d.ts +0 -2
  337. package/dist/relay-client.test.d.ts.map +0 -1
  338. package/dist/relay-client.test.js +0 -305
  339. package/dist/relay-client.test.js.map +0 -1
  340. package/dist/relay-core.test.d.ts +0 -2
  341. package/dist/relay-core.test.d.ts.map +0 -1
  342. package/dist/relay-core.test.js +0 -1427
  343. package/dist/relay-core.test.js.map +0 -1
  344. package/dist/relay-navigation.test.d.ts +0 -2
  345. package/dist/relay-navigation.test.d.ts.map +0 -1
  346. package/dist/relay-navigation.test.js +0 -661
  347. package/dist/relay-navigation.test.js.map +0 -1
  348. package/dist/relay-session.test.d.ts +0 -2
  349. package/dist/relay-session.test.d.ts.map +0 -1
  350. package/dist/relay-session.test.js +0 -1121
  351. package/dist/relay-session.test.js.map +0 -1
  352. package/dist/relay-state.d.ts.map +0 -1
  353. package/dist/relay-state.js.map +0 -1
  354. package/dist/relay-state.test.d.ts +0 -2
  355. package/dist/relay-state.test.d.ts.map +0 -1
  356. package/dist/relay-state.test.js +0 -594
  357. package/dist/relay-state.test.js.map +0 -1
  358. package/dist/replay-ai-index.d.ts.map +0 -1
  359. package/dist/replay-ai-index.js.map +0 -1
  360. package/dist/replay-ai-index.test.d.ts +0 -2
  361. package/dist/replay-ai-index.test.d.ts.map +0 -1
  362. package/dist/replay-ai-index.test.js +0 -255
  363. package/dist/replay-ai-index.test.js.map +0 -1
  364. package/dist/replay-cli.test.d.ts +0 -2
  365. package/dist/replay-cli.test.d.ts.map +0 -1
  366. package/dist/replay-cli.test.js +0 -275
  367. package/dist/replay-cli.test.js.map +0 -1
  368. package/dist/replay-eval.d.ts.map +0 -1
  369. package/dist/replay-eval.js.map +0 -1
  370. package/dist/replay-handoff.d.ts.map +0 -1
  371. package/dist/replay-handoff.js.map +0 -1
  372. package/dist/replay-handoff.test.d.ts +0 -2
  373. package/dist/replay-handoff.test.d.ts.map +0 -1
  374. package/dist/replay-handoff.test.js +0 -123
  375. package/dist/replay-handoff.test.js.map +0 -1
  376. package/dist/replay-workflow-compiler.d.ts.map +0 -1
  377. package/dist/replay-workflow-compiler.js.map +0 -1
  378. package/dist/replay-workflow-compiler.test.d.ts +0 -2
  379. package/dist/replay-workflow-compiler.test.d.ts.map +0 -1
  380. package/dist/replay-workflow-compiler.test.js +0 -223
  381. package/dist/replay-workflow-compiler.test.js.map +0 -1
  382. package/dist/rrweb-recording-relay.d.ts.map +0 -1
  383. package/dist/rrweb-recording-relay.js.map +0 -1
  384. package/dist/rrweb-recording-relay.test.d.ts +0 -2
  385. package/dist/rrweb-recording-relay.test.d.ts.map +0 -1
  386. package/dist/rrweb-recording-relay.test.js +0 -85
  387. package/dist/rrweb-recording-relay.test.js.map +0 -1
  388. package/dist/rrweb-recording.d.ts.map +0 -1
  389. package/dist/rrweb-recording.js.map +0 -1
  390. package/dist/scoped-fs.d.ts.map +0 -1
  391. package/dist/scoped-fs.js.map +0 -1
  392. package/dist/scoped-fs.test.d.ts +0 -5
  393. package/dist/scoped-fs.test.d.ts.map +0 -1
  394. package/dist/scoped-fs.test.js +0 -73
  395. package/dist/scoped-fs.test.js.map +0 -1
  396. package/dist/skill-stub.test.d.ts +0 -2
  397. package/dist/skill-stub.test.d.ts.map +0 -1
  398. package/dist/skill-stub.test.js +0 -22
  399. package/dist/skill-stub.test.js.map +0 -1
  400. package/dist/snapshot-tools.test.d.ts +0 -2
  401. package/dist/snapshot-tools.test.d.ts.map +0 -1
  402. package/dist/snapshot-tools.test.js +0 -856
  403. package/dist/snapshot-tools.test.js.map +0 -1
  404. package/dist/start-relay-server.d.ts.map +0 -1
  405. package/dist/start-relay-server.js.map +0 -1
  406. package/dist/styles-examples.d.ts.map +0 -1
  407. package/dist/styles-examples.js.map +0 -1
  408. package/dist/styles.d.ts.map +0 -1
  409. package/dist/styles.js.map +0 -1
  410. package/dist/tabwright-agent-skill.d.ts.map +0 -1
  411. package/dist/tabwright-agent-skill.js.map +0 -1
  412. package/dist/tabwright-agent-skill.test.d.ts +0 -2
  413. package/dist/tabwright-agent-skill.test.d.ts.map +0 -1
  414. package/dist/tabwright-agent-skill.test.js +0 -51
  415. package/dist/tabwright-agent-skill.test.js.map +0 -1
  416. package/dist/test-declarations.d.ts.map +0 -1
  417. package/dist/test-declarations.js.map +0 -1
  418. package/dist/test-utils.d.ts +0 -69
  419. package/dist/test-utils.d.ts.map +0 -1
  420. package/dist/test-utils.js +0 -448
  421. package/dist/test-utils.js.map +0 -1
  422. package/dist/test-utils.test.d.ts +0 -2
  423. package/dist/test-utils.test.d.ts.map +0 -1
  424. package/dist/test-utils.test.js +0 -55
  425. package/dist/test-utils.test.js.map +0 -1
  426. package/dist/utils.d.ts.map +0 -1
  427. package/dist/utils.js.map +0 -1
  428. package/dist/wait-for-page-load.d.ts.map +0 -1
  429. package/dist/wait-for-page-load.js.map +0 -1
  430. package/dist/workflow-capability.d.ts.map +0 -1
  431. package/dist/workflow-capability.js.map +0 -1
  432. package/dist/workflow-script-flow.test.d.ts +0 -2
  433. package/dist/workflow-script-flow.test.d.ts.map +0 -1
  434. package/dist/workflow-script-flow.test.js +0 -285
  435. package/dist/workflow-script-flow.test.js.map +0 -1
  436. package/src/__snapshots__/x.com.processed.html +0 -1003
  437. package/src/__snapshots__/x.com.processed.withStyles.html +0 -2720
  438. package/src/a11y-client.ts +0 -241
  439. package/src/aria-snapshot.test.ts +0 -311
  440. package/src/aria-snapshot.ts +0 -1681
  441. package/src/aria-snapshot.unit.test.ts +0 -615
  442. package/src/aria-snapshots/github-interactive.txt +0 -193
  443. package/src/aria-snapshots/github-raw.txt +0 -309
  444. package/src/aria-snapshots/hackernews-interactive.txt +0 -477
  445. package/src/aria-snapshots/hackernews-raw.txt +0 -428
  446. package/src/aria-snapshots/prosemirror-interactive.txt +0 -66
  447. package/src/aria-snapshots/prosemirror-raw.txt +0 -145
  448. package/src/assets/aria-labels-hacker-news.png +0 -0
  449. package/src/assets/aria-labels-old-reddit.png +0 -0
  450. package/src/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.ts +0 -5
  451. package/src/assets/cursors/screen-studio/pointer-macos-tahoe.svg +0 -18
  452. package/src/assets/x.com.html +0 -32946
  453. package/src/browser-config.ts +0 -179
  454. package/src/browser-install.ts +0 -284
  455. package/src/browser-launch.ts +0 -75
  456. package/src/builtin-capabilities.ts +0 -2765
  457. package/src/capability-agent-skill.ts +0 -305
  458. package/src/capability-auth-state.ts +0 -197
  459. package/src/capability-auth.ts +0 -249
  460. package/src/capability-cli-confirmation.test.ts +0 -90
  461. package/src/capability-options.test.ts +0 -89
  462. package/src/capability-options.ts +0 -57
  463. package/src/capability-package.test.ts +0 -204
  464. package/src/capability-package.ts +0 -555
  465. package/src/capability-registry.test.ts +0 -1905
  466. package/src/capability-registry.ts +0 -1234
  467. package/src/capability-runner.ts +0 -801
  468. package/src/capability-search-relevance.test.ts +0 -73
  469. package/src/capability-studio.test.ts +0 -45
  470. package/src/capability-studio.ts +0 -641
  471. package/src/cdp-log.test.ts +0 -131
  472. package/src/cdp-log.ts +0 -112
  473. package/src/cdp-relay.ts +0 -2944
  474. package/src/cdp-session.ts +0 -77
  475. package/src/cdp-types.ts +0 -158
  476. package/src/channel-owner-inspect.test.ts +0 -94
  477. package/src/chrome-discovery.test.ts +0 -50
  478. package/src/chrome-discovery.ts +0 -220
  479. package/src/clean-html.ts +0 -141
  480. package/src/cli-help.test.ts +0 -123
  481. package/src/cli.ts +0 -3181
  482. package/src/cloud-client.ts +0 -179
  483. package/src/create-logger.ts +0 -38
  484. package/src/debugger-examples-types.ts +0 -16
  485. package/src/debugger-examples.ts +0 -66
  486. package/src/debugger.ts +0 -708
  487. package/src/diff-utils.test.ts +0 -152
  488. package/src/diff-utils.ts +0 -70
  489. package/src/doctor.test.ts +0 -244
  490. package/src/doctor.ts +0 -321
  491. package/src/editor-examples.ts +0 -158
  492. package/src/editor.ts +0 -426
  493. package/src/env-compat.ts +0 -28
  494. package/src/executor.ts +0 -1824
  495. package/src/executor.unit.test.ts +0 -168
  496. package/src/extension-connection.test.ts +0 -855
  497. package/src/extension-icon-warning.test.ts +0 -45
  498. package/src/ghost-browser.ts +0 -149
  499. package/src/ghost-cursor-client.ts +0 -494
  500. package/src/ghost-cursor-controller.ts +0 -129
  501. package/src/ghost-cursor.ts +0 -123
  502. package/src/htmlrewrite.test.ts +0 -8008
  503. package/src/htmlrewrite.ts +0 -390
  504. package/src/index.ts +0 -53
  505. package/src/kill-port.ts +0 -219
  506. package/src/kitty-graphics.test.ts +0 -139
  507. package/src/kitty-graphics.ts +0 -79
  508. package/src/locator-selector.test.ts +0 -119
  509. package/src/mcp-client.ts +0 -78
  510. package/src/mcp.ts +0 -629
  511. package/src/on-mouse-action.test.ts +0 -226
  512. package/src/options-page.test.ts +0 -839
  513. package/src/package-paths.ts +0 -38
  514. package/src/page-markdown.ts +0 -240
  515. package/src/performance-examples.ts +0 -186
  516. package/src/playwright-import.ts +0 -59
  517. package/src/popup-relocation.test.ts +0 -163
  518. package/src/product-paths.test.ts +0 -47
  519. package/src/product-paths.ts +0 -28
  520. package/src/protocol.test.ts +0 -52
  521. package/src/protocol.ts +0 -351
  522. package/src/react-source.ts +0 -379
  523. package/src/relay-client.test.ts +0 -375
  524. package/src/relay-client.ts +0 -572
  525. package/src/relay-core.test.ts +0 -1603
  526. package/src/relay-navigation.test.ts +0 -790
  527. package/src/relay-session.test.ts +0 -1375
  528. package/src/relay-state.test.ts +0 -729
  529. package/src/relay-state.ts +0 -561
  530. package/src/replay-ai-index.test.ts +0 -278
  531. package/src/replay-ai-index.ts +0 -872
  532. package/src/replay-cli.test.ts +0 -325
  533. package/src/replay-eval.ts +0 -1039
  534. package/src/replay-handoff.test.ts +0 -163
  535. package/src/replay-handoff.ts +0 -109
  536. package/src/replay-workflow-compiler.test.ts +0 -250
  537. package/src/replay-workflow-compiler.ts +0 -700
  538. package/src/resource.md +0 -409
  539. package/src/rrweb-recording-relay.test.ts +0 -99
  540. package/src/rrweb-recording-relay.ts +0 -400
  541. package/src/rrweb-recording.ts +0 -322
  542. package/src/scoped-fs.test.ts +0 -80
  543. package/src/scoped-fs.ts +0 -420
  544. package/src/skill-stub.test.ts +0 -24
  545. package/src/snapshot-tools.test.ts +0 -1017
  546. package/src/snapshots/hacker-news-accessibility-full.md +0 -81
  547. package/src/snapshots/hacker-news-accessibility-interactive.md +0 -43
  548. package/src/snapshots/page-markdown-output.txt +0 -16
  549. package/src/snapshots/shadcn-ui-accessibility-full.md +0 -201
  550. package/src/snapshots/shadcn-ui-accessibility-interactive.md +0 -109
  551. package/src/start-relay-server.ts +0 -69
  552. package/src/styles-examples.ts +0 -84
  553. package/src/styles.ts +0 -343
  554. package/src/tabwright-agent-skill.test.ts +0 -61
  555. package/src/tabwright-agent-skill.ts +0 -105
  556. package/src/test-declarations.ts +0 -13
  557. package/src/test-utils.test.ts +0 -70
  558. package/src/test-utils.ts +0 -566
  559. package/src/utils.ts +0 -78
  560. package/src/wait-for-page-load.ts +0 -198
  561. package/src/workflow-capability.ts +0 -417
  562. package/src/workflow-script-flow.test.ts +0 -388
@@ -1,872 +0,0 @@
1
- import fs from 'node:fs'
2
- import path from 'node:path'
3
- import { getTabwrightUserDataDir } from './product-paths.js'
4
- import { getSavedRrwebRecordingWithEvents } from './rrweb-recording-relay.js'
5
- import type { RrwebEvent } from './protocol.js'
6
-
7
- // rrweb.record already stores rrweb-snapshot serialized DOM nodes in full snapshots and mutation adds.
8
- // This index keeps raw replay as evidence and derives AI-readable labels, fields, and selector hints; rrweb ids are recording-scoped, not future selectors.
9
- type ReplayNodeType = 0 | 1 | 2 | 3 | 4 | 5
10
- type ReplayActionKind = 'click' | 'input'
11
-
12
- interface ReplayDomNode {
13
- id: number
14
- type: ReplayNodeType
15
- tagName?: string
16
- textContent?: string
17
- attributes: Record<string, string>
18
- childIds: number[]
19
- parentId?: number
20
- }
21
-
22
- interface ReplayDomState {
23
- nodes: Map<number, ReplayDomNode>
24
- }
25
-
26
- export interface ReplayAiNodeSummary {
27
- id: number
28
- type: string
29
- tagName?: string
30
- text?: string
31
- label?: string
32
- role?: string
33
- name?: string
34
- placeholder?: string
35
- className?: string
36
- selectorHints: string[]
37
- ancestorText: string[]
38
- }
39
-
40
- export interface ReplayAiAction {
41
- kind: ReplayActionKind
42
- timestamp: number
43
- relativeTime?: number
44
- nodeId?: number
45
- label: string
46
- value?: string
47
- checked?: boolean
48
- node?: ReplayAiNodeSummary
49
- }
50
-
51
- export interface ReplayAiField {
52
- key: string
53
- label: string
54
- nodeId?: number
55
- selectorHints: string[]
56
- value?: string
57
- checked?: boolean
58
- actionCount: number
59
- updatedAt: number
60
- }
61
-
62
- export interface ReplayAiIndexStats {
63
- eventCount: number
64
- fullSnapshotCount: number
65
- mutationEventCount: number
66
- clickEventCount: number
67
- inputEventCount: number
68
- annotationCount: number
69
- }
70
-
71
- export interface ReplayAiAnnotationRect {
72
- x: number
73
- y: number
74
- width: number
75
- height: number
76
- }
77
-
78
- export interface ReplayAiAnnotationTarget {
79
- tagName?: string
80
- label?: string
81
- text?: string
82
- role?: string
83
- name?: string
84
- placeholder?: string
85
- selectorHints: string[]
86
- rect?: ReplayAiAnnotationRect
87
- }
88
-
89
- export interface ReplayAiAnnotation {
90
- id: string
91
- text: string
92
- timestamp: number
93
- relativeTime?: number
94
- url?: string
95
- target?: ReplayAiAnnotationTarget
96
- }
97
-
98
- export interface ReplayAiIndex {
99
- schemaVersion: 1
100
- replayId: string
101
- url?: string
102
- generatedAt: number
103
- stats: ReplayAiIndexStats
104
- actions: ReplayAiAction[]
105
- fields: ReplayAiField[]
106
- annotations: ReplayAiAnnotation[]
107
- interactiveElements: ReplayAiNodeSummary[]
108
- pageText: string[]
109
- warnings: string[]
110
- }
111
-
112
- export interface SavedReplayAiIndex {
113
- id: string
114
- replayId: string
115
- path: string
116
- generatedAt: number
117
- size: number
118
- actionCount: number
119
- fieldCount: number
120
- url?: string
121
- }
122
-
123
- const MAX_AI_ACTIONS = 200
124
- const MAX_INTERACTIVE_ELEMENTS = 120
125
- const MAX_PAGE_TEXTS = 160
126
-
127
- function getReplayAiIndexesDir(): string {
128
- return path.join(getTabwrightUserDataDir(), 'replay-ai-indexes')
129
- }
130
-
131
- function getReplayAiIndexesIndexPath(): string {
132
- return path.join(getReplayAiIndexesDir(), 'index.json')
133
- }
134
-
135
- function getReplayAiIndexPath(replayId: string): string {
136
- return path.join(getReplayAiIndexesDir(), `${replayId}.json`)
137
- }
138
-
139
- function isRecord(value: unknown): value is Record<string, unknown> {
140
- return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
141
- }
142
-
143
- function optionalString(value: unknown): string | undefined {
144
- return typeof value === 'string' && value.trim() ? value : undefined
145
- }
146
-
147
- function numberValue(value: unknown): number | undefined {
148
- return typeof value === 'number' && Number.isFinite(value) ? value : undefined
149
- }
150
-
151
- function stringArrayValue(value: unknown): string[] {
152
- if (!Array.isArray(value)) {
153
- return []
154
- }
155
- return value.filter((item): item is string => {
156
- return typeof item === 'string' && item.length > 0
157
- })
158
- }
159
-
160
- function normalizeText(value: string | undefined): string {
161
- return (value || '').replace(/\s+/g, ' ').trim()
162
- }
163
-
164
- function uniqueStrings(values: string[]): string[] {
165
- return Array.from(new Set(values.filter((value) => {
166
- return value.length > 0
167
- })))
168
- }
169
-
170
- function recordToStringMap(value: unknown): Record<string, string> {
171
- if (!isRecord(value)) {
172
- return {}
173
- }
174
- return Object.fromEntries(
175
- Object.entries(value)
176
- .map(([key, item]) => {
177
- if (typeof item === 'string') {
178
- return [key, item] as const
179
- }
180
- if (typeof item === 'number' || typeof item === 'boolean') {
181
- return [key, String(item)] as const
182
- }
183
- if (isRecord(item)) {
184
- return [key, JSON.stringify(item)] as const
185
- }
186
- return null
187
- })
188
- .filter((entry): entry is readonly [string, string] => {
189
- return Boolean(entry)
190
- }),
191
- )
192
- }
193
-
194
- function getEventType(event: RrwebEvent): number | undefined {
195
- return numberValue(event.type)
196
- }
197
-
198
- function getEventTimestamp(event: RrwebEvent): number | undefined {
199
- return numberValue(event.timestamp)
200
- }
201
-
202
- function getEventData(event: RrwebEvent): Record<string, unknown> {
203
- return isRecord(event.data) ? event.data : {}
204
- }
205
-
206
- function getNodeId(value: unknown): number | undefined {
207
- return numberValue(isRecord(value) ? value.id : undefined)
208
- }
209
-
210
- function readReplayNode(rawNode: unknown, parentId?: number): ReplayDomNode | null {
211
- if (!isRecord(rawNode)) {
212
- return null
213
- }
214
- const id = numberValue(rawNode.id)
215
- const rawType = numberValue(rawNode.type)
216
- if (!id || rawType === undefined || ![0, 1, 2, 3, 4, 5].includes(rawType)) {
217
- return null
218
- }
219
- const type = rawType as ReplayNodeType
220
- const childNodes = Array.isArray(rawNode.childNodes) ? rawNode.childNodes : []
221
- return {
222
- id,
223
- type,
224
- tagName: optionalString(rawNode.tagName)?.toLowerCase(),
225
- textContent: optionalString(rawNode.textContent),
226
- attributes: recordToStringMap(rawNode.attributes),
227
- childIds: childNodes
228
- .map((child) => {
229
- return getNodeId(child)
230
- })
231
- .filter((nodeId): nodeId is number => {
232
- return nodeId !== undefined
233
- }),
234
- parentId,
235
- }
236
- }
237
-
238
- function addReplayNode(state: ReplayDomState, rawNode: unknown, parentId?: number): void {
239
- const node = readReplayNode(rawNode, parentId)
240
- const childNodes = isRecord(rawNode) && Array.isArray(rawNode.childNodes) ? rawNode.childNodes : []
241
- if (!node && childNodes.length === 0) {
242
- return
243
- }
244
- if (!node) {
245
- childNodes.forEach((child) => {
246
- addReplayNode(state, child, parentId)
247
- })
248
- return
249
- }
250
- state.nodes.set(node.id, node)
251
- childNodes.forEach((child) => {
252
- addReplayNode(state, child, node.id)
253
- })
254
- }
255
-
256
- function removeReplayNode(state: ReplayDomState, nodeId: number): void {
257
- const node = state.nodes.get(nodeId)
258
- if (!node) {
259
- return
260
- }
261
- node.childIds.forEach((childId) => {
262
- removeReplayNode(state, childId)
263
- })
264
- state.nodes.delete(nodeId)
265
- }
266
-
267
- function applyMutationEvent(state: ReplayDomState, data: Record<string, unknown>): void {
268
- const removes = Array.isArray(data.removes) ? data.removes : []
269
- removes
270
- .map((remove) => {
271
- return isRecord(remove) ? numberValue(remove.id) : undefined
272
- })
273
- .filter((nodeId): nodeId is number => {
274
- return nodeId !== undefined
275
- })
276
- .forEach((nodeId) => {
277
- removeReplayNode(state, nodeId)
278
- })
279
-
280
- const adds = Array.isArray(data.adds) ? data.adds : []
281
- adds.forEach((add) => {
282
- if (!isRecord(add)) {
283
- return
284
- }
285
- addReplayNode(state, add.node, numberValue(add.parentId))
286
- })
287
-
288
- const texts = Array.isArray(data.texts) ? data.texts : []
289
- texts.forEach((text) => {
290
- if (!isRecord(text)) {
291
- return
292
- }
293
- const nodeId = numberValue(text.id)
294
- const node = nodeId === undefined ? undefined : state.nodes.get(nodeId)
295
- if (!node) {
296
- return
297
- }
298
- node.textContent = optionalString(text.value) || ''
299
- })
300
-
301
- const attributes = Array.isArray(data.attributes) ? data.attributes : []
302
- attributes.forEach((attribute) => {
303
- if (!isRecord(attribute)) {
304
- return
305
- }
306
- const nodeId = numberValue(attribute.id)
307
- const node = nodeId === undefined ? undefined : state.nodes.get(nodeId)
308
- if (!node) {
309
- return
310
- }
311
- node.attributes = {
312
- ...node.attributes,
313
- ...recordToStringMap(attribute.attributes),
314
- }
315
- })
316
- }
317
-
318
- function isNoisyText(value: string): boolean {
319
- return /to pick up a draggable item/i.test(value) || value === 'SCRIPT_PLACEHOLDER'
320
- }
321
-
322
- function nodeText(state: ReplayDomState, nodeId: number, depth = 0): string {
323
- const node = state.nodes.get(nodeId)
324
- if (!node || depth > 20) {
325
- return ''
326
- }
327
- const childText = node.childIds
328
- .map((childId) => {
329
- return nodeText(state, childId, depth + 1)
330
- })
331
- .filter((text) => {
332
- return text.length > 0
333
- })
334
- .join(' ')
335
- return normalizeText([node.textContent, childText].filter(Boolean).join(' '))
336
- }
337
-
338
- function nodeAndAncestors(state: ReplayDomState, nodeId: number, maxDepth: number): ReplayDomNode[] {
339
- const current = state.nodes.get(nodeId)
340
- if (!current) {
341
- return []
342
- }
343
- const ancestors: ReplayDomNode[] = [current]
344
- let next = current.parentId === undefined ? undefined : state.nodes.get(current.parentId)
345
- let depth = 1
346
- while (next && depth < maxDepth) {
347
- ancestors.push(next)
348
- next = next.parentId === undefined ? undefined : state.nodes.get(next.parentId)
349
- depth += 1
350
- }
351
- return ancestors
352
- }
353
-
354
- function actionLabelFromText(value: string): string | undefined {
355
- const text = normalizeText(value)
356
- if (!text || text.length > 120 || isNoisyText(text)) {
357
- return undefined
358
- }
359
- const matchers: Array<{ label: string; pattern: RegExp }> = [
360
- { label: '重新编辑', pattern: /重新编辑/ },
361
- { label: '继续编辑', pattern: /继续编辑/ },
362
- { label: 'Add entry', pattern: /add entry/i },
363
- { label: '新增', pattern: /新增|添加/ },
364
- { label: '提交', pattern: /提交|submit/i },
365
- { label: 'OK', pattern: /\bOK\b|确定/ },
366
- { label: 'Cancel', pattern: /cancel|取消/i },
367
- { label: '编辑', pattern: /编辑/ },
368
- ]
369
- return matchers.find((matcher) => {
370
- return matcher.pattern.test(text)
371
- })?.label
372
- }
373
-
374
- function nodeLabelFromStructure(state: ReplayDomState, nodeId: number): string | undefined {
375
- const ancestors = nodeAndAncestors(state, nodeId, 8)
376
- const classText = ancestors
377
- .map((node) => {
378
- return node.attributes.class || ''
379
- })
380
- .join(' ')
381
- const inModal = classText.includes('designer-modal')
382
- if (classText.includes('designer-formily-array-base-addition')) {
383
- return 'Add entry'
384
- }
385
- if (inModal && classText.includes('designer-btn-dangerous')) {
386
- return '重新编辑'
387
- }
388
- if (inModal && classText.includes('designer-btn-primary')) {
389
- return 'OK'
390
- }
391
- return undefined
392
- }
393
-
394
- function nodeLabelFromAttributes(node: ReplayDomNode): string | undefined {
395
- return (
396
- optionalString(node.attributes['aria-label']) ||
397
- optionalString(node.attributes.title) ||
398
- optionalString(node.attributes.placeholder) ||
399
- optionalString(node.attributes.name)
400
- )
401
- }
402
-
403
- function nodeLabel(state: ReplayDomState, nodeId: number): string | undefined {
404
- const structuredLabel = nodeLabelFromStructure(state, nodeId)
405
- if (structuredLabel) {
406
- return structuredLabel
407
- }
408
- const current = state.nodes.get(nodeId)
409
- const currentAttributeLabel = current ? nodeLabelFromAttributes(current) : undefined
410
- if (currentAttributeLabel) {
411
- return currentAttributeLabel
412
- }
413
- const candidates = nodeAndAncestors(state, nodeId, 8)
414
- .flatMap((node) => {
415
- return [nodeLabelFromAttributes(node), nodeText(state, node.id)]
416
- })
417
- .filter((text): text is string => {
418
- return Boolean(text)
419
- })
420
- const actionLabel = candidates
421
- .map((text) => {
422
- return actionLabelFromText(text)
423
- })
424
- .find((label) => {
425
- return Boolean(label)
426
- })
427
- if (actionLabel) {
428
- return actionLabel
429
- }
430
- return candidates.find((text) => {
431
- return text.length <= 120 && !isNoisyText(text)
432
- })
433
- }
434
-
435
- function attrSelector(name: string, value: string): string {
436
- return `[${name}=${JSON.stringify(value)}]`
437
- }
438
-
439
- function selectorHints(node: ReplayDomNode): string[] {
440
- const tagName = node.tagName || ''
441
- const className = node.attributes.class || ''
442
- const classHints = className
443
- .split(/\s+/)
444
- .filter((classPart) => {
445
- return classPart === 'designer-formily-array-base-addition' || classPart === 'designer-input'
446
- })
447
- .map((classPart) => {
448
- return tagName ? `${tagName}.${classPart}` : `.${classPart}`
449
- })
450
- return uniqueStrings([
451
- node.attributes.id ? `#${node.attributes.id}` : '',
452
- node.attributes['data-testid'] ? attrSelector('data-testid', node.attributes['data-testid']) : '',
453
- node.attributes['data-test'] ? attrSelector('data-test', node.attributes['data-test']) : '',
454
- node.attributes.name && tagName ? `${tagName}${attrSelector('name', node.attributes.name)}` : '',
455
- node.attributes.placeholder && tagName ? `${tagName}${attrSelector('placeholder', node.attributes.placeholder)}` : '',
456
- node.attributes['aria-label'] && tagName ? `${tagName}${attrSelector('aria-label', node.attributes['aria-label'])}` : '',
457
- ...classHints,
458
- ])
459
- }
460
-
461
- function nodeTypeName(type: ReplayNodeType): string {
462
- if (type === 0) {
463
- return 'document'
464
- }
465
- if (type === 1) {
466
- return 'doctype'
467
- }
468
- if (type === 2) {
469
- return 'element'
470
- }
471
- if (type === 3) {
472
- return 'text'
473
- }
474
- if (type === 4) {
475
- return 'cdata'
476
- }
477
- return 'comment'
478
- }
479
-
480
- function summarizeNode(state: ReplayDomState, nodeId: number): ReplayAiNodeSummary | undefined {
481
- const node = state.nodes.get(nodeId)
482
- if (!node) {
483
- return undefined
484
- }
485
- const text = nodeText(state, nodeId)
486
- const ancestors = nodeAndAncestors(state, nodeId, 8).slice(1)
487
- return {
488
- id: node.id,
489
- type: nodeTypeName(node.type),
490
- tagName: node.tagName,
491
- text: text && text.length <= 240 && !isNoisyText(text) ? text : undefined,
492
- label: nodeLabel(state, nodeId),
493
- role: optionalString(node.attributes.role),
494
- name: optionalString(node.attributes.name),
495
- placeholder: optionalString(node.attributes.placeholder),
496
- className: optionalString(node.attributes.class),
497
- selectorHints: selectorHints(node),
498
- ancestorText: uniqueStrings(
499
- ancestors
500
- .map((ancestor) => {
501
- return nodeText(state, ancestor.id)
502
- })
503
- .filter((ancestorText) => {
504
- return ancestorText.length > 0 && ancestorText.length <= 160 && !isNoisyText(ancestorText)
505
- }),
506
- ).slice(0, 6),
507
- }
508
- }
509
-
510
- function isInteractiveNode(node: ReplayDomNode): boolean {
511
- const tagName = node.tagName || ''
512
- const role = node.attributes.role || ''
513
- const className = node.attributes.class || ''
514
- return (
515
- ['button', 'a', 'input', 'textarea', 'select', 'option'].includes(tagName) ||
516
- ['button', 'textbox', 'checkbox', 'combobox', 'menuitem', 'tab'].includes(role) ||
517
- className.includes('designer-formily-array-base-addition')
518
- )
519
- }
520
-
521
- function getFirstTimestamp(events: RrwebEvent[]): number | undefined {
522
- return events
523
- .map((event) => {
524
- return getEventTimestamp(event)
525
- })
526
- .find((timestamp) => {
527
- return timestamp !== undefined
528
- })
529
- }
530
-
531
- function buildFields(actions: ReplayAiAction[]): ReplayAiField[] {
532
- return Object.values(
533
- actions
534
- .filter((action) => {
535
- return action.kind === 'input'
536
- })
537
- .reduce<Record<string, ReplayAiField>>((fields, action) => {
538
- const key = action.nodeId === undefined ? action.label : `rrweb:${action.nodeId}`
539
- const existing = fields[key]
540
- return {
541
- ...fields,
542
- [key]: {
543
- key,
544
- label: action.node?.label || action.label,
545
- nodeId: action.nodeId,
546
- selectorHints: uniqueStrings([...(existing?.selectorHints || []), ...(action.node?.selectorHints || [])]),
547
- value: action.value ?? existing?.value,
548
- checked: action.checked ?? existing?.checked,
549
- actionCount: (existing?.actionCount || 0) + 1,
550
- updatedAt: action.timestamp,
551
- },
552
- }
553
- }, {}),
554
- ).sort((a, b) => {
555
- return a.updatedAt - b.updatedAt
556
- })
557
- }
558
-
559
- function extractUrlFromEvent(event: RrwebEvent): string | undefined {
560
- const data = getEventData(event)
561
- return optionalString(data.href) || optionalString(data.url)
562
- }
563
-
564
- function readAnnotationRect(value: unknown): ReplayAiAnnotationRect | undefined {
565
- if (!isRecord(value)) {
566
- return undefined
567
- }
568
- const x = numberValue(value.x)
569
- const y = numberValue(value.y)
570
- const width = numberValue(value.width)
571
- const height = numberValue(value.height)
572
- if (x === undefined || y === undefined || width === undefined || height === undefined) {
573
- return undefined
574
- }
575
- return { x, y, width, height }
576
- }
577
-
578
- function readAnnotationTarget(value: unknown): ReplayAiAnnotationTarget | undefined {
579
- if (!isRecord(value)) {
580
- return undefined
581
- }
582
- const selectorHints = stringArrayValue(value.selectorHints)
583
- const target: ReplayAiAnnotationTarget = {
584
- tagName: optionalString(value.tagName),
585
- label: optionalString(value.label),
586
- text: optionalString(value.text),
587
- role: optionalString(value.role),
588
- name: optionalString(value.name),
589
- placeholder: optionalString(value.placeholder),
590
- selectorHints,
591
- rect: readAnnotationRect(value.rect),
592
- }
593
- if (
594
- !target.tagName &&
595
- !target.label &&
596
- !target.text &&
597
- !target.role &&
598
- !target.name &&
599
- !target.placeholder &&
600
- target.selectorHints.length === 0 &&
601
- !target.rect
602
- ) {
603
- return undefined
604
- }
605
- return target
606
- }
607
-
608
- function readAnnotationEvent(options: {
609
- data: Record<string, unknown>
610
- timestamp: number
611
- relativeTime?: number
612
- }): ReplayAiAnnotation | undefined {
613
- if (optionalString(options.data.tag) !== 'playwriter.annotation') {
614
- return undefined
615
- }
616
- const payload = isRecord(options.data.payload) ? options.data.payload : {}
617
- const id = optionalString(payload.id)
618
- const text = normalizeText(optionalString(payload.text))
619
- if (!id || !text) {
620
- return undefined
621
- }
622
- return {
623
- id,
624
- text,
625
- timestamp: numberValue(payload.timestamp) || options.timestamp,
626
- relativeTime: options.relativeTime,
627
- url: optionalString(payload.url),
628
- target: readAnnotationTarget(payload.target),
629
- }
630
- }
631
-
632
- function readAnnotationDeleteEvent(options: { data: Record<string, unknown> }): string | undefined {
633
- if (optionalString(options.data.tag) !== 'playwriter.annotation.delete') {
634
- return undefined
635
- }
636
- const payload = isRecord(options.data.payload) ? options.data.payload : {}
637
- return optionalString(payload.id)
638
- }
639
-
640
- export function buildReplayAiIndex(options: {
641
- replayId: string
642
- url?: string
643
- events: RrwebEvent[]
644
- }): ReplayAiIndex {
645
- const state: ReplayDomState = { nodes: new Map<number, ReplayDomNode>() }
646
- const firstTimestamp = getFirstTimestamp(options.events)
647
- const stats: ReplayAiIndexStats = {
648
- eventCount: options.events.length,
649
- fullSnapshotCount: 0,
650
- mutationEventCount: 0,
651
- clickEventCount: 0,
652
- inputEventCount: 0,
653
- annotationCount: 0,
654
- }
655
- const warnings: string[] = []
656
- const actions: ReplayAiAction[] = []
657
- const annotationsById: Map<string, ReplayAiAnnotation> = new Map()
658
- let url = options.url
659
-
660
- options.events.forEach((event) => {
661
- const eventType = getEventType(event)
662
- const data = getEventData(event)
663
- if (!url) {
664
- url = extractUrlFromEvent(event)
665
- }
666
- if (eventType === 2) {
667
- stats.fullSnapshotCount += 1
668
- addReplayNode(state, data.node)
669
- return
670
- }
671
- const timestamp = getEventTimestamp(event)
672
- const relativeTime = firstTimestamp === undefined || timestamp === undefined ? undefined : timestamp - firstTimestamp
673
- if (eventType === 5) {
674
- if (timestamp === undefined) {
675
- warnings.push('Ignored rrweb custom event without timestamp.')
676
- return
677
- }
678
- const deletedAnnotationId = readAnnotationDeleteEvent({ data })
679
- if (deletedAnnotationId) {
680
- annotationsById.delete(deletedAnnotationId)
681
- stats.annotationCount = annotationsById.size
682
- return
683
- }
684
- const annotation = readAnnotationEvent({ data, timestamp, relativeTime })
685
- if (annotation) {
686
- annotationsById.set(annotation.id, annotation)
687
- stats.annotationCount = annotationsById.size
688
- }
689
- return
690
- }
691
- if (eventType !== 3) {
692
- return
693
- }
694
-
695
- const source = numberValue(data.source)
696
- if (source === 0) {
697
- stats.mutationEventCount += 1
698
- applyMutationEvent(state, data)
699
- return
700
- }
701
-
702
- if (timestamp === undefined) {
703
- warnings.push('Ignored rrweb event without timestamp.')
704
- return
705
- }
706
-
707
- if (source === 5) {
708
- stats.inputEventCount += 1
709
- const nodeId = numberValue(data.id)
710
- const value = optionalString(data.text) || optionalString(data.value) || ''
711
- const checked = typeof data.isChecked === 'boolean' ? data.isChecked : undefined
712
- const node = nodeId === undefined ? undefined : state.nodes.get(nodeId)
713
- if (node) {
714
- node.attributes = {
715
- ...node.attributes,
716
- value,
717
- }
718
- }
719
- const summary = nodeId === undefined ? undefined : summarizeNode(state, nodeId)
720
- actions.push({
721
- kind: 'input',
722
- timestamp,
723
- relativeTime,
724
- nodeId,
725
- label:
726
- summary?.label ||
727
- summary?.placeholder ||
728
- summary?.name ||
729
- summary?.selectorHints[0] ||
730
- (nodeId === undefined ? 'input' : `DOM node #${nodeId}`),
731
- value,
732
- checked,
733
- node: summary,
734
- })
735
- return
736
- }
737
-
738
- if (source === 2 && data.type === 2) {
739
- stats.clickEventCount += 1
740
- const nodeId = numberValue(data.id)
741
- const summary = nodeId === undefined ? undefined : summarizeNode(state, nodeId)
742
- actions.push({
743
- kind: 'click',
744
- timestamp,
745
- relativeTime,
746
- nodeId,
747
- label:
748
- summary?.label ||
749
- summary?.text ||
750
- summary?.selectorHints[0] ||
751
- (nodeId === undefined ? 'click' : `DOM node #${nodeId}`),
752
- node: summary,
753
- })
754
- }
755
- })
756
-
757
- const interactiveElements = Array.from(state.nodes.values())
758
- .filter(isInteractiveNode)
759
- .map((node) => {
760
- return summarizeNode(state, node.id)
761
- })
762
- .filter((summary): summary is ReplayAiNodeSummary => {
763
- return Boolean(summary)
764
- })
765
- .filter((summary) => {
766
- return Boolean(summary.label || summary.text || summary.selectorHints.length > 0)
767
- })
768
- .slice(0, MAX_INTERACTIVE_ELEMENTS)
769
- const pageText = uniqueStrings(
770
- Array.from(state.nodes.values())
771
- .map((node) => {
772
- return nodeText(state, node.id)
773
- })
774
- .filter((text) => {
775
- return text.length > 0 && text.length <= 160 && !isNoisyText(text)
776
- }),
777
- ).slice(0, MAX_PAGE_TEXTS)
778
-
779
- return {
780
- schemaVersion: 1,
781
- replayId: options.replayId,
782
- url,
783
- generatedAt: Date.now(),
784
- stats,
785
- actions: actions.slice(0, MAX_AI_ACTIONS),
786
- fields: buildFields(actions),
787
- annotations: Array.from(annotationsById.values()),
788
- interactiveElements,
789
- pageText,
790
- warnings: uniqueStrings(warnings),
791
- }
792
- }
793
-
794
- export function createReplayAiIndexFromRecording(replayId: string): ReplayAiIndex {
795
- const replay = getSavedRrwebRecordingWithEvents(replayId)
796
- if (!replay) {
797
- throw new Error(`Replay recording not found: ${replayId}`)
798
- }
799
- return buildReplayAiIndex({
800
- replayId,
801
- url: replay.recording.url,
802
- events: replay.events,
803
- })
804
- }
805
-
806
- function isSavedReplayAiIndex(value: unknown): value is SavedReplayAiIndex {
807
- if (!isRecord(value)) {
808
- return false
809
- }
810
- return (
811
- typeof value.id === 'string' &&
812
- typeof value.replayId === 'string' &&
813
- typeof value.path === 'string' &&
814
- typeof value.generatedAt === 'number' &&
815
- typeof value.size === 'number' &&
816
- typeof value.actionCount === 'number' &&
817
- typeof value.fieldCount === 'number' &&
818
- (value.url === undefined || typeof value.url === 'string')
819
- )
820
- }
821
-
822
- function readSavedReplayAiIndexes(): SavedReplayAiIndex[] {
823
- const indexPath = getReplayAiIndexesIndexPath()
824
- if (!fs.existsSync(indexPath)) {
825
- return []
826
- }
827
- try {
828
- const parsed = JSON.parse(fs.readFileSync(indexPath, 'utf-8')) as unknown
829
- if (!Array.isArray(parsed)) {
830
- return []
831
- }
832
- return parsed.filter(isSavedReplayAiIndex)
833
- } catch {
834
- return []
835
- }
836
- }
837
-
838
- function writeSavedReplayAiIndexes(indexes: SavedReplayAiIndex[]): void {
839
- const dir = getReplayAiIndexesDir()
840
- if (!fs.existsSync(dir)) {
841
- fs.mkdirSync(dir, { recursive: true })
842
- }
843
- fs.writeFileSync(getReplayAiIndexesIndexPath(), `${JSON.stringify(indexes, null, 2)}\n`)
844
- }
845
-
846
- export function saveReplayAiIndex(index: ReplayAiIndex): SavedReplayAiIndex {
847
- const outputPath = getReplayAiIndexPath(index.replayId)
848
- const dir = path.dirname(outputPath)
849
- if (!fs.existsSync(dir)) {
850
- fs.mkdirSync(dir, { recursive: true })
851
- }
852
- const payload = `${JSON.stringify(index, null, 2)}\n`
853
- fs.writeFileSync(outputPath, payload)
854
- const saved: SavedReplayAiIndex = {
855
- id: index.replayId,
856
- replayId: index.replayId,
857
- path: outputPath,
858
- generatedAt: index.generatedAt,
859
- size: Buffer.byteLength(payload),
860
- actionCount: index.actions.length,
861
- fieldCount: index.fields.length,
862
- url: index.url,
863
- }
864
- const nextIndexes = [
865
- saved,
866
- ...readSavedReplayAiIndexes().filter((existing) => {
867
- return existing.id !== saved.id
868
- }),
869
- ]
870
- writeSavedReplayAiIndexes(nextIndexes.slice(0, 500))
871
- return saved
872
- }