@agentrhq/webcmd 0.1.1 → 0.1.2

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 (415) hide show
  1. package/README.md +317 -24
  2. package/dist/src/adapter-shadow.d.ts +11 -0
  3. package/dist/src/adapter-shadow.js +72 -0
  4. package/dist/src/adapter-shadow.test.d.ts +1 -0
  5. package/dist/src/adapter-shadow.test.js +49 -0
  6. package/dist/src/adapter-source.d.ts +11 -0
  7. package/dist/src/adapter-source.js +24 -0
  8. package/dist/src/adapter-source.test.d.ts +1 -0
  9. package/dist/src/adapter-source.test.js +29 -0
  10. package/dist/src/brand.d.ts +9 -0
  11. package/dist/src/brand.js +9 -0
  12. package/dist/src/brand.test.d.ts +1 -0
  13. package/dist/src/brand.test.js +15 -0
  14. package/dist/src/browser/analyze.d.ts +118 -0
  15. package/dist/src/browser/analyze.js +405 -0
  16. package/dist/src/browser/analyze.test.d.ts +1 -0
  17. package/dist/src/browser/analyze.test.js +209 -0
  18. package/dist/src/browser/article-extract.d.ts +57 -0
  19. package/dist/src/browser/article-extract.e2e.test.d.ts +1 -0
  20. package/dist/src/browser/article-extract.e2e.test.js +105 -0
  21. package/dist/src/browser/article-extract.js +169 -0
  22. package/dist/src/browser/article-extract.test.d.ts +1 -0
  23. package/dist/src/browser/article-extract.test.js +94 -0
  24. package/dist/src/browser/ax-snapshot.d.ts +37 -0
  25. package/dist/src/browser/ax-snapshot.js +217 -0
  26. package/dist/src/browser/ax-snapshot.test.d.ts +1 -0
  27. package/dist/src/browser/ax-snapshot.test.js +91 -0
  28. package/dist/src/browser/base-page.d.ts +151 -0
  29. package/dist/src/browser/base-page.js +1060 -0
  30. package/dist/src/browser/base-page.test.d.ts +1 -0
  31. package/dist/src/browser/base-page.test.js +803 -0
  32. package/dist/src/browser/bridge-readiness.d.ts +14 -0
  33. package/dist/src/browser/bridge-readiness.js +24 -0
  34. package/dist/src/browser/bridge-readiness.test.d.ts +1 -0
  35. package/dist/src/browser/bridge-readiness.test.js +58 -0
  36. package/dist/src/browser/bridge.d.ts +26 -0
  37. package/dist/src/browser/bridge.js +58 -0
  38. package/dist/src/browser/cdp-click-fixture.test.d.ts +1 -0
  39. package/dist/src/browser/cdp-click-fixture.test.js +87 -0
  40. package/dist/src/browser/cdp.d.ts +46 -0
  41. package/dist/src/browser/cdp.js +536 -0
  42. package/dist/src/browser/cdp.test.d.ts +1 -0
  43. package/dist/src/browser/cdp.test.js +79 -0
  44. package/dist/src/browser/compound.d.ts +59 -0
  45. package/dist/src/browser/compound.js +112 -0
  46. package/dist/src/browser/compound.test.d.ts +1 -0
  47. package/dist/src/browser/compound.test.js +175 -0
  48. package/dist/src/browser/config.d.ts +2 -0
  49. package/dist/src/browser/config.js +14 -0
  50. package/dist/src/browser/daemon-client.d.ts +32 -0
  51. package/dist/src/browser/daemon-client.js +135 -0
  52. package/dist/src/browser/daemon-client.test.d.ts +1 -0
  53. package/dist/src/browser/daemon-client.test.js +326 -0
  54. package/dist/src/browser/daemon-lifecycle.d.ts +37 -0
  55. package/dist/src/browser/daemon-lifecycle.js +147 -0
  56. package/dist/src/browser/daemon-transport.d.ts +54 -0
  57. package/dist/src/browser/daemon-transport.js +68 -0
  58. package/dist/src/browser/daemon-version.d.ts +4 -0
  59. package/dist/src/browser/daemon-version.js +12 -0
  60. package/dist/src/browser/dom-helpers.d.ts +41 -0
  61. package/dist/src/browser/dom-helpers.js +239 -0
  62. package/dist/src/browser/dom-helpers.test.d.ts +1 -0
  63. package/dist/src/browser/dom-helpers.test.js +106 -0
  64. package/dist/src/browser/dom-snapshot.d.ts +93 -0
  65. package/dist/src/browser/dom-snapshot.js +894 -0
  66. package/dist/src/browser/dom-snapshot.test.d.ts +11 -0
  67. package/dist/src/browser/dom-snapshot.test.js +313 -0
  68. package/dist/src/browser/errors.d.ts +38 -0
  69. package/dist/src/browser/errors.js +79 -0
  70. package/dist/src/browser/errors.test.d.ts +1 -0
  71. package/dist/src/browser/errors.test.js +60 -0
  72. package/dist/src/browser/extract.d.ts +69 -0
  73. package/dist/src/browser/extract.js +132 -0
  74. package/dist/src/browser/extract.test.d.ts +1 -0
  75. package/dist/src/browser/extract.test.js +129 -0
  76. package/dist/src/browser/find.d.ts +84 -0
  77. package/dist/src/browser/find.js +398 -0
  78. package/dist/src/browser/find.test.d.ts +1 -0
  79. package/dist/src/browser/find.test.js +180 -0
  80. package/dist/src/browser/html-tree.d.ts +75 -0
  81. package/dist/src/browser/html-tree.js +112 -0
  82. package/dist/src/browser/html-tree.test.d.ts +1 -0
  83. package/dist/src/browser/html-tree.test.js +181 -0
  84. package/dist/src/browser/index.d.ts +14 -0
  85. package/dist/src/browser/index.js +12 -0
  86. package/dist/src/browser/network-cache.d.ts +49 -0
  87. package/dist/src/browser/network-cache.js +78 -0
  88. package/dist/src/browser/network-cache.test.d.ts +1 -0
  89. package/dist/src/browser/network-cache.test.js +75 -0
  90. package/dist/src/browser/network-interceptor.d.ts +11 -0
  91. package/dist/src/browser/network-interceptor.js +11 -0
  92. package/dist/src/browser/network-key.d.ts +22 -0
  93. package/dist/src/browser/network-key.js +66 -0
  94. package/dist/src/browser/network-key.test.d.ts +1 -0
  95. package/dist/src/browser/network-key.test.js +49 -0
  96. package/dist/src/browser/page.d.ts +83 -0
  97. package/dist/src/browser/page.js +453 -0
  98. package/dist/src/browser/page.test.d.ts +1 -0
  99. package/dist/src/browser/page.test.js +406 -0
  100. package/dist/src/browser/profile.d.ts +14 -0
  101. package/dist/src/browser/profile.js +86 -0
  102. package/dist/src/browser/protocol.d.ts +63 -0
  103. package/dist/src/browser/protocol.js +1 -0
  104. package/dist/src/browser/runtime/local-cloak/actions.d.ts +3 -0
  105. package/dist/src/browser/runtime/local-cloak/actions.js +240 -0
  106. package/dist/src/browser/runtime/local-cloak/downloads.d.ts +3 -0
  107. package/dist/src/browser/runtime/local-cloak/downloads.js +28 -0
  108. package/dist/src/browser/runtime/local-cloak/network.d.ts +28 -0
  109. package/dist/src/browser/runtime/local-cloak/network.js +120 -0
  110. package/dist/src/browser/runtime/local-cloak/network.test.d.ts +1 -0
  111. package/dist/src/browser/runtime/local-cloak/network.test.js +124 -0
  112. package/dist/src/browser/runtime/local-cloak/profiles.d.ts +6 -0
  113. package/dist/src/browser/runtime/local-cloak/profiles.js +17 -0
  114. package/dist/src/browser/runtime/local-cloak/profiles.test.d.ts +1 -0
  115. package/dist/src/browser/runtime/local-cloak/profiles.test.js +19 -0
  116. package/dist/src/browser/runtime/local-cloak/provider.d.ts +15 -0
  117. package/dist/src/browser/runtime/local-cloak/provider.js +27 -0
  118. package/dist/src/browser/runtime/local-cloak/provider.test.d.ts +1 -0
  119. package/dist/src/browser/runtime/local-cloak/provider.test.js +244 -0
  120. package/dist/src/browser/runtime/local-cloak/session-manager.d.ts +77 -0
  121. package/dist/src/browser/runtime/local-cloak/session-manager.js +280 -0
  122. package/dist/src/browser/runtime/local-cloak/session-manager.test.d.ts +1 -0
  123. package/dist/src/browser/runtime/local-cloak/session-manager.test.js +92 -0
  124. package/dist/src/browser/runtime/provider.d.ts +9 -0
  125. package/dist/src/browser/runtime/provider.js +1 -0
  126. package/dist/src/browser/runtime/provider.test.d.ts +2 -0
  127. package/dist/src/browser/runtime/provider.test.js +49 -0
  128. package/dist/src/browser/shape-filter.d.ts +52 -0
  129. package/dist/src/browser/shape-filter.js +101 -0
  130. package/dist/src/browser/shape-filter.test.d.ts +1 -0
  131. package/dist/src/browser/shape-filter.test.js +101 -0
  132. package/dist/src/browser/shape.d.ts +23 -0
  133. package/dist/src/browser/shape.js +95 -0
  134. package/dist/src/browser/shape.test.d.ts +1 -0
  135. package/dist/src/browser/shape.test.js +82 -0
  136. package/dist/src/browser/stealth.d.ts +11 -0
  137. package/dist/src/browser/stealth.js +359 -0
  138. package/dist/src/browser/stealth.test.d.ts +1 -0
  139. package/dist/src/browser/stealth.test.js +134 -0
  140. package/dist/src/browser/tabs.d.ts +13 -0
  141. package/dist/src/browser/tabs.js +70 -0
  142. package/dist/src/browser/target-errors.d.ts +39 -0
  143. package/dist/src/browser/target-errors.js +45 -0
  144. package/dist/src/browser/target-errors.test.d.ts +1 -0
  145. package/dist/src/browser/target-errors.test.js +94 -0
  146. package/dist/src/browser/target-resolver.d.ts +158 -0
  147. package/dist/src/browser/target-resolver.js +570 -0
  148. package/dist/src/browser/target-resolver.test.d.ts +1 -0
  149. package/dist/src/browser/target-resolver.test.js +118 -0
  150. package/dist/src/browser/utils.d.ts +20 -0
  151. package/dist/src/browser/utils.js +64 -0
  152. package/dist/src/browser/utils.test.d.ts +1 -0
  153. package/dist/src/browser/utils.test.js +29 -0
  154. package/dist/src/browser/verify-fixture.d.ts +65 -0
  155. package/dist/src/browser/verify-fixture.js +318 -0
  156. package/dist/src/browser/verify-fixture.test.d.ts +1 -0
  157. package/dist/src/browser/verify-fixture.test.js +219 -0
  158. package/dist/src/browser/visual-refs.d.ts +11 -0
  159. package/dist/src/browser/visual-refs.js +108 -0
  160. package/dist/src/browser.test.d.ts +1 -0
  161. package/dist/src/browser.test.js +297 -0
  162. package/dist/src/build-manifest.d.ts +103 -0
  163. package/dist/src/build-manifest.js +363 -0
  164. package/dist/src/build-manifest.test.d.ts +1 -0
  165. package/dist/src/build-manifest.test.js +341 -0
  166. package/dist/src/capabilityRouting.d.ts +19 -0
  167. package/dist/src/capabilityRouting.js +56 -0
  168. package/dist/src/capabilityRouting.test.d.ts +1 -0
  169. package/dist/src/capabilityRouting.test.js +63 -0
  170. package/dist/src/cli-argv-preprocess.d.ts +63 -0
  171. package/dist/src/cli-argv-preprocess.js +303 -0
  172. package/dist/src/cli-argv-preprocess.test.d.ts +1 -0
  173. package/dist/src/cli-argv-preprocess.test.js +304 -0
  174. package/dist/src/cli.d.ts +79 -0
  175. package/dist/src/cli.js +3350 -0
  176. package/dist/src/cli.test.d.ts +1 -0
  177. package/dist/src/cli.test.js +3041 -0
  178. package/dist/src/commanderAdapter.d.ts +21 -0
  179. package/dist/src/commanderAdapter.js +208 -0
  180. package/dist/src/commanderAdapter.test.d.ts +1 -0
  181. package/dist/src/commanderAdapter.test.js +352 -0
  182. package/dist/src/commands/auth.d.ts +40 -0
  183. package/dist/src/commands/auth.js +434 -0
  184. package/dist/src/commands/auth.test.d.ts +1 -0
  185. package/dist/src/commands/auth.test.js +252 -0
  186. package/dist/src/commands/daemon.d.ts +9 -0
  187. package/dist/src/commands/daemon.js +91 -0
  188. package/dist/src/commands/daemon.test.d.ts +1 -0
  189. package/dist/src/commands/daemon.test.js +293 -0
  190. package/dist/src/completion-fast.d.ts +22 -0
  191. package/dist/src/completion-fast.js +88 -0
  192. package/dist/src/completion-shared.d.ts +13 -0
  193. package/dist/src/completion-shared.js +61 -0
  194. package/dist/src/completion.d.ts +21 -0
  195. package/dist/src/completion.js +68 -0
  196. package/dist/src/completion.test.d.ts +1 -0
  197. package/dist/src/completion.test.js +24 -0
  198. package/dist/src/constants.d.ts +18 -0
  199. package/dist/src/constants.js +41 -0
  200. package/dist/src/convention-audit.d.ts +50 -0
  201. package/dist/src/convention-audit.js +553 -0
  202. package/dist/src/convention-audit.test.d.ts +1 -0
  203. package/dist/src/convention-audit.test.js +255 -0
  204. package/dist/src/daemon/server.d.ts +13 -0
  205. package/dist/src/daemon/server.js +185 -0
  206. package/dist/src/daemon/server.test.d.ts +1 -0
  207. package/dist/src/daemon/server.test.js +132 -0
  208. package/dist/src/daemon-utils.d.ts +18 -0
  209. package/dist/src/daemon-utils.js +37 -0
  210. package/dist/src/daemon.d.ts +1 -0
  211. package/dist/src/daemon.js +27 -0
  212. package/dist/src/daemon.test.d.ts +1 -0
  213. package/dist/src/daemon.test.js +60 -0
  214. package/dist/src/discovery.d.ts +46 -0
  215. package/dist/src/discovery.js +341 -0
  216. package/dist/src/doctor.d.ts +39 -0
  217. package/dist/src/doctor.js +168 -0
  218. package/dist/src/doctor.test.d.ts +1 -0
  219. package/dist/src/doctor.test.js +302 -0
  220. package/dist/src/download/article-download.d.ts +72 -0
  221. package/dist/src/download/article-download.js +305 -0
  222. package/dist/src/download/article-download.test.d.ts +1 -0
  223. package/dist/src/download/article-download.test.js +235 -0
  224. package/dist/src/download/index.d.ts +71 -0
  225. package/dist/src/download/index.js +363 -0
  226. package/dist/src/download/index.test.d.ts +1 -0
  227. package/dist/src/download/index.test.js +174 -0
  228. package/dist/src/download/media-download.d.ts +49 -0
  229. package/dist/src/download/media-download.js +127 -0
  230. package/dist/src/download/media-download.test.d.ts +1 -0
  231. package/dist/src/download/media-download.test.js +112 -0
  232. package/dist/src/download/progress.d.ts +36 -0
  233. package/dist/src/download/progress.js +120 -0
  234. package/dist/src/download/progress.test.d.ts +1 -0
  235. package/dist/src/download/progress.test.js +36 -0
  236. package/dist/src/electron-apps.d.ts +31 -0
  237. package/dist/src/electron-apps.js +91 -0
  238. package/dist/src/electron-apps.test.d.ts +1 -0
  239. package/dist/src/electron-apps.test.js +76 -0
  240. package/dist/src/engine.test.d.ts +1 -0
  241. package/dist/src/engine.test.js +312 -0
  242. package/dist/src/errors.d.ts +114 -0
  243. package/dist/src/errors.js +174 -0
  244. package/dist/src/errors.test.d.ts +1 -0
  245. package/dist/src/errors.test.js +109 -0
  246. package/dist/src/execution.d.ts +24 -0
  247. package/dist/src/execution.js +509 -0
  248. package/dist/src/execution.test.d.ts +1 -0
  249. package/dist/src/execution.test.js +645 -0
  250. package/dist/src/external.d.ts +49 -0
  251. package/dist/src/external.js +211 -0
  252. package/dist/src/external.test.d.ts +1 -0
  253. package/dist/src/external.test.js +110 -0
  254. package/dist/src/help.d.ts +88 -0
  255. package/dist/src/help.js +556 -0
  256. package/dist/src/help.test.d.ts +1 -0
  257. package/dist/src/help.test.js +58 -0
  258. package/dist/src/hooks.d.ts +46 -0
  259. package/dist/src/hooks.js +58 -0
  260. package/dist/src/hooks.test.d.ts +4 -0
  261. package/dist/src/hooks.test.js +92 -0
  262. package/dist/src/interceptor.d.ts +44 -0
  263. package/dist/src/interceptor.js +183 -0
  264. package/dist/src/interceptor.test.d.ts +4 -0
  265. package/dist/src/interceptor.test.js +81 -0
  266. package/dist/src/launcher.d.ts +41 -0
  267. package/dist/src/launcher.js +226 -0
  268. package/dist/src/launcher.test.d.ts +1 -0
  269. package/dist/src/launcher.test.js +153 -0
  270. package/dist/src/logger.d.ts +26 -0
  271. package/dist/src/logger.js +49 -0
  272. package/dist/src/main.d.ts +5 -0
  273. package/dist/src/main.js +177 -0
  274. package/dist/src/manifest-types.d.ts +43 -0
  275. package/dist/src/manifest-types.js +9 -0
  276. package/dist/src/node-network.d.ts +10 -0
  277. package/dist/src/node-network.js +174 -0
  278. package/dist/src/node-network.test.d.ts +1 -0
  279. package/dist/src/node-network.test.js +55 -0
  280. package/dist/src/observation/artifact.d.ts +16 -0
  281. package/dist/src/observation/artifact.js +260 -0
  282. package/dist/src/observation/artifact.test.d.ts +1 -0
  283. package/dist/src/observation/artifact.test.js +121 -0
  284. package/dist/src/observation/events.d.ts +89 -0
  285. package/dist/src/observation/events.js +1 -0
  286. package/dist/src/observation/index.d.ts +7 -0
  287. package/dist/src/observation/index.js +7 -0
  288. package/dist/src/observation/manager.d.ts +9 -0
  289. package/dist/src/observation/manager.js +27 -0
  290. package/dist/src/observation/manager.test.d.ts +1 -0
  291. package/dist/src/observation/manager.test.js +13 -0
  292. package/dist/src/observation/redaction.d.ts +11 -0
  293. package/dist/src/observation/redaction.js +81 -0
  294. package/dist/src/observation/redaction.test.d.ts +1 -0
  295. package/dist/src/observation/redaction.test.js +32 -0
  296. package/dist/src/observation/retention.d.ts +32 -0
  297. package/dist/src/observation/retention.js +160 -0
  298. package/dist/src/observation/retention.test.d.ts +1 -0
  299. package/dist/src/observation/retention.test.js +118 -0
  300. package/dist/src/observation/ring-buffer.d.ts +22 -0
  301. package/dist/src/observation/ring-buffer.js +45 -0
  302. package/dist/src/observation/ring-buffer.test.d.ts +1 -0
  303. package/dist/src/observation/ring-buffer.test.js +22 -0
  304. package/dist/src/observation/session.d.ts +25 -0
  305. package/dist/src/observation/session.js +50 -0
  306. package/dist/src/output.d.ts +14 -0
  307. package/dist/src/output.js +152 -0
  308. package/dist/src/output.test.d.ts +1 -0
  309. package/dist/src/output.test.js +53 -0
  310. package/dist/src/package-exports.test.d.ts +1 -0
  311. package/dist/src/package-exports.test.js +112 -0
  312. package/dist/src/package-paths.d.ts +8 -0
  313. package/dist/src/package-paths.js +41 -0
  314. package/dist/src/pipeline/executor.d.ts +11 -0
  315. package/dist/src/pipeline/executor.js +93 -0
  316. package/dist/src/pipeline/executor.test.d.ts +4 -0
  317. package/dist/src/pipeline/executor.test.js +182 -0
  318. package/dist/src/pipeline/index.d.ts +5 -0
  319. package/dist/src/pipeline/index.js +5 -0
  320. package/dist/src/pipeline/registry.d.ts +28 -0
  321. package/dist/src/pipeline/registry.js +55 -0
  322. package/dist/src/pipeline/steps/browser.d.ts +13 -0
  323. package/dist/src/pipeline/steps/browser.js +86 -0
  324. package/dist/src/pipeline/steps/download.d.ts +18 -0
  325. package/dist/src/pipeline/steps/download.js +252 -0
  326. package/dist/src/pipeline/steps/download.test.d.ts +1 -0
  327. package/dist/src/pipeline/steps/download.test.js +102 -0
  328. package/dist/src/pipeline/steps/fetch.d.ts +5 -0
  329. package/dist/src/pipeline/steps/fetch.js +122 -0
  330. package/dist/src/pipeline/steps/fetch.test.d.ts +1 -0
  331. package/dist/src/pipeline/steps/fetch.test.js +117 -0
  332. package/dist/src/pipeline/steps/intercept.d.ts +5 -0
  333. package/dist/src/pipeline/steps/intercept.js +50 -0
  334. package/dist/src/pipeline/steps/tap.d.ts +12 -0
  335. package/dist/src/pipeline/steps/tap.js +93 -0
  336. package/dist/src/pipeline/steps/transform.d.ts +9 -0
  337. package/dist/src/pipeline/steps/transform.js +70 -0
  338. package/dist/src/pipeline/template.d.ts +17 -0
  339. package/dist/src/pipeline/template.js +344 -0
  340. package/dist/src/pipeline/template.test.d.ts +4 -0
  341. package/dist/src/pipeline/template.test.js +197 -0
  342. package/dist/src/pipeline/transform.test.d.ts +4 -0
  343. package/dist/src/pipeline/transform.test.js +133 -0
  344. package/dist/src/plugin-manifest.d.ts +70 -0
  345. package/dist/src/plugin-manifest.js +160 -0
  346. package/dist/src/plugin-manifest.test.d.ts +4 -0
  347. package/dist/src/plugin-manifest.test.js +179 -0
  348. package/dist/src/plugin-scaffold.d.ts +28 -0
  349. package/dist/src/plugin-scaffold.js +143 -0
  350. package/dist/src/plugin-scaffold.test.d.ts +4 -0
  351. package/dist/src/plugin-scaffold.test.js +83 -0
  352. package/dist/src/plugin.d.ts +146 -0
  353. package/dist/src/plugin.js +1303 -0
  354. package/dist/src/plugin.test.d.ts +4 -0
  355. package/dist/src/plugin.test.js +1363 -0
  356. package/dist/src/registry-api.d.ts +13 -0
  357. package/dist/src/registry-api.js +10 -0
  358. package/dist/src/registry.d.ts +123 -0
  359. package/dist/src/registry.js +125 -0
  360. package/dist/src/registry.test.d.ts +4 -0
  361. package/dist/src/registry.test.js +209 -0
  362. package/dist/src/runtime-copy.test.d.ts +1 -0
  363. package/dist/src/runtime-copy.test.js +29 -0
  364. package/dist/src/runtime-detect.d.ts +31 -0
  365. package/dist/src/runtime-detect.js +47 -0
  366. package/dist/src/runtime-detect.test.d.ts +1 -0
  367. package/dist/src/runtime-detect.test.js +39 -0
  368. package/dist/src/runtime-identity.test.d.ts +1 -0
  369. package/dist/src/runtime-identity.test.js +18 -0
  370. package/dist/src/runtime.d.ts +47 -0
  371. package/dist/src/runtime.js +54 -0
  372. package/dist/src/scripts/framework.d.ts +7 -0
  373. package/dist/src/scripts/framework.js +25 -0
  374. package/dist/src/scripts/interact.d.ts +4 -0
  375. package/dist/src/scripts/interact.js +20 -0
  376. package/dist/src/scripts/store.d.ts +13 -0
  377. package/dist/src/scripts/store.js +48 -0
  378. package/dist/src/serialization.d.ts +42 -0
  379. package/dist/src/serialization.js +103 -0
  380. package/dist/src/serialization.test.d.ts +1 -0
  381. package/dist/src/serialization.test.js +78 -0
  382. package/dist/src/skills.d.ts +14 -0
  383. package/dist/src/skills.js +127 -0
  384. package/dist/src/skills.test.d.ts +1 -0
  385. package/dist/src/skills.test.js +71 -0
  386. package/dist/src/snapshotFormatter.d.ts +11 -0
  387. package/dist/src/snapshotFormatter.js +338 -0
  388. package/dist/src/snapshotFormatter.test.d.ts +7 -0
  389. package/dist/src/snapshotFormatter.test.js +521 -0
  390. package/dist/src/tui.d.ts +28 -0
  391. package/dist/src/tui.js +179 -0
  392. package/dist/src/tui.test.d.ts +1 -0
  393. package/dist/src/tui.test.js +19 -0
  394. package/dist/src/types.d.ts +236 -0
  395. package/dist/src/types.js +7 -0
  396. package/dist/src/update-check.d.ts +66 -0
  397. package/dist/src/update-check.js +206 -0
  398. package/dist/src/update-check.test.d.ts +1 -0
  399. package/dist/src/update-check.test.js +117 -0
  400. package/dist/src/utils.d.ts +57 -0
  401. package/dist/src/utils.js +152 -0
  402. package/dist/src/utils.test.d.ts +1 -0
  403. package/dist/src/utils.test.js +155 -0
  404. package/dist/src/validate.d.ts +21 -0
  405. package/dist/src/validate.js +130 -0
  406. package/dist/src/validate.test.d.ts +9 -0
  407. package/dist/src/validate.test.js +90 -0
  408. package/dist/src/verify.d.ts +26 -0
  409. package/dist/src/verify.js +67 -0
  410. package/dist/src/version.d.ts +4 -0
  411. package/dist/src/version.js +22 -0
  412. package/dist/src/weixin-download.test.d.ts +1 -0
  413. package/dist/src/weixin-download.test.js +45 -0
  414. package/package.json +4 -3
  415. package/scripts/check-package-bin.mjs +95 -0
