tabwright 1.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 (599) hide show
  1. package/LICENSE +21 -0
  2. package/bin.js +4 -0
  3. package/dist/a11y-client.js +204 -0
  4. package/dist/agent-skills/tabwright/SKILL.md +119 -0
  5. package/dist/aria-snapshot.d.ts +262 -0
  6. package/dist/aria-snapshot.d.ts.map +1 -0
  7. package/dist/aria-snapshot.js +1256 -0
  8. package/dist/aria-snapshot.js.map +1 -0
  9. package/dist/aria-snapshot.test.d.ts +2 -0
  10. package/dist/aria-snapshot.test.d.ts.map +1 -0
  11. package/dist/aria-snapshot.test.js +270 -0
  12. package/dist/aria-snapshot.test.js.map +1 -0
  13. package/dist/aria-snapshot.unit.test.d.ts +2 -0
  14. package/dist/aria-snapshot.unit.test.d.ts.map +1 -0
  15. package/dist/aria-snapshot.unit.test.js +542 -0
  16. package/dist/aria-snapshot.unit.test.js.map +1 -0
  17. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts +5 -0
  18. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts.map +1 -0
  19. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js +5 -0
  20. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js.map +1 -0
  21. package/dist/bippy.js +894 -0
  22. package/dist/browser-config.d.ts +13 -0
  23. package/dist/browser-config.d.ts.map +1 -0
  24. package/dist/browser-config.js +126 -0
  25. package/dist/browser-config.js.map +1 -0
  26. package/dist/browser-install.d.ts +16 -0
  27. package/dist/browser-install.d.ts.map +1 -0
  28. package/dist/browser-install.js +238 -0
  29. package/dist/browser-install.js.map +1 -0
  30. package/dist/browser-launch.d.ts +17 -0
  31. package/dist/browser-launch.d.ts.map +1 -0
  32. package/dist/browser-launch.js +44 -0
  33. package/dist/browser-launch.js.map +1 -0
  34. package/dist/builtin-capabilities.d.ts +28 -0
  35. package/dist/builtin-capabilities.d.ts.map +1 -0
  36. package/dist/builtin-capabilities.js +2673 -0
  37. package/dist/builtin-capabilities.js.map +1 -0
  38. package/dist/capability-agent-skill.d.ts +60 -0
  39. package/dist/capability-agent-skill.d.ts.map +1 -0
  40. package/dist/capability-agent-skill.js +225 -0
  41. package/dist/capability-agent-skill.js.map +1 -0
  42. package/dist/capability-auth-state.d.ts +34 -0
  43. package/dist/capability-auth-state.d.ts.map +1 -0
  44. package/dist/capability-auth-state.js +157 -0
  45. package/dist/capability-auth-state.js.map +1 -0
  46. package/dist/capability-auth.d.ts +36 -0
  47. package/dist/capability-auth.d.ts.map +1 -0
  48. package/dist/capability-auth.js +198 -0
  49. package/dist/capability-auth.js.map +1 -0
  50. package/dist/capability-cli-confirmation.test.d.ts +2 -0
  51. package/dist/capability-cli-confirmation.test.d.ts.map +1 -0
  52. package/dist/capability-cli-confirmation.test.js +79 -0
  53. package/dist/capability-cli-confirmation.test.js.map +1 -0
  54. package/dist/capability-options.d.ts +20 -0
  55. package/dist/capability-options.d.ts.map +1 -0
  56. package/dist/capability-options.js +31 -0
  57. package/dist/capability-options.js.map +1 -0
  58. package/dist/capability-options.test.d.ts +2 -0
  59. package/dist/capability-options.test.d.ts.map +1 -0
  60. package/dist/capability-options.test.js +81 -0
  61. package/dist/capability-options.test.js.map +1 -0
  62. package/dist/capability-package.d.ts +27 -0
  63. package/dist/capability-package.d.ts.map +1 -0
  64. package/dist/capability-package.js +444 -0
  65. package/dist/capability-package.js.map +1 -0
  66. package/dist/capability-package.test.d.ts +2 -0
  67. package/dist/capability-package.test.d.ts.map +1 -0
  68. package/dist/capability-package.test.js +179 -0
  69. package/dist/capability-package.test.js.map +1 -0
  70. package/dist/capability-registry.d.ts +262 -0
  71. package/dist/capability-registry.d.ts.map +1 -0
  72. package/dist/capability-registry.js +931 -0
  73. package/dist/capability-registry.js.map +1 -0
  74. package/dist/capability-registry.test.d.ts +2 -0
  75. package/dist/capability-registry.test.d.ts.map +1 -0
  76. package/dist/capability-registry.test.js +1683 -0
  77. package/dist/capability-registry.test.js.map +1 -0
  78. package/dist/capability-runner.d.ts +99 -0
  79. package/dist/capability-runner.d.ts.map +1 -0
  80. package/dist/capability-runner.js +608 -0
  81. package/dist/capability-runner.js.map +1 -0
  82. package/dist/capability-search-relevance.test.d.ts +2 -0
  83. package/dist/capability-search-relevance.test.d.ts.map +1 -0
  84. package/dist/capability-search-relevance.test.js +67 -0
  85. package/dist/capability-search-relevance.test.js.map +1 -0
  86. package/dist/capability-studio.d.ts +11 -0
  87. package/dist/capability-studio.d.ts.map +1 -0
  88. package/dist/capability-studio.js +593 -0
  89. package/dist/capability-studio.js.map +1 -0
  90. package/dist/capability-studio.test.d.ts +2 -0
  91. package/dist/capability-studio.test.d.ts.map +1 -0
  92. package/dist/capability-studio.test.js +41 -0
  93. package/dist/capability-studio.test.js.map +1 -0
  94. package/dist/cdp-log.d.ts +19 -0
  95. package/dist/cdp-log.d.ts.map +1 -0
  96. package/dist/cdp-log.js +83 -0
  97. package/dist/cdp-log.js.map +1 -0
  98. package/dist/cdp-log.test.d.ts +2 -0
  99. package/dist/cdp-log.test.d.ts.map +1 -0
  100. package/dist/cdp-log.test.js +109 -0
  101. package/dist/cdp-log.test.js.map +1 -0
  102. package/dist/cdp-relay.d.ts +19 -0
  103. package/dist/cdp-relay.d.ts.map +1 -0
  104. package/dist/cdp-relay.js +2375 -0
  105. package/dist/cdp-relay.js.map +1 -0
  106. package/dist/cdp-session.d.ts +37 -0
  107. package/dist/cdp-session.d.ts.map +1 -0
  108. package/dist/cdp-session.js +36 -0
  109. package/dist/cdp-session.js.map +1 -0
  110. package/dist/cdp-types.d.ts +65 -0
  111. package/dist/cdp-types.d.ts.map +1 -0
  112. package/dist/cdp-types.js +91 -0
  113. package/dist/cdp-types.js.map +1 -0
  114. package/dist/channel-owner-inspect.test.d.ts +2 -0
  115. package/dist/channel-owner-inspect.test.d.ts.map +1 -0
  116. package/dist/channel-owner-inspect.test.js +75 -0
  117. package/dist/channel-owner-inspect.test.js.map +1 -0
  118. package/dist/chrome-discovery.d.ts +65 -0
  119. package/dist/chrome-discovery.d.ts.map +1 -0
  120. package/dist/chrome-discovery.js +173 -0
  121. package/dist/chrome-discovery.js.map +1 -0
  122. package/dist/chrome-discovery.test.d.ts +2 -0
  123. package/dist/chrome-discovery.test.d.ts.map +1 -0
  124. package/dist/chrome-discovery.test.js +41 -0
  125. package/dist/chrome-discovery.test.js.map +1 -0
  126. package/dist/clean-html.d.ts +11 -0
  127. package/dist/clean-html.d.ts.map +1 -0
  128. package/dist/clean-html.js +106 -0
  129. package/dist/clean-html.js.map +1 -0
  130. package/dist/cli-help.test.d.ts +2 -0
  131. package/dist/cli-help.test.d.ts.map +1 -0
  132. package/dist/cli-help.test.js +98 -0
  133. package/dist/cli-help.test.js.map +1 -0
  134. package/dist/cli.d.ts +3 -0
  135. package/dist/cli.d.ts.map +1 -0
  136. package/dist/cli.js +2709 -0
  137. package/dist/cli.js.map +1 -0
  138. package/dist/cloud-client.d.ts +56 -0
  139. package/dist/cloud-client.d.ts.map +1 -0
  140. package/dist/cloud-client.js +127 -0
  141. package/dist/cloud-client.js.map +1 -0
  142. package/dist/create-logger.d.ts +9 -0
  143. package/dist/create-logger.d.ts.map +1 -0
  144. package/dist/create-logger.js +27 -0
  145. package/dist/create-logger.js.map +1 -0
  146. package/dist/debugger-api.md +458 -0
  147. package/dist/debugger-examples-types.d.ts +24 -0
  148. package/dist/debugger-examples-types.d.ts.map +1 -0
  149. package/dist/debugger-examples-types.js +2 -0
  150. package/dist/debugger-examples-types.js.map +1 -0
  151. package/dist/debugger-examples.d.ts +6 -0
  152. package/dist/debugger-examples.d.ts.map +1 -0
  153. package/dist/debugger-examples.js +53 -0
  154. package/dist/debugger-examples.js.map +1 -0
  155. package/dist/debugger.d.ts +381 -0
  156. package/dist/debugger.d.ts.map +1 -0
  157. package/dist/debugger.js +630 -0
  158. package/dist/debugger.js.map +1 -0
  159. package/dist/diff-utils.d.ts +20 -0
  160. package/dist/diff-utils.d.ts.map +1 -0
  161. package/dist/diff-utils.js +50 -0
  162. package/dist/diff-utils.js.map +1 -0
  163. package/dist/diff-utils.test.d.ts +2 -0
  164. package/dist/diff-utils.test.d.ts.map +1 -0
  165. package/dist/diff-utils.test.js +137 -0
  166. package/dist/diff-utils.test.js.map +1 -0
  167. package/dist/doctor.d.ts +44 -0
  168. package/dist/doctor.d.ts.map +1 -0
  169. package/dist/doctor.js +246 -0
  170. package/dist/doctor.js.map +1 -0
  171. package/dist/doctor.test.d.ts +2 -0
  172. package/dist/doctor.test.d.ts.map +1 -0
  173. package/dist/doctor.test.js +208 -0
  174. package/dist/doctor.test.js.map +1 -0
  175. package/dist/editor-api.md +374 -0
  176. package/dist/editor-examples.d.ts +11 -0
  177. package/dist/editor-examples.d.ts.map +1 -0
  178. package/dist/editor-examples.js +124 -0
  179. package/dist/editor-examples.js.map +1 -0
  180. package/dist/editor.d.ts +203 -0
  181. package/dist/editor.d.ts.map +1 -0
  182. package/dist/editor.js +363 -0
  183. package/dist/editor.js.map +1 -0
  184. package/dist/env-compat.d.ts +2 -0
  185. package/dist/env-compat.d.ts.map +1 -0
  186. package/dist/env-compat.js +27 -0
  187. package/dist/env-compat.js.map +1 -0
  188. package/dist/executor.d.ts +229 -0
  189. package/dist/executor.d.ts.map +1 -0
  190. package/dist/executor.js +1465 -0
  191. package/dist/executor.js.map +1 -0
  192. package/dist/executor.unit.test.d.ts +2 -0
  193. package/dist/executor.unit.test.d.ts.map +1 -0
  194. package/dist/executor.unit.test.js +143 -0
  195. package/dist/executor.unit.test.js.map +1 -0
  196. package/dist/extension/_locales/en/messages.json +278 -0
  197. package/dist/extension/_locales/zh_CN/messages.json +256 -0
  198. package/dist/extension/assets/options-CYH96Lcx.css +1349 -0
  199. package/dist/extension/background.js +3994 -0
  200. package/dist/extension/icons/SolarCursorSquareBold.png +0 -0
  201. package/dist/extension/icons/icon-black-128.png +0 -0
  202. package/dist/extension/icons/icon-black-16.png +0 -0
  203. package/dist/extension/icons/icon-black-32.png +0 -0
  204. package/dist/extension/icons/icon-black-48.png +0 -0
  205. package/dist/extension/icons/icon-gray-128.png +0 -0
  206. package/dist/extension/icons/icon-gray-16.png +0 -0
  207. package/dist/extension/icons/icon-gray-32.png +0 -0
  208. package/dist/extension/icons/icon-gray-48.png +0 -0
  209. package/dist/extension/icons/icon-green-128.png +0 -0
  210. package/dist/extension/icons/icon-green-16.png +0 -0
  211. package/dist/extension/icons/icon-green-32.png +0 -0
  212. package/dist/extension/icons/icon-green-48.png +0 -0
  213. package/dist/extension/icons/tabwright-icon-black.png +0 -0
  214. package/dist/extension/icons/tabwright-icon-gray-disabled.png +0 -0
  215. package/dist/extension/icons/tabwright-icon-gray-disabled.svg +1 -0
  216. package/dist/extension/manifest.json +54 -0
  217. package/dist/extension/options.js +16145 -0
  218. package/dist/extension/rrweb-recorder.js +12952 -0
  219. package/dist/extension/src/options.html +165 -0
  220. package/dist/extension/src/prism-bash.min.js +1 -0
  221. package/dist/extension/src/prism.min.js +1 -0
  222. package/dist/extension/src/welcome.html +396 -0
  223. package/dist/extension-connection.test.d.ts +2 -0
  224. package/dist/extension-connection.test.d.ts.map +1 -0
  225. package/dist/extension-connection.test.js +708 -0
  226. package/dist/extension-connection.test.js.map +1 -0
  227. package/dist/extension-icon-warning.test.d.ts +2 -0
  228. package/dist/extension-icon-warning.test.d.ts.map +1 -0
  229. package/dist/extension-icon-warning.test.js +33 -0
  230. package/dist/extension-icon-warning.test.js.map +1 -0
  231. package/dist/ghost-browser.d.ts +62 -0
  232. package/dist/ghost-browser.d.ts.map +1 -0
  233. package/dist/ghost-browser.js +107 -0
  234. package/dist/ghost-browser.js.map +1 -0
  235. package/dist/ghost-cursor-client.js +374 -0
  236. package/dist/ghost-cursor-controller.d.ts +46 -0
  237. package/dist/ghost-cursor-controller.d.ts.map +1 -0
  238. package/dist/ghost-cursor-controller.js +98 -0
  239. package/dist/ghost-cursor-controller.js.map +1 -0
  240. package/dist/ghost-cursor.d.ts +27 -0
  241. package/dist/ghost-cursor.d.ts.map +1 -0
  242. package/dist/ghost-cursor.js +79 -0
  243. package/dist/ghost-cursor.js.map +1 -0
  244. package/dist/htmlrewrite.d.ts +8 -0
  245. package/dist/htmlrewrite.d.ts.map +1 -0
  246. package/dist/htmlrewrite.js +339 -0
  247. package/dist/htmlrewrite.js.map +1 -0
  248. package/dist/htmlrewrite.test.d.ts +2 -0
  249. package/dist/htmlrewrite.test.d.ts.map +1 -0
  250. package/dist/htmlrewrite.test.js +7975 -0
  251. package/dist/htmlrewrite.test.js.map +1 -0
  252. package/dist/index.d.ts +20 -0
  253. package/dist/index.d.ts.map +1 -0
  254. package/dist/index.js +11 -0
  255. package/dist/index.js.map +1 -0
  256. package/dist/kill-port.d.ts +29 -0
  257. package/dist/kill-port.d.ts.map +1 -0
  258. package/dist/kill-port.js +190 -0
  259. package/dist/kill-port.js.map +1 -0
  260. package/dist/kitty-graphics.d.ts +22 -0
  261. package/dist/kitty-graphics.d.ts.map +1 -0
  262. package/dist/kitty-graphics.js +71 -0
  263. package/dist/kitty-graphics.js.map +1 -0
  264. package/dist/kitty-graphics.test.d.ts +2 -0
  265. package/dist/kitty-graphics.test.d.ts.map +1 -0
  266. package/dist/kitty-graphics.test.js +125 -0
  267. package/dist/kitty-graphics.test.js.map +1 -0
  268. package/dist/locator-selector.test.d.ts +2 -0
  269. package/dist/locator-selector.test.d.ts.map +1 -0
  270. package/dist/locator-selector.test.js +98 -0
  271. package/dist/locator-selector.test.js.map +1 -0
  272. package/dist/mcp-client.d.ts +20 -0
  273. package/dist/mcp-client.d.ts.map +1 -0
  274. package/dist/mcp-client.js +56 -0
  275. package/dist/mcp-client.js.map +1 -0
  276. package/dist/mcp.d.ts +6 -0
  277. package/dist/mcp.d.ts.map +1 -0
  278. package/dist/mcp.js +511 -0
  279. package/dist/mcp.js.map +1 -0
  280. package/dist/on-mouse-action.test.d.ts +2 -0
  281. package/dist/on-mouse-action.test.d.ts.map +1 -0
  282. package/dist/on-mouse-action.test.js +180 -0
  283. package/dist/on-mouse-action.test.js.map +1 -0
  284. package/dist/options-page.test.d.ts +2 -0
  285. package/dist/options-page.test.d.ts.map +1 -0
  286. package/dist/options-page.test.js +773 -0
  287. package/dist/options-page.test.js.map +1 -0
  288. package/dist/package-paths.d.ts +4 -0
  289. package/dist/package-paths.d.ts.map +1 -0
  290. package/dist/package-paths.js +30 -0
  291. package/dist/package-paths.js.map +1 -0
  292. package/dist/page-markdown.d.ts +40 -0
  293. package/dist/page-markdown.d.ts.map +1 -0
  294. package/dist/page-markdown.js +181 -0
  295. package/dist/page-markdown.js.map +1 -0
  296. package/dist/performance-examples.d.ts +5 -0
  297. package/dist/performance-examples.d.ts.map +1 -0
  298. package/dist/performance-examples.js +112 -0
  299. package/dist/performance-examples.js.map +1 -0
  300. package/dist/performance-profiling.md +417 -0
  301. package/dist/playwright-import.d.ts +19 -0
  302. package/dist/playwright-import.d.ts.map +1 -0
  303. package/dist/playwright-import.js +40 -0
  304. package/dist/playwright-import.js.map +1 -0
  305. package/dist/popup-relocation.test.d.ts +7 -0
  306. package/dist/popup-relocation.test.d.ts.map +1 -0
  307. package/dist/popup-relocation.test.js +139 -0
  308. package/dist/popup-relocation.test.js.map +1 -0
  309. package/dist/product-paths.d.ts +9 -0
  310. package/dist/product-paths.d.ts.map +1 -0
  311. package/dist/product-paths.js +24 -0
  312. package/dist/product-paths.js.map +1 -0
  313. package/dist/product-paths.test.d.ts +2 -0
  314. package/dist/product-paths.test.d.ts.map +1 -0
  315. package/dist/product-paths.test.js +39 -0
  316. package/dist/product-paths.test.js.map +1 -0
  317. package/dist/prompt.md +1004 -0
  318. package/dist/protocol.d.ts +248 -0
  319. package/dist/protocol.d.ts.map +1 -0
  320. package/dist/protocol.js +59 -0
  321. package/dist/protocol.js.map +1 -0
  322. package/dist/protocol.test.d.ts +2 -0
  323. package/dist/protocol.test.d.ts.map +1 -0
  324. package/dist/protocol.test.js +31 -0
  325. package/dist/protocol.test.js.map +1 -0
  326. package/dist/react-source.d.ts +57 -0
  327. package/dist/react-source.d.ts.map +1 -0
  328. package/dist/react-source.js +254 -0
  329. package/dist/react-source.js.map +1 -0
  330. package/dist/readability.js +1674 -0
  331. package/dist/relay-client.d.ts +104 -0
  332. package/dist/relay-client.d.ts.map +1 -0
  333. package/dist/relay-client.js +426 -0
  334. package/dist/relay-client.js.map +1 -0
  335. package/dist/relay-client.test.d.ts +2 -0
  336. package/dist/relay-client.test.d.ts.map +1 -0
  337. package/dist/relay-client.test.js +305 -0
  338. package/dist/relay-client.test.js.map +1 -0
  339. package/dist/relay-core.test.d.ts +2 -0
  340. package/dist/relay-core.test.d.ts.map +1 -0
  341. package/dist/relay-core.test.js +1427 -0
  342. package/dist/relay-core.test.js.map +1 -0
  343. package/dist/relay-navigation.test.d.ts +2 -0
  344. package/dist/relay-navigation.test.d.ts.map +1 -0
  345. package/dist/relay-navigation.test.js +661 -0
  346. package/dist/relay-navigation.test.js.map +1 -0
  347. package/dist/relay-session.test.d.ts +2 -0
  348. package/dist/relay-session.test.d.ts.map +1 -0
  349. package/dist/relay-session.test.js +1121 -0
  350. package/dist/relay-session.test.js.map +1 -0
  351. package/dist/relay-state.d.ts +178 -0
  352. package/dist/relay-state.d.ts.map +1 -0
  353. package/dist/relay-state.js +346 -0
  354. package/dist/relay-state.js.map +1 -0
  355. package/dist/relay-state.test.d.ts +2 -0
  356. package/dist/relay-state.test.d.ts.map +1 -0
  357. package/dist/relay-state.test.js +594 -0
  358. package/dist/relay-state.test.js.map +1 -0
  359. package/dist/replay-ai-index.d.ts +99 -0
  360. package/dist/replay-ai-index.d.ts.map +1 -0
  361. package/dist/replay-ai-index.js +677 -0
  362. package/dist/replay-ai-index.js.map +1 -0
  363. package/dist/replay-ai-index.test.d.ts +2 -0
  364. package/dist/replay-ai-index.test.d.ts.map +1 -0
  365. package/dist/replay-ai-index.test.js +255 -0
  366. package/dist/replay-ai-index.test.js.map +1 -0
  367. package/dist/replay-cli.test.d.ts +2 -0
  368. package/dist/replay-cli.test.d.ts.map +1 -0
  369. package/dist/replay-cli.test.js +275 -0
  370. package/dist/replay-cli.test.js.map +1 -0
  371. package/dist/replay-eval.d.ts +44 -0
  372. package/dist/replay-eval.d.ts.map +1 -0
  373. package/dist/replay-eval.js +902 -0
  374. package/dist/replay-eval.js.map +1 -0
  375. package/dist/replay-handoff.d.ts +29 -0
  376. package/dist/replay-handoff.d.ts.map +1 -0
  377. package/dist/replay-handoff.js +83 -0
  378. package/dist/replay-handoff.js.map +1 -0
  379. package/dist/replay-handoff.test.d.ts +2 -0
  380. package/dist/replay-handoff.test.d.ts.map +1 -0
  381. package/dist/replay-handoff.test.js +123 -0
  382. package/dist/replay-handoff.test.js.map +1 -0
  383. package/dist/replay-workflow-compiler.d.ts +44 -0
  384. package/dist/replay-workflow-compiler.d.ts.map +1 -0
  385. package/dist/replay-workflow-compiler.js +601 -0
  386. package/dist/replay-workflow-compiler.js.map +1 -0
  387. package/dist/replay-workflow-compiler.test.d.ts +2 -0
  388. package/dist/replay-workflow-compiler.test.d.ts.map +1 -0
  389. package/dist/replay-workflow-compiler.test.js +223 -0
  390. package/dist/replay-workflow-compiler.test.js.map +1 -0
  391. package/dist/rrweb-recording-relay.d.ts +56 -0
  392. package/dist/rrweb-recording-relay.d.ts.map +1 -0
  393. package/dist/rrweb-recording-relay.js +299 -0
  394. package/dist/rrweb-recording-relay.js.map +1 -0
  395. package/dist/rrweb-recording-relay.test.d.ts +2 -0
  396. package/dist/rrweb-recording-relay.test.d.ts.map +1 -0
  397. package/dist/rrweb-recording-relay.test.js +85 -0
  398. package/dist/rrweb-recording-relay.test.js.map +1 -0
  399. package/dist/rrweb-recording.d.ts +104 -0
  400. package/dist/rrweb-recording.d.ts.map +1 -0
  401. package/dist/rrweb-recording.js +180 -0
  402. package/dist/rrweb-recording.js.map +1 -0
  403. package/dist/scoped-fs.d.ts +95 -0
  404. package/dist/scoped-fs.d.ts.map +1 -0
  405. package/dist/scoped-fs.js +358 -0
  406. package/dist/scoped-fs.js.map +1 -0
  407. package/dist/scoped-fs.test.d.ts +5 -0
  408. package/dist/scoped-fs.test.d.ts.map +1 -0
  409. package/dist/scoped-fs.test.js +73 -0
  410. package/dist/scoped-fs.test.js.map +1 -0
  411. package/dist/selector-generator.js +7378 -0
  412. package/dist/skill-stub.test.d.ts +2 -0
  413. package/dist/skill-stub.test.d.ts.map +1 -0
  414. package/dist/skill-stub.test.js +22 -0
  415. package/dist/skill-stub.test.js.map +1 -0
  416. package/dist/snapshot-tools.test.d.ts +2 -0
  417. package/dist/snapshot-tools.test.d.ts.map +1 -0
  418. package/dist/snapshot-tools.test.js +856 -0
  419. package/dist/snapshot-tools.test.js.map +1 -0
  420. package/dist/start-relay-server.d.ts +6 -0
  421. package/dist/start-relay-server.d.ts.map +1 -0
  422. package/dist/start-relay-server.js +57 -0
  423. package/dist/start-relay-server.js.map +1 -0
  424. package/dist/styles-api.md +124 -0
  425. package/dist/styles-examples.d.ts +8 -0
  426. package/dist/styles-examples.d.ts.map +1 -0
  427. package/dist/styles-examples.js +64 -0
  428. package/dist/styles-examples.js.map +1 -0
  429. package/dist/styles.d.ts +27 -0
  430. package/dist/styles.d.ts.map +1 -0
  431. package/dist/styles.js +231 -0
  432. package/dist/styles.js.map +1 -0
  433. package/dist/tabwright-agent-skill.d.ts +30 -0
  434. package/dist/tabwright-agent-skill.d.ts.map +1 -0
  435. package/dist/tabwright-agent-skill.js +74 -0
  436. package/dist/tabwright-agent-skill.js.map +1 -0
  437. package/dist/tabwright-agent-skill.test.d.ts +2 -0
  438. package/dist/tabwright-agent-skill.test.d.ts.map +1 -0
  439. package/dist/tabwright-agent-skill.test.js +51 -0
  440. package/dist/tabwright-agent-skill.test.js.map +1 -0
  441. package/dist/test-declarations.d.ts +13 -0
  442. package/dist/test-declarations.d.ts.map +1 -0
  443. package/dist/test-declarations.js +2 -0
  444. package/dist/test-declarations.js.map +1 -0
  445. package/dist/test-utils.d.ts +69 -0
  446. package/dist/test-utils.d.ts.map +1 -0
  447. package/dist/test-utils.js +448 -0
  448. package/dist/test-utils.js.map +1 -0
  449. package/dist/test-utils.test.d.ts +2 -0
  450. package/dist/test-utils.test.d.ts.map +1 -0
  451. package/dist/test-utils.test.js +55 -0
  452. package/dist/test-utils.test.js.map +1 -0
  453. package/dist/utils.d.ts +26 -0
  454. package/dist/utils.d.ts.map +1 -0
  455. package/dist/utils.js +60 -0
  456. package/dist/utils.js.map +1 -0
  457. package/dist/wait-for-page-load.d.ts +16 -0
  458. package/dist/wait-for-page-load.d.ts.map +1 -0
  459. package/dist/wait-for-page-load.js +146 -0
  460. package/dist/wait-for-page-load.js.map +1 -0
  461. package/dist/workflow-capability.d.ts +72 -0
  462. package/dist/workflow-capability.d.ts.map +1 -0
  463. package/dist/workflow-capability.js +316 -0
  464. package/dist/workflow-capability.js.map +1 -0
  465. package/dist/workflow-script-flow.test.d.ts +2 -0
  466. package/dist/workflow-script-flow.test.d.ts.map +1 -0
  467. package/dist/workflow-script-flow.test.js +285 -0
  468. package/dist/workflow-script-flow.test.js.map +1 -0
  469. package/package.json +80 -0
  470. package/src/__snapshots__/x.com.processed.html +1003 -0
  471. package/src/__snapshots__/x.com.processed.withStyles.html +2720 -0
  472. package/src/a11y-client.ts +241 -0
  473. package/src/agent-skills/conan-config/SKILL.md +141 -0
  474. package/src/agent-skills/conan-config/agents/openai.yaml +4 -0
  475. package/src/aria-snapshot.test.ts +311 -0
  476. package/src/aria-snapshot.ts +1681 -0
  477. package/src/aria-snapshot.unit.test.ts +615 -0
  478. package/src/aria-snapshots/github-interactive.txt +193 -0
  479. package/src/aria-snapshots/github-raw.txt +309 -0
  480. package/src/aria-snapshots/hackernews-interactive.txt +477 -0
  481. package/src/aria-snapshots/hackernews-raw.txt +428 -0
  482. package/src/aria-snapshots/prosemirror-interactive.txt +66 -0
  483. package/src/aria-snapshots/prosemirror-raw.txt +145 -0
  484. package/src/assets/aria-labels-hacker-news.png +0 -0
  485. package/src/assets/aria-labels-old-reddit.png +0 -0
  486. package/src/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.ts +5 -0
  487. package/src/assets/cursors/screen-studio/pointer-macos-tahoe.svg +18 -0
  488. package/src/assets/x.com.html +32946 -0
  489. package/src/browser-config.ts +179 -0
  490. package/src/browser-install.ts +284 -0
  491. package/src/browser-launch.ts +75 -0
  492. package/src/builtin-capabilities.ts +2765 -0
  493. package/src/capability-agent-skill.ts +305 -0
  494. package/src/capability-auth-state.ts +197 -0
  495. package/src/capability-auth.ts +249 -0
  496. package/src/capability-cli-confirmation.test.ts +90 -0
  497. package/src/capability-options.test.ts +89 -0
  498. package/src/capability-options.ts +57 -0
  499. package/src/capability-package.test.ts +204 -0
  500. package/src/capability-package.ts +555 -0
  501. package/src/capability-registry.test.ts +1905 -0
  502. package/src/capability-registry.ts +1234 -0
  503. package/src/capability-runner.ts +801 -0
  504. package/src/capability-search-relevance.test.ts +73 -0
  505. package/src/capability-studio.test.ts +45 -0
  506. package/src/capability-studio.ts +641 -0
  507. package/src/cdp-log.test.ts +131 -0
  508. package/src/cdp-log.ts +112 -0
  509. package/src/cdp-relay.ts +2944 -0
  510. package/src/cdp-session.ts +77 -0
  511. package/src/cdp-types.ts +158 -0
  512. package/src/channel-owner-inspect.test.ts +94 -0
  513. package/src/chrome-discovery.test.ts +50 -0
  514. package/src/chrome-discovery.ts +220 -0
  515. package/src/clean-html.ts +141 -0
  516. package/src/cli-help.test.ts +123 -0
  517. package/src/cli.ts +3181 -0
  518. package/src/cloud-client.ts +179 -0
  519. package/src/create-logger.ts +38 -0
  520. package/src/debugger-examples-types.ts +16 -0
  521. package/src/debugger-examples.ts +66 -0
  522. package/src/debugger.ts +708 -0
  523. package/src/diff-utils.test.ts +152 -0
  524. package/src/diff-utils.ts +70 -0
  525. package/src/doctor.test.ts +244 -0
  526. package/src/doctor.ts +321 -0
  527. package/src/editor-examples.ts +158 -0
  528. package/src/editor.ts +426 -0
  529. package/src/env-compat.ts +28 -0
  530. package/src/executor.ts +1824 -0
  531. package/src/executor.unit.test.ts +168 -0
  532. package/src/extension-connection.test.ts +855 -0
  533. package/src/extension-icon-warning.test.ts +45 -0
  534. package/src/ghost-browser.ts +149 -0
  535. package/src/ghost-cursor-client.ts +494 -0
  536. package/src/ghost-cursor-controller.ts +129 -0
  537. package/src/ghost-cursor.ts +123 -0
  538. package/src/htmlrewrite.test.ts +8008 -0
  539. package/src/htmlrewrite.ts +390 -0
  540. package/src/index.ts +53 -0
  541. package/src/kill-port.ts +219 -0
  542. package/src/kitty-graphics.test.ts +139 -0
  543. package/src/kitty-graphics.ts +79 -0
  544. package/src/locator-selector.test.ts +119 -0
  545. package/src/mcp-client.ts +78 -0
  546. package/src/mcp.ts +629 -0
  547. package/src/on-mouse-action.test.ts +226 -0
  548. package/src/options-page.test.ts +839 -0
  549. package/src/package-paths.ts +38 -0
  550. package/src/page-markdown.ts +240 -0
  551. package/src/performance-examples.ts +186 -0
  552. package/src/playwright-import.ts +59 -0
  553. package/src/popup-relocation.test.ts +163 -0
  554. package/src/product-paths.test.ts +47 -0
  555. package/src/product-paths.ts +28 -0
  556. package/src/protocol.test.ts +52 -0
  557. package/src/protocol.ts +351 -0
  558. package/src/react-source.ts +379 -0
  559. package/src/relay-client.test.ts +375 -0
  560. package/src/relay-client.ts +572 -0
  561. package/src/relay-core.test.ts +1603 -0
  562. package/src/relay-navigation.test.ts +790 -0
  563. package/src/relay-session.test.ts +1375 -0
  564. package/src/relay-state.test.ts +729 -0
  565. package/src/relay-state.ts +561 -0
  566. package/src/replay-ai-index.test.ts +278 -0
  567. package/src/replay-ai-index.ts +872 -0
  568. package/src/replay-cli.test.ts +325 -0
  569. package/src/replay-eval.ts +1039 -0
  570. package/src/replay-handoff.test.ts +163 -0
  571. package/src/replay-handoff.ts +109 -0
  572. package/src/replay-workflow-compiler.test.ts +250 -0
  573. package/src/replay-workflow-compiler.ts +700 -0
  574. package/src/resource.md +409 -0
  575. package/src/rrweb-recording-relay.test.ts +99 -0
  576. package/src/rrweb-recording-relay.ts +400 -0
  577. package/src/rrweb-recording.ts +322 -0
  578. package/src/scoped-fs.test.ts +80 -0
  579. package/src/scoped-fs.ts +420 -0
  580. package/src/skill-stub.test.ts +24 -0
  581. package/src/skill.md +1413 -0
  582. package/src/snapshot-tools.test.ts +1017 -0
  583. package/src/snapshots/hacker-news-accessibility-full.md +81 -0
  584. package/src/snapshots/hacker-news-accessibility-interactive.md +43 -0
  585. package/src/snapshots/page-markdown-output.txt +16 -0
  586. package/src/snapshots/shadcn-ui-accessibility-full.md +201 -0
  587. package/src/snapshots/shadcn-ui-accessibility-interactive.md +109 -0
  588. package/src/start-relay-server.ts +69 -0
  589. package/src/styles-examples.ts +84 -0
  590. package/src/styles.ts +343 -0
  591. package/src/tabwright-agent-skill.test.ts +61 -0
  592. package/src/tabwright-agent-skill.ts +105 -0
  593. package/src/test-declarations.ts +13 -0
  594. package/src/test-utils.test.ts +70 -0
  595. package/src/test-utils.ts +566 -0
  596. package/src/utils.ts +78 -0
  597. package/src/wait-for-page-load.ts +198 -0
  598. package/src/workflow-capability.ts +417 -0
  599. package/src/workflow-script-flow.test.ts +388 -0
