tabwright 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (568) hide show
  1. package/dist/agent-skills/tabwright/SKILL.md +3 -0
  2. package/dist/aria-snapshot.d.ts +0 -1
  3. package/dist/aria-snapshot.js +9 -1
  4. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts +0 -1
  5. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js +0 -1
  6. package/dist/bippy.js +5 -5
  7. package/dist/browser-config.d.ts +0 -1
  8. package/dist/browser-config.js +0 -1
  9. package/dist/browser-install.d.ts +0 -1
  10. package/dist/browser-install.js +0 -1
  11. package/dist/browser-launch.d.ts +0 -1
  12. package/dist/browser-launch.js +0 -1
  13. package/dist/capability-agent-skill.d.ts +0 -1
  14. package/dist/capability-agent-skill.js +0 -1
  15. package/dist/capability-auth-state.d.ts +0 -1
  16. package/dist/capability-auth-state.js +0 -1
  17. package/dist/capability-auth.d.ts +0 -1
  18. package/dist/capability-auth.js +0 -1
  19. package/dist/capability-options.d.ts +0 -1
  20. package/dist/capability-options.js +0 -1
  21. package/dist/capability-package.d.ts +0 -1
  22. package/dist/capability-package.js +47 -2
  23. package/dist/capability-registry.d.ts +0 -1
  24. package/dist/capability-registry.js +0 -1
  25. package/dist/capability-runner.d.ts +0 -1
  26. package/dist/capability-runner.js +0 -1
  27. package/dist/capability-studio.d.ts +0 -1
  28. package/dist/capability-studio.js +0 -1
  29. package/dist/cdp-log.d.ts +0 -1
  30. package/dist/cdp-log.js +0 -1
  31. package/dist/cdp-relay.d.ts +0 -1
  32. package/dist/cdp-relay.js +0 -1
  33. package/dist/cdp-session.d.ts +0 -1
  34. package/dist/cdp-session.js +0 -1
  35. package/dist/cdp-types.d.ts +0 -1
  36. package/dist/cdp-types.js +0 -1
  37. package/dist/chrome-discovery.d.ts +0 -1
  38. package/dist/chrome-discovery.js +0 -1
  39. package/dist/clean-html.d.ts +0 -1
  40. package/dist/clean-html.js +0 -1
  41. package/dist/cli.d.ts +0 -1
  42. package/dist/cli.js +10 -56
  43. package/dist/cloud-client.d.ts +0 -1
  44. package/dist/cloud-client.js +0 -1
  45. package/dist/create-logger.d.ts +0 -1
  46. package/dist/create-logger.js +0 -1
  47. package/dist/debugger-examples-types.d.ts +0 -1
  48. package/dist/debugger-examples-types.js +0 -1
  49. package/dist/debugger-examples.d.ts +0 -1
  50. package/dist/debugger-examples.js +0 -1
  51. package/dist/debugger.d.ts +0 -1
  52. package/dist/debugger.js +0 -1
  53. package/dist/diff-utils.d.ts +0 -1
  54. package/dist/diff-utils.js +0 -1
  55. package/dist/doctor.d.ts +0 -1
  56. package/dist/doctor.js +5 -7
  57. package/dist/editor-examples.d.ts +0 -1
  58. package/dist/editor-examples.js +0 -1
  59. package/dist/editor.d.ts +0 -1
  60. package/dist/editor.js +0 -1
  61. package/dist/env-compat.d.ts +0 -1
  62. package/dist/env-compat.js +0 -1
  63. package/dist/executor.d.ts +0 -1
  64. package/dist/executor.js +1 -2
  65. package/dist/extension/background.js +10 -6
  66. package/dist/extension/manifest.json +1 -1
  67. package/dist/extension/options.js +1 -1
  68. package/dist/extension/rrweb-recorder.js +1 -1
  69. package/dist/ghost-browser.d.ts +0 -1
  70. package/dist/ghost-browser.js +0 -1
  71. package/dist/ghost-cursor-controller.d.ts +0 -1
  72. package/dist/ghost-cursor-controller.js +0 -1
  73. package/dist/ghost-cursor.d.ts +0 -1
  74. package/dist/ghost-cursor.js +0 -1
  75. package/dist/htmlrewrite.d.ts +0 -1
  76. package/dist/htmlrewrite.js +0 -1
  77. package/dist/index.d.ts +0 -1
  78. package/dist/index.js +0 -1
  79. package/dist/kill-port.d.ts +0 -1
  80. package/dist/kill-port.js +0 -1
  81. package/dist/kitty-graphics.d.ts +0 -1
  82. package/dist/kitty-graphics.js +0 -1
  83. package/dist/mcp.d.ts +0 -1
  84. package/dist/mcp.js +0 -1
  85. package/dist/package-paths.d.ts +0 -1
  86. package/dist/package-paths.js +0 -1
  87. package/dist/page-markdown.d.ts +0 -1
  88. package/dist/page-markdown.js +0 -1
  89. package/dist/performance-examples.d.ts +0 -1
  90. package/dist/performance-examples.js +0 -1
  91. package/dist/playwright-import.d.ts +0 -1
  92. package/dist/playwright-import.js +0 -1
  93. package/dist/product-paths.d.ts +0 -1
  94. package/dist/product-paths.js +0 -1
  95. package/dist/protocol.d.ts +0 -1
  96. package/dist/protocol.js +0 -1
  97. package/dist/react-source.d.ts +0 -1
  98. package/dist/react-source.js +0 -1
  99. package/dist/readability.js +4 -4
  100. package/dist/relay-client.d.ts +0 -1
  101. package/dist/relay-client.js +0 -1
  102. package/dist/relay-state.d.ts +0 -1
  103. package/dist/relay-state.js +0 -1
  104. package/dist/replay-ai-index.d.ts +0 -1
  105. package/dist/replay-ai-index.js +0 -1
  106. package/dist/replay-eval.d.ts +0 -1
  107. package/dist/replay-eval.js +0 -1
  108. package/dist/replay-handoff.d.ts +0 -1
  109. package/dist/replay-handoff.js +0 -1
  110. package/dist/replay-workflow-compiler.d.ts +0 -1
  111. package/dist/replay-workflow-compiler.js +0 -1
  112. package/dist/rrweb-recording-relay.d.ts +0 -1
  113. package/dist/rrweb-recording-relay.js +0 -1
  114. package/dist/rrweb-recording.d.ts +0 -1
  115. package/dist/rrweb-recording.js +0 -1
  116. package/dist/scoped-fs.d.ts +0 -1
  117. package/dist/scoped-fs.js +0 -1
  118. package/dist/selector-generator.js +2 -2
  119. package/dist/start-relay-server.d.ts +0 -1
  120. package/dist/start-relay-server.js +0 -1
  121. package/dist/styles-examples.d.ts +0 -1
  122. package/dist/styles-examples.js +0 -1
  123. package/dist/styles.d.ts +0 -1
  124. package/dist/styles.js +0 -1
  125. package/dist/tabwright-agent-skill.d.ts +0 -1
  126. package/dist/tabwright-agent-skill.js +0 -1
  127. package/dist/test-declarations.d.ts +0 -1
  128. package/dist/test-declarations.js +0 -1
  129. package/dist/utils.d.ts +0 -1
  130. package/dist/utils.js +2 -2
  131. package/dist/wait-for-page-load.d.ts +0 -1
  132. package/dist/wait-for-page-load.js +0 -1
  133. package/dist/workflow-capability.d.ts +0 -1
  134. package/dist/workflow-capability.js +0 -1
  135. package/package.json +8 -4
  136. package/readme.md +43 -0
  137. package/src/skill.md +5 -2
  138. package/dist/aria-snapshot.d.ts.map +0 -1
  139. package/dist/aria-snapshot.js.map +0 -1
  140. package/dist/aria-snapshot.test.d.ts +0 -2
  141. package/dist/aria-snapshot.test.d.ts.map +0 -1
  142. package/dist/aria-snapshot.test.js +0 -270
  143. package/dist/aria-snapshot.test.js.map +0 -1
  144. package/dist/aria-snapshot.unit.test.d.ts +0 -2
  145. package/dist/aria-snapshot.unit.test.d.ts.map +0 -1
  146. package/dist/aria-snapshot.unit.test.js +0 -542
  147. package/dist/aria-snapshot.unit.test.js.map +0 -1
  148. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts.map +0 -1
  149. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js.map +0 -1
  150. package/dist/browser-config.d.ts.map +0 -1
  151. package/dist/browser-config.js.map +0 -1
  152. package/dist/browser-install.d.ts.map +0 -1
  153. package/dist/browser-install.js.map +0 -1
  154. package/dist/browser-launch.d.ts.map +0 -1
  155. package/dist/browser-launch.js.map +0 -1
  156. package/dist/builtin-capabilities.d.ts +0 -28
  157. package/dist/builtin-capabilities.d.ts.map +0 -1
  158. package/dist/builtin-capabilities.js +0 -2673
  159. package/dist/builtin-capabilities.js.map +0 -1
  160. package/dist/capability-agent-skill.d.ts.map +0 -1
  161. package/dist/capability-agent-skill.js.map +0 -1
  162. package/dist/capability-auth-state.d.ts.map +0 -1
  163. package/dist/capability-auth-state.js.map +0 -1
  164. package/dist/capability-auth.d.ts.map +0 -1
  165. package/dist/capability-auth.js.map +0 -1
  166. package/dist/capability-cli-confirmation.test.d.ts +0 -2
  167. package/dist/capability-cli-confirmation.test.d.ts.map +0 -1
  168. package/dist/capability-cli-confirmation.test.js +0 -79
  169. package/dist/capability-cli-confirmation.test.js.map +0 -1
  170. package/dist/capability-options.d.ts.map +0 -1
  171. package/dist/capability-options.js.map +0 -1
  172. package/dist/capability-options.test.d.ts +0 -2
  173. package/dist/capability-options.test.d.ts.map +0 -1
  174. package/dist/capability-options.test.js +0 -81
  175. package/dist/capability-options.test.js.map +0 -1
  176. package/dist/capability-package.d.ts.map +0 -1
  177. package/dist/capability-package.js.map +0 -1
  178. package/dist/capability-package.test.d.ts +0 -2
  179. package/dist/capability-package.test.d.ts.map +0 -1
  180. package/dist/capability-package.test.js +0 -179
  181. package/dist/capability-package.test.js.map +0 -1
  182. package/dist/capability-registry.d.ts.map +0 -1
  183. package/dist/capability-registry.js.map +0 -1
  184. package/dist/capability-registry.test.d.ts +0 -2
  185. package/dist/capability-registry.test.d.ts.map +0 -1
  186. package/dist/capability-registry.test.js +0 -1683
  187. package/dist/capability-registry.test.js.map +0 -1
  188. package/dist/capability-runner.d.ts.map +0 -1
  189. package/dist/capability-runner.js.map +0 -1
  190. package/dist/capability-search-relevance.test.d.ts +0 -2
  191. package/dist/capability-search-relevance.test.d.ts.map +0 -1
  192. package/dist/capability-search-relevance.test.js +0 -67
  193. package/dist/capability-search-relevance.test.js.map +0 -1
  194. package/dist/capability-studio.d.ts.map +0 -1
  195. package/dist/capability-studio.js.map +0 -1
  196. package/dist/capability-studio.test.d.ts +0 -2
  197. package/dist/capability-studio.test.d.ts.map +0 -1
  198. package/dist/capability-studio.test.js +0 -41
  199. package/dist/capability-studio.test.js.map +0 -1
  200. package/dist/cdp-log.d.ts.map +0 -1
  201. package/dist/cdp-log.js.map +0 -1
  202. package/dist/cdp-log.test.d.ts +0 -2
  203. package/dist/cdp-log.test.d.ts.map +0 -1
  204. package/dist/cdp-log.test.js +0 -109
  205. package/dist/cdp-log.test.js.map +0 -1
  206. package/dist/cdp-relay.d.ts.map +0 -1
  207. package/dist/cdp-relay.js.map +0 -1
  208. package/dist/cdp-session.d.ts.map +0 -1
  209. package/dist/cdp-session.js.map +0 -1
  210. package/dist/cdp-types.d.ts.map +0 -1
  211. package/dist/cdp-types.js.map +0 -1
  212. package/dist/channel-owner-inspect.test.d.ts +0 -2
  213. package/dist/channel-owner-inspect.test.d.ts.map +0 -1
  214. package/dist/channel-owner-inspect.test.js +0 -75
  215. package/dist/channel-owner-inspect.test.js.map +0 -1
  216. package/dist/chrome-discovery.d.ts.map +0 -1
  217. package/dist/chrome-discovery.js.map +0 -1
  218. package/dist/chrome-discovery.test.d.ts +0 -2
  219. package/dist/chrome-discovery.test.d.ts.map +0 -1
  220. package/dist/chrome-discovery.test.js +0 -41
  221. package/dist/chrome-discovery.test.js.map +0 -1
  222. package/dist/clean-html.d.ts.map +0 -1
  223. package/dist/clean-html.js.map +0 -1
  224. package/dist/cli-help.test.d.ts +0 -2
  225. package/dist/cli-help.test.d.ts.map +0 -1
  226. package/dist/cli-help.test.js +0 -98
  227. package/dist/cli-help.test.js.map +0 -1
  228. package/dist/cli.d.ts.map +0 -1
  229. package/dist/cli.js.map +0 -1
  230. package/dist/cloud-client.d.ts.map +0 -1
  231. package/dist/cloud-client.js.map +0 -1
  232. package/dist/create-logger.d.ts.map +0 -1
  233. package/dist/create-logger.js.map +0 -1
  234. package/dist/debugger-examples-types.d.ts.map +0 -1
  235. package/dist/debugger-examples-types.js.map +0 -1
  236. package/dist/debugger-examples.d.ts.map +0 -1
  237. package/dist/debugger-examples.js.map +0 -1
  238. package/dist/debugger.d.ts.map +0 -1
  239. package/dist/debugger.js.map +0 -1
  240. package/dist/diff-utils.d.ts.map +0 -1
  241. package/dist/diff-utils.js.map +0 -1
  242. package/dist/diff-utils.test.d.ts +0 -2
  243. package/dist/diff-utils.test.d.ts.map +0 -1
  244. package/dist/diff-utils.test.js +0 -137
  245. package/dist/diff-utils.test.js.map +0 -1
  246. package/dist/doctor.d.ts.map +0 -1
  247. package/dist/doctor.js.map +0 -1
  248. package/dist/doctor.test.d.ts +0 -2
  249. package/dist/doctor.test.d.ts.map +0 -1
  250. package/dist/doctor.test.js +0 -208
  251. package/dist/doctor.test.js.map +0 -1
  252. package/dist/editor-examples.d.ts.map +0 -1
  253. package/dist/editor-examples.js.map +0 -1
  254. package/dist/editor.d.ts.map +0 -1
  255. package/dist/editor.js.map +0 -1
  256. package/dist/env-compat.d.ts.map +0 -1
  257. package/dist/env-compat.js.map +0 -1
  258. package/dist/executor.d.ts.map +0 -1
  259. package/dist/executor.js.map +0 -1
  260. package/dist/executor.unit.test.d.ts +0 -2
  261. package/dist/executor.unit.test.d.ts.map +0 -1
  262. package/dist/executor.unit.test.js +0 -143
  263. package/dist/executor.unit.test.js.map +0 -1
  264. package/dist/extension-connection.test.d.ts +0 -2
  265. package/dist/extension-connection.test.d.ts.map +0 -1
  266. package/dist/extension-connection.test.js +0 -708
  267. package/dist/extension-connection.test.js.map +0 -1
  268. package/dist/extension-icon-warning.test.d.ts +0 -2
  269. package/dist/extension-icon-warning.test.d.ts.map +0 -1
  270. package/dist/extension-icon-warning.test.js +0 -33
  271. package/dist/extension-icon-warning.test.js.map +0 -1
  272. package/dist/ghost-browser.d.ts.map +0 -1
  273. package/dist/ghost-browser.js.map +0 -1
  274. package/dist/ghost-cursor-controller.d.ts.map +0 -1
  275. package/dist/ghost-cursor-controller.js.map +0 -1
  276. package/dist/ghost-cursor.d.ts.map +0 -1
  277. package/dist/ghost-cursor.js.map +0 -1
  278. package/dist/htmlrewrite.d.ts.map +0 -1
  279. package/dist/htmlrewrite.js.map +0 -1
  280. package/dist/htmlrewrite.test.d.ts +0 -2
  281. package/dist/htmlrewrite.test.d.ts.map +0 -1
  282. package/dist/htmlrewrite.test.js +0 -7975
  283. package/dist/htmlrewrite.test.js.map +0 -1
  284. package/dist/index.d.ts.map +0 -1
  285. package/dist/index.js.map +0 -1
  286. package/dist/kill-port.d.ts.map +0 -1
  287. package/dist/kill-port.js.map +0 -1
  288. package/dist/kitty-graphics.d.ts.map +0 -1
  289. package/dist/kitty-graphics.js.map +0 -1
  290. package/dist/kitty-graphics.test.d.ts +0 -2
  291. package/dist/kitty-graphics.test.d.ts.map +0 -1
  292. package/dist/kitty-graphics.test.js +0 -125
  293. package/dist/kitty-graphics.test.js.map +0 -1
  294. package/dist/locator-selector.test.d.ts +0 -2
  295. package/dist/locator-selector.test.d.ts.map +0 -1
  296. package/dist/locator-selector.test.js +0 -98
  297. package/dist/locator-selector.test.js.map +0 -1
  298. package/dist/mcp-client.d.ts +0 -20
  299. package/dist/mcp-client.d.ts.map +0 -1
  300. package/dist/mcp-client.js +0 -56
  301. package/dist/mcp-client.js.map +0 -1
  302. package/dist/mcp.d.ts.map +0 -1
  303. package/dist/mcp.js.map +0 -1
  304. package/dist/on-mouse-action.test.d.ts +0 -2
  305. package/dist/on-mouse-action.test.d.ts.map +0 -1
  306. package/dist/on-mouse-action.test.js +0 -180
  307. package/dist/on-mouse-action.test.js.map +0 -1
  308. package/dist/options-page.test.d.ts +0 -2
  309. package/dist/options-page.test.d.ts.map +0 -1
  310. package/dist/options-page.test.js +0 -773
  311. package/dist/options-page.test.js.map +0 -1
  312. package/dist/package-paths.d.ts.map +0 -1
  313. package/dist/package-paths.js.map +0 -1
  314. package/dist/page-markdown.d.ts.map +0 -1
  315. package/dist/page-markdown.js.map +0 -1
  316. package/dist/performance-examples.d.ts.map +0 -1
  317. package/dist/performance-examples.js.map +0 -1
  318. package/dist/playwright-import.d.ts.map +0 -1
  319. package/dist/playwright-import.js.map +0 -1
  320. package/dist/popup-relocation.test.d.ts +0 -7
  321. package/dist/popup-relocation.test.d.ts.map +0 -1
  322. package/dist/popup-relocation.test.js +0 -139
  323. package/dist/popup-relocation.test.js.map +0 -1
  324. package/dist/product-paths.d.ts.map +0 -1
  325. package/dist/product-paths.js.map +0 -1
  326. package/dist/product-paths.test.d.ts +0 -2
  327. package/dist/product-paths.test.d.ts.map +0 -1
  328. package/dist/product-paths.test.js +0 -39
  329. package/dist/product-paths.test.js.map +0 -1
  330. package/dist/protocol.d.ts.map +0 -1
  331. package/dist/protocol.js.map +0 -1
  332. package/dist/protocol.test.d.ts +0 -2
  333. package/dist/protocol.test.d.ts.map +0 -1
  334. package/dist/protocol.test.js +0 -31
  335. package/dist/protocol.test.js.map +0 -1
  336. package/dist/react-source.d.ts.map +0 -1
  337. package/dist/react-source.js.map +0 -1
  338. package/dist/relay-client.d.ts.map +0 -1
  339. package/dist/relay-client.js.map +0 -1
  340. package/dist/relay-client.test.d.ts +0 -2
  341. package/dist/relay-client.test.d.ts.map +0 -1
  342. package/dist/relay-client.test.js +0 -305
  343. package/dist/relay-client.test.js.map +0 -1
  344. package/dist/relay-core.test.d.ts +0 -2
  345. package/dist/relay-core.test.d.ts.map +0 -1
  346. package/dist/relay-core.test.js +0 -1427
  347. package/dist/relay-core.test.js.map +0 -1
  348. package/dist/relay-navigation.test.d.ts +0 -2
  349. package/dist/relay-navigation.test.d.ts.map +0 -1
  350. package/dist/relay-navigation.test.js +0 -661
  351. package/dist/relay-navigation.test.js.map +0 -1
  352. package/dist/relay-session.test.d.ts +0 -2
  353. package/dist/relay-session.test.d.ts.map +0 -1
  354. package/dist/relay-session.test.js +0 -1121
  355. package/dist/relay-session.test.js.map +0 -1
  356. package/dist/relay-state.d.ts.map +0 -1
  357. package/dist/relay-state.js.map +0 -1
  358. package/dist/relay-state.test.d.ts +0 -2
  359. package/dist/relay-state.test.d.ts.map +0 -1
  360. package/dist/relay-state.test.js +0 -594
  361. package/dist/relay-state.test.js.map +0 -1
  362. package/dist/replay-ai-index.d.ts.map +0 -1
  363. package/dist/replay-ai-index.js.map +0 -1
  364. package/dist/replay-ai-index.test.d.ts +0 -2
  365. package/dist/replay-ai-index.test.d.ts.map +0 -1
  366. package/dist/replay-ai-index.test.js +0 -255
  367. package/dist/replay-ai-index.test.js.map +0 -1
  368. package/dist/replay-cli.test.d.ts +0 -2
  369. package/dist/replay-cli.test.d.ts.map +0 -1
  370. package/dist/replay-cli.test.js +0 -275
  371. package/dist/replay-cli.test.js.map +0 -1
  372. package/dist/replay-eval.d.ts.map +0 -1
  373. package/dist/replay-eval.js.map +0 -1
  374. package/dist/replay-handoff.d.ts.map +0 -1
  375. package/dist/replay-handoff.js.map +0 -1
  376. package/dist/replay-handoff.test.d.ts +0 -2
  377. package/dist/replay-handoff.test.d.ts.map +0 -1
  378. package/dist/replay-handoff.test.js +0 -123
  379. package/dist/replay-handoff.test.js.map +0 -1
  380. package/dist/replay-workflow-compiler.d.ts.map +0 -1
  381. package/dist/replay-workflow-compiler.js.map +0 -1
  382. package/dist/replay-workflow-compiler.test.d.ts +0 -2
  383. package/dist/replay-workflow-compiler.test.d.ts.map +0 -1
  384. package/dist/replay-workflow-compiler.test.js +0 -223
  385. package/dist/replay-workflow-compiler.test.js.map +0 -1
  386. package/dist/rrweb-recording-relay.d.ts.map +0 -1
  387. package/dist/rrweb-recording-relay.js.map +0 -1
  388. package/dist/rrweb-recording-relay.test.d.ts +0 -2
  389. package/dist/rrweb-recording-relay.test.d.ts.map +0 -1
  390. package/dist/rrweb-recording-relay.test.js +0 -85
  391. package/dist/rrweb-recording-relay.test.js.map +0 -1
  392. package/dist/rrweb-recording.d.ts.map +0 -1
  393. package/dist/rrweb-recording.js.map +0 -1
  394. package/dist/scoped-fs.d.ts.map +0 -1
  395. package/dist/scoped-fs.js.map +0 -1
  396. package/dist/scoped-fs.test.d.ts +0 -5
  397. package/dist/scoped-fs.test.d.ts.map +0 -1
  398. package/dist/scoped-fs.test.js +0 -73
  399. package/dist/scoped-fs.test.js.map +0 -1
  400. package/dist/skill-stub.test.d.ts +0 -2
  401. package/dist/skill-stub.test.d.ts.map +0 -1
  402. package/dist/skill-stub.test.js +0 -22
  403. package/dist/skill-stub.test.js.map +0 -1
  404. package/dist/snapshot-tools.test.d.ts +0 -2
  405. package/dist/snapshot-tools.test.d.ts.map +0 -1
  406. package/dist/snapshot-tools.test.js +0 -856
  407. package/dist/snapshot-tools.test.js.map +0 -1
  408. package/dist/start-relay-server.d.ts.map +0 -1
  409. package/dist/start-relay-server.js.map +0 -1
  410. package/dist/styles-examples.d.ts.map +0 -1
  411. package/dist/styles-examples.js.map +0 -1
  412. package/dist/styles.d.ts.map +0 -1
  413. package/dist/styles.js.map +0 -1
  414. package/dist/tabwright-agent-skill.d.ts.map +0 -1
  415. package/dist/tabwright-agent-skill.js.map +0 -1
  416. package/dist/tabwright-agent-skill.test.d.ts +0 -2
  417. package/dist/tabwright-agent-skill.test.d.ts.map +0 -1
  418. package/dist/tabwright-agent-skill.test.js +0 -51
  419. package/dist/tabwright-agent-skill.test.js.map +0 -1
  420. package/dist/test-declarations.d.ts.map +0 -1
  421. package/dist/test-declarations.js.map +0 -1
  422. package/dist/test-utils.d.ts +0 -69
  423. package/dist/test-utils.d.ts.map +0 -1
  424. package/dist/test-utils.js +0 -448
  425. package/dist/test-utils.js.map +0 -1
  426. package/dist/test-utils.test.d.ts +0 -2
  427. package/dist/test-utils.test.d.ts.map +0 -1
  428. package/dist/test-utils.test.js +0 -55
  429. package/dist/test-utils.test.js.map +0 -1
  430. package/dist/utils.d.ts.map +0 -1
  431. package/dist/utils.js.map +0 -1
  432. package/dist/wait-for-page-load.d.ts.map +0 -1
  433. package/dist/wait-for-page-load.js.map +0 -1
  434. package/dist/workflow-capability.d.ts.map +0 -1
  435. package/dist/workflow-capability.js.map +0 -1
  436. package/dist/workflow-script-flow.test.d.ts +0 -2
  437. package/dist/workflow-script-flow.test.d.ts.map +0 -1
  438. package/dist/workflow-script-flow.test.js +0 -285
  439. package/dist/workflow-script-flow.test.js.map +0 -1
  440. package/src/__snapshots__/x.com.processed.html +0 -1003
  441. package/src/__snapshots__/x.com.processed.withStyles.html +0 -2720
  442. package/src/a11y-client.ts +0 -241
  443. package/src/agent-skills/conan-config/SKILL.md +0 -141
  444. package/src/agent-skills/conan-config/agents/openai.yaml +0 -4
  445. package/src/aria-snapshot.test.ts +0 -311
  446. package/src/aria-snapshot.ts +0 -1681
  447. package/src/aria-snapshot.unit.test.ts +0 -615
  448. package/src/aria-snapshots/github-interactive.txt +0 -193
  449. package/src/aria-snapshots/github-raw.txt +0 -309
  450. package/src/aria-snapshots/hackernews-interactive.txt +0 -477
  451. package/src/aria-snapshots/hackernews-raw.txt +0 -428
  452. package/src/aria-snapshots/prosemirror-interactive.txt +0 -66
  453. package/src/aria-snapshots/prosemirror-raw.txt +0 -145
  454. package/src/assets/aria-labels-hacker-news.png +0 -0
  455. package/src/assets/aria-labels-old-reddit.png +0 -0
  456. package/src/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.ts +0 -5
  457. package/src/assets/cursors/screen-studio/pointer-macos-tahoe.svg +0 -18
  458. package/src/assets/x.com.html +0 -32946
  459. package/src/browser-config.ts +0 -179
  460. package/src/browser-install.ts +0 -284
  461. package/src/browser-launch.ts +0 -75
  462. package/src/builtin-capabilities.ts +0 -2765
  463. package/src/capability-agent-skill.ts +0 -305
  464. package/src/capability-auth-state.ts +0 -197
  465. package/src/capability-auth.ts +0 -249
  466. package/src/capability-cli-confirmation.test.ts +0 -90
  467. package/src/capability-options.test.ts +0 -89
  468. package/src/capability-options.ts +0 -57
  469. package/src/capability-package.test.ts +0 -204
  470. package/src/capability-package.ts +0 -555
  471. package/src/capability-registry.test.ts +0 -1905
  472. package/src/capability-registry.ts +0 -1234
  473. package/src/capability-runner.ts +0 -801
  474. package/src/capability-search-relevance.test.ts +0 -73
  475. package/src/capability-studio.test.ts +0 -45
  476. package/src/capability-studio.ts +0 -641
  477. package/src/cdp-log.test.ts +0 -131
  478. package/src/cdp-log.ts +0 -112
  479. package/src/cdp-relay.ts +0 -2944
  480. package/src/cdp-session.ts +0 -77
  481. package/src/cdp-types.ts +0 -158
  482. package/src/channel-owner-inspect.test.ts +0 -94
  483. package/src/chrome-discovery.test.ts +0 -50
  484. package/src/chrome-discovery.ts +0 -220
  485. package/src/clean-html.ts +0 -141
  486. package/src/cli-help.test.ts +0 -123
  487. package/src/cli.ts +0 -3181
  488. package/src/cloud-client.ts +0 -179
  489. package/src/create-logger.ts +0 -38
  490. package/src/debugger-examples-types.ts +0 -16
  491. package/src/debugger-examples.ts +0 -66
  492. package/src/debugger.ts +0 -708
  493. package/src/diff-utils.test.ts +0 -152
  494. package/src/diff-utils.ts +0 -70
  495. package/src/doctor.test.ts +0 -244
  496. package/src/doctor.ts +0 -321
  497. package/src/editor-examples.ts +0 -158
  498. package/src/editor.ts +0 -426
  499. package/src/env-compat.ts +0 -28
  500. package/src/executor.ts +0 -1824
  501. package/src/executor.unit.test.ts +0 -168
  502. package/src/extension-connection.test.ts +0 -855
  503. package/src/extension-icon-warning.test.ts +0 -45
  504. package/src/ghost-browser.ts +0 -149
  505. package/src/ghost-cursor-client.ts +0 -494
  506. package/src/ghost-cursor-controller.ts +0 -129
  507. package/src/ghost-cursor.ts +0 -123
  508. package/src/htmlrewrite.test.ts +0 -8008
  509. package/src/htmlrewrite.ts +0 -390
  510. package/src/index.ts +0 -53
  511. package/src/kill-port.ts +0 -219
  512. package/src/kitty-graphics.test.ts +0 -139
  513. package/src/kitty-graphics.ts +0 -79
  514. package/src/locator-selector.test.ts +0 -119
  515. package/src/mcp-client.ts +0 -78
  516. package/src/mcp.ts +0 -629
  517. package/src/on-mouse-action.test.ts +0 -226
  518. package/src/options-page.test.ts +0 -839
  519. package/src/package-paths.ts +0 -38
  520. package/src/page-markdown.ts +0 -240
  521. package/src/performance-examples.ts +0 -186
  522. package/src/playwright-import.ts +0 -59
  523. package/src/popup-relocation.test.ts +0 -163
  524. package/src/product-paths.test.ts +0 -47
  525. package/src/product-paths.ts +0 -28
  526. package/src/protocol.test.ts +0 -52
  527. package/src/protocol.ts +0 -351
  528. package/src/react-source.ts +0 -379
  529. package/src/relay-client.test.ts +0 -375
  530. package/src/relay-client.ts +0 -572
  531. package/src/relay-core.test.ts +0 -1603
  532. package/src/relay-navigation.test.ts +0 -790
  533. package/src/relay-session.test.ts +0 -1375
  534. package/src/relay-state.test.ts +0 -729
  535. package/src/relay-state.ts +0 -561
  536. package/src/replay-ai-index.test.ts +0 -278
  537. package/src/replay-ai-index.ts +0 -872
  538. package/src/replay-cli.test.ts +0 -325
  539. package/src/replay-eval.ts +0 -1039
  540. package/src/replay-handoff.test.ts +0 -163
  541. package/src/replay-handoff.ts +0 -109
  542. package/src/replay-workflow-compiler.test.ts +0 -250
  543. package/src/replay-workflow-compiler.ts +0 -700
  544. package/src/resource.md +0 -409
  545. package/src/rrweb-recording-relay.test.ts +0 -99
  546. package/src/rrweb-recording-relay.ts +0 -400
  547. package/src/rrweb-recording.ts +0 -322
  548. package/src/scoped-fs.test.ts +0 -80
  549. package/src/scoped-fs.ts +0 -420
  550. package/src/skill-stub.test.ts +0 -24
  551. package/src/snapshot-tools.test.ts +0 -1017
  552. package/src/snapshots/hacker-news-accessibility-full.md +0 -81
  553. package/src/snapshots/hacker-news-accessibility-interactive.md +0 -43
  554. package/src/snapshots/page-markdown-output.txt +0 -16
  555. package/src/snapshots/shadcn-ui-accessibility-full.md +0 -201
  556. package/src/snapshots/shadcn-ui-accessibility-interactive.md +0 -109
  557. package/src/start-relay-server.ts +0 -69
  558. package/src/styles-examples.ts +0 -84
  559. package/src/styles.ts +0 -343
  560. package/src/tabwright-agent-skill.test.ts +0 -61
  561. package/src/tabwright-agent-skill.ts +0 -105
  562. package/src/test-declarations.ts +0 -13
  563. package/src/test-utils.test.ts +0 -70
  564. package/src/test-utils.ts +0 -566
  565. package/src/utils.ts +0 -78
  566. package/src/wait-for-page-load.ts +0 -198
  567. package/src/workflow-capability.ts +0 -417
  568. package/src/workflow-script-flow.test.ts +0 -388
