tabwright 1.0.0 → 1.0.1

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 (562) hide show
  1. package/dist/aria-snapshot.d.ts +0 -1
  2. package/dist/aria-snapshot.js +9 -1
  3. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts +0 -1
  4. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js +0 -1
  5. package/dist/bippy.js +1 -1
  6. package/dist/browser-config.d.ts +0 -1
  7. package/dist/browser-config.js +0 -1
  8. package/dist/browser-install.d.ts +0 -1
  9. package/dist/browser-install.js +0 -1
  10. package/dist/browser-launch.d.ts +0 -1
  11. package/dist/browser-launch.js +0 -1
  12. package/dist/builtin-capabilities.d.ts +0 -1
  13. package/dist/builtin-capabilities.js +0 -1
  14. package/dist/capability-agent-skill.d.ts +0 -1
  15. package/dist/capability-agent-skill.js +0 -1
  16. package/dist/capability-auth-state.d.ts +0 -1
  17. package/dist/capability-auth-state.js +0 -1
  18. package/dist/capability-auth.d.ts +0 -1
  19. package/dist/capability-auth.js +0 -1
  20. package/dist/capability-options.d.ts +0 -1
  21. package/dist/capability-options.js +0 -1
  22. package/dist/capability-package.d.ts +0 -1
  23. package/dist/capability-package.js +0 -1
  24. package/dist/capability-registry.d.ts +0 -1
  25. package/dist/capability-registry.js +0 -1
  26. package/dist/capability-runner.d.ts +0 -1
  27. package/dist/capability-runner.js +0 -1
  28. package/dist/capability-studio.d.ts +0 -1
  29. package/dist/capability-studio.js +0 -1
  30. package/dist/cdp-log.d.ts +0 -1
  31. package/dist/cdp-log.js +0 -1
  32. package/dist/cdp-relay.d.ts +0 -1
  33. package/dist/cdp-relay.js +0 -1
  34. package/dist/cdp-session.d.ts +0 -1
  35. package/dist/cdp-session.js +0 -1
  36. package/dist/cdp-types.d.ts +0 -1
  37. package/dist/cdp-types.js +0 -1
  38. package/dist/chrome-discovery.d.ts +0 -1
  39. package/dist/chrome-discovery.js +0 -1
  40. package/dist/clean-html.d.ts +0 -1
  41. package/dist/clean-html.js +0 -1
  42. package/dist/cli.d.ts +0 -1
  43. package/dist/cli.js +9 -2
  44. package/dist/cloud-client.d.ts +0 -1
  45. package/dist/cloud-client.js +0 -1
  46. package/dist/create-logger.d.ts +0 -1
  47. package/dist/create-logger.js +0 -1
  48. package/dist/debugger-examples-types.d.ts +0 -1
  49. package/dist/debugger-examples-types.js +0 -1
  50. package/dist/debugger-examples.d.ts +0 -1
  51. package/dist/debugger-examples.js +0 -1
  52. package/dist/debugger.d.ts +0 -1
  53. package/dist/debugger.js +0 -1
  54. package/dist/diff-utils.d.ts +0 -1
  55. package/dist/diff-utils.js +0 -1
  56. package/dist/doctor.d.ts +0 -1
  57. package/dist/doctor.js +5 -7
  58. package/dist/editor-examples.d.ts +0 -1
  59. package/dist/editor-examples.js +0 -1
  60. package/dist/editor.d.ts +0 -1
  61. package/dist/editor.js +0 -1
  62. package/dist/env-compat.d.ts +0 -1
  63. package/dist/env-compat.js +0 -1
  64. package/dist/executor.d.ts +0 -1
  65. package/dist/executor.js +1 -2
  66. package/dist/extension/background.js +7 -3
  67. package/dist/extension/manifest.json +1 -1
  68. package/dist/ghost-browser.d.ts +0 -1
  69. package/dist/ghost-browser.js +0 -1
  70. package/dist/ghost-cursor-controller.d.ts +0 -1
  71. package/dist/ghost-cursor-controller.js +0 -1
  72. package/dist/ghost-cursor.d.ts +0 -1
  73. package/dist/ghost-cursor.js +0 -1
  74. package/dist/htmlrewrite.d.ts +0 -1
  75. package/dist/htmlrewrite.js +0 -1
  76. package/dist/index.d.ts +0 -1
  77. package/dist/index.js +0 -1
  78. package/dist/kill-port.d.ts +0 -1
  79. package/dist/kill-port.js +0 -1
  80. package/dist/kitty-graphics.d.ts +0 -1
  81. package/dist/kitty-graphics.js +0 -1
  82. package/dist/mcp.d.ts +0 -1
  83. package/dist/mcp.js +0 -1
  84. package/dist/package-paths.d.ts +0 -1
  85. package/dist/package-paths.js +0 -1
  86. package/dist/page-markdown.d.ts +0 -1
  87. package/dist/page-markdown.js +0 -1
  88. package/dist/performance-examples.d.ts +0 -1
  89. package/dist/performance-examples.js +0 -1
  90. package/dist/playwright-import.d.ts +0 -1
  91. package/dist/playwright-import.js +0 -1
  92. package/dist/product-paths.d.ts +0 -1
  93. package/dist/product-paths.js +0 -1
  94. package/dist/protocol.d.ts +0 -1
  95. package/dist/protocol.js +0 -1
  96. package/dist/react-source.d.ts +0 -1
  97. package/dist/react-source.js +0 -1
  98. package/dist/readability.js +1 -1
  99. package/dist/relay-client.d.ts +0 -1
  100. package/dist/relay-client.js +0 -1
  101. package/dist/relay-state.d.ts +0 -1
  102. package/dist/relay-state.js +0 -1
  103. package/dist/replay-ai-index.d.ts +0 -1
  104. package/dist/replay-ai-index.js +0 -1
  105. package/dist/replay-eval.d.ts +0 -1
  106. package/dist/replay-eval.js +0 -1
  107. package/dist/replay-handoff.d.ts +0 -1
  108. package/dist/replay-handoff.js +0 -1
  109. package/dist/replay-workflow-compiler.d.ts +0 -1
  110. package/dist/replay-workflow-compiler.js +0 -1
  111. package/dist/rrweb-recording-relay.d.ts +0 -1
  112. package/dist/rrweb-recording-relay.js +0 -1
  113. package/dist/rrweb-recording.d.ts +0 -1
  114. package/dist/rrweb-recording.js +0 -1
  115. package/dist/scoped-fs.d.ts +0 -1
  116. package/dist/scoped-fs.js +0 -1
  117. package/dist/selector-generator.js +1 -1
  118. package/dist/start-relay-server.d.ts +0 -1
  119. package/dist/start-relay-server.js +0 -1
  120. package/dist/styles-examples.d.ts +0 -1
  121. package/dist/styles-examples.js +0 -1
  122. package/dist/styles.d.ts +0 -1
  123. package/dist/styles.js +0 -1
  124. package/dist/tabwright-agent-skill.d.ts +0 -1
  125. package/dist/tabwright-agent-skill.js +0 -1
  126. package/dist/test-declarations.d.ts +0 -1
  127. package/dist/test-declarations.js +0 -1
  128. package/dist/utils.d.ts +0 -1
  129. package/dist/utils.js +2 -2
  130. package/dist/wait-for-page-load.d.ts +0 -1
  131. package/dist/wait-for-page-load.js +0 -1
  132. package/dist/workflow-capability.d.ts +0 -1
  133. package/dist/workflow-capability.js +0 -1
  134. package/package.json +9 -4
  135. package/readme.md +35 -0
  136. package/dist/aria-snapshot.d.ts.map +0 -1
  137. package/dist/aria-snapshot.js.map +0 -1
  138. package/dist/aria-snapshot.test.d.ts +0 -2
  139. package/dist/aria-snapshot.test.d.ts.map +0 -1
  140. package/dist/aria-snapshot.test.js +0 -270
  141. package/dist/aria-snapshot.test.js.map +0 -1
  142. package/dist/aria-snapshot.unit.test.d.ts +0 -2
  143. package/dist/aria-snapshot.unit.test.d.ts.map +0 -1
  144. package/dist/aria-snapshot.unit.test.js +0 -542
  145. package/dist/aria-snapshot.unit.test.js.map +0 -1
  146. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.d.ts.map +0 -1
  147. package/dist/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.js.map +0 -1
  148. package/dist/browser-config.d.ts.map +0 -1
  149. package/dist/browser-config.js.map +0 -1
  150. package/dist/browser-install.d.ts.map +0 -1
  151. package/dist/browser-install.js.map +0 -1
  152. package/dist/browser-launch.d.ts.map +0 -1
  153. package/dist/browser-launch.js.map +0 -1
  154. package/dist/builtin-capabilities.d.ts.map +0 -1
  155. package/dist/builtin-capabilities.js.map +0 -1
  156. package/dist/capability-agent-skill.d.ts.map +0 -1
  157. package/dist/capability-agent-skill.js.map +0 -1
  158. package/dist/capability-auth-state.d.ts.map +0 -1
  159. package/dist/capability-auth-state.js.map +0 -1
  160. package/dist/capability-auth.d.ts.map +0 -1
  161. package/dist/capability-auth.js.map +0 -1
  162. package/dist/capability-cli-confirmation.test.d.ts +0 -2
  163. package/dist/capability-cli-confirmation.test.d.ts.map +0 -1
  164. package/dist/capability-cli-confirmation.test.js +0 -79
  165. package/dist/capability-cli-confirmation.test.js.map +0 -1
  166. package/dist/capability-options.d.ts.map +0 -1
  167. package/dist/capability-options.js.map +0 -1
  168. package/dist/capability-options.test.d.ts +0 -2
  169. package/dist/capability-options.test.d.ts.map +0 -1
  170. package/dist/capability-options.test.js +0 -81
  171. package/dist/capability-options.test.js.map +0 -1
  172. package/dist/capability-package.d.ts.map +0 -1
  173. package/dist/capability-package.js.map +0 -1
  174. package/dist/capability-package.test.d.ts +0 -2
  175. package/dist/capability-package.test.d.ts.map +0 -1
  176. package/dist/capability-package.test.js +0 -179
  177. package/dist/capability-package.test.js.map +0 -1
  178. package/dist/capability-registry.d.ts.map +0 -1
  179. package/dist/capability-registry.js.map +0 -1
  180. package/dist/capability-registry.test.d.ts +0 -2
  181. package/dist/capability-registry.test.d.ts.map +0 -1
  182. package/dist/capability-registry.test.js +0 -1683
  183. package/dist/capability-registry.test.js.map +0 -1
  184. package/dist/capability-runner.d.ts.map +0 -1
  185. package/dist/capability-runner.js.map +0 -1
  186. package/dist/capability-search-relevance.test.d.ts +0 -2
  187. package/dist/capability-search-relevance.test.d.ts.map +0 -1
  188. package/dist/capability-search-relevance.test.js +0 -67
  189. package/dist/capability-search-relevance.test.js.map +0 -1
  190. package/dist/capability-studio.d.ts.map +0 -1
  191. package/dist/capability-studio.js.map +0 -1
  192. package/dist/capability-studio.test.d.ts +0 -2
  193. package/dist/capability-studio.test.d.ts.map +0 -1
  194. package/dist/capability-studio.test.js +0 -41
  195. package/dist/capability-studio.test.js.map +0 -1
  196. package/dist/cdp-log.d.ts.map +0 -1
  197. package/dist/cdp-log.js.map +0 -1
  198. package/dist/cdp-log.test.d.ts +0 -2
  199. package/dist/cdp-log.test.d.ts.map +0 -1
  200. package/dist/cdp-log.test.js +0 -109
  201. package/dist/cdp-log.test.js.map +0 -1
  202. package/dist/cdp-relay.d.ts.map +0 -1
  203. package/dist/cdp-relay.js.map +0 -1
  204. package/dist/cdp-session.d.ts.map +0 -1
  205. package/dist/cdp-session.js.map +0 -1
  206. package/dist/cdp-types.d.ts.map +0 -1
  207. package/dist/cdp-types.js.map +0 -1
  208. package/dist/channel-owner-inspect.test.d.ts +0 -2
  209. package/dist/channel-owner-inspect.test.d.ts.map +0 -1
  210. package/dist/channel-owner-inspect.test.js +0 -75
  211. package/dist/channel-owner-inspect.test.js.map +0 -1
  212. package/dist/chrome-discovery.d.ts.map +0 -1
  213. package/dist/chrome-discovery.js.map +0 -1
  214. package/dist/chrome-discovery.test.d.ts +0 -2
  215. package/dist/chrome-discovery.test.d.ts.map +0 -1
  216. package/dist/chrome-discovery.test.js +0 -41
  217. package/dist/chrome-discovery.test.js.map +0 -1
  218. package/dist/clean-html.d.ts.map +0 -1
  219. package/dist/clean-html.js.map +0 -1
  220. package/dist/cli-help.test.d.ts +0 -2
  221. package/dist/cli-help.test.d.ts.map +0 -1
  222. package/dist/cli-help.test.js +0 -98
  223. package/dist/cli-help.test.js.map +0 -1
  224. package/dist/cli.d.ts.map +0 -1
  225. package/dist/cli.js.map +0 -1
  226. package/dist/cloud-client.d.ts.map +0 -1
  227. package/dist/cloud-client.js.map +0 -1
  228. package/dist/create-logger.d.ts.map +0 -1
  229. package/dist/create-logger.js.map +0 -1
  230. package/dist/debugger-examples-types.d.ts.map +0 -1
  231. package/dist/debugger-examples-types.js.map +0 -1
  232. package/dist/debugger-examples.d.ts.map +0 -1
  233. package/dist/debugger-examples.js.map +0 -1
  234. package/dist/debugger.d.ts.map +0 -1
  235. package/dist/debugger.js.map +0 -1
  236. package/dist/diff-utils.d.ts.map +0 -1
  237. package/dist/diff-utils.js.map +0 -1
  238. package/dist/diff-utils.test.d.ts +0 -2
  239. package/dist/diff-utils.test.d.ts.map +0 -1
  240. package/dist/diff-utils.test.js +0 -137
  241. package/dist/diff-utils.test.js.map +0 -1
  242. package/dist/doctor.d.ts.map +0 -1
  243. package/dist/doctor.js.map +0 -1
  244. package/dist/doctor.test.d.ts +0 -2
  245. package/dist/doctor.test.d.ts.map +0 -1
  246. package/dist/doctor.test.js +0 -208
  247. package/dist/doctor.test.js.map +0 -1
  248. package/dist/editor-examples.d.ts.map +0 -1
  249. package/dist/editor-examples.js.map +0 -1
  250. package/dist/editor.d.ts.map +0 -1
  251. package/dist/editor.js.map +0 -1
  252. package/dist/env-compat.d.ts.map +0 -1
  253. package/dist/env-compat.js.map +0 -1
  254. package/dist/executor.d.ts.map +0 -1
  255. package/dist/executor.js.map +0 -1
  256. package/dist/executor.unit.test.d.ts +0 -2
  257. package/dist/executor.unit.test.d.ts.map +0 -1
  258. package/dist/executor.unit.test.js +0 -143
  259. package/dist/executor.unit.test.js.map +0 -1
  260. package/dist/extension-connection.test.d.ts +0 -2
  261. package/dist/extension-connection.test.d.ts.map +0 -1
  262. package/dist/extension-connection.test.js +0 -708
  263. package/dist/extension-connection.test.js.map +0 -1
  264. package/dist/extension-icon-warning.test.d.ts +0 -2
  265. package/dist/extension-icon-warning.test.d.ts.map +0 -1
  266. package/dist/extension-icon-warning.test.js +0 -33
  267. package/dist/extension-icon-warning.test.js.map +0 -1
  268. package/dist/ghost-browser.d.ts.map +0 -1
  269. package/dist/ghost-browser.js.map +0 -1
  270. package/dist/ghost-cursor-controller.d.ts.map +0 -1
  271. package/dist/ghost-cursor-controller.js.map +0 -1
  272. package/dist/ghost-cursor.d.ts.map +0 -1
  273. package/dist/ghost-cursor.js.map +0 -1
  274. package/dist/htmlrewrite.d.ts.map +0 -1
  275. package/dist/htmlrewrite.js.map +0 -1
  276. package/dist/htmlrewrite.test.d.ts +0 -2
  277. package/dist/htmlrewrite.test.d.ts.map +0 -1
  278. package/dist/htmlrewrite.test.js +0 -7975
  279. package/dist/htmlrewrite.test.js.map +0 -1
  280. package/dist/index.d.ts.map +0 -1
  281. package/dist/index.js.map +0 -1
  282. package/dist/kill-port.d.ts.map +0 -1
  283. package/dist/kill-port.js.map +0 -1
  284. package/dist/kitty-graphics.d.ts.map +0 -1
  285. package/dist/kitty-graphics.js.map +0 -1
  286. package/dist/kitty-graphics.test.d.ts +0 -2
  287. package/dist/kitty-graphics.test.d.ts.map +0 -1
  288. package/dist/kitty-graphics.test.js +0 -125
  289. package/dist/kitty-graphics.test.js.map +0 -1
  290. package/dist/locator-selector.test.d.ts +0 -2
  291. package/dist/locator-selector.test.d.ts.map +0 -1
  292. package/dist/locator-selector.test.js +0 -98
  293. package/dist/locator-selector.test.js.map +0 -1
  294. package/dist/mcp-client.d.ts +0 -20
  295. package/dist/mcp-client.d.ts.map +0 -1
  296. package/dist/mcp-client.js +0 -56
  297. package/dist/mcp-client.js.map +0 -1
  298. package/dist/mcp.d.ts.map +0 -1
  299. package/dist/mcp.js.map +0 -1
  300. package/dist/on-mouse-action.test.d.ts +0 -2
  301. package/dist/on-mouse-action.test.d.ts.map +0 -1
  302. package/dist/on-mouse-action.test.js +0 -180
  303. package/dist/on-mouse-action.test.js.map +0 -1
  304. package/dist/options-page.test.d.ts +0 -2
  305. package/dist/options-page.test.d.ts.map +0 -1
  306. package/dist/options-page.test.js +0 -773
  307. package/dist/options-page.test.js.map +0 -1
  308. package/dist/package-paths.d.ts.map +0 -1
  309. package/dist/package-paths.js.map +0 -1
  310. package/dist/page-markdown.d.ts.map +0 -1
  311. package/dist/page-markdown.js.map +0 -1
  312. package/dist/performance-examples.d.ts.map +0 -1
  313. package/dist/performance-examples.js.map +0 -1
  314. package/dist/playwright-import.d.ts.map +0 -1
  315. package/dist/playwright-import.js.map +0 -1
  316. package/dist/popup-relocation.test.d.ts +0 -7
  317. package/dist/popup-relocation.test.d.ts.map +0 -1
  318. package/dist/popup-relocation.test.js +0 -139
  319. package/dist/popup-relocation.test.js.map +0 -1
  320. package/dist/product-paths.d.ts.map +0 -1
  321. package/dist/product-paths.js.map +0 -1
  322. package/dist/product-paths.test.d.ts +0 -2
  323. package/dist/product-paths.test.d.ts.map +0 -1
  324. package/dist/product-paths.test.js +0 -39
  325. package/dist/product-paths.test.js.map +0 -1
  326. package/dist/protocol.d.ts.map +0 -1
  327. package/dist/protocol.js.map +0 -1
  328. package/dist/protocol.test.d.ts +0 -2
  329. package/dist/protocol.test.d.ts.map +0 -1
  330. package/dist/protocol.test.js +0 -31
  331. package/dist/protocol.test.js.map +0 -1
  332. package/dist/react-source.d.ts.map +0 -1
  333. package/dist/react-source.js.map +0 -1
  334. package/dist/relay-client.d.ts.map +0 -1
  335. package/dist/relay-client.js.map +0 -1
  336. package/dist/relay-client.test.d.ts +0 -2
  337. package/dist/relay-client.test.d.ts.map +0 -1
  338. package/dist/relay-client.test.js +0 -305
  339. package/dist/relay-client.test.js.map +0 -1
  340. package/dist/relay-core.test.d.ts +0 -2
  341. package/dist/relay-core.test.d.ts.map +0 -1
  342. package/dist/relay-core.test.js +0 -1427
  343. package/dist/relay-core.test.js.map +0 -1
  344. package/dist/relay-navigation.test.d.ts +0 -2
  345. package/dist/relay-navigation.test.d.ts.map +0 -1
  346. package/dist/relay-navigation.test.js +0 -661
  347. package/dist/relay-navigation.test.js.map +0 -1
  348. package/dist/relay-session.test.d.ts +0 -2
  349. package/dist/relay-session.test.d.ts.map +0 -1
  350. package/dist/relay-session.test.js +0 -1121
  351. package/dist/relay-session.test.js.map +0 -1
  352. package/dist/relay-state.d.ts.map +0 -1
  353. package/dist/relay-state.js.map +0 -1
  354. package/dist/relay-state.test.d.ts +0 -2
  355. package/dist/relay-state.test.d.ts.map +0 -1
  356. package/dist/relay-state.test.js +0 -594
  357. package/dist/relay-state.test.js.map +0 -1
  358. package/dist/replay-ai-index.d.ts.map +0 -1
  359. package/dist/replay-ai-index.js.map +0 -1
  360. package/dist/replay-ai-index.test.d.ts +0 -2
  361. package/dist/replay-ai-index.test.d.ts.map +0 -1
  362. package/dist/replay-ai-index.test.js +0 -255
  363. package/dist/replay-ai-index.test.js.map +0 -1
  364. package/dist/replay-cli.test.d.ts +0 -2
  365. package/dist/replay-cli.test.d.ts.map +0 -1
  366. package/dist/replay-cli.test.js +0 -275
  367. package/dist/replay-cli.test.js.map +0 -1
  368. package/dist/replay-eval.d.ts.map +0 -1
  369. package/dist/replay-eval.js.map +0 -1
  370. package/dist/replay-handoff.d.ts.map +0 -1
  371. package/dist/replay-handoff.js.map +0 -1
  372. package/dist/replay-handoff.test.d.ts +0 -2
  373. package/dist/replay-handoff.test.d.ts.map +0 -1
  374. package/dist/replay-handoff.test.js +0 -123
  375. package/dist/replay-handoff.test.js.map +0 -1
  376. package/dist/replay-workflow-compiler.d.ts.map +0 -1
  377. package/dist/replay-workflow-compiler.js.map +0 -1
  378. package/dist/replay-workflow-compiler.test.d.ts +0 -2
  379. package/dist/replay-workflow-compiler.test.d.ts.map +0 -1
  380. package/dist/replay-workflow-compiler.test.js +0 -223
  381. package/dist/replay-workflow-compiler.test.js.map +0 -1
  382. package/dist/rrweb-recording-relay.d.ts.map +0 -1
  383. package/dist/rrweb-recording-relay.js.map +0 -1
  384. package/dist/rrweb-recording-relay.test.d.ts +0 -2
  385. package/dist/rrweb-recording-relay.test.d.ts.map +0 -1
  386. package/dist/rrweb-recording-relay.test.js +0 -85
  387. package/dist/rrweb-recording-relay.test.js.map +0 -1
  388. package/dist/rrweb-recording.d.ts.map +0 -1
  389. package/dist/rrweb-recording.js.map +0 -1
  390. package/dist/scoped-fs.d.ts.map +0 -1
  391. package/dist/scoped-fs.js.map +0 -1
  392. package/dist/scoped-fs.test.d.ts +0 -5
  393. package/dist/scoped-fs.test.d.ts.map +0 -1
  394. package/dist/scoped-fs.test.js +0 -73
  395. package/dist/scoped-fs.test.js.map +0 -1
  396. package/dist/skill-stub.test.d.ts +0 -2
  397. package/dist/skill-stub.test.d.ts.map +0 -1
  398. package/dist/skill-stub.test.js +0 -22
  399. package/dist/skill-stub.test.js.map +0 -1
  400. package/dist/snapshot-tools.test.d.ts +0 -2
  401. package/dist/snapshot-tools.test.d.ts.map +0 -1
  402. package/dist/snapshot-tools.test.js +0 -856
  403. package/dist/snapshot-tools.test.js.map +0 -1
  404. package/dist/start-relay-server.d.ts.map +0 -1
  405. package/dist/start-relay-server.js.map +0 -1
  406. package/dist/styles-examples.d.ts.map +0 -1
  407. package/dist/styles-examples.js.map +0 -1
  408. package/dist/styles.d.ts.map +0 -1
  409. package/dist/styles.js.map +0 -1
  410. package/dist/tabwright-agent-skill.d.ts.map +0 -1
  411. package/dist/tabwright-agent-skill.js.map +0 -1
  412. package/dist/tabwright-agent-skill.test.d.ts +0 -2
  413. package/dist/tabwright-agent-skill.test.d.ts.map +0 -1
  414. package/dist/tabwright-agent-skill.test.js +0 -51
  415. package/dist/tabwright-agent-skill.test.js.map +0 -1
  416. package/dist/test-declarations.d.ts.map +0 -1
  417. package/dist/test-declarations.js.map +0 -1
  418. package/dist/test-utils.d.ts +0 -69
  419. package/dist/test-utils.d.ts.map +0 -1
  420. package/dist/test-utils.js +0 -448
  421. package/dist/test-utils.js.map +0 -1
  422. package/dist/test-utils.test.d.ts +0 -2
  423. package/dist/test-utils.test.d.ts.map +0 -1
  424. package/dist/test-utils.test.js +0 -55
  425. package/dist/test-utils.test.js.map +0 -1
  426. package/dist/utils.d.ts.map +0 -1
  427. package/dist/utils.js.map +0 -1
  428. package/dist/wait-for-page-load.d.ts.map +0 -1
  429. package/dist/wait-for-page-load.js.map +0 -1
  430. package/dist/workflow-capability.d.ts.map +0 -1
  431. package/dist/workflow-capability.js.map +0 -1
  432. package/dist/workflow-script-flow.test.d.ts +0 -2
  433. package/dist/workflow-script-flow.test.d.ts.map +0 -1
  434. package/dist/workflow-script-flow.test.js +0 -285
  435. package/dist/workflow-script-flow.test.js.map +0 -1
  436. package/src/__snapshots__/x.com.processed.html +0 -1003
  437. package/src/__snapshots__/x.com.processed.withStyles.html +0 -2720
  438. package/src/a11y-client.ts +0 -241
  439. package/src/aria-snapshot.test.ts +0 -311
  440. package/src/aria-snapshot.ts +0 -1681
  441. package/src/aria-snapshot.unit.test.ts +0 -615
  442. package/src/aria-snapshots/github-interactive.txt +0 -193
  443. package/src/aria-snapshots/github-raw.txt +0 -309
  444. package/src/aria-snapshots/hackernews-interactive.txt +0 -477
  445. package/src/aria-snapshots/hackernews-raw.txt +0 -428
  446. package/src/aria-snapshots/prosemirror-interactive.txt +0 -66
  447. package/src/aria-snapshots/prosemirror-raw.txt +0 -145
  448. package/src/assets/aria-labels-hacker-news.png +0 -0
  449. package/src/assets/aria-labels-old-reddit.png +0 -0
  450. package/src/assets/cursors/screen-studio/pointer-macos-tahoe-data-url.ts +0 -5
  451. package/src/assets/cursors/screen-studio/pointer-macos-tahoe.svg +0 -18
  452. package/src/assets/x.com.html +0 -32946
  453. package/src/browser-config.ts +0 -179
  454. package/src/browser-install.ts +0 -284
  455. package/src/browser-launch.ts +0 -75
  456. package/src/builtin-capabilities.ts +0 -2765
  457. package/src/capability-agent-skill.ts +0 -305
  458. package/src/capability-auth-state.ts +0 -197
  459. package/src/capability-auth.ts +0 -249
  460. package/src/capability-cli-confirmation.test.ts +0 -90
  461. package/src/capability-options.test.ts +0 -89
  462. package/src/capability-options.ts +0 -57
  463. package/src/capability-package.test.ts +0 -204
  464. package/src/capability-package.ts +0 -555
  465. package/src/capability-registry.test.ts +0 -1905
  466. package/src/capability-registry.ts +0 -1234
  467. package/src/capability-runner.ts +0 -801
  468. package/src/capability-search-relevance.test.ts +0 -73
  469. package/src/capability-studio.test.ts +0 -45
  470. package/src/capability-studio.ts +0 -641
  471. package/src/cdp-log.test.ts +0 -131
  472. package/src/cdp-log.ts +0 -112
  473. package/src/cdp-relay.ts +0 -2944
  474. package/src/cdp-session.ts +0 -77
  475. package/src/cdp-types.ts +0 -158
  476. package/src/channel-owner-inspect.test.ts +0 -94
  477. package/src/chrome-discovery.test.ts +0 -50
  478. package/src/chrome-discovery.ts +0 -220
  479. package/src/clean-html.ts +0 -141
  480. package/src/cli-help.test.ts +0 -123
  481. package/src/cli.ts +0 -3181
  482. package/src/cloud-client.ts +0 -179
  483. package/src/create-logger.ts +0 -38
  484. package/src/debugger-examples-types.ts +0 -16
  485. package/src/debugger-examples.ts +0 -66
  486. package/src/debugger.ts +0 -708
  487. package/src/diff-utils.test.ts +0 -152
  488. package/src/diff-utils.ts +0 -70
  489. package/src/doctor.test.ts +0 -244
  490. package/src/doctor.ts +0 -321
  491. package/src/editor-examples.ts +0 -158
  492. package/src/editor.ts +0 -426
  493. package/src/env-compat.ts +0 -28
  494. package/src/executor.ts +0 -1824
  495. package/src/executor.unit.test.ts +0 -168
  496. package/src/extension-connection.test.ts +0 -855
  497. package/src/extension-icon-warning.test.ts +0 -45
  498. package/src/ghost-browser.ts +0 -149
  499. package/src/ghost-cursor-client.ts +0 -494
  500. package/src/ghost-cursor-controller.ts +0 -129
  501. package/src/ghost-cursor.ts +0 -123
  502. package/src/htmlrewrite.test.ts +0 -8008
  503. package/src/htmlrewrite.ts +0 -390
  504. package/src/index.ts +0 -53
  505. package/src/kill-port.ts +0 -219
  506. package/src/kitty-graphics.test.ts +0 -139
  507. package/src/kitty-graphics.ts +0 -79
  508. package/src/locator-selector.test.ts +0 -119
  509. package/src/mcp-client.ts +0 -78
  510. package/src/mcp.ts +0 -629
  511. package/src/on-mouse-action.test.ts +0 -226
  512. package/src/options-page.test.ts +0 -839
  513. package/src/package-paths.ts +0 -38
  514. package/src/page-markdown.ts +0 -240
  515. package/src/performance-examples.ts +0 -186
  516. package/src/playwright-import.ts +0 -59
  517. package/src/popup-relocation.test.ts +0 -163
  518. package/src/product-paths.test.ts +0 -47
  519. package/src/product-paths.ts +0 -28
  520. package/src/protocol.test.ts +0 -52
  521. package/src/protocol.ts +0 -351
  522. package/src/react-source.ts +0 -379
  523. package/src/relay-client.test.ts +0 -375
  524. package/src/relay-client.ts +0 -572
  525. package/src/relay-core.test.ts +0 -1603
  526. package/src/relay-navigation.test.ts +0 -790
  527. package/src/relay-session.test.ts +0 -1375
  528. package/src/relay-state.test.ts +0 -729
  529. package/src/relay-state.ts +0 -561
  530. package/src/replay-ai-index.test.ts +0 -278
  531. package/src/replay-ai-index.ts +0 -872
  532. package/src/replay-cli.test.ts +0 -325
  533. package/src/replay-eval.ts +0 -1039
  534. package/src/replay-handoff.test.ts +0 -163
  535. package/src/replay-handoff.ts +0 -109
  536. package/src/replay-workflow-compiler.test.ts +0 -250
  537. package/src/replay-workflow-compiler.ts +0 -700
  538. package/src/resource.md +0 -409
  539. package/src/rrweb-recording-relay.test.ts +0 -99
  540. package/src/rrweb-recording-relay.ts +0 -400
  541. package/src/rrweb-recording.ts +0 -322
  542. package/src/scoped-fs.test.ts +0 -80
  543. package/src/scoped-fs.ts +0 -420
  544. package/src/skill-stub.test.ts +0 -24
  545. package/src/snapshot-tools.test.ts +0 -1017
  546. package/src/snapshots/hacker-news-accessibility-full.md +0 -81
  547. package/src/snapshots/hacker-news-accessibility-interactive.md +0 -43
  548. package/src/snapshots/page-markdown-output.txt +0 -16
  549. package/src/snapshots/shadcn-ui-accessibility-full.md +0 -201
  550. package/src/snapshots/shadcn-ui-accessibility-interactive.md +0 -109
  551. package/src/start-relay-server.ts +0 -69
  552. package/src/styles-examples.ts +0 -84
  553. package/src/styles.ts +0 -343
  554. package/src/tabwright-agent-skill.test.ts +0 -61
  555. package/src/tabwright-agent-skill.ts +0 -105
  556. package/src/test-declarations.ts +0 -13
  557. package/src/test-utils.test.ts +0 -70
  558. package/src/test-utils.ts +0 -566
  559. package/src/utils.ts +0 -78
  560. package/src/wait-for-page-load.ts +0 -198
  561. package/src/workflow-capability.ts +0 -417
  562. 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
- }