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,708 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { createMCPClient } from './mcp-client.js';
5
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
6
+ import { chromium } from '@xmorse/playwright-core';
7
+ import { getCdpUrl } from './utils.js';
8
+ import { setupTestContext, cleanupTestContext, getExtensionServiceWorker, launchPersistentContextWithExtensions, js, } from './test-utils.js';
9
+ import { getExtensionsStatus } from './relay-client.js';
10
+ import './test-declarations.js';
11
+ const TEST_PORT = 19990;
12
+ describe('Extension Connection Tests', () => {
13
+ let client;
14
+ let cleanup = null;
15
+ let testCtx = null;
16
+ beforeAll(async () => {
17
+ testCtx = await setupTestContext({ port: TEST_PORT, tempDirPrefix: 'pw-conn-test-', toggleExtension: true });
18
+ const result = await createMCPClient({ port: TEST_PORT });
19
+ client = result.client;
20
+ cleanup = result.cleanup;
21
+ }, 600000);
22
+ afterAll(async () => {
23
+ await cleanupTestContext(testCtx, cleanup);
24
+ cleanup = null;
25
+ testCtx = null;
26
+ });
27
+ const getBrowserContext = () => {
28
+ if (!testCtx?.browserContext)
29
+ throw new Error('Browser not initialized');
30
+ return testCtx.browserContext;
31
+ };
32
+ it('should handle new pages and toggling with new connections', async () => {
33
+ const browserContext = getBrowserContext();
34
+ const serviceWorker = await getExtensionServiceWorker(browserContext);
35
+ // 1. Create a new page
36
+ const page = await browserContext.newPage();
37
+ const testUrl = 'https://example.com/';
38
+ await page.goto(testUrl);
39
+ await page.bringToFront();
40
+ // 2. Enable extension on this new tab
41
+ const result = await serviceWorker.evaluate(async () => {
42
+ return await globalThis.toggleExtensionForActiveTab();
43
+ });
44
+ expect(result.isConnected).toBe(true);
45
+ // 3. Verify we can connect via direct CDP and see the page
46
+ let directBrowser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }));
47
+ let contexts = directBrowser.contexts();
48
+ let pages = contexts[0].pages();
49
+ let foundPage = pages.find((p) => p.url() === testUrl);
50
+ expect(foundPage).toBeDefined();
51
+ expect(foundPage?.url()).toBe(testUrl);
52
+ const sum1 = await foundPage?.evaluate(() => 1 + 1);
53
+ expect(sum1).toBe(2);
54
+ await directBrowser.close();
55
+ // 4. Disable extension on this tab
56
+ const resultDisabled = await serviceWorker.evaluate(async () => {
57
+ return await globalThis.toggleExtensionForActiveTab();
58
+ });
59
+ expect(resultDisabled.isConnected).toBe(false);
60
+ // 5. Connect again - page should NOT be visible
61
+ directBrowser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }));
62
+ contexts = directBrowser.contexts();
63
+ pages = contexts[0].pages();
64
+ foundPage = pages.find((p) => p.url() === testUrl);
65
+ expect(foundPage).toBeUndefined();
66
+ await directBrowser.close();
67
+ // 6. Re-enable extension
68
+ const resultEnabled = await serviceWorker.evaluate(async () => {
69
+ return await globalThis.toggleExtensionForActiveTab();
70
+ });
71
+ expect(resultEnabled.isConnected).toBe(true);
72
+ // 7. Verify page is back
73
+ directBrowser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }));
74
+ await new Promise((r) => setTimeout(r, 100));
75
+ contexts = directBrowser.contexts();
76
+ if (contexts[0].pages().length === 0) {
77
+ await new Promise((r) => setTimeout(r, 100));
78
+ }
79
+ pages = contexts[0].pages();
80
+ foundPage = pages.find((p) => p.url() === testUrl);
81
+ expect(foundPage).toBeDefined();
82
+ expect(foundPage?.url()).toBe(testUrl);
83
+ const sum2 = await foundPage?.evaluate(() => 2 + 2);
84
+ expect(sum2).toBe(4);
85
+ await directBrowser.close();
86
+ await page.close();
87
+ }, 120000);
88
+ it('should handle new pages and toggling with persistent connection', async () => {
89
+ const browserContext = getBrowserContext();
90
+ const serviceWorker = await getExtensionServiceWorker(browserContext);
91
+ const directBrowser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }));
92
+ await new Promise((r) => setTimeout(r, 100));
93
+ // 1. Create a new page
94
+ const page = await browserContext.newPage();
95
+ const testUrl = 'https://example.com/persistent';
96
+ await page.goto(testUrl);
97
+ await page.bringToFront();
98
+ // 2. Enable extension
99
+ await serviceWorker.evaluate(async () => {
100
+ await globalThis.toggleExtensionForActiveTab();
101
+ });
102
+ // 3. Verify page appears (polling)
103
+ let foundPage;
104
+ for (let i = 0; i < 50; i++) {
105
+ const pages = directBrowser.contexts()[0].pages();
106
+ foundPage = pages.find((p) => p.url() === testUrl);
107
+ if (foundPage)
108
+ break;
109
+ await new Promise((r) => setTimeout(r, 100));
110
+ }
111
+ expect(foundPage).toBeDefined();
112
+ expect(foundPage?.url()).toBe(testUrl);
113
+ const sum1 = await foundPage?.evaluate(() => 10 + 20);
114
+ expect(sum1).toBe(30);
115
+ // 4. Disable extension
116
+ await serviceWorker.evaluate(async () => {
117
+ await globalThis.toggleExtensionForActiveTab();
118
+ });
119
+ // 5. Verify page disappears (polling)
120
+ for (let i = 0; i < 50; i++) {
121
+ const pages = directBrowser.contexts()[0].pages();
122
+ foundPage = pages.find((p) => p.url() === testUrl);
123
+ if (!foundPage)
124
+ break;
125
+ await new Promise((r) => setTimeout(r, 100));
126
+ }
127
+ expect(foundPage).toBeUndefined();
128
+ // 6. Re-enable extension
129
+ await serviceWorker.evaluate(async () => {
130
+ await globalThis.toggleExtensionForActiveTab();
131
+ });
132
+ // 7. Verify page reappears (polling)
133
+ for (let i = 0; i < 50; i++) {
134
+ const pages = directBrowser.contexts()[0].pages();
135
+ foundPage = pages.find((p) => p.url() === testUrl);
136
+ if (foundPage)
137
+ break;
138
+ await new Promise((r) => setTimeout(r, 100));
139
+ }
140
+ expect(foundPage).toBeDefined();
141
+ expect(foundPage?.url()).toBe(testUrl);
142
+ const sum2 = await foundPage?.evaluate(() => 30 + 40);
143
+ expect(sum2).toBe(70);
144
+ await page.close();
145
+ await directBrowser.close();
146
+ });
147
+ it('should maintain connection across reloads and navigation', async () => {
148
+ const browserContext = getBrowserContext();
149
+ const serviceWorker = await getExtensionServiceWorker(browserContext);
150
+ // 1. Setup page
151
+ const page = await browserContext.newPage();
152
+ const initialUrl = 'https://example.com/';
153
+ await page.goto(initialUrl);
154
+ await page.bringToFront();
155
+ // 2. Enable extension
156
+ await serviceWorker.evaluate(async () => {
157
+ await globalThis.toggleExtensionForActiveTab();
158
+ });
159
+ // 3. Connect via CDP
160
+ const cdpUrl = getCdpUrl({ port: TEST_PORT });
161
+ const directBrowser = await chromium.connectOverCDP(cdpUrl);
162
+ const connectedPage = directBrowser
163
+ .contexts()[0]
164
+ .pages()
165
+ .find((p) => p.url() === initialUrl);
166
+ expect(connectedPage).toBeDefined();
167
+ expect(await connectedPage?.evaluate(() => 1 + 1)).toBe(2);
168
+ // 4. Reload
169
+ await connectedPage?.reload();
170
+ await connectedPage?.waitForLoadState('domcontentloaded');
171
+ expect(await connectedPage?.title()).toBe('Example Domain');
172
+ expect(await connectedPage?.evaluate(() => 2 + 2)).toBe(4);
173
+ // 5. Navigate to new URL
174
+ const newUrl = 'https://example.org/';
175
+ await connectedPage?.goto(newUrl);
176
+ await connectedPage?.waitForLoadState('domcontentloaded');
177
+ expect(connectedPage?.url()).toBe(newUrl);
178
+ expect(await connectedPage?.title()).toContain('Example Domain');
179
+ expect(await connectedPage?.evaluate(() => 3 + 3)).toBe(6);
180
+ await directBrowser.close();
181
+ await page.close();
182
+ });
183
+ it('should support multiple concurrent tabs', async () => {
184
+ const browserContext = getBrowserContext();
185
+ const serviceWorker = await getExtensionServiceWorker(browserContext);
186
+ await new Promise((resolve) => setTimeout(resolve, 100));
187
+ // Tab A
188
+ const pageA = await browserContext.newPage();
189
+ await pageA.goto('https://example.com/tab-a');
190
+ await pageA.bringToFront();
191
+ await new Promise((resolve) => setTimeout(resolve, 100));
192
+ await serviceWorker.evaluate(async () => {
193
+ await globalThis.toggleExtensionForActiveTab();
194
+ });
195
+ // Tab B
196
+ const pageB = await browserContext.newPage();
197
+ await pageB.goto('https://example.com/tab-b');
198
+ await pageB.bringToFront();
199
+ await new Promise((resolve) => setTimeout(resolve, 100));
200
+ await serviceWorker.evaluate(async () => {
201
+ await globalThis.toggleExtensionForActiveTab();
202
+ });
203
+ // Get target IDs for both
204
+ const targetIds = await serviceWorker.evaluate(async () => {
205
+ const state = globalThis.getExtensionState();
206
+ const chrome = globalThis.chrome;
207
+ const tabs = await chrome.tabs.query({});
208
+ const tabA = tabs.find((t) => t.url?.includes('tab-a'));
209
+ const tabB = tabs.find((t) => t.url?.includes('tab-b'));
210
+ return {
211
+ idA: state.tabs.get(tabA?.id ?? -1)?.targetId,
212
+ idB: state.tabs.get(tabB?.id ?? -1)?.targetId,
213
+ };
214
+ });
215
+ expect(targetIds).toMatchInlineSnapshot({
216
+ idA: expect.any(String),
217
+ idB: expect.any(String),
218
+ }, `
219
+ {
220
+ "idA": Any<String>,
221
+ "idB": Any<String>,
222
+ }
223
+ `);
224
+ expect(targetIds.idA).not.toBe(targetIds.idB);
225
+ // Verify independent connections
226
+ const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }));
227
+ const pages = browser.contexts()[0].pages();
228
+ const results = await Promise.all(pages.map(async (p) => ({
229
+ url: p.url(),
230
+ title: await p.title(),
231
+ })));
232
+ expect(results).toMatchInlineSnapshot(`
233
+ [
234
+ {
235
+ "title": "",
236
+ "url": "about:blank",
237
+ },
238
+ {
239
+ "title": "Example Domain",
240
+ "url": "https://example.com/tab-a",
241
+ },
242
+ {
243
+ "title": "Example Domain",
244
+ "url": "https://example.com/tab-b",
245
+ },
246
+ ]
247
+ `);
248
+ // Verify execution on both pages
249
+ const pageA_CDP = pages.find((p) => p.url().includes('tab-a'));
250
+ const pageB_CDP = pages.find((p) => p.url().includes('tab-b'));
251
+ expect(await pageA_CDP?.evaluate(() => 10 + 10)).toBe(20);
252
+ expect(await pageB_CDP?.evaluate(() => 20 + 20)).toBe(40);
253
+ await browser.close();
254
+ await pageA.close();
255
+ await pageB.close();
256
+ });
257
+ it('should warn and switch page when the active page closes', async () => {
258
+ const browserContext = getBrowserContext();
259
+ const serviceWorker = await getExtensionServiceWorker(browserContext);
260
+ const pageA = await browserContext.newPage();
261
+ await pageA.goto('https://example.com/close-warning-a');
262
+ await pageA.bringToFront();
263
+ await serviceWorker.evaluate(async () => {
264
+ await globalThis.toggleExtensionForActiveTab();
265
+ });
266
+ const pageB = await browserContext.newPage();
267
+ await pageB.goto('https://example.com/close-warning-b');
268
+ await pageB.bringToFront();
269
+ await serviceWorker.evaluate(async () => {
270
+ await globalThis.toggleExtensionForActiveTab();
271
+ });
272
+ const closeResult = await client.callTool({
273
+ name: 'execute',
274
+ arguments: {
275
+ code: js `
276
+ state.page = page;
277
+ const closedUrl = state.page.url();
278
+ await state.page.close();
279
+ return { closedUrl, remainingPages: context.pages().length };
280
+ `,
281
+ },
282
+ });
283
+ const closeOutput = closeResult.content[0].text;
284
+ expect(closeOutput).toContain('[WARNING] The current page in state.page was closed');
285
+ expect(closeOutput).toContain('Switched active page to index');
286
+ expect(closeResult.isError).not.toBe(true);
287
+ const nextResult = await client.callTool({
288
+ name: 'execute',
289
+ arguments: {
290
+ code: js `
291
+ return { pageUrl: page.url(), pagesCount: context.pages().length };
292
+ `,
293
+ },
294
+ });
295
+ const nextOutput = nextResult.content[0].text;
296
+ expect(nextOutput).toContain('pagesCount');
297
+ expect(nextOutput).not.toContain('No Playwright pages are available');
298
+ expect(nextOutput).not.toContain('[WARNING] The current page was closed');
299
+ expect(nextResult.isError).not.toBe(true);
300
+ if (!pageA.isClosed()) {
301
+ await pageA.close();
302
+ }
303
+ if (!pageB.isClosed()) {
304
+ await pageB.close();
305
+ }
306
+ });
307
+ it('should switch page without warning when closed page is not stored in state', async () => {
308
+ const browserContext = getBrowserContext();
309
+ const serviceWorker = await getExtensionServiceWorker(browserContext);
310
+ const pageA = await browserContext.newPage();
311
+ await pageA.goto('https://example.com/close-no-state-warning-a');
312
+ await pageA.bringToFront();
313
+ await serviceWorker.evaluate(async () => {
314
+ await globalThis.toggleExtensionForActiveTab();
315
+ });
316
+ const pageB = await browserContext.newPage();
317
+ await pageB.goto('https://example.com/close-no-state-warning-b');
318
+ await pageB.bringToFront();
319
+ await serviceWorker.evaluate(async () => {
320
+ await globalThis.toggleExtensionForActiveTab();
321
+ });
322
+ const closeResult = await client.callTool({
323
+ name: 'execute',
324
+ arguments: {
325
+ code: js `
326
+ const closedUrl = page.url();
327
+ await page.close();
328
+ return { closedUrl, remainingPages: context.pages().length };
329
+ `,
330
+ },
331
+ });
332
+ const closeOutput = closeResult.content[0].text;
333
+ expect(closeOutput).not.toContain('[WARNING] The current page in state.page was closed');
334
+ expect(closeOutput).not.toContain('Switched active page to index');
335
+ expect(closeResult.isError).not.toBe(true);
336
+ const nextResult = await client.callTool({
337
+ name: 'execute',
338
+ arguments: {
339
+ code: js `
340
+ return { pageUrl: page.url(), pagesCount: context.pages().length };
341
+ `,
342
+ },
343
+ });
344
+ const nextOutput = nextResult.content[0].text;
345
+ expect(nextOutput).toContain('pagesCount');
346
+ expect(nextResult.isError).not.toBe(true);
347
+ if (!pageA.isClosed()) {
348
+ await pageA.close();
349
+ }
350
+ if (!pageB.isClosed()) {
351
+ await pageB.close();
352
+ }
353
+ });
354
+ it('should show correct url when enabling extension after navigation', async () => {
355
+ const browserContext = getBrowserContext();
356
+ const serviceWorker = await getExtensionServiceWorker(browserContext);
357
+ const page = await browserContext.newPage();
358
+ const targetUrl = 'https://example.com/late-enable';
359
+ await page.goto(targetUrl);
360
+ await page.bringToFront();
361
+ await page.waitForLoadState('domcontentloaded');
362
+ await serviceWorker.evaluate(async () => {
363
+ await globalThis.toggleExtensionForActiveTab();
364
+ });
365
+ const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }));
366
+ await new Promise((r) => setTimeout(r, 100));
367
+ const cdpPage = browser
368
+ .contexts()[0]
369
+ .pages()
370
+ .find((p) => p.url() === targetUrl);
371
+ expect(cdpPage).toBeDefined();
372
+ expect(cdpPage?.url()).toBe(targetUrl);
373
+ await browser.close();
374
+ await page.close();
375
+ }, 60000);
376
+ it('should be able to reconnect after disconnecting everything', async () => {
377
+ const browserContext = getBrowserContext();
378
+ const serviceWorker = await getExtensionServiceWorker(browserContext);
379
+ const pages = await browserContext.pages();
380
+ expect(pages.length).toBeGreaterThan(0);
381
+ const page = pages[0];
382
+ await page.goto('https://example.com/disconnect-test');
383
+ await page.waitForLoadState('domcontentloaded');
384
+ await page.bringToFront();
385
+ // Enable extension on this page
386
+ const initialEnable = await serviceWorker.evaluate(async () => {
387
+ return await globalThis.toggleExtensionForActiveTab();
388
+ });
389
+ console.log('Initial enable result:', initialEnable);
390
+ expect(initialEnable.isConnected).toBe(true);
391
+ await new Promise((resolve) => setTimeout(resolve, 100));
392
+ // Verify MCP can see the page
393
+ const beforeDisconnect = await client.callTool({
394
+ name: 'execute',
395
+ arguments: {
396
+ code: js `
397
+ const pages = context.pages();
398
+ console.log('Pages before disconnect:', pages.length);
399
+ const testPage = pages.find(p => p.url().includes('disconnect-test'));
400
+ console.log('Found test page:', !!testPage);
401
+ return { pagesCount: pages.length, foundTestPage: !!testPage };
402
+ `,
403
+ },
404
+ });
405
+ const beforeOutput = beforeDisconnect.content[0].text;
406
+ expect(beforeOutput).toContain('foundTestPage');
407
+ console.log('Before disconnect:', beforeOutput);
408
+ // 2. Disconnect everything
409
+ console.log('Calling disconnectEverything...');
410
+ await serviceWorker.evaluate(async () => {
411
+ await globalThis.disconnectEverything();
412
+ });
413
+ await new Promise((resolve) => setTimeout(resolve, 100));
414
+ // 3. The disconnected page must disappear. Depending on auto-enable and
415
+ // extension generation, the relay may expose a fresh blank target or no page.
416
+ const afterDisconnect = await client.callTool({
417
+ name: 'execute',
418
+ arguments: {
419
+ code: js `
420
+ const pages = context.pages();
421
+ console.log('Pages after disconnect:', pages.length);
422
+ const disconnectedPage = pages.find(p => p.url().includes('disconnect-test'));
423
+ return { pagesCount: pages.length, foundDisconnectedPage: !!disconnectedPage };
424
+ `,
425
+ },
426
+ });
427
+ const afterDisconnectOutput = afterDisconnect.content[0].text;
428
+ console.log('After disconnect:', afterDisconnectOutput);
429
+ if (afterDisconnect.isError === true) {
430
+ expect(afterDisconnectOutput).toContain('No Playwright pages are available');
431
+ }
432
+ else {
433
+ expect(afterDisconnectOutput).toContain('foundDisconnectedPage: false');
434
+ }
435
+ // 4. Re-enable extension on the same page
436
+ console.log('Re-enabling extension...');
437
+ await page.bringToFront();
438
+ const reconnectResult = await serviceWorker.evaluate(async () => {
439
+ console.log('About to call toggleExtensionForActiveTab');
440
+ const result = await globalThis.toggleExtensionForActiveTab();
441
+ console.log('toggleExtensionForActiveTab result:', result);
442
+ return result;
443
+ });
444
+ console.log('Reconnect result:', reconnectResult);
445
+ expect(reconnectResult.isConnected).toBe(true);
446
+ console.log('Waiting for reconnection to stabilize...');
447
+ await new Promise((resolve) => setTimeout(resolve, 100));
448
+ // 5. Reset the MCP client's playwright connection
449
+ console.log('Resetting MCP playwright connection...');
450
+ const resetResult = await client.callTool({
451
+ name: 'reset',
452
+ arguments: {},
453
+ });
454
+ console.log('Reset result:', resetResult.content[0].text);
455
+ expect(resetResult.content[0].text).toContain('Connection reset successfully');
456
+ // 6. Verify MCP can see the page again
457
+ console.log('Attempting to access page via MCP...');
458
+ const afterReconnect = await client.callTool({
459
+ name: 'execute',
460
+ arguments: {
461
+ code: js `
462
+ console.log('Checking pages after reconnect...');
463
+ const pages = context.pages();
464
+ console.log('Pages after reconnect:', pages.length);
465
+
466
+ if (pages.length === 0) {
467
+ console.log('No pages found!');
468
+ return { pagesCount: 0, foundTestPage: false };
469
+ }
470
+
471
+ const testPage = pages.find(p => p.url().includes('disconnect-test'));
472
+ console.log('Found test page after reconnect:', !!testPage);
473
+
474
+ if (testPage) {
475
+ console.log('Test page URL:', testPage.url());
476
+ return { pagesCount: pages.length, foundTestPage: true, url: testPage.url() };
477
+ }
478
+
479
+ return { pagesCount: pages.length, foundTestPage: false };
480
+ `,
481
+ },
482
+ });
483
+ const afterReconnectOutput = afterReconnect.content[0].text;
484
+ console.log('After reconnect:', afterReconnectOutput);
485
+ expect(afterReconnectOutput).toContain('foundTestPage');
486
+ expect(afterReconnectOutput).toContain('disconnect-test');
487
+ // Clean up
488
+ await page.goto('about:blank');
489
+ });
490
+ it('should auto-reconnect MCP after extension WebSocket reconnects', async () => {
491
+ const serviceWorker = await getExtensionServiceWorker(testCtx.browserContext);
492
+ // 1. Create a test page and enable extension
493
+ const page = await testCtx.browserContext.newPage();
494
+ await page.goto('https://example.com/auto-reconnect-test');
495
+ await page.waitForLoadState('domcontentloaded');
496
+ await page.bringToFront();
497
+ const initialEnable = await serviceWorker.evaluate(async () => {
498
+ return await globalThis.toggleExtensionForActiveTab();
499
+ });
500
+ expect(initialEnable.isConnected).toBe(true);
501
+ await new Promise((resolve) => setTimeout(resolve, 100));
502
+ // 2. Verify MCP can execute commands
503
+ const beforeResult = await client.callTool({
504
+ name: 'execute',
505
+ arguments: {
506
+ code: js `
507
+ let testPage;
508
+ for (let i = 0; i < 20; i++) {
509
+ const pages = context.pages();
510
+ testPage = pages.find(p => p.url().includes('auto-reconnect-test'));
511
+ if (testPage) break;
512
+ await new Promise((r) => { setTimeout(r, 100) });
513
+ }
514
+ const pages = context.pages();
515
+ return { pagesCount: pages.length, foundTestPage: !!testPage, url: testPage?.url() };
516
+ `,
517
+ },
518
+ });
519
+ const beforeOutput = beforeResult.content[0].text;
520
+ expect(beforeOutput).toContain('foundTestPage');
521
+ expect(beforeOutput).toContain('true');
522
+ expect(beforeOutput).toContain('auto-reconnect-test');
523
+ // 3. Simulate extension WebSocket reconnection
524
+ await serviceWorker.evaluate(async () => {
525
+ await globalThis.disconnectEverything();
526
+ });
527
+ await new Promise((resolve) => setTimeout(resolve, 100));
528
+ // Re-enable extension
529
+ await page.bringToFront();
530
+ const reconnectResult = await serviceWorker.evaluate(async () => {
531
+ return await globalThis.toggleExtensionForActiveTab();
532
+ });
533
+ expect(reconnectResult.isConnected).toBe(true);
534
+ await new Promise((resolve) => setTimeout(resolve, 100));
535
+ // 4. Execute command WITHOUT calling resetPlaywright()
536
+ const afterResult = await client.callTool({
537
+ name: 'execute',
538
+ arguments: {
539
+ code: js `
540
+ let testPage;
541
+ for (let i = 0; i < 20; i++) {
542
+ const pages = context.pages();
543
+ testPage = pages.find(p => p.url().includes('auto-reconnect-test'));
544
+ if (testPage) break;
545
+ await new Promise((r) => { setTimeout(r, 100) });
546
+ }
547
+ const pages = context.pages();
548
+ return { pagesCount: pages.length, foundTestPage: !!testPage, url: testPage?.url() };
549
+ `,
550
+ },
551
+ });
552
+ const afterOutput = afterResult.content[0].text;
553
+ expect(afterOutput).toContain('foundTestPage');
554
+ expect(afterOutput).toContain('true');
555
+ expect(afterOutput).toContain('auto-reconnect-test');
556
+ expect(afterOutput).not.toContain('Extension not connected');
557
+ expect(afterResult.isError).not.toBe(true);
558
+ // Clean up
559
+ await page.goto('about:blank');
560
+ });
561
+ it('should keep an active browser connected when another Chromium context starts', async () => {
562
+ const browserContext = getBrowserContext();
563
+ const serviceWorker = await getExtensionServiceWorker(browserContext);
564
+ await serviceWorker.evaluate(async () => {
565
+ await globalThis.disconnectEverything();
566
+ });
567
+ const page = await browserContext.newPage();
568
+ const targetUrl = 'https://example.com/multi-context-stability';
569
+ await page.goto(targetUrl);
570
+ await page.waitForLoadState('domcontentloaded');
571
+ await page.bringToFront();
572
+ const enableResult = await serviceWorker.evaluate(async () => {
573
+ return await globalThis.toggleExtensionForActiveTab();
574
+ });
575
+ expect(enableResult.isConnected).toBe(true);
576
+ const secondUserDataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pw-conn-second-'));
577
+ const extensionPath = path.resolve(process.cwd(), '../extension', `dist-${TEST_PORT}`);
578
+ const secondContext = await launchPersistentContextWithExtensions({
579
+ userDataDir: secondUserDataDir,
580
+ extensionPaths: [extensionPath],
581
+ });
582
+ try {
583
+ await getExtensionServiceWorker(secondContext);
584
+ const statusSnapshots = [];
585
+ for (let i = 0; i < 4; i++) {
586
+ await new Promise((resolve) => {
587
+ setTimeout(resolve, 1000);
588
+ });
589
+ const statuses = await getExtensionsStatus(TEST_PORT);
590
+ statusSnapshots.push({
591
+ keys: statuses.map((status) => {
592
+ return status.stableKey || status.extensionId;
593
+ }),
594
+ activeTargets: statuses.map((status) => {
595
+ return status.activeTargets;
596
+ }),
597
+ });
598
+ }
599
+ expect(statusSnapshots.every((snapshot) => {
600
+ return snapshot.keys.length >= 2;
601
+ })).toBe(true);
602
+ expect(statusSnapshots.every((snapshot) => {
603
+ return new Set(snapshot.keys).size === snapshot.keys.length;
604
+ })).toBe(true);
605
+ expect(statusSnapshots.every((snapshot) => {
606
+ return snapshot.activeTargets.some((count) => count > 0);
607
+ })).toBe(true);
608
+ const executeResult = await client.callTool({
609
+ name: 'execute',
610
+ arguments: {
611
+ code: js `
612
+ const pages = context.pages();
613
+ const testPage = pages.find((p) => p.url().includes('multi-context-stability'));
614
+ return { pagesCount: pages.length, found: !!testPage, url: testPage?.url() };
615
+ `,
616
+ },
617
+ });
618
+ const executeOutput = executeResult.content[0].text;
619
+ expect(executeOutput).toContain('found: true');
620
+ expect(executeOutput).toContain(targetUrl);
621
+ expect(executeResult.isError).not.toBe(true);
622
+ }
623
+ finally {
624
+ await secondContext.close();
625
+ fs.rmSync(secondUserDataDir, { recursive: true, force: true });
626
+ if (!page.isClosed()) {
627
+ await page.close();
628
+ }
629
+ await serviceWorker.evaluate(async () => {
630
+ await globalThis.disconnectEverything();
631
+ });
632
+ }
633
+ }, 120000);
634
+ it('should maintain correct page.url() with service worker pages', async () => {
635
+ const browserContext = getBrowserContext();
636
+ const serviceWorker = await getExtensionServiceWorker(browserContext);
637
+ const page = await browserContext.newPage();
638
+ const targetUrl = 'https://example.com/sw-test';
639
+ await page.goto(targetUrl);
640
+ await page.bringToFront();
641
+ await serviceWorker.evaluate(async () => {
642
+ await globalThis.toggleExtensionForActiveTab();
643
+ });
644
+ await new Promise((r) => setTimeout(r, 100));
645
+ const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }));
646
+ const cdpPages = browser.contexts()[0].pages();
647
+ const testPage = cdpPages.find((p) => p.url().includes('sw-test'));
648
+ expect(testPage).toBeDefined();
649
+ expect(testPage?.url()).toContain('sw-test');
650
+ expect(testPage?.url()).not.toContain('sw.js');
651
+ await browser.close();
652
+ await page.close();
653
+ }, 30000);
654
+ it('should maintain correct page.url() after repeated connections', async () => {
655
+ const browserContext = getBrowserContext();
656
+ const serviceWorker = await getExtensionServiceWorker(browserContext);
657
+ const page = await browserContext.newPage();
658
+ const targetUrl = 'https://example.com/repeated-test';
659
+ await page.goto(targetUrl);
660
+ await page.bringToFront();
661
+ await serviceWorker.evaluate(async () => {
662
+ await globalThis.toggleExtensionForActiveTab();
663
+ });
664
+ for (let i = 0; i < 5; i++) {
665
+ const browser = await chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT }));
666
+ const cdpPages = browser.contexts()[0].pages();
667
+ const testPage = cdpPages.find((p) => p.url().includes('repeated-test'));
668
+ expect(testPage).toBeDefined();
669
+ expect(testPage?.url()).toBe(targetUrl);
670
+ await browser.close();
671
+ await new Promise((r) => setTimeout(r, 100));
672
+ }
673
+ await page.close();
674
+ }, 30000);
675
+ it('should maintain correct page.url() with concurrent MCP and CDP connections', async () => {
676
+ const browserContext = getBrowserContext();
677
+ const serviceWorker = await getExtensionServiceWorker(browserContext);
678
+ const page = await browserContext.newPage();
679
+ const targetUrl = 'https://example.com/concurrent-test';
680
+ await page.goto(targetUrl);
681
+ await page.bringToFront();
682
+ await serviceWorker.evaluate(async () => {
683
+ await globalThis.toggleExtensionForActiveTab();
684
+ });
685
+ await new Promise((r) => setTimeout(r, 400));
686
+ const [mcpResult, cdpBrowser] = await Promise.all([
687
+ client.callTool({
688
+ name: 'execute',
689
+ arguments: {
690
+ code: js `
691
+ const pages = context.pages();
692
+ const testPage = pages.find(p => p.url().includes('concurrent-test'));
693
+ return { url: testPage?.url(), found: !!testPage };
694
+ `,
695
+ },
696
+ }),
697
+ chromium.connectOverCDP(getCdpUrl({ port: TEST_PORT })),
698
+ ]);
699
+ const mcpOutput = mcpResult.content[0].text;
700
+ expect(mcpOutput).toContain(targetUrl);
701
+ const cdpPages = cdpBrowser.contexts()[0].pages();
702
+ const cdpPage = cdpPages.find((p) => p.url().includes('concurrent-test'));
703
+ expect(cdpPage?.url()).toBe(targetUrl);
704
+ await cdpBrowser.close();
705
+ await page.close();
706
+ }, 30000);
707
+ });
708
+ //# sourceMappingURL=extension-connection.test.js.map