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
package/src/styles.ts ADDED
@@ -0,0 +1,343 @@
1
+ import type { ICDPSession } from './cdp-session.js'
2
+ import type { Locator } from '@xmorse/playwright-core'
3
+
4
+ export interface StyleSource {
5
+ url: string
6
+ line: number
7
+ column: number
8
+ }
9
+
10
+ export type StyleDeclarations = Record<string, string>
11
+
12
+ export interface StyleRule {
13
+ selector: string
14
+ source: StyleSource | null
15
+ origin: 'regular' | 'user-agent' | 'injected' | 'inspector'
16
+ declarations: StyleDeclarations
17
+ inheritedFrom: string | null
18
+ }
19
+
20
+ export interface StylesResult {
21
+ element: string
22
+ inlineStyle: StyleDeclarations | null
23
+ rules: StyleRule[]
24
+ }
25
+
26
+ interface CSSProperty {
27
+ name: string
28
+ value: string
29
+ important?: boolean
30
+ }
31
+
32
+ interface CSSStyle {
33
+ cssProperties: CSSProperty[]
34
+ cssText?: string
35
+ }
36
+
37
+ interface CSSRule {
38
+ selectorList: { text: string }
39
+ style: CSSStyle
40
+ styleSheetId?: string
41
+ origin: string
42
+ }
43
+
44
+ interface RuleMatch {
45
+ rule: CSSRule
46
+ matchingSelectors: number[]
47
+ }
48
+
49
+ interface InheritedStyleEntry {
50
+ inlineStyle?: CSSStyle
51
+ matchedCSSRules: RuleMatch[]
52
+ }
53
+
54
+ interface SourceRange {
55
+ startLine: number
56
+ startColumn: number
57
+ endLine: number
58
+ endColumn: number
59
+ }
60
+
61
+ interface CSSStyleSheetHeader {
62
+ styleSheetId: string
63
+ sourceURL?: string
64
+ origin: string
65
+ }
66
+
67
+ export async function getStylesForLocator({
68
+ locator,
69
+ cdp: cdpSession,
70
+ includeUserAgentStyles = false,
71
+ }: {
72
+ locator: Locator
73
+ cdp: ICDPSession
74
+ includeUserAgentStyles?: boolean
75
+ }): Promise<StylesResult> {
76
+ const cdp = cdpSession
77
+ await cdp.send('DOM.enable')
78
+ await cdp.send('CSS.enable')
79
+
80
+ const elementHandle = await locator.elementHandle()
81
+ if (!elementHandle) {
82
+ throw new Error('Could not get element handle from locator')
83
+ }
84
+
85
+ const remoteObject = (elementHandle as any)._channel?.objectId
86
+ ? { objectId: (elementHandle as any)._channel.objectId }
87
+ : null
88
+
89
+ let backendNodeId: number
90
+ if (remoteObject?.objectId) {
91
+ const nodeInfo = await cdp.send('DOM.describeNode', {
92
+ objectId: remoteObject.objectId,
93
+ })
94
+ backendNodeId = nodeInfo.node.backendNodeId
95
+ } else {
96
+ const box = await elementHandle.boundingBox()
97
+ if (!box) {
98
+ throw new Error('Element has no bounding box')
99
+ }
100
+ const docResult = await cdp.send('DOM.getDocument', { depth: 0 })
101
+ const nodeAtPoint = await cdp.send('DOM.getNodeForLocation', {
102
+ x: Math.round(box.x + box.width / 2),
103
+ y: Math.round(box.y + box.height / 2),
104
+ })
105
+ backendNodeId = nodeAtPoint.backendNodeId
106
+ }
107
+
108
+ const pushResult = await cdp.send('DOM.pushNodesByBackendIdsToFrontend', {
109
+ backendNodeIds: [backendNodeId],
110
+ })
111
+ const nodeId = pushResult.nodeIds[0]
112
+
113
+ if (!nodeId) {
114
+ throw new Error('Could not get nodeId for element')
115
+ }
116
+
117
+ const nodeInfo = await cdp.send('DOM.describeNode', { nodeId })
118
+ const elementDescription = formatElementDescription(nodeInfo.node)
119
+
120
+ const matchedStyles = await cdp.send('CSS.getMatchedStylesForNode', { nodeId })
121
+
122
+ const stylesheetUrls = new Map<string, string>()
123
+
124
+ const processStyleSheetId = async (styleSheetId: string | undefined): Promise<StyleSource | null> => {
125
+ if (!styleSheetId) {
126
+ return null
127
+ }
128
+
129
+ if (!stylesheetUrls.has(styleSheetId)) {
130
+ try {
131
+ const header = await cdp.send('CSS.getStyleSheetText', { styleSheetId })
132
+ stylesheetUrls.set(styleSheetId, '')
133
+ } catch {
134
+ stylesheetUrls.set(styleSheetId, '')
135
+ }
136
+ }
137
+
138
+ return null
139
+ }
140
+
141
+ const rules: StyleRule[] = []
142
+
143
+ if (matchedStyles.matchedCSSRules) {
144
+ for (const ruleMatch of matchedStyles.matchedCSSRules) {
145
+ const rule = ruleMatch.rule
146
+ const sourceRange = (rule as any).selectorList?.range as SourceRange | undefined
147
+ const styleSheetId = rule.styleSheetId
148
+
149
+ let source: StyleSource | null = null
150
+ if (styleSheetId && sourceRange) {
151
+ const styleSheet = (matchedStyles as any).cssStyleSheetHeaders?.find(
152
+ (h: CSSStyleSheetHeader) => h.styleSheetId === styleSheetId,
153
+ )
154
+ const url =
155
+ styleSheet?.sourceURL || (rule as any).origin === 'user-agent' ? 'user-agent' : `stylesheet:${styleSheetId}`
156
+
157
+ source = {
158
+ url: (rule as any).styleSheetId ? await getStylesheetUrl(cdp, styleSheetId) : 'user-agent',
159
+ line: sourceRange.startLine + 1,
160
+ column: sourceRange.startColumn,
161
+ }
162
+ }
163
+
164
+ rules.push({
165
+ selector: rule.selectorList.text,
166
+ source,
167
+ origin: rule.origin as StyleRule['origin'],
168
+ declarations: extractDeclarations(rule.style),
169
+ inheritedFrom: null,
170
+ })
171
+ }
172
+ }
173
+
174
+ if (matchedStyles.inherited) {
175
+ for (let i = 0; i < matchedStyles.inherited.length; i++) {
176
+ const inheritedEntry = matchedStyles.inherited[i] as InheritedStyleEntry
177
+ const ancestorDesc = `ancestor[${i + 1}]`
178
+
179
+ if (inheritedEntry.inlineStyle) {
180
+ const declarations = extractDeclarations(inheritedEntry.inlineStyle)
181
+ if (Object.keys(declarations).length > 0) {
182
+ rules.push({
183
+ selector: 'element.style',
184
+ source: null,
185
+ origin: 'regular',
186
+ declarations,
187
+ inheritedFrom: ancestorDesc,
188
+ })
189
+ }
190
+ }
191
+
192
+ for (const ruleMatch of inheritedEntry.matchedCSSRules) {
193
+ const rule = ruleMatch.rule
194
+ const sourceRange = (rule as any).selectorList?.range as SourceRange | undefined
195
+ const styleSheetId = rule.styleSheetId
196
+
197
+ let source: StyleSource | null = null
198
+ if (styleSheetId && sourceRange) {
199
+ source = {
200
+ url: await getStylesheetUrl(cdp, styleSheetId),
201
+ line: sourceRange.startLine + 1,
202
+ column: sourceRange.startColumn,
203
+ }
204
+ }
205
+
206
+ const declarations = extractDeclarations(rule.style)
207
+ if (Object.keys(declarations).length > 0) {
208
+ rules.push({
209
+ selector: rule.selectorList.text,
210
+ source,
211
+ origin: rule.origin as StyleRule['origin'],
212
+ declarations,
213
+ inheritedFrom: ancestorDesc,
214
+ })
215
+ }
216
+ }
217
+ }
218
+ }
219
+
220
+ let inlineStyle: StyleDeclarations | null = null
221
+ if (matchedStyles.inlineStyle) {
222
+ const declarations = extractDeclarations(matchedStyles.inlineStyle as CSSStyle)
223
+ if (Object.keys(declarations).length > 0) {
224
+ inlineStyle = declarations
225
+ }
226
+ }
227
+
228
+ const filteredRules = includeUserAgentStyles ? rules : rules.filter((r) => r.origin !== 'user-agent')
229
+
230
+ return {
231
+ element: elementDescription,
232
+ inlineStyle,
233
+ rules: filteredRules,
234
+ }
235
+ }
236
+
237
+ function extractDeclarations(style: CSSStyle): StyleDeclarations {
238
+ if (!style?.cssProperties) {
239
+ return {}
240
+ }
241
+
242
+ const result: StyleDeclarations = {}
243
+ for (const prop of style.cssProperties) {
244
+ if (!prop.value || prop.value === 'initial' || prop.name.startsWith('-webkit-')) {
245
+ continue
246
+ }
247
+ const value = prop.important ? `${prop.value} !important` : prop.value
248
+ result[prop.name] = value
249
+ }
250
+ return result
251
+ }
252
+
253
+ function formatElementDescription(node: any): string {
254
+ let desc = node.localName || node.nodeName?.toLowerCase() || 'element'
255
+
256
+ if (node.attributes) {
257
+ const attrs: Record<string, string> = {}
258
+ for (let i = 0; i < node.attributes.length; i += 2) {
259
+ attrs[node.attributes[i]] = node.attributes[i + 1]
260
+ }
261
+
262
+ if (attrs.id) {
263
+ desc += `#${attrs.id}`
264
+ }
265
+ if (attrs.class) {
266
+ desc += `.${attrs.class.split(' ').join('.')}`
267
+ }
268
+ }
269
+
270
+ return desc
271
+ }
272
+
273
+ async function getStylesheetUrl(cdp: ICDPSession, styleSheetId: string): Promise<string> {
274
+ try {
275
+ await cdp.send('CSS.getStyleSheetText', { styleSheetId })
276
+ return `stylesheet:${styleSheetId}`
277
+ } catch {
278
+ return `stylesheet:${styleSheetId}`
279
+ }
280
+ }
281
+
282
+ export function formatStylesAsText(styles: StylesResult): string {
283
+ const lines: string[] = []
284
+
285
+ lines.push(`Element: ${styles.element}`)
286
+ lines.push('')
287
+
288
+ if (styles.inlineStyle) {
289
+ lines.push('Inline styles:')
290
+ for (const [prop, value] of Object.entries(styles.inlineStyle)) {
291
+ lines.push(` ${prop}: ${value}`)
292
+ }
293
+ lines.push('')
294
+ }
295
+
296
+ const directRules = styles.rules.filter((r) => !r.inheritedFrom)
297
+ const inheritedRules = styles.rules.filter((r) => r.inheritedFrom)
298
+
299
+ if (directRules.length > 0) {
300
+ lines.push('Matched rules:')
301
+ for (const rule of directRules) {
302
+ lines.push(` ${rule.selector} {`)
303
+ const sourceInfo = rule.source ? ` /* ${rule.source.url}:${rule.source.line}:${rule.source.column} */` : ''
304
+ if (sourceInfo) {
305
+ lines.push(` ${sourceInfo}`)
306
+ }
307
+ for (const [prop, value] of Object.entries(rule.declarations)) {
308
+ lines.push(` ${prop}: ${value};`)
309
+ }
310
+ lines.push(' }')
311
+ }
312
+ lines.push('')
313
+ }
314
+
315
+ if (inheritedRules.length > 0) {
316
+ const byAncestor = new Map<string, StyleRule[]>()
317
+ for (const rule of inheritedRules) {
318
+ const key = rule.inheritedFrom!
319
+ if (!byAncestor.has(key)) {
320
+ byAncestor.set(key, [])
321
+ }
322
+ byAncestor.get(key)!.push(rule)
323
+ }
324
+
325
+ for (const [ancestor, rules] of byAncestor) {
326
+ lines.push(`Inherited from ${ancestor}:`)
327
+ for (const rule of rules) {
328
+ lines.push(` ${rule.selector} {`)
329
+ const sourceInfo = rule.source ? ` /* ${rule.source.url}:${rule.source.line}:${rule.source.column} */` : ''
330
+ if (sourceInfo) {
331
+ lines.push(` ${sourceInfo}`)
332
+ }
333
+ for (const [prop, value] of Object.entries(rule.declarations)) {
334
+ lines.push(` ${prop}: ${value};`)
335
+ }
336
+ lines.push(' }')
337
+ }
338
+ lines.push('')
339
+ }
340
+ }
341
+
342
+ return lines.join('\n')
343
+ }
@@ -0,0 +1,61 @@
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+ import { afterEach, describe, expect, test } from 'vitest'
4
+ import { getTabwrightAgentSkillStatus, installTabwrightAgentSkill } from './tabwright-agent-skill.js'
5
+
6
+ const tempDirs: string[] = []
7
+
8
+ afterEach(() => {
9
+ tempDirs.splice(0).map((dir) => {
10
+ fs.rmSync(dir, { recursive: true, force: true })
11
+ return dir
12
+ })
13
+ })
14
+
15
+ function createFixture(): { bundledSkillPath: string; codexHome: string } {
16
+ const tmpRoot = path.resolve(process.cwd(), '..', 'tmp')
17
+ fs.mkdirSync(tmpRoot, { recursive: true })
18
+ const dir = fs.mkdtempSync(path.join(tmpRoot, 'tabwright-agent-skill-test-'))
19
+ tempDirs.push(dir)
20
+ const bundledSkillPath = path.join(dir, 'bundled', 'SKILL.md')
21
+ fs.mkdirSync(path.dirname(bundledSkillPath), { recursive: true })
22
+ fs.writeFileSync(bundledSkillPath, '---\nname: tabwright\ndescription: Test skill\n---\n\nUse Tabwright.\n')
23
+ return { bundledSkillPath, codexHome: path.join(dir, 'codex-home') }
24
+ }
25
+
26
+ describe('Tabwright agent skill installation', () => {
27
+ test('installs the bundled skill and reports it current', () => {
28
+ const fixture = createFixture()
29
+ const missing = getTabwrightAgentSkillStatus(fixture)
30
+ expect(missing.state).toBe('missing')
31
+ expect(missing.installCommand).toBe('tabwright skill install --target codex')
32
+
33
+ const installed = installTabwrightAgentSkill(fixture)
34
+ expect(installed.fileStatus).toBe('created')
35
+ expect(installed.state).toBe('current')
36
+ expect(fs.readFileSync(installed.installedPath, 'utf-8')).toBe(
37
+ fs.readFileSync(fixture.bundledSkillPath, 'utf-8'),
38
+ )
39
+
40
+ const unchanged = installTabwrightAgentSkill(fixture)
41
+ expect(unchanged.fileStatus).toBe('unchanged')
42
+ })
43
+
44
+ test('requires force before replacing a different installed skill', () => {
45
+ const fixture = createFixture()
46
+ const installedPath = path.join(fixture.codexHome, 'skills', 'tabwright', 'SKILL.md')
47
+ fs.mkdirSync(path.dirname(installedPath), { recursive: true })
48
+ fs.writeFileSync(installedPath, 'locally edited skill\n')
49
+
50
+ const outdated = getTabwrightAgentSkillStatus(fixture)
51
+ expect(outdated.state).toBe('outdated')
52
+ expect(outdated.installCommand).toBe('tabwright skill install --target codex --force')
53
+ expect(() => {
54
+ installTabwrightAgentSkill(fixture)
55
+ }).toThrow(/Use --force to overwrite/)
56
+
57
+ const updated = installTabwrightAgentSkill({ ...fixture, overwrite: true })
58
+ expect(updated.fileStatus).toBe('updated')
59
+ expect(updated.state).toBe('current')
60
+ })
61
+ })
@@ -0,0 +1,105 @@
1
+ import crypto from 'node:crypto'
2
+ import fs from 'node:fs'
3
+ import os from 'node:os'
4
+ import path from 'node:path'
5
+ import { getInstalledTabwrightPackageDir } from './package-paths.js'
6
+
7
+ export type TabwrightAgentSkillTarget = 'codex'
8
+ export type TabwrightAgentSkillState = 'missing' | 'current' | 'outdated'
9
+
10
+ export interface TabwrightAgentSkillStatus {
11
+ target: TabwrightAgentSkillTarget
12
+ state: TabwrightAgentSkillState
13
+ bundledPath: string
14
+ installedPath: string
15
+ bundledSha256: string
16
+ installedSha256?: string
17
+ installCommand: string
18
+ }
19
+
20
+ export interface TabwrightAgentSkillInstallResult extends TabwrightAgentSkillStatus {
21
+ fileStatus: 'created' | 'updated' | 'unchanged'
22
+ next: string[]
23
+ }
24
+
25
+ export function getBundledTabwrightAgentSkillPath(options: { bundledSkillPath?: string } = {}): string {
26
+ if (options.bundledSkillPath) {
27
+ return options.bundledSkillPath
28
+ }
29
+ const packageDir = getInstalledTabwrightPackageDir()
30
+ const repositoryRoot = path.join(packageDir, '..')
31
+ const packagedSkillPath = path.join(packageDir, 'dist', 'agent-skills', 'tabwright', 'SKILL.md')
32
+ const repositorySkillPath = path.join(repositoryRoot, 'skills', 'tabwright', 'SKILL.md')
33
+ const candidates = fs.existsSync(path.join(repositoryRoot, '.git'))
34
+ ? [repositorySkillPath, packagedSkillPath]
35
+ : [packagedSkillPath]
36
+ const bundledPath = candidates.find((candidate) => {
37
+ return fs.existsSync(candidate)
38
+ })
39
+ if (!bundledPath) {
40
+ throw new Error(`Bundled Tabwright skill not found under ${packageDir}. Rebuild or reinstall the CLI.`)
41
+ }
42
+ return bundledPath
43
+ }
44
+
45
+ export function getTabwrightAgentSkillStatus(options: {
46
+ target?: TabwrightAgentSkillTarget
47
+ codexHome?: string
48
+ bundledSkillPath?: string
49
+ } = {}): TabwrightAgentSkillStatus {
50
+ const target = options.target || 'codex'
51
+ const bundledPath = getBundledTabwrightAgentSkillPath({ bundledSkillPath: options.bundledSkillPath })
52
+ const installedPath = path.join(getCodexHome(options.codexHome), 'skills', 'tabwright', 'SKILL.md')
53
+ const bundledContent = fs.readFileSync(bundledPath, 'utf-8')
54
+ const installedContent = fs.existsSync(installedPath) ? fs.readFileSync(installedPath, 'utf-8') : undefined
55
+ const state: TabwrightAgentSkillState = (() => {
56
+ if (installedContent === undefined) {
57
+ return 'missing'
58
+ }
59
+ return installedContent === bundledContent ? 'current' : 'outdated'
60
+ })()
61
+ return {
62
+ target,
63
+ state,
64
+ bundledPath,
65
+ installedPath,
66
+ bundledSha256: sha256(bundledContent),
67
+ ...(installedContent === undefined ? {} : { installedSha256: sha256(installedContent) }),
68
+ installCommand: `tabwright skill install --target ${target}${state === 'outdated' ? ' --force' : ''}`,
69
+ }
70
+ }
71
+
72
+ export function installTabwrightAgentSkill(options: {
73
+ target?: TabwrightAgentSkillTarget
74
+ codexHome?: string
75
+ bundledSkillPath?: string
76
+ overwrite?: boolean
77
+ } = {}): TabwrightAgentSkillInstallResult {
78
+ const before = getTabwrightAgentSkillStatus(options)
79
+ if (before.state === 'current') {
80
+ return {
81
+ ...before,
82
+ fileStatus: 'unchanged',
83
+ next: ['Restart or open a new Codex thread so it can load the Tabwright skill.'],
84
+ }
85
+ }
86
+ if (before.state === 'outdated' && !options.overwrite) {
87
+ throw new Error(`Installed Tabwright skill differs from this CLI: ${before.installedPath}. Use --force to overwrite.`)
88
+ }
89
+ fs.mkdirSync(path.dirname(before.installedPath), { recursive: true })
90
+ fs.copyFileSync(before.bundledPath, before.installedPath)
91
+ const after = getTabwrightAgentSkillStatus(options)
92
+ return {
93
+ ...after,
94
+ fileStatus: before.state === 'missing' ? 'created' : 'updated',
95
+ next: ['Restart or open a new Codex thread so it can load the Tabwright skill.'],
96
+ }
97
+ }
98
+
99
+ function getCodexHome(codexHome?: string): string {
100
+ return path.resolve(codexHome || process.env.CODEX_HOME || path.join(os.homedir(), '.codex'))
101
+ }
102
+
103
+ function sha256(content: string): string {
104
+ return crypto.createHash('sha256').update(content).digest('hex')
105
+ }
@@ -0,0 +1,13 @@
1
+ import type { ExtensionState } from 'mcp-extension/src/types.js'
2
+
3
+ declare global {
4
+ var toggleExtensionForActiveTab: () => Promise<{ isConnected: boolean; state: ExtensionState }>
5
+ var getExtensionState: () => ExtensionState
6
+ var disconnectEverything: () => Promise<void>
7
+
8
+ // Browser globals used in evaluate() calls
9
+ var window: any
10
+ var document: any
11
+ }
12
+
13
+ export {}
@@ -0,0 +1,70 @@
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+ import { describe, expect, test } from 'vitest'
4
+ import { startTabwrightCDPRelayServer } from './cdp-relay.js'
5
+ import {
6
+ getExtensionServiceWorker,
7
+ getLegacyExtensionLaunchArgs,
8
+ isExtensionLoadUnavailableError,
9
+ launchPersistentContextWithExtensions,
10
+ } from './test-utils.js'
11
+
12
+ describe('extension test browser launch', () => {
13
+ test('builds the legacy extension launch fallback flags', () => {
14
+ const extensionPaths = ['./extension-one', './extension-two']
15
+ const args = getLegacyExtensionLaunchArgs({ extensionPaths })
16
+ const resolvedPaths = extensionPaths.map((extensionPath) => {
17
+ return path.resolve(extensionPath)
18
+ })
19
+
20
+ expect(args).toContain(`--disable-extensions-except=${resolvedPaths.join(',')}`)
21
+ expect(args).toContain(`--load-extension=${resolvedPaths.join(',')}`)
22
+ })
23
+
24
+ test('recognizes older browsers without Extensions.loadUnpacked', () => {
25
+ expect(
26
+ isExtensionLoadUnavailableError(
27
+ new Error("Protocol error (Extensions.loadUnpacked): 'Extensions.loadUnpacked' wasn't found"),
28
+ ),
29
+ ).toBe(true)
30
+ expect(isExtensionLoadUnavailableError(new Error('Method not found'))).toBe(true)
31
+ expect(isExtensionLoadUnavailableError(new Error('Manifest is invalid'))).toBe(false)
32
+ })
33
+
34
+ test.runIf(Boolean(process.env.PLAYWRITER_TEST_EXTENSION_PATH))(
35
+ 'loads an unpacked extension in the installed Chrome build',
36
+ async () => {
37
+ const extensionPath = process.env.PLAYWRITER_TEST_EXTENSION_PATH
38
+ if (!extensionPath) {
39
+ throw new Error('PLAYWRITER_TEST_EXTENSION_PATH is required')
40
+ }
41
+
42
+ const tempRoot = path.join(process.cwd(), 'tmp')
43
+ fs.mkdirSync(tempRoot, { recursive: true })
44
+ const userDataDir = fs.mkdtempSync(path.join(tempRoot, 'pw-extension-load-test-'))
45
+ const relayServer = await startTabwrightCDPRelayServer({
46
+ port: Number(process.env.PLAYWRITER_TEST_RELAY_PORT) || 19_997,
47
+ })
48
+ try {
49
+ const browserContext = await launchPersistentContextWithExtensions({
50
+ userDataDir,
51
+ extensionPaths: [extensionPath],
52
+ })
53
+ try {
54
+ const serviceWorker = await getExtensionServiceWorker(browserContext).catch(async (error: unknown) => {
55
+ const session = await browserContext.browser()?.newBrowserCDPSession()
56
+ const targets = session ? await session.send('Target.getTargets') : null
57
+ throw new Error(`No extension service worker target was visible: ${JSON.stringify(targets)}`, { cause: error })
58
+ })
59
+ expect(serviceWorker.url()).toMatch(/^chrome-extension:\/\//)
60
+ } finally {
61
+ await browserContext.close()
62
+ }
63
+ } finally {
64
+ relayServer.close()
65
+ fs.rmSync(userDataDir, { recursive: true, force: true })
66
+ }
67
+ },
68
+ 60_000,
69
+ )
70
+ })