@@ -0,0 +1,536 @@
1
+ /**
2
+ * CDP client — implements IPage by connecting directly to a Chrome/Electron CDP WebSocket.
3
+ *
4
+ * Fixes applied:
5
+ * - send() now has a 30s timeout guard (P0 #4)
6
+ * - goto() waits for Page.loadEventFired instead of hardcoded 1s sleep (P1 #3)
7
+ * - Implemented scroll, autoScroll, screenshot, networkRequests (P1 #2)
8
+ * - Shared DOM helper methods extracted to reduce duplication with Page (P1 #5)
9
+ */
10
+ import { WebSocket } from 'ws';
11
+ import { request as httpRequest } from 'node:http';
12
+ import { request as httpsRequest } from 'node:https';
13
+ import { buildEvaluateExpression } from './utils.js';
14
+ import { generateStealthJs } from './stealth.js';
15
+ import { waitForDomStableJs } from './dom-helpers.js';
16
+ import { isRecord, saveBase64ToFile } from '../utils.js';
17
+ import { getAllElectronApps } from '../electron-apps.js';
18
+ import { BasePage } from './base-page.js';
19
+ const CDP_SEND_TIMEOUT = 30_000;
20
+ // Memory guard for in-process capture. The 4k cap we used to apply everywhere
21
+ // silently truncated JSON so `JSON.parse` failed or gave partial objects — the
22
+ // primary agent-facing bug. Now we keep the full body up to a large cap and
23
+ // surface `responseBodyFullSize` + `responseBodyTruncated` so downstream layers
24
+ // can tell the agent what happened instead of lying about the payload.
25
+ export const CDP_RESPONSE_BODY_CAPTURE_LIMIT = 8 * 1024 * 1024;
26
+ export class CDPBridge {
27
+ _ws = null;
28
+ _idCounter = 0;
29
+ _pending = new Map();
30
+ _eventListeners = new Map();
31
+ async connect(opts) {
32
+ if (this._ws)
33
+ throw new Error('CDPBridge is already connected. Call close() before reconnecting.');
34
+ const endpoint = opts?.cdpEndpoint ?? process.env.WEBCMD_CDP_ENDPOINT;
35
+ if (!endpoint)
36
+ throw new Error('CDP endpoint not provided (pass cdpEndpoint or set WEBCMD_CDP_ENDPOINT)');
37
+ let wsUrl = endpoint;
38
+ if (endpoint.startsWith('http')) {
39
+ const targets = await fetchJsonDirect(`${endpoint.replace(/\/$/, '')}/json`);
40
+ const target = selectCDPTarget(targets);
41
+ if (!target || !target.webSocketDebuggerUrl) {
42
+ throw new Error('No inspectable targets found at CDP endpoint');
43
+ }
44
+ wsUrl = target.webSocketDebuggerUrl;
45
+ }
46
+ return new Promise((resolve, reject) => {
47
+ const ws = new WebSocket(wsUrl);
48
+ const timeoutMs = (opts?.timeout ?? 10) * 1000;
49
+ const timeout = setTimeout(() => {
50
+ this._ws = null;
51
+ ws.close();
52
+ reject(new Error('CDP connect timeout'));
53
+ }, timeoutMs);
54
+ ws.on('open', async () => {
55
+ clearTimeout(timeout);
56
+ this._ws = ws;
57
+ try {
58
+ await this.send('Page.enable');
59
+ await this.send('Page.addScriptToEvaluateOnNewDocument', { source: generateStealthJs() });
60
+ }
61
+ catch (err) {
62
+ ws.close();
63
+ reject(err instanceof Error ? err : new Error(String(err)));
64
+ return;
65
+ }
66
+ resolve(new CDPPage(this));
67
+ });
68
+ ws.on('error', (err) => {
69
+ clearTimeout(timeout);
70
+ reject(err);
71
+ });
72
+ ws.on('message', (data) => {
73
+ try {
74
+ const msg = JSON.parse(data.toString());
75
+ if (msg.id && this._pending.has(msg.id)) {
76
+ const entry = this._pending.get(msg.id);
77
+ clearTimeout(entry.timer);
78
+ this._pending.delete(msg.id);
79
+ if (msg.error) {
80
+ entry.reject(new Error(msg.error.message));
81
+ }
82
+ else {
83
+ entry.resolve(msg.result);
84
+ }
85
+ }
86
+ if (msg.method) {
87
+ const listeners = this._eventListeners.get(msg.method);
88
+ if (listeners) {
89
+ for (const fn of listeners)
90
+ fn(msg.params);
91
+ }
92
+ }
93
+ }
94
+ catch (err) {
95
+ if (process.env.WEBCMD_VERBOSE) {
96
+ // eslint-disable-next-line no-console
97
+ console.error('[cdp] Failed to parse WebSocket message:', err instanceof Error ? err.message : err);
98
+ }
99
+ }
100
+ });
101
+ });
102
+ }
103
+ async close() {
104
+ if (this._ws) {
105
+ this._ws.close();
106
+ this._ws = null;
107
+ }
108
+ for (const p of this._pending.values()) {
109
+ clearTimeout(p.timer);
110
+ p.reject(new Error('CDP connection closed'));
111
+ }
112
+ this._pending.clear();
113
+ this._eventListeners.clear();
114
+ }
115
+ async send(method, params = {}, timeoutMs = CDP_SEND_TIMEOUT) {
116
+ if (!this._ws || this._ws.readyState !== WebSocket.OPEN) {
117
+ throw new Error('CDP connection is not open');
118
+ }
119
+ const id = ++this._idCounter;
120
+ return new Promise((resolve, reject) => {
121
+ const timer = setTimeout(() => {
122
+ this._pending.delete(id);
123
+ reject(new Error(`CDP command '${method}' timed out after ${timeoutMs / 1000}s`));
124
+ }, timeoutMs);
125
+ this._pending.set(id, { resolve, reject, timer });
126
+ this._ws.send(JSON.stringify({ id, method, params }));
127
+ });
128
+ }
129
+ on(event, handler) {
130
+ let set = this._eventListeners.get(event);
131
+ if (!set) {
132
+ set = new Set();
133
+ this._eventListeners.set(event, set);
134
+ }
135
+ set.add(handler);
136
+ }
137
+ off(event, handler) {
138
+ this._eventListeners.get(event)?.delete(handler);
139
+ }
140
+ waitForEvent(event, timeoutMs = 15_000) {
141
+ return new Promise((resolve, reject) => {
142
+ const timer = setTimeout(() => {
143
+ this.off(event, handler);
144
+ reject(new Error(`Timed out waiting for CDP event '${event}'`));
145
+ }, timeoutMs);
146
+ const handler = (params) => {
147
+ clearTimeout(timer);
148
+ this.off(event, handler);
149
+ resolve(params);
150
+ };
151
+ this.on(event, handler);
152
+ });
153
+ }
154
+ }
155
+ class CDPPage extends BasePage {
156
+ bridge;
157
+ _pageEnabled = false;
158
+ // Network capture state (mirrors extension/src/cdp.ts NetworkCaptureEntry shape)
159
+ _networkCapturing = false;
160
+ _networkCapturePattern = '';
161
+ _networkEntries = [];
162
+ _pendingRequests = new Map(); // requestId → index in _networkEntries
163
+ _pendingBodyFetches = new Set(); // track in-flight getResponseBody calls
164
+ _consoleMessages = [];
165
+ _consoleCapturing = false;
166
+ constructor(bridge) {
167
+ super();
168
+ this.bridge = bridge;
169
+ }
170
+ async goto(url, options) {
171
+ if (!this._pageEnabled) {
172
+ await this.bridge.send('Page.enable');
173
+ this._pageEnabled = true;
174
+ }
175
+ const loadPromise = this.bridge.waitForEvent('Page.loadEventFired', 30_000).catch(() => { });
176
+ await this.bridge.send('Page.navigate', { url });
177
+ await loadPromise;
178
+ this._lastUrl = url;
179
+ if (options?.waitUntil !== 'none') {
180
+ const maxMs = options?.settleMs ?? 1000;
181
+ await this.evaluate(waitForDomStableJs(maxMs, Math.min(500, maxMs)));
182
+ }
183
+ }
184
+ async evaluate(input, ...args) {
185
+ const expression = buildEvaluateExpression(input, args);
186
+ const result = await this.bridge.send('Runtime.evaluate', {
187
+ expression,
188
+ returnByValue: true,
189
+ awaitPromise: true,
190
+ });
191
+ if (result.exceptionDetails) {
192
+ throw new Error('Evaluate error: ' + (result.exceptionDetails.exception?.description || 'Unknown exception'));
193
+ }
194
+ return result.result?.value;
195
+ }
196
+ async getCookies(opts = {}) {
197
+ const result = await this.bridge.send('Network.getCookies', opts.url ? { urls: [opts.url] } : {});
198
+ const cookies = isRecord(result) && Array.isArray(result.cookies) ? result.cookies : [];
199
+ const domain = opts.domain;
200
+ return domain
201
+ ? cookies.filter((cookie) => isCookie(cookie) && matchesCookieDomain(cookie.domain, domain))
202
+ : cookies;
203
+ }
204
+ async screenshot(options = {}) {
205
+ const fullPage = options.fullPage === true;
206
+ const overrideWidth = options.width && options.width > 0 ? Math.ceil(options.width) : undefined;
207
+ // height is ignored under fullPage so the captureBeyondViewport path stays unchanged for users who pass --height alongside --full-page.
208
+ const overrideHeight = !fullPage && options.height && options.height > 0 ? Math.ceil(options.height) : undefined;
209
+ const needsOverride = overrideWidth !== undefined || overrideHeight !== undefined;
210
+ if (needsOverride) {
211
+ if (overrideWidth !== undefined && fullPage) {
212
+ await this.bridge.send('Emulation.setDeviceMetricsOverride', {
213
+ mobile: false,
214
+ width: overrideWidth,
215
+ height: 0,
216
+ deviceScaleFactor: 1,
217
+ });
218
+ }
219
+ let finalWidth = overrideWidth ?? 0;
220
+ let finalHeight = overrideHeight ?? 0;
221
+ if (fullPage) {
222
+ const metrics = await this.bridge.send('Page.getLayoutMetrics');
223
+ const m = isRecord(metrics) ? metrics : {};
224
+ const css = isRecord(m.cssContentSize) ? m.cssContentSize : undefined;
225
+ const fb = isRecord(m.contentSize) ? m.contentSize : undefined;
226
+ const size = css ?? fb;
227
+ if (size && typeof size.width === 'number' && typeof size.height === 'number') {
228
+ if (finalWidth === 0)
229
+ finalWidth = Math.ceil(size.width);
230
+ finalHeight = Math.ceil(size.height);
231
+ }
232
+ }
233
+ await this.bridge.send('Emulation.setDeviceMetricsOverride', {
234
+ mobile: false,
235
+ width: finalWidth,
236
+ height: finalHeight,
237
+ deviceScaleFactor: 1,
238
+ });
239
+ }
240
+ try {
241
+ const result = await this.bridge.send('Page.captureScreenshot', {
242
+ format: options.format ?? 'png',
243
+ quality: options.format === 'jpeg' ? (options.quality ?? 80) : undefined,
244
+ captureBeyondViewport: !needsOverride && fullPage,
245
+ });
246
+ const base64 = isRecord(result) && typeof result.data === 'string' ? result.data : '';
247
+ if (options.path) {
248
+ await saveBase64ToFile(base64, options.path);
249
+ }
250
+ return base64;
251
+ }
252
+ finally {
253
+ if (needsOverride) {
254
+ await this.bridge.send('Emulation.clearDeviceMetricsOverride').catch(() => { });
255
+ }
256
+ }
257
+ }
258
+ async startNetworkCapture(pattern = '') {
259
+ // Always update the filter pattern
260
+ this._networkCapturePattern = pattern;
261
+ // Reset state only on first start; avoid wiping entries if already capturing
262
+ if (!this._networkCapturing) {
263
+ this._networkEntries = [];
264
+ this._pendingRequests.clear();
265
+ this._pendingBodyFetches.clear();
266
+ await this.bridge.send('Network.enable');
267
+ // Step 1: Record request method/url on requestWillBeSent
268
+ this.bridge.on('Network.requestWillBeSent', (params) => {
269
+ const p = params;
270
+ if (!this._networkCapturePattern || p.request.url.includes(this._networkCapturePattern)) {
271
+ const idx = this._networkEntries.push({
272
+ url: p.request.url,
273
+ method: p.request.method,
274
+ timestamp: Date.now(),
275
+ }) - 1;
276
+ this._pendingRequests.set(p.requestId, idx);
277
+ }
278
+ });
279
+ // Step 2: Fill in response metadata on responseReceived
280
+ this.bridge.on('Network.responseReceived', (params) => {
281
+ const p = params;
282
+ const idx = this._pendingRequests.get(p.requestId);
283
+ if (idx !== undefined) {
284
+ this._networkEntries[idx].responseStatus = p.response.status;
285
+ this._networkEntries[idx].responseContentType = p.response.mimeType || '';
286
+ }
287
+ });
288
+ // Step 3: Fetch body on loadingFinished (body is only reliably available after this)
289
+ this.bridge.on('Network.loadingFinished', (params) => {
290
+ const p = params;
291
+ const idx = this._pendingRequests.get(p.requestId);
292
+ if (idx !== undefined) {
293
+ const bodyFetch = this.bridge.send('Network.getResponseBody', { requestId: p.requestId }).then((result) => {
294
+ const r = result;
295
+ if (typeof r?.body === 'string') {
296
+ const fullSize = r.body.length;
297
+ const truncated = fullSize > CDP_RESPONSE_BODY_CAPTURE_LIMIT;
298
+ const body = truncated ? r.body.slice(0, CDP_RESPONSE_BODY_CAPTURE_LIMIT) : r.body;
299
+ this._networkEntries[idx].responsePreview = r.base64Encoded ? `base64:${body}` : body;
300
+ this._networkEntries[idx].responseBodyFullSize = fullSize;
301
+ this._networkEntries[idx].responseBodyTruncated = truncated;
302
+ }
303
+ }).catch((err) => {
304
+ // Body unavailable for some requests (e.g. uploads) — non-fatal
305
+ if (process.env.WEBCMD_VERBOSE) {
306
+ // eslint-disable-next-line no-console
307
+ console.error(`[cdp] getResponseBody failed for ${p.requestId}:`, err instanceof Error ? err.message : err);
308
+ }
309
+ }).finally(() => {
310
+ this._pendingBodyFetches.delete(bodyFetch);
311
+ });
312
+ this._pendingBodyFetches.add(bodyFetch);
313
+ this._pendingRequests.delete(p.requestId);
314
+ }
315
+ });
316
+ this._networkCapturing = true;
317
+ }
318
+ return true;
319
+ }
320
+ async readNetworkCapture() {
321
+ // Await all in-flight body fetches so entries have responsePreview populated
322
+ if (this._pendingBodyFetches.size > 0) {
323
+ await Promise.all([...this._pendingBodyFetches]);
324
+ }
325
+ const entries = [...this._networkEntries];
326
+ this._networkEntries = [];
327
+ return entries;
328
+ }
329
+ async consoleMessages(level = 'all') {
330
+ if (!this._consoleCapturing) {
331
+ await this.bridge.send('Runtime.enable');
332
+ this.bridge.on('Runtime.consoleAPICalled', (params) => {
333
+ const p = params;
334
+ const text = (p.args || []).map(a => a.value !== undefined ? String(a.value) : (a.description || '')).join(' ');
335
+ this._consoleMessages.push({ type: p.type, text, timestamp: Date.now() });
336
+ if (this._consoleMessages.length > 500)
337
+ this._consoleMessages.shift();
338
+ });
339
+ // Capture uncaught exceptions as error-level messages
340
+ this.bridge.on('Runtime.exceptionThrown', (params) => {
341
+ const p = params;
342
+ const desc = p.exceptionDetails?.exception?.description || p.exceptionDetails?.text || 'Unknown exception';
343
+ this._consoleMessages.push({ type: 'error', text: desc, timestamp: Date.now() });
344
+ if (this._consoleMessages.length > 500)
345
+ this._consoleMessages.shift();
346
+ });
347
+ this._consoleCapturing = true;
348
+ }
349
+ if (level === 'all')
350
+ return [...this._consoleMessages];
351
+ // 'error' level includes both console.error() and uncaught exceptions
352
+ if (level === 'error')
353
+ return this._consoleMessages.filter(m => m.type === 'error' || m.type === 'warning');
354
+ return this._consoleMessages.filter(m => m.type === level);
355
+ }
356
+ async tabs() {
357
+ return [];
358
+ }
359
+ async selectTab(_target) {
360
+ // Not supported in direct CDP mode
361
+ }
362
+ async cdp(method, params = {}) {
363
+ return this.bridge.send(method, params);
364
+ }
365
+ async handleJavaScriptDialog(accept, promptText) {
366
+ await this.cdp('Page.handleJavaScriptDialog', {
367
+ accept,
368
+ ...(promptText !== undefined && { promptText }),
369
+ });
370
+ }
371
+ async nativeClick(x, y) {
372
+ await this.cdp('Input.dispatchMouseEvent', {
373
+ type: 'mouseMoved',
374
+ x,
375
+ y,
376
+ });
377
+ await this.cdp('Input.dispatchMouseEvent', {
378
+ type: 'mousePressed',
379
+ x,
380
+ y,
381
+ button: 'left',
382
+ clickCount: 1,
383
+ });
384
+ await this.cdp('Input.dispatchMouseEvent', {
385
+ type: 'mouseReleased',
386
+ x,
387
+ y,
388
+ button: 'left',
389
+ clickCount: 1,
390
+ });
391
+ }
392
+ async nativeType(text) {
393
+ await this.cdp('Input.insertText', { text });
394
+ }
395
+ async insertText(text) {
396
+ await this.nativeType(text);
397
+ }
398
+ async nativeKeyPress(key, modifiers = []) {
399
+ let modifierFlags = 0;
400
+ for (const mod of modifiers) {
401
+ if (mod === 'Alt')
402
+ modifierFlags |= 1;
403
+ if (mod === 'Ctrl' || mod === 'Control')
404
+ modifierFlags |= 2;
405
+ if (mod === 'Meta')
406
+ modifierFlags |= 4;
407
+ if (mod === 'Shift')
408
+ modifierFlags |= 8;
409
+ }
410
+ await this.cdp('Input.dispatchKeyEvent', {
411
+ type: 'keyDown',
412
+ key,
413
+ modifiers: modifierFlags,
414
+ });
415
+ await this.cdp('Input.dispatchKeyEvent', {
416
+ type: 'keyUp',
417
+ key,
418
+ modifiers: modifierFlags,
419
+ });
420
+ }
421
+ }
422
+ function isCookie(value) {
423
+ return isRecord(value)
424
+ && typeof value.name === 'string'
425
+ && typeof value.value === 'string'
426
+ && typeof value.domain === 'string';
427
+ }
428
+ function matchesCookieDomain(cookieDomain, targetDomain) {
429
+ const normalizedCookieDomain = cookieDomain.replace(/^\./, '').toLowerCase();
430
+ const normalizedTargetDomain = targetDomain.replace(/^\./, '').toLowerCase();
431
+ return normalizedTargetDomain === normalizedCookieDomain
432
+ || normalizedTargetDomain.endsWith(`.${normalizedCookieDomain}`);
433
+ }
434
+ function selectCDPTarget(targets) {
435
+ const preferredPattern = compilePreferredPattern(process.env.WEBCMD_CDP_TARGET);
436
+ const ranked = targets
437
+ .map((target, index) => ({ target, index, score: scoreCDPTarget(target, preferredPattern) }))
438
+ .filter(({ score }) => Number.isFinite(score))
439
+ .sort((a, b) => {
440
+ if (b.score !== a.score)
441
+ return b.score - a.score;
442
+ return a.index - b.index;
443
+ });
444
+ return ranked[0]?.target;
445
+ }
446
+ function scoreCDPTarget(target, preferredPattern) {
447
+ if (!target.webSocketDebuggerUrl)
448
+ return Number.NEGATIVE_INFINITY;
449
+ const type = (target.type ?? '').toLowerCase();
450
+ const url = (target.url ?? '').toLowerCase();
451
+ const title = (target.title ?? '').toLowerCase();
452
+ const haystack = `${title} ${url}`;
453
+ if (!haystack.trim() && !type)
454
+ return Number.NEGATIVE_INFINITY;
455
+ if (haystack.includes('devtools'))
456
+ return Number.NEGATIVE_INFINITY;
457
+ if (type === 'background_page' || type === 'service_worker')
458
+ return Number.NEGATIVE_INFINITY;
459
+ let score = 0;
460
+ if (preferredPattern && preferredPattern.test(haystack))
461
+ score += 1000;
462
+ if (type === 'app')
463
+ score += 120;
464
+ else if (type === 'webview')
465
+ score += 100;
466
+ else if (type === 'page')
467
+ score += 80;
468
+ else if (type === 'iframe')
469
+ score += 20;
470
+ if (url.startsWith('http://localhost') || url.startsWith('https://localhost'))
471
+ score += 90;
472
+ if (url.startsWith('file://'))
473
+ score += 60;
474
+ if (url.startsWith('http://127.0.0.1') || url.startsWith('https://127.0.0.1'))
475
+ score += 50;
476
+ if (url.startsWith('about:blank'))
477
+ score -= 120;
478
+ if (url === '' || url === 'about:blank')
479
+ score -= 40;
480
+ if (title && title !== 'devtools')
481
+ score += 25;
482
+ // Boost score for known Electron app names from the registry (builtin + user-defined)
483
+ const appNames = Object.values(getAllElectronApps()).map(a => (a.displayName ?? a.processName).toLowerCase());
484
+ for (const name of appNames) {
485
+ if (title.includes(name)) {
486
+ score += 120;
487
+ break;
488
+ }
489
+ }
490
+ for (const name of appNames) {
491
+ if (url.includes(name)) {
492
+ score += 100;
493
+ break;
494
+ }
495
+ }
496
+ return score;
497
+ }
498
+ function compilePreferredPattern(raw) {
499
+ const value = raw?.trim();
500
+ if (!value)
501
+ return undefined;
502
+ return new RegExp(escapeRegExp(value.toLowerCase()));
503
+ }
504
+ function escapeRegExp(value) {
505
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
506
+ }
507
+ export const __test__ = {
508
+ selectCDPTarget,
509
+ scoreCDPTarget,
510
+ };
511
+ function fetchJsonDirect(url) {
512
+ return new Promise((resolve, reject) => {
513
+ const parsed = new URL(url);
514
+ const request = (parsed.protocol === 'https:' ? httpsRequest : httpRequest)(parsed, (res) => {
515
+ const statusCode = res.statusCode ?? 0;
516
+ if (statusCode < 200 || statusCode >= 300) {
517
+ res.resume();
518
+ reject(new Error(`Failed to fetch CDP targets: HTTP ${statusCode}`));
519
+ return;
520
+ }
521
+ const chunks = [];
522
+ res.on('data', (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
523
+ res.on('end', () => {
524
+ try {
525
+ resolve(JSON.parse(Buffer.concat(chunks).toString('utf8')));
526
+ }
527
+ catch (error) {
528
+ reject(error instanceof Error ? error : new Error(String(error)));
529
+ }
530
+ });
531
+ });
532
+ request.on('error', reject);
533
+ request.setTimeout(10_000, () => request.destroy(new Error('Timed out fetching CDP targets')));
534
+ request.end();
535
+ });
536
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,79 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+ const { MockWebSocket } = vi.hoisted(() => {
3
+ class MockWebSocket {
4
+ static OPEN = 1;
5
+ readyState = 1;
6
+ handlers = new Map();
7
+ constructor(_url) {
8
+ queueMicrotask(() => this.emit('open'));
9
+ }
10
+ on(event, handler) {
11
+ const handlers = this.handlers.get(event) ?? [];
12
+ handlers.push(handler);
13
+ this.handlers.set(event, handlers);
14
+ }
15
+ send(_message) { }
16
+ close() {
17
+ this.readyState = 3;
18
+ }
19
+ emit(event, ...args) {
20
+ for (const handler of this.handlers.get(event) ?? []) {
21
+ handler(...args);
22
+ }
23
+ }
24
+ }
25
+ return { MockWebSocket };
26
+ });
27
+ vi.mock('ws', () => ({
28
+ WebSocket: MockWebSocket,
29
+ }));
30
+ import { CDPBridge } from './cdp.js';
31
+ describe('CDPBridge cookies', () => {
32
+ beforeEach(() => {
33
+ vi.unstubAllEnvs();
34
+ });
35
+ it('filters cookies by actual domain match instead of substring match', async () => {
36
+ vi.stubEnv('WEBCMD_CDP_ENDPOINT', 'ws://127.0.0.1:9222/devtools/page/1');
37
+ const bridge = new CDPBridge();
38
+ vi.spyOn(bridge, 'send').mockResolvedValue({
39
+ cookies: [
40
+ { name: 'good', value: '1', domain: '.example.com' },
41
+ { name: 'exact', value: '2', domain: 'example.com' },
42
+ { name: 'bad', value: '3', domain: 'notexample.com' },
43
+ ],
44
+ });
45
+ const page = await bridge.connect();
46
+ const cookies = await page.getCookies({ domain: 'example.com' });
47
+ expect(cookies).toEqual([
48
+ { name: 'good', value: '1', domain: '.example.com' },
49
+ { name: 'exact', value: '2', domain: 'example.com' },
50
+ ]);
51
+ });
52
+ it('exposes native input helpers on direct CDP pages', async () => {
53
+ vi.stubEnv('WEBCMD_CDP_ENDPOINT', 'ws://127.0.0.1:9222/devtools/page/1');
54
+ const bridge = new CDPBridge();
55
+ const send = vi.spyOn(bridge, 'send').mockResolvedValue({});
56
+ const page = await bridge.connect();
57
+ send.mockClear();
58
+ expect(page.nativeType).toBeTypeOf('function');
59
+ expect(page.nativeKeyPress).toBeTypeOf('function');
60
+ expect(page.nativeClick).toBeTypeOf('function');
61
+ expect(page.handleJavaScriptDialog).toBeTypeOf('function');
62
+ expect(page.cdp).toBeTypeOf('function');
63
+ await page.nativeType('hello');
64
+ await page.nativeKeyPress('a', ['Ctrl']);
65
+ await page.nativeClick(10, 20);
66
+ await page.handleJavaScriptDialog(true, 'ok');
67
+ await page.cdp('Page.getLayoutMetrics', {});
68
+ expect(send.mock.calls).toEqual([
69
+ ['Input.insertText', { text: 'hello' }],
70
+ ['Input.dispatchKeyEvent', { type: 'keyDown', key: 'a', modifiers: 2 }],
71
+ ['Input.dispatchKeyEvent', { type: 'keyUp', key: 'a', modifiers: 2 }],
72
+ ['Input.dispatchMouseEvent', { type: 'mouseMoved', x: 10, y: 20 }],
73
+ ['Input.dispatchMouseEvent', { type: 'mousePressed', x: 10, y: 20, button: 'left', clickCount: 1 }],
74
+ ['Input.dispatchMouseEvent', { type: 'mouseReleased', x: 10, y: 20, button: 'left', clickCount: 1 }],
75
+ ['Page.handleJavaScriptDialog', { accept: true, promptText: 'ok' }],
76
+ ['Page.getLayoutMetrics', {}],
77
+ ]);
78
+ });
79
+ });
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Compound-component expansion for high-agent-failure form controls.
3
+ *
4
+ * Agents burn turns on three recurring input categories because the raw
5
+ * attribute dump from `browser state` under-specifies them:
6
+ *
7
+ * - date / time / datetime-local / month / week — agents type
8
+ * free-form strings and the browser silently ignores mismatched formats.
9
+ * - select — the snapshot caps visible options at ~6; agents don't know
10
+ * the full option set, can't match by label, and waste turns clicking
11
+ * to open the dropdown just to read options.
12
+ * - file — the snapshot shows current filenames but not `accept` or
13
+ * `multiple`; agents re-upload or pick unsupported MIME types.
14
+ *
15
+ * `compoundInfoOf(el)` returns a structured JSON summary agents can rely
16
+ * on. Included in `browser find --css` envelope so the agent gets the
17
+ * rich view without extra round-trips.
18
+ *
19
+ * Emitted as a JS source string (`COMPOUND_INFO_JS`) so it can be inlined
20
+ * into the generated evaluate scripts under find / snapshot / eval.
21
+ */
22
+ export type DateLikeControl = 'date' | 'time' | 'datetime-local' | 'month' | 'week';
23
+ export interface DateCompound {
24
+ control: DateLikeControl;
25
+ format: string;
26
+ current: string;
27
+ min?: string;
28
+ max?: string;
29
+ }
30
+ export interface SelectOption {
31
+ label: string;
32
+ value: string;
33
+ selected: boolean;
34
+ disabled?: boolean;
35
+ }
36
+ export interface SelectCompound {
37
+ control: 'select';
38
+ multiple: boolean;
39
+ current: string | string[];
40
+ options: SelectOption[];
41
+ options_total: number;
42
+ }
43
+ export interface FileCompound {
44
+ control: 'file';
45
+ multiple: boolean;
46
+ current: string[];
47
+ accept?: string;
48
+ }
49
+ export type CompoundInfo = DateCompound | SelectCompound | FileCompound;
50
+ /** Max options included in a SelectCompound.options[]. Above this, `options_total` still reflects the true count. */
51
+ export declare const COMPOUND_SELECT_OPTIONS_CAP = 50;
52
+ /** Max characters per option label / file name. */
53
+ export declare const COMPOUND_LABEL_CAP = 80;
54
+ /**
55
+ * JavaScript source declaring `compoundInfoOf(el)`. Inlined into the JS
56
+ * emitted by `buildFindJs` (and any other evaluate script that needs the
57
+ * rich compound view). Returns a `CompoundInfo` object or `null`.
58
+ */
59
+ export declare const COMPOUND_INFO_JS = "\nfunction compoundInfoOf(el) {\n if (!el || !el.tagName) return null;\n const tag = el.tagName;\n const LABEL_CAP = 80;\n const OPTS_CAP = 50;\n if (tag === 'INPUT') {\n const type = (el.getAttribute('type') || 'text').toLowerCase();\n const FORMATS = {\n 'date': 'YYYY-MM-DD',\n 'time': 'HH:MM',\n 'datetime-local': 'YYYY-MM-DDTHH:MM',\n 'month': 'YYYY-MM',\n 'week': 'YYYY-W##',\n };\n if (FORMATS[type]) {\n const info = {\n control: type,\n format: FORMATS[type],\n current: (el.value == null ? '' : String(el.value)),\n };\n const min = el.getAttribute('min');\n if (min) info.min = min;\n const max = el.getAttribute('max');\n if (max) info.max = max;\n return info;\n }\n if (type === 'file') {\n const info = {\n control: 'file',\n multiple: !!el.multiple,\n current: [],\n };\n const accept = el.getAttribute('accept');\n if (accept) info.accept = accept;\n try {\n if (el.files && el.files.length) {\n for (let i = 0; i < el.files.length; i++) {\n const name = (el.files[i].name || '').slice(0, LABEL_CAP);\n info.current.push(name);\n }\n }\n } catch (_) {}\n return info;\n }\n return null;\n }\n if (tag === 'SELECT') {\n const multiple = !!el.multiple;\n const options = [];\n const selectedLabels = [];\n let total = 0;\n try {\n const opts = el.options || [];\n total = opts.length;\n // Walk ALL options so `current` reflects selections that sit beyond the\n // serialization cap. Only the first OPTS_CAP entries get pushed into\n // options[]; anything past the cap still contributes to selectedLabels\n // so agents see the true current state of big dropdowns.\n for (let i = 0; i < opts.length; i++) {\n const o = opts[i];\n const labelRaw = (o.label != null && o.label !== '') ? o.label : (o.text || '');\n const label = String(labelRaw).trim().slice(0, LABEL_CAP);\n if (i < OPTS_CAP) {\n const entry = { label: label, value: o.value, selected: !!o.selected };\n if (o.disabled) entry.disabled = true;\n options.push(entry);\n }\n if (o.selected) selectedLabels.push(label);\n }\n } catch (_) {}\n return {\n control: 'select',\n multiple: multiple,\n current: multiple ? selectedLabels : (selectedLabels[0] || ''),\n options: options,\n options_total: total,\n };\n }\n return null;\n}\n";