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/mcp.ts ADDED
@@ -0,0 +1,629 @@
1
+ import './env-compat.js'
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
4
+ import { z } from 'zod'
5
+ import fs from 'node:fs'
6
+ import path from 'node:path'
7
+ import util from 'node:util'
8
+ import { fileURLToPath } from 'node:url'
9
+ import { createRequire } from 'node:module'
10
+
11
+ // Prevent Buffers from dumping hex bytes in util.inspect output.
12
+ // Without this, returning a screenshot Buffer would log ~400+ chars of useless hex.
13
+ Buffer.prototype[util.inspect.custom] = function () {
14
+ return `<Buffer ${this.length} bytes>`
15
+ }
16
+
17
+ import dedent from 'string-dedent'
18
+ import { LOG_FILE_PATH, VERSION, parseRelayHost } from './utils.js'
19
+ import { ensureRelayServer, getLocalRelayHttpBaseUrl, RELAY_PORT } from './relay-client.js'
20
+ import { PlaywrightExecutor, CodeExecutionTimeoutError, type ExecuteResult } from './executor.js'
21
+ import { discoverChromeInstances, resolveDirectInput, appendSessionToWsUrl } from './chrome-discovery.js'
22
+ import crypto from 'node:crypto'
23
+ import {
24
+ listCapabilities,
25
+ readCapabilityScript,
26
+ routeCapabilities,
27
+ searchCapabilities,
28
+ toCapabilityContract,
29
+ toCapabilitySummary,
30
+ } from './capability-registry.js'
31
+ import { refreshCapabilityAuthWithExecutor } from './capability-auth.js'
32
+ import { runCapabilityWithExecutor, runNodeCapability } from './capability-runner.js'
33
+
34
+ const __filename = fileURLToPath(import.meta.url)
35
+ const __dirname = path.dirname(__filename)
36
+ const require = createRequire(import.meta.url)
37
+
38
+ // Single executor instance for MCP (created lazily)
39
+ let executor: PlaywrightExecutor | null = null
40
+
41
+ interface RemoteConfig {
42
+ host: string
43
+ port: number
44
+ token?: string
45
+ }
46
+
47
+ function getRemoteConfig(): RemoteConfig | null {
48
+ const host = process.env.TABWRIGHT_HOST
49
+ if (!host) {
50
+ return null
51
+ }
52
+ return {
53
+ host,
54
+ port: RELAY_PORT,
55
+ token: process.env.TABWRIGHT_TOKEN,
56
+ }
57
+ }
58
+
59
+ function getLogServerUrl(): string {
60
+ const remote = getRemoteConfig()
61
+ if (remote) {
62
+ const { httpBaseUrl } = parseRelayHost(remote.host, remote.port)
63
+ return `${httpBaseUrl}/mcp-log`
64
+ }
65
+ return `http://127.0.0.1:${RELAY_PORT}/mcp-log`
66
+ }
67
+
68
+ async function sendLogToRelayServer(level: string, ...args: any[]) {
69
+ try {
70
+ const headers: Record<string, string> = { 'Content-Type': 'application/json' }
71
+ const token = process.env.TABWRIGHT_TOKEN
72
+ if (token) {
73
+ headers['Authorization'] = `Bearer ${token}`
74
+ }
75
+ await fetch(getLogServerUrl(), {
76
+ method: 'POST',
77
+ headers,
78
+ body: JSON.stringify({ level, args }),
79
+ signal: AbortSignal.timeout(1000),
80
+ })
81
+ } catch {
82
+ // Silently fail if relay server is not available
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Log to both console.error (for early startup) and relay server log file.
88
+ * Fire-and-forget to avoid blocking.
89
+ */
90
+ function mcpLog(...args: any[]) {
91
+ console.error(...args)
92
+ sendLogToRelayServer('log', ...args)
93
+ }
94
+
95
+ /** MCP-specific logger for executor */
96
+ const mcpLogger = {
97
+ log: (...args: any[]) => mcpLog(...args),
98
+ error: (...args: any[]) => {
99
+ console.error(...args)
100
+ sendLogToRelayServer('error', ...args)
101
+ },
102
+ }
103
+
104
+ async function ensureRelayServerForMcp(): Promise<void> {
105
+ await ensureRelayServer({ logger: mcpLogger })
106
+ }
107
+
108
+ /**
109
+ * Resolve direct CDP config from TABWRIGHT_DIRECT env var.
110
+ * - "auto" / "1" / "true": auto-discover Chrome on default port 9222
111
+ * - "ws://..." / "wss://...": use explicit WebSocket endpoint
112
+ * - "host:port": resolve to ws:// URL via HTTP probe + DevToolsActivePort fallback
113
+ */
114
+ async function getDirectCdpConfig(): Promise<{ directCdpUrl: string } | null> {
115
+ const directEnv = process.env.TABWRIGHT_DIRECT
116
+ if (!directEnv) {
117
+ return null
118
+ }
119
+
120
+ // Auto-discover: check default port 9222
121
+ if (directEnv === '1') {
122
+ const instances = await discoverChromeInstances()
123
+ if (instances.length === 0) {
124
+ throw new Error(
125
+ 'TABWRIGHT_DIRECT is set but no Chrome found on port 9222. ' +
126
+ 'Enable debugging at chrome://inspect/#remote-debugging or launch with --remote-debugging-port=9222.',
127
+ )
128
+ }
129
+ const sessionId = crypto.randomUUID()
130
+ const wsUrl = appendSessionToWsUrl(instances[0].wsUrl, sessionId)
131
+ mcpLog(`Direct CDP: using ${instances[0].browser} on port ${instances[0].port}`)
132
+ return { directCdpUrl: wsUrl }
133
+ }
134
+
135
+ // ws://, wss://, or host:port — resolveDirectInput handles all three
136
+ const resolved = await resolveDirectInput(directEnv)
137
+ const sessionId = crypto.randomUUID()
138
+ const directCdpUrl = appendSessionToWsUrl(resolved, sessionId)
139
+ mcpLog(`Direct CDP: resolved ${directEnv} → ${directCdpUrl}`)
140
+ return { directCdpUrl }
141
+ }
142
+
143
+ async function getOrCreateExecutor(): Promise<PlaywrightExecutor> {
144
+ if (executor) {
145
+ return executor
146
+ }
147
+
148
+ // Direct CDP mode takes priority over relay/remote
149
+ const directConfig = await getDirectCdpConfig()
150
+ if (directConfig) {
151
+ executor = new PlaywrightExecutor({
152
+ cdpConfig: directConfig,
153
+ logger: mcpLogger,
154
+ cwd: process.cwd(),
155
+ })
156
+ return executor
157
+ }
158
+
159
+ const remote = getRemoteConfig()
160
+ if (!remote) {
161
+ await ensureRelayServerForMcp()
162
+ }
163
+
164
+ // Pass config instead of pre-generated URL so executor can generate unique URLs for each connection
165
+ const cdpConfig = remote || { host: await getLocalRelayHttpBaseUrl(RELAY_PORT), port: RELAY_PORT }
166
+ executor = new PlaywrightExecutor({
167
+ cdpConfig,
168
+ logger: mcpLogger,
169
+ cwd: process.cwd(),
170
+ })
171
+
172
+ return executor
173
+ }
174
+
175
+ async function checkRemoteServer({ host, port }: { host: string; port: number }): Promise<void> {
176
+ const { httpBaseUrl } = parseRelayHost(host, port)
177
+ const versionUrl = `${httpBaseUrl}/version`
178
+ try {
179
+ const response = await fetch(versionUrl, { signal: AbortSignal.timeout(3000) })
180
+ if (!response.ok) {
181
+ throw new Error(`Server responded with status ${response.status}`)
182
+ }
183
+ } catch (error: any) {
184
+ const isConnectionError = error.cause?.code === 'ECONNREFUSED' || error.name === 'TimeoutError'
185
+ if (isConnectionError) {
186
+ throw new Error(
187
+ `Cannot connect to remote relay server at ${host}. ` +
188
+ `Make sure 'npx -y tabwright serve' is running on the host machine.`,
189
+ )
190
+ }
191
+ throw new Error(`Failed to connect to remote relay server: ${error.message}`)
192
+ }
193
+ }
194
+
195
+ const server = new McpServer({
196
+ name: 'tabwright',
197
+ title: 'The better playwright MCP: works as a browser extension. No context bloat. More capable.',
198
+ version: VERSION,
199
+ })
200
+
201
+ const promptContent =
202
+ fs.readFileSync(path.join(__dirname, '..', 'dist', 'prompt.md'), 'utf-8') +
203
+ `\n\nfor debugging internal Tabwright errors, check Tabwright relay server logs at: ${LOG_FILE_PATH}`
204
+
205
+ server.resource(
206
+ 'debugger-api',
207
+ 'https://playwriter.dev/resources/debugger-api.md',
208
+ { mimeType: 'text/plain' },
209
+ async () => {
210
+ const packageJsonPath = require.resolve('tabwright/package.json')
211
+ const packageDir = path.dirname(packageJsonPath)
212
+ const content = fs.readFileSync(path.join(packageDir, 'dist', 'debugger-api.md'), 'utf-8')
213
+ return {
214
+ contents: [{ uri: 'https://playwriter.dev/resources/debugger-api.md', text: content, mimeType: 'text/plain' }],
215
+ }
216
+ },
217
+ )
218
+
219
+ server.resource(
220
+ 'editor-api',
221
+ 'https://playwriter.dev/resources/editor-api.md',
222
+ { mimeType: 'text/plain' },
223
+ async () => {
224
+ const packageJsonPath = require.resolve('tabwright/package.json')
225
+ const packageDir = path.dirname(packageJsonPath)
226
+ const content = fs.readFileSync(path.join(packageDir, 'dist', 'editor-api.md'), 'utf-8')
227
+ return {
228
+ contents: [{ uri: 'https://playwriter.dev/resources/editor-api.md', text: content, mimeType: 'text/plain' }],
229
+ }
230
+ },
231
+ )
232
+
233
+ server.resource(
234
+ 'styles-api',
235
+ 'https://playwriter.dev/resources/styles-api.md',
236
+ { mimeType: 'text/plain' },
237
+ async () => {
238
+ const packageJsonPath = require.resolve('tabwright/package.json')
239
+ const packageDir = path.dirname(packageJsonPath)
240
+ const content = fs.readFileSync(path.join(packageDir, 'dist', 'styles-api.md'), 'utf-8')
241
+ return {
242
+ contents: [{ uri: 'https://playwriter.dev/resources/styles-api.md', text: content, mimeType: 'text/plain' }],
243
+ }
244
+ },
245
+ )
246
+
247
+ server.resource(
248
+ 'capabilities',
249
+ 'tabwright://capabilities',
250
+ { mimeType: 'application/json' },
251
+ async () => {
252
+ const capabilities = listCapabilities({ cwd: process.cwd() }).map(toCapabilityContract)
253
+ return {
254
+ contents: [
255
+ {
256
+ uri: 'tabwright://capabilities',
257
+ text: JSON.stringify(capabilities, null, 2),
258
+ mimeType: 'application/json',
259
+ },
260
+ ],
261
+ }
262
+ },
263
+ )
264
+
265
+ function executeResultToMcpContent(options: {
266
+ result: ExecuteResult
267
+ prefix?: string
268
+ }): Array<{ type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string }> {
269
+ const MAX_TEXT = 10000
270
+ let text = options.prefix ? `${options.prefix}\n\n${options.result.text}` : options.result.text
271
+ for (const s of options.result.screenshots) {
272
+ text += `\nScreenshot saved to: ${s.path} (image included below, ${s.labelCount} labels)\n`
273
+ text += `Accessibility snapshot:\n${s.snapshot}\n`
274
+ }
275
+ if (text.length > MAX_TEXT) {
276
+ text = text.slice(0, MAX_TEXT) + '\n\n[Truncated]'
277
+ }
278
+
279
+ const content: Array<{ type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string }> = [
280
+ { type: 'text', text },
281
+ ]
282
+ for (const image of options.result.images) {
283
+ content.push({ type: 'image', data: image.data, mimeType: image.mimeType })
284
+ }
285
+ return content
286
+ }
287
+
288
+ server.tool(
289
+ 'capability',
290
+ dedent`
291
+ Search, inspect, refresh auth for, or run saved Tabwright capabilities. Capabilities are reusable Tabwright scripts with AI-readable contracts, local secrets, and run logs.
292
+
293
+ For concrete user tasks, use action "route" first. If it returns an exact-match direct-run capability, use action "run" directly with the returned input; do not search, describe, or open a page first.
294
+ Capability ids are not shell commands. If route output includes shellCommand, use that exact Tabwright CLI command; never run the capability id directly as a binary.
295
+ Do not treat every URL as a direct-run signal. If "route" returns no match, use action "search" before creating new browser code and action "describe" before running. Only use action "refresh_auth" after explicit user confirmation because it updates local credentials.
296
+ If a capability operation requires confirmation, stop and ask the user. Only after explicit approval may you retry action "run" with confirmation set to the operation's exact confirmationToken. force never bypasses this gate.
297
+ `,
298
+ {
299
+ action: z.enum(['list', 'route', 'search', 'show', 'describe', 'run', 'refresh_auth']).describe('Capability action'),
300
+ id: z.string().optional().describe('Capability id for show/describe/run/refresh_auth'),
301
+ query: z.string().optional().describe('Task or URL for action "route"; search query for action "search"'),
302
+ limit: z.number().default(10).describe('Maximum number of search results'),
303
+ input: z.record(z.string(), z.unknown()).optional().describe('JSON input for run'),
304
+ force: z.boolean().optional().describe('Run draft capabilities or bypass URL match checks'),
305
+ confirmation: z.string().optional().describe('Exact confirmationToken, supplied only after explicit user approval'),
306
+ timeout: z.number().default(10000).describe('Timeout in milliseconds'),
307
+ },
308
+ async ({ action, id, query, limit, input, force, confirmation, timeout }) => {
309
+ try {
310
+ if (action === 'list') {
311
+ return {
312
+ content: [
313
+ {
314
+ type: 'text',
315
+ text: JSON.stringify(listCapabilities({ cwd: process.cwd() }).map(toCapabilityContract), null, 2),
316
+ },
317
+ ],
318
+ }
319
+ }
320
+
321
+ if (action === 'search') {
322
+ return {
323
+ content: [
324
+ {
325
+ type: 'text',
326
+ text: JSON.stringify(
327
+ searchCapabilities({ query: query || '', cwd: process.cwd(), limit }).map((result) => {
328
+ return {
329
+ score: result.score,
330
+ reasons: result.reasons,
331
+ ...toCapabilityContract(result.capability),
332
+ }
333
+ }),
334
+ null,
335
+ 2,
336
+ ),
337
+ },
338
+ ],
339
+ }
340
+ }
341
+
342
+ if (action === 'route') {
343
+ return {
344
+ content: [
345
+ {
346
+ type: 'text',
347
+ text: JSON.stringify(
348
+ routeCapabilities({ task: query || '', cwd: process.cwd(), limit }).map((route) => {
349
+ return {
350
+ shellCommand: route.shellCommand,
351
+ command: route.command,
352
+ capabilityId: route.capability.manifest.id,
353
+ operation: route.operation,
354
+ id: route.capability.manifest.id,
355
+ title: route.capability.manifest.title,
356
+ location: route.capability.location,
357
+ routingHint:
358
+ route.operation === undefined
359
+ ? route.capability.manifest.routingHint
360
+ : route.capability.manifest.operations[route.operation]?.routingHint,
361
+ input: route.input,
362
+ commandWarning: route.commandWarning,
363
+ executionHint: route.executionHint,
364
+ reasons: route.reasons,
365
+ matchedText: route.matchedText,
366
+ }
367
+ }),
368
+ null,
369
+ 2,
370
+ ),
371
+ },
372
+ ],
373
+ }
374
+ }
375
+
376
+ if (!id) {
377
+ return { content: [{ type: 'text', text: 'id is required' }], isError: true }
378
+ }
379
+
380
+ if (action === 'show' || action === 'describe') {
381
+ const capability = listCapabilities({ cwd: process.cwd() }).find((candidate) => {
382
+ return candidate.manifest.id === id
383
+ })
384
+ if (!capability) {
385
+ return { content: [{ type: 'text', text: `Capability not found: ${id}` }], isError: true }
386
+ }
387
+ return {
388
+ content: [
389
+ {
390
+ type: 'text',
391
+ text: JSON.stringify(
392
+ {
393
+ ...(action === 'describe' ? toCapabilityContract(capability) : toCapabilitySummary(capability)),
394
+ ...(action === 'show' ? { script: readCapabilityScript({ id, cwd: process.cwd() }) } : {}),
395
+ },
396
+ null,
397
+ 2,
398
+ ),
399
+ },
400
+ ],
401
+ }
402
+ }
403
+
404
+ if (action === 'refresh_auth') {
405
+ const exec = await getOrCreateExecutor()
406
+ const result = await refreshCapabilityAuthWithExecutor({
407
+ executor: exec,
408
+ id,
409
+ cwd: process.cwd(),
410
+ timeout,
411
+ })
412
+ return {
413
+ content: [
414
+ {
415
+ type: 'text',
416
+ text: JSON.stringify(
417
+ {
418
+ capability: result.capability.manifest.id,
419
+ saved: result.saved,
420
+ secretKey: result.secretKey,
421
+ cookieCount: result.cookieCount,
422
+ cookieNames: result.cookieNames,
423
+ urls: result.urls,
424
+ expiresAt: result.expiresAt,
425
+ path: result.path,
426
+ },
427
+ null,
428
+ 2,
429
+ ),
430
+ },
431
+ ],
432
+ }
433
+ }
434
+
435
+ const capability = listCapabilities({ cwd: process.cwd() }).find((candidate) => {
436
+ return candidate.manifest.id === id
437
+ })
438
+ if (!capability) {
439
+ return { content: [{ type: 'text', text: `Capability not found: ${id}` }], isError: true }
440
+ }
441
+ if (capability.manifest.runtime === 'node') {
442
+ const result = await runNodeCapability({
443
+ id,
444
+ input: input || {},
445
+ cwd: process.cwd(),
446
+ timeout,
447
+ force,
448
+ confirmation,
449
+ })
450
+ return {
451
+ content: [
452
+ {
453
+ type: 'text',
454
+ text: `Capability output:\n${JSON.stringify(result.output, null, 2)}\n\n${result.text}`,
455
+ },
456
+ ],
457
+ isError: result.isError,
458
+ }
459
+ }
460
+
461
+ const exec = await getOrCreateExecutor()
462
+ const result = await runCapabilityWithExecutor({
463
+ executor: exec,
464
+ id,
465
+ input: input || {},
466
+ cwd: process.cwd(),
467
+ timeout,
468
+ force,
469
+ confirmation,
470
+ })
471
+ return {
472
+ content: executeResultToMcpContent({
473
+ result: result.executeResult,
474
+ prefix: `Capability output:\n${JSON.stringify(result.output, null, 2)}`,
475
+ }),
476
+ isError: result.executeResult.isError,
477
+ }
478
+ } catch (error) {
479
+ const errorStack = error instanceof Error ? error.stack || error.message : String(error)
480
+ console.error('Error in capability tool:', errorStack)
481
+ return {
482
+ content: [{ type: 'text', text: `Error running capability: ${error instanceof Error ? error.message : String(error)}` }],
483
+ isError: true,
484
+ }
485
+ }
486
+ },
487
+ )
488
+
489
+ server.tool(
490
+ 'execute',
491
+ promptContent,
492
+ {
493
+ code: z
494
+ .string()
495
+ .describe(
496
+ 'js playwright code, has {page, state, context} in scope. Should be one line, using ; to execute multiple statements. you MUST call execute multiple times instead of writing complex scripts in a single tool call.',
497
+ ),
498
+ timeout: z.number().default(10000).describe('Timeout in milliseconds for code execution (default: 10000ms)'),
499
+ },
500
+ async ({ code, timeout }) => {
501
+ try {
502
+ // Check relay server on every execute to auto-recover from crashes
503
+ // (skip in direct CDP mode — no relay involved)
504
+ if (!process.env.TABWRIGHT_DIRECT) {
505
+ const remote = getRemoteConfig()
506
+ if (!remote) {
507
+ await ensureRelayServerForMcp()
508
+ }
509
+ }
510
+
511
+ const exec = await getOrCreateExecutor()
512
+ const result = await exec.execute(code, timeout)
513
+
514
+ // Transform executor result to MCP format
515
+ // Append screenshot metadata to text for MCP (image is included inline as content)
516
+ const MAX_TEXT = 10000
517
+ let text = result.text
518
+ for (const s of result.screenshots) {
519
+ text += `\nScreenshot saved to: ${s.path} (image included below, ${s.labelCount} labels)\n`
520
+ text += `Accessibility snapshot:\n${s.snapshot}\n`
521
+ }
522
+ if (text.length > MAX_TEXT) {
523
+ text = text.slice(0, MAX_TEXT) + '\n\n[Truncated]'
524
+ }
525
+
526
+ const content: Array<{ type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string }> = [
527
+ { type: 'text', text },
528
+ ]
529
+
530
+ for (const image of result.images) {
531
+ content.push({ type: 'image', data: image.data, mimeType: image.mimeType })
532
+ }
533
+
534
+ if (result.isError) {
535
+ return { content, isError: true }
536
+ }
537
+
538
+ return { content }
539
+ } catch (error: any) {
540
+ const errorStack = error.stack || error.message
541
+ const isTimeoutError =
542
+ error instanceof CodeExecutionTimeoutError || error?.name === 'TimeoutError' || error?.name === 'AbortError'
543
+
544
+ console.error('Error in execute tool:', errorStack)
545
+ if (!isTimeoutError) {
546
+ sendLogToRelayServer('error', 'Error in execute tool:', errorStack)
547
+ }
548
+
549
+ const resetHint = isTimeoutError
550
+ ? ''
551
+ : '\n\n[HINT: If this is an internal Playwright error, page/browser closed, or connection issue, call the `reset` tool to reconnect. Do NOT reset for other non-connection non-internal errors.]'
552
+
553
+ // timeout stacks are internal noise (Promise.race / setTimeout); only show the message
554
+ const errorText = isTimeoutError ? error.message : errorStack
555
+ return {
556
+ content: [{ type: 'text', text: `Error executing code: ${errorText}${resetHint}` }],
557
+ isError: true,
558
+ }
559
+ }
560
+ },
561
+ )
562
+
563
+ server.tool(
564
+ 'reset',
565
+ dedent`
566
+ Recreates the CDP connection and resets the browser/page/context. Use this when the MCP stops responding, you get connection errors, if there are no pages in context, assertion failures, page closed, or other issues.
567
+
568
+ After calling this tool, the page and context variables are automatically updated in the execution environment.
569
+
570
+ This tools also removes any custom properties you may have added to the global scope AND clearing all keys from the \`state\` object. Only \`page\`, \`context\`, \`state\` (empty), \`console\`, and utility functions will remain.
571
+
572
+ if playwright always returns all pages as about:blank urls and evaluate does not work you should ask the user to restart Chrome. This is a known Chrome bug.
573
+ `,
574
+ {},
575
+ async () => {
576
+ try {
577
+ // Check relay server to auto-recover from crashes
578
+ // (skip in direct CDP mode — no relay involved)
579
+ if (!process.env.TABWRIGHT_DIRECT) {
580
+ const remote = getRemoteConfig()
581
+ if (!remote) {
582
+ await ensureRelayServerForMcp()
583
+ }
584
+ }
585
+
586
+ const exec = await getOrCreateExecutor()
587
+ const { page, context } = await exec.reset()
588
+ const pagesCount = context.pages().length
589
+ return {
590
+ content: [
591
+ {
592
+ type: 'text',
593
+ text: `Connection reset successfully. ${pagesCount} page(s) available. Current page URL: ${page.url()}`,
594
+ },
595
+ ],
596
+ }
597
+ } catch (error: any) {
598
+ return {
599
+ content: [{ type: 'text', text: `Failed to reset connection: ${error.message}` }],
600
+ isError: true,
601
+ }
602
+ }
603
+ },
604
+ )
605
+
606
+ export async function startMcp(options: { host?: string; token?: string } = {}) {
607
+ if (options.host) {
608
+ process.env.TABWRIGHT_HOST = options.host
609
+ }
610
+ if (options.token) {
611
+ process.env.TABWRIGHT_TOKEN = options.token
612
+ }
613
+
614
+ // In direct CDP mode (TABWRIGHT_DIRECT env var), no relay server needed
615
+ if (process.env.TABWRIGHT_DIRECT) {
616
+ mcpLog(`Using direct CDP connection: ${process.env.TABWRIGHT_DIRECT}`)
617
+ } else {
618
+ const remote = getRemoteConfig()
619
+ if (!remote) {
620
+ await ensureRelayServerForMcp()
621
+ } else {
622
+ mcpLog(`Using remote CDP relay server: ${remote.host}`)
623
+ await checkRemoteServer(remote)
624
+ }
625
+ }
626
+
627
+ const transport = new StdioServerTransport()
628
+ await server.connect(transport)
629
+ }