tabwright 1.0.0

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