@@ -0,0 +1,700 @@
1
+ import { getSavedRrwebRecordingWithEvents } from './rrweb-recording-relay.js'
2
+ import { buildReplayAiIndex } from './replay-ai-index.js'
3
+ import { saveWorkflowCapability, type SavedWorkflowCapability } from './workflow-capability.js'
4
+ import type { RrwebEvent } from './protocol.js'
5
+
6
+ type ReplayNodeType = 2 | 3
7
+
8
+ interface ReplayDomNode {
9
+ id: number
10
+ type: ReplayNodeType
11
+ tagName?: string
12
+ textContent?: string
13
+ attributes: Record<string, string>
14
+ childIds: number[]
15
+ parentId?: number
16
+ }
17
+
18
+ interface ReplayClick {
19
+ timestamp: number
20
+ nodeId: number
21
+ text: string
22
+ tagName?: string
23
+ }
24
+
25
+ interface ReplayInput {
26
+ timestamp: number
27
+ nodeId: number
28
+ value: string
29
+ tagName?: string
30
+ }
31
+
32
+ export interface ReplayWorkflowAnalysis {
33
+ replayId: string
34
+ url?: string
35
+ demonstratedValue?: string
36
+ clickedTexts: string[]
37
+ inputValues: string[]
38
+ annotations: Array<{
39
+ text: string
40
+ target?: string
41
+ selectorHints: string[]
42
+ }>
43
+ actionKind: 'list-append' | 'unknown'
44
+ draftDialogAction?: 'continue' | 'restart'
45
+ confidence: 'low' | 'medium' | 'high'
46
+ reasons: string[]
47
+ }
48
+
49
+ export interface CompileReplayWorkflowOptions {
50
+ replayId: string
51
+ id: string
52
+ title?: string
53
+ description?: string
54
+ cwd?: string
55
+ overwrite?: boolean
56
+ valueInputPath?: string
57
+ }
58
+
59
+ export interface CompiledReplayWorkflow {
60
+ analysis: ReplayWorkflowAnalysis
61
+ saved: SavedWorkflowCapability
62
+ }
63
+
64
+ export class UnsupportedReplayWorkflowError extends Error {
65
+ readonly analysis: ReplayWorkflowAnalysis
66
+
67
+ constructor(options: { analysis: ReplayWorkflowAnalysis }) {
68
+ super(`Replay compiler could not infer a supported workflow: ${options.analysis.reasons.join(' ')}`)
69
+ this.name = 'UnsupportedReplayWorkflowError'
70
+ this.analysis = options.analysis
71
+ }
72
+ }
73
+
74
+ function isRecord(value: unknown): value is Record<string, unknown> {
75
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
76
+ }
77
+
78
+ function optionalString(value: unknown): string | undefined {
79
+ return typeof value === 'string' && value.trim() ? value : undefined
80
+ }
81
+
82
+ function numberValue(value: unknown): number | undefined {
83
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined
84
+ }
85
+
86
+ function normalizeText(value: string | undefined): string {
87
+ return (value || '').replace(/\s+/g, ' ').trim()
88
+ }
89
+
90
+ function recordToStringMap(value: unknown): Record<string, string> {
91
+ if (!isRecord(value)) {
92
+ return {}
93
+ }
94
+ return Object.fromEntries(
95
+ Object.entries(value)
96
+ .map(([key, item]) => {
97
+ if (typeof item === 'string') {
98
+ return [key, item] as const
99
+ }
100
+ if (isRecord(item)) {
101
+ return [key, JSON.stringify(item)] as const
102
+ }
103
+ return null
104
+ })
105
+ .filter((entry): entry is readonly [string, string] => {
106
+ return Boolean(entry)
107
+ }),
108
+ )
109
+ }
110
+
111
+ function getEventType(event: RrwebEvent): number | undefined {
112
+ return numberValue(event.type)
113
+ }
114
+
115
+ function getEventTimestamp(event: RrwebEvent): number {
116
+ return numberValue(event.timestamp) || 0
117
+ }
118
+
119
+ function getEventData(event: RrwebEvent): Record<string, unknown> {
120
+ return isRecord(event.data) ? event.data : {}
121
+ }
122
+
123
+ function getNodeId(value: unknown): number | undefined {
124
+ return numberValue(isRecord(value) ? value.id : undefined)
125
+ }
126
+
127
+ function readReplayNode(rawNode: unknown, parentId?: number): ReplayDomNode | null {
128
+ if (!isRecord(rawNode)) {
129
+ return null
130
+ }
131
+ const id = numberValue(rawNode.id)
132
+ const type = numberValue(rawNode.type)
133
+ if (!id || (type !== 2 && type !== 3)) {
134
+ return null
135
+ }
136
+ const childNodes = Array.isArray(rawNode.childNodes) ? rawNode.childNodes : []
137
+ return {
138
+ id,
139
+ type,
140
+ tagName: optionalString(rawNode.tagName)?.toLowerCase(),
141
+ textContent: optionalString(rawNode.textContent),
142
+ attributes: recordToStringMap(rawNode.attributes),
143
+ childIds: childNodes
144
+ .map((child) => {
145
+ return getNodeId(child)
146
+ })
147
+ .filter((nodeId): nodeId is number => {
148
+ return nodeId !== undefined
149
+ }),
150
+ parentId,
151
+ }
152
+ }
153
+
154
+ function addReplayNode(nodes: Map<number, ReplayDomNode>, rawNode: unknown, parentId?: number): void {
155
+ const node = readReplayNode(rawNode, parentId)
156
+ const childNodes = isRecord(rawNode) && Array.isArray(rawNode.childNodes) ? rawNode.childNodes : []
157
+ if (!node && childNodes.length === 0) {
158
+ return
159
+ }
160
+ if (!node) {
161
+ childNodes.forEach((child) => {
162
+ addReplayNode(nodes, child, parentId)
163
+ })
164
+ return
165
+ }
166
+ nodes.set(node.id, node)
167
+ childNodes.forEach((child) => {
168
+ addReplayNode(nodes, child, node.id)
169
+ })
170
+ }
171
+
172
+ function removeReplayNode(nodes: Map<number, ReplayDomNode>, nodeId: number): void {
173
+ const node = nodes.get(nodeId)
174
+ if (!node) {
175
+ return
176
+ }
177
+ node.childIds.forEach((childId) => {
178
+ removeReplayNode(nodes, childId)
179
+ })
180
+ nodes.delete(nodeId)
181
+ }
182
+
183
+ function applyMutationEvent(nodes: Map<number, ReplayDomNode>, data: Record<string, unknown>): void {
184
+ const removes = Array.isArray(data.removes) ? data.removes : []
185
+ removes
186
+ .map((remove) => {
187
+ return isRecord(remove) ? numberValue(remove.id) : undefined
188
+ })
189
+ .filter((nodeId): nodeId is number => {
190
+ return nodeId !== undefined
191
+ })
192
+ .forEach((nodeId) => {
193
+ removeReplayNode(nodes, nodeId)
194
+ })
195
+
196
+ const adds = Array.isArray(data.adds) ? data.adds : []
197
+ adds.forEach((add) => {
198
+ if (!isRecord(add)) {
199
+ return
200
+ }
201
+ const parentId = numberValue(add.parentId)
202
+ addReplayNode(nodes, add.node, parentId)
203
+ })
204
+
205
+ const texts = Array.isArray(data.texts) ? data.texts : []
206
+ texts.forEach((text) => {
207
+ if (!isRecord(text)) {
208
+ return
209
+ }
210
+ const nodeId = numberValue(text.id)
211
+ const node = nodeId === undefined ? undefined : nodes.get(nodeId)
212
+ if (!node) {
213
+ return
214
+ }
215
+ node.textContent = optionalString(text.value) || ''
216
+ })
217
+
218
+ const attributes = Array.isArray(data.attributes) ? data.attributes : []
219
+ attributes.forEach((attribute) => {
220
+ if (!isRecord(attribute)) {
221
+ return
222
+ }
223
+ const nodeId = numberValue(attribute.id)
224
+ const node = nodeId === undefined ? undefined : nodes.get(nodeId)
225
+ if (!node) {
226
+ return
227
+ }
228
+ node.attributes = {
229
+ ...node.attributes,
230
+ ...recordToStringMap(attribute.attributes),
231
+ }
232
+ })
233
+ }
234
+
235
+ function nodeText(nodes: Map<number, ReplayDomNode>, nodeId: number): string {
236
+ const node = nodes.get(nodeId)
237
+ if (!node) {
238
+ return ''
239
+ }
240
+ const childText = node.childIds
241
+ .map((childId) => {
242
+ return nodeText(nodes, childId)
243
+ })
244
+ .filter((text) => {
245
+ return text.length > 0
246
+ })
247
+ .join(' ')
248
+ return normalizeText([node.textContent, childText].filter(Boolean).join(' '))
249
+ }
250
+
251
+ function nodeAndAncestors(nodes: Map<number, ReplayDomNode>, nodeId: number, maxDepth: number): ReplayDomNode[] {
252
+ const current = nodes.get(nodeId)
253
+ if (!current) {
254
+ return []
255
+ }
256
+ const ancestors: ReplayDomNode[] = [current]
257
+ let next = current.parentId === undefined ? undefined : nodes.get(current.parentId)
258
+ let depth = 1
259
+ while (next && depth < maxDepth) {
260
+ ancestors.push(next)
261
+ next = next.parentId === undefined ? undefined : nodes.get(next.parentId)
262
+ depth += 1
263
+ }
264
+ return ancestors
265
+ }
266
+
267
+ function actionLabelFromText(value: string): string | undefined {
268
+ const text = normalizeText(value)
269
+ if (!text || text.length > 80) {
270
+ return undefined
271
+ }
272
+ if (/to pick up a draggable item/i.test(text)) {
273
+ return undefined
274
+ }
275
+ const matchers: Array<{ label: string; pattern: RegExp }> = [
276
+ { label: '重新编辑', pattern: /重新编辑/ },
277
+ { label: '继续编辑', pattern: /继续编辑/ },
278
+ { label: 'Add entry', pattern: /add entry/i },
279
+ { label: '新增', pattern: /新增|添加/ },
280
+ { label: '提交', pattern: /提交|submit/i },
281
+ { label: 'OK', pattern: /\bOK\b|确定/ },
282
+ { label: 'Cancel', pattern: /cancel|取消/i },
283
+ { label: '编辑', pattern: /编辑|\bedit\b/i },
284
+ ]
285
+ return matchers.find((matcher) => {
286
+ return matcher.pattern.test(text)
287
+ })?.label
288
+ }
289
+
290
+ function clickLabelFromStructure(nodes: Map<number, ReplayDomNode>, nodeId: number): string | undefined {
291
+ const ancestors = nodeAndAncestors(nodes, nodeId, 8)
292
+ const classText = ancestors
293
+ .map((node) => {
294
+ return node.attributes.class || ''
295
+ })
296
+ .join(' ')
297
+ const inModal = classText.includes('designer-modal')
298
+ if (classText.includes('designer-formily-array-base-addition')) {
299
+ return 'Add entry'
300
+ }
301
+ if (inModal && classText.includes('designer-btn-dangerous')) {
302
+ return '重新编辑'
303
+ }
304
+ if (inModal && classText.includes('designer-btn-primary')) {
305
+ return 'OK'
306
+ }
307
+ return undefined
308
+ }
309
+
310
+ function nearestText(nodes: Map<number, ReplayDomNode>, nodeId: number): string {
311
+ const structuredLabel = clickLabelFromStructure(nodes, nodeId)
312
+ if (structuredLabel) {
313
+ return structuredLabel
314
+ }
315
+ const candidates = nodeAndAncestors(nodes, nodeId, 8)
316
+ .map((node) => {
317
+ return nodeText(nodes, node.id)
318
+ })
319
+ .filter((text) => {
320
+ return text.length > 0
321
+ })
322
+ const actionLabel = candidates
323
+ .map((text) => {
324
+ return actionLabelFromText(text)
325
+ })
326
+ .find((label) => {
327
+ return Boolean(label)
328
+ })
329
+ if (actionLabel) {
330
+ return actionLabel
331
+ }
332
+ return ''
333
+ }
334
+
335
+ function uniqueStrings(values: string[]): string[] {
336
+ return Array.from(new Set(values.filter((value) => {
337
+ return value.length > 0
338
+ })))
339
+ }
340
+
341
+ function lastNonEmpty(values: string[]): string | undefined {
342
+ return values
343
+ .slice()
344
+ .reverse()
345
+ .find((value) => {
346
+ return value.length > 0
347
+ })
348
+ }
349
+
350
+ function detectActionKind(options: { clickedTexts: string[]; inputValues: string[] }): ReplayWorkflowAnalysis['actionKind'] {
351
+ const clicked = options.clickedTexts.join('\n').toLowerCase()
352
+ const hasAdd = clicked.includes('add entry') || clicked.includes('新增') || clicked.includes('添加')
353
+ const hasSubmit = clicked.includes('提交') || clicked.includes('submit')
354
+ if (hasAdd && hasSubmit && lastNonEmpty(options.inputValues)) {
355
+ return 'list-append'
356
+ }
357
+ return 'unknown'
358
+ }
359
+
360
+ function isWorkflowClickLabel(value: string): boolean {
361
+ return /编辑|重新编辑|继续编辑|\bedit\b|add entry|新增|添加|提交|submit|\bOK\b|确定|cancel|取消/i.test(value)
362
+ }
363
+
364
+ export function analyzeReplayWorkflow(options: {
365
+ replayId: string
366
+ url?: string
367
+ events: RrwebEvent[]
368
+ }): ReplayWorkflowAnalysis {
369
+ const aiIndex = buildReplayAiIndex(options)
370
+ const clickedTexts = uniqueStrings(
371
+ aiIndex.actions
372
+ .filter((action) => {
373
+ return action.kind === 'click' && isWorkflowClickLabel(action.label)
374
+ })
375
+ .map((action) => {
376
+ return action.label
377
+ }),
378
+ )
379
+ const inputValues = uniqueStrings(
380
+ aiIndex.actions
381
+ .filter((action) => {
382
+ return action.kind === 'input'
383
+ })
384
+ .map((action) => {
385
+ return normalizeText(action.value)
386
+ }),
387
+ )
388
+ const actionKind = detectActionKind({ clickedTexts, inputValues })
389
+ const demonstratedValue = lastNonEmpty(inputValues)
390
+ const annotations = aiIndex.annotations.map((annotation) => {
391
+ return {
392
+ text: annotation.text,
393
+ target: annotation.target?.label || annotation.target?.text || annotation.target?.tagName,
394
+ selectorHints: annotation.target?.selectorHints || [],
395
+ }
396
+ })
397
+ const draftDialogAction = clickedTexts.some((text) => {
398
+ return text.includes('重新编辑')
399
+ })
400
+ ? 'restart'
401
+ : clickedTexts.some((text) => {
402
+ return text.includes('继续编辑')
403
+ })
404
+ ? 'continue'
405
+ : undefined
406
+ const reasons = [
407
+ clickedTexts.length > 0 ? `Observed clicks: ${clickedTexts.join(' -> ')}` : 'No click text could be inferred.',
408
+ demonstratedValue ? `Observed final input value: ${demonstratedValue}` : 'No final input value could be inferred.',
409
+ annotations.length > 0 ? `Observed user annotations: ${annotations.map((annotation) => {
410
+ return annotation.text
411
+ }).join(' | ')}` : 'No user annotations were recorded.',
412
+ actionKind === 'list-append' ? 'Detected list append pattern.' : 'Could not classify the replay into a known workflow template.',
413
+ ]
414
+ return {
415
+ replayId: options.replayId,
416
+ url: options.url,
417
+ demonstratedValue,
418
+ clickedTexts,
419
+ inputValues,
420
+ annotations,
421
+ actionKind,
422
+ draftDialogAction,
423
+ confidence: actionKind === 'list-append' && demonstratedValue ? 'high' : clickedTexts.length > 0 ? 'medium' : 'low',
424
+ reasons,
425
+ }
426
+ }
427
+
428
+ function literal(value: unknown): string {
429
+ return JSON.stringify(value, null, 2)
430
+ }
431
+
432
+ function buildListAppendScript(analysis: ReplayWorkflowAnalysis, options: CompileReplayWorkflowOptions): string {
433
+ const valueInputPath = options.valueInputPath || 'value'
434
+ const replayUrl = analysis.url || ''
435
+ const pageKey = (() => {
436
+ if (!replayUrl) {
437
+ return ''
438
+ }
439
+ try {
440
+ const url = new URL(replayUrl)
441
+ const directKey = url.searchParams.get('key')
442
+ if (directKey) {
443
+ return directKey
444
+ }
445
+ const hashQuery = url.hash.includes('?') ? url.hash.slice(url.hash.indexOf('?') + 1) : ''
446
+ return new URLSearchParams(hashQuery).get('key') || ''
447
+ } catch {
448
+ return ''
449
+ }
450
+ })()
451
+ const draftDialogAction = analysis.draftDialogAction || 'restart'
452
+ return [
453
+ '// Generated by replayWorkflow.compile: execute the inferred user flow first, return needs_ai on drift.',
454
+ `const replayAnalysis = ${literal(analysis)};`,
455
+ `const replayUrl = ${literal(replayUrl)};`,
456
+ `const expectedPageKey = ${literal(pageKey)};`,
457
+ `const valueInputPath = ${literal(valueInputPath)};`,
458
+ `const draftDialogAction = ${literal(draftDialogAction)};`,
459
+ '',
460
+ 'function getPathValue(source, path) {',
461
+ ' const parts = String(path || "").split(".").filter((part) => part.length > 0);',
462
+ ' return parts.reduce((current, part) => {',
463
+ ' if (!current || typeof current !== "object") return undefined;',
464
+ ' if (!Object.prototype.hasOwnProperty.call(current, part)) return undefined;',
465
+ ' return current[part];',
466
+ ' }, source);',
467
+ '}',
468
+ '',
469
+ 'function errorMessage(error) {',
470
+ ' if (error && typeof error === "object" && typeof error.message === "string") return error.message;',
471
+ ' return String(error);',
472
+ '}',
473
+ '',
474
+ 'async function readSnapshotText() {',
475
+ ' if (typeof snapshot !== "function") return undefined;',
476
+ ' try {',
477
+ ' const value = await snapshot({ page });',
478
+ ' return (typeof value === "string" ? value : JSON.stringify(value, null, 2)).slice(0, 12000);',
479
+ ' } catch (error) {',
480
+ ' return "snapshot failed: " + errorMessage(error);',
481
+ ' }',
482
+ '}',
483
+ '',
484
+ 'async function needsAi(reason, extra) {',
485
+ ' return {',
486
+ ' status: "needs_ai",',
487
+ ' reason,',
488
+ ' replayAnalysis,',
489
+ ' ...extra,',
490
+ ' context: {',
491
+ ' url: page.url(),',
492
+ ' title: await page.title().catch(() => ""),',
493
+ ' snapshot: await readSnapshotText(),',
494
+ ' },',
495
+ ' };',
496
+ '}',
497
+ '',
498
+ 'async function countVisible(locator) {',
499
+ ' return await locator.evaluateAll((nodes) => nodes.filter((node) => {',
500
+ ' return Boolean(node.offsetWidth || node.offsetHeight || node.getClientRects().length);',
501
+ ' }).length);',
502
+ '}',
503
+ '',
504
+ 'async function clickFirstVisible(candidates, phase) {',
505
+ ' for (let index = 0; index < candidates.length; index += 1) {',
506
+ ' const selector = candidates[index];',
507
+ ' const locator = page.locator(selector);',
508
+ ' if (await countVisible(locator).catch(() => 0)) {',
509
+ ' await locator.first().click();',
510
+ ' return { status: "ok", selector };',
511
+ ' }',
512
+ ' }',
513
+ ' return await needsAi("Expected clickable target was not visible.", { phase, candidates });',
514
+ '}',
515
+ '',
516
+ 'async function dialogText() {',
517
+ ' const dialog = page.locator(".designer-modal, .ant-modal, [role=dialog]").last();',
518
+ ' if (!(await countVisible(dialog).catch(() => 0))) return "";',
519
+ ' return await dialog.innerText().catch(() => "");',
520
+ '}',
521
+ '',
522
+ 'async function waitForConfigValue(value) {',
523
+ ' const detailResponse = await page.waitForResponse((response) => {',
524
+ ' return response.url().includes("/enhancedConfigs/detail?id=") && response.status() === 200;',
525
+ ' }, { timeout: 15000 }).catch((error) => {',
526
+ ' return { error };',
527
+ ' });',
528
+ ' if (detailResponse && detailResponse.error) {',
529
+ ' return { status: "unknown", error: errorMessage(detailResponse.error) };',
530
+ ' }',
531
+ ' try {',
532
+ ' const body = await detailResponse.json();',
533
+ ' const configValue = body && body.data && body.data.config ? body.data.config.value : "";',
534
+ ' return { status: String(configValue).includes(value) ? "matched" : "mismatch", value: configValue };',
535
+ ' } catch (error) {',
536
+ ' return { status: "unknown", error: errorMessage(error) };',
537
+ ' }',
538
+ '}',
539
+ '',
540
+ 'const itemValue = String(getPathValue(input, valueInputPath) ?? input.value ?? input.text ?? "").trim();',
541
+ 'if (!itemValue) {',
542
+ ' return await needsAi("Missing input value for replay-generated workflow.", { phase: "input", valueInputPath });',
543
+ '}',
544
+ 'if (replayUrl && expectedPageKey && !page.url().includes(expectedPageKey)) {',
545
+ ' await page.goto(replayUrl);',
546
+ ' await page.waitForLoadState("domcontentloaded").catch(() => undefined);',
547
+ '}',
548
+ 'if (replayUrl && !expectedPageKey && page.url() === "about:blank") {',
549
+ ' await page.goto(replayUrl);',
550
+ ' await page.waitForLoadState("domcontentloaded").catch(() => undefined);',
551
+ '}',
552
+ 'if (expectedPageKey && !page.url().includes(expectedPageKey)) {',
553
+ ' return await needsAi("Current page does not match replay target config.", { phase: "page-check", expectedPageKey });',
554
+ '}',
555
+ 'if (await page.locator(`text=${itemValue}`).count()) {',
556
+ ' return { status: "completed", reason: "value already exists", value: itemValue, replayAnalysis };',
557
+ '}',
558
+ '',
559
+ 'const alreadyEditing =',
560
+ ' (await countVisible(page.locator("button:has-text(\\"提交\\")")).catch(() => 0)) > 0 ||',
561
+ ' (await countVisible(page.locator("button:has-text(\\"Submit\\")")).catch(() => 0)) > 0 ||',
562
+ ' (await countVisible(page.locator(".designer-formily-array-base-addition")).catch(() => 0)) > 0;',
563
+ 'if (!alreadyEditing) {',
564
+ ' const editResult = await clickFirstVisible([',
565
+ ' "button:has-text(\\"编辑\\")",',
566
+ ' "button:has-text(\\"Edit\\")",',
567
+ ' "button:has-text(\\"重新编辑\\")",',
568
+ ' "button:has-text(\\"Restart\\")",',
569
+ ' ], "enter-edit");',
570
+ ' if (editResult.status !== "ok") return editResult;',
571
+ ' await page.waitForTimeout(800);',
572
+ '',
573
+ ' const draftText = await dialogText();',
574
+ ' if (draftText.includes("继续编辑上次修改") || /continue previous edit|draft/i.test(draftText)) {',
575
+ ' const draftResult = draftDialogAction === "continue"',
576
+ ' ? await clickFirstVisible(["button:has-text(\\"继续编辑\\")", "button:has-text(\\"Continue\\")"], "draft-dialog")',
577
+ ' : await clickFirstVisible(["button:has-text(\\"重新编辑\\")", "button:has-text(\\"Restart\\")"], "draft-dialog");',
578
+ ' if (draftResult.status !== "ok") return draftResult;',
579
+ ' await page.waitForTimeout(800);',
580
+ ' }',
581
+ '}',
582
+ '',
583
+ 'const designerInputs = page.locator("textarea.designer-input");',
584
+ 'const beforeValues = await designerInputs.evaluateAll((nodes) => nodes.map((node) => node.value));',
585
+ 'const addResult = await clickFirstVisible([',
586
+ ' "button:has-text(\\"Add entry\\")",',
587
+ ' "button:has-text(\\"新增\\")",',
588
+ ' "button:has-text(\\"添加\\")",',
589
+ ' ".designer-formily-array-base-addition",',
590
+ '], "add-entry");',
591
+ 'if (addResult.status !== "ok") return addResult;',
592
+ 'await page.waitForTimeout(500);',
593
+ 'const afterAddCount = await designerInputs.count();',
594
+ 'if (afterAddCount <= beforeValues.length) {',
595
+ ' return await needsAi("Add entry did not create a new list input.", { phase: "add-entry", beforeValues, afterAddCount });',
596
+ '}',
597
+ 'const targetInput = designerInputs.nth(afterAddCount - 1);',
598
+ 'await targetInput.fill(itemValue);',
599
+ 'const afterValues = await designerInputs.evaluateAll((nodes) => nodes.map((node) => node.value));',
600
+ 'if (!afterValues.includes(itemValue)) {',
601
+ ' return await needsAi("Filled value was not present in list inputs.", { phase: "fill", afterValues, itemValue });',
602
+ '}',
603
+ '',
604
+ 'const submitResult = await clickFirstVisible(["button:has-text(\\"提交\\")", "button:has-text(\\"Submit\\")"], "submit");',
605
+ 'if (submitResult.status !== "ok") return submitResult;',
606
+ 'await page.waitForTimeout(500);',
607
+ 'const confirmText = await dialogText();',
608
+ 'if (!confirmText.includes(itemValue)) {',
609
+ ' return await needsAi("Confirm diff does not include the new value.", { phase: "confirm-dialog", confirmText, itemValue });',
610
+ '}',
611
+ '',
612
+ 'const updatePromise = page.waitForResponse((response) => {',
613
+ ' return response.url().includes("/enhancedConfigs/update") && response.request().method() === "POST";',
614
+ '}, { timeout: 15000 }).catch((error) => {',
615
+ ' return { error };',
616
+ '});',
617
+ 'const publishPromise = page.waitForResponse((response) => {',
618
+ ' return response.url().includes("/enhancedConfigs/publish") && response.request().method() === "POST";',
619
+ '}, { timeout: 15000 }).catch((error) => {',
620
+ ' return { error };',
621
+ '});',
622
+ 'const detailPromise = waitForConfigValue(itemValue);',
623
+ 'const okResult = await clickFirstVisible(["button:has-text(\\"OK\\")", "button:has-text(\\"确定\\")"], "confirm-ok");',
624
+ 'if (okResult.status !== "ok") return okResult;',
625
+ 'const updateResponse = await updatePromise;',
626
+ 'if (updateResponse && updateResponse.error) {',
627
+ ' return await needsAi("Update request was not observed.", { phase: "update-request", error: errorMessage(updateResponse.error) });',
628
+ '}',
629
+ 'const publishResponse = await publishPromise;',
630
+ 'if (publishResponse && publishResponse.error) {',
631
+ ' return await needsAi("Publish request was not observed.", { phase: "publish-request", error: errorMessage(publishResponse.error) });',
632
+ '}',
633
+ 'const updateBody = await updateResponse.json().catch(() => null);',
634
+ 'const publishBody = await publishResponse.json().catch(() => null);',
635
+ 'if (!updateBody || updateBody.code !== 0) {',
636
+ ' return await needsAi("Update request returned an unexpected body.", { phase: "update-request", updateBody });',
637
+ '}',
638
+ 'if (!publishBody || publishBody.code !== 0 || publishBody.data !== true) {',
639
+ ' return await needsAi("Publish request returned an unexpected body.", { phase: "publish-request", publishBody });',
640
+ '}',
641
+ 'const detail = await detailPromise;',
642
+ 'if (detail.status === "mismatch") {',
643
+ ' return await needsAi("Detail response does not contain the new value.", { phase: "verify", detail, itemValue });',
644
+ '}',
645
+ 'return {',
646
+ ' status: "completed",',
647
+ ' value: itemValue,',
648
+ ' replayAnalysis,',
649
+ ' update: { status: updateResponse.status(), body: updateBody },',
650
+ ' publish: { status: publishResponse.status(), body: publishBody },',
651
+ ' detail,',
652
+ '};',
653
+ '',
654
+ ].join('\n')
655
+ }
656
+
657
+ export function compileReplayWorkflow(options: CompileReplayWorkflowOptions): CompiledReplayWorkflow {
658
+ const replay = getSavedRrwebRecordingWithEvents(options.replayId)
659
+ if (!replay) {
660
+ throw new Error(`Replay recording not found: ${options.replayId}`)
661
+ }
662
+ const analysis = analyzeReplayWorkflow({
663
+ replayId: options.replayId,
664
+ url: replay.recording.url,
665
+ events: replay.events,
666
+ })
667
+ if (analysis.actionKind !== 'list-append') {
668
+ throw new UnsupportedReplayWorkflowError({ analysis })
669
+ }
670
+ const script = buildListAppendScript(analysis, options)
671
+ const saved = saveWorkflowCapability({
672
+ id: options.id,
673
+ title: options.title || `Workflow from replay ${options.replayId}`,
674
+ description:
675
+ options.description ||
676
+ 'Compiled from an rrweb replay. Appends a list item, submits, publishes, and returns needs_ai on page drift.',
677
+ script,
678
+ cwd: options.cwd,
679
+ location: 'project',
680
+ overwrite: options.overwrite,
681
+ sourceRecordingId: options.replayId,
682
+ inputSchema: {
683
+ type: 'object',
684
+ properties: {
685
+ value: { type: 'string' },
686
+ },
687
+ required: ['value'],
688
+ },
689
+ outputSchema: {
690
+ type: 'object',
691
+ properties: {
692
+ status: { type: 'string' },
693
+ value: { type: 'string' },
694
+ },
695
+ },
696
+ match: replay.recording.url ? [replay.recording.url] : [],
697
+ tags: ['rrweb-replay-compiled'],
698
+ })
699
+ return { analysis, saved }
700
+ }