@@ -1,390 +0,0 @@
1
- import posthtml from 'posthtml'
2
- import beautify from 'posthtml-beautify'
3
-
4
- export interface FormatHtmlOptions {
5
- html: string
6
- keepStyles?: boolean
7
- maxAttrLen?: number
8
- maxContentLen?: number
9
- }
10
-
11
- export async function formatHtmlForPrompt({
12
- html,
13
- keepStyles = false,
14
- maxAttrLen = 200,
15
- maxContentLen = 500,
16
- }: FormatHtmlOptions) {
17
- const tagsToRemove = ['hint', 'style', 'link', 'script', 'meta', 'noscript', 'svg', 'head']
18
-
19
- const attributesToKeep = [
20
- // Standard descriptive attributes
21
- 'label',
22
- 'title',
23
- 'alt',
24
- 'href',
25
- 'name',
26
- 'value',
27
- 'checked',
28
- 'placeholder',
29
- 'type',
30
- 'role',
31
- 'target',
32
- // Descriptive aria attributes (text content)
33
- 'aria-label',
34
- 'aria-placeholder',
35
- 'aria-valuetext',
36
- 'aria-roledescription',
37
- // Useful aria state attributes
38
- 'aria-hidden',
39
- 'aria-expanded',
40
- 'aria-checked',
41
- 'aria-selected',
42
- 'aria-disabled',
43
- 'aria-pressed',
44
- 'aria-required',
45
- 'aria-current',
46
- // Test IDs (data-testid, data-test, data-cy, data-qa are covered by data-* prefix)
47
- 'testid',
48
- 'test-id',
49
- 'tid',
50
- 'qa',
51
- 'qa-id',
52
- 'e2e',
53
- 'e2e-id',
54
- 'automation-id',
55
- 'automationid',
56
- 'selenium',
57
- 'pw',
58
- 'vimium-label',
59
- // Conditionally added: 'style', 'class'
60
- ]
61
-
62
- if (keepStyles) {
63
- attributesToKeep.push('style', 'class')
64
- }
65
-
66
- const truncate = (str: string, maxLen: number): string => {
67
- if (str.length <= maxLen) return str
68
- const remaining = str.length - maxLen
69
- return str.slice(0, maxLen) + `...${remaining} more characters`
70
- }
71
-
72
- // Create a custom plugin to remove tags and filter attributes
73
- const removeTagsAndAttrsPlugin = () => {
74
- return (tree) => {
75
- // Remove comments at root level
76
- tree = tree.filter((item) => {
77
- if (typeof item === 'string') {
78
- const trimmed = item.trim()
79
- return !(trimmed.startsWith('<!--') && trimmed.endsWith('-->'))
80
- }
81
- return true
82
- })
83
-
84
- // Process each node recursively
85
- const processNode = (node) => {
86
- if (typeof node === 'string') {
87
- // Truncate text content
88
- const trimmed = node.trim()
89
- if (trimmed.length === 0) return node
90
- return truncate(node, maxContentLen)
91
- }
92
-
93
- // Remove unwanted tags
94
- if (node.tag && tagsToRemove.includes(node.tag.toLowerCase())) {
95
- return null
96
- }
97
-
98
- // Filter attributes
99
- if (node.attrs) {
100
- const newAttrs: typeof node.attrs = {}
101
- for (const [attr, value] of Object.entries(node.attrs)) {
102
- const shouldKeep = attr.startsWith('data-') || attributesToKeep.includes(attr)
103
-
104
- if (shouldKeep) {
105
- // Truncate attribute values
106
- newAttrs[attr] = typeof value === 'string' ? truncate(value, maxAttrLen) : value
107
- }
108
- }
109
- node.attrs = newAttrs
110
- }
111
-
112
- // Process content recursively
113
- if (node.content && Array.isArray(node.content)) {
114
- node.content = node.content.map(processNode).filter((item) => {
115
- if (item === null) return false
116
- if (typeof item === 'string') {
117
- const trimmed = item.trim()
118
- return !(trimmed.startsWith('<!--') && trimmed.endsWith('-->'))
119
- }
120
- return true
121
- })
122
- }
123
-
124
- return node
125
- }
126
-
127
- // Process all root nodes
128
- return tree.map(processNode).filter((item) => item !== null)
129
- }
130
- }
131
-
132
- // Plugin to remove aria-hidden="true" subtrees entirely
133
- // These are hidden from assistive tech and usually decorative
134
- const removeAriaHiddenPlugin = () => {
135
- return (tree) => {
136
- const processNode = (node) => {
137
- if (typeof node === 'string') return node
138
- if (!node.tag) return node
139
-
140
- // Remove if aria-hidden="true"
141
- if (node.attrs?.['aria-hidden'] === 'true') {
142
- return null
143
- }
144
-
145
- // Process children recursively
146
- if (node.content && Array.isArray(node.content)) {
147
- node.content = node.content.map(processNode).filter((item) => item !== null)
148
- }
149
-
150
- return node
151
- }
152
-
153
- return tree.map(processNode).filter((item) => item !== null)
154
- }
155
- }
156
-
157
- // Plugin to remove images with empty alt text (purely decorative)
158
- // Runs before decorative subtree pruning so containers become empty
159
- const removeEmptyAltImagesPlugin = () => {
160
- return (tree) => {
161
- const processNode = (node) => {
162
- if (typeof node === 'string') return node
163
- if (!node.tag) return node
164
-
165
- // Remove img with empty or missing alt
166
- if (node.tag.toLowerCase() === 'img') {
167
- const alt = node.attrs?.alt
168
- if (alt === '' || alt === undefined) {
169
- return null
170
- }
171
- }
172
-
173
- // Process children recursively
174
- if (node.content && Array.isArray(node.content)) {
175
- node.content = node.content.map(processNode).filter((item) => item !== null)
176
- }
177
-
178
- return node
179
- }
180
-
181
- return tree.map(processNode).filter((item) => item !== null)
182
- }
183
- }
184
-
185
- // Plugin to remove decorative subtrees that have no useful content for agents
186
- // A subtree is decorative if it has:
187
- // - No text content (leaf text nodes)
188
- // - No actionable elements with meaningful attributes
189
- const removeDecorativeSubtreesPlugin = () => {
190
- const actionableTags = ['button', 'a', 'input', 'select', 'textarea']
191
- const meaningfulAttrs = ['aria-label', 'title', 'alt', 'value', 'placeholder', 'href', 'name']
192
-
193
- // Form elements are always actionable, keep unconditionally
194
- const formTags = ['input', 'select', 'textarea']
195
-
196
- // Check if a subtree has any useful content
197
- const hasUsefulContent = (node): boolean => {
198
- if (typeof node === 'string') {
199
- return node.trim().length > 0
200
- }
201
- if (!node.tag) return false
202
-
203
- // Form elements are always useful for agents to interact with
204
- if (formTags.includes(node.tag.toLowerCase())) {
205
- return true
206
- }
207
-
208
- // Images with non-empty alt text are useful (descriptive content)
209
- if (node.tag.toLowerCase() === 'img') {
210
- const alt = node.attrs?.alt
211
- if (typeof alt === 'string' && alt.trim().length > 0) {
212
- return true
213
- }
214
- }
215
-
216
- // Check if this is an actionable element with meaningful attributes
217
- if (actionableTags.includes(node.tag.toLowerCase())) {
218
- if (node.attrs) {
219
- for (const attr of meaningfulAttrs) {
220
- const value = node.attrs[attr]
221
- if (typeof value === 'string' && value.trim().length > 0) {
222
- return true
223
- }
224
- }
225
- }
226
- }
227
-
228
- // Check children recursively
229
- if (node.content && Array.isArray(node.content)) {
230
- for (const child of node.content) {
231
- if (hasUsefulContent(child)) {
232
- return true
233
- }
234
- }
235
- }
236
-
237
- return false
238
- }
239
-
240
- return (tree) => {
241
- const processNode = (node) => {
242
- if (typeof node === 'string') return node
243
- if (!node.tag) return node
244
-
245
- // First process children
246
- if (node.content && Array.isArray(node.content)) {
247
- node.content = node.content.map(processNode).filter((item) => item !== null)
248
- }
249
-
250
- // After processing children, check if this subtree is now decorative
251
- // Skip root-level semantic elements (body, main, etc.)
252
- const semanticTags = ['html', 'body', 'main', 'header', 'footer', 'nav', 'section', 'article', 'aside']
253
- if (semanticTags.includes(node.tag.toLowerCase())) {
254
- return node
255
- }
256
-
257
- // If no useful content in this subtree, remove it
258
- if (!hasUsefulContent(node)) {
259
- return null
260
- }
261
-
262
- return node
263
- }
264
-
265
- return tree.map(processNode).filter((item) => item !== null)
266
- }
267
- }
268
-
269
- // Plugin to unwrap unnecessary nested wrapper elements
270
- // e.g., <div><div><div><p>text</p></div></div></div> -> <div><p>text</p></div>
271
- const unwrapNestedWrappersPlugin = () => {
272
- return (tree) => {
273
- const isWhitespaceOnly = (node) => {
274
- return typeof node === 'string' && node.trim().length === 0
275
- }
276
-
277
- const hasNoAttrs = (node) => {
278
- return !node.attrs || Object.keys(node.attrs).length === 0
279
- }
280
-
281
- const unwrapNode = (node) => {
282
- if (typeof node === 'string') return node
283
- if (!node.tag) return node
284
-
285
- // First, recursively process children
286
- if (node.content && Array.isArray(node.content)) {
287
- node.content = node.content.map(unwrapNode)
288
- }
289
-
290
- // Check if this node is an unnecessary wrapper:
291
- // - has no attributes
292
- // - has exactly one non-whitespace child that is an element
293
- if (hasNoAttrs(node) && node.content && Array.isArray(node.content)) {
294
- const nonWhitespaceChildren = node.content.filter((c) => !isWhitespaceOnly(c))
295
-
296
- if (nonWhitespaceChildren.length === 1) {
297
- const onlyChild = nonWhitespaceChildren[0]
298
- // If the only child is also an element (not text), unwrap
299
- if (typeof onlyChild !== 'string' && onlyChild.tag) {
300
- // Replace this node with its child
301
- return onlyChild
302
- }
303
- }
304
- }
305
-
306
- return node
307
- }
308
-
309
- // Apply multiple passes until stable (handles deeply nested wrappers)
310
- let result = tree.map(unwrapNode)
311
- let prevJson = ''
312
- let currJson = JSON.stringify(result)
313
- while (prevJson !== currJson) {
314
- prevJson = currJson
315
- result = result.map(unwrapNode)
316
- currJson = JSON.stringify(result)
317
- }
318
-
319
- return result
320
- }
321
- }
322
-
323
- // Plugin to remove empty elements (no attrs, no content)
324
- // Runs repeatedly until no more empty elements exist
325
- const removeEmptyElementsPlugin = () => {
326
- return (tree) => {
327
- const isEmptyElement = (node) => {
328
- if (typeof node === 'string') return false
329
- if (!node.tag) return false
330
- const hasAttrs = node.attrs && Object.keys(node.attrs).length > 0
331
- const hasContent =
332
- node.content && node.content.some((c) => (typeof c === 'string' ? c.trim().length > 0 : true))
333
- return !hasAttrs && !hasContent
334
- }
335
-
336
- const removeEmpty = (content) => {
337
- if (!content || !Array.isArray(content)) return content
338
-
339
- return content
340
- .map((node) => {
341
- if (typeof node === 'string') return node
342
- if (node.content) {
343
- node.content = removeEmpty(node.content)
344
- }
345
- return node
346
- })
347
- .filter((node) => !isEmptyElement(node))
348
- }
349
-
350
- // Apply multiple passes until stable
351
- let result = removeEmpty(tree)
352
- let prevJson = ''
353
- let currJson = JSON.stringify(result)
354
- while (prevJson !== currJson) {
355
- prevJson = currJson
356
- result = removeEmpty(result)
357
- currJson = JSON.stringify(result)
358
- }
359
-
360
- return result
361
- }
362
- }
363
-
364
- // Process HTML
365
- const processor = posthtml()
366
- .use(removeTagsAndAttrsPlugin())
367
- .use(removeAriaHiddenPlugin())
368
- .use(removeEmptyAltImagesPlugin())
369
- .use(removeDecorativeSubtreesPlugin())
370
- .use(removeEmptyElementsPlugin())
371
- .use(unwrapNestedWrappersPlugin())
372
- .use(
373
- beautify({
374
- rules: {
375
- indent: 1, // 1-space indent
376
- blankLines: false, // no extra blank lines
377
- maxlen: 100000, // effectively never wrap by content length
378
- },
379
- jsBeautifyOptions: {
380
- wrap_line_length: 0, // disable js-beautify wrapping
381
- preserve_newlines: false, // reduce stray newlines
382
- },
383
- }),
384
- )
385
-
386
- // Process with await
387
- const result = await processor.process(html)
388
-
389
- return result.html
390
- }
package/src/index.ts DELETED
@@ -1,53 +0,0 @@
1
- export * from './cdp-relay.js'
2
- export * from './utils.js'
3
- export { getCDPSessionForPage, PlaywrightCDPSessionAdapter } from './cdp-session.js'
4
- export type { ICDPSession } from './cdp-session.js'
5
- export { Editor } from './editor.js'
6
- export type { ReadResult, SearchMatch, EditResult } from './editor.js'
7
- export { Debugger } from './debugger.js'
8
- export type { BreakpointInfo, LocationInfo, EvaluateResult, ScriptInfo } from './debugger.js'
9
- export { getAriaSnapshot, showAriaRefLabels, hideAriaRefLabels } from './aria-snapshot.js'
10
- export type { AriaRef, AriaSnapshotResult } from './aria-snapshot.js'
11
- export {
12
- startReplayRecording,
13
- stopReplayRecording,
14
- isReplayRecording,
15
- cancelReplayRecording,
16
- listReplayRecordings,
17
- getReplayRecordingEvents,
18
- createReplayApi,
19
- } from './rrweb-recording.js'
20
- export type {
21
- StartReplayOptions,
22
- StopReplayOptions,
23
- ReplayState,
24
- SavedReplayRecording,
25
- } from './rrweb-recording.js'
26
- export type { RrwebEvent } from './protocol.js'
27
- export { saveWorkflowCapability, saveWorkflowFromRecording } from './workflow-capability.js'
28
- export type {
29
- RecordingWorkflowFinalRequest,
30
- RecordingWorkflowStep,
31
- SaveWorkflowCapabilityOptions,
32
- SaveWorkflowFromRecordingOptions,
33
- SavedWorkflowCapability,
34
- } from './workflow-capability.js'
35
- export { analyzeReplayWorkflow, compileReplayWorkflow } from './replay-workflow-compiler.js'
36
- export type {
37
- CompiledReplayWorkflow,
38
- CompileReplayWorkflowOptions,
39
- ReplayWorkflowAnalysis,
40
- } from './replay-workflow-compiler.js'
41
- export {
42
- buildReplayAiIndex,
43
- createReplayAiIndexFromRecording,
44
- saveReplayAiIndex,
45
- } from './replay-ai-index.js'
46
- export type {
47
- ReplayAiAction,
48
- ReplayAiField,
49
- ReplayAiIndex,
50
- ReplayAiIndexStats,
51
- ReplayAiNodeSummary,
52
- SavedReplayAiIndex,
53
- } from './replay-ai-index.js'
package/src/kill-port.ts DELETED
@@ -1,219 +0,0 @@
1
- /**
2
- * Cross-platform process termination for a TCP port.
3
- *
4
- * This mirrors the approach used by the `kill-port-process` npm package:
5
- * https://github.com/hilleer/kill-port-process
6
- *
7
- * Notes:
8
- * - Windows: discover listeners via PowerShell/netstat and kill via taskkill.
9
- * - Unix: discover listeners via lsof (preferred) or fuser (fallback) and kill via
10
- * process.kill(). This intentionally avoids shell pipelines (grep/awk/xargs).
11
- */
12
-
13
- import { execFile } from 'node:child_process'
14
- import os from 'node:os'
15
- import { promisify } from 'node:util'
16
-
17
- const execFileAsync = promisify(execFile)
18
-
19
- export type KillPortSignal = 'SIGTERM' | 'SIGKILL'
20
-
21
- function isValidPort(port: number): boolean {
22
- return Number.isInteger(port) && port > 0 && port <= 65535
23
- }
24
-
25
- function parsePids(output: string): number[] {
26
- const matches = output.match(/\d+/g) || []
27
- const pids = matches
28
- .map((text) => {
29
- return Number(text)
30
- })
31
- .filter((pid) => {
32
- return Number.isInteger(pid) && pid > 0
33
- })
34
-
35
- return [...new Set(pids)]
36
- }
37
-
38
- function parseUnixLsofPids(stdout: string): number[] {
39
- const pids = stdout
40
- .split(/\r?\n/g)
41
- .map((line) => {
42
- return line.trim()
43
- })
44
- .filter((line) => {
45
- // lsof output starts with a header row; lines we care about contain LISTEN.
46
- return Boolean(line) && !line.startsWith('COMMAND') && line.includes('LISTEN')
47
- })
48
- .map((line) => {
49
- const columns = line.split(/\s+/g)
50
- // `awk '{print $2}'` in kill-port-process extracts PID from 2nd column.
51
- return Number(columns[1] || '')
52
- })
53
- .filter((pid) => {
54
- return Number.isInteger(pid) && pid > 0
55
- })
56
-
57
- return [...new Set(pids)]
58
- }
59
-
60
- function parseWindowsNetstatPids(output: string, port: number): number[] {
61
- const rows = output
62
- .split(/\r?\n/g)
63
- .map((line) => {
64
- return line.trim()
65
- })
66
- .filter((line) => {
67
- return line.startsWith('TCP')
68
- })
69
-
70
- const pids = rows
71
- .map((row) => {
72
- const columns = row.split(/\s+/g)
73
- const localAddress = columns[1] || ''
74
- const state = columns[3] || ''
75
- const pid = columns[4] || ''
76
- const endsWithPort = localAddress.endsWith(`:${port}`)
77
- if (!endsWithPort || state !== 'LISTENING') {
78
- return NaN
79
- }
80
- return Number(pid)
81
- })
82
- .filter((pid) => {
83
- return Number.isInteger(pid) && pid > 0
84
- })
85
-
86
- return [...new Set(pids)]
87
- }
88
-
89
- async function getPidsForPortWindows(port: number): Promise<number[]> {
90
- const powerShellScript = [
91
- "$ErrorActionPreference='SilentlyContinue'",
92
- `@(Get-NetTCPConnection -LocalPort ${port} -State Listen | Select-Object -ExpandProperty OwningProcess -Unique) -join [Environment]::NewLine`,
93
- ].join('; ')
94
-
95
- try {
96
- const { stdout } = await execFileAsync('powershell', ['-NoProfile', '-Command', powerShellScript])
97
- const pids = parsePids(stdout)
98
- if (pids.length > 0) {
99
- return pids
100
- }
101
- } catch {}
102
-
103
- try {
104
- const { stdout } = await execFileAsync('cmd', ['/d', '/s', '/c', 'netstat -ano -p tcp'])
105
- return parseWindowsNetstatPids(stdout, port)
106
- } catch {
107
- return []
108
- }
109
- }
110
-
111
- async function getPidsForPortUnix(port: number): Promise<number[]> {
112
- try {
113
- // Prefer lsof's built-in filtering and pid-only output.
114
- const { stdout } = await execFileAsync('lsof', ['-n', '-P', '-i', `TCP:${port}`, '-sTCP:LISTEN', '-t'])
115
- const pids = parsePids(stdout)
116
- return pids
117
- } catch {}
118
-
119
- try {
120
- // Compatibility fallback: some environments may have lsof but not support
121
- // the exact flags above. Parse the tabular output.
122
- const { stdout } = await execFileAsync('lsof', ['-i', `tcp:${port}`])
123
- const pids = parseUnixLsofPids(stdout)
124
- if (pids.length > 0) {
125
- return pids
126
- }
127
- } catch {}
128
-
129
- // Fallback for Linux environments that may not have `lsof`.
130
- try {
131
- const { stdout } = await execFileAsync('fuser', [`${port}/tcp`])
132
- return parsePids(stdout).filter((pid) => {
133
- return pid !== port
134
- })
135
- } catch {
136
- return []
137
- }
138
- }
139
-
140
- /**
141
- * Return PIDs (if any) that are currently LISTENing on the given TCP port.
142
- *
143
- * This is intentionally separate from killPortProcess(): callers sometimes need
144
- * to detect/diagnose EADDRINUSE before attempting to start a server.
145
- */
146
- export async function getListeningPidsForPort({ port }: { port: number }): Promise<number[]> {
147
- if (!isValidPort(port)) {
148
- throw new Error(`Invalid port: ${port}`)
149
- }
150
-
151
- return os.platform() === 'win32' ? await getPidsForPortWindows(port) : await getPidsForPortUnix(port)
152
- }
153
-
154
- function toError(value: unknown): Error {
155
- if (value instanceof Error) {
156
- return value
157
- }
158
- return new Error(String(value))
159
- }
160
-
161
- async function terminatePidWindows(pid: number): Promise<void> {
162
- try {
163
- await execFileAsync('taskkill', ['/PID', String(pid), '/T', '/F'])
164
- } catch {}
165
- }
166
-
167
- /**
168
- * Kill any listening process bound to the provided TCP port.
169
- */
170
- export async function killPortProcess({
171
- port,
172
- signal = 'SIGKILL',
173
- }: {
174
- port: number
175
- signal?: KillPortSignal
176
- }): Promise<void> {
177
- if (!isValidPort(port)) {
178
- throw new Error(`Invalid port: ${port}`)
179
- }
180
-
181
- if (os.platform() === 'win32') {
182
- const pids = await getListeningPidsForPort({ port })
183
- const currentPid = process.pid
184
- const targetPids = pids.filter((pid) => {
185
- return pid !== currentPid
186
- })
187
- await Promise.all(
188
- targetPids.map(async (pid) => {
189
- await terminatePidWindows(pid)
190
- }),
191
- )
192
- return
193
- }
194
-
195
- const pids = await getListeningPidsForPort({ port })
196
- const currentPid = process.pid
197
- const targetPids = pids.filter((pid) => {
198
- return pid !== currentPid
199
- })
200
-
201
- if (targetPids.length === 0) {
202
- return
203
- }
204
-
205
- await Promise.all(
206
- targetPids.map(async (pid) => {
207
- try {
208
- process.kill(pid, signal)
209
- } catch (error) {
210
- const err = toError(error)
211
- // If the process already exited between discovery and kill, ignore.
212
- if ((err as NodeJS.ErrnoException).code === 'ESRCH') {
213
- return
214
- }
215
- throw new Error(`Failed to kill pid ${pid} on port ${port}`, { cause: err })
216
- }
217
- }),
218
- )
219
- }