tabwright 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (599) hide show
  1. package/LICENSE +21 -0
  2. package/bin.js +4 -0
  3. package/dist/a11y-client.js +204 -0
  4. package/dist/agent-skills/tabwright/SKILL.md +119 -0
  5. package/dist/aria-snapshot.d.ts +262 -0
  6. package/dist/aria-snapshot.d.ts.map +1 -0
  7. package/dist/aria-snapshot.js +1256 -0
  8. package/dist/aria-snapshot.js.map +1 -0
  9. package/dist/aria-snapshot.test.d.ts +2 -0
  10. package/dist/aria-snapshot.test.d.ts.map +1 -0
  11. package/dist/aria-snapshot.test.js +270 -0
  12. package/dist/aria-snapshot.test.js.map +1 -0
  13. package/dist/aria-snapshot.unit.test.d.ts +2 -0
  14. package/dist/aria-snapshot.unit.test.d.ts.map +1 -0
  15. package/dist/aria-snapshot.unit.test.js +542 -0
  16. package/dist/aria-snapshot.unit.test.js.map +1 -0
  17. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts +5 -0
  18. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts.map +1 -0
  19. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js +5 -0
  20. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js.map +1 -0
  21. package/dist/bippy.js +894 -0
  22. package/dist/browser-config.d.ts +13 -0
  23. package/dist/browser-config.d.ts.map +1 -0
  24. package/dist/browser-config.js +126 -0
  25. package/dist/browser-config.js.map +1 -0
  26. package/dist/browser-install.d.ts +16 -0
  27. package/dist/browser-install.d.ts.map +1 -0
  28. package/dist/browser-install.js +238 -0
  29. package/dist/browser-install.js.map +1 -0
  30. package/dist/browser-launch.d.ts +17 -0
  31. package/dist/browser-launch.d.ts.map +1 -0
  32. package/dist/browser-launch.js +44 -0
  33. package/dist/browser-launch.js.map +1 -0
  34. package/dist/builtin-capabilities.d.ts +28 -0
  35. package/dist/builtin-capabilities.d.ts.map +1 -0
  36. package/dist/builtin-capabilities.js +2673 -0
  37. package/dist/builtin-capabilities.js.map +1 -0
  38. package/dist/capability-agent-skill.d.ts +60 -0
  39. package/dist/capability-agent-skill.d.ts.map +1 -0
  40. package/dist/capability-agent-skill.js +225 -0
  41. package/dist/capability-agent-skill.js.map +1 -0
  42. package/dist/capability-auth-state.d.ts +34 -0
  43. package/dist/capability-auth-state.d.ts.map +1 -0
  44. package/dist/capability-auth-state.js +157 -0
  45. package/dist/capability-auth-state.js.map +1 -0
  46. package/dist/capability-auth.d.ts +36 -0
  47. package/dist/capability-auth.d.ts.map +1 -0
  48. package/dist/capability-auth.js +198 -0
  49. package/dist/capability-auth.js.map +1 -0
  50. package/dist/capability-cli-confirmation.test.d.ts +2 -0
  51. package/dist/capability-cli-confirmation.test.d.ts.map +1 -0
  52. package/dist/capability-cli-confirmation.test.js +79 -0
  53. package/dist/capability-cli-confirmation.test.js.map +1 -0
  54. package/dist/capability-options.d.ts +20 -0
  55. package/dist/capability-options.d.ts.map +1 -0
  56. package/dist/capability-options.js +31 -0
  57. package/dist/capability-options.js.map +1 -0
  58. package/dist/capability-options.test.d.ts +2 -0
  59. package/dist/capability-options.test.d.ts.map +1 -0
  60. package/dist/capability-options.test.js +81 -0
  61. package/dist/capability-options.test.js.map +1 -0
  62. package/dist/capability-package.d.ts +27 -0
  63. package/dist/capability-package.d.ts.map +1 -0
  64. package/dist/capability-package.js +444 -0
  65. package/dist/capability-package.js.map +1 -0
  66. package/dist/capability-package.test.d.ts +2 -0
  67. package/dist/capability-package.test.d.ts.map +1 -0
  68. package/dist/capability-package.test.js +179 -0
  69. package/dist/capability-package.test.js.map +1 -0
  70. package/dist/capability-registry.d.ts +262 -0
  71. package/dist/capability-registry.d.ts.map +1 -0
  72. package/dist/capability-registry.js +931 -0
  73. package/dist/capability-registry.js.map +1 -0
  74. package/dist/capability-registry.test.d.ts +2 -0
  75. package/dist/capability-registry.test.d.ts.map +1 -0
  76. package/dist/capability-registry.test.js +1683 -0
  77. package/dist/capability-registry.test.js.map +1 -0
  78. package/dist/capability-runner.d.ts +99 -0
  79. package/dist/capability-runner.d.ts.map +1 -0
  80. package/dist/capability-runner.js +608 -0
  81. package/dist/capability-runner.js.map +1 -0
  82. package/dist/capability-search-relevance.test.d.ts +2 -0
  83. package/dist/capability-search-relevance.test.d.ts.map +1 -0
  84. package/dist/capability-search-relevance.test.js +67 -0
  85. package/dist/capability-search-relevance.test.js.map +1 -0
  86. package/dist/capability-studio.d.ts +11 -0
  87. package/dist/capability-studio.d.ts.map +1 -0
  88. package/dist/capability-studio.js +593 -0
  89. package/dist/capability-studio.js.map +1 -0
  90. package/dist/capability-studio.test.d.ts +2 -0
  91. package/dist/capability-studio.test.d.ts.map +1 -0
  92. package/dist/capability-studio.test.js +41 -0
  93. package/dist/capability-studio.test.js.map +1 -0
  94. package/dist/cdp-log.d.ts +19 -0
  95. package/dist/cdp-log.d.ts.map +1 -0
  96. package/dist/cdp-log.js +83 -0
  97. package/dist/cdp-log.js.map +1 -0
  98. package/dist/cdp-log.test.d.ts +2 -0
  99. package/dist/cdp-log.test.d.ts.map +1 -0
  100. package/dist/cdp-log.test.js +109 -0
  101. package/dist/cdp-log.test.js.map +1 -0
  102. package/dist/cdp-relay.d.ts +19 -0
  103. package/dist/cdp-relay.d.ts.map +1 -0
  104. package/dist/cdp-relay.js +2375 -0
  105. package/dist/cdp-relay.js.map +1 -0
  106. package/dist/cdp-session.d.ts +37 -0
  107. package/dist/cdp-session.d.ts.map +1 -0
  108. package/dist/cdp-session.js +36 -0
  109. package/dist/cdp-session.js.map +1 -0
  110. package/dist/cdp-types.d.ts +65 -0
  111. package/dist/cdp-types.d.ts.map +1 -0
  112. package/dist/cdp-types.js +91 -0
  113. package/dist/cdp-types.js.map +1 -0
  114. package/dist/channel-owner-inspect.test.d.ts +2 -0
  115. package/dist/channel-owner-inspect.test.d.ts.map +1 -0
  116. package/dist/channel-owner-inspect.test.js +75 -0
  117. package/dist/channel-owner-inspect.test.js.map +1 -0
  118. package/dist/chrome-discovery.d.ts +65 -0
  119. package/dist/chrome-discovery.d.ts.map +1 -0
  120. package/dist/chrome-discovery.js +173 -0
  121. package/dist/chrome-discovery.js.map +1 -0
  122. package/dist/chrome-discovery.test.d.ts +2 -0
  123. package/dist/chrome-discovery.test.d.ts.map +1 -0
  124. package/dist/chrome-discovery.test.js +41 -0
  125. package/dist/chrome-discovery.test.js.map +1 -0
  126. package/dist/clean-html.d.ts +11 -0
  127. package/dist/clean-html.d.ts.map +1 -0
  128. package/dist/clean-html.js +106 -0
  129. package/dist/clean-html.js.map +1 -0
  130. package/dist/cli-help.test.d.ts +2 -0
  131. package/dist/cli-help.test.d.ts.map +1 -0
  132. package/dist/cli-help.test.js +98 -0
  133. package/dist/cli-help.test.js.map +1 -0
  134. package/dist/cli.d.ts +3 -0
  135. package/dist/cli.d.ts.map +1 -0
  136. package/dist/cli.js +2709 -0
  137. package/dist/cli.js.map +1 -0
  138. package/dist/cloud-client.d.ts +56 -0
  139. package/dist/cloud-client.d.ts.map +1 -0
  140. package/dist/cloud-client.js +127 -0
  141. package/dist/cloud-client.js.map +1 -0
  142. package/dist/create-logger.d.ts +9 -0
  143. package/dist/create-logger.d.ts.map +1 -0
  144. package/dist/create-logger.js +27 -0
  145. package/dist/create-logger.js.map +1 -0
  146. package/dist/debugger-api.md +458 -0
  147. package/dist/debugger-examples-types.d.ts +24 -0
  148. package/dist/debugger-examples-types.d.ts.map +1 -0
  149. package/dist/debugger-examples-types.js +2 -0
  150. package/dist/debugger-examples-types.js.map +1 -0
  151. package/dist/debugger-examples.d.ts +6 -0
  152. package/dist/debugger-examples.d.ts.map +1 -0
  153. package/dist/debugger-examples.js +53 -0
  154. package/dist/debugger-examples.js.map +1 -0
  155. package/dist/debugger.d.ts +381 -0
  156. package/dist/debugger.d.ts.map +1 -0
  157. package/dist/debugger.js +630 -0
  158. package/dist/debugger.js.map +1 -0
  159. package/dist/diff-utils.d.ts +20 -0
  160. package/dist/diff-utils.d.ts.map +1 -0
  161. package/dist/diff-utils.js +50 -0
  162. package/dist/diff-utils.js.map +1 -0
  163. package/dist/diff-utils.test.d.ts +2 -0
  164. package/dist/diff-utils.test.d.ts.map +1 -0
  165. package/dist/diff-utils.test.js +137 -0
  166. package/dist/diff-utils.test.js.map +1 -0
  167. package/dist/doctor.d.ts +44 -0
  168. package/dist/doctor.d.ts.map +1 -0
  169. package/dist/doctor.js +246 -0
  170. package/dist/doctor.js.map +1 -0
  171. package/dist/doctor.test.d.ts +2 -0
  172. package/dist/doctor.test.d.ts.map +1 -0
  173. package/dist/doctor.test.js +208 -0
  174. package/dist/doctor.test.js.map +1 -0
  175. package/dist/editor-api.md +374 -0
  176. package/dist/editor-examples.d.ts +11 -0
  177. package/dist/editor-examples.d.ts.map +1 -0
  178. package/dist/editor-examples.js +124 -0
  179. package/dist/editor-examples.js.map +1 -0
  180. package/dist/editor.d.ts +203 -0
  181. package/dist/editor.d.ts.map +1 -0
  182. package/dist/editor.js +363 -0
  183. package/dist/editor.js.map +1 -0
  184. package/dist/env-compat.d.ts +2 -0
  185. package/dist/env-compat.d.ts.map +1 -0
  186. package/dist/env-compat.js +27 -0
  187. package/dist/env-compat.js.map +1 -0
  188. package/dist/executor.d.ts +229 -0
  189. package/dist/executor.d.ts.map +1 -0
  190. package/dist/executor.js +1465 -0
  191. package/dist/executor.js.map +1 -0
  192. package/dist/executor.unit.test.d.ts +2 -0
  193. package/dist/executor.unit.test.d.ts.map +1 -0
  194. package/dist/executor.unit.test.js +143 -0
  195. package/dist/executor.unit.test.js.map +1 -0
  196. package/dist/extension/_locales/en/messages.json +278 -0
  197. package/dist/extension/_locales/zh_CN/messages.json +256 -0
  198. package/dist/extension/assets/options-CYH96Lcx.css +1349 -0
  199. package/dist/extension/background.js +3994 -0
  200. package/dist/extension/icons/SolarCursorSquareBold.png +0 -0
  201. package/dist/extension/icons/icon-black-128.png +0 -0
  202. package/dist/extension/icons/icon-black-16.png +0 -0
  203. package/dist/extension/icons/icon-black-32.png +0 -0
  204. package/dist/extension/icons/icon-black-48.png +0 -0
  205. package/dist/extension/icons/icon-gray-128.png +0 -0
  206. package/dist/extension/icons/icon-gray-16.png +0 -0
  207. package/dist/extension/icons/icon-gray-32.png +0 -0
  208. package/dist/extension/icons/icon-gray-48.png +0 -0
  209. package/dist/extension/icons/icon-green-128.png +0 -0
  210. package/dist/extension/icons/icon-green-16.png +0 -0
  211. package/dist/extension/icons/icon-green-32.png +0 -0
  212. package/dist/extension/icons/icon-green-48.png +0 -0
  213. package/dist/extension/icons/tabwright-icon-black.png +0 -0
  214. package/dist/extension/icons/tabwright-icon-gray-disabled.png +0 -0
  215. package/dist/extension/icons/tabwright-icon-gray-disabled.svg +1 -0
  216. package/dist/extension/manifest.json +54 -0
  217. package/dist/extension/options.js +16145 -0
  218. package/dist/extension/rrweb-recorder.js +12952 -0
  219. package/dist/extension/src/options.html +165 -0
  220. package/dist/extension/src/prism-bash.min.js +1 -0
  221. package/dist/extension/src/prism.min.js +1 -0
  222. package/dist/extension/src/welcome.html +396 -0
  223. package/dist/extension-connection.test.d.ts +2 -0
  224. package/dist/extension-connection.test.d.ts.map +1 -0
  225. package/dist/extension-connection.test.js +708 -0
  226. package/dist/extension-connection.test.js.map +1 -0
  227. package/dist/extension-icon-warning.test.d.ts +2 -0
  228. package/dist/extension-icon-warning.test.d.ts.map +1 -0
  229. package/dist/extension-icon-warning.test.js +33 -0
  230. package/dist/extension-icon-warning.test.js.map +1 -0
  231. package/dist/ghost-browser.d.ts +62 -0
  232. package/dist/ghost-browser.d.ts.map +1 -0
  233. package/dist/ghost-browser.js +107 -0
  234. package/dist/ghost-browser.js.map +1 -0
  235. package/dist/ghost-cursor-client.js +374 -0
  236. package/dist/ghost-cursor-controller.d.ts +46 -0
  237. package/dist/ghost-cursor-controller.d.ts.map +1 -0
  238. package/dist/ghost-cursor-controller.js +98 -0
  239. package/dist/ghost-cursor-controller.js.map +1 -0
  240. package/dist/ghost-cursor.d.ts +27 -0
  241. package/dist/ghost-cursor.d.ts.map +1 -0
  242. package/dist/ghost-cursor.js +79 -0
  243. package/dist/ghost-cursor.js.map +1 -0
  244. package/dist/htmlrewrite.d.ts +8 -0
  245. package/dist/htmlrewrite.d.ts.map +1 -0
  246. package/dist/htmlrewrite.js +339 -0
  247. package/dist/htmlrewrite.js.map +1 -0
  248. package/dist/htmlrewrite.test.d.ts +2 -0
  249. package/dist/htmlrewrite.test.d.ts.map +1 -0
  250. package/dist/htmlrewrite.test.js +7975 -0
  251. package/dist/htmlrewrite.test.js.map +1 -0
  252. package/dist/index.d.ts +20 -0
  253. package/dist/index.d.ts.map +1 -0
  254. package/dist/index.js +11 -0
  255. package/dist/index.js.map +1 -0
  256. package/dist/kill-port.d.ts +29 -0
  257. package/dist/kill-port.d.ts.map +1 -0
  258. package/dist/kill-port.js +190 -0
  259. package/dist/kill-port.js.map +1 -0
  260. package/dist/kitty-graphics.d.ts +22 -0
  261. package/dist/kitty-graphics.d.ts.map +1 -0
  262. package/dist/kitty-graphics.js +71 -0
  263. package/dist/kitty-graphics.js.map +1 -0
  264. package/dist/kitty-graphics.test.d.ts +2 -0
  265. package/dist/kitty-graphics.test.d.ts.map +1 -0
  266. package/dist/kitty-graphics.test.js +125 -0
  267. package/dist/kitty-graphics.test.js.map +1 -0
  268. package/dist/locator-selector.test.d.ts +2 -0
  269. package/dist/locator-selector.test.d.ts.map +1 -0
  270. package/dist/locator-selector.test.js +98 -0
  271. package/dist/locator-selector.test.js.map +1 -0
  272. package/dist/mcp-client.d.ts +20 -0
  273. package/dist/mcp-client.d.ts.map +1 -0
  274. package/dist/mcp-client.js +56 -0
  275. package/dist/mcp-client.js.map +1 -0
  276. package/dist/mcp.d.ts +6 -0
  277. package/dist/mcp.d.ts.map +1 -0
  278. package/dist/mcp.js +511 -0
  279. package/dist/mcp.js.map +1 -0
  280. package/dist/on-mouse-action.test.d.ts +2 -0
  281. package/dist/on-mouse-action.test.d.ts.map +1 -0
  282. package/dist/on-mouse-action.test.js +180 -0
  283. package/dist/on-mouse-action.test.js.map +1 -0
  284. package/dist/options-page.test.d.ts +2 -0
  285. package/dist/options-page.test.d.ts.map +1 -0
  286. package/dist/options-page.test.js +773 -0
  287. package/dist/options-page.test.js.map +1 -0
  288. package/dist/package-paths.d.ts +4 -0
  289. package/dist/package-paths.d.ts.map +1 -0
  290. package/dist/package-paths.js +30 -0
  291. package/dist/package-paths.js.map +1 -0
  292. package/dist/page-markdown.d.ts +40 -0
  293. package/dist/page-markdown.d.ts.map +1 -0
  294. package/dist/page-markdown.js +181 -0
  295. package/dist/page-markdown.js.map +1 -0
  296. package/dist/performance-examples.d.ts +5 -0
  297. package/dist/performance-examples.d.ts.map +1 -0
  298. package/dist/performance-examples.js +112 -0
  299. package/dist/performance-examples.js.map +1 -0
  300. package/dist/performance-profiling.md +417 -0
  301. package/dist/playwright-import.d.ts +19 -0
  302. package/dist/playwright-import.d.ts.map +1 -0
  303. package/dist/playwright-import.js +40 -0
  304. package/dist/playwright-import.js.map +1 -0
  305. package/dist/popup-relocation.test.d.ts +7 -0
  306. package/dist/popup-relocation.test.d.ts.map +1 -0
  307. package/dist/popup-relocation.test.js +139 -0
  308. package/dist/popup-relocation.test.js.map +1 -0
  309. package/dist/product-paths.d.ts +9 -0
  310. package/dist/product-paths.d.ts.map +1 -0
  311. package/dist/product-paths.js +24 -0
  312. package/dist/product-paths.js.map +1 -0
  313. package/dist/product-paths.test.d.ts +2 -0
  314. package/dist/product-paths.test.d.ts.map +1 -0
  315. package/dist/product-paths.test.js +39 -0
  316. package/dist/product-paths.test.js.map +1 -0
  317. package/dist/prompt.md +1004 -0
  318. package/dist/protocol.d.ts +248 -0
  319. package/dist/protocol.d.ts.map +1 -0
  320. package/dist/protocol.js +59 -0
  321. package/dist/protocol.js.map +1 -0
  322. package/dist/protocol.test.d.ts +2 -0
  323. package/dist/protocol.test.d.ts.map +1 -0
  324. package/dist/protocol.test.js +31 -0
  325. package/dist/protocol.test.js.map +1 -0
  326. package/dist/react-source.d.ts +57 -0
  327. package/dist/react-source.d.ts.map +1 -0
  328. package/dist/react-source.js +254 -0
  329. package/dist/react-source.js.map +1 -0
  330. package/dist/readability.js +1674 -0
  331. package/dist/relay-client.d.ts +104 -0
  332. package/dist/relay-client.d.ts.map +1 -0
  333. package/dist/relay-client.js +426 -0
  334. package/dist/relay-client.js.map +1 -0
  335. package/dist/relay-client.test.d.ts +2 -0
  336. package/dist/relay-client.test.d.ts.map +1 -0
  337. package/dist/relay-client.test.js +305 -0
  338. package/dist/relay-client.test.js.map +1 -0
  339. package/dist/relay-core.test.d.ts +2 -0
  340. package/dist/relay-core.test.d.ts.map +1 -0
  341. package/dist/relay-core.test.js +1427 -0
  342. package/dist/relay-core.test.js.map +1 -0
  343. package/dist/relay-navigation.test.d.ts +2 -0
  344. package/dist/relay-navigation.test.d.ts.map +1 -0
  345. package/dist/relay-navigation.test.js +661 -0
  346. package/dist/relay-navigation.test.js.map +1 -0
  347. package/dist/relay-session.test.d.ts +2 -0
  348. package/dist/relay-session.test.d.ts.map +1 -0
  349. package/dist/relay-session.test.js +1121 -0
  350. package/dist/relay-session.test.js.map +1 -0
  351. package/dist/relay-state.d.ts +178 -0
  352. package/dist/relay-state.d.ts.map +1 -0
  353. package/dist/relay-state.js +346 -0
  354. package/dist/relay-state.js.map +1 -0
  355. package/dist/relay-state.test.d.ts +2 -0
  356. package/dist/relay-state.test.d.ts.map +1 -0
  357. package/dist/relay-state.test.js +594 -0
  358. package/dist/relay-state.test.js.map +1 -0
  359. package/dist/replay-ai-index.d.ts +99 -0
  360. package/dist/replay-ai-index.d.ts.map +1 -0
  361. package/dist/replay-ai-index.js +677 -0
  362. package/dist/replay-ai-index.js.map +1 -0
  363. package/dist/replay-ai-index.test.d.ts +2 -0
  364. package/dist/replay-ai-index.test.d.ts.map +1 -0
  365. package/dist/replay-ai-index.test.js +255 -0
  366. package/dist/replay-ai-index.test.js.map +1 -0
  367. package/dist/replay-cli.test.d.ts +2 -0
  368. package/dist/replay-cli.test.d.ts.map +1 -0
  369. package/dist/replay-cli.test.js +275 -0
  370. package/dist/replay-cli.test.js.map +1 -0
  371. package/dist/replay-eval.d.ts +44 -0
  372. package/dist/replay-eval.d.ts.map +1 -0
  373. package/dist/replay-eval.js +902 -0
  374. package/dist/replay-eval.js.map +1 -0
  375. package/dist/replay-handoff.d.ts +29 -0
  376. package/dist/replay-handoff.d.ts.map +1 -0
  377. package/dist/replay-handoff.js +83 -0
  378. package/dist/replay-handoff.js.map +1 -0
  379. package/dist/replay-handoff.test.d.ts +2 -0
  380. package/dist/replay-handoff.test.d.ts.map +1 -0
  381. package/dist/replay-handoff.test.js +123 -0
  382. package/dist/replay-handoff.test.js.map +1 -0
  383. package/dist/replay-workflow-compiler.d.ts +44 -0
  384. package/dist/replay-workflow-compiler.d.ts.map +1 -0
  385. package/dist/replay-workflow-compiler.js +601 -0
  386. package/dist/replay-workflow-compiler.js.map +1 -0
  387. package/dist/replay-workflow-compiler.test.d.ts +2 -0
  388. package/dist/replay-workflow-compiler.test.d.ts.map +1 -0
  389. package/dist/replay-workflow-compiler.test.js +223 -0
  390. package/dist/replay-workflow-compiler.test.js.map +1 -0
  391. package/dist/rrweb-recording-relay.d.ts +56 -0
  392. package/dist/rrweb-recording-relay.d.ts.map +1 -0
  393. package/dist/rrweb-recording-relay.js +299 -0
  394. package/dist/rrweb-recording-relay.js.map +1 -0
  395. package/dist/rrweb-recording-relay.test.d.ts +2 -0
  396. package/dist/rrweb-recording-relay.test.d.ts.map +1 -0
  397. package/dist/rrweb-recording-relay.test.js +85 -0
  398. package/dist/rrweb-recording-relay.test.js.map +1 -0
  399. package/dist/rrweb-recording.d.ts +104 -0
  400. package/dist/rrweb-recording.d.ts.map +1 -0
  401. package/dist/rrweb-recording.js +180 -0
  402. package/dist/rrweb-recording.js.map +1 -0
  403. package/dist/scoped-fs.d.ts +95 -0
  404. package/dist/scoped-fs.d.ts.map +1 -0
  405. package/dist/scoped-fs.js +358 -0
  406. package/dist/scoped-fs.js.map +1 -0
  407. package/dist/scoped-fs.test.d.ts +5 -0
  408. package/dist/scoped-fs.test.d.ts.map +1 -0
  409. package/dist/scoped-fs.test.js +73 -0
  410. package/dist/scoped-fs.test.js.map +1 -0
  411. package/dist/selector-generator.js +7378 -0
  412. package/dist/skill-stub.test.d.ts +2 -0
  413. package/dist/skill-stub.test.d.ts.map +1 -0
  414. package/dist/skill-stub.test.js +22 -0
  415. package/dist/skill-stub.test.js.map +1 -0
  416. package/dist/snapshot-tools.test.d.ts +2 -0
  417. package/dist/snapshot-tools.test.d.ts.map +1 -0
  418. package/dist/snapshot-tools.test.js +856 -0
  419. package/dist/snapshot-tools.test.js.map +1 -0
  420. package/dist/start-relay-server.d.ts +6 -0
  421. package/dist/start-relay-server.d.ts.map +1 -0
  422. package/dist/start-relay-server.js +57 -0
  423. package/dist/start-relay-server.js.map +1 -0
  424. package/dist/styles-api.md +124 -0
  425. package/dist/styles-examples.d.ts +8 -0
  426. package/dist/styles-examples.d.ts.map +1 -0
  427. package/dist/styles-examples.js +64 -0
  428. package/dist/styles-examples.js.map +1 -0
  429. package/dist/styles.d.ts +27 -0
  430. package/dist/styles.d.ts.map +1 -0
  431. package/dist/styles.js +231 -0
  432. package/dist/styles.js.map +1 -0
  433. package/dist/tabwright-agent-skill.d.ts +30 -0
  434. package/dist/tabwright-agent-skill.d.ts.map +1 -0
  435. package/dist/tabwright-agent-skill.js +74 -0
  436. package/dist/tabwright-agent-skill.js.map +1 -0
  437. package/dist/tabwright-agent-skill.test.d.ts +2 -0
  438. package/dist/tabwright-agent-skill.test.d.ts.map +1 -0
  439. package/dist/tabwright-agent-skill.test.js +51 -0
  440. package/dist/tabwright-agent-skill.test.js.map +1 -0
  441. package/dist/test-declarations.d.ts +13 -0
  442. package/dist/test-declarations.d.ts.map +1 -0
  443. package/dist/test-declarations.js +2 -0
  444. package/dist/test-declarations.js.map +1 -0
  445. package/dist/test-utils.d.ts +69 -0
  446. package/dist/test-utils.d.ts.map +1 -0
  447. package/dist/test-utils.js +448 -0
  448. package/dist/test-utils.js.map +1 -0
  449. package/dist/test-utils.test.d.ts +2 -0
  450. package/dist/test-utils.test.d.ts.map +1 -0
  451. package/dist/test-utils.test.js +55 -0
  452. package/dist/test-utils.test.js.map +1 -0
  453. package/dist/utils.d.ts +26 -0
  454. package/dist/utils.d.ts.map +1 -0
  455. package/dist/utils.js +60 -0
  456. package/dist/utils.js.map +1 -0
  457. package/dist/wait-for-page-load.d.ts +16 -0
  458. package/dist/wait-for-page-load.d.ts.map +1 -0
  459. package/dist/wait-for-page-load.js +146 -0
  460. package/dist/wait-for-page-load.js.map +1 -0
  461. package/dist/workflow-capability.d.ts +72 -0
  462. package/dist/workflow-capability.d.ts.map +1 -0
  463. package/dist/workflow-capability.js +316 -0
  464. package/dist/workflow-capability.js.map +1 -0
  465. package/dist/workflow-script-flow.test.d.ts +2 -0
  466. package/dist/workflow-script-flow.test.d.ts.map +1 -0
  467. package/dist/workflow-script-flow.test.js +285 -0
  468. package/dist/workflow-script-flow.test.js.map +1 -0
  469. package/package.json +80 -0
  470. package/src/__snapshots__/x.com.processed.html +1003 -0
  471. package/src/__snapshots__/x.com.processed.withStyles.html +2720 -0
  472. package/src/a11y-client.ts +241 -0
  473. package/src/agent-skills/conan-config/SKILL.md +141 -0
  474. package/src/agent-skills/conan-config/agents/openai.yaml +4 -0
  475. package/src/aria-snapshot.test.ts +311 -0
  476. package/src/aria-snapshot.ts +1681 -0
  477. package/src/aria-snapshot.unit.test.ts +615 -0
  478. package/src/aria-snapshots/github-interactive.txt +193 -0
  479. package/src/aria-snapshots/github-raw.txt +309 -0
  480. package/src/aria-snapshots/hackernews-interactive.txt +477 -0
  481. package/src/aria-snapshots/hackernews-raw.txt +428 -0
  482. package/src/aria-snapshots/prosemirror-interactive.txt +66 -0
  483. package/src/aria-snapshots/prosemirror-raw.txt +145 -0
  484. package/src/assets/aria-labels-hacker-news.png +0 -0
  485. package/src/assets/aria-labels-old-reddit.png +0 -0
  486. package/src/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.ts +5 -0
  487. package/src/assets/cursors/screen-studio/pointer-macos-tahoe.svg +18 -0
  488. package/src/assets/x.com.html +32946 -0
  489. package/src/browser-config.ts +179 -0
  490. package/src/browser-install.ts +284 -0
  491. package/src/browser-launch.ts +75 -0
  492. package/src/builtin-capabilities.ts +2765 -0
  493. package/src/capability-agent-skill.ts +305 -0
  494. package/src/capability-auth-state.ts +197 -0
  495. package/src/capability-auth.ts +249 -0
  496. package/src/capability-cli-confirmation.test.ts +90 -0
  497. package/src/capability-options.test.ts +89 -0
  498. package/src/capability-options.ts +57 -0
  499. package/src/capability-package.test.ts +204 -0
  500. package/src/capability-package.ts +555 -0
  501. package/src/capability-registry.test.ts +1905 -0
  502. package/src/capability-registry.ts +1234 -0
  503. package/src/capability-runner.ts +801 -0
  504. package/src/capability-search-relevance.test.ts +73 -0
  505. package/src/capability-studio.test.ts +45 -0
  506. package/src/capability-studio.ts +641 -0
  507. package/src/cdp-log.test.ts +131 -0
  508. package/src/cdp-log.ts +112 -0
  509. package/src/cdp-relay.ts +2944 -0
  510. package/src/cdp-session.ts +77 -0
  511. package/src/cdp-types.ts +158 -0
  512. package/src/channel-owner-inspect.test.ts +94 -0
  513. package/src/chrome-discovery.test.ts +50 -0
  514. package/src/chrome-discovery.ts +220 -0
  515. package/src/clean-html.ts +141 -0
  516. package/src/cli-help.test.ts +123 -0
  517. package/src/cli.ts +3181 -0
  518. package/src/cloud-client.ts +179 -0
  519. package/src/create-logger.ts +38 -0
  520. package/src/debugger-examples-types.ts +16 -0
  521. package/src/debugger-examples.ts +66 -0
  522. package/src/debugger.ts +708 -0
  523. package/src/diff-utils.test.ts +152 -0
  524. package/src/diff-utils.ts +70 -0
  525. package/src/doctor.test.ts +244 -0
  526. package/src/doctor.ts +321 -0
  527. package/src/editor-examples.ts +158 -0
  528. package/src/editor.ts +426 -0
  529. package/src/env-compat.ts +28 -0
  530. package/src/executor.ts +1824 -0
  531. package/src/executor.unit.test.ts +168 -0
  532. package/src/extension-connection.test.ts +855 -0
  533. package/src/extension-icon-warning.test.ts +45 -0
  534. package/src/ghost-browser.ts +149 -0
  535. package/src/ghost-cursor-client.ts +494 -0
  536. package/src/ghost-cursor-controller.ts +129 -0
  537. package/src/ghost-cursor.ts +123 -0
  538. package/src/htmlrewrite.test.ts +8008 -0
  539. package/src/htmlrewrite.ts +390 -0
  540. package/src/index.ts +53 -0
  541. package/src/kill-port.ts +219 -0
  542. package/src/kitty-graphics.test.ts +139 -0
  543. package/src/kitty-graphics.ts +79 -0
  544. package/src/locator-selector.test.ts +119 -0
  545. package/src/mcp-client.ts +78 -0
  546. package/src/mcp.ts +629 -0
  547. package/src/on-mouse-action.test.ts +226 -0
  548. package/src/options-page.test.ts +839 -0
  549. package/src/package-paths.ts +38 -0
  550. package/src/page-markdown.ts +240 -0
  551. package/src/performance-examples.ts +186 -0
  552. package/src/playwright-import.ts +59 -0
  553. package/src/popup-relocation.test.ts +163 -0
  554. package/src/product-paths.test.ts +47 -0
  555. package/src/product-paths.ts +28 -0
  556. package/src/protocol.test.ts +52 -0
  557. package/src/protocol.ts +351 -0
  558. package/src/react-source.ts +379 -0
  559. package/src/relay-client.test.ts +375 -0
  560. package/src/relay-client.ts +572 -0
  561. package/src/relay-core.test.ts +1603 -0
  562. package/src/relay-navigation.test.ts +790 -0
  563. package/src/relay-session.test.ts +1375 -0
  564. package/src/relay-state.test.ts +729 -0
  565. package/src/relay-state.ts +561 -0
  566. package/src/replay-ai-index.test.ts +278 -0
  567. package/src/replay-ai-index.ts +872 -0
  568. package/src/replay-cli.test.ts +325 -0
  569. package/src/replay-eval.ts +1039 -0
  570. package/src/replay-handoff.test.ts +163 -0
  571. package/src/replay-handoff.ts +109 -0
  572. package/src/replay-workflow-compiler.test.ts +250 -0
  573. package/src/replay-workflow-compiler.ts +700 -0
  574. package/src/resource.md +409 -0
  575. package/src/rrweb-recording-relay.test.ts +99 -0
  576. package/src/rrweb-recording-relay.ts +400 -0
  577. package/src/rrweb-recording.ts +322 -0
  578. package/src/scoped-fs.test.ts +80 -0
  579. package/src/scoped-fs.ts +420 -0
  580. package/src/skill-stub.test.ts +24 -0
  581. package/src/skill.md +1413 -0
  582. package/src/snapshot-tools.test.ts +1017 -0
  583. package/src/snapshots/hacker-news-accessibility-full.md +81 -0
  584. package/src/snapshots/hacker-news-accessibility-interactive.md +43 -0
  585. package/src/snapshots/page-markdown-output.txt +16 -0
  586. package/src/snapshots/shadcn-ui-accessibility-full.md +201 -0
  587. package/src/snapshots/shadcn-ui-accessibility-interactive.md +109 -0
  588. package/src/start-relay-server.ts +69 -0
  589. package/src/styles-examples.ts +84 -0
  590. package/src/styles.ts +343 -0
  591. package/src/tabwright-agent-skill.test.ts +61 -0
  592. package/src/tabwright-agent-skill.ts +105 -0
  593. package/src/test-declarations.ts +13 -0
  594. package/src/test-utils.test.ts +70 -0
  595. package/src/test-utils.ts +566 -0
  596. package/src/utils.ts +78 -0
  597. package/src/wait-for-page-load.ts +198 -0
  598. package/src/workflow-capability.ts +417 -0
  599. package/src/workflow-script-flow.test.ts +388 -0
