tabwright 1.0.0 → 1.0.1

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