@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,434 @@
1
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import { homedir } from 'node:os';
3
+ import { dirname, join } from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ import { InvalidArgumentError, Option } from 'commander';
6
+ import { AuthRequiredError, CliError, getErrorMessage } from '../errors.js';
7
+ import { executeCommand } from '../execution.js';
8
+ import { fullName, getRegistry, } from '../registry.js';
9
+ import { render as renderOutput } from '../output.js';
10
+ const AUTH_REFRESH_STATE_VERSION = 1;
11
+ const AUTH_REFRESH_INTERVAL_MS = 24 * 60 * 60 * 1000;
12
+ function parsePositiveInt(raw, label, fallback) {
13
+ if (raw === undefined || raw === null || raw === '')
14
+ return fallback;
15
+ const parsed = Number(raw);
16
+ if (!Number.isInteger(parsed) || parsed <= 0) {
17
+ throw new InvalidArgumentError(`${label} must be a positive integer. Received: "${String(raw)}"`);
18
+ }
19
+ return parsed;
20
+ }
21
+ function parseSiteFilter(raw) {
22
+ if (!raw || !raw.trim())
23
+ return null;
24
+ const sites = raw.split(',').map(site => site.trim()).filter(Boolean);
25
+ return sites.length > 0 ? new Set(sites) : null;
26
+ }
27
+ function defaultAuthRefreshStatePath() {
28
+ return join(homedir(), '.webcmd', 'auth-refresh.json');
29
+ }
30
+ function emptyAuthRefreshState() {
31
+ return { version: AUTH_REFRESH_STATE_VERSION, sites: {} };
32
+ }
33
+ async function loadAuthRefreshState(statePath) {
34
+ try {
35
+ const parsed = JSON.parse(await readFile(statePath, 'utf8'));
36
+ if (parsed && parsed.version === AUTH_REFRESH_STATE_VERSION && parsed.sites && typeof parsed.sites === 'object') {
37
+ return { version: AUTH_REFRESH_STATE_VERSION, sites: parsed.sites };
38
+ }
39
+ }
40
+ catch (error) {
41
+ if (error.code !== 'ENOENT')
42
+ throw error;
43
+ }
44
+ return emptyAuthRefreshState();
45
+ }
46
+ async function saveAuthRefreshState(statePath, state) {
47
+ await mkdir(dirname(statePath), { recursive: true });
48
+ await writeFile(statePath, `${JSON.stringify(state, null, 2)}\n`, 'utf8');
49
+ }
50
+ function lastTouchedMs(entry) {
51
+ if (!entry?.last_touched_at)
52
+ return null;
53
+ const parsed = Date.parse(entry.last_touched_at);
54
+ return Number.isFinite(parsed) ? parsed : null;
55
+ }
56
+ function isRefreshThrottled(entry, now) {
57
+ const touched = lastTouchedMs(entry);
58
+ return touched !== null && now.getTime() - touched < AUTH_REFRESH_INTERVAL_MS;
59
+ }
60
+ function nextRefreshAt(entry) {
61
+ const touched = lastTouchedMs(entry);
62
+ return touched === null ? '' : new Date(touched + AUTH_REFRESH_INTERVAL_MS).toISOString();
63
+ }
64
+ function authWhoamiCommands() {
65
+ const seen = new Set();
66
+ return [...getRegistry().values()]
67
+ .filter((cmd) => {
68
+ if (seen.has(cmd))
69
+ return false;
70
+ seen.add(cmd);
71
+ return cmd.name === 'whoami' && cmd.browser === true && cmd.access === 'read';
72
+ })
73
+ .sort((a, b) => a.site.localeCompare(b.site));
74
+ }
75
+ async function loadLazyCommand(cmd) {
76
+ const internal = cmd;
77
+ if (!internal._lazy || !internal._modulePath)
78
+ return cmd;
79
+ await import(pathToFileURL(internal._modulePath).href);
80
+ return getRegistry().get(fullName(cmd)) ?? cmd;
81
+ }
82
+ function withTimeoutArg(cmd, timeoutSeconds) {
83
+ const hasTimeout = cmd.args.some(arg => arg.name === 'timeout');
84
+ return {
85
+ ...cmd,
86
+ args: hasTimeout
87
+ ? cmd.args
88
+ : [...cmd.args, { name: 'timeout', type: 'int', default: timeoutSeconds, help: 'Per-site auth command timeout in seconds' }],
89
+ };
90
+ }
91
+ function quickCheckCommand(cmd, timeoutSeconds) {
92
+ if (cmd.browser !== true || typeof cmd.authStatus?.quickCheck !== 'function')
93
+ return null;
94
+ return withTimeoutArg({
95
+ ...cmd,
96
+ func: cmd.authStatus.quickCheck,
97
+ navigateBefore: false,
98
+ siteSession: 'ephemeral',
99
+ defaultWindowMode: 'background',
100
+ }, timeoutSeconds);
101
+ }
102
+ function normalizeQuickResult(result) {
103
+ if (typeof result === 'boolean')
104
+ return result;
105
+ if (result && typeof result === 'object' && !Array.isArray(result)) {
106
+ const value = result.logged_in;
107
+ if (typeof value === 'boolean')
108
+ return value;
109
+ }
110
+ return null;
111
+ }
112
+ function safeIdentityValue(value) {
113
+ if (value === undefined || value === null)
114
+ return '';
115
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean')
116
+ return String(value);
117
+ return '';
118
+ }
119
+ function identitySummary(result) {
120
+ if (!result || typeof result !== 'object' || Array.isArray(result))
121
+ return '';
122
+ const row = result;
123
+ const blocked = /(?:email|phone|real.?name|first.?name|last.?name|cookie|token|session|secret|password|csrf|jwt|bearer|wt2)/i;
124
+ for (const key of ['username', 'handle', 'user_id', 'id', 'name', 'nickname', 'user_type', 'url']) {
125
+ if (blocked.test(key))
126
+ continue;
127
+ const value = safeIdentityValue(row[key]);
128
+ if (value)
129
+ return value;
130
+ }
131
+ for (const [key, raw] of Object.entries(row)) {
132
+ if (key === 'site' || key === 'logged_in' || blocked.test(key))
133
+ continue;
134
+ const value = safeIdentityValue(raw);
135
+ if (value)
136
+ return value;
137
+ }
138
+ return '';
139
+ }
140
+ function rowForError(site, checked, error) {
141
+ if (error instanceof AuthRequiredError) {
142
+ return { site, status: 'not_logged_in', logged_in: false, identity: '', checked, error: '' };
143
+ }
144
+ const code = error instanceof CliError ? error.code : '';
145
+ const message = getErrorMessage(error);
146
+ return {
147
+ site,
148
+ status: 'error',
149
+ logged_in: '',
150
+ identity: '',
151
+ checked,
152
+ error: code ? `${code}: ${message}` : message,
153
+ };
154
+ }
155
+ function refreshCommand(cmd, timeoutSeconds) {
156
+ if (cmd.browser !== true)
157
+ return null;
158
+ let refreshFunc = cmd.authStatus?.refresh;
159
+ if (typeof refreshFunc !== 'function') {
160
+ const quickCheck = cmd.authStatus?.quickCheck;
161
+ if (typeof quickCheck !== 'function' || !cmd.domain)
162
+ return null;
163
+ const refreshUrl = cmd.domain.startsWith('http://') || cmd.domain.startsWith('https://')
164
+ ? cmd.domain
165
+ : `https://${cmd.domain}`;
166
+ refreshFunc = async (page, kwargs, debug) => {
167
+ await page.goto(refreshUrl);
168
+ await page.wait(1);
169
+ const loggedIn = normalizeQuickResult(await quickCheck(page, kwargs, debug));
170
+ if (loggedIn !== true) {
171
+ throw new AuthRequiredError(cmd.domain ?? cmd.site, `Auth refresh quickCheck failed for ${cmd.site}`);
172
+ }
173
+ return { status: 'touched' };
174
+ };
175
+ }
176
+ return withTimeoutArg({
177
+ ...cmd,
178
+ func: refreshFunc,
179
+ navigateBefore: false,
180
+ siteSession: 'persistent',
181
+ defaultWindowMode: 'background',
182
+ }, timeoutSeconds);
183
+ }
184
+ function normalizeRefreshStatus(result) {
185
+ if (result && typeof result === 'object' && !Array.isArray(result)) {
186
+ const row = result;
187
+ if (row.status === 'refreshed' || row.refreshed === true)
188
+ return 'refreshed';
189
+ }
190
+ return 'touched';
191
+ }
192
+ function refreshRowForError(site, entry, error) {
193
+ if (error instanceof AuthRequiredError) {
194
+ return {
195
+ site,
196
+ status: 'not_logged_in',
197
+ last_touched_at: entry?.last_touched_at ?? '',
198
+ next_refresh_at: nextRefreshAt(entry),
199
+ error: '',
200
+ };
201
+ }
202
+ const code = error instanceof CliError ? error.code : '';
203
+ const message = getErrorMessage(error);
204
+ return {
205
+ site,
206
+ status: 'error',
207
+ last_touched_at: entry?.last_touched_at ?? '',
208
+ next_refresh_at: nextRefreshAt(entry),
209
+ error: code ? `${code}: ${message}` : message,
210
+ };
211
+ }
212
+ async function runQuick(cmd, opts) {
213
+ const loaded = await loadLazyCommand(cmd);
214
+ const quickCmd = quickCheckCommand(loaded, opts.timeoutSeconds);
215
+ if (!quickCmd) {
216
+ return {
217
+ site: cmd.site,
218
+ status: 'unknown',
219
+ logged_in: '',
220
+ identity: '',
221
+ checked: 'skipped',
222
+ error: 'quickCheck not implemented; use --full to run whoami',
223
+ };
224
+ }
225
+ try {
226
+ const result = await executeCommand(quickCmd, { timeout: opts.timeoutSeconds }, false, {
227
+ siteSession: 'ephemeral',
228
+ keepTab: 'false',
229
+ windowMode: 'background',
230
+ ...(opts.profile ? { profile: opts.profile } : {}),
231
+ });
232
+ const loggedIn = normalizeQuickResult(result);
233
+ if (loggedIn === true) {
234
+ return { site: cmd.site, status: 'logged_in', logged_in: true, identity: '', checked: 'quick', error: '' };
235
+ }
236
+ if (loggedIn === false) {
237
+ return { site: cmd.site, status: 'not_logged_in', logged_in: false, identity: '', checked: 'quick', error: '' };
238
+ }
239
+ return {
240
+ site: cmd.site,
241
+ status: 'unknown',
242
+ logged_in: '',
243
+ identity: '',
244
+ checked: 'quick',
245
+ error: 'quickCheck returned no boolean logged_in signal',
246
+ };
247
+ }
248
+ catch (error) {
249
+ return rowForError(cmd.site, 'quick', error);
250
+ }
251
+ }
252
+ async function runFull(cmd, opts) {
253
+ const loaded = await loadLazyCommand(cmd);
254
+ const fullCmd = withTimeoutArg(loaded, opts.timeoutSeconds);
255
+ try {
256
+ const result = await executeCommand(fullCmd, { timeout: opts.timeoutSeconds }, false, {
257
+ siteSession: 'ephemeral',
258
+ keepTab: 'false',
259
+ windowMode: 'background',
260
+ ...(opts.profile ? { profile: opts.profile } : {}),
261
+ });
262
+ return {
263
+ site: cmd.site,
264
+ status: 'logged_in',
265
+ logged_in: true,
266
+ identity: identitySummary(result),
267
+ checked: 'full',
268
+ error: '',
269
+ };
270
+ }
271
+ catch (error) {
272
+ return rowForError(cmd.site, 'full', error);
273
+ }
274
+ }
275
+ async function runRefresh(cmd, opts) {
276
+ const existing = opts.state.sites[cmd.site];
277
+ if (!opts.force && isRefreshThrottled(existing, opts.now)) {
278
+ return {
279
+ site: cmd.site,
280
+ status: 'skipped',
281
+ last_touched_at: existing?.last_touched_at ?? '',
282
+ next_refresh_at: nextRefreshAt(existing),
283
+ error: '',
284
+ };
285
+ }
286
+ const attemptAt = opts.now.toISOString();
287
+ const loaded = await loadLazyCommand(cmd);
288
+ const refreshCmd = refreshCommand(loaded, opts.timeoutSeconds);
289
+ if (!refreshCmd) {
290
+ opts.state.sites[cmd.site] = { ...existing, last_attempt_at: attemptAt, last_status: 'unsupported' };
291
+ return {
292
+ site: cmd.site,
293
+ status: 'unsupported',
294
+ last_touched_at: existing?.last_touched_at ?? '',
295
+ next_refresh_at: nextRefreshAt(existing),
296
+ error: 'refresh probe is not available for this site',
297
+ };
298
+ }
299
+ try {
300
+ const result = await executeCommand(refreshCmd, { timeout: opts.timeoutSeconds }, false, {
301
+ siteSession: 'persistent',
302
+ keepTab: 'true',
303
+ windowMode: 'background',
304
+ ...(opts.profile ? { profile: opts.profile } : {}),
305
+ });
306
+ const status = normalizeRefreshStatus(result);
307
+ opts.state.sites[cmd.site] = {
308
+ ...existing,
309
+ last_attempt_at: attemptAt,
310
+ last_touched_at: attemptAt,
311
+ last_status: status,
312
+ };
313
+ return {
314
+ site: cmd.site,
315
+ status,
316
+ last_touched_at: attemptAt,
317
+ next_refresh_at: new Date(opts.now.getTime() + AUTH_REFRESH_INTERVAL_MS).toISOString(),
318
+ error: '',
319
+ };
320
+ }
321
+ catch (error) {
322
+ const status = error instanceof AuthRequiredError ? 'not_logged_in' : 'error';
323
+ opts.state.sites[cmd.site] = { ...existing, last_attempt_at: attemptAt, last_status: status };
324
+ return refreshRowForError(cmd.site, existing, error);
325
+ }
326
+ }
327
+ async function mapConcurrent(items, concurrency, worker) {
328
+ const results = new Array(items.length);
329
+ let next = 0;
330
+ const runners = Array.from({ length: Math.min(concurrency, items.length) }, async () => {
331
+ while (next < items.length) {
332
+ const index = next++;
333
+ results[index] = await worker(items[index]);
334
+ }
335
+ });
336
+ await Promise.all(runners);
337
+ return results;
338
+ }
339
+ export async function collectAuthStatus(options) {
340
+ const selectedSites = parseSiteFilter(options.sites);
341
+ const mode = options.full ? 'full' : 'quick';
342
+ const concurrency = parsePositiveInt(options.concurrency, '--concurrency', mode === 'full' ? 3 : 8);
343
+ const timeoutSeconds = parsePositiveInt(options.timeout, '--timeout', mode === 'full' ? 20 : 8);
344
+ const only = String(options.only ?? 'all');
345
+ if (!['all', 'logged-in', 'not-logged-in', 'unknown', 'error'].includes(only)) {
346
+ throw new InvalidArgumentError('--only must be one of: all, logged-in, not-logged-in, unknown, error');
347
+ }
348
+ const commands = authWhoamiCommands().filter(cmd => !selectedSites || selectedSites.has(cmd.site));
349
+ const rows = await mapConcurrent(commands, concurrency, cmd => (mode === 'full'
350
+ ? runFull(cmd, { timeoutSeconds, profile: options.profile })
351
+ : runQuick(cmd, { timeoutSeconds, profile: options.profile })));
352
+ const normalizedOnly = only.replace(/-/g, '_');
353
+ return normalizedOnly === 'all'
354
+ ? rows
355
+ : rows.filter(row => row.status === normalizedOnly);
356
+ }
357
+ export async function collectAuthRefresh(options) {
358
+ const selectedSites = parseSiteFilter(options.sites);
359
+ const concurrency = parsePositiveInt(options.concurrency, '--concurrency', 3);
360
+ const timeoutSeconds = parsePositiveInt(options.timeout, '--timeout', 20);
361
+ const statePath = options.statePath ?? defaultAuthRefreshStatePath();
362
+ const now = options.now ?? new Date();
363
+ const state = await loadAuthRefreshState(statePath);
364
+ const commands = authWhoamiCommands().filter(cmd => !selectedSites || selectedSites.has(cmd.site));
365
+ const rows = await mapConcurrent(commands, concurrency, cmd => runRefresh(cmd, {
366
+ timeoutSeconds,
367
+ profile: options.profile,
368
+ now,
369
+ state,
370
+ force: options.all === true,
371
+ }));
372
+ await saveAuthRefreshState(statePath, state);
373
+ return rows;
374
+ }
375
+ export function registerAuthCommands(program) {
376
+ const auth = program
377
+ .command('auth')
378
+ .description('Inspect website login status');
379
+ const status = auth
380
+ .command('status')
381
+ .description('Show login status for sites with auth adapters')
382
+ .option('--site <sites>', 'Comma-separated site names to check, e.g. github,chatgpt')
383
+ .option('--full', 'Run full per-site whoami probes instead of quick no-navigation checks', false)
384
+ .option('--concurrency <n>', 'Maximum sites to check at once')
385
+ .option('--timeout <seconds>', 'Per-site timeout in seconds')
386
+ .addOption(new Option('--only <status>', 'Filter rows by status').choices(['all', 'logged-in', 'not-logged-in', 'unknown', 'error']).default('all'))
387
+ .option('-f, --format <fmt>', 'Output format: table, plain, json, yaml, md, csv', 'table')
388
+ .action(async (opts) => {
389
+ const globals = typeof status.optsWithGlobals === 'function' ? status.optsWithGlobals() : {};
390
+ const rows = await collectAuthStatus({
391
+ sites: opts.site,
392
+ full: opts.full === true,
393
+ concurrency: opts.concurrency,
394
+ timeout: opts.timeout,
395
+ only: opts.only,
396
+ profile: typeof globals.profile === 'string' && globals.profile.trim() ? globals.profile.trim() : undefined,
397
+ });
398
+ const fmt = typeof opts.format === 'string' ? opts.format : 'table';
399
+ renderOutput(rows, {
400
+ fmt,
401
+ fmtExplicit: status.getOptionValueSource('format') === 'cli',
402
+ columns: ['site', 'status', 'identity', 'checked', 'error'],
403
+ title: 'webcmd/auth status',
404
+ source: opts.full ? 'full whoami probe' : 'quick auth check',
405
+ });
406
+ });
407
+ const refresh = auth
408
+ .command('refresh')
409
+ .description('Touch logged-in site sessions to keep browser auth fresh')
410
+ .option('--site <sites>', 'Comma-separated site names to refresh, e.g. github,claude')
411
+ .option('--all', 'Ignore the 24h refresh throttle and force every selected site', false)
412
+ .option('--concurrency <n>', 'Maximum sites to refresh at once')
413
+ .option('--timeout <seconds>', 'Per-site timeout in seconds')
414
+ .option('-f, --format <fmt>', 'Output format: table, plain, json, yaml, md, csv', 'table')
415
+ .action(async (opts) => {
416
+ const globals = typeof refresh.optsWithGlobals === 'function' ? refresh.optsWithGlobals() : {};
417
+ const rows = await collectAuthRefresh({
418
+ sites: opts.site,
419
+ all: opts.all === true,
420
+ concurrency: opts.concurrency,
421
+ timeout: opts.timeout,
422
+ profile: typeof globals.profile === 'string' && globals.profile.trim() ? globals.profile.trim() : undefined,
423
+ });
424
+ const fmt = typeof opts.format === 'string' ? opts.format : 'table';
425
+ renderOutput(rows, {
426
+ fmt,
427
+ fmtExplicit: refresh.getOptionValueSource('format') === 'cli',
428
+ columns: ['site', 'status', 'last_touched_at', 'next_refresh_at', 'error'],
429
+ title: 'webcmd/auth refresh',
430
+ source: opts.all ? 'forced persistent touch' : 'persistent touch with 24h throttle',
431
+ });
432
+ });
433
+ return auth;
434
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,252 @@
1
+ import { mkdtemp, readFile } from 'node:fs/promises';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
5
+ const executeCommandMock = vi.hoisted(() => vi.fn());
6
+ vi.mock('../execution.js', () => ({
7
+ executeCommand: executeCommandMock,
8
+ }));
9
+ import { collectAuthRefresh, collectAuthStatus } from './auth.js';
10
+ import { AuthRequiredError } from '../errors.js';
11
+ import { cli, getRegistry, Strategy } from '../registry.js';
12
+ function registerWhoami(site, opts = {}) {
13
+ cli({
14
+ site,
15
+ name: 'whoami',
16
+ access: 'read',
17
+ description: `${site} whoami`,
18
+ strategy: Strategy.COOKIE,
19
+ browser: true,
20
+ domain: `${site}.example.com`,
21
+ navigateBefore: false,
22
+ args: [],
23
+ columns: ['logged_in', 'site', 'username'],
24
+ authStatus: {
25
+ ...(opts.quick ? { quickCheck: async () => ({ logged_in: opts.quickLoggedIn ?? false }) } : {}),
26
+ ...(opts.refresh ? { refresh: async () => ({ status: opts.refresh }) } : {}),
27
+ },
28
+ func: async () => opts.identity ?? { logged_in: true, site, username: site },
29
+ });
30
+ }
31
+ async function tempStatePath() {
32
+ const dir = await mkdtemp(join(tmpdir(), 'webcmd-auth-refresh-test-'));
33
+ return join(dir, 'auth-refresh.json');
34
+ }
35
+ beforeEach(() => {
36
+ getRegistry().clear();
37
+ executeCommandMock.mockReset();
38
+ executeCommandMock.mockImplementation(async (cmd, kwargs) => {
39
+ if (!cmd.func)
40
+ return {};
41
+ return cmd.func({ goto: vi.fn(), wait: vi.fn() }, kwargs);
42
+ });
43
+ });
44
+ describe('auth status collection', () => {
45
+ it('uses quickCheck by default and does not run full whoami', async () => {
46
+ registerWhoami('alpha', { quick: true, quickLoggedIn: true, identity: { username: 'full-alpha' } });
47
+ const rows = await collectAuthStatus({ sites: 'alpha' });
48
+ expect(rows).toEqual([
49
+ { site: 'alpha', status: 'logged_in', logged_in: true, identity: '', checked: 'quick', error: '' },
50
+ ]);
51
+ expect(executeCommandMock).toHaveBeenCalledTimes(1);
52
+ expect(executeCommandMock.mock.calls[0]?.[0]).toMatchObject({
53
+ site: 'alpha',
54
+ name: 'whoami',
55
+ navigateBefore: false,
56
+ siteSession: 'ephemeral',
57
+ defaultWindowMode: 'background',
58
+ });
59
+ });
60
+ it('marks sites without quickCheck as unknown unless --full is used', async () => {
61
+ registerWhoami('beta');
62
+ const rows = await collectAuthStatus({ sites: 'beta' });
63
+ expect(rows).toEqual([
64
+ {
65
+ site: 'beta',
66
+ status: 'unknown',
67
+ logged_in: '',
68
+ identity: '',
69
+ checked: 'skipped',
70
+ error: 'quickCheck not implemented; use --full to run whoami',
71
+ },
72
+ ]);
73
+ expect(executeCommandMock).not.toHaveBeenCalled();
74
+ });
75
+ it('runs full whoami with --full and returns a safe identity summary', async () => {
76
+ registerWhoami('gamma', {
77
+ identity: {
78
+ logged_in: true,
79
+ site: 'gamma',
80
+ email: 'hidden@example.com',
81
+ username: 'public-handle',
82
+ },
83
+ });
84
+ const rows = await collectAuthStatus({ sites: 'gamma', full: true });
85
+ expect(rows).toEqual([
86
+ { site: 'gamma', status: 'logged_in', logged_in: true, identity: 'public-handle', checked: 'full', error: '' },
87
+ ]);
88
+ });
89
+ it('converts AuthRequiredError into not_logged_in rows', async () => {
90
+ registerWhoami('delta', { quick: true });
91
+ executeCommandMock.mockRejectedValueOnce(new AuthRequiredError('delta.example.com'));
92
+ const rows = await collectAuthStatus({ sites: 'delta' });
93
+ expect(rows).toEqual([
94
+ { site: 'delta', status: 'not_logged_in', logged_in: false, identity: '', checked: 'quick', error: '' },
95
+ ]);
96
+ });
97
+ });
98
+ describe('auth refresh collection', () => {
99
+ it('touches sites through persistent sessions and writes last_touched_at on success', async () => {
100
+ registerWhoami('alpha', { quick: true, quickLoggedIn: true });
101
+ const statePath = await tempStatePath();
102
+ const now = new Date('2026-06-06T12:00:00.000Z');
103
+ const rows = await collectAuthRefresh({ sites: 'alpha', statePath, now });
104
+ expect(rows).toEqual([
105
+ {
106
+ site: 'alpha',
107
+ status: 'touched',
108
+ last_touched_at: now.toISOString(),
109
+ next_refresh_at: '2026-06-07T12:00:00.000Z',
110
+ error: '',
111
+ },
112
+ ]);
113
+ expect(executeCommandMock).toHaveBeenCalledTimes(1);
114
+ expect(executeCommandMock.mock.calls[0]?.[0]).toMatchObject({
115
+ site: 'alpha',
116
+ name: 'whoami',
117
+ navigateBefore: false,
118
+ siteSession: 'persistent',
119
+ defaultWindowMode: 'background',
120
+ });
121
+ expect(executeCommandMock.mock.calls[0]?.[3]).toMatchObject({
122
+ siteSession: 'persistent',
123
+ keepTab: 'true',
124
+ windowMode: 'background',
125
+ });
126
+ const state = JSON.parse(await readFile(statePath, 'utf8'));
127
+ expect(state.sites.alpha).toMatchObject({
128
+ last_touched_at: now.toISOString(),
129
+ last_attempt_at: now.toISOString(),
130
+ last_status: 'touched',
131
+ });
132
+ });
133
+ it('uses adapter refresh hooks when present and records refreshed', async () => {
134
+ registerWhoami('beta', { refresh: 'refreshed' });
135
+ const statePath = await tempStatePath();
136
+ const rows = await collectAuthRefresh({
137
+ sites: 'beta',
138
+ statePath,
139
+ now: new Date('2026-06-06T12:00:00.000Z'),
140
+ });
141
+ expect(rows[0]?.status).toBe('refreshed');
142
+ expect(executeCommandMock).toHaveBeenCalledTimes(1);
143
+ });
144
+ it('skips sites touched within the hidden 24h throttle', async () => {
145
+ registerWhoami('gamma', { quick: true, quickLoggedIn: true });
146
+ const statePath = await tempStatePath();
147
+ await collectAuthRefresh({
148
+ sites: 'gamma',
149
+ statePath,
150
+ now: new Date('2026-06-06T12:00:00.000Z'),
151
+ });
152
+ executeCommandMock.mockClear();
153
+ const rows = await collectAuthRefresh({
154
+ sites: 'gamma',
155
+ statePath,
156
+ now: new Date('2026-06-07T11:59:00.000Z'),
157
+ });
158
+ expect(rows).toEqual([
159
+ {
160
+ site: 'gamma',
161
+ status: 'skipped',
162
+ last_touched_at: '2026-06-06T12:00:00.000Z',
163
+ next_refresh_at: '2026-06-07T12:00:00.000Z',
164
+ error: '',
165
+ },
166
+ ]);
167
+ expect(executeCommandMock).not.toHaveBeenCalled();
168
+ });
169
+ it('lets --all bypass the 24h throttle', async () => {
170
+ registerWhoami('delta', { quick: true, quickLoggedIn: true });
171
+ const statePath = await tempStatePath();
172
+ await collectAuthRefresh({
173
+ sites: 'delta',
174
+ statePath,
175
+ now: new Date('2026-06-06T12:00:00.000Z'),
176
+ });
177
+ executeCommandMock.mockClear();
178
+ const rows = await collectAuthRefresh({
179
+ sites: 'delta',
180
+ all: true,
181
+ statePath,
182
+ now: new Date('2026-06-07T11:59:00.000Z'),
183
+ });
184
+ expect(rows[0]?.status).toBe('touched');
185
+ expect(rows[0]?.last_touched_at).toBe('2026-06-07T11:59:00.000Z');
186
+ expect(executeCommandMock).toHaveBeenCalledTimes(1);
187
+ });
188
+ it('does not throttle not_logged_in results', async () => {
189
+ registerWhoami('epsilon', { quick: true, quickLoggedIn: true });
190
+ const statePath = await tempStatePath();
191
+ executeCommandMock.mockRejectedValueOnce(new AuthRequiredError('epsilon.example.com'));
192
+ const rows = await collectAuthRefresh({
193
+ sites: 'epsilon',
194
+ statePath,
195
+ now: new Date('2026-06-06T12:00:00.000Z'),
196
+ });
197
+ expect(rows).toEqual([
198
+ { site: 'epsilon', status: 'not_logged_in', last_touched_at: '', next_refresh_at: '', error: '' },
199
+ ]);
200
+ const state = JSON.parse(await readFile(statePath, 'utf8'));
201
+ expect(state.sites.epsilon).toMatchObject({
202
+ last_attempt_at: '2026-06-06T12:00:00.000Z',
203
+ last_status: 'not_logged_in',
204
+ });
205
+ expect(state.sites.epsilon.last_touched_at).toBeUndefined();
206
+ executeCommandMock.mockClear();
207
+ await collectAuthRefresh({
208
+ sites: 'epsilon',
209
+ statePath,
210
+ now: new Date('2026-06-06T12:01:00.000Z'),
211
+ });
212
+ expect(executeCommandMock).toHaveBeenCalledTimes(1);
213
+ });
214
+ it('does not update last_touched_at for generic errors', async () => {
215
+ registerWhoami('zeta', { quick: true, quickLoggedIn: true });
216
+ const statePath = await tempStatePath();
217
+ executeCommandMock.mockRejectedValueOnce(new Error('network down'));
218
+ const rows = await collectAuthRefresh({
219
+ sites: 'zeta',
220
+ statePath,
221
+ now: new Date('2026-06-06T12:00:00.000Z'),
222
+ });
223
+ expect(rows).toEqual([
224
+ { site: 'zeta', status: 'error', last_touched_at: '', next_refresh_at: '', error: 'network down' },
225
+ ]);
226
+ const state = JSON.parse(await readFile(statePath, 'utf8'));
227
+ expect(state.sites.zeta).toMatchObject({
228
+ last_attempt_at: '2026-06-06T12:00:00.000Z',
229
+ last_status: 'error',
230
+ });
231
+ expect(state.sites.zeta.last_touched_at).toBeUndefined();
232
+ });
233
+ it('marks sites without quickCheck or refresh hook as unsupported instead of running DOM whoami fallback', async () => {
234
+ registerWhoami('eta');
235
+ const statePath = await tempStatePath();
236
+ const rows = await collectAuthRefresh({
237
+ sites: 'eta',
238
+ statePath,
239
+ now: new Date('2026-06-06T12:00:00.000Z'),
240
+ });
241
+ expect(rows).toEqual([
242
+ {
243
+ site: 'eta',
244
+ status: 'unsupported',
245
+ last_touched_at: '',
246
+ next_refresh_at: '',
247
+ error: 'refresh probe is not available for this site',
248
+ },
249
+ ]);
250
+ expect(executeCommandMock).not.toHaveBeenCalled();
251
+ });
252
+ });