tabwright 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (568) hide show
  1. package/dist/agent-skills/tabwright/SKILL.md +3 -0
  2. package/dist/aria-snapshot.d.ts +0 -1
  3. package/dist/aria-snapshot.js +9 -1
  4. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts +0 -1
  5. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js +0 -1
  6. package/dist/bippy.js +5 -5
  7. package/dist/browser-config.d.ts +0 -1
  8. package/dist/browser-config.js +0 -1
  9. package/dist/browser-install.d.ts +0 -1
  10. package/dist/browser-install.js +0 -1
  11. package/dist/browser-launch.d.ts +0 -1
  12. package/dist/browser-launch.js +0 -1
  13. package/dist/capability-agent-skill.d.ts +0 -1
  14. package/dist/capability-agent-skill.js +0 -1
  15. package/dist/capability-auth-state.d.ts +0 -1
  16. package/dist/capability-auth-state.js +0 -1
  17. package/dist/capability-auth.d.ts +0 -1
  18. package/dist/capability-auth.js +0 -1
  19. package/dist/capability-options.d.ts +0 -1
  20. package/dist/capability-options.js +0 -1
  21. package/dist/capability-package.d.ts +0 -1
  22. package/dist/capability-package.js +47 -2
  23. package/dist/capability-registry.d.ts +0 -1
  24. package/dist/capability-registry.js +0 -1
  25. package/dist/capability-runner.d.ts +0 -1
  26. package/dist/capability-runner.js +0 -1
  27. package/dist/capability-studio.d.ts +0 -1
  28. package/dist/capability-studio.js +0 -1
  29. package/dist/cdp-log.d.ts +0 -1
  30. package/dist/cdp-log.js +0 -1
  31. package/dist/cdp-relay.d.ts +0 -1
  32. package/dist/cdp-relay.js +0 -1
  33. package/dist/cdp-session.d.ts +0 -1
  34. package/dist/cdp-session.js +0 -1
  35. package/dist/cdp-types.d.ts +0 -1
  36. package/dist/cdp-types.js +0 -1
  37. package/dist/chrome-discovery.d.ts +0 -1
  38. package/dist/chrome-discovery.js +0 -1
  39. package/dist/clean-html.d.ts +0 -1
  40. package/dist/clean-html.js +0 -1
  41. package/dist/cli.d.ts +0 -1
  42. package/dist/cli.js +10 -56
  43. package/dist/cloud-client.d.ts +0 -1
  44. package/dist/cloud-client.js +0 -1
  45. package/dist/create-logger.d.ts +0 -1
  46. package/dist/create-logger.js +0 -1
  47. package/dist/debugger-examples-types.d.ts +0 -1
  48. package/dist/debugger-examples-types.js +0 -1
  49. package/dist/debugger-examples.d.ts +0 -1
  50. package/dist/debugger-examples.js +0 -1
  51. package/dist/debugger.d.ts +0 -1
  52. package/dist/debugger.js +0 -1
  53. package/dist/diff-utils.d.ts +0 -1
  54. package/dist/diff-utils.js +0 -1
  55. package/dist/doctor.d.ts +0 -1
  56. package/dist/doctor.js +5 -7
  57. package/dist/editor-examples.d.ts +0 -1
  58. package/dist/editor-examples.js +0 -1
  59. package/dist/editor.d.ts +0 -1
  60. package/dist/editor.js +0 -1
  61. package/dist/env-compat.d.ts +0 -1
  62. package/dist/env-compat.js +0 -1
  63. package/dist/executor.d.ts +0 -1
  64. package/dist/executor.js +1 -2
  65. package/dist/extension/background.js +10 -6
  66. package/dist/extension/manifest.json +1 -1
  67. package/dist/extension/options.js +1 -1
  68. package/dist/extension/rrweb-recorder.js +1 -1
  69. package/dist/ghost-browser.d.ts +0 -1
  70. package/dist/ghost-browser.js +0 -1
  71. package/dist/ghost-cursor-controller.d.ts +0 -1
  72. package/dist/ghost-cursor-controller.js +0 -1
  73. package/dist/ghost-cursor.d.ts +0 -1
  74. package/dist/ghost-cursor.js +0 -1
  75. package/dist/htmlrewrite.d.ts +0 -1
  76. package/dist/htmlrewrite.js +0 -1
  77. package/dist/index.d.ts +0 -1
  78. package/dist/index.js +0 -1
  79. package/dist/kill-port.d.ts +0 -1
  80. package/dist/kill-port.js +0 -1
  81. package/dist/kitty-graphics.d.ts +0 -1
  82. package/dist/kitty-graphics.js +0 -1
  83. package/dist/mcp.d.ts +0 -1
  84. package/dist/mcp.js +0 -1
  85. package/dist/package-paths.d.ts +0 -1
  86. package/dist/package-paths.js +0 -1
  87. package/dist/page-markdown.d.ts +0 -1
  88. package/dist/page-markdown.js +0 -1
  89. package/dist/performance-examples.d.ts +0 -1
  90. package/dist/performance-examples.js +0 -1
  91. package/dist/playwright-import.d.ts +0 -1
  92. package/dist/playwright-import.js +0 -1
  93. package/dist/product-paths.d.ts +0 -1
  94. package/dist/product-paths.js +0 -1
  95. package/dist/protocol.d.ts +0 -1
  96. package/dist/protocol.js +0 -1
  97. package/dist/react-source.d.ts +0 -1
  98. package/dist/react-source.js +0 -1
  99. package/dist/readability.js +4 -4
  100. package/dist/relay-client.d.ts +0 -1
  101. package/dist/relay-client.js +0 -1
  102. package/dist/relay-state.d.ts +0 -1
  103. package/dist/relay-state.js +0 -1
  104. package/dist/replay-ai-index.d.ts +0 -1
  105. package/dist/replay-ai-index.js +0 -1
  106. package/dist/replay-eval.d.ts +0 -1
  107. package/dist/replay-eval.js +0 -1
  108. package/dist/replay-handoff.d.ts +0 -1
  109. package/dist/replay-handoff.js +0 -1
  110. package/dist/replay-workflow-compiler.d.ts +0 -1
  111. package/dist/replay-workflow-compiler.js +0 -1
  112. package/dist/rrweb-recording-relay.d.ts +0 -1
  113. package/dist/rrweb-recording-relay.js +0 -1
  114. package/dist/rrweb-recording.d.ts +0 -1
  115. package/dist/rrweb-recording.js +0 -1
  116. package/dist/scoped-fs.d.ts +0 -1
  117. package/dist/scoped-fs.js +0 -1
  118. package/dist/selector-generator.js +2 -2
  119. package/dist/start-relay-server.d.ts +0 -1
  120. package/dist/start-relay-server.js +0 -1
  121. package/dist/styles-examples.d.ts +0 -1
  122. package/dist/styles-examples.js +0 -1
  123. package/dist/styles.d.ts +0 -1
  124. package/dist/styles.js +0 -1
  125. package/dist/tabwright-agent-skill.d.ts +0 -1
  126. package/dist/tabwright-agent-skill.js +0 -1
  127. package/dist/test-declarations.d.ts +0 -1
  128. package/dist/test-declarations.js +0 -1
  129. package/dist/utils.d.ts +0 -1
  130. package/dist/utils.js +2 -2
  131. package/dist/wait-for-page-load.d.ts +0 -1
  132. package/dist/wait-for-page-load.js +0 -1
  133. package/dist/workflow-capability.d.ts +0 -1
  134. package/dist/workflow-capability.js +0 -1
  135. package/package.json +8 -4
  136. package/readme.md +43 -0
  137. package/src/skill.md +5 -2
  138. package/dist/aria-snapshot.d.ts.map +0 -1
  139. package/dist/aria-snapshot.js.map +0 -1
  140. package/dist/aria-snapshot.test.d.ts +0 -2
  141. package/dist/aria-snapshot.test.d.ts.map +0 -1
  142. package/dist/aria-snapshot.test.js +0 -270
  143. package/dist/aria-snapshot.test.js.map +0 -1
  144. package/dist/aria-snapshot.unit.test.d.ts +0 -2
  145. package/dist/aria-snapshot.unit.test.d.ts.map +0 -1
  146. package/dist/aria-snapshot.unit.test.js +0 -542
  147. package/dist/aria-snapshot.unit.test.js.map +0 -1
  148. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts.map +0 -1
  149. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js.map +0 -1
  150. package/dist/browser-config.d.ts.map +0 -1
  151. package/dist/browser-config.js.map +0 -1
  152. package/dist/browser-install.d.ts.map +0 -1
  153. package/dist/browser-install.js.map +0 -1
  154. package/dist/browser-launch.d.ts.map +0 -1
  155. package/dist/browser-launch.js.map +0 -1
  156. package/dist/builtin-capabilities.d.ts +0 -28
  157. package/dist/builtin-capabilities.d.ts.map +0 -1
  158. package/dist/builtin-capabilities.js +0 -2673
  159. package/dist/builtin-capabilities.js.map +0 -1
  160. package/dist/capability-agent-skill.d.ts.map +0 -1
  161. package/dist/capability-agent-skill.js.map +0 -1
  162. package/dist/capability-auth-state.d.ts.map +0 -1
  163. package/dist/capability-auth-state.js.map +0 -1
  164. package/dist/capability-auth.d.ts.map +0 -1
  165. package/dist/capability-auth.js.map +0 -1
  166. package/dist/capability-cli-confirmation.test.d.ts +0 -2
  167. package/dist/capability-cli-confirmation.test.d.ts.map +0 -1
  168. package/dist/capability-cli-confirmation.test.js +0 -79
  169. package/dist/capability-cli-confirmation.test.js.map +0 -1
  170. package/dist/capability-options.d.ts.map +0 -1
  171. package/dist/capability-options.js.map +0 -1
  172. package/dist/capability-options.test.d.ts +0 -2
  173. package/dist/capability-options.test.d.ts.map +0 -1
  174. package/dist/capability-options.test.js +0 -81
  175. package/dist/capability-options.test.js.map +0 -1
  176. package/dist/capability-package.d.ts.map +0 -1
  177. package/dist/capability-package.js.map +0 -1
  178. package/dist/capability-package.test.d.ts +0 -2
  179. package/dist/capability-package.test.d.ts.map +0 -1
  180. package/dist/capability-package.test.js +0 -179
  181. package/dist/capability-package.test.js.map +0 -1
  182. package/dist/capability-registry.d.ts.map +0 -1
  183. package/dist/capability-registry.js.map +0 -1
  184. package/dist/capability-registry.test.d.ts +0 -2
  185. package/dist/capability-registry.test.d.ts.map +0 -1
  186. package/dist/capability-registry.test.js +0 -1683
  187. package/dist/capability-registry.test.js.map +0 -1
  188. package/dist/capability-runner.d.ts.map +0 -1
  189. package/dist/capability-runner.js.map +0 -1
  190. package/dist/capability-search-relevance.test.d.ts +0 -2
  191. package/dist/capability-search-relevance.test.d.ts.map +0 -1
  192. package/dist/capability-search-relevance.test.js +0 -67
  193. package/dist/capability-search-relevance.test.js.map +0 -1
  194. package/dist/capability-studio.d.ts.map +0 -1
  195. package/dist/capability-studio.js.map +0 -1
  196. package/dist/capability-studio.test.d.ts +0 -2
  197. package/dist/capability-studio.test.d.ts.map +0 -1
  198. package/dist/capability-studio.test.js +0 -41
  199. package/dist/capability-studio.test.js.map +0 -1
  200. package/dist/cdp-log.d.ts.map +0 -1
  201. package/dist/cdp-log.js.map +0 -1
  202. package/dist/cdp-log.test.d.ts +0 -2
  203. package/dist/cdp-log.test.d.ts.map +0 -1
  204. package/dist/cdp-log.test.js +0 -109
  205. package/dist/cdp-log.test.js.map +0 -1
  206. package/dist/cdp-relay.d.ts.map +0 -1
  207. package/dist/cdp-relay.js.map +0 -1
  208. package/dist/cdp-session.d.ts.map +0 -1
  209. package/dist/cdp-session.js.map +0 -1
  210. package/dist/cdp-types.d.ts.map +0 -1
  211. package/dist/cdp-types.js.map +0 -1
  212. package/dist/channel-owner-inspect.test.d.ts +0 -2
  213. package/dist/channel-owner-inspect.test.d.ts.map +0 -1
  214. package/dist/channel-owner-inspect.test.js +0 -75
  215. package/dist/channel-owner-inspect.test.js.map +0 -1
  216. package/dist/chrome-discovery.d.ts.map +0 -1
  217. package/dist/chrome-discovery.js.map +0 -1
  218. package/dist/chrome-discovery.test.d.ts +0 -2
  219. package/dist/chrome-discovery.test.d.ts.map +0 -1
  220. package/dist/chrome-discovery.test.js +0 -41
  221. package/dist/chrome-discovery.test.js.map +0 -1
  222. package/dist/clean-html.d.ts.map +0 -1
  223. package/dist/clean-html.js.map +0 -1
  224. package/dist/cli-help.test.d.ts +0 -2
  225. package/dist/cli-help.test.d.ts.map +0 -1
  226. package/dist/cli-help.test.js +0 -98
  227. package/dist/cli-help.test.js.map +0 -1
  228. package/dist/cli.d.ts.map +0 -1
  229. package/dist/cli.js.map +0 -1
  230. package/dist/cloud-client.d.ts.map +0 -1
  231. package/dist/cloud-client.js.map +0 -1
  232. package/dist/create-logger.d.ts.map +0 -1
  233. package/dist/create-logger.js.map +0 -1
  234. package/dist/debugger-examples-types.d.ts.map +0 -1
  235. package/dist/debugger-examples-types.js.map +0 -1
  236. package/dist/debugger-examples.d.ts.map +0 -1
  237. package/dist/debugger-examples.js.map +0 -1
  238. package/dist/debugger.d.ts.map +0 -1
  239. package/dist/debugger.js.map +0 -1
  240. package/dist/diff-utils.d.ts.map +0 -1
  241. package/dist/diff-utils.js.map +0 -1
  242. package/dist/diff-utils.test.d.ts +0 -2
  243. package/dist/diff-utils.test.d.ts.map +0 -1
  244. package/dist/diff-utils.test.js +0 -137
  245. package/dist/diff-utils.test.js.map +0 -1
  246. package/dist/doctor.d.ts.map +0 -1
  247. package/dist/doctor.js.map +0 -1
  248. package/dist/doctor.test.d.ts +0 -2
  249. package/dist/doctor.test.d.ts.map +0 -1
  250. package/dist/doctor.test.js +0 -208
  251. package/dist/doctor.test.js.map +0 -1
  252. package/dist/editor-examples.d.ts.map +0 -1
  253. package/dist/editor-examples.js.map +0 -1
  254. package/dist/editor.d.ts.map +0 -1
  255. package/dist/editor.js.map +0 -1
  256. package/dist/env-compat.d.ts.map +0 -1
  257. package/dist/env-compat.js.map +0 -1
  258. package/dist/executor.d.ts.map +0 -1
  259. package/dist/executor.js.map +0 -1
  260. package/dist/executor.unit.test.d.ts +0 -2
  261. package/dist/executor.unit.test.d.ts.map +0 -1
  262. package/dist/executor.unit.test.js +0 -143
  263. package/dist/executor.unit.test.js.map +0 -1
  264. package/dist/extension-connection.test.d.ts +0 -2
  265. package/dist/extension-connection.test.d.ts.map +0 -1
  266. package/dist/extension-connection.test.js +0 -708
  267. package/dist/extension-connection.test.js.map +0 -1
  268. package/dist/extension-icon-warning.test.d.ts +0 -2
  269. package/dist/extension-icon-warning.test.d.ts.map +0 -1
  270. package/dist/extension-icon-warning.test.js +0 -33
  271. package/dist/extension-icon-warning.test.js.map +0 -1
  272. package/dist/ghost-browser.d.ts.map +0 -1
  273. package/dist/ghost-browser.js.map +0 -1
  274. package/dist/ghost-cursor-controller.d.ts.map +0 -1
  275. package/dist/ghost-cursor-controller.js.map +0 -1
  276. package/dist/ghost-cursor.d.ts.map +0 -1
  277. package/dist/ghost-cursor.js.map +0 -1
  278. package/dist/htmlrewrite.d.ts.map +0 -1
  279. package/dist/htmlrewrite.js.map +0 -1
  280. package/dist/htmlrewrite.test.d.ts +0 -2
  281. package/dist/htmlrewrite.test.d.ts.map +0 -1
  282. package/dist/htmlrewrite.test.js +0 -7975
  283. package/dist/htmlrewrite.test.js.map +0 -1
  284. package/dist/index.d.ts.map +0 -1
  285. package/dist/index.js.map +0 -1
  286. package/dist/kill-port.d.ts.map +0 -1
  287. package/dist/kill-port.js.map +0 -1
  288. package/dist/kitty-graphics.d.ts.map +0 -1
  289. package/dist/kitty-graphics.js.map +0 -1
  290. package/dist/kitty-graphics.test.d.ts +0 -2
  291. package/dist/kitty-graphics.test.d.ts.map +0 -1
  292. package/dist/kitty-graphics.test.js +0 -125
  293. package/dist/kitty-graphics.test.js.map +0 -1
  294. package/dist/locator-selector.test.d.ts +0 -2
  295. package/dist/locator-selector.test.d.ts.map +0 -1
  296. package/dist/locator-selector.test.js +0 -98
  297. package/dist/locator-selector.test.js.map +0 -1
  298. package/dist/mcp-client.d.ts +0 -20
  299. package/dist/mcp-client.d.ts.map +0 -1
  300. package/dist/mcp-client.js +0 -56
  301. package/dist/mcp-client.js.map +0 -1
  302. package/dist/mcp.d.ts.map +0 -1
  303. package/dist/mcp.js.map +0 -1
  304. package/dist/on-mouse-action.test.d.ts +0 -2
  305. package/dist/on-mouse-action.test.d.ts.map +0 -1
  306. package/dist/on-mouse-action.test.js +0 -180
  307. package/dist/on-mouse-action.test.js.map +0 -1
  308. package/dist/options-page.test.d.ts +0 -2
  309. package/dist/options-page.test.d.ts.map +0 -1
  310. package/dist/options-page.test.js +0 -773
  311. package/dist/options-page.test.js.map +0 -1
  312. package/dist/package-paths.d.ts.map +0 -1
  313. package/dist/package-paths.js.map +0 -1
  314. package/dist/page-markdown.d.ts.map +0 -1
  315. package/dist/page-markdown.js.map +0 -1
  316. package/dist/performance-examples.d.ts.map +0 -1
  317. package/dist/performance-examples.js.map +0 -1
  318. package/dist/playwright-import.d.ts.map +0 -1
  319. package/dist/playwright-import.js.map +0 -1
  320. package/dist/popup-relocation.test.d.ts +0 -7
  321. package/dist/popup-relocation.test.d.ts.map +0 -1
  322. package/dist/popup-relocation.test.js +0 -139
  323. package/dist/popup-relocation.test.js.map +0 -1
  324. package/dist/product-paths.d.ts.map +0 -1
  325. package/dist/product-paths.js.map +0 -1
  326. package/dist/product-paths.test.d.ts +0 -2
  327. package/dist/product-paths.test.d.ts.map +0 -1
  328. package/dist/product-paths.test.js +0 -39
  329. package/dist/product-paths.test.js.map +0 -1
  330. package/dist/protocol.d.ts.map +0 -1
  331. package/dist/protocol.js.map +0 -1
  332. package/dist/protocol.test.d.ts +0 -2
  333. package/dist/protocol.test.d.ts.map +0 -1
  334. package/dist/protocol.test.js +0 -31
  335. package/dist/protocol.test.js.map +0 -1
  336. package/dist/react-source.d.ts.map +0 -1
  337. package/dist/react-source.js.map +0 -1
  338. package/dist/relay-client.d.ts.map +0 -1
  339. package/dist/relay-client.js.map +0 -1
  340. package/dist/relay-client.test.d.ts +0 -2
  341. package/dist/relay-client.test.d.ts.map +0 -1
  342. package/dist/relay-client.test.js +0 -305
  343. package/dist/relay-client.test.js.map +0 -1
  344. package/dist/relay-core.test.d.ts +0 -2
  345. package/dist/relay-core.test.d.ts.map +0 -1
  346. package/dist/relay-core.test.js +0 -1427
  347. package/dist/relay-core.test.js.map +0 -1
  348. package/dist/relay-navigation.test.d.ts +0 -2
  349. package/dist/relay-navigation.test.d.ts.map +0 -1
  350. package/dist/relay-navigation.test.js +0 -661
  351. package/dist/relay-navigation.test.js.map +0 -1
  352. package/dist/relay-session.test.d.ts +0 -2
  353. package/dist/relay-session.test.d.ts.map +0 -1
  354. package/dist/relay-session.test.js +0 -1121
  355. package/dist/relay-session.test.js.map +0 -1
  356. package/dist/relay-state.d.ts.map +0 -1
  357. package/dist/relay-state.js.map +0 -1
  358. package/dist/relay-state.test.d.ts +0 -2
  359. package/dist/relay-state.test.d.ts.map +0 -1
  360. package/dist/relay-state.test.js +0 -594
  361. package/dist/relay-state.test.js.map +0 -1
  362. package/dist/replay-ai-index.d.ts.map +0 -1
  363. package/dist/replay-ai-index.js.map +0 -1
  364. package/dist/replay-ai-index.test.d.ts +0 -2
  365. package/dist/replay-ai-index.test.d.ts.map +0 -1
  366. package/dist/replay-ai-index.test.js +0 -255
  367. package/dist/replay-ai-index.test.js.map +0 -1
  368. package/dist/replay-cli.test.d.ts +0 -2
  369. package/dist/replay-cli.test.d.ts.map +0 -1
  370. package/dist/replay-cli.test.js +0 -275
  371. package/dist/replay-cli.test.js.map +0 -1
  372. package/dist/replay-eval.d.ts.map +0 -1
  373. package/dist/replay-eval.js.map +0 -1
  374. package/dist/replay-handoff.d.ts.map +0 -1
  375. package/dist/replay-handoff.js.map +0 -1
  376. package/dist/replay-handoff.test.d.ts +0 -2
  377. package/dist/replay-handoff.test.d.ts.map +0 -1
  378. package/dist/replay-handoff.test.js +0 -123
  379. package/dist/replay-handoff.test.js.map +0 -1
  380. package/dist/replay-workflow-compiler.d.ts.map +0 -1
  381. package/dist/replay-workflow-compiler.js.map +0 -1
  382. package/dist/replay-workflow-compiler.test.d.ts +0 -2
  383. package/dist/replay-workflow-compiler.test.d.ts.map +0 -1
  384. package/dist/replay-workflow-compiler.test.js +0 -223
  385. package/dist/replay-workflow-compiler.test.js.map +0 -1
  386. package/dist/rrweb-recording-relay.d.ts.map +0 -1
  387. package/dist/rrweb-recording-relay.js.map +0 -1
  388. package/dist/rrweb-recording-relay.test.d.ts +0 -2
  389. package/dist/rrweb-recording-relay.test.d.ts.map +0 -1
  390. package/dist/rrweb-recording-relay.test.js +0 -85
  391. package/dist/rrweb-recording-relay.test.js.map +0 -1
  392. package/dist/rrweb-recording.d.ts.map +0 -1
  393. package/dist/rrweb-recording.js.map +0 -1
  394. package/dist/scoped-fs.d.ts.map +0 -1
  395. package/dist/scoped-fs.js.map +0 -1
  396. package/dist/scoped-fs.test.d.ts +0 -5
  397. package/dist/scoped-fs.test.d.ts.map +0 -1
  398. package/dist/scoped-fs.test.js +0 -73
  399. package/dist/scoped-fs.test.js.map +0 -1
  400. package/dist/skill-stub.test.d.ts +0 -2
  401. package/dist/skill-stub.test.d.ts.map +0 -1
  402. package/dist/skill-stub.test.js +0 -22
  403. package/dist/skill-stub.test.js.map +0 -1
  404. package/dist/snapshot-tools.test.d.ts +0 -2
  405. package/dist/snapshot-tools.test.d.ts.map +0 -1
  406. package/dist/snapshot-tools.test.js +0 -856
  407. package/dist/snapshot-tools.test.js.map +0 -1
  408. package/dist/start-relay-server.d.ts.map +0 -1
  409. package/dist/start-relay-server.js.map +0 -1
  410. package/dist/styles-examples.d.ts.map +0 -1
  411. package/dist/styles-examples.js.map +0 -1
  412. package/dist/styles.d.ts.map +0 -1
  413. package/dist/styles.js.map +0 -1
  414. package/dist/tabwright-agent-skill.d.ts.map +0 -1
  415. package/dist/tabwright-agent-skill.js.map +0 -1
  416. package/dist/tabwright-agent-skill.test.d.ts +0 -2
  417. package/dist/tabwright-agent-skill.test.d.ts.map +0 -1
  418. package/dist/tabwright-agent-skill.test.js +0 -51
  419. package/dist/tabwright-agent-skill.test.js.map +0 -1
  420. package/dist/test-declarations.d.ts.map +0 -1
  421. package/dist/test-declarations.js.map +0 -1
  422. package/dist/test-utils.d.ts +0 -69
  423. package/dist/test-utils.d.ts.map +0 -1
  424. package/dist/test-utils.js +0 -448
  425. package/dist/test-utils.js.map +0 -1
  426. package/dist/test-utils.test.d.ts +0 -2
  427. package/dist/test-utils.test.d.ts.map +0 -1
  428. package/dist/test-utils.test.js +0 -55
  429. package/dist/test-utils.test.js.map +0 -1
  430. package/dist/utils.d.ts.map +0 -1
  431. package/dist/utils.js.map +0 -1
  432. package/dist/wait-for-page-load.d.ts.map +0 -1
  433. package/dist/wait-for-page-load.js.map +0 -1
  434. package/dist/workflow-capability.d.ts.map +0 -1
  435. package/dist/workflow-capability.js.map +0 -1
  436. package/dist/workflow-script-flow.test.d.ts +0 -2
  437. package/dist/workflow-script-flow.test.d.ts.map +0 -1
  438. package/dist/workflow-script-flow.test.js +0 -285
  439. package/dist/workflow-script-flow.test.js.map +0 -1
  440. package/src/__snapshots__/x.com.processed.html +0 -1003
  441. package/src/__snapshots__/x.com.processed.withStyles.html +0 -2720
  442. package/src/a11y-client.ts +0 -241
  443. package/src/agent-skills/conan-config/SKILL.md +0 -141
  444. package/src/agent-skills/conan-config/agents/openai.yaml +0 -4
  445. package/src/aria-snapshot.test.ts +0 -311
  446. package/src/aria-snapshot.ts +0 -1681
  447. package/src/aria-snapshot.unit.test.ts +0 -615
  448. package/src/aria-snapshots/github-interactive.txt +0 -193
  449. package/src/aria-snapshots/github-raw.txt +0 -309
  450. package/src/aria-snapshots/hackernews-interactive.txt +0 -477
  451. package/src/aria-snapshots/hackernews-raw.txt +0 -428
  452. package/src/aria-snapshots/prosemirror-interactive.txt +0 -66
  453. package/src/aria-snapshots/prosemirror-raw.txt +0 -145
  454. package/src/assets/aria-labels-hacker-news.png +0 -0
  455. package/src/assets/aria-labels-old-reddit.png +0 -0
  456. package/src/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.ts +0 -5
  457. package/src/assets/cursors/screen-studio/pointer-macos-tahoe.svg +0 -18
  458. package/src/assets/x.com.html +0 -32946
  459. package/src/browser-config.ts +0 -179
  460. package/src/browser-install.ts +0 -284
  461. package/src/browser-launch.ts +0 -75
  462. package/src/builtin-capabilities.ts +0 -2765
  463. package/src/capability-agent-skill.ts +0 -305
  464. package/src/capability-auth-state.ts +0 -197
  465. package/src/capability-auth.ts +0 -249
  466. package/src/capability-cli-confirmation.test.ts +0 -90
  467. package/src/capability-options.test.ts +0 -89
  468. package/src/capability-options.ts +0 -57
  469. package/src/capability-package.test.ts +0 -204
  470. package/src/capability-package.ts +0 -555
  471. package/src/capability-registry.test.ts +0 -1905
  472. package/src/capability-registry.ts +0 -1234
  473. package/src/capability-runner.ts +0 -801
  474. package/src/capability-search-relevance.test.ts +0 -73
  475. package/src/capability-studio.test.ts +0 -45
  476. package/src/capability-studio.ts +0 -641
  477. package/src/cdp-log.test.ts +0 -131
  478. package/src/cdp-log.ts +0 -112
  479. package/src/cdp-relay.ts +0 -2944
  480. package/src/cdp-session.ts +0 -77
  481. package/src/cdp-types.ts +0 -158
  482. package/src/channel-owner-inspect.test.ts +0 -94
  483. package/src/chrome-discovery.test.ts +0 -50
  484. package/src/chrome-discovery.ts +0 -220
  485. package/src/clean-html.ts +0 -141
  486. package/src/cli-help.test.ts +0 -123
  487. package/src/cli.ts +0 -3181
  488. package/src/cloud-client.ts +0 -179
  489. package/src/create-logger.ts +0 -38
  490. package/src/debugger-examples-types.ts +0 -16
  491. package/src/debugger-examples.ts +0 -66
  492. package/src/debugger.ts +0 -708
  493. package/src/diff-utils.test.ts +0 -152
  494. package/src/diff-utils.ts +0 -70
  495. package/src/doctor.test.ts +0 -244
  496. package/src/doctor.ts +0 -321
  497. package/src/editor-examples.ts +0 -158
  498. package/src/editor.ts +0 -426
  499. package/src/env-compat.ts +0 -28
  500. package/src/executor.ts +0 -1824
  501. package/src/executor.unit.test.ts +0 -168
  502. package/src/extension-connection.test.ts +0 -855
  503. package/src/extension-icon-warning.test.ts +0 -45
  504. package/src/ghost-browser.ts +0 -149
  505. package/src/ghost-cursor-client.ts +0 -494
  506. package/src/ghost-cursor-controller.ts +0 -129
  507. package/src/ghost-cursor.ts +0 -123
  508. package/src/htmlrewrite.test.ts +0 -8008
  509. package/src/htmlrewrite.ts +0 -390
  510. package/src/index.ts +0 -53
  511. package/src/kill-port.ts +0 -219
  512. package/src/kitty-graphics.test.ts +0 -139
  513. package/src/kitty-graphics.ts +0 -79
  514. package/src/locator-selector.test.ts +0 -119
  515. package/src/mcp-client.ts +0 -78
  516. package/src/mcp.ts +0 -629
  517. package/src/on-mouse-action.test.ts +0 -226
  518. package/src/options-page.test.ts +0 -839
  519. package/src/package-paths.ts +0 -38
  520. package/src/page-markdown.ts +0 -240
  521. package/src/performance-examples.ts +0 -186
  522. package/src/playwright-import.ts +0 -59
  523. package/src/popup-relocation.test.ts +0 -163
  524. package/src/product-paths.test.ts +0 -47
  525. package/src/product-paths.ts +0 -28
  526. package/src/protocol.test.ts +0 -52
  527. package/src/protocol.ts +0 -351
  528. package/src/react-source.ts +0 -379
  529. package/src/relay-client.test.ts +0 -375
  530. package/src/relay-client.ts +0 -572
  531. package/src/relay-core.test.ts +0 -1603
  532. package/src/relay-navigation.test.ts +0 -790
  533. package/src/relay-session.test.ts +0 -1375
  534. package/src/relay-state.test.ts +0 -729
  535. package/src/relay-state.ts +0 -561
  536. package/src/replay-ai-index.test.ts +0 -278
  537. package/src/replay-ai-index.ts +0 -872
  538. package/src/replay-cli.test.ts +0 -325
  539. package/src/replay-eval.ts +0 -1039
  540. package/src/replay-handoff.test.ts +0 -163
  541. package/src/replay-handoff.ts +0 -109
  542. package/src/replay-workflow-compiler.test.ts +0 -250
  543. package/src/replay-workflow-compiler.ts +0 -700
  544. package/src/resource.md +0 -409
  545. package/src/rrweb-recording-relay.test.ts +0 -99
  546. package/src/rrweb-recording-relay.ts +0 -400
  547. package/src/rrweb-recording.ts +0 -322
  548. package/src/scoped-fs.test.ts +0 -80
  549. package/src/scoped-fs.ts +0 -420
  550. package/src/skill-stub.test.ts +0 -24
  551. package/src/snapshot-tools.test.ts +0 -1017
  552. package/src/snapshots/hacker-news-accessibility-full.md +0 -81
  553. package/src/snapshots/hacker-news-accessibility-interactive.md +0 -43
  554. package/src/snapshots/page-markdown-output.txt +0 -16
  555. package/src/snapshots/shadcn-ui-accessibility-full.md +0 -201
  556. package/src/snapshots/shadcn-ui-accessibility-interactive.md +0 -109
  557. package/src/start-relay-server.ts +0 -69
  558. package/src/styles-examples.ts +0 -84
  559. package/src/styles.ts +0 -343
  560. package/src/tabwright-agent-skill.test.ts +0 -61
  561. package/src/tabwright-agent-skill.ts +0 -105
  562. package/src/test-declarations.ts +0 -13
  563. package/src/test-utils.test.ts +0 -70
  564. package/src/test-utils.ts +0 -566
  565. package/src/utils.ts +0 -78
  566. package/src/wait-for-page-load.ts +0 -198
  567. package/src/workflow-capability.ts +0 -417
  568. package/src/workflow-script-flow.test.ts +0 -388
