@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,255 @@
1
+ import { afterEach, describe, expect, it } from 'vitest';
2
+ import * as fs from 'node:fs';
3
+ import * as os from 'node:os';
4
+ import * as path from 'node:path';
5
+ import { renderConventionAuditText, runConventionAudit } from './convention-audit.js';
6
+ describe('convention audit', () => {
7
+ const tempDirs = [];
8
+ afterEach(() => {
9
+ for (const dir of tempDirs.splice(0)) {
10
+ fs.rmSync(dir, { recursive: true, force: true });
11
+ }
12
+ });
13
+ function makeProject(manifest, files) {
14
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'webcmd-convention-audit-'));
15
+ tempDirs.push(root);
16
+ fs.mkdirSync(path.join(root, 'clis'), { recursive: true });
17
+ fs.writeFileSync(path.join(root, 'cli-manifest.json'), JSON.stringify(manifest, null, 2));
18
+ for (const [relative, content] of Object.entries(files)) {
19
+ const file = path.join(root, 'clis', relative);
20
+ fs.mkdirSync(path.dirname(file), { recursive: true });
21
+ fs.writeFileSync(file, content);
22
+ }
23
+ return root;
24
+ }
25
+ it('reports column, metadata, typed-error, and write-pair violations', () => {
26
+ const root = makeProject([
27
+ {
28
+ site: 'demo',
29
+ name: 'search',
30
+ access: 'read',
31
+ columns: ['id', 'title', 'authorName'],
32
+ sourceFile: 'demo/search.js',
33
+ },
34
+ {
35
+ site: 'demo',
36
+ name: 'like',
37
+ access: 'write',
38
+ sourceFile: 'demo/like.js',
39
+ },
40
+ {
41
+ site: 'demo',
42
+ name: 'missing',
43
+ columns: [],
44
+ sourceFile: 'demo/missing.js',
45
+ },
46
+ {
47
+ site: 'clean',
48
+ name: 'search',
49
+ access: 'read',
50
+ columns: ['id', 'title'],
51
+ sourceFile: 'clean/search.js',
52
+ },
53
+ ], {
54
+ 'demo/search.js': `
55
+ export async function run(kwargs) {
56
+ const limit = Math.min(kwargs.limit, 100);
57
+ try {
58
+ await fetch('/items');
59
+ } catch {
60
+ return [];
61
+ }
62
+ rows.push({
63
+ id: item.id,
64
+ title: item.title ?? 'unknown',
65
+ url: item.url,
66
+ authorName: item.authorName,
67
+ });
68
+ return limit;
69
+ }
70
+ `,
71
+ 'demo/like.js': 'export async function run() { return { ok: true }; }',
72
+ 'demo/missing.js': 'export async function run() { return { ok: true }; }',
73
+ 'clean/search.js': 'export async function run() { rows.push({ id: item.id, title: item.title }); }',
74
+ });
75
+ const report = runConventionAudit({ projectRoot: root });
76
+ const category = (rule) => report.categories.find((item) => item.rule === rule);
77
+ expect(report.ok).toBe(false);
78
+ expect(category('silent-column-drop').violations[0]).toMatchObject({
79
+ command: 'demo/search',
80
+ details: expect.objectContaining({ missing: ['url'] }),
81
+ });
82
+ expect(category('camelCase-in-columns').violations[0]).toMatchObject({
83
+ command: 'demo/search',
84
+ details: { column: 'authorName' },
85
+ });
86
+ expect(category('missing-access-metadata').violations[0]).toMatchObject({ command: 'demo/missing' });
87
+ expect(category('silent-clamp').violations[0]).toMatchObject({ command: 'demo/search' });
88
+ expect(category('silent-empty-fallback').violations[0]).toMatchObject({ command: 'demo/search' });
89
+ expect(category('silent-sentinel').violations[0]).toMatchObject({ command: 'demo/search' });
90
+ expect(category('write-without-delete-pair').violations[0]).toMatchObject({
91
+ command: 'demo/like',
92
+ details: { expected_any_of: ['unlike'] },
93
+ });
94
+ });
95
+ it('supports site and command target filters', () => {
96
+ const root = makeProject([
97
+ { site: 'demo', name: 'search', access: 'read', columns: ['id'], sourceFile: 'demo/search.js' },
98
+ { site: 'other', name: 'search', access: 'read', columns: ['id'], sourceFile: 'other/search.js' },
99
+ ], {
100
+ 'demo/search.js': 'export async function run() { rows.push({ id: 1, hidden: true }); }',
101
+ 'other/search.js': 'export async function run() { rows.push({ id: 1, hidden: true }); }',
102
+ });
103
+ expect(runConventionAudit({ projectRoot: root, site: 'demo' }).summary.commands).toBe(1);
104
+ expect(runConventionAudit({ projectRoot: root, target: 'other/search' }).summary.commands).toBe(1);
105
+ expect(runConventionAudit({ projectRoot: root, target: 'missing' }).summary.commands).toBe(0);
106
+ });
107
+ it('renders a compact text report', () => {
108
+ const root = makeProject([
109
+ { site: 'demo', name: 'search', access: 'read', columns: ['id'], sourceFile: 'demo/search.js' },
110
+ ], {
111
+ 'demo/search.js': 'export async function run() { rows.push({ id: 1 }); }',
112
+ });
113
+ const text = renderConventionAuditText(runConventionAudit({ projectRoot: root }));
114
+ expect(text).toContain('Convention Audit Report');
115
+ expect(text).toContain('OK - no convention violations found.');
116
+ });
117
+ it('scans pipeline map blocks for silent column drops', () => {
118
+ const root = makeProject([
119
+ { site: 'demo', name: 'feed', access: 'read', columns: ['id', 'title'], sourceFile: 'demo/feed.js' },
120
+ ], {
121
+ 'demo/feed.js': `
122
+ cli({
123
+ site: 'demo',
124
+ name: 'feed',
125
+ access: 'read',
126
+ columns: ['id', 'title'],
127
+ pipeline: [
128
+ { map: {
129
+ id: '\${{ item.id }}',
130
+ title: '\${{ item.title }}',
131
+ url: '\${{ item.url }}',
132
+ } },
133
+ ],
134
+ });
135
+ `,
136
+ });
137
+ const report = runConventionAudit({ projectRoot: root });
138
+ const violations = report.categories.find((item) => item.rule === 'silent-column-drop').violations;
139
+ expect(violations[0]).toMatchObject({
140
+ command: 'demo/feed',
141
+ details: expect.objectContaining({ missing: ['url'] }),
142
+ });
143
+ });
144
+ it('ignores ok:false diagnostic objects when checking emitted rows', () => {
145
+ const root = makeProject([
146
+ { site: 'demo', name: 'search', access: 'read', columns: ['id', 'url'], sourceFile: 'demo/search.js' },
147
+ ], {
148
+ 'demo/search.js': `
149
+ export async function run() {
150
+ if (!document.querySelector('.items')) {
151
+ return { ok: false, bodyLen: document.body.innerText.length, sample: document.body.innerText.slice(0, 800), url: location.href };
152
+ }
153
+ return rows.map((row) => ({ id: row.id, url: row.url }));
154
+ }
155
+ `,
156
+ });
157
+ const report = runConventionAudit({ projectRoot: root });
158
+ const violations = report.categories.find((item) => item.rule === 'silent-column-drop').violations;
159
+ expect(violations).toEqual([]);
160
+ });
161
+ it('ignores raw intermediate keys when a final mapper converts them into columns', () => {
162
+ const root = makeProject([
163
+ {
164
+ site: 'demo',
165
+ name: 'search',
166
+ access: 'read',
167
+ columns: ['id', 'rating', 'reviews', 'price'],
168
+ sourceFile: 'demo/search.js',
169
+ },
170
+ ], {
171
+ 'demo/search.js': `
172
+ export async function run() {
173
+ rows.push({
174
+ id: item.id,
175
+ starClass: item.starClass,
176
+ reviewsRaw: item.reviewsRaw,
177
+ priceRaw: item.priceRaw,
178
+ });
179
+ return rows.map((r) => ({
180
+ id: r.id,
181
+ rating: r.starClass ? Number(r.starClass) / 10 : null,
182
+ reviews: parseReviewCount(r.reviewsRaw),
183
+ price: parsePrice(r.priceRaw),
184
+ }));
185
+ }
186
+ `,
187
+ });
188
+ const report = runConventionAudit({ projectRoot: root });
189
+ const violations = report.categories.find((item) => item.rule === 'silent-column-drop').violations;
190
+ expect(violations).toEqual([]);
191
+ });
192
+ it('still reports raw keys emitted directly without a final mapper', () => {
193
+ const root = makeProject([
194
+ { site: 'demo', name: 'search', access: 'read', columns: ['id', 'title'], sourceFile: 'demo/search.js' },
195
+ ], {
196
+ 'demo/search.js': `
197
+ export async function run() {
198
+ rows.push({
199
+ id: item.id,
200
+ title: titleRaw,
201
+ titleRaw,
202
+ });
203
+ return rows;
204
+ }
205
+ `,
206
+ });
207
+ const report = runConventionAudit({ projectRoot: root });
208
+ const violations = report.categories.find((item) => item.rule === 'silent-column-drop').violations;
209
+ expect(violations[0]).toMatchObject({
210
+ command: 'demo/search',
211
+ details: expect.objectContaining({ missing: ['titleRaw'] }),
212
+ });
213
+ });
214
+ it('only reports empty array fallbacks inside catch blocks', () => {
215
+ const root = makeProject([
216
+ { site: 'demo', name: 'guard', access: 'read', columns: ['id'], sourceFile: 'demo/guard.js' },
217
+ { site: 'demo', name: 'catch', access: 'read', columns: ['id'], sourceFile: 'demo/catch.js' },
218
+ ], {
219
+ 'demo/guard.js': 'export async function run() { if (!store) return []; rows.push({ id: 1 }); }',
220
+ 'demo/catch.js': 'export async function run() { try { await fetch("/"); } catch (err) { return []; } rows.push({ id: 1 }); }',
221
+ });
222
+ const report = runConventionAudit({ projectRoot: root });
223
+ const violations = report.categories.find((item) => item.rule === 'silent-empty-fallback').violations;
224
+ expect(violations.map((violation) => violation.command)).toEqual(['demo/catch']);
225
+ });
226
+ it('does not report sentinel fallbacks inside thrown error messages', () => {
227
+ const root = makeProject([
228
+ { site: 'demo', name: 'error', access: 'read', columns: ['id'], sourceFile: 'demo/error.js' },
229
+ { site: 'demo', name: 'row', access: 'read', columns: ['id', 'title'], sourceFile: 'demo/row.js' },
230
+ ], {
231
+ 'demo/error.js': `
232
+ export async function run(data) {
233
+ if (!data.ok) throw new Error(\`demo failed: \${data.message ?? 'unknown'}\`);
234
+ return [{ id: 1 }];
235
+ }
236
+ `,
237
+ 'demo/row.js': `
238
+ export async function run(item) {
239
+ return [{ id: item.id, title: item.title ?? 'unknown' }];
240
+ }
241
+ `,
242
+ });
243
+ const report = runConventionAudit({ projectRoot: root });
244
+ const violations = report.categories.find((item) => item.rule === 'silent-sentinel').violations;
245
+ expect(violations.map((violation) => violation.command)).toEqual(['demo/row']);
246
+ });
247
+ });
248
+ describe('extension removal audit', () => {
249
+ it('does not ship the old browser extension package', () => {
250
+ expect(fs.existsSync(path.join(process.cwd(), 'extension', 'manifest.json'))).toBe(false);
251
+ });
252
+ it('does not keep extension-only e2e smoke tests', () => {
253
+ expect(fs.existsSync(path.join(process.cwd(), 'tests/e2e/browser-ax-chrome.test.ts'))).toBe(false);
254
+ });
255
+ });
@@ -0,0 +1,13 @@
1
+ import { type Server } from 'node:http';
2
+ import type { BrowserRuntimeProvider } from '../browser/runtime/provider.js';
3
+ export interface DaemonServerOptions {
4
+ port?: number;
5
+ host?: string;
6
+ version: string;
7
+ }
8
+ export interface DaemonServerHandle {
9
+ server: Server;
10
+ listen(): Promise<void>;
11
+ close(): Promise<void>;
12
+ }
13
+ export declare function createDaemonServer(provider: BrowserRuntimeProvider, opts: DaemonServerOptions): DaemonServerHandle;
@@ -0,0 +1,185 @@
1
+ import { createServer } from 'node:http';
2
+ import { DAEMON_HEADER_NAME, DEFAULT_DAEMON_PORT } from '../constants.js';
3
+ import { getResponseCorsHeaders } from '../daemon-utils.js';
4
+ const MAX_BODY = 1024 * 1024;
5
+ const LOG_BUFFER_SIZE = 200;
6
+ function readBody(req) {
7
+ return new Promise((resolve, reject) => {
8
+ const chunks = [];
9
+ let size = 0;
10
+ let aborted = false;
11
+ req.on('data', (c) => {
12
+ size += c.length;
13
+ if (size > MAX_BODY) {
14
+ aborted = true;
15
+ req.destroy();
16
+ reject(new Error('Body too large'));
17
+ return;
18
+ }
19
+ chunks.push(c);
20
+ });
21
+ req.on('end', () => {
22
+ if (!aborted)
23
+ resolve(Buffer.concat(chunks).toString('utf-8'));
24
+ });
25
+ req.on('error', (err) => {
26
+ if (!aborted)
27
+ reject(err);
28
+ });
29
+ });
30
+ }
31
+ function jsonResponse(res, status, data, extraHeaders) {
32
+ res.writeHead(status, { 'Content-Type': 'application/json', ...extraHeaders });
33
+ res.end(JSON.stringify(data));
34
+ }
35
+ export function createDaemonServer(provider, opts) {
36
+ const port = opts.port ?? DEFAULT_DAEMON_PORT;
37
+ const host = opts.host ?? '127.0.0.1';
38
+ const logBuffer = [];
39
+ const pending = new Set();
40
+ let shutdownStarted = false;
41
+ function pushLog(level, msg) {
42
+ logBuffer.push({ level, msg, ts: Date.now() });
43
+ if (logBuffer.length > LOG_BUFFER_SIZE)
44
+ logBuffer.shift();
45
+ }
46
+ async function shutdownProvider() {
47
+ if (shutdownStarted)
48
+ return;
49
+ shutdownStarted = true;
50
+ await provider.shutdown();
51
+ }
52
+ async function handleRequest(req, res) {
53
+ const origin = req.headers.origin;
54
+ if (origin && !origin.startsWith('chrome-extension://')) {
55
+ jsonResponse(res, 403, { ok: false, error: 'Forbidden: cross-origin request blocked' });
56
+ return;
57
+ }
58
+ if (req.method === 'OPTIONS') {
59
+ res.writeHead(204);
60
+ res.end();
61
+ return;
62
+ }
63
+ const url = req.url ?? '/';
64
+ const pathname = url.split('?')[0];
65
+ if (req.method === 'GET' && pathname === '/ping') {
66
+ jsonResponse(res, 200, { ok: true }, getResponseCorsHeaders(pathname, origin));
67
+ return;
68
+ }
69
+ if (!req.headers[DAEMON_HEADER_NAME.toLowerCase()]) {
70
+ jsonResponse(res, 403, { ok: false, error: `Forbidden: missing ${DAEMON_HEADER_NAME} header` });
71
+ return;
72
+ }
73
+ if (req.method === 'GET' && pathname === '/status') {
74
+ const mem = process.memoryUsage();
75
+ const params = new URL(url, `http://localhost:${port}`).searchParams;
76
+ const contextId = params.get('contextId')?.trim() || undefined;
77
+ const runtime = await provider.status({ contextId });
78
+ jsonResponse(res, 200, {
79
+ ok: true,
80
+ pid: process.pid,
81
+ uptime: process.uptime(),
82
+ daemonVersion: opts.version,
83
+ ...runtime,
84
+ pending: pending.size + runtime.pending,
85
+ memoryMB: Math.round(mem.rss / 1024 / 1024 * 10) / 10,
86
+ port,
87
+ });
88
+ return;
89
+ }
90
+ if (req.method === 'GET' && pathname === '/logs') {
91
+ const params = new URL(url, `http://localhost:${port}`).searchParams;
92
+ const level = params.get('level');
93
+ const logs = level ? logBuffer.filter((entry) => entry.level === level) : logBuffer;
94
+ jsonResponse(res, 200, { ok: true, logs });
95
+ return;
96
+ }
97
+ if (req.method === 'DELETE' && pathname === '/logs') {
98
+ logBuffer.length = 0;
99
+ jsonResponse(res, 200, { ok: true });
100
+ return;
101
+ }
102
+ if (req.method === 'POST' && pathname === '/shutdown') {
103
+ jsonResponse(res, 200, { ok: true, message: 'Shutting down' });
104
+ setTimeout(() => {
105
+ shutdownProvider().finally(() => {
106
+ server.close();
107
+ });
108
+ }, 10);
109
+ return;
110
+ }
111
+ if (req.method === 'POST' && pathname === '/command') {
112
+ try {
113
+ const body = JSON.parse(await readBody(req));
114
+ if (!body.id) {
115
+ jsonResponse(res, 400, { ok: false, error: 'Missing command id' });
116
+ return;
117
+ }
118
+ if (pending.has(body.id)) {
119
+ jsonResponse(res, 409, { id: body.id, ok: false, error: 'Duplicate command id already pending; retry' });
120
+ return;
121
+ }
122
+ pending.add(body.id);
123
+ const timeoutMs = typeof body.timeout === 'number' && body.timeout > 0 ? body.timeout * 1000 : 120_000;
124
+ let timeoutId;
125
+ try {
126
+ const result = await Promise.race([
127
+ provider.dispatch(body),
128
+ new Promise((resolve) => {
129
+ timeoutId = setTimeout(() => resolve({
130
+ id: body.id,
131
+ ok: false,
132
+ errorCode: 'command_result_unknown',
133
+ error: `Command timeout (${timeoutMs / 1000}s)`,
134
+ errorHint: 'Inspect the browser state before retrying non-idempotent commands.',
135
+ }), timeoutMs);
136
+ }),
137
+ ]);
138
+ if (!result.ok)
139
+ pushLog('warn', `Command ${body.id} failed: ${result.error ?? result.errorCode ?? 'unknown error'}`);
140
+ jsonResponse(res, result.ok ? 200 : result.errorCode === 'command_result_unknown' ? 408 : 400, result);
141
+ }
142
+ finally {
143
+ if (timeoutId)
144
+ clearTimeout(timeoutId);
145
+ pending.delete(body.id);
146
+ }
147
+ }
148
+ catch (err) {
149
+ jsonResponse(res, 400, { ok: false, error: err instanceof Error ? err.message : 'Invalid request' });
150
+ }
151
+ return;
152
+ }
153
+ jsonResponse(res, 404, { error: 'Not found' });
154
+ }
155
+ const server = createServer((req, res) => {
156
+ handleRequest(req, res).catch((err) => {
157
+ jsonResponse(res, 500, { ok: false, error: err instanceof Error ? err.message : String(err) });
158
+ });
159
+ });
160
+ return {
161
+ server,
162
+ listen: () => new Promise((resolve, reject) => {
163
+ server.once('error', reject);
164
+ server.listen(port, host, () => {
165
+ server.off('error', reject);
166
+ resolve();
167
+ });
168
+ }),
169
+ close: async () => {
170
+ await shutdownProvider();
171
+ await new Promise((resolve, reject) => {
172
+ if (!server.listening) {
173
+ resolve();
174
+ return;
175
+ }
176
+ server.close((err) => {
177
+ if (err)
178
+ reject(err);
179
+ else
180
+ resolve();
181
+ });
182
+ });
183
+ },
184
+ };
185
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,132 @@
1
+ import { afterEach, describe, expect, it, vi } from 'vitest';
2
+ import { DAEMON_HEADER_NAME } from '../constants.js';
3
+ import { createDaemonServer } from './server.js';
4
+ class FakeProvider {
5
+ commands = [];
6
+ shutdownCalled = false;
7
+ delayMs = 0;
8
+ async status() {
9
+ return {
10
+ runtimeConnected: true,
11
+ runtimeName: 'fake',
12
+ runtimeVersion: '1.2.3',
13
+ profiles: [{ contextId: 'default', runtimeConnected: true, runtimeVersion: '1.2.3', pending: 0 }],
14
+ pending: 0,
15
+ commandResultUnknown: 0,
16
+ };
17
+ }
18
+ async dispatch(command) {
19
+ if (this.delayMs > 0)
20
+ await new Promise((resolve) => setTimeout(resolve, this.delayMs));
21
+ this.commands.push(command);
22
+ return { id: command.id, ok: true, data: { action: command.action }, page: 'page-1' };
23
+ }
24
+ async shutdown() {
25
+ this.shutdownCalled = true;
26
+ }
27
+ }
28
+ describe('createDaemonServer', () => {
29
+ const servers = [];
30
+ afterEach(async () => {
31
+ while (servers.length)
32
+ await servers.pop().close();
33
+ });
34
+ async function start(provider = new FakeProvider()) {
35
+ const daemon = createDaemonServer(provider, { port: 0, host: '127.0.0.1', version: 'test' });
36
+ await daemon.listen();
37
+ servers.push(daemon);
38
+ const address = daemon.server.address();
39
+ return { provider, baseUrl: `http://127.0.0.1:${address.port}` };
40
+ }
41
+ it('returns runtime-named status fields without extension aliases', async () => {
42
+ const { baseUrl } = await start();
43
+ const res = await fetch(`${baseUrl}/status`, { headers: { [DAEMON_HEADER_NAME]: '1' } });
44
+ const body = await res.json();
45
+ expect(body).toMatchObject({
46
+ ok: true,
47
+ runtimeConnected: true,
48
+ runtimeName: 'fake',
49
+ runtimeVersion: '1.2.3',
50
+ profiles: [{ contextId: 'default', runtimeConnected: true }],
51
+ });
52
+ expect(body).not.toHaveProperty(`extension${'Connected'}`);
53
+ expect(body).not.toHaveProperty(`extension${'Version'}`);
54
+ });
55
+ it('dispatches /command through the provider', async () => {
56
+ const { provider, baseUrl } = await start();
57
+ const res = await fetch(`${baseUrl}/command`, {
58
+ method: 'POST',
59
+ headers: { [DAEMON_HEADER_NAME]: '1', 'Content-Type': 'application/json' },
60
+ body: JSON.stringify({ id: 'cmd-1', action: 'navigate', session: 'work', url: 'https://example.com' }),
61
+ });
62
+ await expect(res.json()).resolves.toEqual({
63
+ id: 'cmd-1',
64
+ ok: true,
65
+ data: { action: 'navigate' },
66
+ page: 'page-1',
67
+ });
68
+ expect(provider.commands).toHaveLength(1);
69
+ expect(provider.commands[0]).toMatchObject({ id: 'cmd-1', action: 'navigate', session: 'work' });
70
+ });
71
+ it('clears custom command timeout timers after successful provider dispatch', async () => {
72
+ const setTimeoutSpy = vi.spyOn(globalThis, 'setTimeout');
73
+ const clearTimeoutSpy = vi.spyOn(globalThis, 'clearTimeout');
74
+ try {
75
+ const { baseUrl } = await start();
76
+ const res = await fetch(`${baseUrl}/command`, {
77
+ method: 'POST',
78
+ headers: { [DAEMON_HEADER_NAME]: '1', 'Content-Type': 'application/json' },
79
+ body: JSON.stringify({ id: 'fast-custom-timeout', action: 'navigate', session: 'work', timeout: 60 }),
80
+ });
81
+ expect(res.status).toBe(200);
82
+ await expect(res.json()).resolves.toMatchObject({
83
+ id: 'fast-custom-timeout',
84
+ ok: true,
85
+ });
86
+ const timeoutCallIndex = setTimeoutSpy.mock.calls.findIndex(([, delay]) => delay === 60_000);
87
+ expect(timeoutCallIndex).toBeGreaterThanOrEqual(0);
88
+ const commandTimeoutHandle = setTimeoutSpy.mock.results[timeoutCallIndex]?.value;
89
+ expect(clearTimeoutSpy).toHaveBeenCalledWith(commandTimeoutHandle);
90
+ }
91
+ finally {
92
+ setTimeoutSpy.mockRestore();
93
+ clearTimeoutSpy.mockRestore();
94
+ }
95
+ });
96
+ it('requires X-Webcmd on non-ping endpoints', async () => {
97
+ const { baseUrl } = await start();
98
+ const res = await fetch(`${baseUrl}/status`);
99
+ expect(res.status).toBe(403);
100
+ });
101
+ it('records daemon logs through /logs', async () => {
102
+ const { baseUrl } = await start();
103
+ const res = await fetch(`${baseUrl}/logs`, { headers: { [DAEMON_HEADER_NAME]: '1' } });
104
+ const body = await res.json();
105
+ expect(body).toMatchObject({ ok: true, logs: expect.any(Array) });
106
+ });
107
+ it('times out slow provider commands and clears pending state', async () => {
108
+ const provider = new FakeProvider();
109
+ provider.delayMs = 100;
110
+ const { baseUrl } = await start(provider);
111
+ const res = await fetch(`${baseUrl}/command`, {
112
+ method: 'POST',
113
+ headers: { [DAEMON_HEADER_NAME]: '1', 'Content-Type': 'application/json' },
114
+ body: JSON.stringify({ id: 'slow', action: 'exec', session: 'work', timeout: 0.01 }),
115
+ });
116
+ expect(res.status).toBe(408);
117
+ await expect(res.json()).resolves.toMatchObject({
118
+ id: 'slow',
119
+ ok: false,
120
+ errorCode: 'command_result_unknown',
121
+ });
122
+ });
123
+ it('calls provider shutdown before closing', async () => {
124
+ const { provider, baseUrl } = await start();
125
+ const res = await fetch(`${baseUrl}/shutdown`, {
126
+ method: 'POST',
127
+ headers: { [DAEMON_HEADER_NAME]: '1' },
128
+ });
129
+ expect(res.status).toBe(200);
130
+ await vi.waitFor(() => expect(provider.shutdownCalled).toBe(true));
131
+ });
132
+ });
@@ -0,0 +1,18 @@
1
+ export declare const COMMAND_RESULT_UNKNOWN_CODE = "command_result_unknown";
2
+ export declare const COMMAND_RESULT_UNKNOWN_HINT = "Inspect the browser/session state before retrying. Do not blindly retry write commands such as navigate, click, type, or eval.";
3
+ export declare const PROFILE_DISCONNECTED_HINT = "Open that Chrome profile and make sure the Webcmd extension is enabled, or choose another profile with webcmd profile use <name>.";
4
+ export type DaemonFailureContract = {
5
+ message: string;
6
+ errorCode: string;
7
+ errorHint: string;
8
+ status: number;
9
+ countAsCommandResultUnknown: boolean;
10
+ };
11
+ export declare function commandResultUnknownMessage(action: string): string;
12
+ export declare function buildExtensionDisconnectFailure(input: {
13
+ contextId: string;
14
+ action: string;
15
+ dispatched: boolean;
16
+ }): DaemonFailureContract;
17
+ export declare function buildCommandDispatchFailure(contextId: string): DaemonFailureContract;
18
+ export declare function getResponseCorsHeaders(pathname: string, origin?: string): Record<string, string> | undefined;
@@ -0,0 +1,37 @@
1
+ export const COMMAND_RESULT_UNKNOWN_CODE = 'command_result_unknown';
2
+ export const COMMAND_RESULT_UNKNOWN_HINT = 'Inspect the browser/session state before retrying. Do not blindly retry write commands such as navigate, click, type, or eval.';
3
+ export const PROFILE_DISCONNECTED_HINT = 'Open that Chrome profile and make sure the Webcmd extension is enabled, or choose another profile with webcmd profile use <name>.';
4
+ export function commandResultUnknownMessage(action) {
5
+ return `Browser connection dropped after the ${action} command was dispatched; it may have completed.`;
6
+ }
7
+ export function buildExtensionDisconnectFailure(input) {
8
+ if (input.dispatched) {
9
+ return {
10
+ message: commandResultUnknownMessage(input.action),
11
+ errorCode: COMMAND_RESULT_UNKNOWN_CODE,
12
+ errorHint: COMMAND_RESULT_UNKNOWN_HINT,
13
+ status: 503,
14
+ countAsCommandResultUnknown: true,
15
+ };
16
+ }
17
+ return buildCommandDispatchFailure(input.contextId);
18
+ }
19
+ export function buildCommandDispatchFailure(contextId) {
20
+ return {
21
+ message: `Browser profile "${contextId}" disconnected before command dispatch`,
22
+ errorCode: 'profile_disconnected',
23
+ errorHint: PROFILE_DISCONNECTED_HINT,
24
+ status: 503,
25
+ countAsCommandResultUnknown: false,
26
+ };
27
+ }
28
+ export function getResponseCorsHeaders(pathname, origin) {
29
+ if (pathname !== '/ping')
30
+ return undefined;
31
+ if (!origin || !origin.startsWith('chrome-extension://'))
32
+ return undefined;
33
+ return {
34
+ 'Access-Control-Allow-Origin': origin,
35
+ Vary: 'Origin',
36
+ };
37
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,27 @@
1
+ import { DEFAULT_DAEMON_PORT, unsupportedDaemonPortEnvMessage } from './constants.js';
2
+ import { EXIT_CODES } from './errors.js';
3
+ import { log } from './logger.js';
4
+ import { PKG_VERSION } from './version.js';
5
+ import { createDaemonServer } from './daemon/server.js';
6
+ import { LocalCloakRuntimeProvider } from './browser/runtime/local-cloak/provider.js';
7
+ if (process.env.WEBCMD_DAEMON_PORT) {
8
+ log.error(unsupportedDaemonPortEnvMessage(process.env.WEBCMD_DAEMON_PORT));
9
+ process.exit(EXIT_CODES.USAGE_ERROR);
10
+ }
11
+ const provider = new LocalCloakRuntimeProvider();
12
+ const daemon = createDaemonServer(provider, { port: DEFAULT_DAEMON_PORT, host: '127.0.0.1', version: PKG_VERSION });
13
+ daemon.listen().then(() => {
14
+ log.info(`[daemon] Listening on http://127.0.0.1:${DEFAULT_DAEMON_PORT}`);
15
+ }).catch((err) => {
16
+ if (err.code === 'EADDRINUSE') {
17
+ log.error(`[daemon] Port ${DEFAULT_DAEMON_PORT} already in use — another daemon is likely running. Exiting.`);
18
+ process.exit(EXIT_CODES.SERVICE_UNAVAIL);
19
+ }
20
+ log.error(`[daemon] Server error: ${err.message}`);
21
+ process.exit(EXIT_CODES.GENERIC_ERROR);
22
+ });
23
+ function shutdown() {
24
+ daemon.close().finally(() => process.exit(EXIT_CODES.SUCCESS));
25
+ }
26
+ process.on('SIGTERM', shutdown);
27
+ process.on('SIGINT', shutdown);