@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,244 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { LocalCloakRuntimeProvider } from './provider.js';
3
+ function fakePage(url) {
4
+ let closed = false;
5
+ let viewportSize = { width: 1280, height: 720 };
6
+ return {
7
+ isClosed: vi.fn(() => closed),
8
+ goto: vi.fn(async (nextUrl) => {
9
+ url = nextUrl;
10
+ }),
11
+ evaluate: vi.fn().mockResolvedValue({ ok: true }),
12
+ frames: vi.fn(() => []),
13
+ title: vi.fn().mockResolvedValue('Example'),
14
+ url: vi.fn(() => url),
15
+ screenshot: vi.fn().mockResolvedValue(Buffer.from('image')),
16
+ viewportSize: vi.fn(() => viewportSize),
17
+ setViewportSize: vi.fn(async (size) => {
18
+ viewportSize = size;
19
+ }),
20
+ locator: vi.fn(),
21
+ bringToFront: vi.fn().mockResolvedValue(undefined),
22
+ close: vi.fn().mockImplementation(async () => {
23
+ closed = true;
24
+ }),
25
+ };
26
+ }
27
+ function makeProviderWithFakePage() {
28
+ const pages = [fakePage('https://example.com/')];
29
+ const context = {
30
+ pages: vi.fn(() => pages.filter((page) => !page.isClosed())),
31
+ newPage: vi.fn(async () => {
32
+ const page = fakePage('about:blank');
33
+ pages.push(page);
34
+ return page;
35
+ }),
36
+ cookies: vi.fn().mockResolvedValue([{ name: 'sid', value: '1', domain: 'example.com', path: '/' }]),
37
+ close: vi.fn().mockResolvedValue(undefined),
38
+ };
39
+ const provider = new LocalCloakRuntimeProvider({
40
+ baseDir: '/tmp/webcmd-test',
41
+ launchPersistentContext: vi.fn().mockResolvedValue(context),
42
+ });
43
+ return { provider, page: pages[0], pages, context };
44
+ }
45
+ describe('LocalCloakRuntimeProvider', () => {
46
+ it('reports a runtime-named connected status before any profile launches', async () => {
47
+ const provider = new LocalCloakRuntimeProvider({ baseDir: '/tmp/webcmd-test' });
48
+ await expect(provider.status()).resolves.toMatchObject({
49
+ runtimeConnected: true,
50
+ runtimeName: 'cloak',
51
+ profiles: [],
52
+ pending: 0,
53
+ });
54
+ });
55
+ it('navigates and returns page identity', async () => {
56
+ const { provider, page } = makeProviderWithFakePage();
57
+ const result = await provider.dispatch({
58
+ id: 'cmd-1',
59
+ action: 'navigate',
60
+ session: 'work',
61
+ surface: 'browser',
62
+ url: 'https://example.com/',
63
+ profileId: 'default',
64
+ });
65
+ expect(result).toMatchObject({ id: 'cmd-1', ok: true, page: expect.any(String) });
66
+ expect(page.goto).toHaveBeenCalledWith('https://example.com/', expect.objectContaining({ waitUntil: 'load' }));
67
+ });
68
+ it('evaluates JavaScript in the resolved page', async () => {
69
+ const { provider } = makeProviderWithFakePage();
70
+ const nav = await provider.dispatch({ id: 'nav', action: 'navigate', session: 'work', surface: 'browser', url: 'https://example.com/', profileId: 'default' });
71
+ await expect(provider.dispatch({ id: 'exec', action: 'exec', session: 'work', surface: 'browser', page: nav.page, code: '1 + 1', profileId: 'default' }))
72
+ .resolves.toMatchObject({ id: 'exec', ok: true, data: { ok: true }, page: nav.page });
73
+ });
74
+ it('evaluates JavaScript in the requested iframe', async () => {
75
+ const { provider, page } = makeProviderWithFakePage();
76
+ const frame = { evaluate: vi.fn().mockResolvedValue('inside frame'), url: vi.fn(() => 'https://frame.example/'), name: vi.fn(() => 'frame') };
77
+ page.frames.mockReturnValue([page, frame]);
78
+ const nav = await provider.dispatch({ id: 'nav', action: 'navigate', session: 'work', surface: 'browser', url: 'https://example.com/', profileId: 'default' });
79
+ await expect(provider.dispatch({ id: 'exec', action: 'exec', session: 'work', surface: 'browser', page: nav.page, frameIndex: 0, code: 'document.body.textContent', profileId: 'default' }))
80
+ .resolves.toMatchObject({ id: 'exec', ok: true, data: 'inside frame', page: nav.page });
81
+ expect(frame.evaluate).toHaveBeenCalledWith('document.body.textContent');
82
+ expect(page.evaluate).not.toHaveBeenCalledWith('document.body.textContent');
83
+ });
84
+ it('returns a typed error when the requested iframe is out of range', async () => {
85
+ const { provider, page } = makeProviderWithFakePage();
86
+ page.frames.mockReturnValue([page]);
87
+ const nav = await provider.dispatch({ id: 'nav', action: 'navigate', session: 'work', surface: 'browser', url: 'https://example.com/', profileId: 'default' });
88
+ await expect(provider.dispatch({ id: 'exec', action: 'exec', session: 'work', surface: 'browser', page: nav.page, frameIndex: 0, code: '1 + 1', profileId: 'default' }))
89
+ .resolves.toMatchObject({
90
+ id: 'exec',
91
+ ok: false,
92
+ errorCode: 'frame_not_found',
93
+ error: 'Frame not found: 0',
94
+ page: nav.page,
95
+ });
96
+ });
97
+ it('returns a typed stale page error instead of falling back when command.page is unknown', async () => {
98
+ const { provider, page } = makeProviderWithFakePage();
99
+ await provider.dispatch({ id: 'nav', action: 'navigate', session: 'work', surface: 'browser', url: 'https://example.com/', profileId: 'default' });
100
+ await expect(provider.dispatch({ id: 'exec', action: 'exec', session: 'work', surface: 'browser', page: 'page-stale', code: '1 + 1', profileId: 'default' }))
101
+ .resolves.toMatchObject({
102
+ id: 'exec',
103
+ ok: false,
104
+ errorCode: 'stale_page_identity',
105
+ error: 'Page not found: page-stale — stale page identity',
106
+ });
107
+ expect(page.evaluate).not.toHaveBeenCalled();
108
+ });
109
+ it('returns typed validation errors for missing navigate url and exec code', async () => {
110
+ const { provider } = makeProviderWithFakePage();
111
+ await expect(provider.dispatch({ id: 'nav', action: 'navigate', session: 'work', surface: 'browser', profileId: 'default' }))
112
+ .resolves.toMatchObject({ id: 'nav', ok: false, errorCode: 'invalid_request', error: 'Missing url' });
113
+ await expect(provider.dispatch({ id: 'exec', action: 'exec', session: 'work', surface: 'browser', profileId: 'default' }))
114
+ .resolves.toMatchObject({ id: 'exec', ok: false, errorCode: 'invalid_request', error: 'Missing code' });
115
+ });
116
+ it('returns filtered cookies from the resolved context', async () => {
117
+ const { provider } = makeProviderWithFakePage();
118
+ await expect(provider.dispatch({ id: 'cookies', action: 'cookies', session: 'work', surface: 'browser', domain: 'example.com', profileId: 'default' }))
119
+ .resolves.toMatchObject({ id: 'cookies', ok: true, data: [{ name: 'sid', value: '1', domain: 'example.com', path: '/' }] });
120
+ });
121
+ it('captures screenshots as base64 and preserves page identity', async () => {
122
+ const { provider } = makeProviderWithFakePage();
123
+ const nav = await provider.dispatch({ id: 'nav', action: 'navigate', session: 'work', surface: 'browser', url: 'https://example.com/', profileId: 'default' });
124
+ await expect(provider.dispatch({ id: 'shot', action: 'screenshot', session: 'work', surface: 'browser', page: nav.page, format: 'png', fullPage: true, profileId: 'default' }))
125
+ .resolves.toMatchObject({ id: 'shot', ok: true, data: Buffer.from('image').toString('base64'), page: nav.page });
126
+ });
127
+ it('applies screenshot width overrides with the current viewport height', async () => {
128
+ const { provider, page } = makeProviderWithFakePage();
129
+ const nav = await provider.dispatch({ id: 'nav', action: 'navigate', session: 'work', surface: 'browser', url: 'https://example.com/', profileId: 'default' });
130
+ await provider.dispatch({ id: 'shot', action: 'screenshot', session: 'work', surface: 'browser', page: nav.page, format: 'png', width: 900, profileId: 'default' });
131
+ expect(page.setViewportSize).toHaveBeenCalledWith({ width: 900, height: 720 });
132
+ expect(page.screenshot).toHaveBeenCalledWith(expect.objectContaining({ fullPage: undefined }));
133
+ });
134
+ it('applies screenshot height overrides with the current viewport width', async () => {
135
+ const { provider, page } = makeProviderWithFakePage();
136
+ const nav = await provider.dispatch({ id: 'nav', action: 'navigate', session: 'work', surface: 'browser', url: 'https://example.com/', profileId: 'default' });
137
+ await provider.dispatch({ id: 'shot', action: 'screenshot', session: 'work', surface: 'browser', page: nav.page, format: 'png', height: 480, profileId: 'default' });
138
+ expect(page.setViewportSize).toHaveBeenCalledWith({ width: 1280, height: 480 });
139
+ });
140
+ it('restores the previous viewport after screenshot overrides', async () => {
141
+ const { provider, page } = makeProviderWithFakePage();
142
+ const nav = await provider.dispatch({ id: 'nav', action: 'navigate', session: 'work', surface: 'browser', url: 'https://example.com/', profileId: 'default' });
143
+ await provider.dispatch({ id: 'shot', action: 'screenshot', session: 'work', surface: 'browser', page: nav.page, format: 'png', width: 900, height: 480, profileId: 'default' });
144
+ expect(page.setViewportSize).toHaveBeenNthCalledWith(1, { width: 900, height: 480 });
145
+ expect(page.setViewportSize).toHaveBeenNthCalledWith(2, { width: 1280, height: 720 });
146
+ expect(page.screenshot).toHaveBeenCalledTimes(1);
147
+ });
148
+ it('ignores screenshot height overrides for full-page captures while applying width', async () => {
149
+ const { provider, page } = makeProviderWithFakePage();
150
+ const nav = await provider.dispatch({ id: 'nav', action: 'navigate', session: 'work', surface: 'browser', url: 'https://example.com/', profileId: 'default' });
151
+ await provider.dispatch({ id: 'shot', action: 'screenshot', session: 'work', surface: 'browser', page: nav.page, format: 'png', fullPage: true, width: 700, height: 480, profileId: 'default' });
152
+ expect(page.setViewportSize).toHaveBeenCalledWith({ width: 700, height: 720 });
153
+ expect(page.screenshot).toHaveBeenCalledWith(expect.objectContaining({ fullPage: true }));
154
+ });
155
+ it('requires an explicit Cloak tab target for bind', async () => {
156
+ const { provider } = makeProviderWithFakePage();
157
+ await expect(provider.dispatch({ id: 'bind', action: 'bind', session: 'work', surface: 'browser', profileId: 'default' }))
158
+ .resolves.toMatchObject({
159
+ id: 'bind',
160
+ ok: false,
161
+ errorCode: 'invalid_request',
162
+ error: 'Bind requires --page or --index for a Cloak runtime tab',
163
+ });
164
+ });
165
+ it('binds a browser session to an existing Cloak tab by page id', async () => {
166
+ const { provider, pages } = makeProviderWithFakePage();
167
+ const created = await provider.dispatch({ id: 'new', action: 'tabs', op: 'new', session: 'manual', surface: 'browser', url: 'https://signed-in.example/', profileId: 'default' });
168
+ await expect(provider.dispatch({ id: 'bind', action: 'bind', session: 'work', surface: 'browser', page: created.page, profileId: 'default' }))
169
+ .resolves.toMatchObject({
170
+ id: 'bind',
171
+ ok: true,
172
+ page: created.page,
173
+ data: { bound: true, session: 'work', page: created.page, url: 'https://signed-in.example/' },
174
+ });
175
+ await provider.dispatch({ id: 'exec', action: 'exec', session: 'work', surface: 'browser', code: 'window.__loggedIn', profileId: 'default' });
176
+ expect(pages[1].evaluate).toHaveBeenCalledWith('window.__loggedIn');
177
+ expect(pages[0].evaluate).not.toHaveBeenCalledWith('window.__loggedIn');
178
+ });
179
+ it('binds a browser session to an existing Cloak tab by index', async () => {
180
+ const { provider, pages } = makeProviderWithFakePage();
181
+ await provider.dispatch({ id: 'nav', action: 'navigate', session: 'first', surface: 'browser', url: 'https://first.example/', profileId: 'default' });
182
+ await provider.dispatch({ id: 'new', action: 'tabs', op: 'new', session: 'manual', surface: 'browser', url: 'https://second.example/', profileId: 'default' });
183
+ await expect(provider.dispatch({ id: 'bind', action: 'bind', session: 'work', surface: 'browser', index: 1, profileId: 'default' }))
184
+ .resolves.toMatchObject({
185
+ id: 'bind',
186
+ ok: true,
187
+ data: { bound: true, session: 'work', url: 'https://second.example/' },
188
+ });
189
+ await provider.dispatch({ id: 'exec', action: 'exec', session: 'work', surface: 'browser', code: 'document.readyState', profileId: 'default' });
190
+ expect(pages[1].evaluate).toHaveBeenCalledWith('document.readyState');
191
+ });
192
+ it('returns a typed bind error when the requested Cloak tab is missing', async () => {
193
+ const { provider } = makeProviderWithFakePage();
194
+ await provider.dispatch({ id: 'nav', action: 'navigate', session: 'first', surface: 'browser', url: 'https://first.example/', profileId: 'default' });
195
+ await expect(provider.dispatch({ id: 'bind', action: 'bind', session: 'work', surface: 'browser', page: 'missing-page', profileId: 'default' }))
196
+ .resolves.toMatchObject({
197
+ id: 'bind',
198
+ ok: false,
199
+ errorCode: 'bound_tab_not_found',
200
+ error: 'Cloak tab not found for bind target',
201
+ });
202
+ });
203
+ it('sets file input through the first matching locator', async () => {
204
+ const { provider, page } = makeProviderWithFakePage();
205
+ const setInputFiles = vi.fn().mockResolvedValue(undefined);
206
+ page.locator = vi.fn().mockReturnValue({ first: () => ({ setInputFiles }) });
207
+ const nav = await provider.dispatch({ id: 'nav', action: 'navigate', session: 'work', surface: 'browser', url: 'https://example.com/', profileId: 'default' });
208
+ await expect(provider.dispatch({ id: 'upload', action: 'set-file-input', session: 'work', surface: 'browser', page: nav.page, files: ['/tmp/a.txt'], profileId: 'default' }))
209
+ .resolves.toMatchObject({ id: 'upload', ok: true, data: { count: 1 } });
210
+ expect(setInputFiles).toHaveBeenCalledWith(['/tmp/a.txt']);
211
+ });
212
+ it('lists current tabs with page identities', async () => {
213
+ const { provider } = makeProviderWithFakePage();
214
+ const nav = await provider.dispatch({ id: 'nav', action: 'navigate', session: 'work', surface: 'browser', url: 'https://example.com/', profileId: 'default' });
215
+ await expect(provider.dispatch({ id: 'tabs', action: 'tabs', op: 'list', session: 'work', surface: 'browser', profileId: 'default' }))
216
+ .resolves.toMatchObject({
217
+ id: 'tabs',
218
+ ok: true,
219
+ data: [expect.objectContaining({ id: nav.page, page: nav.page, index: 0, url: 'https://example.com/' })],
220
+ });
221
+ });
222
+ it('creates, selects, and closes tabs by command op', async () => {
223
+ const { provider, pages } = makeProviderWithFakePage();
224
+ const created = await provider.dispatch({ id: 'new', action: 'tabs', op: 'new', session: 'work', surface: 'browser', url: 'https://second.example/', profileId: 'default' });
225
+ expect(created).toMatchObject({ id: 'new', ok: true, page: expect.any(String), data: { url: 'https://second.example/' } });
226
+ expect(pages[1].goto).toHaveBeenCalledWith('https://second.example/', expect.objectContaining({ waitUntil: 'load' }));
227
+ await expect(provider.dispatch({ id: 'select', action: 'tabs', op: 'select', session: 'work', surface: 'browser', page: created.page, profileId: 'default' }))
228
+ .resolves.toMatchObject({ id: 'select', ok: true, page: created.page, data: { selected: true } });
229
+ expect(pages[1].bringToFront).toHaveBeenCalled();
230
+ await expect(provider.dispatch({ id: 'close', action: 'tabs', op: 'close', session: 'work', surface: 'browser', page: created.page, profileId: 'default' }))
231
+ .resolves.toMatchObject({ id: 'close', ok: true, data: { closed: created.page } });
232
+ expect(pages[1].close).toHaveBeenCalled();
233
+ });
234
+ it('closes a window by page identity when command.page is provided', async () => {
235
+ const { provider, pages } = makeProviderWithFakePage();
236
+ const first = await provider.dispatch({ id: 'first', action: 'navigate', session: 'first', surface: 'browser', url: 'https://first.example/', profileId: 'default' });
237
+ const second = await provider.dispatch({ id: 'second', action: 'tabs', op: 'new', session: 'second', surface: 'browser', url: 'https://second.example/', profileId: 'default' });
238
+ await expect(provider.dispatch({ id: 'close-window', action: 'close-window', session: 'first', surface: 'browser', page: second.page, profileId: 'default' }))
239
+ .resolves.toMatchObject({ id: 'close-window', ok: true, data: { closed: true, page: second.page } });
240
+ expect(pages[0].isClosed()).toBe(false);
241
+ expect(pages[1].close).toHaveBeenCalled();
242
+ expect(first.page).not.toBe(second.page);
243
+ });
244
+ });
@@ -0,0 +1,77 @@
1
+ import type { BrowserContext, Page as PlaywrightPage } from 'playwright-core';
2
+ import { launchPersistentContext as cloakLaunchPersistentContext } from 'cloakbrowser';
3
+ import type { BrowserSurface, SiteSessionMode } from '../../protocol.js';
4
+ import { CloakNetworkCapture } from './network.js';
5
+ export type LaunchPersistentContext = typeof cloakLaunchPersistentContext;
6
+ export interface SessionKeyInput {
7
+ profileId?: string;
8
+ session?: string;
9
+ surface?: BrowserSurface;
10
+ siteSession?: SiteSessionMode;
11
+ idleTimeout?: number;
12
+ }
13
+ export interface CloakPageLease {
14
+ profileId: string;
15
+ leaseKey: string;
16
+ context: BrowserContext;
17
+ page: PlaywrightPage;
18
+ pageId: string;
19
+ }
20
+ export interface CloakTabInfo {
21
+ id: string;
22
+ page: string;
23
+ index: number;
24
+ title: string;
25
+ url: string;
26
+ profileId: string;
27
+ session: string;
28
+ surface: BrowserSurface;
29
+ selected: boolean;
30
+ }
31
+ export interface CloakSessionManagerOptions {
32
+ baseDir?: string;
33
+ launchPersistentContext?: LaunchPersistentContext;
34
+ }
35
+ export declare function resolveLeaseKey(input: SessionKeyInput): string;
36
+ export declare class CloakSessionManager {
37
+ private readonly opts;
38
+ readonly networkCapture: CloakNetworkCapture;
39
+ private readonly launchPersistentContext;
40
+ private readonly profiles;
41
+ constructor(opts?: CloakSessionManagerOptions);
42
+ profileStatuses(): {
43
+ contextId: string;
44
+ runtimeConnected: boolean;
45
+ runtimeVersion: string | undefined;
46
+ pending: number;
47
+ lastSeenAt: number;
48
+ }[];
49
+ getPage(input: SessionKeyInput): Promise<CloakPageLease>;
50
+ findPageById(pageId: string, opts?: Pick<SessionKeyInput, 'idleTimeout'>): CloakPageLease | null;
51
+ pageIdFor(page: PlaywrightPage): string | undefined;
52
+ registerPage(input: SessionKeyInput, page: PlaywrightPage): string;
53
+ listPages(input: Pick<SessionKeyInput, 'profileId'>): Promise<CloakTabInfo[]>;
54
+ newPage(input: SessionKeyInput & {
55
+ url?: string;
56
+ }): Promise<CloakPageLease>;
57
+ selectPage(input: Pick<SessionKeyInput, 'profileId'> & {
58
+ pageId?: string;
59
+ index?: number;
60
+ }): Promise<CloakPageLease | null>;
61
+ bindPage(input: SessionKeyInput & {
62
+ pageId?: string;
63
+ index?: number;
64
+ }): Promise<CloakPageLease | null>;
65
+ closePage(input: Pick<SessionKeyInput, 'profileId'> & {
66
+ pageId?: string;
67
+ index?: number;
68
+ }): Promise<string | null>;
69
+ release(input: SessionKeyInput): Promise<void>;
70
+ shutdown(): Promise<void>;
71
+ private getProfileRuntime;
72
+ private openEntries;
73
+ private findEntryByPageId;
74
+ private refreshIdleTimer;
75
+ private expireLease;
76
+ private clearIdleTimer;
77
+ }
@@ -0,0 +1,280 @@
1
+ import fs from 'node:fs';
2
+ import { launchPersistentContext as cloakLaunchPersistentContext } from 'cloakbrowser';
3
+ import { normalizeProfileId, resolveCloakProfileDir } from './profiles.js';
4
+ import { CloakNetworkCapture } from './network.js';
5
+ let pageCounter = 0;
6
+ export function resolveLeaseKey(input) {
7
+ const surface = input.surface === 'adapter' ? 'adapter' : 'browser';
8
+ const session = input.session?.trim();
9
+ if (!session)
10
+ throw new Error('Browser session is required.');
11
+ return `${surface}\u0000${encodeURIComponent(session)}`;
12
+ }
13
+ function pageIsClosed(page) {
14
+ return page.isClosed?.() === true;
15
+ }
16
+ export class CloakSessionManager {
17
+ opts;
18
+ networkCapture = new CloakNetworkCapture();
19
+ launchPersistentContext;
20
+ profiles = new Map();
21
+ constructor(opts = {}) {
22
+ this.opts = opts;
23
+ this.launchPersistentContext = opts.launchPersistentContext ?? cloakLaunchPersistentContext;
24
+ }
25
+ profileStatuses() {
26
+ return [...this.profiles.entries()].map(([contextId, runtime]) => ({
27
+ contextId,
28
+ runtimeConnected: true,
29
+ runtimeVersion: runtime.runtimeVersion,
30
+ pending: 0,
31
+ lastSeenAt: runtime.lastSeenAt,
32
+ }));
33
+ }
34
+ async getPage(input) {
35
+ const profileId = normalizeProfileId(input.profileId);
36
+ const session = requireSession(input.session);
37
+ const surface = normalizeSurface(input.surface);
38
+ const leaseKey = resolveLeaseKey(input);
39
+ const runtime = await this.getProfileRuntime(profileId);
40
+ const existing = runtime.pages.get(leaseKey);
41
+ if (existing && !pageIsClosed(existing.page)) {
42
+ runtime.lastSeenAt = Date.now();
43
+ existing.idleTimeout = input.idleTimeout;
44
+ this.refreshIdleTimer(runtime, leaseKey, existing);
45
+ return { profileId, leaseKey, context: runtime.context, page: existing.page, pageId: existing.pageId };
46
+ }
47
+ const existingPages = runtime.context.pages();
48
+ const page = existingPages[0] && runtime.pages.size === 0 ? existingPages[0] : await runtime.context.newPage();
49
+ const pageId = nextPageId();
50
+ const entry = { page, pageId, session, surface, siteSession: input.siteSession, idleTimeout: input.idleTimeout };
51
+ runtime.pages.set(leaseKey, entry);
52
+ this.refreshIdleTimer(runtime, leaseKey, entry);
53
+ runtime.selectedPageId = pageId;
54
+ runtime.lastSeenAt = Date.now();
55
+ return { profileId, leaseKey, context: runtime.context, page, pageId };
56
+ }
57
+ findPageById(pageId, opts = {}) {
58
+ for (const [profileId, runtime] of this.profiles.entries()) {
59
+ for (const [leaseKey, entry] of runtime.pages.entries()) {
60
+ if (entry.pageId === pageId && !pageIsClosed(entry.page)) {
61
+ entry.idleTimeout = opts.idleTimeout;
62
+ this.refreshIdleTimer(runtime, leaseKey, entry);
63
+ return { profileId, leaseKey, context: runtime.context, page: entry.page, pageId: entry.pageId };
64
+ }
65
+ }
66
+ }
67
+ return null;
68
+ }
69
+ pageIdFor(page) {
70
+ for (const runtime of this.profiles.values()) {
71
+ for (const entry of runtime.pages.values()) {
72
+ if (entry.page === page)
73
+ return entry.pageId;
74
+ }
75
+ }
76
+ return undefined;
77
+ }
78
+ registerPage(input, page) {
79
+ const profileId = normalizeProfileId(input.profileId);
80
+ const session = requireSession(input.session);
81
+ const surface = normalizeSurface(input.surface);
82
+ const runtime = this.profiles.get(profileId);
83
+ if (!runtime)
84
+ throw new Error(`Profile ${profileId} is not running`);
85
+ const pageId = nextPageId();
86
+ const leaseKey = `${resolveLeaseKey(input)}\u0000${pageId}`;
87
+ const entry = { page, pageId, session, surface, siteSession: input.siteSession, idleTimeout: input.idleTimeout };
88
+ runtime.pages.set(leaseKey, entry);
89
+ this.refreshIdleTimer(runtime, leaseKey, entry);
90
+ runtime.selectedPageId = pageId;
91
+ runtime.lastSeenAt = Date.now();
92
+ return pageId;
93
+ }
94
+ async listPages(input) {
95
+ const profileId = normalizeProfileId(input.profileId);
96
+ const runtime = this.profiles.get(profileId);
97
+ if (!runtime)
98
+ return [];
99
+ const entries = this.openEntries(runtime);
100
+ return Promise.all(entries.map(async ([, entry], index) => ({
101
+ id: entry.pageId,
102
+ page: entry.pageId,
103
+ index,
104
+ title: await entry.page.title().catch(() => ''),
105
+ url: entry.page.url(),
106
+ profileId,
107
+ session: entry.session,
108
+ surface: entry.surface,
109
+ selected: runtime.selectedPageId === entry.pageId,
110
+ })));
111
+ }
112
+ async newPage(input) {
113
+ const profileId = normalizeProfileId(input.profileId);
114
+ const session = requireSession(input.session);
115
+ const surface = normalizeSurface(input.surface);
116
+ const runtime = await this.getProfileRuntime(profileId);
117
+ const page = await runtime.context.newPage();
118
+ if (input.url) {
119
+ await page.goto(input.url, { waitUntil: 'load' });
120
+ }
121
+ const pageId = nextPageId();
122
+ const leaseKey = `${resolveLeaseKey(input)}\u0000${pageId}`;
123
+ const entry = { page, pageId, session, surface, siteSession: input.siteSession, idleTimeout: input.idleTimeout };
124
+ runtime.pages.set(leaseKey, entry);
125
+ this.refreshIdleTimer(runtime, leaseKey, entry);
126
+ runtime.lastSeenAt = Date.now();
127
+ return { profileId, leaseKey, context: runtime.context, page, pageId };
128
+ }
129
+ async selectPage(input) {
130
+ const profileId = normalizeProfileId(input.profileId);
131
+ const runtime = this.profiles.get(profileId);
132
+ if (!runtime)
133
+ return null;
134
+ const match = input.pageId ? this.findEntryByPageId(runtime, input.pageId) : this.openEntries(runtime)[input.index ?? -1];
135
+ if (!match)
136
+ return null;
137
+ const [leaseKey, entry] = match;
138
+ await entry.page.bringToFront?.().catch(() => { });
139
+ runtime.selectedPageId = entry.pageId;
140
+ runtime.lastSeenAt = Date.now();
141
+ return { profileId, leaseKey, context: runtime.context, page: entry.page, pageId: entry.pageId };
142
+ }
143
+ async bindPage(input) {
144
+ const profileId = normalizeProfileId(input.profileId);
145
+ const session = requireSession(input.session);
146
+ const surface = normalizeSurface(input.surface);
147
+ const runtime = this.profiles.get(profileId);
148
+ if (!runtime)
149
+ return null;
150
+ const match = input.pageId ? this.findEntryByPageId(runtime, input.pageId) : this.openEntries(runtime)[input.index ?? -1];
151
+ if (!match)
152
+ return null;
153
+ const [sourceKey, entry] = match;
154
+ const canonicalKey = resolveLeaseKey({ profileId, session, surface });
155
+ const currentCanonical = runtime.pages.get(canonicalKey);
156
+ if (currentCanonical && currentCanonical !== entry && !pageIsClosed(currentCanonical.page)) {
157
+ const preservedKey = `${canonicalKey}\u0000${currentCanonical.pageId}`;
158
+ runtime.pages.delete(canonicalKey);
159
+ runtime.pages.set(preservedKey, currentCanonical);
160
+ this.refreshIdleTimer(runtime, preservedKey, currentCanonical);
161
+ }
162
+ if (sourceKey !== canonicalKey)
163
+ runtime.pages.delete(sourceKey);
164
+ entry.session = session;
165
+ entry.surface = surface;
166
+ entry.siteSession = input.siteSession;
167
+ entry.idleTimeout = input.idleTimeout;
168
+ runtime.pages.set(canonicalKey, entry);
169
+ await entry.page.bringToFront?.().catch(() => { });
170
+ this.refreshIdleTimer(runtime, canonicalKey, entry);
171
+ runtime.selectedPageId = entry.pageId;
172
+ runtime.lastSeenAt = Date.now();
173
+ return { profileId, leaseKey: canonicalKey, context: runtime.context, page: entry.page, pageId: entry.pageId };
174
+ }
175
+ async closePage(input) {
176
+ const profileId = normalizeProfileId(input.profileId);
177
+ const runtime = this.profiles.get(profileId);
178
+ if (!runtime)
179
+ return null;
180
+ const match = input.pageId ? this.findEntryByPageId(runtime, input.pageId) : this.openEntries(runtime)[input.index ?? -1];
181
+ if (!match)
182
+ return null;
183
+ const [leaseKey, entry] = match;
184
+ runtime.pages.delete(leaseKey);
185
+ this.clearIdleTimer(entry);
186
+ if (runtime.selectedPageId === entry.pageId)
187
+ runtime.selectedPageId = undefined;
188
+ if (!pageIsClosed(entry.page))
189
+ await entry.page.close().catch(() => { });
190
+ runtime.lastSeenAt = Date.now();
191
+ return entry.pageId;
192
+ }
193
+ async release(input) {
194
+ const profileId = normalizeProfileId(input.profileId);
195
+ const runtime = this.profiles.get(profileId);
196
+ if (!runtime)
197
+ return;
198
+ const leaseKey = resolveLeaseKey(input);
199
+ const exactEntry = runtime.pages.get(leaseKey);
200
+ const entries = exactEntry
201
+ ? [[leaseKey, exactEntry]]
202
+ : this.openEntries(runtime).filter(([, entry]) => entry.session === requireSession(input.session) && entry.surface === normalizeSurface(input.surface));
203
+ for (const [key, entry] of entries) {
204
+ runtime.pages.delete(key);
205
+ this.clearIdleTimer(entry);
206
+ if (runtime.selectedPageId === entry.pageId)
207
+ runtime.selectedPageId = undefined;
208
+ if (entry.siteSession !== 'persistent' && !pageIsClosed(entry.page)) {
209
+ await entry.page.close().catch(() => { });
210
+ }
211
+ }
212
+ }
213
+ async shutdown() {
214
+ for (const runtime of this.profiles.values()) {
215
+ for (const entry of runtime.pages.values())
216
+ this.clearIdleTimer(entry);
217
+ await runtime.context.close().catch(() => { });
218
+ }
219
+ this.profiles.clear();
220
+ }
221
+ async getProfileRuntime(profileId) {
222
+ const existing = this.profiles.get(profileId);
223
+ if (existing)
224
+ return existing;
225
+ const userDataDir = resolveCloakProfileDir(profileId, { baseDir: this.opts.baseDir });
226
+ fs.mkdirSync(userDataDir, { recursive: true });
227
+ const context = await this.launchPersistentContext({
228
+ userDataDir,
229
+ headless: false,
230
+ humanize: true,
231
+ });
232
+ const runtime = { context, pages: new Map(), lastSeenAt: Date.now() };
233
+ this.profiles.set(profileId, runtime);
234
+ return runtime;
235
+ }
236
+ openEntries(runtime) {
237
+ return [...runtime.pages.entries()].filter(([, entry]) => !pageIsClosed(entry.page));
238
+ }
239
+ findEntryByPageId(runtime, pageId) {
240
+ return this.openEntries(runtime).find(([, entry]) => entry.pageId === pageId) ?? null;
241
+ }
242
+ refreshIdleTimer(runtime, leaseKey, entry) {
243
+ this.clearIdleTimer(entry);
244
+ if (!entry.idleTimeout || entry.idleTimeout <= 0 || entry.siteSession === 'persistent')
245
+ return;
246
+ entry.idleTimer = setTimeout(() => {
247
+ void this.expireLease(runtime, leaseKey, entry);
248
+ }, entry.idleTimeout);
249
+ entry.idleTimer.unref?.();
250
+ }
251
+ async expireLease(runtime, leaseKey, entry) {
252
+ if (runtime.pages.get(leaseKey) !== entry)
253
+ return;
254
+ runtime.pages.delete(leaseKey);
255
+ this.clearIdleTimer(entry);
256
+ if (runtime.selectedPageId === entry.pageId)
257
+ runtime.selectedPageId = undefined;
258
+ runtime.lastSeenAt = Date.now();
259
+ if (entry.siteSession !== 'persistent' && !pageIsClosed(entry.page)) {
260
+ await entry.page.close().catch(() => { });
261
+ }
262
+ }
263
+ clearIdleTimer(entry) {
264
+ if (entry.idleTimer)
265
+ clearTimeout(entry.idleTimer);
266
+ entry.idleTimer = undefined;
267
+ }
268
+ }
269
+ function nextPageId() {
270
+ return `page-${Date.now()}-${++pageCounter}`;
271
+ }
272
+ function normalizeSurface(surface) {
273
+ return surface === 'adapter' ? 'adapter' : 'browser';
274
+ }
275
+ function requireSession(session) {
276
+ const normalized = session?.trim();
277
+ if (!normalized)
278
+ throw new Error('Browser session is required.');
279
+ return normalized;
280
+ }