@@ -0,0 +1,801 @@
1
+ import crypto from 'node:crypto'
2
+ import fs from 'node:fs'
3
+ import path from 'node:path'
4
+ import util from 'node:util'
5
+ import vm from 'node:vm'
6
+ import {
7
+ appendCapabilityRun,
8
+ capabilityMatchesUrl,
9
+ getCapabilityContractFingerprint,
10
+ getCapabilityContractHealth,
11
+ readCapabilitySecrets,
12
+ requireCapability,
13
+ resolveCapabilityOperation,
14
+ updateCapabilityManifest,
15
+ validateJsonAgainstSchema,
16
+ type CapabilityContractCheckStatus,
17
+ type CapabilityRecord,
18
+ type CapabilityRunContract,
19
+ type CapabilityRunRecord,
20
+ type ResolvedCapabilityOperation,
21
+ } from './capability-registry.js'
22
+ import type { ExecuteResult } from './executor.js'
23
+
24
+ export interface CapabilityExecutor {
25
+ execute(code: string, timeout?: number, options?: { includeStructuredResult?: boolean }): Promise<ExecuteResult>
26
+ }
27
+
28
+ export interface PreparedCapabilityRun {
29
+ capability: CapabilityRecord
30
+ operation: ResolvedCapabilityOperation
31
+ code: string
32
+ input: unknown
33
+ inputHash: string
34
+ }
35
+
36
+ export interface CapabilityRunResult {
37
+ capability: CapabilityRecord
38
+ executeResult: ExecuteResult
39
+ output: unknown
40
+ runRecord: CapabilityRunRecord
41
+ }
42
+
43
+ export interface NodeCapabilityRunResult {
44
+ capability: CapabilityRecord
45
+ output: unknown
46
+ text: string
47
+ isError: boolean
48
+ runRecord: CapabilityRunRecord
49
+ }
50
+
51
+ export interface CapabilityExecutionObservation {
52
+ status: 'success' | 'error'
53
+ output: unknown
54
+ error?: string
55
+ observedNetworkUrls?: string[]
56
+ url?: string
57
+ }
58
+
59
+ export interface FinalizedCapabilityRun {
60
+ capability: CapabilityRecord
61
+ output: unknown
62
+ runRecord: CapabilityRunRecord
63
+ contractError?: Error
64
+ }
65
+
66
+ interface CapabilityExecutionEnvelope {
67
+ __tabwrightCapabilityEnvelope: 1
68
+ output: unknown
69
+ observedNetworkUrls: string[]
70
+ url?: string
71
+ error?: string
72
+ }
73
+
74
+ interface NodeCapabilityExecution {
75
+ output: unknown
76
+ observedNetworkUrls: string[]
77
+ }
78
+
79
+ class ObservedCapabilityExecutionError extends Error {
80
+ observedNetworkUrls: string[]
81
+
82
+ constructor(options: { cause: unknown; observedNetworkUrls: string[] }) {
83
+ const message = options.cause instanceof Error ? options.cause.message : String(options.cause)
84
+ super(message, { cause: options.cause })
85
+ this.name = 'ObservedCapabilityExecutionError'
86
+ this.observedNetworkUrls = options.observedNetworkUrls
87
+ }
88
+ }
89
+
90
+ interface CapabilityArtifacts {
91
+ root: string
92
+ path(options: { filename: string }): string
93
+ writeJson(options: { filename: string; value: unknown }): string
94
+ writeText(options: { filename: string; text: string }): string
95
+ }
96
+
97
+ export function prepareCapabilityRun(options: {
98
+ id: string
99
+ input: unknown
100
+ cwd?: string
101
+ force?: boolean
102
+ confirmation?: string
103
+ }): PreparedCapabilityRun {
104
+ const capability = requireCapability({ id: options.id, cwd: options.cwd })
105
+ const operation = validateCapabilityRunnable({
106
+ capability,
107
+ input: options.input,
108
+ force: options.force,
109
+ confirmation: options.confirmation,
110
+ })
111
+
112
+ const script = fs.readFileSync(capability.scriptPath, 'utf-8')
113
+ return {
114
+ capability,
115
+ operation,
116
+ code: buildCapabilityCode({ capability, operation, script, input: options.input, force: options.force }),
117
+ input: options.input,
118
+ inputHash: hashInput(options.input),
119
+ }
120
+ }
121
+
122
+ export async function runNodeCapability(options: {
123
+ id: string
124
+ input: unknown
125
+ timeout?: number
126
+ cwd?: string
127
+ force?: boolean
128
+ confirmation?: string
129
+ }): Promise<NodeCapabilityRunResult> {
130
+ const capability = requireCapability({ id: options.id, cwd: options.cwd })
131
+ if (capability.manifest.runtime !== 'node') {
132
+ throw new Error(`Capability ${options.id} is runtime "${capability.manifest.runtime}", not "node"`)
133
+ }
134
+ const operation = validateCapabilityRunnable({
135
+ capability,
136
+ input: options.input,
137
+ force: options.force,
138
+ confirmation: options.confirmation,
139
+ })
140
+
141
+ const start = Date.now()
142
+ const inputHash = hashInput(options.input)
143
+ const execution = await executeNodeCapabilityScript({
144
+ capability,
145
+ operation,
146
+ input: options.input,
147
+ timeout: options.timeout || 10000,
148
+ }).catch((error: unknown) => {
149
+ const finalized = finalizeCapabilityRun({
150
+ capability,
151
+ operation,
152
+ cwd: options.cwd,
153
+ inputHash,
154
+ startedAt: start,
155
+ execution: {
156
+ status: 'error',
157
+ output: undefined,
158
+ error: error instanceof Error ? error.message : String(error),
159
+ observedNetworkUrls: error instanceof ObservedCapabilityExecutionError ? error.observedNetworkUrls : [],
160
+ },
161
+ })
162
+ throw finalized.contractError || error
163
+ })
164
+ const finalized = finalizeCapabilityRun({
165
+ capability,
166
+ operation,
167
+ cwd: options.cwd,
168
+ inputHash,
169
+ startedAt: start,
170
+ execution: {
171
+ status: 'success',
172
+ output: execution.output,
173
+ observedNetworkUrls: execution.observedNetworkUrls,
174
+ },
175
+ })
176
+ if (finalized.contractError) {
177
+ throw finalized.contractError
178
+ }
179
+
180
+ return {
181
+ capability: finalized.capability,
182
+ output: finalized.output,
183
+ text: formatNodeOutput(finalized.output),
184
+ isError: false,
185
+ runRecord: finalized.runRecord,
186
+ }
187
+ }
188
+
189
+ export async function runCapabilityWithExecutor(options: {
190
+ executor: CapabilityExecutor
191
+ id: string
192
+ input: unknown
193
+ timeout?: number
194
+ cwd?: string
195
+ force?: boolean
196
+ confirmation?: string
197
+ }): Promise<CapabilityRunResult> {
198
+ const prepared = prepareCapabilityRun(options)
199
+ const start = Date.now()
200
+ const executeResult = await options.executor
201
+ .execute(prepared.code, options.timeout || 10000, {
202
+ includeStructuredResult: true,
203
+ })
204
+ .catch((error: unknown) => {
205
+ finalizeCapabilityRun({
206
+ capability: prepared.capability,
207
+ operation: prepared.operation,
208
+ cwd: options.cwd,
209
+ inputHash: prepared.inputHash,
210
+ startedAt: start,
211
+ execution: {
212
+ status: 'error',
213
+ output: undefined,
214
+ error: error instanceof Error ? error.message : String(error),
215
+ },
216
+ })
217
+ throw error
218
+ })
219
+ const observation = readCapabilityExecutionObservation(executeResult.structuredResult)
220
+ const isExecutionError = executeResult.isError || Boolean(observation.error)
221
+ const normalizedExecuteResult: ExecuteResult = {
222
+ ...executeResult,
223
+ text: normalizeCapabilityExecutionText({
224
+ text: executeResult.text,
225
+ output: observation.output,
226
+ error: observation.error,
227
+ }),
228
+ isError: isExecutionError,
229
+ structuredResult: observation.output,
230
+ }
231
+ const finalized = finalizeCapabilityRun({
232
+ capability: prepared.capability,
233
+ operation: prepared.operation,
234
+ cwd: options.cwd,
235
+ inputHash: prepared.inputHash,
236
+ startedAt: start,
237
+ execution: {
238
+ status: isExecutionError ? 'error' : 'success',
239
+ output: observation.output,
240
+ error: isExecutionError ? observation.error || normalizedExecuteResult.text : undefined,
241
+ observedNetworkUrls: observation.observedNetworkUrls,
242
+ url: observation.url,
243
+ },
244
+ })
245
+ if (finalized.contractError) {
246
+ throw finalized.contractError
247
+ }
248
+
249
+ return {
250
+ capability: finalized.capability,
251
+ executeResult: normalizedExecuteResult,
252
+ output: finalized.output,
253
+ runRecord: finalized.runRecord,
254
+ }
255
+ }
256
+
257
+ export function finalizeCapabilityRun(options: {
258
+ capability: CapabilityRecord
259
+ operation: ResolvedCapabilityOperation
260
+ cwd?: string
261
+ inputHash: string
262
+ startedAt: number
263
+ execution: CapabilityExecutionObservation
264
+ }): FinalizedCapabilityRun {
265
+ const fingerprint = getCapabilityContractFingerprint(options.capability)
266
+ const outputValidation =
267
+ options.execution.status === 'success'
268
+ ? validateJsonAgainstSchema({
269
+ schema: options.operation.outputSchema,
270
+ value: options.execution.output,
271
+ label: 'output',
272
+ })
273
+ : { valid: false, errors: [] }
274
+ const network = validateObservedNetworkUrls({
275
+ capability: options.capability,
276
+ operation: options.operation,
277
+ executionStatus: options.execution.status,
278
+ observedNetworkUrls: options.execution.observedNetworkUrls || [],
279
+ })
280
+ const failures: CapabilityRunContract['failures'] = [
281
+ ...(options.execution.status === 'success' && !outputValidation.valid
282
+ ? outputValidation.errors.map((message) => {
283
+ return { kind: 'output-schema' as const, message }
284
+ })
285
+ : []),
286
+ ...network.undeclaredHosts.map((host) => {
287
+ return {
288
+ kind: 'undeclared-host' as const,
289
+ message: `Network host is not declared by capability permissions: ${host}`,
290
+ }
291
+ }),
292
+ ]
293
+ const contractStatus: CapabilityRunContract['status'] = (() => {
294
+ if (failures.length > 0) {
295
+ return 'failed'
296
+ }
297
+ if (options.execution.status === 'error') {
298
+ return 'unknown'
299
+ }
300
+ return 'passed'
301
+ })()
302
+ const trustBefore = options.capability.manifest.status
303
+ const nextCapability = (() => {
304
+ if (contractStatus !== 'failed' || trustBefore !== 'trusted') {
305
+ return options.capability
306
+ }
307
+ return updateCapabilityManifest({
308
+ id: options.capability.manifest.id,
309
+ cwd: options.cwd,
310
+ patch: { status: 'draft' },
311
+ })
312
+ })()
313
+ const contract: CapabilityRunContract = {
314
+ schemaVersion: 1,
315
+ fingerprint,
316
+ status: contractStatus,
317
+ failures,
318
+ output: {
319
+ status: options.execution.status === 'error' ? 'unknown' : outputValidation.valid ? 'passed' : 'failed',
320
+ errors: outputValidation.errors,
321
+ },
322
+ network: {
323
+ status: network.status,
324
+ observedHosts: network.observedHosts,
325
+ undeclaredHosts: network.undeclaredHosts,
326
+ },
327
+ trust: {
328
+ before: trustBefore,
329
+ after: nextCapability.manifest.status,
330
+ downgraded: trustBefore === 'trusted' && nextCapability.manifest.status === 'draft',
331
+ },
332
+ }
333
+ const contractError = (() => {
334
+ if (contractStatus !== 'failed') {
335
+ return undefined
336
+ }
337
+ return new Error(
338
+ [
339
+ 'Capability execution completed but contract conformance failed.',
340
+ ...failures.map((failure) => {
341
+ return failure.message
342
+ }),
343
+ trustBefore === 'trusted'
344
+ ? 'The capability was moved to draft. Do not automatically retry a write operation.'
345
+ : 'The capability remains draft. Do not automatically retry a write operation.',
346
+ ].join('\n'),
347
+ )
348
+ })()
349
+ const runRecord = buildCapabilityRunRecord({
350
+ capability: options.capability,
351
+ operation: options.operation,
352
+ status: options.execution.status === 'error' || contractError ? 'error' : 'success',
353
+ durationMs: Date.now() - options.startedAt,
354
+ inputHash: options.inputHash,
355
+ error: options.execution.error || contractError?.message,
356
+ url: options.execution.url,
357
+ contract,
358
+ })
359
+ appendCapabilityRun({ capability: options.capability, record: runRecord })
360
+ return {
361
+ capability: nextCapability,
362
+ output: options.execution.output,
363
+ runRecord,
364
+ contractError,
365
+ }
366
+ }
367
+
368
+ export function readCapabilityExecutionObservation(value: unknown): {
369
+ output: unknown
370
+ observedNetworkUrls: string[]
371
+ url?: string
372
+ error?: string
373
+ } {
374
+ if (!isCapabilityExecutionEnvelope(value)) {
375
+ return { output: value, observedNetworkUrls: [] }
376
+ }
377
+ return {
378
+ output: value.output,
379
+ observedNetworkUrls: value.observedNetworkUrls,
380
+ url: value.url,
381
+ error: value.error,
382
+ }
383
+ }
384
+
385
+ export function normalizeCapabilityExecutionText(options: { text: string; output: unknown; error?: string }): string {
386
+ const markerIndex = options.text.lastIndexOf('[return value]')
387
+ if (markerIndex === -1) {
388
+ return options.error || options.text
389
+ }
390
+ const prefix = options.text.slice(0, markerIndex).trimEnd()
391
+ const resultText: string = (() => {
392
+ if (options.error) {
393
+ return options.error
394
+ }
395
+ if (options.output === undefined) {
396
+ return ''
397
+ }
398
+ const formatted =
399
+ typeof options.output === 'string'
400
+ ? options.output
401
+ : util.inspect(options.output, {
402
+ depth: 4,
403
+ colors: false,
404
+ maxArrayLength: 100,
405
+ maxStringLength: 1000,
406
+ breakLength: 80,
407
+ })
408
+ return formatted.trim() ? `[return value] ${formatted}` : ''
409
+ })()
410
+ return (
411
+ [prefix, resultText]
412
+ .filter((value) => {
413
+ return value.length > 0
414
+ })
415
+ .join('\n')
416
+ .trim() || 'Code executed successfully (no output)'
417
+ )
418
+ }
419
+
420
+ function isCapabilityExecutionEnvelope(value: unknown): value is CapabilityExecutionEnvelope {
421
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
422
+ return false
423
+ }
424
+ const candidate = value as Partial<CapabilityExecutionEnvelope>
425
+ return (
426
+ candidate.__tabwrightCapabilityEnvelope === 1 &&
427
+ Array.isArray(candidate.observedNetworkUrls) &&
428
+ candidate.observedNetworkUrls.every((url) => {
429
+ return typeof url === 'string'
430
+ }) &&
431
+ (candidate.url === undefined || typeof candidate.url === 'string') &&
432
+ (candidate.error === undefined || typeof candidate.error === 'string')
433
+ )
434
+ }
435
+
436
+ function validateObservedNetworkUrls(options: {
437
+ capability: CapabilityRecord
438
+ operation: ResolvedCapabilityOperation
439
+ executionStatus: 'success' | 'error'
440
+ observedNetworkUrls: string[]
441
+ }): {
442
+ status: CapabilityContractCheckStatus
443
+ observedHosts: string[]
444
+ undeclaredHosts: string[]
445
+ } {
446
+ const observations = options.observedNetworkUrls.flatMap((rawUrl) => {
447
+ try {
448
+ const url = new URL(rawUrl)
449
+ return [{ url: url.toString(), host: url.origin }]
450
+ } catch {
451
+ return []
452
+ }
453
+ })
454
+ const observedHosts = [...new Set(observations.map((observation) => observation.host))].sort()
455
+ if (observations.length === 0) {
456
+ return {
457
+ status: options.executionStatus === 'error' ? 'unknown' : 'not-applicable',
458
+ observedHosts,
459
+ undeclaredHosts: [],
460
+ }
461
+ }
462
+
463
+ const networkPermissions = (options.operation.permissions || options.capability.manifest.permissions).filter(
464
+ (permission) => {
465
+ return permission === 'network' || permission.startsWith('network:')
466
+ },
467
+ )
468
+ if (networkPermissions.includes('network')) {
469
+ return {
470
+ status: options.executionStatus === 'error' ? 'unknown' : 'passed',
471
+ observedHosts,
472
+ undeclaredHosts: [],
473
+ }
474
+ }
475
+ const scopedPermissions = networkPermissions.flatMap((permission) => {
476
+ return permission.startsWith('network:') ? [permission.slice('network:'.length)] : []
477
+ })
478
+ if (options.capability.manifest.runtime === 'browser' && scopedPermissions.length === 0) {
479
+ return {
480
+ status: options.executionStatus === 'error' ? 'unknown' : 'not-applicable',
481
+ observedHosts,
482
+ undeclaredHosts: [],
483
+ }
484
+ }
485
+
486
+ const undeclaredHosts = [
487
+ ...new Set(
488
+ observations.flatMap((observation) => {
489
+ const declared = scopedPermissions.some((pattern) => {
490
+ return matchesGlob({ value: observation.url, pattern })
491
+ })
492
+ return declared ? [] : [observation.host]
493
+ }),
494
+ ),
495
+ ].sort()
496
+ return {
497
+ status: undeclaredHosts.length > 0 ? 'failed' : options.executionStatus === 'error' ? 'unknown' : 'passed',
498
+ observedHosts,
499
+ undeclaredHosts,
500
+ }
501
+ }
502
+
503
+ function matchesGlob(options: { value: string; pattern: string }): boolean {
504
+ const escaped = options.pattern
505
+ .split('*')
506
+ .map((part) => {
507
+ return part.replace(/[|\\{}()[\]^$+?.]/g, '\\$&')
508
+ })
509
+ .join('.*')
510
+ return new RegExp(`^${escaped}$`).test(options.value)
511
+ }
512
+
513
+ export function buildCapabilityRunRecord(options: {
514
+ capability: CapabilityRecord
515
+ operation: ResolvedCapabilityOperation
516
+ status: 'success' | 'error'
517
+ durationMs: number
518
+ inputHash: string
519
+ error?: string
520
+ url?: string
521
+ contract?: CapabilityRunContract
522
+ }): CapabilityRunRecord {
523
+ return {
524
+ id: options.capability.manifest.id,
525
+ operation: options.operation.id,
526
+ status: options.status,
527
+ durationMs: options.durationMs,
528
+ inputHash: options.inputHash,
529
+ error: options.error,
530
+ url: options.url,
531
+ contract: options.contract,
532
+ createdAt: new Date().toISOString(),
533
+ }
534
+ }
535
+
536
+ export function validateCapabilityUrl(options: { capability: CapabilityRecord; url: string; force?: boolean }): void {
537
+ if (options.force) {
538
+ return
539
+ }
540
+ if (capabilityMatchesUrl({ capability: options.capability.manifest, url: options.url })) {
541
+ return
542
+ }
543
+ throw new Error(`Capability ${options.capability.manifest.id} does not match current page URL: ${options.url}`)
544
+ }
545
+
546
+ function validateCapabilityRunnable(options: {
547
+ capability: CapabilityRecord
548
+ input: unknown
549
+ force?: boolean
550
+ confirmation?: string
551
+ }): ResolvedCapabilityOperation {
552
+ if (options.capability.manifest.status === 'disabled') {
553
+ throw new Error(`Capability is disabled: ${options.capability.manifest.id}`)
554
+ }
555
+ if (getCapabilityContractHealth(options.capability).state === 'drifted' && !options.force) {
556
+ throw new Error(
557
+ `Capability ${options.capability.manifest.id} failed conformance for its current contract. Repair it and run with --force before trusting it again.`,
558
+ )
559
+ }
560
+ if (options.capability.manifest.status !== 'trusted' && !options.force) {
561
+ throw new Error(`Capability is ${options.capability.manifest.status}. Run with --force or trust it first.`)
562
+ }
563
+ const operation = resolveCapabilityOperation({ capability: options.capability, input: options.input })
564
+ const validation = validateJsonAgainstSchema({
565
+ schema: operation.inputSchema,
566
+ value: options.input,
567
+ label: 'input',
568
+ })
569
+ if (!validation.valid) {
570
+ throw new Error(`Invalid capability input:\n${validation.errors.join('\n')}`)
571
+ }
572
+ if (operation.requiresConfirmation && options.confirmation !== operation.confirmationToken) {
573
+ throw new Error(
574
+ `Capability ${options.capability.manifest.id}${operation.id ? ` operation ${operation.id}` : ''} requires explicit user confirmation for its ${operation.sideEffect} side effect. After approval, rerun with --confirm ${operation.confirmationToken}.`,
575
+ )
576
+ }
577
+ return operation
578
+ }
579
+
580
+ async function executeNodeCapabilityScript(options: {
581
+ capability: CapabilityRecord
582
+ operation: ResolvedCapabilityOperation
583
+ input: unknown
584
+ timeout: number
585
+ }): Promise<NodeCapabilityExecution> {
586
+ const script = fs.readFileSync(options.capability.scriptPath, 'utf-8')
587
+ const secrets = readCapabilitySecrets({ capability: options.capability })
588
+ const artifacts = createCapabilityArtifacts({ capability: options.capability })
589
+ const observedNetworkUrls: Set<string> = new Set()
590
+ const observedFetch: typeof fetch = async (input, init) => {
591
+ const requestUrl = input instanceof Request ? input.url : input.toString()
592
+ observedNetworkUrls.add(requestUrl)
593
+ const response = await fetch(input, init)
594
+ if (response.url) {
595
+ observedNetworkUrls.add(response.url)
596
+ }
597
+ return response
598
+ }
599
+ const vmContext = vm.createContext({
600
+ input: options.input,
601
+ capability: {
602
+ id: options.capability.manifest.id,
603
+ title: options.capability.manifest.title,
604
+ description: options.capability.manifest.description,
605
+ operation: options.operation.id,
606
+ permissions: options.operation.permissions || options.capability.manifest.permissions,
607
+ runtime: options.capability.manifest.runtime,
608
+ },
609
+ secrets,
610
+ artifacts,
611
+ console,
612
+ fetch: observedFetch,
613
+ URL,
614
+ URLSearchParams,
615
+ Headers,
616
+ Request,
617
+ Response,
618
+ FormData,
619
+ Buffer,
620
+ TextEncoder,
621
+ TextDecoder,
622
+ AbortController,
623
+ AbortSignal,
624
+ structuredClone,
625
+ setTimeout,
626
+ clearTimeout,
627
+ crypto,
628
+ })
629
+ const wrappedCode = [
630
+ 'const __tabwrightCapabilityOutput = await (async () => {',
631
+ script,
632
+ '\n})();',
633
+ 'return __tabwrightCapabilityOutput === undefined ? undefined : JSON.parse(JSON.stringify(__tabwrightCapabilityOutput));',
634
+ `//# sourceURL=tabwright-node-capability://${options.capability.manifest.id}`,
635
+ '',
636
+ ].join('\n')
637
+
638
+ const timeout = createCapabilityTimeout({ timeout: options.timeout })
639
+ try {
640
+ const output = await Promise.race([
641
+ vm.runInContext(`(async () => { ${wrappedCode} })()`, vmContext, {
642
+ timeout: options.timeout,
643
+ displayErrors: true,
644
+ }),
645
+ timeout.promise,
646
+ ])
647
+ return { output, observedNetworkUrls: [...observedNetworkUrls] }
648
+ } catch (error) {
649
+ throw new ObservedCapabilityExecutionError({
650
+ cause: error,
651
+ observedNetworkUrls: [...observedNetworkUrls],
652
+ })
653
+ } finally {
654
+ timeout.cancel()
655
+ }
656
+ }
657
+
658
+ function createCapabilityTimeout(options: { timeout: number }): {
659
+ promise: Promise<never>
660
+ cancel: () => void
661
+ } {
662
+ const controller = new AbortController()
663
+ const promise = new Promise<never>((_, reject) => {
664
+ const timer = setTimeout(() => {
665
+ reject(new Error(`Capability execution timed out after ${options.timeout}ms`))
666
+ }, options.timeout)
667
+ controller.signal.addEventListener(
668
+ 'abort',
669
+ () => {
670
+ clearTimeout(timer)
671
+ },
672
+ { once: true },
673
+ )
674
+ })
675
+ return {
676
+ promise,
677
+ cancel: () => {
678
+ controller.abort()
679
+ },
680
+ }
681
+ }
682
+
683
+ function createCapabilityArtifacts(options: { capability: CapabilityRecord }): CapabilityArtifacts {
684
+ const root = path.join(options.capability.dir, 'artifacts')
685
+ return {
686
+ root,
687
+ path: (pathOptions) => {
688
+ return resolveArtifactPath({ root, filename: pathOptions.filename })
689
+ },
690
+ writeJson: (writeOptions) => {
691
+ return writeArtifactText({
692
+ root,
693
+ filename: writeOptions.filename,
694
+ text: `${JSON.stringify(writeOptions.value, null, 2)}\n`,
695
+ })
696
+ },
697
+ writeText: (writeOptions) => {
698
+ return writeArtifactText({ root, filename: writeOptions.filename, text: writeOptions.text })
699
+ },
700
+ }
701
+ }
702
+
703
+ function writeArtifactText(options: { root: string; filename: string; text: string }): string {
704
+ const filePath = resolveArtifactPath({ root: options.root, filename: options.filename })
705
+ fs.mkdirSync(path.dirname(filePath), { recursive: true })
706
+ fs.writeFileSync(filePath, options.text)
707
+ return filePath
708
+ }
709
+
710
+ function resolveArtifactPath(options: { root: string; filename: string }): string {
711
+ const root = path.resolve(options.root)
712
+ if (!options.filename.trim()) {
713
+ throw new Error('Artifact filename must not be empty')
714
+ }
715
+ const filePath = path.resolve(root, options.filename)
716
+ if (filePath !== root && !filePath.startsWith(`${root}${path.sep}`)) {
717
+ throw new Error(`Artifact filename must stay inside artifacts directory: ${options.filename}`)
718
+ }
719
+ return filePath
720
+ }
721
+
722
+ function formatNodeOutput(output: unknown): string {
723
+ return `[return value] ${util.inspect(output, {
724
+ depth: 4,
725
+ colors: false,
726
+ maxArrayLength: 100,
727
+ maxStringLength: 1000,
728
+ breakLength: 80,
729
+ })}`
730
+ }
731
+
732
+ function buildCapabilityCode(options: {
733
+ capability: CapabilityRecord
734
+ operation: ResolvedCapabilityOperation
735
+ script: string
736
+ input: unknown
737
+ force?: boolean
738
+ }): string {
739
+ const inputLiteral = JSON.stringify(options.input)
740
+ const capabilityLiteral = JSON.stringify({
741
+ id: options.capability.manifest.id,
742
+ title: options.capability.manifest.title,
743
+ description: options.capability.manifest.description,
744
+ operation: options.operation.id,
745
+ permissions: options.operation.permissions || options.capability.manifest.permissions,
746
+ })
747
+ const matchLiteral = JSON.stringify(options.operation.match)
748
+ return [
749
+ `const input = ${inputLiteral};`,
750
+ `const capability = ${capabilityLiteral};`,
751
+ `const __tabwrightCapabilityMatch = ${matchLiteral};`,
752
+ `const __tabwrightCapabilityForce = ${options.force ? 'true' : 'false'};`,
753
+ 'if (!__tabwrightCapabilityForce && __tabwrightCapabilityMatch.length > 0) {',
754
+ ' const __currentUrl = page.url();',
755
+ ' const __matched = __tabwrightCapabilityMatch.some((pattern) => {',
756
+ " const escaped = pattern.split('*').map((part) => part.replace(/[|\\\\{}()[\\]^$+?.]/g, '\\\\$&')).join('.*');",
757
+ ' return new RegExp(`^${escaped}$`).test(__currentUrl);',
758
+ ' });',
759
+ ' if (!__matched) {',
760
+ ' throw new Error(`Capability ${capability.id} does not match current page URL: ${__currentUrl}`);',
761
+ ' }',
762
+ '}',
763
+ 'const __tabwrightCapabilityObservedNetworkUrls = new Set();',
764
+ 'const __tabwrightCapabilityOnRequest = (request) => {',
765
+ ' __tabwrightCapabilityObservedNetworkUrls.add(request.url());',
766
+ '};',
767
+ "page.on('request', __tabwrightCapabilityOnRequest);",
768
+ 'try {',
769
+ ' const __tabwrightCapabilityOutput = await (async () => {',
770
+ options.script,
771
+ '\n })();',
772
+ ' return {',
773
+ ' __tabwrightCapabilityEnvelope: 1,',
774
+ ' output: __tabwrightCapabilityOutput === undefined ? undefined : JSON.parse(JSON.stringify(__tabwrightCapabilityOutput)),',
775
+ ' observedNetworkUrls: [...__tabwrightCapabilityObservedNetworkUrls],',
776
+ ' url: page.url(),',
777
+ ' };',
778
+ '} catch (__tabwrightCapabilityError) {',
779
+ ' return {',
780
+ ' __tabwrightCapabilityEnvelope: 1,',
781
+ ' output: undefined,',
782
+ ' observedNetworkUrls: [...__tabwrightCapabilityObservedNetworkUrls],',
783
+ ' url: page.url(),',
784
+ ' error: __tabwrightCapabilityError instanceof Error',
785
+ ' ? (__tabwrightCapabilityError.stack || __tabwrightCapabilityError.message)',
786
+ ' : String(__tabwrightCapabilityError),',
787
+ ' };',
788
+ '} finally {',
789
+ " page.off('request', __tabwrightCapabilityOnRequest);",
790
+ '}',
791
+ `//# sourceURL=tabwright-capability://${options.capability.manifest.id}`,
792
+ '',
793
+ ].join('\n')
794
+ }
795
+
796
+ function hashInput(input: unknown): string {
797
+ return crypto
798
+ .createHash('sha256')
799
+ .update(JSON.stringify(input) || 'undefined')
800
+ .digest('hex')
801
+ }