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,1039 +0,0 @@
1
- import fs from 'node:fs'
2
- import http from 'node:http'
3
- import path from 'node:path'
4
- import util from 'node:util'
5
- import { chromium, type Browser, type Page } from '@xmorse/playwright-core'
6
- import pc from 'picocolors'
7
- import { prepareCapabilityRun, runCapabilityWithExecutor, type CapabilityExecutor } from './capability-runner.js'
8
- import { createReplayAiIndexFromRecording } from './replay-ai-index.js'
9
- import { compileReplayWorkflow } from './replay-workflow-compiler.js'
10
- import type { ExecuteResult } from './executor.js'
11
- import type { RrwebEvent } from './protocol.js'
12
- import { getTabwrightUserDataDir } from './product-paths.js'
13
-
14
- type ReplayEvalExpectedStatus = 'completed' | 'needs_ai' | 'compile_failed'
15
-
16
- type ReplayEvalCase = {
17
- id: string
18
- title: string
19
- description: string
20
- editLabel: string
21
- addLabel: string
22
- submitLabel: string
23
- okLabel: string
24
- demonstratedValue: string
25
- runValue: string
26
- initialValues?: string[]
27
- alreadyEditing?: boolean
28
- draftAction?: 'restart' | 'continue'
29
- brokenAdd?: boolean
30
- unsupported?: boolean
31
- addAnnotation?: boolean
32
- deleteAnnotation?: boolean
33
- expectedStatus: ReplayEvalExpectedStatus
34
- expectedReasonIncludes?: string
35
- expectedAnnotationCount?: number
36
- }
37
-
38
- export type ReplayEvalCaseResult = {
39
- id: string
40
- title: string
41
- status: 'passed' | 'failed'
42
- durationMs: number
43
- replayId: string
44
- phases: Array<'recording' | 'index' | 'compile' | 'run' | 'verify'>
45
- index?: {
46
- actionCount: number
47
- fieldCount: number
48
- annotationCount: number
49
- }
50
- compile?: {
51
- actionKind: string
52
- confidence: string
53
- demonstratedValue?: string
54
- }
55
- run?: {
56
- status?: string
57
- value?: string
58
- reason?: string
59
- completed?: number
60
- total?: number
61
- }
62
- error?: string
63
- }
64
-
65
- export type ReplayEvalReport = {
66
- generatedAt: string
67
- durationMs: number
68
- passed: number
69
- failed: number
70
- total: number
71
- results: ReplayEvalCaseResult[]
72
- artifactsDir: string
73
- }
74
-
75
- export type RunReplayEvalOptions = {
76
- caseId?: string
77
- reportPath?: string
78
- keepArtifacts?: boolean
79
- headed?: boolean
80
- }
81
-
82
- type ExampleCaseState = {
83
- values: string[]
84
- }
85
-
86
- type ExampleServer = {
87
- baseUrl: string
88
- close: () => Promise<void>
89
- }
90
-
91
- type AsyncFunctionConstructor = new (...args: string[]) => (...args: unknown[]) => Promise<unknown>
92
-
93
- const REPLAY_EVAL_CASES: ReplayEvalCase[] = [
94
- {
95
- id: 'zh-list-append',
96
- title: 'Chinese admin list append',
97
- description: '编辑 -> Add entry -> 填值 -> 提交 -> OK',
98
- editLabel: '编辑',
99
- addLabel: 'Add entry',
100
- submitLabel: '提交',
101
- okLabel: 'OK',
102
- demonstratedValue: 'test2',
103
- runValue: 'test3',
104
- expectedStatus: 'completed',
105
- },
106
- {
107
- id: 'en-list-append',
108
- title: 'English list append',
109
- description: 'Edit -> Add entry -> fill -> Submit -> OK',
110
- editLabel: 'Edit',
111
- addLabel: 'Add entry',
112
- submitLabel: 'Submit',
113
- okLabel: 'OK',
114
- demonstratedValue: 'alpha',
115
- runValue: 'beta',
116
- expectedStatus: 'completed',
117
- },
118
- {
119
- id: 'cn-add-confirm',
120
- title: 'Chinese add and confirm labels',
121
- description: '新增/确定 button labels should still compile and run.',
122
- editLabel: '编辑',
123
- addLabel: '新增',
124
- submitLabel: '提交',
125
- okLabel: '确定',
126
- demonstratedValue: '中文值1',
127
- runValue: '中文值2',
128
- expectedStatus: 'completed',
129
- },
130
- {
131
- id: 'already-editing',
132
- title: 'Already editing page',
133
- description: 'Generated script should continue from an already-editing page.',
134
- editLabel: '编辑',
135
- addLabel: 'Add entry',
136
- submitLabel: '提交',
137
- okLabel: 'OK',
138
- demonstratedValue: 'inline-demo',
139
- runValue: 'inline-run',
140
- alreadyEditing: true,
141
- expectedStatus: 'completed',
142
- },
143
- {
144
- id: 'draft-restart',
145
- title: 'Draft dialog restart',
146
- description: 'Replay clicked 重新编辑, so generated script should restart the draft.',
147
- editLabel: '编辑',
148
- addLabel: 'Add entry',
149
- submitLabel: '提交',
150
- okLabel: 'OK',
151
- demonstratedValue: 'restart-demo',
152
- runValue: 'restart-run',
153
- draftAction: 'restart',
154
- expectedStatus: 'completed',
155
- },
156
- {
157
- id: 'draft-continue',
158
- title: 'Draft dialog continue',
159
- description: 'Replay clicked 继续编辑, so generated script should continue the draft.',
160
- editLabel: '编辑',
161
- addLabel: 'Add entry',
162
- submitLabel: '提交',
163
- okLabel: 'OK',
164
- demonstratedValue: 'continue-demo',
165
- runValue: 'continue-run',
166
- draftAction: 'continue',
167
- expectedStatus: 'completed',
168
- },
169
- {
170
- id: 'duplicate-short-circuit',
171
- title: 'Duplicate value short-circuit',
172
- description: 'If the target value is already visible, script should return completed without editing.',
173
- editLabel: '编辑',
174
- addLabel: 'Add entry',
175
- submitLabel: '提交',
176
- okLabel: 'OK',
177
- demonstratedValue: 'existing-demo',
178
- runValue: 'existing-demo',
179
- initialValues: ['existing-demo'],
180
- expectedStatus: 'completed',
181
- },
182
- {
183
- id: 'drift-add-fails',
184
- title: 'Page drift handoff',
185
- description: 'The add button no longer creates an input, so script should return needs_ai.',
186
- editLabel: '编辑',
187
- addLabel: 'Add entry',
188
- submitLabel: '提交',
189
- okLabel: 'OK',
190
- demonstratedValue: 'drift-demo',
191
- runValue: 'drift-run',
192
- brokenAdd: true,
193
- expectedStatus: 'needs_ai',
194
- expectedReasonIncludes: 'Add entry did not create a new list input',
195
- },
196
- {
197
- id: 'annotation-delete-index',
198
- title: 'Deleted annotation index',
199
- description: 'A deleted annotation should not reach AI index output.',
200
- editLabel: '编辑',
201
- addLabel: 'Add entry',
202
- submitLabel: '提交',
203
- okLabel: 'OK',
204
- demonstratedValue: 'annotation-demo',
205
- runValue: 'annotation-run',
206
- addAnnotation: true,
207
- deleteAnnotation: true,
208
- expectedStatus: 'completed',
209
- expectedAnnotationCount: 0,
210
- },
211
- {
212
- id: 'unsupported-click-only',
213
- title: 'Unsupported click-only replay',
214
- description: 'Compiler should fail clearly instead of generating a fake workflow.',
215
- editLabel: '编辑',
216
- addLabel: 'Add entry',
217
- submitLabel: '提交',
218
- okLabel: 'OK',
219
- demonstratedValue: '',
220
- runValue: '',
221
- unsupported: true,
222
- expectedStatus: 'compile_failed',
223
- },
224
- ]
225
-
226
- function ensureDir(dir: string): void {
227
- fs.mkdirSync(dir, { recursive: true })
228
- }
229
-
230
- function createLocalTempDir(prefix: string): string {
231
- const root = path.join(process.cwd(), 'tmp')
232
- ensureDir(root)
233
- return fs.mkdtempSync(path.join(root, prefix))
234
- }
235
-
236
- function writeJson(filePath: string, value: unknown): void {
237
- ensureDir(path.dirname(filePath))
238
- fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`)
239
- }
240
-
241
- function normalizeError(error: unknown): string {
242
- return error instanceof Error ? error.message : String(error)
243
- }
244
-
245
- function textNode(id: number, textContent: string): Record<string, unknown> {
246
- return { id, type: 3, textContent }
247
- }
248
-
249
- function elementNode(options: {
250
- id: number
251
- tagName: string
252
- attributes?: Record<string, string>
253
- childNodes?: Array<Record<string, unknown>>
254
- }): Record<string, unknown> {
255
- return {
256
- id: options.id,
257
- type: 2,
258
- tagName: options.tagName,
259
- attributes: options.attributes || {},
260
- childNodes: options.childNodes || [],
261
- }
262
- }
263
-
264
- function clickEvent(options: { timestamp: number; id: number }): RrwebEvent {
265
- return {
266
- type: 3,
267
- timestamp: options.timestamp,
268
- data: {
269
- source: 2,
270
- type: 2,
271
- id: options.id,
272
- x: 10,
273
- y: 10,
274
- pointerType: 0,
275
- },
276
- }
277
- }
278
-
279
- function inputEvent(options: { timestamp: number; id: number; text: string }): RrwebEvent {
280
- return {
281
- type: 3,
282
- timestamp: options.timestamp,
283
- data: {
284
- source: 5,
285
- id: options.id,
286
- text: options.text,
287
- isChecked: false,
288
- },
289
- }
290
- }
291
-
292
- function annotationEvent(options: { timestamp: number; id: string; text: string }): RrwebEvent {
293
- return {
294
- type: 5,
295
- timestamp: options.timestamp,
296
- data: {
297
- tag: 'playwriter.annotation',
298
- payload: {
299
- schemaVersion: 1,
300
- id: options.id,
301
- text: options.text,
302
- timestamp: options.timestamp,
303
- target: {
304
- tagName: 'textarea',
305
- label: 'List value',
306
- selectorHints: ['textarea.designer-input'],
307
- rect: { x: 10, y: 20, width: 240, height: 32 },
308
- },
309
- },
310
- },
311
- }
312
- }
313
-
314
- function annotationDeleteEvent(options: { timestamp: number; id: string }): RrwebEvent {
315
- return {
316
- type: 5,
317
- timestamp: options.timestamp,
318
- data: {
319
- tag: 'playwriter.annotation.delete',
320
- payload: {
321
- schemaVersion: 1,
322
- id: options.id,
323
- timestamp: options.timestamp,
324
- },
325
- },
326
- }
327
- }
328
-
329
- function createReplayEvents(testCase: ReplayEvalCase): RrwebEvent[] {
330
- const nodes = [
331
- elementNode({ id: 10, tagName: 'button', childNodes: [textNode(11, testCase.editLabel)] }),
332
- elementNode({
333
- id: 12,
334
- tagName: 'button',
335
- attributes: { class: 'designer-btn designer-btn-dangerous' },
336
- childNodes: [textNode(13, testCase.draftAction === 'restart' ? '重新编辑' : 'Restart')],
337
- }),
338
- elementNode({
339
- id: 14,
340
- tagName: 'button',
341
- attributes: { class: 'designer-btn designer-btn-primary' },
342
- childNodes: [textNode(15, testCase.draftAction === 'continue' ? '继续编辑' : 'Continue')],
343
- }),
344
- elementNode({
345
- id: 20,
346
- tagName: 'button',
347
- attributes: { class: 'designer-formily-array-base-addition' },
348
- childNodes: [textNode(21, testCase.addLabel)],
349
- }),
350
- elementNode({ id: 30, tagName: 'textarea', attributes: { class: 'designer-input' } }),
351
- elementNode({ id: 40, tagName: 'button', childNodes: [textNode(41, testCase.submitLabel)] }),
352
- elementNode({
353
- id: 50,
354
- tagName: 'button',
355
- attributes: { class: 'designer-btn designer-btn-primary' },
356
- childNodes: [textNode(51, testCase.okLabel)],
357
- }),
358
- ]
359
- const events: RrwebEvent[] = [
360
- {
361
- type: 2,
362
- timestamp: 1000,
363
- data: {
364
- node: {
365
- id: 1,
366
- type: 0,
367
- childNodes: [
368
- {
369
- id: 2,
370
- type: 1,
371
- childNodes: [
372
- elementNode({
373
- id: 3,
374
- tagName: 'body',
375
- childNodes: nodes,
376
- }),
377
- ],
378
- },
379
- ],
380
- },
381
- },
382
- },
383
- ]
384
- if (testCase.unsupported) {
385
- events.push(clickEvent({ timestamp: 1100, id: 10 }))
386
- return events
387
- }
388
- if (!testCase.alreadyEditing) {
389
- events.push(clickEvent({ timestamp: 1100, id: 10 }))
390
- }
391
- if (testCase.draftAction === 'restart') {
392
- events.push(clickEvent({ timestamp: 1200, id: 12 }))
393
- }
394
- if (testCase.draftAction === 'continue') {
395
- events.push(clickEvent({ timestamp: 1200, id: 14 }))
396
- }
397
- events.push(clickEvent({ timestamp: 1300, id: 20 }))
398
- events.push(inputEvent({ timestamp: 1400, id: 30, text: testCase.demonstratedValue }))
399
- if (testCase.addAnnotation) {
400
- events.push(annotationEvent({ timestamp: 1450, id: `${testCase.id}-annotation`, text: '重点填写这个列表项' }))
401
- }
402
- if (testCase.deleteAnnotation) {
403
- events.push(annotationDeleteEvent({ timestamp: 1460, id: `${testCase.id}-annotation` }))
404
- }
405
- events.push(clickEvent({ timestamp: 1500, id: 40 }))
406
- events.push(clickEvent({ timestamp: 1600, id: 50 }))
407
- return events
408
- }
409
-
410
- function htmlEscape(value: string): string {
411
- return value
412
- .replace(/&/g, '&amp;')
413
- .replace(/</g, '&lt;')
414
- .replace(/>/g, '&gt;')
415
- .replace(/"/g, '&quot;')
416
- .replace(/'/g, '&#39;')
417
- }
418
-
419
- function buildExampleHtml(testCase: ReplayEvalCase, state: ExampleCaseState): string {
420
- const config = {
421
- id: testCase.id,
422
- labels: {
423
- edit: testCase.editLabel,
424
- add: testCase.addLabel,
425
- submit: testCase.submitLabel,
426
- ok: testCase.okLabel,
427
- restart: testCase.draftAction === 'restart' ? '重新编辑' : 'Restart',
428
- continue: testCase.draftAction === 'continue' ? '继续编辑' : 'Continue',
429
- },
430
- initialValues: state.values,
431
- alreadyEditing: Boolean(testCase.alreadyEditing),
432
- draftAction: testCase.draftAction || null,
433
- brokenAdd: Boolean(testCase.brokenAdd),
434
- }
435
- return `<!doctype html>
436
- <html>
437
- <head>
438
- <meta charset="utf-8" />
439
- <title>${htmlEscape(testCase.title)}</title>
440
- <style>
441
- body { font-family: system-ui, sans-serif; padding: 24px; color: #172033; }
442
- button { margin: 6px; padding: 7px 12px; border: 1px solid #cbd5e1; border-radius: 6px; background: white; cursor: pointer; }
443
- textarea { display: block; width: 320px; min-height: 36px; margin: 8px 0; border: 1px solid #cbd5e1; border-radius: 6px; padding: 7px; }
444
- .designer-modal { position: fixed; inset: auto 24px 24px auto; width: 360px; padding: 16px; border: 1px solid #cbd5e1; border-radius: 8px; background: white; box-shadow: 0 18px 48px rgba(15,23,42,.18); }
445
- .readonly-value { padding: 4px 0; }
446
- </style>
447
- </head>
448
- <body>
449
- <h1>${htmlEscape(testCase.title)}</h1>
450
- <div id="app"></div>
451
- <script>
452
- const config = ${JSON.stringify(config)};
453
- const app = document.getElementById('app');
454
- const state = {
455
- values: [...config.initialValues],
456
- editing: config.alreadyEditing,
457
- draftShown: false,
458
- };
459
- function renderReadOnly() {
460
- app.innerHTML = '<button id="edit">' + config.labels.edit + '</button><div id="values"></div>';
461
- const values = document.getElementById('values');
462
- state.values.forEach((value) => {
463
- const item = document.createElement('div');
464
- item.className = 'readonly-value';
465
- item.textContent = value;
466
- values.appendChild(item);
467
- });
468
- document.getElementById('edit').addEventListener('click', () => {
469
- if (config.draftAction && !state.draftShown) {
470
- state.draftShown = true;
471
- renderDraftDialog();
472
- return;
473
- }
474
- state.editing = true;
475
- render();
476
- });
477
- }
478
- function renderDraftDialog() {
479
- renderReadOnly();
480
- const modal = document.createElement('div');
481
- modal.className = 'designer-modal';
482
- modal.innerHTML = '<p>继续编辑上次修改 / Continue previous edit draft</p><button class="designer-btn designer-btn-dangerous" id="restart">' + config.labels.restart + '</button><button class="designer-btn designer-btn-primary" id="continue">' + config.labels.continue + '</button>';
483
- document.body.appendChild(modal);
484
- document.getElementById('restart').addEventListener('click', () => {
485
- modal.remove();
486
- state.values = [];
487
- state.editing = true;
488
- render();
489
- });
490
- document.getElementById('continue').addEventListener('click', () => {
491
- modal.remove();
492
- state.editing = true;
493
- render();
494
- });
495
- }
496
- function renderEditor() {
497
- app.innerHTML = '<div id="editor"></div><button class="designer-formily-array-base-addition" id="add">' + config.labels.add + '</button><button id="submit">' + config.labels.submit + '</button>';
498
- const editor = document.getElementById('editor');
499
- state.values.forEach((value, index) => {
500
- const input = document.createElement('textarea');
501
- input.className = 'designer-input';
502
- input.value = value;
503
- input.addEventListener('input', () => {
504
- state.values[index] = input.value;
505
- });
506
- editor.appendChild(input);
507
- });
508
- document.getElementById('add').addEventListener('click', () => {
509
- if (!config.brokenAdd) {
510
- state.values.push('');
511
- }
512
- render();
513
- });
514
- document.getElementById('submit').addEventListener('click', () => {
515
- renderConfirm();
516
- });
517
- }
518
- function renderConfirm() {
519
- const modal = document.createElement('div');
520
- modal.className = 'designer-modal';
521
- modal.innerHTML = '<p>Confirm values: ' + state.values.join(', ') + '</p><button class="designer-btn designer-btn-primary" id="ok">' + config.labels.ok + '</button>';
522
- document.body.appendChild(modal);
523
- document.getElementById('ok').addEventListener('click', async () => {
524
- await fetch('/enhancedConfigs/update', {
525
- method: 'POST',
526
- headers: { 'content-type': 'application/json' },
527
- body: JSON.stringify({ caseId: config.id, values: state.values }),
528
- });
529
- await fetch('/enhancedConfigs/publish', { method: 'POST' });
530
- await fetch('/enhancedConfigs/detail?id=' + encodeURIComponent(config.id));
531
- modal.remove();
532
- state.editing = false;
533
- render();
534
- });
535
- }
536
- function render() {
537
- if (state.editing) {
538
- renderEditor();
539
- return;
540
- }
541
- renderReadOnly();
542
- }
543
- render();
544
- </script>
545
- </body>
546
- </html>`
547
- }
548
-
549
- function requestBody(request: http.IncomingMessage): Promise<string> {
550
- return new Promise((resolve, reject) => {
551
- const chunks: Buffer[] = []
552
- request.on('data', (chunk: Buffer) => {
553
- chunks.push(chunk)
554
- })
555
- request.on('end', () => {
556
- resolve(Buffer.concat(chunks).toString('utf-8'))
557
- })
558
- request.on('error', (error) => {
559
- reject(error)
560
- })
561
- })
562
- }
563
-
564
- async function startExampleServer(cases: ReplayEvalCase[]): Promise<ExampleServer> {
565
- const casesById = new Map(
566
- cases.map((testCase) => {
567
- return [testCase.id, testCase] as const
568
- }),
569
- )
570
- const states: Map<string, ExampleCaseState> = new Map(
571
- cases.map((testCase) => {
572
- const state: ExampleCaseState = { values: [...(testCase.initialValues || [])] }
573
- return [testCase.id, state]
574
- }),
575
- )
576
- const server = http.createServer((request, response) => {
577
- const host = request.headers.host || 'localhost'
578
- const url = new URL(request.url || '/', `http://${host}`)
579
- const sendJson = (statusCode: number, value: unknown): void => {
580
- response.writeHead(statusCode, { 'content-type': 'application/json' })
581
- response.end(JSON.stringify(value))
582
- }
583
- if (request.method === 'GET' && url.pathname.startsWith('/case/')) {
584
- const caseId = decodeURIComponent(url.pathname.slice('/case/'.length))
585
- const testCase = casesById.get(caseId)
586
- const state = states.get(caseId)
587
- if (!testCase || !state) {
588
- response.writeHead(404)
589
- response.end('Not found')
590
- return
591
- }
592
- response.writeHead(200, { 'content-type': 'text/html; charset=utf-8' })
593
- response.end(buildExampleHtml(testCase, state))
594
- return
595
- }
596
- if (request.method === 'POST' && url.pathname === '/enhancedConfigs/update') {
597
- requestBody(request)
598
- .then((body) => {
599
- const parsed = JSON.parse(body || '{}') as { caseId?: unknown; values?: unknown }
600
- const caseId = typeof parsed.caseId === 'string' ? parsed.caseId : ''
601
- const state = states.get(caseId)
602
- if (state && Array.isArray(parsed.values)) {
603
- state.values = parsed.values.map((value) => {
604
- return String(value)
605
- })
606
- }
607
- sendJson(200, { code: 0, data: true })
608
- })
609
- .catch((error: unknown) => {
610
- sendJson(500, { code: 1, message: normalizeError(error) })
611
- })
612
- return
613
- }
614
- if (request.method === 'POST' && url.pathname === '/enhancedConfigs/publish') {
615
- sendJson(200, { code: 0, data: true })
616
- return
617
- }
618
- if (request.method === 'GET' && url.pathname === '/enhancedConfigs/detail') {
619
- const caseId = url.searchParams.get('id') || ''
620
- const state = states.get(caseId)
621
- sendJson(200, {
622
- code: 0,
623
- data: {
624
- config: {
625
- value: JSON.stringify(state?.values || []),
626
- },
627
- },
628
- })
629
- return
630
- }
631
- response.writeHead(404)
632
- response.end('Not found')
633
- })
634
-
635
- await new Promise<void>((resolve, reject) => {
636
- server.on('error', reject)
637
- server.listen(0, '127.0.0.1', () => {
638
- resolve()
639
- })
640
- })
641
- const address = server.address()
642
- if (!address || typeof address === 'string') {
643
- throw new Error('Replay eval server did not expose a TCP port')
644
- }
645
- return {
646
- baseUrl: `http://127.0.0.1:${address.port}`,
647
- close: async () => {
648
- await new Promise<void>((resolve, reject) => {
649
- server.close((error) => {
650
- if (error) {
651
- reject(error)
652
- return
653
- }
654
- resolve()
655
- })
656
- })
657
- },
658
- }
659
- }
660
-
661
- function getChromeExecutable(): string | undefined {
662
- const candidates = [
663
- process.env.TABWRIGHT_TEST_CHROME || process.env.PLAYWRITER_TEST_CHROME,
664
- '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
665
- '/Applications/Chromium.app/Contents/MacOS/Chromium',
666
- '/usr/bin/google-chrome',
667
- '/usr/bin/google-chrome-stable',
668
- '/usr/bin/chromium',
669
- '/usr/bin/chromium-browser',
670
- 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
671
- 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
672
- ].filter((candidate): candidate is string => {
673
- return Boolean(candidate)
674
- })
675
- return candidates.find((candidate) => {
676
- return fs.existsSync(candidate)
677
- })
678
- }
679
-
680
- async function launchEvalBrowser(options: { headed?: boolean }): Promise<Browser> {
681
- const executablePath = getChromeExecutable()
682
- return await chromium.launch({
683
- ...(executablePath ? { executablePath } : { channel: 'chromium' }),
684
- headless: !options.headed,
685
- })
686
- }
687
-
688
- function formatOutput(value: unknown): string {
689
- return `[return value] ${util.inspect(value, {
690
- depth: 5,
691
- colors: false,
692
- maxArrayLength: 80,
693
- maxStringLength: 2000,
694
- breakLength: 100,
695
- })}`
696
- }
697
-
698
- class PageEvalExecutor implements CapabilityExecutor {
699
- constructor(private page: Page) {}
700
-
701
- async execute(code: string, timeout = 15000): Promise<ExecuteResult> {
702
- const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor as AsyncFunctionConstructor
703
- const runner = new AsyncFunction(
704
- 'page',
705
- 'snapshot',
706
- 'console',
707
- 'setTimeout',
708
- 'clearTimeout',
709
- 'URL',
710
- 'URLSearchParams',
711
- 'fetch',
712
- 'Buffer',
713
- code,
714
- )
715
- const snapshot = async (): Promise<string> => {
716
- return await this.page.locator('body').innerText({ timeout: 2000 }).catch((error: unknown) => {
717
- return `snapshot failed: ${normalizeError(error)}`
718
- })
719
- }
720
- try {
721
- const structuredResult = await Promise.race([
722
- runner(this.page, snapshot, console, setTimeout, clearTimeout, URL, URLSearchParams, fetch, Buffer),
723
- new Promise((_, reject) => {
724
- setTimeout(() => {
725
- reject(new Error(`Replay eval execution timed out after ${timeout}ms`))
726
- }, timeout)
727
- }),
728
- ])
729
- return {
730
- text: formatOutput(structuredResult),
731
- images: [],
732
- screenshots: [],
733
- isError: false,
734
- structuredResult: JSON.parse(JSON.stringify(structuredResult)),
735
- }
736
- } catch (error: unknown) {
737
- return {
738
- text: normalizeError(error),
739
- images: [],
740
- screenshots: [],
741
- isError: true,
742
- }
743
- }
744
- }
745
- }
746
-
747
- function writeRecording(options: {
748
- home: string
749
- replayId: string
750
- url: string
751
- events: RrwebEvent[]
752
- }): void {
753
- const recordingsDir = path.join(getTabwrightUserDataDir({ homeDir: options.home }), 'rrweb-recordings')
754
- const recordingPath = path.join(recordingsDir, `${options.replayId}.json`)
755
- writeJson(recordingPath, options.events)
756
- writeJson(path.join(recordingsDir, 'index.json'), [
757
- {
758
- id: options.replayId,
759
- path: recordingPath,
760
- startedAt: 1000,
761
- savedAt: 2000,
762
- duration: 1000,
763
- size: fs.statSync(recordingPath).size,
764
- eventCount: options.events.length,
765
- tabId: 1,
766
- url: options.url,
767
- },
768
- ])
769
- }
770
-
771
- function getOutputStatus(output: unknown): string | undefined {
772
- if (!output || typeof output !== 'object') {
773
- return undefined
774
- }
775
- const candidate = output as { status?: unknown }
776
- return typeof candidate.status === 'string' ? candidate.status : undefined
777
- }
778
-
779
- function outputField(output: unknown, key: string): string | undefined {
780
- if (!output || typeof output !== 'object') {
781
- return undefined
782
- }
783
- const value = (output as Record<string, unknown>)[key]
784
- return typeof value === 'string' ? value : undefined
785
- }
786
-
787
- function outputNumberField(output: unknown, key: string): number | undefined {
788
- if (!output || typeof output !== 'object') {
789
- return undefined
790
- }
791
- const value = (output as Record<string, unknown>)[key]
792
- return typeof value === 'number' ? value : undefined
793
- }
794
-
795
- function assertCaseResult(options: { testCase: ReplayEvalCase; output: unknown; annotationCount: number }): void {
796
- if (options.testCase.expectedAnnotationCount !== undefined && options.annotationCount !== options.testCase.expectedAnnotationCount) {
797
- throw new Error(`Expected ${options.testCase.expectedAnnotationCount} annotations, got ${options.annotationCount}`)
798
- }
799
- const status = getOutputStatus(options.output)
800
- if (status !== options.testCase.expectedStatus) {
801
- throw new Error(`Expected run status ${options.testCase.expectedStatus}, got ${status || 'undefined'}`)
802
- }
803
- if (options.testCase.expectedReasonIncludes) {
804
- const reason = outputField(options.output, 'reason') || ''
805
- const needsAi = options.output && typeof options.output === 'object' ? (options.output as Record<string, unknown>).needsAi : undefined
806
- const nestedReason = outputField(needsAi, 'reason') || ''
807
- if (!reason.includes(options.testCase.expectedReasonIncludes) && !nestedReason.includes(options.testCase.expectedReasonIncludes)) {
808
- throw new Error(`Expected reason to include "${options.testCase.expectedReasonIncludes}", got "${reason || nestedReason}"`)
809
- }
810
- }
811
- }
812
-
813
- async function runOneEvalCase(options: {
814
- testCase: ReplayEvalCase
815
- server: ExampleServer
816
- browser: Browser
817
- artifactsDir: string
818
- }): Promise<ReplayEvalCaseResult> {
819
- const start = Date.now()
820
- const phases: ReplayEvalCaseResult['phases'] = []
821
- const replayId = `eval-${options.testCase.id}`
822
- const home = path.join(options.artifactsDir, replayId, 'home')
823
- const cwd = path.join(options.artifactsDir, replayId, 'cwd')
824
- ensureDir(home)
825
- ensureDir(cwd)
826
- const previousHome = process.env.HOME
827
- const url = `${options.server.baseUrl}/case/${encodeURIComponent(options.testCase.id)}?key=${encodeURIComponent(options.testCase.id)}`
828
- try {
829
- process.env.HOME = home
830
- const events = createReplayEvents(options.testCase)
831
- writeRecording({ home, replayId, url, events })
832
- phases.push('recording')
833
-
834
- const index = createReplayAiIndexFromRecording(replayId)
835
- phases.push('index')
836
-
837
- if (options.testCase.expectedStatus === 'compile_failed') {
838
- try {
839
- compileReplayWorkflow({ replayId, id: `${options.testCase.id}-capability`, cwd, overwrite: true })
840
- } catch (error: unknown) {
841
- phases.push('compile')
842
- return {
843
- id: options.testCase.id,
844
- title: options.testCase.title,
845
- status: 'passed',
846
- durationMs: Date.now() - start,
847
- replayId,
848
- phases,
849
- index: {
850
- actionCount: index.actions.length,
851
- fieldCount: index.fields.length,
852
- annotationCount: index.annotations.length,
853
- },
854
- error: normalizeError(error),
855
- }
856
- }
857
- throw new Error('Expected replay compiler to fail, but it produced a capability')
858
- }
859
-
860
- const compiled = compileReplayWorkflow({ replayId, id: `${options.testCase.id}-capability`, cwd, overwrite: true })
861
- phases.push('compile')
862
-
863
- const page = await options.browser.newPage()
864
- try {
865
- await page.goto(url)
866
- const executor = new PageEvalExecutor(page)
867
- const runResult = await runCapabilityWithExecutor({
868
- executor,
869
- id: `${options.testCase.id}-capability`,
870
- input: { value: options.testCase.runValue },
871
- cwd,
872
- force: true,
873
- confirmation: `${options.testCase.id}-capability`,
874
- timeout: 20000,
875
- })
876
- phases.push('run')
877
- assertCaseResult({
878
- testCase: options.testCase,
879
- output: runResult.output,
880
- annotationCount: index.annotations.length,
881
- })
882
- phases.push('verify')
883
- return {
884
- id: options.testCase.id,
885
- title: options.testCase.title,
886
- status: 'passed',
887
- durationMs: Date.now() - start,
888
- replayId,
889
- phases,
890
- index: {
891
- actionCount: index.actions.length,
892
- fieldCount: index.fields.length,
893
- annotationCount: index.annotations.length,
894
- },
895
- compile: {
896
- actionKind: compiled.analysis.actionKind,
897
- confidence: compiled.analysis.confidence,
898
- demonstratedValue: compiled.analysis.demonstratedValue,
899
- },
900
- run: {
901
- status: getOutputStatus(runResult.output),
902
- value: outputField(runResult.output, 'value'),
903
- reason: outputField(runResult.output, 'reason'),
904
- completed: outputNumberField(runResult.output, 'completed'),
905
- total: outputNumberField(runResult.output, 'total'),
906
- },
907
- }
908
- } finally {
909
- await page.close().catch(() => {})
910
- }
911
- } catch (error: unknown) {
912
- return {
913
- id: options.testCase.id,
914
- title: options.testCase.title,
915
- status: 'failed',
916
- durationMs: Date.now() - start,
917
- replayId,
918
- phases,
919
- error: normalizeError(error),
920
- }
921
- } finally {
922
- if (previousHome === undefined) {
923
- delete process.env.HOME
924
- } else {
925
- process.env.HOME = previousHome
926
- }
927
- }
928
- }
929
-
930
- function renderReportHtml(report: ReplayEvalReport): string {
931
- const rows = report.results
932
- .map((result) => {
933
- const statusColor = result.status === 'passed' ? '#15803d' : '#b91c1c'
934
- return `<tr>
935
- <td>${htmlEscape(result.id)}</td>
936
- <td>${htmlEscape(result.title)}</td>
937
- <td style="color:${statusColor};font-weight:700">${htmlEscape(result.status)}</td>
938
- <td>${result.durationMs}ms</td>
939
- <td>${htmlEscape(result.phases.join(' -> '))}</td>
940
- <td>${htmlEscape(result.run?.status || result.error || '-')}</td>
941
- </tr>`
942
- })
943
- .join('\n')
944
- return `<!doctype html>
945
- <html>
946
- <head>
947
- <meta charset="utf-8" />
948
- <title>Tabwright Replay Eval</title>
949
- <style>
950
- body { font-family: ui-sans-serif, system-ui, sans-serif; margin: 32px; color: #172033; }
951
- table { border-collapse: collapse; width: 100%; }
952
- th, td { border-bottom: 1px solid #e2e8f0; padding: 8px; text-align: left; vertical-align: top; }
953
- th { background: #f8fafc; font-size: 12px; text-transform: uppercase; color: #64748b; }
954
- .summary { margin-bottom: 18px; padding: 14px; border: 1px solid #e2e8f0; border-radius: 8px; background: #f8fafc; }
955
- </style>
956
- </head>
957
- <body>
958
- <h1>Tabwright Replay Eval</h1>
959
- <div class="summary">
960
- <strong>${report.passed}/${report.total} passed</strong>
961
- <span>generated ${htmlEscape(report.generatedAt)}</span>
962
- <span>duration ${report.durationMs}ms</span>
963
- <span>artifacts ${htmlEscape(report.artifactsDir)}</span>
964
- </div>
965
- <table>
966
- <thead>
967
- <tr><th>Case</th><th>Title</th><th>Status</th><th>Duration</th><th>Phases</th><th>Run/Error</th></tr>
968
- </thead>
969
- <tbody>${rows}</tbody>
970
- </table>
971
- </body>
972
- </html>`
973
- }
974
-
975
- export async function runReplayEval(options: RunReplayEvalOptions = {}): Promise<ReplayEvalReport> {
976
- const selectedCases = options.caseId
977
- ? REPLAY_EVAL_CASES.filter((testCase) => {
978
- return testCase.id === options.caseId
979
- })
980
- : REPLAY_EVAL_CASES
981
- if (selectedCases.length === 0) {
982
- throw new Error(`Replay eval case not found: ${options.caseId}`)
983
- }
984
- const start = Date.now()
985
- const artifactsDir = createLocalTempDir('replay-eval-')
986
- const server = await startExampleServer(selectedCases)
987
- const browser = await launchEvalBrowser({ headed: options.headed })
988
- try {
989
- const results: ReplayEvalCaseResult[] = []
990
- for (const testCase of selectedCases) {
991
- results.push(
992
- await runOneEvalCase({
993
- testCase,
994
- server,
995
- browser,
996
- artifactsDir,
997
- }),
998
- )
999
- }
1000
- const passed = results.filter((result) => {
1001
- return result.status === 'passed'
1002
- }).length
1003
- const report: ReplayEvalReport = {
1004
- generatedAt: new Date().toISOString(),
1005
- durationMs: Date.now() - start,
1006
- passed,
1007
- failed: results.length - passed,
1008
- total: results.length,
1009
- results,
1010
- artifactsDir,
1011
- }
1012
- if (options.reportPath) {
1013
- ensureDir(path.dirname(options.reportPath))
1014
- fs.writeFileSync(options.reportPath, renderReportHtml(report))
1015
- }
1016
- if (!options.keepArtifacts) {
1017
- fs.rmSync(artifactsDir, { recursive: true, force: true })
1018
- return { ...report, artifactsDir: `${artifactsDir} (removed)` }
1019
- }
1020
- return report
1021
- } finally {
1022
- await browser.close().catch(() => {})
1023
- await server.close().catch(() => {})
1024
- }
1025
- }
1026
-
1027
- export function formatReplayEvalReport(report: ReplayEvalReport): string {
1028
- const lines = [
1029
- `Replay eval: ${report.passed}/${report.total} passed in ${report.durationMs}ms`,
1030
- `Artifacts: ${report.artifactsDir}`,
1031
- '',
1032
- ...report.results.map((result) => {
1033
- const status = result.status === 'passed' ? pc.green('PASS') : pc.red('FAIL')
1034
- const detail = result.error || result.run?.status || ''
1035
- return `${status} ${result.id} (${result.durationMs}ms) ${detail}`
1036
- }),
1037
- ]
1038
- return lines.join('\n')
1039
- }