@@ -1,839 +0,0 @@
1
- import fs from 'node:fs'
2
- import http from 'node:http'
3
- import net from 'node:net'
4
- import path from 'node:path'
5
- import { afterAll, beforeAll, describe, expect, test } from 'vitest'
6
- import { cleanupTestContext, setupTestContext, type TestContext } from './test-utils.js'
7
-
8
- const TEST_PORT = 19984
9
-
10
- type StaticServer = {
11
- baseUrl: string
12
- close: () => Promise<void>
13
- }
14
-
15
- let testCtx: TestContext | null = null
16
-
17
- function getExtensionDistRoot(): string {
18
- const candidates = [
19
- path.join(process.cwd(), 'extension', `dist-${TEST_PORT}`),
20
- path.resolve(process.cwd(), '..', 'extension', `dist-${TEST_PORT}`),
21
- ]
22
- const distRoot = candidates.find((candidate) => {
23
- return fs.existsSync(path.join(candidate, 'src', 'options.html'))
24
- })
25
- if (!distRoot) {
26
- throw new Error(`Could not find extension dist for port ${TEST_PORT}`)
27
- }
28
- return distRoot
29
- }
30
-
31
- async function createStaticServer(rootDir: string): Promise<StaticServer> {
32
- const openSockets: Set<net.Socket> = new Set()
33
- const server = http.createServer((req, res) => {
34
- const url = new URL(req.url || '/', 'http://127.0.0.1')
35
- const pathname = url.pathname === '/' ? '/src/options.html' : url.pathname
36
- const filePath = path.resolve(rootDir, `.${pathname}`)
37
-
38
- if (filePath !== rootDir && !filePath.startsWith(`${rootDir}${path.sep}`)) {
39
- res.writeHead(403)
40
- res.end('forbidden')
41
- return
42
- }
43
- if (!fs.existsSync(filePath)) {
44
- res.writeHead(404)
45
- res.end('not found')
46
- return
47
- }
48
-
49
- const contentType = filePath.endsWith('.js')
50
- ? 'text/javascript'
51
- : filePath.endsWith('.html')
52
- ? 'text/html'
53
- : filePath.endsWith('.css')
54
- ? 'text/css'
55
- : 'application/octet-stream'
56
- res.writeHead(200, { 'Content-Type': contentType })
57
- res.end(fs.readFileSync(filePath))
58
- })
59
-
60
- server.on('connection', (socket) => {
61
- openSockets.add(socket)
62
- socket.on('close', () => {
63
- openSockets.delete(socket)
64
- })
65
- })
66
-
67
- await new Promise<void>((resolve) => {
68
- server.listen(0, '127.0.0.1', () => {
69
- resolve()
70
- })
71
- })
72
-
73
- const address = server.address()
74
- if (!address || typeof address === 'string') {
75
- throw new Error('Failed to start static server')
76
- }
77
-
78
- return {
79
- baseUrl: `http://127.0.0.1:${address.port}`,
80
- close: async () => {
81
- openSockets.forEach((socket) => {
82
- socket.destroy()
83
- })
84
- await new Promise<void>((resolve, reject) => {
85
- server.close((error) => {
86
- if (error) {
87
- reject(error)
88
- return
89
- }
90
- resolve()
91
- })
92
- })
93
- },
94
- }
95
- }
96
-
97
- describe('extension options page', () => {
98
- beforeAll(async () => {
99
- testCtx = await setupTestContext({ port: TEST_PORT, tempDirPrefix: 'options-page-test-' })
100
- }, 600000)
101
-
102
- afterAll(async () => {
103
- await cleanupTestContext(testCtx)
104
- testCtx = null
105
- })
106
-
107
- test('shows DOM replays and loads selected playback from the options page', async () => {
108
- if (!testCtx) {
109
- throw new Error('Test context is not initialized')
110
- }
111
-
112
- const distRoot = getExtensionDistRoot()
113
- const staticServer = await createStaticServer(distRoot)
114
- let replayEventsRequested = false
115
- const replay = {
116
- id: 'replay-options-smoke',
117
- path: '/Users/test/.tabwright/rrweb-recordings/replay-options-smoke.json',
118
- startedAt: Date.now() - 2000,
119
- savedAt: Date.now(),
120
- duration: 2000,
121
- size: 2048,
122
- eventCount: 2,
123
- tabId: 7,
124
- sessionId: 'pw-tab-options',
125
- url: 'https://example.com/materials/new',
126
- }
127
- const recordings = Array.from({ length: 30 }, (_, index) => {
128
- return {
129
- ...replay,
130
- id: index === 0 ? replay.id : `replay-options-smoke-${index}`,
131
- path: index === 0 ? replay.path : `/Users/test/.tabwright/rrweb-recordings/replay-options-smoke-${index}.json`,
132
- startedAt: replay.startedAt - index * 1000,
133
- savedAt: replay.savedAt - index * 1000,
134
- tabId: replay.tabId + index,
135
- }
136
- })
137
- const replayEvents = [
138
- {
139
- type: 4,
140
- timestamp: replay.startedAt,
141
- data: { href: replay.url, width: 1280, height: 720 },
142
- },
143
- {
144
- type: 2,
145
- timestamp: replay.startedAt + 100,
146
- data: { node: { id: 1, type: 0, childNodes: [] } },
147
- },
148
- {
149
- type: 3,
150
- timestamp: replay.startedAt + 200,
151
- data: {
152
- source: 0,
153
- adds: [],
154
- removes: [],
155
- texts: [{ id: 404, value: 'missing node update' }],
156
- attributes: [],
157
- },
158
- },
159
- {
160
- type: 5,
161
- timestamp: replay.startedAt + 5000,
162
- data: { tag: 'end', payload: {} },
163
- },
164
- ]
165
-
166
- const page = await testCtx.browserContext.newPage()
167
- const missingNodeConsoleWarnings: string[] = []
168
- page.on('console', (message) => {
169
- if (message.type() === 'warning' && message.text().includes('Node with id')) {
170
- missingNodeConsoleWarnings.push(message.text())
171
- }
172
- })
173
- await page.setViewportSize({ width: 1280, height: 720 })
174
- try {
175
- await testCtx.browserContext.grantPermissions(['clipboard-read', 'clipboard-write'], {
176
- origin: staticServer.baseUrl,
177
- })
178
- await page.route(`http://127.0.0.1:${TEST_PORT}/**`, async (route) => {
179
- const request = route.request()
180
- const url = new URL(request.url())
181
- const corsHeaders = {
182
- 'access-control-allow-origin': '*',
183
- 'access-control-allow-methods': 'GET,POST,OPTIONS',
184
- 'access-control-allow-headers': 'content-type',
185
- }
186
-
187
- if (request.method() === 'OPTIONS') {
188
- await route.fulfill({ status: 204, headers: corsHeaders, body: '' })
189
- return
190
- }
191
-
192
- if (url.pathname === '/rrweb-recordings') {
193
- await route.fulfill({
194
- status: 200,
195
- headers: { ...corsHeaders, 'content-type': 'application/json' },
196
- body: JSON.stringify({ recordings }),
197
- })
198
- return
199
- }
200
-
201
- if (url.pathname === `/rrweb-recordings/${replay.id}/events`) {
202
- replayEventsRequested = true
203
- await route.fulfill({
204
- status: 200,
205
- headers: { ...corsHeaders, 'content-type': 'application/json' },
206
- body: JSON.stringify({ recording: replay, events: replayEvents }),
207
- })
208
- return
209
- }
210
-
211
- await route.fulfill({ status: 404, headers: corsHeaders, body: 'not found' })
212
- })
213
-
214
- await page.goto(`${staticServer.baseUrl}/src/options.html`)
215
- await page.locator('.language-button[data-language="en"]').click()
216
- const recordingItem = page.locator('.recording-item').first()
217
- await recordingItem.waitFor({ timeout: 10000 })
218
- await expect
219
- .poll(async () => {
220
- return await recordingItem.textContent()
221
- })
222
- .toContain('2 events')
223
- const replaysList = page.locator('#replays-list')
224
- await expect
225
- .poll(async () => {
226
- return await replaysList.evaluate((element) => {
227
- const list = element as unknown as { scrollHeight: number; clientHeight: number }
228
- return list.scrollHeight > list.clientHeight
229
- })
230
- })
231
- .toBe(true)
232
- await replaysList.evaluate((element) => {
233
- const list = element as unknown as { scrollHeight: number; scrollTop: number }
234
- list.scrollTop = list.scrollHeight
235
- })
236
- await expect
237
- .poll(async () => {
238
- return await replaysList.evaluate((element) => {
239
- const list = element as unknown as { scrollTop: number }
240
- return list.scrollTop > 0
241
- })
242
- })
243
- .toBe(true)
244
- await replaysList.evaluate((element) => {
245
- const list = element as unknown as { scrollTop: number }
246
- list.scrollTop = 0
247
- })
248
- await recordingItem.locator('.recording-select').click()
249
-
250
- await expect
251
- .poll(() => {
252
- return replayEventsRequested
253
- })
254
- .toBe(true)
255
- await expect
256
- .poll(async () => {
257
- return await page.locator('#status-text').textContent()
258
- })
259
- .toContain('Replay ready')
260
- await expect
261
- .poll(async () => {
262
- return await page.locator('#replay-controls').isVisible()
263
- })
264
- .toBe(true)
265
- await expect
266
- .poll(async () => {
267
- return await page.locator('#replay-play-toggle').textContent()
268
- })
269
- .toBe('Play')
270
- await expect
271
- .poll(async () => {
272
- return Number(await page.locator('#replay-timeline').inputValue())
273
- })
274
- .toBe(0)
275
- await page.locator('#replay-play-toggle').click()
276
- await expect
277
- .poll(async () => {
278
- return await page.locator('#replay-play-toggle').textContent()
279
- })
280
- .toBe('Pause')
281
- await expect
282
- .poll(async () => {
283
- return await page.locator('#replay-warning').textContent()
284
- })
285
- .toContain('1 DOM update')
286
- expect(missingNodeConsoleWarnings).toEqual([])
287
- await page.locator('#replay-play-toggle').click()
288
- await expect
289
- .poll(async () => {
290
- return await page.locator('#replay-play-toggle').textContent()
291
- })
292
- .toBe('Play')
293
- await expect
294
- .poll(async () => {
295
- return await page.locator('#replay-details').textContent()
296
- })
297
- .toContain('replay-options-smoke')
298
- await expect
299
- .poll(async () => {
300
- return await page.locator('#replay-details').textContent()
301
- })
302
- .toContain('https://example.com/materials/new')
303
- await recordingItem.getByRole('button', { name: 'Copy for AI' }).click()
304
- const replayContext = await page.evaluate(async () => {
305
- const clipboardNavigator = navigator as Navigator & {
306
- clipboard: { readText: () => Promise<string> }
307
- }
308
- return await clipboardNavigator.clipboard.readText()
309
- })
310
- expect(replayContext).toContain('Replay ID: replay-options-smoke')
311
- expect(replayContext).toContain(replay.path)
312
- await page.locator('#replay-player .replayer-wrapper').waitFor()
313
- await expect
314
- .poll(async () => {
315
- const playerBox = await page.locator('#replay-player').boundingBox()
316
- const wrapperBox = await page.locator('#replay-player .replayer-wrapper').boundingBox()
317
- if (!playerBox || !wrapperBox) {
318
- return false
319
- }
320
- return wrapperBox.width <= playerBox.width + 1 && wrapperBox.height <= playerBox.height + 1
321
- })
322
- .toBe(true)
323
- } finally {
324
- await testCtx.browserContext.clearPermissions()
325
- await page.close()
326
- await staticServer.close()
327
- }
328
- }, 30000)
329
-
330
- test('shows capabilities with clear status labels and focused actions', async () => {
331
- if (!testCtx) {
332
- throw new Error('Test context is not initialized')
333
- }
334
-
335
- const distRoot = getExtensionDistRoot()
336
- const staticServer = await createStaticServer(distRoot)
337
- const capabilityBase = {
338
- id: 'query-user',
339
- title: 'Query User',
340
- description: 'Look up a user by email.',
341
- status: 'trusted',
342
- runtime: 'browser',
343
- match: ['https://admin.example.com/users*'],
344
- routingHint: 'exact-match-direct-run',
345
- permissions: ['browser.read', 'browser.write'],
346
- sideEffect: 'write',
347
- requiresConfirmation: true,
348
- whenToUse: ['Use when the user asks to look up an admin user by email.'],
349
- whenNotToUse: ['Do not use for public profile lookup.'],
350
- tags: ['admin'],
351
- inputSchema: {
352
- type: 'object',
353
- properties: {
354
- email: { type: 'string' },
355
- },
356
- required: ['email'],
357
- },
358
- outputSchema: {
359
- type: 'object',
360
- properties: {
361
- id: { type: 'string' },
362
- },
363
- },
364
- location: 'project',
365
- dir: '/Users/test/project/.tabwright/capabilities/query-user',
366
- autonomousInvocation: {
367
- allowed: false,
368
- reasons: ['sideEffect is write', 'requires confirmation'],
369
- },
370
- recentRuns: [
371
- {
372
- id: 'run-1',
373
- status: 'success',
374
- durationMs: 42,
375
- inputHash: 'abc',
376
- createdAt: '2026-07-07T00:00:00.000Z',
377
- },
378
- ],
379
- agentSkill: {
380
- target: 'codex',
381
- draftExists: true,
382
- draftPath: '/Users/test/project/.tabwright/capabilities/query-user/agent-skills/codex/SKILL.md',
383
- installedExists: false,
384
- installedPath: '/Users/test/.codex/skills/query-user/SKILL.md',
385
- initCommand: 'tabwright capability skill init query-user',
386
- showCommand: 'tabwright capability skill show query-user',
387
- installCommand: 'tabwright capability skill install query-user',
388
- },
389
- }
390
- const trustedNextCommand =
391
- 'tabwright capability run query-user --browser user --input-json \'{"email":"from-contract@example.com"}\' --confirm query-user --json'
392
- let authRefreshAttempts = 0
393
- let capabilityAuthState: {
394
- type: string
395
- status: string
396
- canRefresh: boolean
397
- browserUrls: string[]
398
- requiredCookieNames: string[]
399
- cookieNames: string[]
400
- refreshCommand: string
401
- refreshedAt?: string
402
- expiresAt?: string
403
- } = {
404
- type: 'cookie',
405
- status: 'missing',
406
- canRefresh: true,
407
- browserUrls: ['https://admin.example.com/'],
408
- requiredCookieNames: ['SESSION'],
409
- cookieNames: [],
410
- refreshCommand: 'tabwright capability refresh-auth query-user --browser user --json',
411
- }
412
- const capability = {
413
- ...capabilityBase,
414
- authState: capabilityAuthState,
415
- lifecycle: {
416
- stage: 'trusted',
417
- nextAction: 'run',
418
- nextCommand: trustedNextCommand,
419
- contractHealth: {
420
- state: 'healthy',
421
- checkedAt: '2026-07-07T00:00:00.000Z',
422
- reasons: [],
423
- },
424
- },
425
- }
426
- const driftedNextCommand = 'tabwright capability show drifted-user --json'
427
- const driftedCapability = {
428
- ...capabilityBase,
429
- id: 'drifted-user',
430
- title: 'Drifted User Query',
431
- status: 'draft',
432
- autonomousInvocation: {
433
- allowed: false,
434
- reasons: ['current contract failed conformance'],
435
- },
436
- lifecycle: {
437
- stage: 'drifted',
438
- nextAction: 'repair',
439
- nextCommand: driftedNextCommand,
440
- contractHealth: {
441
- state: 'drifted',
442
- checkedAt: '2026-07-08T00:00:00.000Z',
443
- reasons: ['output.userId must be string'],
444
- },
445
- },
446
- }
447
- const disabledCapability = {
448
- ...capabilityBase,
449
- id: 'legacy-disabled',
450
- title: 'Legacy Disabled',
451
- status: 'disabled',
452
- autonomousInvocation: {
453
- allowed: false,
454
- reasons: ['status is disabled'],
455
- },
456
- }
457
- const legacyTrustedCapability = {
458
- ...capabilityBase,
459
- id: 'legacy-trusted',
460
- title: 'Legacy Trusted',
461
- sideEffect: 'read',
462
- requiresConfirmation: false,
463
- autonomousInvocation: {
464
- allowed: true,
465
- reasons: [],
466
- },
467
- }
468
- const historicalTrustedNextCommand = "tabwright capability run historical-trusted --input-json '{}' --json"
469
- const historicalTrustedCapability = {
470
- ...legacyTrustedCapability,
471
- id: 'historical-trusted',
472
- title: 'Historical Trusted',
473
- lifecycle: {
474
- stage: 'trusted',
475
- nextAction: 'run',
476
- nextCommand: historicalTrustedNextCommand,
477
- contractHealth: {
478
- state: 'unknown',
479
- reasons: [],
480
- },
481
- },
482
- }
483
- const futureLifecycleCapability = {
484
- ...legacyTrustedCapability,
485
- id: 'future-lifecycle',
486
- title: 'Future Lifecycle',
487
- recentRuns: [{ status: 'future-run-format' }],
488
- lifecycle: {
489
- stage: 'reviewed',
490
- nextAction: 'approve',
491
- nextCommand: 'tabwright capability trust future-lifecycle',
492
- contractHealth: {
493
- state: 'future-health',
494
- reasons: [],
495
- },
496
- },
497
- }
498
-
499
- const page = await testCtx.browserContext.newPage()
500
- await page.setViewportSize({ width: 1280, height: 720 })
501
- page.setDefaultTimeout(10000)
502
- async function readClipboard(): Promise<string> {
503
- return await page.evaluate(async () => {
504
- const clipboardNavigator = navigator as Navigator & {
505
- clipboard: { readText: () => Promise<string> }
506
- }
507
- return await clipboardNavigator.clipboard.readText()
508
- })
509
- }
510
- try {
511
- await testCtx.browserContext.grantPermissions(['clipboard-read', 'clipboard-write'], {
512
- origin: staticServer.baseUrl,
513
- })
514
- await page.route(`http://127.0.0.1:${TEST_PORT}/**`, async (route) => {
515
- const request = route.request()
516
- const url = new URL(request.url())
517
- const corsHeaders = {
518
- 'access-control-allow-origin': '*',
519
- 'access-control-allow-methods': 'GET,POST,OPTIONS',
520
- 'access-control-allow-headers': 'content-type',
521
- }
522
-
523
- if (request.method() === 'OPTIONS') {
524
- await route.fulfill({ status: 204, headers: corsHeaders, body: '' })
525
- return
526
- }
527
-
528
- if (url.pathname === '/rrweb-recordings') {
529
- await route.fulfill({
530
- status: 200,
531
- headers: { ...corsHeaders, 'content-type': 'application/json' },
532
- body: JSON.stringify({ recordings: [] }),
533
- })
534
- return
535
- }
536
-
537
- if (url.pathname === '/capabilities') {
538
- await route.fulfill({
539
- status: 200,
540
- headers: { ...corsHeaders, 'content-type': 'application/json' },
541
- body: JSON.stringify({
542
- cwd: '/Users/test/project',
543
- capabilities: [
544
- { ...capability, authState: capabilityAuthState },
545
- driftedCapability,
546
- disabledCapability,
547
- legacyTrustedCapability,
548
- historicalTrustedCapability,
549
- futureLifecycleCapability,
550
- ],
551
- }),
552
- })
553
- return
554
- }
555
-
556
- if (url.pathname === '/capabilities/query-user/auth/refresh' && request.method() === 'POST') {
557
- authRefreshAttempts += 1
558
- if (authRefreshAttempts === 1) {
559
- await route.fulfill({
560
- status: 409,
561
- headers: { ...corsHeaders, 'content-type': 'application/json' },
562
- body: JSON.stringify({
563
- code: 'no_enabled_tab',
564
- error: 'enable Tabwright on a browser tab before authenticating this capability',
565
- }),
566
- })
567
- return
568
- }
569
- capabilityAuthState = {
570
- ...capabilityAuthState,
571
- status: 'authenticated',
572
- cookieNames: ['SESSION'],
573
- refreshedAt: '2026-07-13T10:00:00.000Z',
574
- expiresAt: '2026-07-20T10:00:00.000Z',
575
- }
576
- await route.fulfill({
577
- status: 200,
578
- headers: { ...corsHeaders, 'content-type': 'application/json' },
579
- body: JSON.stringify({ capability: 'query-user', saved: true, authState: capabilityAuthState }),
580
- })
581
- return
582
- }
583
-
584
- await route.fulfill({ status: 404, headers: corsHeaders, body: 'not found' })
585
- })
586
-
587
- await page.goto(`${staticServer.baseUrl}/src/options.html`, { waitUntil: 'domcontentloaded' })
588
- await page.locator('.language-button[data-language="en"]').click()
589
- const skillsTab = page.locator('.tab-button[data-tab="skills"]')
590
- await skillsTab.waitFor()
591
- await skillsTab.click()
592
- const capabilityItem = page.locator('.skill-item').filter({ hasText: 'Query User' })
593
- await capabilityItem.waitFor({ timeout: 10000 })
594
- await capabilityItem.click()
595
-
596
- await expect
597
- .poll(async () => {
598
- return await page.locator('#skill-detail').textContent()
599
- })
600
- .toContain('query-user')
601
- await expect
602
- .poll(async () => {
603
- return await page.locator('#skill-detail').textContent()
604
- })
605
- .toContain('Needs your confirmation')
606
- await expect
607
- .poll(async () => {
608
- return await page.locator('#skill-detail').textContent()
609
- })
610
- .toContain('AI instructions need publishing')
611
- await expect
612
- .poll(async () => {
613
- return await page.locator('.lifecycle-card').textContent()
614
- })
615
- .toContain('Contract healthy')
616
- await page.locator('.lifecycle-card').getByRole('button', { name: 'Copy next step' }).click()
617
- const runCommand = await readClipboard()
618
- expect(runCommand).toBe(trustedNextCommand)
619
- await page.getByRole('button', { name: 'Copy for AI' }).click()
620
- const aiContext = await readClipboard()
621
- expect(aiContext).toContain('Capability ID: query-user')
622
- expect(aiContext).toContain('Look up a user by email.')
623
-
624
- const authCard = page.locator('.auth-card')
625
- await expect
626
- .poll(async () => {
627
- return await authCard.textContent()
628
- })
629
- .toContain('Not authenticated')
630
- await authCard.getByRole('button', { name: 'Authenticate with current Chrome' }).click()
631
- const authDialog = page.locator('.auth-dialog')
632
- await expect
633
- .poll(async () => {
634
- return await authDialog.textContent()
635
- })
636
- .toContain('admin.example.com')
637
- await authDialog.getByRole('button', { name: 'Allow and authenticate' }).click()
638
- await expect.poll(() => authRefreshAttempts).toBe(1)
639
- await expect
640
- .poll(async () => {
641
- return await authCard.locator('.auth-error').textContent()
642
- })
643
- .toContain('Enable Tabwright on a normal browser tab')
644
- await authCard.getByRole('button', { name: 'Authenticate with current Chrome' }).click()
645
- await page.locator('.auth-dialog').getByRole('button', { name: 'Allow and authenticate' }).click()
646
- await expect.poll(() => authRefreshAttempts).toBe(2)
647
- await expect
648
- .poll(async () => {
649
- return await page.locator('.auth-card').textContent()
650
- })
651
- .toContain('Authenticated')
652
-
653
- await page.locator('.skill-item').filter({ hasText: 'Drifted User Query' }).click()
654
- await expect
655
- .poll(async () => {
656
- return await page.locator('.lifecycle-card').textContent()
657
- })
658
- .toContain('Repair contract drift')
659
- await expect
660
- .poll(async () => {
661
- return await page.locator('.lifecycle-card').textContent()
662
- })
663
- .toContain('output.userId must be string')
664
- await page.locator('.lifecycle-card').getByRole('button', { name: 'Copy next step' }).click()
665
- expect(await readClipboard()).toBe(driftedNextCommand)
666
-
667
- await page.locator('.skill-item').filter({ hasText: 'Legacy Disabled' }).click()
668
- await expect
669
- .poll(async () => {
670
- return await page.locator('.lifecycle-card').textContent()
671
- })
672
- .toContain('Enable as draft')
673
- await page.locator('.lifecycle-card').getByRole('button', { name: 'Copy next step' }).click()
674
- expect(await readClipboard()).toBe("tabwright capability draft 'legacy-disabled'")
675
-
676
- await page.locator('.skill-item').filter({ hasText: 'Legacy Trusted' }).click()
677
- await expect
678
- .poll(async () => {
679
- return await page.locator('.lifecycle-card').textContent()
680
- })
681
- .toContain('Not yet checked for usability')
682
- await page.locator('.lifecycle-card').getByRole('button', { name: 'Copy next step' }).click()
683
- expect(await readClipboard()).toContain("tabwright capability run 'legacy-trusted'")
684
-
685
- await page.locator('.skill-item').filter({ hasText: 'Historical Trusted' }).click()
686
- await expect
687
- .poll(async () => {
688
- return await page.locator('.lifecycle-card').textContent()
689
- })
690
- .toContain('Not yet checked for usability')
691
- await page.locator('.lifecycle-card').getByRole('button', { name: 'Copy next step' }).click()
692
- expect(await readClipboard()).toBe(historicalTrustedNextCommand)
693
-
694
- await page.locator('.skill-item').filter({ hasText: 'Future Lifecycle' }).click()
695
- await expect
696
- .poll(async () => {
697
- return await page.locator('.lifecycle-card').textContent()
698
- })
699
- .toContain('This extension cannot interpret the capability lifecycle')
700
- await expect
701
- .poll(async () => {
702
- return await page.locator('#skill-detail').textContent()
703
- })
704
- .not.toContain('future-run-format')
705
- await page.locator('.lifecycle-card').getByRole('button', { name: 'Copy next step' }).click()
706
- expect(await readClipboard()).toBe("tabwright capability describe 'future-lifecycle' --json")
707
-
708
- await page.locator('.skill-item').filter({ hasText: 'Drifted User Query' }).click()
709
- await page.locator('.language-button[data-language="zh_CN"]').click()
710
- await expect
711
- .poll(async () => {
712
- return await page.locator('.lifecycle-card').textContent()
713
- })
714
- .toContain('下一步:重新检查')
715
- await expect
716
- .poll(async () => {
717
- return await page.locator('.lifecycle-card').textContent()
718
- })
719
- .toContain('配置发生变化 · 检查于')
720
- expect(await page.locator('.lifecycle-card').textContent()).not.toContain('$action$')
721
- } finally {
722
- await testCtx.browserContext.clearPermissions()
723
- await page.close()
724
- await staticServer.close()
725
- }
726
- }, 30000)
727
-
728
- test('shows a persistent degraded warning for stale relay review endpoints and clears it after recovery', async () => {
729
- if (!testCtx) {
730
- throw new Error('Test context is not initialized')
731
- }
732
-
733
- const distRoot = getExtensionDistRoot()
734
- const staticServer = await createStaticServer(distRoot)
735
- let reviewEndpointsAvailable = false
736
- const page = await testCtx.browserContext.newPage()
737
- page.setDefaultTimeout(10000)
738
- try {
739
- await page.route(`http://127.0.0.1:${TEST_PORT}/**`, async (route) => {
740
- const request = route.request()
741
- const url = new URL(request.url())
742
- const corsHeaders = {
743
- 'access-control-allow-origin': '*',
744
- 'access-control-allow-methods': 'GET,POST,OPTIONS',
745
- 'access-control-allow-headers': 'content-type',
746
- }
747
-
748
- if (request.method() === 'OPTIONS') {
749
- await route.fulfill({ status: 204, headers: corsHeaders, body: '' })
750
- return
751
- }
752
-
753
- if (!reviewEndpointsAvailable) {
754
- await route.fulfill({ status: 404, headers: corsHeaders, body: 'not found' })
755
- return
756
- }
757
-
758
- if (url.pathname === '/rrweb-recordings') {
759
- await route.fulfill({
760
- status: 200,
761
- headers: { ...corsHeaders, 'content-type': 'application/json' },
762
- body: JSON.stringify({ recordings: [] }),
763
- })
764
- return
765
- }
766
-
767
- if (url.pathname === '/capabilities') {
768
- await route.fulfill({
769
- status: 200,
770
- headers: { ...corsHeaders, 'content-type': 'application/json' },
771
- body: JSON.stringify({ cwd: '/Users/test/project', capabilities: [] }),
772
- })
773
- return
774
- }
775
-
776
- await route.fulfill({ status: 404, headers: corsHeaders, body: 'not found' })
777
- })
778
-
779
- await page.goto(`${staticServer.baseUrl}/src/options.html`, { waitUntil: 'domcontentloaded' })
780
- await page.locator('.language-button[data-language="en"]').click()
781
- await expect
782
- .poll(async () => {
783
- return await page.locator('#relay-review-warning').isVisible()
784
- })
785
- .toBe(true)
786
- await expect
787
- .poll(async () => {
788
- return await page.locator('#relay-review-warning').textContent()
789
- })
790
- .toContain('Your files were not deleted')
791
- await expect
792
- .poll(async () => {
793
- return await page.locator('#recordings-count').textContent()
794
- })
795
- .toBe('–')
796
-
797
- await page.locator('.tab-button[data-tab="skills"]').click()
798
- await expect
799
- .poll(async () => {
800
- return await page.locator('#skills-count').textContent()
801
- })
802
- .toBe('–')
803
- await expect
804
- .poll(async () => {
805
- return await page.locator('#relay-review-warning').isVisible()
806
- })
807
- .toBe(true)
808
-
809
- reviewEndpointsAvailable = true
810
- await page.locator('#refresh-button').click()
811
- await expect
812
- .poll(async () => {
813
- return await page.locator('#skills-count').textContent()
814
- })
815
- .toBe('0')
816
- await expect
817
- .poll(async () => {
818
- return await page.locator('#relay-review-warning').isVisible()
819
- })
820
- .toBe(true)
821
-
822
- await page.locator('.tab-button[data-tab="recordings"]').click()
823
- await page.locator('#refresh-button').click()
824
- await expect
825
- .poll(async () => {
826
- return await page.locator('#recordings-count').textContent()
827
- })
828
- .toBe('0')
829
- await expect
830
- .poll(async () => {
831
- return await page.locator('#relay-review-warning').isVisible()
832
- })
833
- .toBe(false)
834
- } finally {
835
- await page.close()
836
- await staticServer.close()
837
- }
838
- }, 30000)
839
- })