tabwright 1.0.0 → 2.0.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 (568) hide show
  1. package/dist/agent-skills/tabwright/SKILL.md +3 -0
  2. package/dist/aria-snapshot.d.ts +0 -1
  3. package/dist/aria-snapshot.js +9 -1
  4. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts +0 -1
  5. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js +0 -1
  6. package/dist/bippy.js +5 -5
  7. package/dist/browser-config.d.ts +0 -1
  8. package/dist/browser-config.js +0 -1
  9. package/dist/browser-install.d.ts +0 -1
  10. package/dist/browser-install.js +0 -1
  11. package/dist/browser-launch.d.ts +0 -1
  12. package/dist/browser-launch.js +0 -1
  13. package/dist/capability-agent-skill.d.ts +0 -1
  14. package/dist/capability-agent-skill.js +0 -1
  15. package/dist/capability-auth-state.d.ts +0 -1
  16. package/dist/capability-auth-state.js +0 -1
  17. package/dist/capability-auth.d.ts +0 -1
  18. package/dist/capability-auth.js +0 -1
  19. package/dist/capability-options.d.ts +0 -1
  20. package/dist/capability-options.js +0 -1
  21. package/dist/capability-package.d.ts +0 -1
  22. package/dist/capability-package.js +47 -2
  23. package/dist/capability-registry.d.ts +0 -1
  24. package/dist/capability-registry.js +0 -1
  25. package/dist/capability-runner.d.ts +0 -1
  26. package/dist/capability-runner.js +0 -1
  27. package/dist/capability-studio.d.ts +0 -1
  28. package/dist/capability-studio.js +0 -1
  29. package/dist/cdp-log.d.ts +0 -1
  30. package/dist/cdp-log.js +0 -1
  31. package/dist/cdp-relay.d.ts +0 -1
  32. package/dist/cdp-relay.js +0 -1
  33. package/dist/cdp-session.d.ts +0 -1
  34. package/dist/cdp-session.js +0 -1
  35. package/dist/cdp-types.d.ts +0 -1
  36. package/dist/cdp-types.js +0 -1
  37. package/dist/chrome-discovery.d.ts +0 -1
  38. package/dist/chrome-discovery.js +0 -1
  39. package/dist/clean-html.d.ts +0 -1
  40. package/dist/clean-html.js +0 -1
  41. package/dist/cli.d.ts +0 -1
  42. package/dist/cli.js +10 -56
  43. package/dist/cloud-client.d.ts +0 -1
  44. package/dist/cloud-client.js +0 -1
  45. package/dist/create-logger.d.ts +0 -1
  46. package/dist/create-logger.js +0 -1
  47. package/dist/debugger-examples-types.d.ts +0 -1
  48. package/dist/debugger-examples-types.js +0 -1
  49. package/dist/debugger-examples.d.ts +0 -1
  50. package/dist/debugger-examples.js +0 -1
  51. package/dist/debugger.d.ts +0 -1
  52. package/dist/debugger.js +0 -1
  53. package/dist/diff-utils.d.ts +0 -1
  54. package/dist/diff-utils.js +0 -1
  55. package/dist/doctor.d.ts +0 -1
  56. package/dist/doctor.js +5 -7
  57. package/dist/editor-examples.d.ts +0 -1
  58. package/dist/editor-examples.js +0 -1
  59. package/dist/editor.d.ts +0 -1
  60. package/dist/editor.js +0 -1
  61. package/dist/env-compat.d.ts +0 -1
  62. package/dist/env-compat.js +0 -1
  63. package/dist/executor.d.ts +0 -1
  64. package/dist/executor.js +1 -2
  65. package/dist/extension/background.js +10 -6
  66. package/dist/extension/manifest.json +1 -1
  67. package/dist/extension/options.js +1 -1
  68. package/dist/extension/rrweb-recorder.js +1 -1
  69. package/dist/ghost-browser.d.ts +0 -1
  70. package/dist/ghost-browser.js +0 -1
  71. package/dist/ghost-cursor-controller.d.ts +0 -1
  72. package/dist/ghost-cursor-controller.js +0 -1
  73. package/dist/ghost-cursor.d.ts +0 -1
  74. package/dist/ghost-cursor.js +0 -1
  75. package/dist/htmlrewrite.d.ts +0 -1
  76. package/dist/htmlrewrite.js +0 -1
  77. package/dist/index.d.ts +0 -1
  78. package/dist/index.js +0 -1
  79. package/dist/kill-port.d.ts +0 -1
  80. package/dist/kill-port.js +0 -1
  81. package/dist/kitty-graphics.d.ts +0 -1
  82. package/dist/kitty-graphics.js +0 -1
  83. package/dist/mcp.d.ts +0 -1
  84. package/dist/mcp.js +0 -1
  85. package/dist/package-paths.d.ts +0 -1
  86. package/dist/package-paths.js +0 -1
  87. package/dist/page-markdown.d.ts +0 -1
  88. package/dist/page-markdown.js +0 -1
  89. package/dist/performance-examples.d.ts +0 -1
  90. package/dist/performance-examples.js +0 -1
  91. package/dist/playwright-import.d.ts +0 -1
  92. package/dist/playwright-import.js +0 -1
  93. package/dist/product-paths.d.ts +0 -1
  94. package/dist/product-paths.js +0 -1
  95. package/dist/protocol.d.ts +0 -1
  96. package/dist/protocol.js +0 -1
  97. package/dist/react-source.d.ts +0 -1
  98. package/dist/react-source.js +0 -1
  99. package/dist/readability.js +4 -4
  100. package/dist/relay-client.d.ts +0 -1
  101. package/dist/relay-client.js +0 -1
  102. package/dist/relay-state.d.ts +0 -1
  103. package/dist/relay-state.js +0 -1
  104. package/dist/replay-ai-index.d.ts +0 -1
  105. package/dist/replay-ai-index.js +0 -1
  106. package/dist/replay-eval.d.ts +0 -1
  107. package/dist/replay-eval.js +0 -1
  108. package/dist/replay-handoff.d.ts +0 -1
  109. package/dist/replay-handoff.js +0 -1
  110. package/dist/replay-workflow-compiler.d.ts +0 -1
  111. package/dist/replay-workflow-compiler.js +0 -1
  112. package/dist/rrweb-recording-relay.d.ts +0 -1
  113. package/dist/rrweb-recording-relay.js +0 -1
  114. package/dist/rrweb-recording.d.ts +0 -1
  115. package/dist/rrweb-recording.js +0 -1
  116. package/dist/scoped-fs.d.ts +0 -1
  117. package/dist/scoped-fs.js +0 -1
  118. package/dist/selector-generator.js +2 -2
  119. package/dist/start-relay-server.d.ts +0 -1
  120. package/dist/start-relay-server.js +0 -1
  121. package/dist/styles-examples.d.ts +0 -1
  122. package/dist/styles-examples.js +0 -1
  123. package/dist/styles.d.ts +0 -1
  124. package/dist/styles.js +0 -1
  125. package/dist/tabwright-agent-skill.d.ts +0 -1
  126. package/dist/tabwright-agent-skill.js +0 -1
  127. package/dist/test-declarations.d.ts +0 -1
  128. package/dist/test-declarations.js +0 -1
  129. package/dist/utils.d.ts +0 -1
  130. package/dist/utils.js +2 -2
  131. package/dist/wait-for-page-load.d.ts +0 -1
  132. package/dist/wait-for-page-load.js +0 -1
  133. package/dist/workflow-capability.d.ts +0 -1
  134. package/dist/workflow-capability.js +0 -1
  135. package/package.json +8 -4
  136. package/readme.md +43 -0
  137. package/src/skill.md +5 -2
  138. package/dist/aria-snapshot.d.ts.map +0 -1
  139. package/dist/aria-snapshot.js.map +0 -1
  140. package/dist/aria-snapshot.test.d.ts +0 -2
  141. package/dist/aria-snapshot.test.d.ts.map +0 -1
  142. package/dist/aria-snapshot.test.js +0 -270
  143. package/dist/aria-snapshot.test.js.map +0 -1
  144. package/dist/aria-snapshot.unit.test.d.ts +0 -2
  145. package/dist/aria-snapshot.unit.test.d.ts.map +0 -1
  146. package/dist/aria-snapshot.unit.test.js +0 -542
  147. package/dist/aria-snapshot.unit.test.js.map +0 -1
  148. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts.map +0 -1
  149. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js.map +0 -1
  150. package/dist/browser-config.d.ts.map +0 -1
  151. package/dist/browser-config.js.map +0 -1
  152. package/dist/browser-install.d.ts.map +0 -1
  153. package/dist/browser-install.js.map +0 -1
  154. package/dist/browser-launch.d.ts.map +0 -1
  155. package/dist/browser-launch.js.map +0 -1
  156. package/dist/builtin-capabilities.d.ts +0 -28
  157. package/dist/builtin-capabilities.d.ts.map +0 -1
  158. package/dist/builtin-capabilities.js +0 -2673
  159. package/dist/builtin-capabilities.js.map +0 -1
  160. package/dist/capability-agent-skill.d.ts.map +0 -1
  161. package/dist/capability-agent-skill.js.map +0 -1
  162. package/dist/capability-auth-state.d.ts.map +0 -1
  163. package/dist/capability-auth-state.js.map +0 -1
  164. package/dist/capability-auth.d.ts.map +0 -1
  165. package/dist/capability-auth.js.map +0 -1
  166. package/dist/capability-cli-confirmation.test.d.ts +0 -2
  167. package/dist/capability-cli-confirmation.test.d.ts.map +0 -1
  168. package/dist/capability-cli-confirmation.test.js +0 -79
  169. package/dist/capability-cli-confirmation.test.js.map +0 -1
  170. package/dist/capability-options.d.ts.map +0 -1
  171. package/dist/capability-options.js.map +0 -1
  172. package/dist/capability-options.test.d.ts +0 -2
  173. package/dist/capability-options.test.d.ts.map +0 -1
  174. package/dist/capability-options.test.js +0 -81
  175. package/dist/capability-options.test.js.map +0 -1
  176. package/dist/capability-package.d.ts.map +0 -1
  177. package/dist/capability-package.js.map +0 -1
  178. package/dist/capability-package.test.d.ts +0 -2
  179. package/dist/capability-package.test.d.ts.map +0 -1
  180. package/dist/capability-package.test.js +0 -179
  181. package/dist/capability-package.test.js.map +0 -1
  182. package/dist/capability-registry.d.ts.map +0 -1
  183. package/dist/capability-registry.js.map +0 -1
  184. package/dist/capability-registry.test.d.ts +0 -2
  185. package/dist/capability-registry.test.d.ts.map +0 -1
  186. package/dist/capability-registry.test.js +0 -1683
  187. package/dist/capability-registry.test.js.map +0 -1
  188. package/dist/capability-runner.d.ts.map +0 -1
  189. package/dist/capability-runner.js.map +0 -1
  190. package/dist/capability-search-relevance.test.d.ts +0 -2
  191. package/dist/capability-search-relevance.test.d.ts.map +0 -1
  192. package/dist/capability-search-relevance.test.js +0 -67
  193. package/dist/capability-search-relevance.test.js.map +0 -1
  194. package/dist/capability-studio.d.ts.map +0 -1
  195. package/dist/capability-studio.js.map +0 -1
  196. package/dist/capability-studio.test.d.ts +0 -2
  197. package/dist/capability-studio.test.d.ts.map +0 -1
  198. package/dist/capability-studio.test.js +0 -41
  199. package/dist/capability-studio.test.js.map +0 -1
  200. package/dist/cdp-log.d.ts.map +0 -1
  201. package/dist/cdp-log.js.map +0 -1
  202. package/dist/cdp-log.test.d.ts +0 -2
  203. package/dist/cdp-log.test.d.ts.map +0 -1
  204. package/dist/cdp-log.test.js +0 -109
  205. package/dist/cdp-log.test.js.map +0 -1
  206. package/dist/cdp-relay.d.ts.map +0 -1
  207. package/dist/cdp-relay.js.map +0 -1
  208. package/dist/cdp-session.d.ts.map +0 -1
  209. package/dist/cdp-session.js.map +0 -1
  210. package/dist/cdp-types.d.ts.map +0 -1
  211. package/dist/cdp-types.js.map +0 -1
  212. package/dist/channel-owner-inspect.test.d.ts +0 -2
  213. package/dist/channel-owner-inspect.test.d.ts.map +0 -1
  214. package/dist/channel-owner-inspect.test.js +0 -75
  215. package/dist/channel-owner-inspect.test.js.map +0 -1
  216. package/dist/chrome-discovery.d.ts.map +0 -1
  217. package/dist/chrome-discovery.js.map +0 -1
  218. package/dist/chrome-discovery.test.d.ts +0 -2
  219. package/dist/chrome-discovery.test.d.ts.map +0 -1
  220. package/dist/chrome-discovery.test.js +0 -41
  221. package/dist/chrome-discovery.test.js.map +0 -1
  222. package/dist/clean-html.d.ts.map +0 -1
  223. package/dist/clean-html.js.map +0 -1
  224. package/dist/cli-help.test.d.ts +0 -2
  225. package/dist/cli-help.test.d.ts.map +0 -1
  226. package/dist/cli-help.test.js +0 -98
  227. package/dist/cli-help.test.js.map +0 -1
  228. package/dist/cli.d.ts.map +0 -1
  229. package/dist/cli.js.map +0 -1
  230. package/dist/cloud-client.d.ts.map +0 -1
  231. package/dist/cloud-client.js.map +0 -1
  232. package/dist/create-logger.d.ts.map +0 -1
  233. package/dist/create-logger.js.map +0 -1
  234. package/dist/debugger-examples-types.d.ts.map +0 -1
  235. package/dist/debugger-examples-types.js.map +0 -1
  236. package/dist/debugger-examples.d.ts.map +0 -1
  237. package/dist/debugger-examples.js.map +0 -1
  238. package/dist/debugger.d.ts.map +0 -1
  239. package/dist/debugger.js.map +0 -1
  240. package/dist/diff-utils.d.ts.map +0 -1
  241. package/dist/diff-utils.js.map +0 -1
  242. package/dist/diff-utils.test.d.ts +0 -2
  243. package/dist/diff-utils.test.d.ts.map +0 -1
  244. package/dist/diff-utils.test.js +0 -137
  245. package/dist/diff-utils.test.js.map +0 -1
  246. package/dist/doctor.d.ts.map +0 -1
  247. package/dist/doctor.js.map +0 -1
  248. package/dist/doctor.test.d.ts +0 -2
  249. package/dist/doctor.test.d.ts.map +0 -1
  250. package/dist/doctor.test.js +0 -208
  251. package/dist/doctor.test.js.map +0 -1
  252. package/dist/editor-examples.d.ts.map +0 -1
  253. package/dist/editor-examples.js.map +0 -1
  254. package/dist/editor.d.ts.map +0 -1
  255. package/dist/editor.js.map +0 -1
  256. package/dist/env-compat.d.ts.map +0 -1
  257. package/dist/env-compat.js.map +0 -1
  258. package/dist/executor.d.ts.map +0 -1
  259. package/dist/executor.js.map +0 -1
  260. package/dist/executor.unit.test.d.ts +0 -2
  261. package/dist/executor.unit.test.d.ts.map +0 -1
  262. package/dist/executor.unit.test.js +0 -143
  263. package/dist/executor.unit.test.js.map +0 -1
  264. package/dist/extension-connection.test.d.ts +0 -2
  265. package/dist/extension-connection.test.d.ts.map +0 -1
  266. package/dist/extension-connection.test.js +0 -708
  267. package/dist/extension-connection.test.js.map +0 -1
  268. package/dist/extension-icon-warning.test.d.ts +0 -2
  269. package/dist/extension-icon-warning.test.d.ts.map +0 -1
  270. package/dist/extension-icon-warning.test.js +0 -33
  271. package/dist/extension-icon-warning.test.js.map +0 -1
  272. package/dist/ghost-browser.d.ts.map +0 -1
  273. package/dist/ghost-browser.js.map +0 -1
  274. package/dist/ghost-cursor-controller.d.ts.map +0 -1
  275. package/dist/ghost-cursor-controller.js.map +0 -1
  276. package/dist/ghost-cursor.d.ts.map +0 -1
  277. package/dist/ghost-cursor.js.map +0 -1
  278. package/dist/htmlrewrite.d.ts.map +0 -1
  279. package/dist/htmlrewrite.js.map +0 -1
  280. package/dist/htmlrewrite.test.d.ts +0 -2
  281. package/dist/htmlrewrite.test.d.ts.map +0 -1
  282. package/dist/htmlrewrite.test.js +0 -7975
  283. package/dist/htmlrewrite.test.js.map +0 -1
  284. package/dist/index.d.ts.map +0 -1
  285. package/dist/index.js.map +0 -1
  286. package/dist/kill-port.d.ts.map +0 -1
  287. package/dist/kill-port.js.map +0 -1
  288. package/dist/kitty-graphics.d.ts.map +0 -1
  289. package/dist/kitty-graphics.js.map +0 -1
  290. package/dist/kitty-graphics.test.d.ts +0 -2
  291. package/dist/kitty-graphics.test.d.ts.map +0 -1
  292. package/dist/kitty-graphics.test.js +0 -125
  293. package/dist/kitty-graphics.test.js.map +0 -1
  294. package/dist/locator-selector.test.d.ts +0 -2
  295. package/dist/locator-selector.test.d.ts.map +0 -1
  296. package/dist/locator-selector.test.js +0 -98
  297. package/dist/locator-selector.test.js.map +0 -1
  298. package/dist/mcp-client.d.ts +0 -20
  299. package/dist/mcp-client.d.ts.map +0 -1
  300. package/dist/mcp-client.js +0 -56
  301. package/dist/mcp-client.js.map +0 -1
  302. package/dist/mcp.d.ts.map +0 -1
  303. package/dist/mcp.js.map +0 -1
  304. package/dist/on-mouse-action.test.d.ts +0 -2
  305. package/dist/on-mouse-action.test.d.ts.map +0 -1
  306. package/dist/on-mouse-action.test.js +0 -180
  307. package/dist/on-mouse-action.test.js.map +0 -1
  308. package/dist/options-page.test.d.ts +0 -2
  309. package/dist/options-page.test.d.ts.map +0 -1
  310. package/dist/options-page.test.js +0 -773
  311. package/dist/options-page.test.js.map +0 -1
  312. package/dist/package-paths.d.ts.map +0 -1
  313. package/dist/package-paths.js.map +0 -1
  314. package/dist/page-markdown.d.ts.map +0 -1
  315. package/dist/page-markdown.js.map +0 -1
  316. package/dist/performance-examples.d.ts.map +0 -1
  317. package/dist/performance-examples.js.map +0 -1
  318. package/dist/playwright-import.d.ts.map +0 -1
  319. package/dist/playwright-import.js.map +0 -1
  320. package/dist/popup-relocation.test.d.ts +0 -7
  321. package/dist/popup-relocation.test.d.ts.map +0 -1
  322. package/dist/popup-relocation.test.js +0 -139
  323. package/dist/popup-relocation.test.js.map +0 -1
  324. package/dist/product-paths.d.ts.map +0 -1
  325. package/dist/product-paths.js.map +0 -1
  326. package/dist/product-paths.test.d.ts +0 -2
  327. package/dist/product-paths.test.d.ts.map +0 -1
  328. package/dist/product-paths.test.js +0 -39
  329. package/dist/product-paths.test.js.map +0 -1
  330. package/dist/protocol.d.ts.map +0 -1
  331. package/dist/protocol.js.map +0 -1
  332. package/dist/protocol.test.d.ts +0 -2
  333. package/dist/protocol.test.d.ts.map +0 -1
  334. package/dist/protocol.test.js +0 -31
  335. package/dist/protocol.test.js.map +0 -1
  336. package/dist/react-source.d.ts.map +0 -1
  337. package/dist/react-source.js.map +0 -1
  338. package/dist/relay-client.d.ts.map +0 -1
  339. package/dist/relay-client.js.map +0 -1
  340. package/dist/relay-client.test.d.ts +0 -2
  341. package/dist/relay-client.test.d.ts.map +0 -1
  342. package/dist/relay-client.test.js +0 -305
  343. package/dist/relay-client.test.js.map +0 -1
  344. package/dist/relay-core.test.d.ts +0 -2
  345. package/dist/relay-core.test.d.ts.map +0 -1
  346. package/dist/relay-core.test.js +0 -1427
  347. package/dist/relay-core.test.js.map +0 -1
  348. package/dist/relay-navigation.test.d.ts +0 -2
  349. package/dist/relay-navigation.test.d.ts.map +0 -1
  350. package/dist/relay-navigation.test.js +0 -661
  351. package/dist/relay-navigation.test.js.map +0 -1
  352. package/dist/relay-session.test.d.ts +0 -2
  353. package/dist/relay-session.test.d.ts.map +0 -1
  354. package/dist/relay-session.test.js +0 -1121
  355. package/dist/relay-session.test.js.map +0 -1
  356. package/dist/relay-state.d.ts.map +0 -1
  357. package/dist/relay-state.js.map +0 -1
  358. package/dist/relay-state.test.d.ts +0 -2
  359. package/dist/relay-state.test.d.ts.map +0 -1
  360. package/dist/relay-state.test.js +0 -594
  361. package/dist/relay-state.test.js.map +0 -1
  362. package/dist/replay-ai-index.d.ts.map +0 -1
  363. package/dist/replay-ai-index.js.map +0 -1
  364. package/dist/replay-ai-index.test.d.ts +0 -2
  365. package/dist/replay-ai-index.test.d.ts.map +0 -1
  366. package/dist/replay-ai-index.test.js +0 -255
  367. package/dist/replay-ai-index.test.js.map +0 -1
  368. package/dist/replay-cli.test.d.ts +0 -2
  369. package/dist/replay-cli.test.d.ts.map +0 -1
  370. package/dist/replay-cli.test.js +0 -275
  371. package/dist/replay-cli.test.js.map +0 -1
  372. package/dist/replay-eval.d.ts.map +0 -1
  373. package/dist/replay-eval.js.map +0 -1
  374. package/dist/replay-handoff.d.ts.map +0 -1
  375. package/dist/replay-handoff.js.map +0 -1
  376. package/dist/replay-handoff.test.d.ts +0 -2
  377. package/dist/replay-handoff.test.d.ts.map +0 -1
  378. package/dist/replay-handoff.test.js +0 -123
  379. package/dist/replay-handoff.test.js.map +0 -1
  380. package/dist/replay-workflow-compiler.d.ts.map +0 -1
  381. package/dist/replay-workflow-compiler.js.map +0 -1
  382. package/dist/replay-workflow-compiler.test.d.ts +0 -2
  383. package/dist/replay-workflow-compiler.test.d.ts.map +0 -1
  384. package/dist/replay-workflow-compiler.test.js +0 -223
  385. package/dist/replay-workflow-compiler.test.js.map +0 -1
  386. package/dist/rrweb-recording-relay.d.ts.map +0 -1
  387. package/dist/rrweb-recording-relay.js.map +0 -1
  388. package/dist/rrweb-recording-relay.test.d.ts +0 -2
  389. package/dist/rrweb-recording-relay.test.d.ts.map +0 -1
  390. package/dist/rrweb-recording-relay.test.js +0 -85
  391. package/dist/rrweb-recording-relay.test.js.map +0 -1
  392. package/dist/rrweb-recording.d.ts.map +0 -1
  393. package/dist/rrweb-recording.js.map +0 -1
  394. package/dist/scoped-fs.d.ts.map +0 -1
  395. package/dist/scoped-fs.js.map +0 -1
  396. package/dist/scoped-fs.test.d.ts +0 -5
  397. package/dist/scoped-fs.test.d.ts.map +0 -1
  398. package/dist/scoped-fs.test.js +0 -73
  399. package/dist/scoped-fs.test.js.map +0 -1
  400. package/dist/skill-stub.test.d.ts +0 -2
  401. package/dist/skill-stub.test.d.ts.map +0 -1
  402. package/dist/skill-stub.test.js +0 -22
  403. package/dist/skill-stub.test.js.map +0 -1
  404. package/dist/snapshot-tools.test.d.ts +0 -2
  405. package/dist/snapshot-tools.test.d.ts.map +0 -1
  406. package/dist/snapshot-tools.test.js +0 -856
  407. package/dist/snapshot-tools.test.js.map +0 -1
  408. package/dist/start-relay-server.d.ts.map +0 -1
  409. package/dist/start-relay-server.js.map +0 -1
  410. package/dist/styles-examples.d.ts.map +0 -1
  411. package/dist/styles-examples.js.map +0 -1
  412. package/dist/styles.d.ts.map +0 -1
  413. package/dist/styles.js.map +0 -1
  414. package/dist/tabwright-agent-skill.d.ts.map +0 -1
  415. package/dist/tabwright-agent-skill.js.map +0 -1
  416. package/dist/tabwright-agent-skill.test.d.ts +0 -2
  417. package/dist/tabwright-agent-skill.test.d.ts.map +0 -1
  418. package/dist/tabwright-agent-skill.test.js +0 -51
  419. package/dist/tabwright-agent-skill.test.js.map +0 -1
  420. package/dist/test-declarations.d.ts.map +0 -1
  421. package/dist/test-declarations.js.map +0 -1
  422. package/dist/test-utils.d.ts +0 -69
  423. package/dist/test-utils.d.ts.map +0 -1
  424. package/dist/test-utils.js +0 -448
  425. package/dist/test-utils.js.map +0 -1
  426. package/dist/test-utils.test.d.ts +0 -2
  427. package/dist/test-utils.test.d.ts.map +0 -1
  428. package/dist/test-utils.test.js +0 -55
  429. package/dist/test-utils.test.js.map +0 -1
  430. package/dist/utils.d.ts.map +0 -1
  431. package/dist/utils.js.map +0 -1
  432. package/dist/wait-for-page-load.d.ts.map +0 -1
  433. package/dist/wait-for-page-load.js.map +0 -1
  434. package/dist/workflow-capability.d.ts.map +0 -1
  435. package/dist/workflow-capability.js.map +0 -1
  436. package/dist/workflow-script-flow.test.d.ts +0 -2
  437. package/dist/workflow-script-flow.test.d.ts.map +0 -1
  438. package/dist/workflow-script-flow.test.js +0 -285
  439. package/dist/workflow-script-flow.test.js.map +0 -1
  440. package/src/__snapshots__/x.com.processed.html +0 -1003
  441. package/src/__snapshots__/x.com.processed.withStyles.html +0 -2720
  442. package/src/a11y-client.ts +0 -241
  443. package/src/agent-skills/conan-config/SKILL.md +0 -141
  444. package/src/agent-skills/conan-config/agents/openai.yaml +0 -4
  445. package/src/aria-snapshot.test.ts +0 -311
  446. package/src/aria-snapshot.ts +0 -1681
  447. package/src/aria-snapshot.unit.test.ts +0 -615
  448. package/src/aria-snapshots/github-interactive.txt +0 -193
  449. package/src/aria-snapshots/github-raw.txt +0 -309
  450. package/src/aria-snapshots/hackernews-interactive.txt +0 -477
  451. package/src/aria-snapshots/hackernews-raw.txt +0 -428
  452. package/src/aria-snapshots/prosemirror-interactive.txt +0 -66
  453. package/src/aria-snapshots/prosemirror-raw.txt +0 -145
  454. package/src/assets/aria-labels-hacker-news.png +0 -0
  455. package/src/assets/aria-labels-old-reddit.png +0 -0
  456. package/src/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.ts +0 -5
  457. package/src/assets/cursors/screen-studio/pointer-macos-tahoe.svg +0 -18
  458. package/src/assets/x.com.html +0 -32946
  459. package/src/browser-config.ts +0 -179
  460. package/src/browser-install.ts +0 -284
  461. package/src/browser-launch.ts +0 -75
  462. package/src/builtin-capabilities.ts +0 -2765
  463. package/src/capability-agent-skill.ts +0 -305
  464. package/src/capability-auth-state.ts +0 -197
  465. package/src/capability-auth.ts +0 -249
  466. package/src/capability-cli-confirmation.test.ts +0 -90
  467. package/src/capability-options.test.ts +0 -89
  468. package/src/capability-options.ts +0 -57
  469. package/src/capability-package.test.ts +0 -204
  470. package/src/capability-package.ts +0 -555
  471. package/src/capability-registry.test.ts +0 -1905
  472. package/src/capability-registry.ts +0 -1234
  473. package/src/capability-runner.ts +0 -801
  474. package/src/capability-search-relevance.test.ts +0 -73
  475. package/src/capability-studio.test.ts +0 -45
  476. package/src/capability-studio.ts +0 -641
  477. package/src/cdp-log.test.ts +0 -131
  478. package/src/cdp-log.ts +0 -112
  479. package/src/cdp-relay.ts +0 -2944
  480. package/src/cdp-session.ts +0 -77
  481. package/src/cdp-types.ts +0 -158
  482. package/src/channel-owner-inspect.test.ts +0 -94
  483. package/src/chrome-discovery.test.ts +0 -50
  484. package/src/chrome-discovery.ts +0 -220
  485. package/src/clean-html.ts +0 -141
  486. package/src/cli-help.test.ts +0 -123
  487. package/src/cli.ts +0 -3181
  488. package/src/cloud-client.ts +0 -179
  489. package/src/create-logger.ts +0 -38
  490. package/src/debugger-examples-types.ts +0 -16
  491. package/src/debugger-examples.ts +0 -66
  492. package/src/debugger.ts +0 -708
  493. package/src/diff-utils.test.ts +0 -152
  494. package/src/diff-utils.ts +0 -70
  495. package/src/doctor.test.ts +0 -244
  496. package/src/doctor.ts +0 -321
  497. package/src/editor-examples.ts +0 -158
  498. package/src/editor.ts +0 -426
  499. package/src/env-compat.ts +0 -28
  500. package/src/executor.ts +0 -1824
  501. package/src/executor.unit.test.ts +0 -168
  502. package/src/extension-connection.test.ts +0 -855
  503. package/src/extension-icon-warning.test.ts +0 -45
  504. package/src/ghost-browser.ts +0 -149
  505. package/src/ghost-cursor-client.ts +0 -494
  506. package/src/ghost-cursor-controller.ts +0 -129
  507. package/src/ghost-cursor.ts +0 -123
  508. package/src/htmlrewrite.test.ts +0 -8008
  509. package/src/htmlrewrite.ts +0 -390
  510. package/src/index.ts +0 -53
  511. package/src/kill-port.ts +0 -219
  512. package/src/kitty-graphics.test.ts +0 -139
  513. package/src/kitty-graphics.ts +0 -79
  514. package/src/locator-selector.test.ts +0 -119
  515. package/src/mcp-client.ts +0 -78
  516. package/src/mcp.ts +0 -629
  517. package/src/on-mouse-action.test.ts +0 -226
  518. package/src/options-page.test.ts +0 -839
  519. package/src/package-paths.ts +0 -38
  520. package/src/page-markdown.ts +0 -240
  521. package/src/performance-examples.ts +0 -186
  522. package/src/playwright-import.ts +0 -59
  523. package/src/popup-relocation.test.ts +0 -163
  524. package/src/product-paths.test.ts +0 -47
  525. package/src/product-paths.ts +0 -28
  526. package/src/protocol.test.ts +0 -52
  527. package/src/protocol.ts +0 -351
  528. package/src/react-source.ts +0 -379
  529. package/src/relay-client.test.ts +0 -375
  530. package/src/relay-client.ts +0 -572
  531. package/src/relay-core.test.ts +0 -1603
  532. package/src/relay-navigation.test.ts +0 -790
  533. package/src/relay-session.test.ts +0 -1375
  534. package/src/relay-state.test.ts +0 -729
  535. package/src/relay-state.ts +0 -561
  536. package/src/replay-ai-index.test.ts +0 -278
  537. package/src/replay-ai-index.ts +0 -872
  538. package/src/replay-cli.test.ts +0 -325
  539. package/src/replay-eval.ts +0 -1039
  540. package/src/replay-handoff.test.ts +0 -163
  541. package/src/replay-handoff.ts +0 -109
  542. package/src/replay-workflow-compiler.test.ts +0 -250
  543. package/src/replay-workflow-compiler.ts +0 -700
  544. package/src/resource.md +0 -409
  545. package/src/rrweb-recording-relay.test.ts +0 -99
  546. package/src/rrweb-recording-relay.ts +0 -400
  547. package/src/rrweb-recording.ts +0 -322
  548. package/src/scoped-fs.test.ts +0 -80
  549. package/src/scoped-fs.ts +0 -420
  550. package/src/skill-stub.test.ts +0 -24
  551. package/src/snapshot-tools.test.ts +0 -1017
  552. package/src/snapshots/hacker-news-accessibility-full.md +0 -81
  553. package/src/snapshots/hacker-news-accessibility-interactive.md +0 -43
  554. package/src/snapshots/page-markdown-output.txt +0 -16
  555. package/src/snapshots/shadcn-ui-accessibility-full.md +0 -201
  556. package/src/snapshots/shadcn-ui-accessibility-interactive.md +0 -109
  557. package/src/start-relay-server.ts +0 -69
  558. package/src/styles-examples.ts +0 -84
  559. package/src/styles.ts +0 -343
  560. package/src/tabwright-agent-skill.test.ts +0 -61
  561. package/src/tabwright-agent-skill.ts +0 -105
  562. package/src/test-declarations.ts +0 -13
  563. package/src/test-utils.test.ts +0 -70
  564. package/src/test-utils.ts +0 -566
  565. package/src/utils.ts +0 -78
  566. package/src/wait-for-page-load.ts +0 -198
  567. package/src/workflow-capability.ts +0 -417
  568. 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
- }