@noxsoft/anima 7.0.1 → 7.0.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 (421) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/{accounts-COxGcLGB.js → accounts-BDDwy6Zf.js} +3 -3
  3. package/dist/{accounts-DIES085e.js → accounts-BNxfCMUW.js} +5 -5
  4. package/dist/{accounts-B_2nt5Cd.js → accounts-BzjBXZYp.js} +2 -2
  5. package/dist/{accounts-TUsfghIW.js → accounts-PpT_kved.js} +11 -11
  6. package/dist/{acp-cli-CWgqDQQH.js → acp-cli-B4F3SojX.js} +12 -12
  7. package/dist/{acp-cli-D0wfP8-l.js → acp-cli-CtTTCUan.js} +15 -15
  8. package/dist/{active-listener-BKtsWhsb.js → active-listener-C3NdbMQD.js} +4 -4
  9. package/dist/{active-listener-gGCoq55D.js → active-listener-D78ohfOc.js} +6 -6
  10. package/dist/{active-listener-D2r8IO7g.js → active-listener-Z1MbDSH8.js} +4 -4
  11. package/dist/{agent-paths-niQrLbGc.js → agent-paths-DRAU6-8h.js} +2 -2
  12. package/dist/{agent-scope-Dm8IL1Ks.js → agent-scope-B1FoYHfj.js} +3 -3
  13. package/dist/{agent-scope-CxBzAozu.js → agent-scope-CENGF2NR.js} +2 -2
  14. package/dist/{agent-scope-CXxC8FFX.js → agent-scope-DQ0N_hof.js} +2 -2
  15. package/dist/{agent-scope-ByIGrCTT.js → agent-scope-DpgOQfBp.js} +2 -2
  16. package/dist/{agent-PoYM2xa7.js → agent-viQL5eva.js} +18 -18
  17. package/dist/{agent-BjD_hkGZ.js → agent-xPFmA8jO.js} +14 -14
  18. package/dist/{agents-y3HCk1ks.js → agents-Cf9QArEB.js} +20 -20
  19. package/dist/{agents.config-BR5JLtud.js → agents.config-DrViQjgD.js} +1 -1
  20. package/dist/{agents.config-Br4ULmK0.js → agents.config-sfN0WxRg.js} +1 -1
  21. package/dist/{anthropic-direct-runner-Bu8w-wlJ.js → anthropic-direct-runner-BNiXWmel.js} +11 -11
  22. package/dist/{anthropic-direct-runner-C5pnwYzT.js → anthropic-direct-runner-BgFOZS8B.js} +11 -11
  23. package/dist/{audit-DDz7UOIx.js → audit-CupURkPI.js} +15 -15
  24. package/dist/{audit-B05W5ckN.js → audit-jddM3B16.js} +13 -13
  25. package/dist/{auth-Cp__MMeO.js → auth-Bw3NUKcg.js} +2 -2
  26. package/dist/{auth-DsC5pZ_0.js → auth-CuGlMw6p.js} +2 -2
  27. package/dist/{auth-choice-BYOaX-W4.js → auth-choice-D3Gi-WXq.js} +7 -7
  28. package/dist/{auth-choice-CRP6z43z.js → auth-choice-DmkqIhe6.js} +7 -7
  29. package/dist/{auth-health-Cc8-vy8y.js → auth-health-CIbz_YRs.js} +1 -1
  30. package/dist/{auth-health-Dhr8p2SD.js → auth-health-CPmz2ZaM.js} +1 -1
  31. package/dist/{auth-profiles-DKu7ZUzl.js → auth-profiles-D0T20ZZX.js} +4 -4
  32. package/dist/{auth-profiles-C-LuhW6c.js → auth-profiles-XI2YBb-w.js} +3 -3
  33. package/dist/{auth-profiles-Brxz2ojJ.js → auth-profiles-fjGcjhZ4.js} +5 -5
  34. package/dist/{auth-profiles-DtWUl1-k.js → auth-profiles-jK6n3-Cc.js} +4 -4
  35. package/dist/{auth-store-Bd0GoqEL.js → auth-store-B4pR_KvR.js} +3 -3
  36. package/dist/{auth-store-BEfSfCbW.js → auth-store-ChpmVcla.js} +3 -3
  37. package/dist/{auth-store-Jvgz2_l1.js → auth-store-CqgKZB5l.js} +2 -2
  38. package/dist/{auth-store-BpYI9t_y.js → auth-store-po566wly.js} +3 -3
  39. package/dist/{banner-XT5N0ZF4.js → banner-C_CFUih5.js} +2 -2
  40. package/dist/{bonjour-discovery-D3HFfTyG.js → bonjour-discovery-B8gxGE91.js} +2 -2
  41. package/dist/{bonjour-discovery-Co-b97Dz.js → bonjour-discovery-CZGDX9Ac.js} +2 -2
  42. package/dist/build-info.json +3 -3
  43. package/dist/bundled/boot-md/handler.js +23 -23
  44. package/dist/bundled/bootstrap-extra-files/handler.js +3 -3
  45. package/dist/bundled/session-memory/handler.js +22 -22
  46. package/dist/{call-CDPbPDAr.js → call-Bn9iKzhX.js} +4 -4
  47. package/dist/{call-B4lhqS6H.js → call-CPfxv8yg.js} +5 -5
  48. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  49. package/dist/{catalog-CsXv59Tq.js → catalog-BqTvQqiq.js} +2 -2
  50. package/dist/{catalog-B-TAbJ2o.js → catalog-yCaNFdQz.js} +2 -2
  51. package/dist/{channel-web-yWytZHhN.js → channel-web-CfKNWfmp.js} +14 -14
  52. package/dist/{channels-status-issues-WkG3Tmxk.js → channels-status-issues-4XxYhQ8S.js} +4 -4
  53. package/dist/{channels-status-issues-CklLFAsD.js → channels-status-issues-BhtWH-p2.js} +4 -4
  54. package/dist/{chrome-CmxIwwsr.js → chrome-CN17GbZN.js} +2 -2
  55. package/dist/{chrome-BaU-H9m7.js → chrome-CVb9kRv_.js} +3 -3
  56. package/dist/{chrome-DLUBPBPz.js → chrome-D1Jm1Bdq.js} +9 -9
  57. package/dist/{chrome-B8EnYGj1.js → chrome-Nb2mFwWK.js} +2 -2
  58. package/dist/{chunk-B4Kx-ocg.js → chunk-B5s6o9xI.js} +3 -3
  59. package/dist/{chunk-DJXDX69U.js → chunk-CTS4rIMF.js} +3 -3
  60. package/dist/{chunk-CFSle8n5.js → chunk-DXTTGmeb.js} +1 -1
  61. package/dist/{chunk-Cy0Bj0F3.js → chunk-isZGJq82.js} +1 -1
  62. package/dist/{clack-prompter-0JW5kry0.js → clack-prompter-ChmRN__Q.js} +5 -5
  63. package/dist/{clack-prompter-fZSmnHda.js → clack-prompter-CpLhDhPM.js} +5 -5
  64. package/dist/cli/daemon-cli.js +1 -1
  65. package/dist/{cli-C7mOU26p.js → cli-BzTZ8Gnp.js} +46 -46
  66. package/dist/{cli-DfcdnRcl.js → cli-DLYU8BVw.js} +47 -47
  67. package/dist/{client-CfLiulzK.js → client-DNDzi0CF.js} +3 -3
  68. package/dist/{client-BWkoTfOH.js → client-DOTb2PN6.js} +2 -2
  69. package/dist/{command-format-kLw3YIIu.js → command-format-JgYolX96.js} +1 -1
  70. package/dist/{command-registry-DUTqrmna.js → command-registry-BQiM7sYY.js} +14 -14
  71. package/dist/{commands-Mekaw9WG.js → commands-CymFClS1.js} +2 -2
  72. package/dist/{common-DT_obM-k.js → common-C36MniDL.js} +2 -2
  73. package/dist/{common-Bf_TG87Y.js → common-Coq2knq6.js} +2 -2
  74. package/dist/{common-BCW6hLGI.js → common-c4ZysSLq.js} +2 -2
  75. package/dist/{common-CqIa2poH.js → common-fIXNXke2.js} +2 -2
  76. package/dist/{completion-cli-BBm9JIHZ.js → completion-cli-BP8IIlzX.js} +4 -4
  77. package/dist/{completion-cli-Cpj91U30.js → completion-cli-DW87AQgF.js} +3 -3
  78. package/dist/{config-ZYN8tezd.js → config-C7s14LLE.js} +24 -6
  79. package/dist/{config-BrVuTQ8R.js → config-DmsfUvB0.js} +24 -6
  80. package/dist/{config-CweTwOtr.js → config-LS-6Xgqo.js} +25 -7
  81. package/dist/{config-DaD4FsAn.js → config-MZ5clMl4.js} +25 -7
  82. package/dist/config-cli-BAj5hoD-.js +15 -0
  83. package/dist/config-cli-C6WtFt5S.js +11 -0
  84. package/dist/{config-guard-C4b2dksv.js → config-guard-BAVhoqm4.js} +5 -5
  85. package/dist/{config-guard-CWhoBtB3.js → config-guard-Em1kJe5K.js} +19 -19
  86. package/dist/{configure-BE8TA8Yt.js → configure-CHPG13jf.js} +24 -24
  87. package/dist/{configure-CU3kulTq.js → configure-Dd6zJb-q.js} +72 -72
  88. package/dist/{configure-BfWsTKMF.js → configure-DeLC66Op.js} +25 -25
  89. package/dist/{configure-4jIAlOdj.js → configure-i6y1krRa.js} +75 -75
  90. package/dist/{context-mdxDsO1v.js → context-C22AMgsc.js} +10 -2
  91. package/dist/{control-service-5YtMvm7D.js → control-service-BGnqY7vv.js} +5 -5
  92. package/dist/{control-service-3CI4vt1h.js → control-service-DxuB_IUw.js} +4 -4
  93. package/dist/control-ui/assets/{index-D4wqLVMN.js → index-XnQwXlLu.js} +2 -2
  94. package/dist/control-ui/assets/{index-D4wqLVMN.js.map → index-XnQwXlLu.js.map} +1 -1
  95. package/dist/control-ui/assets/index-tpHK2r2n.js +73 -0
  96. package/dist/control-ui/assets/index-tpHK2r2n.js.map +1 -0
  97. package/dist/control-ui/assets/{observers-B7MfWiIZ.js → observers-DqhQeBfm.js} +2 -2
  98. package/dist/control-ui/assets/{observers-B7MfWiIZ.js.map → observers-DqhQeBfm.js.map} +1 -1
  99. package/dist/control-ui/index.html +1 -1
  100. package/dist/{cron-cli-D9XrF-Gx.js → cron-cli-3VJy8n6n.js} +14 -14
  101. package/dist/{cron-cli-Cht6Itx6.js → cron-cli-C_B6qK9W.js} +16 -16
  102. package/dist/{daemon-cli-CrdPhSxr.js → daemon-cli-B0IaAuYH.js} +15 -15
  103. package/dist/{daemon-cli-9zrnYRjh.js → daemon-cli-BsY7ZPql.js} +17 -17
  104. package/dist/daemon-cli.js +19 -1
  105. package/dist/{daemon-runtime-BrUj88ZO.js → daemon-runtime-BoIX72LK.js} +2 -2
  106. package/dist/{daemon-runtime-DCqwraWR.js → daemon-runtime-DSPDxySK.js} +3 -3
  107. package/dist/{deliver-d-CaN0uL.js → deliver-BJ0JgwhN.js} +11 -11
  108. package/dist/{deliver-BKzX3YoN.js → deliver-BknvuSJz.js} +6 -6
  109. package/dist/{deliver-C1L5nO0K.js → deliver-D86kSZGn.js} +7 -7
  110. package/dist/{deliver-B-dPbUIs.js → deliver-bdH5itRb.js} +11 -11
  111. package/dist/{delivery-queue-BKQk1j0k.js → delivery-queue-B6Y3ea25.js} +1 -1
  112. package/dist/{deps-DKPoFoa8.js → deps-oUYlT5Sq.js} +1 -1
  113. package/dist/{diagnostics-BhSwKIcN.js → diagnostics-CXoISuYV.js} +1 -1
  114. package/dist/{diagnostics-Cu9pZAFn.js → diagnostics-aUz0rVDl.js} +1 -1
  115. package/dist/{dispatcher-BQQugU-7.js → dispatcher-DpEzmU7s.js} +2 -2
  116. package/dist/{dispatcher-DzwzLQRk.js → dispatcher-DwlzWX2u.js} +2 -2
  117. package/dist/{dns-cli-V2bo6vSt.js → dns-cli-D8tgv6zY.js} +10 -10
  118. package/dist/{dns-cli-C8KIX4P3.js → dns-cli-DawPrcXI.js} +12 -12
  119. package/dist/{docs-cli-D2cVJxjP.js → docs-cli-Bsx7Yd3w.js} +6 -6
  120. package/dist/{docs-cli-Bt-YV3xs.js → docs-cli-DnrE1Tqw.js} +7 -7
  121. package/dist/{doctor-CFpVHDFT.js → doctor-BNJ_edyo.js} +36 -36
  122. package/dist/{doctor-DOudOs1k.js → doctor-DY5SmosG.js} +38 -38
  123. package/dist/{doctor-completion-DfNyJGIj.js → doctor-completion-B6lgyLsC.js} +2 -2
  124. package/dist/{doctor-completion-R0UlpjIj.js → doctor-completion-mLt2Eo9P.js} +3 -3
  125. package/dist/{doctor-config-flow-Dxy7RIm0.js → doctor-config-flow-CvJDaN8t.js} +8 -8
  126. package/dist/{doctor-config-flow-Bgl0Cc20.js → doctor-config-flow-D7SJ61Ak.js} +6 -6
  127. package/dist/{engine-BDDM-iAi.js → engine-BrJ7eiEh.js} +2 -2
  128. package/dist/entry.js +18 -2
  129. package/dist/{env-DlTia1B4.js → env-ByZjwIJR.js} +1 -1
  130. package/dist/{exec-DUzVF5_D.js → exec-4nfFrGP7.js} +1 -1
  131. package/dist/{exec-BylR5qWS.js → exec-ChPERQB-.js} +1 -1
  132. package/dist/{exec-BtBJICHE.js → exec-CigQCGkt.js} +1 -1
  133. package/dist/{exec-C6tXfeqA.js → exec-Dn2S9A7x.js} +1 -1
  134. package/dist/{exec-approvals-cli-DYZVBnqS.js → exec-approvals-cli-DmdfF4o_.js} +17 -17
  135. package/dist/{exec-approvals-cli-CN2WeH7y.js → exec-approvals-cli-c5UsPAU1.js} +19 -19
  136. package/dist/extensionAPI.js +21 -21
  137. package/dist/{gateway-cli-DtIum1te.js → gateway-cli-C4FwPHzu.js} +95 -95
  138. package/dist/{gateway-cli-CFlPUx9N.js → gateway-cli-CkFzsHGb.js} +93 -93
  139. package/dist/{gateway-rpc-Cj_h2sVM.js → gateway-rpc-CgeNTQUV.js} +3 -3
  140. package/dist/{gateway-rpc-CnXMGsxp.js → gateway-rpc-DpVHyNFu.js} +3 -3
  141. package/dist/{gmail-setup-utils-BIXtKTpT.js → gmail-setup-utils-JWsjxDBV.js} +4 -4
  142. package/dist/{gmail-setup-utils-DaJoXV_3.js → gmail-setup-utils-lTV5KDPF.js} +3 -3
  143. package/dist/{health-ngQNjXh4.js → health-C6rAUaME.js} +13 -13
  144. package/dist/{health-yw_uaucz.js → health-DrokrOLQ.js} +13 -13
  145. package/dist/{health-format-BLnFZCH_.js → health-format-CTOsgiTE.js} +2 -2
  146. package/dist/{health-format-D-JJ5_S4.js → health-format-CzNDrJ8Z.js} +2 -2
  147. package/dist/{heartbeat-visibility-BaL8JzkS.js → heartbeat-visibility-DZOi_4uV.js} +1 -1
  148. package/dist/{heartbeat-visibility-mAzdNSiS.js → heartbeat-visibility-XbT4yJ3S.js} +1 -1
  149. package/dist/{help-format-ZKxl6UCb.js → help-format-D4k6gkpr.js} +1 -1
  150. package/dist/{help-format-Dt-I_Mls.js → help-format-DgCbU9Ow.js} +1 -1
  151. package/dist/{hooks-cli-D6YfDiUI.js → hooks-cli-CBDm7Rjw.js} +50 -50
  152. package/dist/{hooks-cli-CPgLAn7a.js → hooks-cli-DVNU2Cp_.js} +53 -53
  153. package/dist/{hooks-status-DdweuSIj.js → hooks-status-BQ7M6bIq.js} +3 -3
  154. package/dist/{hooks-status-DqfJDvYl.js → hooks-status-BlfmlpC0.js} +3 -3
  155. package/dist/{image-ops-Ct3GueyT.js → image-ops-flDr58qn.js} +2 -2
  156. package/dist/{image-ops-BdrMmiG4.js → image-ops-vj06APeW.js} +2 -2
  157. package/dist/index.js +62 -62
  158. package/dist/{installs-a4Vz_J08.js → installs-BeTulUkL.js} +4 -4
  159. package/dist/{installs-Bi6UipiE.js → installs-D1t93Dvw.js} +4 -4
  160. package/dist/{lifecycle-core-BTICG85s.js → lifecycle-core-DmxyMl5D.js} +5 -5
  161. package/dist/{lifecycle-core-B8PI1NZJ.js → lifecycle-core-OpMLwiRd.js} +3 -3
  162. package/dist/{links-DcilUrqq.js → links-NDZcSjct.js} +1 -1
  163. package/dist/{links-BjjDMNIq.js → links-RNygAKHu.js} +1 -1
  164. package/dist/llm-slug-generator.js +22 -22
  165. package/dist/{loader-C87TLS4J.js → loader-5Xm3Jxa-.js} +1 -1
  166. package/dist/{logging-Chc1Sj6N.js → logging-B0-OIfnO.js} +1 -1
  167. package/dist/{logging-_rCcBkls.js → logging-CX0bU2da.js} +2 -2
  168. package/dist/{login-DKkQ3Czu.js → login-BegD27g3.js} +5 -5
  169. package/dist/{login-MzVPMRxL.js → login-CSaeXIuW.js} +7 -7
  170. package/dist/{login-BTOKtSQN.js → login-WPS724ji.js} +5 -5
  171. package/dist/{login-qr-BGbHImRb.js → login-qr-BVzUWR4o.js} +8 -8
  172. package/dist/{login-qr-CxRI-tE2.js → login-qr-C0eNn9SV.js} +12 -12
  173. package/dist/{login-qr-OUAGpDsU.js → login-qr-DLLfBALk.js} +9 -9
  174. package/dist/{login-qr-BjpDVBJE.js → login-qr-updBsqHf.js} +10 -10
  175. package/dist/{login-BEaBOSnw.js → login-zlt00-k4.js} +6 -6
  176. package/dist/{logs-cli-BiAJbjnq.js → logs-cli-BDQoLnjr.js} +15 -15
  177. package/dist/{logs-cli-Bc6IOyHA.js → logs-cli-BPljn0BF.js} +14 -14
  178. package/dist/{manager-BYu34CX3.js → manager-B-8JFgek.js} +27 -11
  179. package/dist/{manager-C6L_DH0O.js → manager-CE4cPrH2.js} +7 -7
  180. package/dist/{manager-D8VCuzru.js → manager-DPojhf1D.js} +9 -9
  181. package/dist/{manager-b_aZwo00.js → manager-kKsAUV03.js} +27 -11
  182. package/dist/{manifest-registry-W_OfCIRP.js → manifest-registry-BAebAG4I.js} +1 -1
  183. package/dist/{manifest-registry-qF960vMH.js → manifest-registry-Cwvk5hu8.js} +1 -1
  184. package/dist/{memory-cli-B0kKl-9T.js → memory-cli-BJmQIQSw.js} +11 -11
  185. package/dist/{memory-cli-DLtBA6r5.js → memory-cli-DMJqELwh.js} +10 -10
  186. package/dist/{message-channel-CMsexA3K.js → message-channel-CfwNj8mC.js} +1 -1
  187. package/dist/{message-channel-DIHHKJhk.js → message-channel-qmDI9YoO.js} +1 -1
  188. package/dist/{model-auth-KpsOXKDc.js → model-auth-BCdRf282.js} +19 -3
  189. package/dist/{model-auth-CHB3EySM.js → model-auth-Bs6eoQ1l.js} +19 -3
  190. package/dist/{model-selection-CLcoOT3e.js → model-selection-BhIAjo3P.js} +1 -1
  191. package/dist/{model-selection-DjsJGv1R.js → model-selection-CVcwboE_.js} +1 -1
  192. package/dist/{model-selection-CY6r_3wt.js → model-selection-CeZMza3d.js} +1 -1
  193. package/dist/{model-selection-DcO3qJOu.js → model-selection-f7lJs3PI.js} +1 -1
  194. package/dist/{models-BXdBXPMB.js → models-DxRmPLiS.js} +97 -50
  195. package/dist/{models-cli-1Kj8gkGy.js → models-cli-B9KClY_f.js} +137 -82
  196. package/dist/{models-cli-DdJcmOGI.js → models-cli-BFZLSACV.js} +66 -58
  197. package/dist/{node-cli-DU_oREff.js → node-cli-BetF7Xgf.js} +26 -26
  198. package/dist/{node-cli-BmuVEJ1C.js → node-cli-CLeoh03V.js} +25 -25
  199. package/dist/{node-service-qZXF7T7A.js → node-service-FcwxyU8p.js} +1 -1
  200. package/dist/{node-service-cOoW5hLa.js → node-service-zrXojq7t.js} +1 -1
  201. package/dist/{note-CeLGcHqv.js → note-BTIeG9az.js} +1 -1
  202. package/dist/{note-iMYVGjpA.js → note-D_tpPSPO.js} +2 -2
  203. package/dist/{noxsoft-bootstrap-CrlkSFzd.js → noxsoft-bootstrap-CPS7t3Sk.js} +3 -3
  204. package/dist/{noxsoft-bootstrap-C4dSx7K_.js → noxsoft-bootstrap-CqygYIJa.js} +2 -2
  205. package/dist/{npm-registry-spec-jf7Mowdn.js → npm-registry-spec-BeX9-fmS.js} +1 -1
  206. package/dist/{npm-registry-spec-Br4B4I_3.js → npm-registry-spec-DB6xqMfu.js} +1 -1
  207. package/dist/{onboard-CHX1Jdt_.js → onboard-BZORsTGE.js} +18 -18
  208. package/dist/{onboard-BzScK9k6.js → onboard-Doq7UgRV.js} +19 -19
  209. package/dist/{onboard-channels-DfXxMbYu.js → onboard-channels-BREQ8Tyw.js} +9 -9
  210. package/dist/{onboard-channels-wUF4oRB-.js → onboard-channels-CpM1Nwqf.js} +8 -8
  211. package/dist/{onboard-helpers-CJ3HzoUO.js → onboard-helpers-rHLFiSIc.js} +7 -7
  212. package/dist/{onboard-helpers-CFudIoX4.js → onboard-helpers-uf70JxTj.js} +9 -9
  213. package/dist/{onboarding-fnZOw6Wv.js → onboarding-BGXbXgds.js} +21 -21
  214. package/dist/{onboarding-6jxAKxhe.js → onboarding-DQplq13s.js} +22 -22
  215. package/dist/{orchestrator-CrFD887e.js → orchestrator-CERtu86A.js} +1 -1
  216. package/dist/{outbound-Bmft-5um.js → outbound-Bii3QonX.js} +4 -4
  217. package/dist/{outbound-C577aWZp.js → outbound-BpcyR1eA.js} +4 -4
  218. package/dist/{outbound-fPqdCDR4.js → outbound-C1WShhf8.js} +4 -4
  219. package/dist/{outbound-DW2eod1S.js → outbound-DKY6oeyQ.js} +4 -4
  220. package/dist/{outbound-send-deps-DMsqr5fd.js → outbound-send-deps-CtiCh8EY.js} +1 -1
  221. package/dist/{parse-timeout-D4UO8pY_.js → parse-timeout-Bp5yQ1yW.js} +3 -3
  222. package/dist/{parse-timeout-C4WLf3Qy.js → parse-timeout-Cn7M8c5R.js} +3 -3
  223. package/dist/{path-env-DLQPf9qj.js → path-env-BAjR_Xf_.js} +1 -1
  224. package/dist/{paths-DMk3Q7yD.js → paths-BM1wivAU.js} +1 -1
  225. package/dist/{paths-CAQJvbeZ.js → paths-BqA7F6bT.js} +2 -2
  226. package/dist/{paths-Q6h5HODL.js → paths-DAbvPUdJ.js} +1 -1
  227. package/dist/{pi-auth-json-B_lKNFK6.js → pi-auth-json-BhkzZgQz.js} +5 -5
  228. package/dist/{pi-auth-json-BmdBnmlZ.js → pi-auth-json-CM3QDr9_.js} +6 -6
  229. package/dist/{pi-auth-json-WTvcP2gz.js → pi-auth-json-Dry5jXVt.js} +6 -6
  230. package/dist/{pi-auth-json-DkYqdjrV.js → pi-auth-json-qHO_AF3h.js} +6 -6
  231. package/dist/{pi-embedded-B1eVXOsQ.js → pi-embedded-CrzqUkHv.js} +304 -59
  232. package/dist/{pi-embedded-DbvG9mmD.js → pi-embedded-Dn3Ip_VN.js} +308 -63
  233. package/dist/{pi-embedded-helpers-BZ9GspxK.js → pi-embedded-helpers-BPtBCnl-.js} +1 -1
  234. package/dist/{pi-embedded-helpers-D2SLlgS4.js → pi-embedded-helpers-BSFtS9Fl.js} +1 -1
  235. package/dist/{pi-tools.policy-WdTAfqbV.js → pi-tools.policy-DuWNVoem.js} +6 -6
  236. package/dist/{pi-tools.policy-D2FusuQa.js → pi-tools.policy-DyckzpRL.js} +7 -7
  237. package/dist/{plugin-auto-enable-DhuD30Je.js → plugin-auto-enable-Btd2iEwF.js} +5 -5
  238. package/dist/{plugin-auto-enable-CtYcdTju.js → plugin-auto-enable-DvYJhgJ2.js} +5 -5
  239. package/dist/{plugin-registry-DKexyPAq.js → plugin-registry-BOuDey4w.js} +4 -4
  240. package/dist/{plugin-registry-CtkU96jV.js → plugin-registry-ChWHnegS.js} +4 -4
  241. package/dist/plugin-sdk/agents/local-model-installer.d.ts +11 -0
  242. package/dist/plugin-sdk/agents/openai-direct-runner.d.ts +2 -1
  243. package/dist/plugin-sdk/config/types.agent-defaults.d.ts +40 -0
  244. package/dist/plugin-sdk/config/types.models.d.ts +1 -1
  245. package/dist/plugin-sdk/config/zod-schema.agent-defaults.d.ts +13 -0
  246. package/dist/plugin-sdk/config/zod-schema.agents.d.ts +13 -0
  247. package/dist/plugin-sdk/config/zod-schema.core.d.ts +6 -6
  248. package/dist/plugin-sdk/config/zod-schema.d.ts +15 -2
  249. package/dist/plugin-sdk/index.js +25 -7
  250. package/dist/{plugins-DYcg0qBW.js → plugins-BqPGs8w-.js} +1 -1
  251. package/dist/{plugins-BOMS6J5A.js → plugins-C8FLxXbd.js} +1 -1
  252. package/dist/{plugins-cli-BQmysVFP.js → plugins-cli-CbOP5ml6.js} +51 -51
  253. package/dist/{plugins-cli-B3l7kalt.js → plugins-cli-dH6LKRQM.js} +53 -53
  254. package/dist/{polls-DFISjV7H.js → polls-aumqIVob.js} +5 -5
  255. package/dist/{ports-BGLuwt2Z.js → ports--opAW6yN.js} +2 -2
  256. package/dist/{ports-q535r1PZ.js → ports-B20JTuiL.js} +2 -2
  257. package/dist/{ports-B_f42zcA.js → ports-C4ACB4MP.js} +2 -2
  258. package/dist/{ports-DaVrZDUq.js → ports-D6bjtvhF.js} +2 -2
  259. package/dist/{program-context-C4x0zjOR.js → program-context-7yQclqBT.js} +35 -35
  260. package/dist/{program-mSyCYzsQ.js → program-pWHcYdeO.js} +58 -58
  261. package/dist/{progress-glCgu57m.js → progress-BveMw0-_.js} +1 -1
  262. package/dist/{progress-CVLvQV_t.js → progress-qMmjCvh9.js} +1 -1
  263. package/dist/{prompt-style-BI53UVgE.js → prompt-style-DWuEFbBO.js} +1 -1
  264. package/dist/{prompt-style-D6SRiiTV.js → prompt-style-zgo1vAG1.js} +1 -1
  265. package/dist/{prompts-BmgT_kkv.js → prompts-C4v0DSTU.js} +6 -6
  266. package/dist/{prompts-Bq4QGFQM.js → prompts-D6Xc1Ddb.js} +4 -4
  267. package/dist/{pw-ai-DxNrJcCA.js → pw-ai-2XnGTARu.js} +3 -3
  268. package/dist/{pw-ai-CB-zeR7h.js → pw-ai-BUnz28XN.js} +5 -5
  269. package/dist/{pw-ai-C_1-7IgH.js → pw-ai-CRnDr120.js} +3 -3
  270. package/dist/{pw-ai-B4u5FDqO.js → pw-ai-Dq14LFsx.js} +6 -6
  271. package/dist/{qmd-manager-C_XBZ_bT.js → qmd-manager-6nqaD-q9.js} +5 -5
  272. package/dist/{qmd-manager-CO795NK4.js → qmd-manager-B6-V0aC1.js} +6 -6
  273. package/dist/{qmd-manager-CpNYgSrx.js → qmd-manager-BNL9Pl2G.js} +6 -6
  274. package/dist/{qmd-manager-Q0OSDQ-e.js → qmd-manager-CpynR-al.js} +5 -5
  275. package/dist/{register.agent-DBxUWr1K.js → register.agent-BMxuTqFN.js} +68 -68
  276. package/dist/{register.agent-CzEM3bkp.js → register.agent-BO6_QTx6.js} +65 -65
  277. package/dist/{register.anima-RI6gewtj.js → register.anima-5SAY6OxG.js} +4 -4
  278. package/dist/{register.anima--gufBuS-.js → register.anima-CLGhoqmw.js} +8 -8
  279. package/dist/register.configure-Bz9pap1L.js +106 -0
  280. package/dist/register.configure-dMfZ1zcY.js +107 -0
  281. package/dist/register.maintenance-CL2eIgmC.js +102 -0
  282. package/dist/register.maintenance-k1dBbjUg.js +103 -0
  283. package/dist/{register.message-BhGJ_1Iy.js → register.message-Cqlz-6uM.js} +52 -52
  284. package/dist/{register.message-ACbKb7JS.js → register.message-Cz34rs9W.js} +50 -50
  285. package/dist/{register.onboard-DR_YYtbi.js → register.onboard-Cmh46n62.js} +70 -70
  286. package/dist/{register.onboard-CwkY7CRm.js → register.onboard-_4FOFCA2.js} +67 -67
  287. package/dist/{register.setup-Cn3e7Std.js → register.setup-CHgH1mdn.js} +70 -70
  288. package/dist/{register.setup-BSm6O1ml.js → register.setup-CKY65php.js} +67 -67
  289. package/dist/{register.status-health-sessions-DAl9OeGB.js → register.status-health-sessions-CNX6wp0V.js} +60 -60
  290. package/dist/{register.status-health-sessions-CpxsZeet.js → register.status-health-sessions-DNvtWNtb.js} +63 -63
  291. package/dist/{register.subclis-DEFeoyPP.js → register.subclis-Br8nY-dd.js} +23 -23
  292. package/dist/{reply-ylwOKuOF.js → reply-DqXPXQ20.js} +322 -77
  293. package/dist/{reply-prefix-CEnF6TUe.js → reply-prefix-CZy4g8SY.js} +1 -1
  294. package/dist/{reply-prefix-Og65nAYv.js → reply-prefix-DuANpRN_.js} +1 -1
  295. package/dist/{routes-CWCAc8uJ.js → routes-CAjh83-X.js} +6 -6
  296. package/dist/{routes-FT0Us8Md.js → routes-DTjggbOR.js} +6 -6
  297. package/dist/{run-D6Ete2Z-.js → run-0F-ZU2kW.js} +2038 -172
  298. package/dist/{run-B6eBjo22.js → run-Bu-fwhic.js} +2043 -177
  299. package/dist/{run-main-CQHE4XaN.js → run-main-BcC_mt4v.js} +72 -72
  300. package/dist/{runtime-guard-D14Z_QY6.js → runtime-guard-Ccc4Qj4K.js} +1 -1
  301. package/dist/{runtime-guard-DdP10b7Q.js → runtime-guard-E3CIN3Xo.js} +1 -1
  302. package/dist/{sandbox-D-N7M7lp.js → sandbox-DSHSoUHO.js} +6 -6
  303. package/dist/{sandbox-cli-CQKz2I1X.js → sandbox-cli-BiO-r7eU.js} +22 -22
  304. package/dist/{sandbox-cli-DHNFlTo-.js → sandbox-cli-D6ikivGS.js} +22 -22
  305. package/dist/{sandbox-pBHlfFdB.js → sandbox-mSWYRXFm.js} +6 -6
  306. package/dist/{security-cli-Bdi7MuP6.js → security-cli-Bqq5Klnm.js} +25 -25
  307. package/dist/{security-cli-C3aI09uy.js → security-cli-CcBxjHGL.js} +25 -25
  308. package/dist/{semantic-CQApJNO_.js → semantic-CPfLgc8S.js} +1 -1
  309. package/dist/{semantic-9rgWUrz3.js → semantic-DLW1Sflk.js} +1 -1
  310. package/dist/{semantic-C1UN3bb9.js → semantic-jL8x-DTZ.js} +1 -1
  311. package/dist/{server-context-Yx4pgBqJ.js → server-context-DTlBzMyD.js} +7 -7
  312. package/dist/{server-context-Clykq0XU.js → server-context-EPPcxp2p.js} +8 -8
  313. package/dist/{server-node-events-DIuVwITd.js → server-node-events-BGWQiInn.js} +52 -52
  314. package/dist/{server-node-events-CV5m_fuq.js → server-node-events-BuxYvQ0t.js} +50 -50
  315. package/dist/{service-4VfZwSv1.js → service-BoUEkrUm.js} +1 -1
  316. package/dist/{service-audit-KzOtcw_V.js → service-audit-B_BC6-F8.js} +3 -3
  317. package/dist/{service-audit-Bwpoc2LD.js → service-audit-CjH8ed-j.js} +3 -3
  318. package/dist/{service-Dd1DfPia.js → service-ho_k2vjr.js} +1 -1
  319. package/dist/{session-jljC5QVG.js → session-B4wJoEqn.js} +4 -4
  320. package/dist/{session-CSmfU0D3.js → session-BF7WjlT0.js} +1 -1
  321. package/dist/{session-Jlf3l006.js → session-BnOV0y0e.js} +6 -6
  322. package/dist/{session-BqHD-8a_.js → session-CSgjW31i.js} +5 -5
  323. package/dist/{session-BiA6jrcs.js → session-DO_miKel.js} +1 -1
  324. package/dist/{session-5YO_H-Ra.js → session-DcRzV4l4.js} +1 -1
  325. package/dist/{session-BzrnfWQ2.js → session-DlMsi6dM.js} +5 -5
  326. package/dist/{session-cost-usage-DnxtnK1E.js → session-cost-usage-BNvno_kS.js} +1 -1
  327. package/dist/{sessions-C_3wTmSA.js → sessions-B2NwIaNC.js} +6 -6
  328. package/dist/{sessions-BOzeFzuL.js → sessions-DBQx8E1H.js} +5 -5
  329. package/dist/{sessions-BmE5Z_1i.js → sessions-DxAfgPEp.js} +6 -6
  330. package/dist/{settings-cli-T66kDBNA.js → settings-cli-CHwTEE6P.js} +72 -72
  331. package/dist/{settings-cli-LWW2xQBQ.js → settings-cli-DsUKlq8R.js} +74 -74
  332. package/dist/{setup-token-6DSKE0Tn.js → setup-token-BX6QI7ce.js} +26 -26
  333. package/dist/{setup-token-0zfSBnMQ.js → setup-token-CU5mami5.js} +26 -26
  334. package/dist/{shared-C-rqLtIT.js → shared-BFzq0XE1.js} +2 -2
  335. package/dist/{shared-7KwLAyAq.js → shared-D3ZAXqdo.js} +3 -3
  336. package/dist/{shell-env-CMI9f7-7.js → shell-env-BR7Sbtw1.js} +1 -1
  337. package/dist/{shell-env-HkVWMh--.js → shell-env-BZ2Wha1e.js} +1 -1
  338. package/dist/{shell-env-iPnSIi-t.js → shell-env-Bgk3WFTi.js} +1 -1
  339. package/dist/{skills-DtoVe1dS.js → skills-BT0Lx09M.js} +2 -2
  340. package/dist/{skills-4v6-kw0C.js → skills-DjVFhlQY.js} +3 -3
  341. package/dist/{skills-cli-BoasNTpZ.js → skills-cli-BX5pL-D4.js} +15 -15
  342. package/dist/{skills-cli-TeAq3fRG.js → skills-cli-wKTnuQos.js} +14 -14
  343. package/dist/{skills-install-D6_qpRjW.js → skills-install-CVWWsOf2.js} +4 -4
  344. package/dist/{skills-install-Qw2oU8L8.js → skills-install-Ye1kjpCv.js} +4 -4
  345. package/dist/{skills-status-DuLjkX2E.js → skills-status-BUKnQ3ek.js} +2 -2
  346. package/dist/{skills-status-CvH7AUoY.js → skills-status-BmZufjT1.js} +3 -3
  347. package/dist/{soul-Bt8UNmTq.js → soul-C0oc6fbP.js} +1 -1
  348. package/dist/{soul-D9k5zulC.js → soul-DEsrpMAk.js} +1 -1
  349. package/dist/{soul-BiIdv3Wp.js → soul-Doq8As4R.js} +1 -1
  350. package/dist/{soul-DQSYs-4l.js → soul-DyLtQVJh.js} +1 -1
  351. package/dist/{sqlite-BMMt7osH.js → sqlite-CFCo1Ghe.js} +2 -2
  352. package/dist/{sqlite-Cm6OqTQB.js → sqlite-DVkTX4wZ.js} +1 -1
  353. package/dist/{sqlite-CZ1vD4VS.js → sqlite-DrhFRoal.js} +2 -2
  354. package/dist/{sqlite-CpAJt-JS.js → sqlite-M5Ot9X4U.js} +1 -1
  355. package/dist/start-C-gTbKUz.js +158 -0
  356. package/dist/start-DZKfWnpD.js +157 -0
  357. package/dist/{status-CDcFjNtS.js → status-BN6HYR8t.js} +4 -4
  358. package/dist/{status-CobgQziJ.js → status-BimVB8cj.js} +4 -4
  359. package/dist/{status-D37aRiV3.js → status-CSkpd-tb.js} +27 -27
  360. package/dist/{status-BhRELdY_.js → status-D1zupVBm.js} +24 -24
  361. package/dist/{status.update-B6Tdpk07.js → status.update-HKMS5T9H.js} +2 -2
  362. package/dist/{status.update-E9dSFk_b.js → status.update-oapjZPr_.js} +3 -3
  363. package/dist/{subagent-registry-CDEUbtey.js → subagent-registry-D87n8mHd.js} +318 -81
  364. package/dist/{subsystem-D1AJZPgG.js → subsystem-CkjVkxc4.js} +17 -1
  365. package/dist/{subsystem-D-Xta-sj.js → subsystem-CyrIA90F.js} +17 -1
  366. package/dist/{subsystem-BAADN1B8.js → subsystem-DLVQ9bjX.js} +17 -1
  367. package/dist/{system-cli-DoLzi2Sn.js → system-cli-BRPiBm4G.js} +13 -13
  368. package/dist/{system-cli-CP7JrhR0.js → system-cli-DaNHLGRC.js} +15 -15
  369. package/dist/{systemd-6iLWJxQQ.js → systemd-CS58NHpx.js} +2 -2
  370. package/dist/{systemd-hints-C5Kfh4GW.js → systemd-hints-7HkQ202-.js} +1 -1
  371. package/dist/{systemd-linger-CxGmIy_5.js → systemd-linger-BMNvTAmy.js} +2 -2
  372. package/dist/{systemd-linger-BVwGXVS0.js → systemd-linger-C9PGBtXs.js} +2 -2
  373. package/dist/{systemd-Bx76sJ3M.js → systemd-zYTszfyU.js} +2 -2
  374. package/dist/{table-Blmz7glr.js → table-Bea_v9UU.js} +2 -2
  375. package/dist/{table-Bt7rSYC6.js → table-ohGAZZLQ.js} +1 -1
  376. package/dist/{tokens-CmlI2hSz.js → tokens-BelyD23F.js} +1 -1
  377. package/dist/{tokens-SP2Q7i59.js → tokens-nliOJNMv.js} +1 -1
  378. package/dist/{tool-images-C6cKHTbj.js → tool-images-BEiRPCYM.js} +2 -2
  379. package/dist/{tool-images-2qproko3.js → tool-images-BH8q2ZMq.js} +2 -2
  380. package/dist/{tool-images-D1HuaGdS.js → tool-images-DJrhuxOM.js} +1 -1
  381. package/dist/{tool-images-CgDT0Xzv.js → tool-images-dAVG0qoz.js} +2 -2
  382. package/dist/{tui-r4qpJhNk.js → tui-DnzqtbW3.js} +9 -9
  383. package/dist/{tui-C2eLfbhA.js → tui-FJlF9b--.js} +8 -8
  384. package/dist/{tui-cli-cLSYBQu9.js → tui-cli-BtLvABYH.js} +27 -27
  385. package/dist/{tui-cli-BgcbCtgc.js → tui-cli-Cm3G2SAN.js} +26 -26
  386. package/dist/{update-CqKpX3cX.js → update-Cpvsdq3a.js} +3 -3
  387. package/dist/{update-DA91za97.js → update-DrQkwR-M.js} +3 -3
  388. package/dist/{update-cli-QtM0G6CE.js → update-cli-DpKplMO0.js} +79 -79
  389. package/dist/{update-cli-BjHgpnxD.js → update-cli-DueHX0OM.js} +83 -83
  390. package/dist/{update-runner-C8SRcVm3.js → update-runner-C7CjKcMp.js} +5 -5
  391. package/dist/{update-runner-Fb3Un6UZ.js → update-runner-DtqDU0xF.js} +5 -5
  392. package/dist/{utils-D1VGbO3C.js → utils-BNuEYQIN.js} +1 -1
  393. package/dist/{utils-CLYlhJuc.js → utils-CkCznJhR.js} +1 -1
  394. package/dist/{web-BDig9tCy.js → web-Br9HCEvC.js} +54 -54
  395. package/dist/{web-CPPJ5y4c.js → web-BxkEMATs.js} +25 -25
  396. package/dist/{web-C4lrKULd.js → web-CPHrMWsv.js} +24 -24
  397. package/dist/web-HXy7rlIW.js +65 -0
  398. package/dist/{webhooks-cli-k3QMf7Rs.js → webhooks-cli-CdoaCUQ5.js} +11 -11
  399. package/dist/{webhooks-cli-vlEfXEKm.js → webhooks-cli-D65dKr5L.js} +12 -12
  400. package/dist/{whatsapp-actions-Hr-W8vjY.js → whatsapp-actions--CtxOhlj.js} +12 -12
  401. package/dist/{whatsapp-actions-C0tlEdLy.js → whatsapp-actions--eONuB4M.js} +14 -14
  402. package/dist/{whatsapp-actions-BJn-z76S.js → whatsapp-actions-BM0a0V4y.js} +17 -17
  403. package/dist/{whatsapp-actions-6fPRKwPV.js → whatsapp-actions-Bhz79Fgg.js} +11 -11
  404. package/dist/{widearea-dns-CtU9Fx7K.js → widearea-dns-D2VSHQ7y.js} +1 -1
  405. package/dist/{widearea-dns-CHAT20aR.js → widearea-dns-DlJrNJOg.js} +1 -1
  406. package/dist/{workspace-BFIZCnGo.js → workspace-D6JhsXVL.js} +1 -1
  407. package/dist/{ws-log-CUobU2tD.js → ws-log-Cvz4xRCD.js} +1 -1
  408. package/dist/{ws-log-CG6cvCZW.js → ws-log-DwsFDY7m.js} +1 -1
  409. package/package.json +3 -1
  410. package/scripts/install-local-qwen3-coder.sh +7 -0
  411. package/dist/config-cli-CF2ERR8G.js +0 -11
  412. package/dist/config-cli-Dmd4Oyjp.js +0 -15
  413. package/dist/control-ui/assets/index-DIEQjjCN.js +0 -73
  414. package/dist/control-ui/assets/index-DIEQjjCN.js.map +0 -1
  415. package/dist/register.configure-Cs3uLUBo.js +0 -107
  416. package/dist/register.configure-Dpe8Qel3.js +0 -106
  417. package/dist/register.maintenance-BEYN8SJL.js +0 -103
  418. package/dist/register.maintenance-DqAdzWBM.js +0 -102
  419. package/dist/start-BdcAszpl.js +0 -157
  420. package/dist/start-gVOPVCgi.js +0 -158
  421. package/dist/web-Vx_ENtYI.js +0 -65
@@ -1,77 +1,77 @@
1
- import { $ as resolveStateDir, B as CONFIG_PATH, D as setVerbose, F as getLogger, G as resolveConfigPath, H as STATE_DIR, I as getResolvedLoggerSettings, J as resolveGatewayLockDir, L as setLoggerOverride, P as getChildLogger, Tt as expandHomePrefix, U as isNixMode, Y as resolveGatewayPort, d as setConsoleSubsystemFilter, dt as getActivePluginRegistry, f as setConsoleTimestampPrefix, g as defaultRuntime, l as getResolvedConsoleSettings, n as isTruthyEnvValue, o as createSubsystemLogger, r as logAcceptedEnvOption, rt as DEFAULT_CHAT_CHANNEL, s as runtimeForLogger, tt as CHANNEL_IDS } from "./entry.js";
2
- import { w as normalizeSecretInput } from "./auth-profiles-Brxz2ojJ.js";
3
- import { t as formatCliCommand } from "./command-format-kLw3YIIu.js";
1
+ import { Et as expandHomePrefix, F as getChildLogger, I as getLogger, K as resolveConfigPath, L as getResolvedLoggerSettings, O as setVerbose, R as setLoggerOverride, U as STATE_DIR, V as CONFIG_PATH, W as isNixMode, X as resolveGatewayPort, Y as resolveGatewayLockDir, _ as defaultRuntime, d as setConsoleSubsystemFilter, et as resolveStateDir, f as setConsoleTimestampPrefix, ft as getActivePluginRegistry, it as DEFAULT_CHAT_CHANNEL, l as getResolvedConsoleSettings, n as isTruthyEnvValue, nt as CHANNEL_IDS, o as createSubsystemLogger, r as logAcceptedEnvOption, s as runtimeForLogger } from "./entry.js";
2
+ import { w as normalizeSecretInput } from "./auth-profiles-fjGcjhZ4.js";
3
+ import { t as formatCliCommand } from "./command-format-JgYolX96.js";
4
4
  import { b as isSubagentSessionKey, d as resolveAgentIdFromSessionKey, i as buildAgentMainSessionKey, l as normalizeAgentId, m as toAgentRequestSessionKey, n as DEFAULT_AGENT_ID, t as DEFAULT_ACCOUNT_ID, u as normalizeMainKey, v as isCronRunSessionKey, x as parseAgentSessionKey } from "./session-key-DP2WHl90.js";
5
- import { E as truncateUtf16Safe, S as shortenHomePath, n as clamp, s as ensureDir$1, t as CONFIG_DIR, u as isPlainObject, y as resolveUserPath } from "./utils-D1VGbO3C.js";
6
- import { a as logDebug, c as logWarn, n as runExec, t as runCommandWithTimeout } from "./exec-BtBJICHE.js";
5
+ import { E as truncateUtf16Safe, S as shortenHomePath, n as clamp, s as ensureDir$1, t as CONFIG_DIR, u as isPlainObject, y as resolveUserPath } from "./utils-BNuEYQIN.js";
6
+ import { a as logDebug, c as logWarn, n as runExec, t as runCommandWithTimeout } from "./exec-CigQCGkt.js";
7
7
  import { t as resolveAnimaPackageRoot } from "./anima-root-CxtpOklc.js";
8
- import { T as resolveWorkspaceTemplateDir, _ as DEFAULT_MEMORY_FILENAME, b as DEFAULT_USER_FILENAME, c as resolveDefaultAgentId, d as DEFAULT_AGENTS_FILENAME, g as DEFAULT_MEMORY_ALT_FILENAME, h as DEFAULT_IDENTITY_FILENAME, i as resolveAgentModelFallbacksOverride, l as resolveSessionAgentId, m as DEFAULT_HEARTBEAT_FILENAME, n as resolveAgentConfig, p as DEFAULT_BOOTSTRAP_FILENAME, r as resolveAgentDir, s as resolveAgentWorkspaceDir, t as listAgentIds, v as DEFAULT_SOUL_FILENAME, w as resolveDefaultAgentWorkspaceDir, x as ensureAgentWorkspace, y as DEFAULT_TOOLS_FILENAME } from "./agent-scope-Dm8IL1Ks.js";
9
- import { _ as DEFAULT_MODEL, a as isCliProvider, d as resolveConfiguredModelRef, f as resolveDefaultModelForAgent, g as DEFAULT_CONTEXT_TOKENS, h as resolveThinkingDefault, i as getModelRefStatus, p as resolveHooksGmailModel, u as resolveAllowedModelRef, v as DEFAULT_PROVIDER } from "./model-selection-DcO3qJOu.js";
10
- import { i as loadWorkspaceSkillEntries, r as buildWorkspaceSkillSnapshot, x as hasBinary } from "./skills-DtoVe1dS.js";
11
- import { o as isTestDefaultMemorySlotDisabled } from "./manifest-registry-W_OfCIRP.js";
12
- import { t as buildWorkspaceSkillStatus } from "./skills-status-DuLjkX2E.js";
13
- import { A as resolveAgentMaxConcurrent, M as VERSION, T as applyLegacyMigrations, a as parseConfigJson5, c as resolveConfigSnapshotHash, d as AnimaSchema, i as loadConfig, j as resolveSubagentMaxConcurrent, l as writeConfigFile, m as parseDurationMs, n as migrateLegacyConfig, o as readConfigFileSnapshot, p as sensitive, r as createConfigIO, s as readConfigFileSnapshotForWrite, u as validateConfigObjectWithPlugins, w as applyMergePatch } from "./config-BrVuTQ8R.js";
14
- import { $ as validateNodePairRequestParams, A as validateCronStatusParams, B as validateExecApprovalsNodeGetParams, C as validateConfigSetParams, Ct as validateWizardCancelParams, D as validateCronRemoveParams, Dt as PROTOCOL_VERSION, E as validateCronListParams, Et as validateWizardStatusParams, F as validateDeviceTokenRevokeParams, G as validateNodeDescribeParams, H as validateExecApprovalsSetParams, I as validateDeviceTokenRotateParams, It as deriveDeviceIdFromPublicKey, J as validateNodeInvokeResultParams, K as validateNodeEventParams, L as validateExecApprovalRequestParams, M as validateDevicePairApproveParams, N as validateDevicePairListParams, Nt as normalizeInputProvenance, O as validateCronRunParams, Ot as ErrorCodes, P as validateDevicePairRejectParams, Pt as buildDeviceAuthPayload, Q as validateNodePairRejectParams, R as validateExecApprovalResolveParams, Rt as normalizeDevicePublicKeyBase64Url, S as validateConfigSchemaParams, St as validateWebLoginWaitParams, T as validateCronAddParams, Tt as validateWizardStartParams, U as validateLogsTailParams, V as validateExecApprovalsNodeSetParams, W as validateModelsListParams, X as validateNodePairApproveParams, Y as validateNodeListParams, Z as validateNodePairListParams, _ as validateChatInjectParams, _t as validateTalkConfigParams, a as validateAgentWaitParams, at as validateSessionsCompactParams, b as validateConfigGetParams, bt as validateWakeParams, c as validateAgentsFilesGetParams, ct as validateSessionsPatchParams, d as validateAgentsListParams, dt as validateSessionsResolveParams, et as validateNodePairVerifyParams, f as validateAgentsUpdateParams, ft as validateSessionsUsageParams, g as validateChatHistoryParams, gt as validateSkillsUpdateParams, h as validateChatAbortParams, ht as validateSkillsStatusParams, i as validateAgentParams, it as validateSendParams, j as validateCronUpdateParams, jt as parseSessionLabel, k as validateCronRunsParams, kt as errorShape, l as validateAgentsFilesListParams, lt as validateSessionsPreviewParams, m as validateChannelsStatusParams, mt as validateSkillsInstallParams, n as formatValidationErrors, nt as validatePollParams, o as validateAgentsCreateParams, ot as validateSessionsDeleteParams, p as validateChannelsLogoutParams, pt as validateSkillsBinsParams, q as validateNodeInvokeParams, r as validateAgentIdentityParams, rt as validateRequestFrame, s as validateAgentsDeleteParams, st as validateSessionsListParams, tt as validateNodeRenameParams, u as validateAgentsFilesSetParams, ut as validateSessionsResetParams, v as validateChatSendParams, vt as validateTalkModeParams, w as validateConnectParams, wt as validateWizardNextParams, x as validateConfigPatchParams, xt as validateWebLoginStartParams, y as validateConfigApplyParams, yt as validateUpdateRunParams, z as validateExecApprovalsGetParams, zt as verifyDeviceSignature } from "./client-CfLiulzK.js";
8
+ import { T as resolveWorkspaceTemplateDir, _ as DEFAULT_MEMORY_FILENAME, b as DEFAULT_USER_FILENAME, c as resolveDefaultAgentId, d as DEFAULT_AGENTS_FILENAME, g as DEFAULT_MEMORY_ALT_FILENAME, h as DEFAULT_IDENTITY_FILENAME, i as resolveAgentModelFallbacksOverride, l as resolveSessionAgentId, m as DEFAULT_HEARTBEAT_FILENAME, n as resolveAgentConfig, p as DEFAULT_BOOTSTRAP_FILENAME, r as resolveAgentDir, s as resolveAgentWorkspaceDir, t as listAgentIds, v as DEFAULT_SOUL_FILENAME, w as resolveDefaultAgentWorkspaceDir, x as ensureAgentWorkspace, y as DEFAULT_TOOLS_FILENAME } from "./agent-scope-B1FoYHfj.js";
9
+ import { _ as DEFAULT_MODEL, a as isCliProvider, d as resolveConfiguredModelRef, f as resolveDefaultModelForAgent, g as DEFAULT_CONTEXT_TOKENS, h as resolveThinkingDefault, i as getModelRefStatus, p as resolveHooksGmailModel, u as resolveAllowedModelRef, v as DEFAULT_PROVIDER } from "./model-selection-f7lJs3PI.js";
10
+ import { i as loadWorkspaceSkillEntries, r as buildWorkspaceSkillSnapshot, x as hasBinary } from "./skills-BT0Lx09M.js";
11
+ import { o as isTestDefaultMemorySlotDisabled } from "./manifest-registry-BAebAG4I.js";
12
+ import { t as buildWorkspaceSkillStatus } from "./skills-status-BUKnQ3ek.js";
13
+ import { A as resolveAgentMaxConcurrent, M as VERSION, T as applyLegacyMigrations, a as parseConfigJson5, c as resolveConfigSnapshotHash, d as AnimaSchema, i as loadConfig, j as resolveSubagentMaxConcurrent, l as writeConfigFile, m as parseDurationMs, n as migrateLegacyConfig, o as readConfigFileSnapshot, p as sensitive, r as createConfigIO, s as readConfigFileSnapshotForWrite, u as validateConfigObjectWithPlugins, w as applyMergePatch } from "./config-DmsfUvB0.js";
14
+ import { $ as validateNodePairRequestParams, A as validateCronStatusParams, B as validateExecApprovalsNodeGetParams, C as validateConfigSetParams, Ct as validateWizardCancelParams, D as validateCronRemoveParams, Dt as PROTOCOL_VERSION, E as validateCronListParams, Et as validateWizardStatusParams, F as validateDeviceTokenRevokeParams, G as validateNodeDescribeParams, H as validateExecApprovalsSetParams, I as validateDeviceTokenRotateParams, It as deriveDeviceIdFromPublicKey, J as validateNodeInvokeResultParams, K as validateNodeEventParams, L as validateExecApprovalRequestParams, M as validateDevicePairApproveParams, N as validateDevicePairListParams, Nt as normalizeInputProvenance, O as validateCronRunParams, Ot as ErrorCodes, P as validateDevicePairRejectParams, Pt as buildDeviceAuthPayload, Q as validateNodePairRejectParams, R as validateExecApprovalResolveParams, Rt as normalizeDevicePublicKeyBase64Url, S as validateConfigSchemaParams, St as validateWebLoginWaitParams, T as validateCronAddParams, Tt as validateWizardStartParams, U as validateLogsTailParams, V as validateExecApprovalsNodeSetParams, W as validateModelsListParams, X as validateNodePairApproveParams, Y as validateNodeListParams, Z as validateNodePairListParams, _ as validateChatInjectParams, _t as validateTalkConfigParams, a as validateAgentWaitParams, at as validateSessionsCompactParams, b as validateConfigGetParams, bt as validateWakeParams, c as validateAgentsFilesGetParams, ct as validateSessionsPatchParams, d as validateAgentsListParams, dt as validateSessionsResolveParams, et as validateNodePairVerifyParams, f as validateAgentsUpdateParams, ft as validateSessionsUsageParams, g as validateChatHistoryParams, gt as validateSkillsUpdateParams, h as validateChatAbortParams, ht as validateSkillsStatusParams, i as validateAgentParams, it as validateSendParams, j as validateCronUpdateParams, jt as parseSessionLabel, k as validateCronRunsParams, kt as errorShape, l as validateAgentsFilesListParams, lt as validateSessionsPreviewParams, m as validateChannelsStatusParams, mt as validateSkillsInstallParams, n as formatValidationErrors, nt as validatePollParams, o as validateAgentsCreateParams, ot as validateSessionsDeleteParams, p as validateChannelsLogoutParams, pt as validateSkillsBinsParams, q as validateNodeInvokeParams, r as validateAgentIdentityParams, rt as validateRequestFrame, s as validateAgentsDeleteParams, st as validateSessionsListParams, tt as validateNodeRenameParams, u as validateAgentsFilesSetParams, ut as validateSessionsResetParams, v as validateChatSendParams, vt as validateTalkModeParams, w as validateConnectParams, wt as validateWizardNextParams, x as validateConfigPatchParams, xt as validateWebLoginStartParams, y as validateConfigApplyParams, yt as validateUpdateRunParams, z as validateExecApprovalsGetParams, zt as verifyDeviceSignature } from "./client-DNDzi0CF.js";
15
15
  import { n as pickPrimaryTailnetIPv6, t as pickPrimaryTailnetIPv4 } from "./tailnet-DpzsRR75.js";
16
- import { s as loadGatewayTlsRuntime$1 } from "./call-B4lhqS6H.js";
17
- import { f as GATEWAY_CLIENT_CAPS, g as hasGatewayClientCap, i as isGatewayMessageChannel, l as normalizeMessageChannel, n as isDeliverableMessageChannel, p as GATEWAY_CLIENT_IDS, r as isGatewayCliClient, s as isWebchatClient, t as INTERNAL_MESSAGE_CHANNEL } from "./message-channel-DIHHKJhk.js";
16
+ import { s as loadGatewayTlsRuntime$1 } from "./call-CPfxv8yg.js";
17
+ import { f as GATEWAY_CLIENT_CAPS, g as hasGatewayClientCap, i as isGatewayMessageChannel, l as normalizeMessageChannel, n as isDeliverableMessageChannel, p as GATEWAY_CLIENT_IDS, r as isGatewayCliClient, s as isWebchatClient, t as INTERNAL_MESSAGE_CHANNEL } from "./message-channel-qmDI9YoO.js";
18
18
  import { c as resolveGatewayBindHost, d as rawDataToString, i as isTrustedProxyAddress, l as resolveGatewayClientIp, n as isLoopbackHost, r as isPrivateOrLoopbackAddress, s as pickPrimaryLanIPv4, t as isLoopbackAddress, u as resolveGatewayListenHosts } from "./net-CRsiP49R.js";
19
- import { $ as ensureOutboundSessionEntry, $n as extractImageContentFromSource, $t as loadProviderStore, A as getTotalQueueSize, An as registerSkillsChangeListener, B as loadCombinedSessionStoreForGateway, Cn as renamePairedNode, Ct as normalizeCronJobPatch, D as setCliSessionId, Dn as generatePairingToken, Dr as getAgentRunContext, Dt as normalizePayloadToSystemText, E as getCliSessionId, En as verifyNodeToken, Er as emitAgentEvent, Et as normalizeOptionalText, F as readLatestAssistantReply, Fn as enqueueSystemEvent, Ft as isExternalHookSession, G as archiveFileOnDisk, Gn as DEFAULT_INPUT_IMAGE_MAX_BYTES, Gt as isGatewaySigusr1RestartExternallyAllowed, H as pruneLegacyStoreKeys, Hn as DEFAULT_INPUT_FILE_MAX_BYTES, Ht as consumeGatewaySigusr1RestartAuthorization, I as resolveAnnounceTargetFromKey, In as isSystemEventContextChanged, It as applyBrowserProxyPaths, J as readSessionMessages, Jn as DEFAULT_INPUT_PDF_MAX_PAGES, Jt as setGatewaySigusr1RestartPolicy, K as archiveSessionTranscripts, Kn as DEFAULT_INPUT_IMAGE_MIMES, Kt as markGatewaySigusr1RestartHandled, L as canonicalizeSpawnedByForAgent, Lt as persistBrowserProxyFiles, M as setCommandLaneConcurrency, Mn as applyModelOverrideToSessionEntry, Mt as buildSafeExternalPrompt, N as waitForActiveTasks, Nn as applyVerboseOverride, Nt as detectSuspiciousPatterns, O as getActiveTaskCount, On as verifyPairingToken, Or as onAgentEvent, Ot as normalizeRequiredName, P as createAnimaTools, Pn as parseVerboseOverride, Pt as getHookType, Qn as extractFileContentFromSource, Qt as loadProviderUsageSummary, R as listAgentsForGateway, S as getTotalPendingReplies, Sn as rejectNodePairing, St as normalizeCronJobCreate, T as BARE_SESSION_RESET_PROMPT, Tn as updatePairedNodeMetadata, Tr as clearAgentRunContext, Tt as normalizeOptionalAgentId, U as resolveGatewaySessionStoreTarget, Un as DEFAULT_INPUT_FILE_MAX_CHARS, Ut as deferGatewayRestartUntilIdle, V as loadSessionEntry, Vn as registerUnhandledRejectionHandler, Vt as CommandLane, W as resolveSessionModelRef, Wn as DEFAULT_INPUT_FILE_MIMES, Wt as emitGatewayRestart, X as resolveSessionTranscriptCandidates, Xn as DEFAULT_INPUT_PDF_MIN_TEXT_CHARS, Xt as normalizeGroupActivation, Y as readSessionPreviewItemsFromTranscript, Yn as DEFAULT_INPUT_PDF_MAX_PIXELS, Yt as setPreRestartDeferralCheck, Z as stripEnvelopeFromMessages, Zn as DEFAULT_INPUT_TIMEOUT_MS, _n as refreshRemoteNodeBins, _t as formatRestartSentinelMessage, a as runSubagentAnnounceFlow, ar as stopDiagnosticHeartbeat, b as dispatchInboundMessage, bn as approveNodePairing, c as waitForEmbeddedPiRunEnd, ct as resolveSessionDeliveryTarget, d as buildDefaultToolPolicyPipelineSteps, dn as normalizeSendPolicy, dr as formatZonedTimestamp, dt as resolveMessageChannelSelection, en as maskApiKey, er as normalizeMimeList, et as resolveOutboundSessionRoute, f as sniffMimeFromBase64, fn as resolveSendPolicy, g as getChannelActivity, gn as refreshRemoteBinsForConnectedNodes, gt as formatDoctorNonInteractiveHint, hn as recordRemoteNodeInfo, hr as stopSubagentsForRequester, ht as consumeRestartSentinel, ir as startDiagnosticHeartbeat, j as resetAllLanes, kn as getSkillsSnapshotVersion, kr as registerAgentRunContext, kt as migrateLegacyCronPayload, l as runNoxSoftEmbeddedAgent, ln as requestHeartbeatNow, m as loadAnimaPlugins, mn as primeRemoteSkillsCache, mr as isAbortTrigger, mt as resolveWorkingModeModelSelection, n as initSubagentRegistry, o as clearSessionQueues, or as isDiagnosticsEnabled, p as getPluginToolMeta, pn as getRemoteSkillEligibility, pt as runWithModelFallback, q as capArrayByJsonBytes, qn as DEFAULT_INPUT_MAX_REDIRECTS, qt as scheduleGatewaySigusr1Restart, r as listDescendantRunsForRequester, rr as resolveAgentTimeoutMs, s as abortEmbeddedPiRun, st as resolveOutboundTarget, t as countActiveDescendantRuns, tn as saveProviderStore, tr as estimateBase64DecodedBytes, u as applyToolPolicyPipeline, ut as resetDirectoryCache, vn as removeRemoteNodeInfo, wn as requestNodePairing, wt as inferLegacyName, x as createReplyDispatcher, xn as listNodePairing, xt as writeRestartSentinel, yn as setSkillsRemoteRegistry, yr as resolveAgentIdentity, yt as summarizeRestartSentinel, z as listSessionsFromStore, zn as loadModelCatalog } from "./subagent-registry-CDEUbtey.js";
20
- import { C as resolveMainSessionKeyFromConfig, I as normalizeSessionDeliveryFields, M as deliveryContextFromSession, P as mergeDeliveryContext, S as resolveMainSessionKey, T as snapshotSessionOrigin, b as resolveAgentMainSessionKey, i as loadSessionStore, l as updateSessionStore, t as extractDeliveryInfo, x as resolveExplicitAgentSessionKey } from "./sessions-C_3wTmSA.js";
21
- import { n as SILENT_REPLY_TOKEN, r as isSilentReplyText } from "./tokens-CmlI2hSz.js";
22
- import { B as resolveTtsConfig, F as isTtsProviderConfigured, G as setTtsEnabled, H as resolveTtsProviderOrder, J as textToSpeech, M as getTtsProvider, P as isTtsEnabled, R as resolveTtsApiKey, T as resolveUserTimezone, V as resolveTtsPrefsPath, X as OPENAI_TTS_MODELS, Z as OPENAI_TTS_VOICES, ct as createInternalHookEvent, dt as DEFAULT_HEARTBEAT_ACK_MAX_CHARS, et as clearSteer, ht as stripHeartbeatToken, it as getEgoManager, lt as registerInternalHook, nt as getSteerHistory, q as setTtsProvider, rt as setSteer, st as clearInternalHooks, tt as getSteer, ut as triggerInternalHook, z as resolveTtsAutoMode } from "./anthropic-direct-runner-Bu8w-wlJ.js";
23
- import { a as normalizeElevatedLevel, c as normalizeUsageDisplay, d as supportsXHighThinking, l as normalizeVerboseLevel, n as formatXHighModelHint, o as normalizeReasoningLevel, s as normalizeThinkLevel, t as formatThinkingLevels } from "./pi-embedded-helpers-D2SLlgS4.js";
24
- import { _ as resolveToolProfilePolicy, p as collectExplicitAllowlist } from "./sandbox-D-N7M7lp.js";
25
- import { a as AUTH_RATE_LIMIT_SCOPE_DEVICE_TOKEN, c as safeEqualSecret, d as enableTailscaleFunnel, f as enableTailscaleServe, i as resolveGatewayAuth, l as disableTailscaleFunnel, m as getTailnetHostname, n as authorizeGatewayConnect, o as AUTH_RATE_LIMIT_SCOPE_SHARED_SECRET, r as isLocalDirectRequest, s as createAuthRateLimiter, t as assertGatewayAuthConfigured, u as disableTailscaleServe } from "./auth-Cp__MMeO.js";
26
- import { r as movePathToTrash } from "./server-context-Clykq0XU.js";
19
+ import { $ as stripEnvelopeFromMessages, $n as DEFAULT_INPUT_TIMEOUT_MS, A as getActiveTaskCount, An as verifyPairingToken, Ar as onAgentEvent, At as normalizeRequiredName, B as listAgentsForGateway, C as createReplyDispatcher, Cn as listNodePairing, Ct as writeRestartSentinel, D as BARE_SESSION_RESET_PROMPT, Dn as updatePairedNodeMetadata, Dr as clearAgentRunContext, Dt as normalizeOptionalAgentId, En as requestNodePairing, Et as inferLegacyName, F as waitForActiveTasks, Fn as applyVerboseOverride, Ft as detectSuspiciousPatterns, G as resolveGatewaySessionStoreTarget, Gn as DEFAULT_INPUT_FILE_MAX_CHARS, Gt as deferGatewayRestartUntilIdle, H as loadCombinedSessionStoreForGateway, I as createAnimaTools, In as parseVerboseOverride, It as getHookType, J as archiveSessionTranscripts, Jn as DEFAULT_INPUT_IMAGE_MIMES, Jt as markGatewaySigusr1RestartHandled, K as resolveSessionModelRef, Kn as DEFAULT_INPUT_FILE_MIMES, Kt as emitGatewayRestart, L as readLatestAssistantReply, Ln as enqueueSystemEvent, Lt as isExternalHookSession, M as getTotalQueueSize, Mn as registerSkillsChangeListener, N as resetAllLanes, O as getCliSessionId, On as verifyNodeToken, Or as emitAgentEvent, Ot as normalizeOptionalText, P as setCommandLaneConcurrency, Pn as applyModelOverrideToSessionEntry, Pt as buildSafeExternalPrompt, Q as resolveSessionTranscriptCandidates, Qn as DEFAULT_INPUT_PDF_MIN_TEXT_CHARS, Qt as normalizeGroupActivation, R as resolveAnnounceTargetFromKey, Rn as isSystemEventContextChanged, Rt as applyBrowserProxyPaths, S as dispatchInboundMessage, Sn as approveNodePairing, Tn as renamePairedNode, Tt as normalizeCronJobPatch, U as loadSessionEntry, Un as registerUnhandledRejectionHandler, Ut as CommandLane, V as listSessionsFromStore, Vn as loadModelCatalog, W as pruneLegacyStoreKeys, Wn as DEFAULT_INPUT_FILE_MAX_BYTES, Wt as consumeGatewaySigusr1RestartAuthorization, X as readSessionMessages, Xn as DEFAULT_INPUT_PDF_MAX_PAGES, Xt as setGatewaySigusr1RestartPolicy, Y as capArrayByJsonBytes, Yn as DEFAULT_INPUT_MAX_REDIRECTS, Yt as scheduleGatewaySigusr1Restart, Z as readSessionPreviewItemsFromTranscript, Zn as DEFAULT_INPUT_PDF_MAX_PIXELS, Zt as setPreRestartDeferralCheck, _n as recordRemoteNodeInfo, _r as stopSubagentsForRequester, _t as consumeRestartSentinel, a as runSubagentAnnounceFlow, ar as resolveAgentTimeoutMs, bn as removeRemoteNodeInfo, c as waitForEmbeddedPiRunEnd, cr as isDiagnosticsEnabled, dn as requestHeartbeatNow, en as loadProviderUsageSummary, er as extractFileContentFromSource, f as applyToolPolicyPipeline, ft as resetDirectoryCache, g as loadAnimaPlugins, gn as primeRemoteSkillsCache, gr as isAbortTrigger, gt as resolveWorkingModeModelSelection, h as getPluginToolMeta, hn as getRemoteSkillEligibility, ht as runWithModelFallback, jn as getSkillsSnapshotVersion, jr as registerAgentRunContext, jt as migrateLegacyCronPayload, k as setCliSessionId, kn as generatePairingToken, kr as getAgentRunContext, kt as normalizePayloadToSystemText, l as runNoxSoftEmbeddedAgent, lt as resolveOutboundTarget, m as sniffMimeFromBase64, mn as resolveSendPolicy, n as initSubagentRegistry, nn as maskApiKey, nr as normalizeMimeList, nt as resolveOutboundSessionRoute, o as clearSessionQueues, or as startDiagnosticHeartbeat, p as buildDefaultToolPolicyPipelineSteps, pn as normalizeSendPolicy, pr as formatZonedTimestamp, pt as resolveMessageChannelSelection, q as archiveFileOnDisk, qn as DEFAULT_INPUT_IMAGE_MAX_BYTES, qt as isGatewaySigusr1RestartExternallyAllowed, r as listDescendantRunsForRequester, rn as saveProviderStore, rr as estimateBase64DecodedBytes, s as abortEmbeddedPiRun, sr as stopDiagnosticHeartbeat, t as countActiveDescendantRuns, tn as loadProviderStore, tr as extractImageContentFromSource, tt as ensureOutboundSessionEntry, ut as resolveSessionDeliveryTarget, v as getChannelActivity, vn as refreshRemoteBinsForConnectedNodes, vt as formatDoctorNonInteractiveHint, w as getTotalPendingReplies, wn as rejectNodePairing, wt as normalizeCronJobCreate, xn as setSkillsRemoteRegistry, xr as resolveAgentIdentity, xt as summarizeRestartSentinel, yn as refreshRemoteNodeBins, yt as formatRestartSentinelMessage, z as canonicalizeSpawnedByForAgent, zt as persistBrowserProxyFiles } from "./subagent-registry-D87n8mHd.js";
20
+ import { C as resolveMainSessionKeyFromConfig, I as normalizeSessionDeliveryFields, M as deliveryContextFromSession, P as mergeDeliveryContext, S as resolveMainSessionKey, T as snapshotSessionOrigin, b as resolveAgentMainSessionKey, i as loadSessionStore, l as updateSessionStore, t as extractDeliveryInfo, x as resolveExplicitAgentSessionKey } from "./sessions-B2NwIaNC.js";
21
+ import { n as SILENT_REPLY_TOKEN, r as isSilentReplyText } from "./tokens-nliOJNMv.js";
22
+ import { B as resolveTtsConfig, F as isTtsProviderConfigured, G as setTtsEnabled, H as resolveTtsProviderOrder, J as textToSpeech, M as getTtsProvider, P as isTtsEnabled, R as resolveTtsApiKey, T as resolveUserTimezone, V as resolveTtsPrefsPath, X as OPENAI_TTS_MODELS, Z as OPENAI_TTS_VOICES, ct as createInternalHookEvent, dt as DEFAULT_HEARTBEAT_ACK_MAX_CHARS, et as clearSteer, ht as stripHeartbeatToken, it as getEgoManager, lt as registerInternalHook, nt as getSteerHistory, q as setTtsProvider, rt as setSteer, st as clearInternalHooks, tt as getSteer, ut as triggerInternalHook, z as resolveTtsAutoMode } from "./anthropic-direct-runner-BNiXWmel.js";
23
+ import { a as normalizeElevatedLevel, c as normalizeUsageDisplay, d as supportsXHighThinking, l as normalizeVerboseLevel, n as formatXHighModelHint, o as normalizeReasoningLevel, s as normalizeThinkLevel, t as formatThinkingLevels } from "./pi-embedded-helpers-BSFtS9Fl.js";
24
+ import { _ as resolveToolProfilePolicy, p as collectExplicitAllowlist } from "./sandbox-DSHSoUHO.js";
25
+ import { a as AUTH_RATE_LIMIT_SCOPE_DEVICE_TOKEN, c as safeEqualSecret, d as enableTailscaleFunnel, f as enableTailscaleServe, i as resolveGatewayAuth, l as disableTailscaleFunnel, m as getTailnetHostname, n as authorizeGatewayConnect, o as AUTH_RATE_LIMIT_SCOPE_SHARED_SECRET, r as isLocalDirectRequest, s as createAuthRateLimiter, t as assertGatewayAuthConfigured, u as disableTailscaleServe } from "./auth-Bw3NUKcg.js";
26
+ import { r as movePathToTrash } from "./server-context-EPPcxp2p.js";
27
27
  import { n as formatErrorMessage } from "./errors-COFgygw8.js";
28
- import { o as detectMime } from "./image-ops-BdrMmiG4.js";
29
- import { i as formatPortDiagnostics, n as inspectPortUsage } from "./ports-B_f42zcA.js";
30
- import { n as listChannelPlugins, r as normalizeChannelId, t as getChannelPlugin } from "./plugins-BOMS6J5A.js";
31
- import { c as resolveStorePath, i as resolveSessionTranscriptPath, n as resolveSessionFilePath, r as resolveSessionFilePathOptions, s as resolveSessionTranscriptsDirForAgent } from "./paths-DMk3Q7yD.js";
32
- import { o as normalizeReplyPayloadsForDelivery, t as deliverOutboundPayloads, x as runGlobalGatewayStopSafely, y as getGlobalHookRunner } from "./deliver-C1L5nO0K.js";
33
- import { i as resolveMemoryBackendConfig, r as getMemorySearchManager } from "./memory-cli-B0kKl-9T.js";
34
- import { a as readTrustGraphSnapshot, c as pruneExpiredPending, d as writeJsonAtomic, l as readJsonFile, o as saveTrustGraph, s as createAsyncLock, u as resolvePairingPaths } from "./loader-C87TLS4J.js";
35
- import { t as ToolInputError } from "./common-CqIa2poH.js";
36
- import { o as normalizePollInput } from "./active-listener-gGCoq55D.js";
37
- import { t as lookupContextTokens } from "./context-mdxDsO1v.js";
38
- import { a as resolveSubagentToolPolicy, i as resolveGroupToolPolicy, r as resolveEffectiveToolPolicy } from "./pi-tools.policy-D2FusuQa.js";
28
+ import { o as detectMime } from "./image-ops-flDr58qn.js";
29
+ import { i as formatPortDiagnostics, n as inspectPortUsage } from "./ports-C4ACB4MP.js";
30
+ import { n as listChannelPlugins, r as normalizeChannelId, t as getChannelPlugin } from "./plugins-C8FLxXbd.js";
31
+ import { c as resolveStorePath, i as resolveSessionTranscriptPath, n as resolveSessionFilePath, r as resolveSessionFilePathOptions, s as resolveSessionTranscriptsDirForAgent } from "./paths-BM1wivAU.js";
32
+ import { o as normalizeReplyPayloadsForDelivery, t as deliverOutboundPayloads, x as runGlobalGatewayStopSafely, y as getGlobalHookRunner } from "./deliver-D86kSZGn.js";
33
+ import { i as resolveMemoryBackendConfig, r as getMemorySearchManager } from "./memory-cli-BJmQIQSw.js";
34
+ import { a as readTrustGraphSnapshot, c as pruneExpiredPending, d as writeJsonAtomic, l as readJsonFile, o as saveTrustGraph, s as createAsyncLock, u as resolvePairingPaths } from "./loader-5Xm3Jxa-.js";
35
+ import { t as ToolInputError } from "./common-c4ZysSLq.js";
36
+ import { o as normalizePollInput } from "./active-listener-D78ohfOc.js";
37
+ import { t as lookupContextTokens } from "./context-C22AMgsc.js";
38
+ import { a as resolveSubagentToolPolicy, i as resolveGroupToolPolicy, r as resolveEffectiveToolPolicy } from "./pi-tools.policy-DyckzpRL.js";
39
39
  import { f as resolveExecApprovalsSocketPath, o as normalizeExecApprovals, p as saveExecApprovals, r as ensureExecApprovals, s as readExecApprovalsSnapshot, t as DEFAULT_EXEC_APPROVAL_TIMEOUT_MS } from "./exec-approvals-CpOeHRBL.js";
40
- import { i as loadSessionUsageTimeSeries, l as deriveSessionTotalTokens, n as loadCostUsageSummary, r as loadSessionCostSummary, t as discoverAllSessions, u as hasNonzeroUsage } from "./session-cost-usage-DnxtnK1E.js";
41
- import { n as createBrowserControlContext, r as startBrowserControlServiceFromConfig } from "./control-service-3CI4vt1h.js";
42
- import { t as createBrowserRouteDispatcher } from "./dispatcher-BQQugU-7.js";
40
+ import { i as loadSessionUsageTimeSeries, l as deriveSessionTotalTokens, n as loadCostUsageSummary, r as loadSessionCostSummary, t as discoverAllSessions, u as hasNonzeroUsage } from "./session-cost-usage-BNvno_kS.js";
41
+ import { n as createBrowserControlContext, r as startBrowserControlServiceFromConfig } from "./control-service-DxuB_IUw.js";
42
+ import { t as createBrowserRouteDispatcher } from "./dispatcher-DwlzWX2u.js";
43
43
  import { t as parseAbsoluteTimeMs } from "./parse-DLMgOMDI.js";
44
44
  import { c as saveToken, i as getToken, l as whoami, n as clearToken, o as registerWithInvite, s as resolveSuggestedIdentity, t as TOKEN_PATH } from "./noxsoft-auth-CgCk5707.js";
45
- import { c as resolveCronStyleNow, i as onHeartbeatEvent, r as getLastHeartbeatEvent, t as resolveHeartbeatVisibility } from "./heartbeat-visibility-mAzdNSiS.js";
46
- import { r as buildHistoryContextFromEntries, t as createReplyPrefixOptions } from "./reply-prefix-Og65nAYv.js";
45
+ import { c as resolveCronStyleNow, i as onHeartbeatEvent, r as getLastHeartbeatEvent, t as resolveHeartbeatVisibility } from "./heartbeat-visibility-XbT4yJ3S.js";
46
+ import { r as buildHistoryContextFromEntries, t as createReplyPrefixOptions } from "./reply-prefix-DuANpRN_.js";
47
47
  import { t as ensureAnimaCliOnPath } from "./path-env-CafGfJPa.js";
48
48
  import { n as DEFAULT_GATEWAY_HTTP_TOOL_DENY } from "./dangerous-tools-Asx2qyrG.js";
49
- import { C as resolveAssistantAvatarUrl, S as normalizeControlUiBasePath, b as CONTROL_UI_AVATAR_PREFIX, c as handleReset, h as resolveControlUiLinks, x as buildControlUiAvatarUrl } from "./onboard-helpers-CFudIoX4.js";
50
- import { t as resolveGatewayService } from "./service-4VfZwSv1.js";
49
+ import { C as resolveAssistantAvatarUrl, S as normalizeControlUiBasePath, b as CONTROL_UI_AVATAR_PREFIX, c as handleReset, h as resolveControlUiLinks, x as buildControlUiAvatarUrl } from "./onboard-helpers-uf70JxTj.js";
50
+ import { t as resolveGatewayService } from "./service-BoUEkrUm.js";
51
51
  import { t as parsePort } from "./parse-port-BKB9Exlg.js";
52
- import { n as resolveWideAreaDiscoveryDomain, r as writeWideAreaGatewayZone } from "./widearea-dns-CtU9Fx7K.js";
53
- import { i as toOptionString, n as extractGatewayMiskeys, r as maybeExplainGatewayServiceStop, t as describeUnknownError } from "./shared-7KwLAyAq.js";
54
- import { o as isNodeCommandAllowed, s as resolveNodeCommandAllowlist } from "./audit-DDz7UOIx.js";
55
- import { r as getStatusSummary } from "./status-D37aRiV3.js";
52
+ import { n as resolveWideAreaDiscoveryDomain, r as writeWideAreaGatewayZone } from "./widearea-dns-D2VSHQ7y.js";
53
+ import { i as toOptionString, n as extractGatewayMiskeys, r as maybeExplainGatewayServiceStop, t as describeUnknownError } from "./shared-D3ZAXqdo.js";
54
+ import { o as isNodeCommandAllowed, s as resolveNodeCommandAllowlist } from "./audit-CupURkPI.js";
55
+ import { r as getStatusSummary } from "./status-CSkpd-tb.js";
56
56
  import { t as resolveChannelDefaultAccountId } from "./helpers-CVp8W9aa.js";
57
- import { c as setHeartbeatsEnabled, l as startHeartbeatRunner, n as getHealthSnapshot, s as runHeartbeatOnce } from "./health-ngQNjXh4.js";
58
- import { n as createDefaultDeps, r as createOutboundSendDeps$1, t as createOutboundSendDeps } from "./outbound-send-deps-DMsqr5fd.js";
59
- import { t as buildChannelUiCatalog } from "./catalog-B-TAbJ2o.js";
60
- import { t as applyPluginAutoEnable } from "./plugin-auto-enable-DhuD30Je.js";
61
- import { a as resolveControlUiRootOverrideSync, n as ensureControlUiAssetsBuilt, o as resolveControlUiRootSync } from "./health-format-BLnFZCH_.js";
57
+ import { c as setHeartbeatsEnabled, l as startHeartbeatRunner, n as getHealthSnapshot, s as runHeartbeatOnce } from "./health-C6rAUaME.js";
58
+ import { n as createDefaultDeps, r as createOutboundSendDeps$1, t as createOutboundSendDeps } from "./outbound-send-deps-CtiCh8EY.js";
59
+ import { t as buildChannelUiCatalog } from "./catalog-yCaNFdQz.js";
60
+ import { t as applyPluginAutoEnable } from "./plugin-auto-enable-Btd2iEwF.js";
61
+ import { a as resolveControlUiRootOverrideSync, n as ensureControlUiAssetsBuilt, o as resolveControlUiRootSync } from "./health-format-CTOsgiTE.js";
62
62
  import { n as validateSystemRunCommandConsistency, r as getMachineDisplayName, t as formatExecCommand } from "./system-run-command-CxQM9dLk.js";
63
- import { h as normalizeUpdateChannel, l as DEFAULT_PACKAGE_CHANNEL, n as checkUpdateStatus, o as resolveNpmChannelTag, r as compareSemverStrings } from "./channels-status-issues-CklLFAsD.js";
64
- import { t as WizardCancelledError } from "./prompts-BmgT_kkv.js";
65
- import { i as shouldIncludeHook, n as loadWorkspaceHookEntries, r as resolveHookConfig } from "./hooks-status-DqfJDvYl.js";
66
- import { t as runOnboardingWizard } from "./onboarding-6jxAKxhe.js";
67
- import { a as setGatewayWsLogStyle, i as summarizeAgentEventForWsLog, n as logWs, r as shouldLogWs, t as formatForLog } from "./ws-log-CG6cvCZW.js";
68
- import { T as resolveGmailHookRuntimeConfig, _ as buildGogWatchServeArgs, i as ensureTailscaleEndpoint, v as buildGogWatchStartArgs } from "./gmail-setup-utils-BIXtKTpT.js";
69
- import { a as loadAgentIdentity, c as loadAgentIdentityFromWorkspace, i as listAgentEntries, o as pruneAgentConfig, r as findAgentEntryIndex, t as applyAgentConfig } from "./agents.config-Br4ULmK0.js";
70
- import { n as resolveAgentDeliveryPlan, r as resolveAgentOutboundTarget, t as agentCommand } from "./agent-PoYM2xa7.js";
63
+ import { h as normalizeUpdateChannel, l as DEFAULT_PACKAGE_CHANNEL, n as checkUpdateStatus, o as resolveNpmChannelTag, r as compareSemverStrings } from "./channels-status-issues-BhtWH-p2.js";
64
+ import { t as WizardCancelledError } from "./prompts-C4v0DSTU.js";
65
+ import { i as shouldIncludeHook, n as loadWorkspaceHookEntries, r as resolveHookConfig } from "./hooks-status-BlfmlpC0.js";
66
+ import { t as runOnboardingWizard } from "./onboarding-DQplq13s.js";
67
+ import { a as setGatewayWsLogStyle, i as summarizeAgentEventForWsLog, n as logWs, r as shouldLogWs, t as formatForLog } from "./ws-log-DwsFDY7m.js";
68
+ import { T as resolveGmailHookRuntimeConfig, _ as buildGogWatchServeArgs, i as ensureTailscaleEndpoint, v as buildGogWatchStartArgs } from "./gmail-setup-utils-JWsjxDBV.js";
69
+ import { a as loadAgentIdentity, c as loadAgentIdentityFromWorkspace, i as listAgentEntries, o as pruneAgentConfig, r as findAgentEntryIndex, t as applyAgentConfig } from "./agents.config-sfN0WxRg.js";
70
+ import { n as resolveAgentDeliveryPlan, r as resolveAgentOutboundTarget, t as agentCommand } from "./agent-viQL5eva.js";
71
71
  import { t as migrateFromCoherence } from "./migrate-bgeTT_GR.js";
72
- import { t as installSkill } from "./skills-install-Qw2oU8L8.js";
73
- import { t as runGatewayUpdate } from "./update-runner-Fb3Un6UZ.js";
74
- import { n as forceFreePortAndWait } from "./ports-BGLuwt2Z.js";
72
+ import { t as installSkill } from "./skills-install-Ye1kjpCv.js";
73
+ import { t as runGatewayUpdate } from "./update-runner-DtqDU0xF.js";
74
+ import { n as forceFreePortAndWait } from "./ports--opAW6yN.js";
75
75
  import { execFile, spawn, spawnSync } from "node:child_process";
76
76
  import os from "node:os";
77
77
  import path from "node:path";
@@ -109,7 +109,7 @@ function getActiveEmbeddedRunCount() {
109
109
 
110
110
  //#endregion
111
111
  //#region src/infra/exec-approval-forwarder.ts
112
- const log$12 = createSubsystemLogger("gateway/exec-approvals");
112
+ const log$14 = createSubsystemLogger("gateway/exec-approvals");
113
113
  const DEFAULT_MODE = "session";
114
114
  function normalizeMode(mode) {
115
115
  return mode ?? DEFAULT_MODE;
@@ -224,7 +224,7 @@ async function deliverToTargets(params) {
224
224
  payloads: [{ text: params.text }]
225
225
  });
226
226
  } catch (err) {
227
- log$12.error(`exec approvals: failed to deliver to ${channel}:${target.to}: ${String(err)}`);
227
+ log$14.error(`exec approvals: failed to deliver to ${channel}:${target.to}: ${String(err)}`);
228
228
  }
229
229
  });
230
230
  await Promise.allSettled(deliveries);
@@ -1461,7 +1461,7 @@ function createAgentEventHandler({ broadcast, broadcastToConnIds, nodeSendToSess
1461
1461
  * Automatically starts `gog gmail watch serve` when the gateway starts,
1462
1462
  * if hooks.gmail is configured with an account.
1463
1463
  */
1464
- const log$11 = createSubsystemLogger("gmail-watcher");
1464
+ const log$13 = createSubsystemLogger("gmail-watcher");
1465
1465
  const ADDRESS_IN_USE_RE = /address already in use|EADDRINUSE/i;
1466
1466
  function isAddressInUseError(line) {
1467
1467
  return ADDRESS_IN_USE_RE.test(line);
@@ -1485,13 +1485,13 @@ async function startGmailWatch(cfg) {
1485
1485
  const result = await runCommandWithTimeout(args, { timeoutMs: 12e4 });
1486
1486
  if (result.code !== 0) {
1487
1487
  const message = result.stderr || result.stdout || "gog watch start failed";
1488
- log$11.error(`watch start failed: ${message}`);
1488
+ log$13.error(`watch start failed: ${message}`);
1489
1489
  return false;
1490
1490
  }
1491
- log$11.info(`watch started for ${cfg.account}`);
1491
+ log$13.info(`watch started for ${cfg.account}`);
1492
1492
  return true;
1493
1493
  } catch (err) {
1494
- log$11.error(`watch start error: ${String(err)}`);
1494
+ log$13.error(`watch start error: ${String(err)}`);
1495
1495
  return false;
1496
1496
  }
1497
1497
  }
@@ -1500,7 +1500,7 @@ async function startGmailWatch(cfg) {
1500
1500
  */
1501
1501
  function spawnGogServe(cfg) {
1502
1502
  const args = buildGogWatchServeArgs(cfg);
1503
- log$11.info(`starting gog ${args.join(" ")}`);
1503
+ log$13.info(`starting gog ${args.join(" ")}`);
1504
1504
  let addressInUse = false;
1505
1505
  const child = spawn("gog", args, {
1506
1506
  stdio: [
@@ -1512,25 +1512,25 @@ function spawnGogServe(cfg) {
1512
1512
  });
1513
1513
  child.stdout?.on("data", (data) => {
1514
1514
  const line = data.toString().trim();
1515
- if (line) log$11.info(`[gog] ${line}`);
1515
+ if (line) log$13.info(`[gog] ${line}`);
1516
1516
  });
1517
1517
  child.stderr?.on("data", (data) => {
1518
1518
  const line = data.toString().trim();
1519
1519
  if (!line) return;
1520
1520
  if (isAddressInUseError(line)) addressInUse = true;
1521
- log$11.warn(`[gog] ${line}`);
1521
+ log$13.warn(`[gog] ${line}`);
1522
1522
  });
1523
1523
  child.on("error", (err) => {
1524
- log$11.error(`gog process error: ${String(err)}`);
1524
+ log$13.error(`gog process error: ${String(err)}`);
1525
1525
  });
1526
1526
  child.on("exit", (code, signal) => {
1527
1527
  if (shuttingDown) return;
1528
1528
  if (addressInUse) {
1529
- log$11.warn("gog serve failed to bind (address already in use); stopping restarts. Another watcher is likely running. Set ANIMA_SKIP_GMAIL_WATCHER=1 or stop the other process.");
1529
+ log$13.warn("gog serve failed to bind (address already in use); stopping restarts. Another watcher is likely running. Set ANIMA_SKIP_GMAIL_WATCHER=1 or stop the other process.");
1530
1530
  watcherProcess = null;
1531
1531
  return;
1532
1532
  }
1533
- log$11.warn(`gog exited (code=${code}, signal=${signal}); restarting in 5s`);
1533
+ log$13.warn(`gog exited (code=${code}, signal=${signal}); restarting in 5s`);
1534
1534
  watcherProcess = null;
1535
1535
  setTimeout(() => {
1536
1536
  if (shuttingDown || !currentConfig) return;
@@ -1570,15 +1570,15 @@ async function startGmailWatcher(cfg) {
1570
1570
  port: runtimeConfig.serve.port,
1571
1571
  target: runtimeConfig.tailscale.target
1572
1572
  });
1573
- log$11.info(`tailscale ${runtimeConfig.tailscale.mode} configured for port ${runtimeConfig.serve.port}`);
1573
+ log$13.info(`tailscale ${runtimeConfig.tailscale.mode} configured for port ${runtimeConfig.serve.port}`);
1574
1574
  } catch (err) {
1575
- log$11.error(`tailscale setup failed: ${String(err)}`);
1575
+ log$13.error(`tailscale setup failed: ${String(err)}`);
1576
1576
  return {
1577
1577
  started: false,
1578
1578
  reason: `tailscale setup failed: ${String(err)}`
1579
1579
  };
1580
1580
  }
1581
- if (!await startGmailWatch(runtimeConfig)) log$11.warn("gmail watch start failed, but continuing with serve");
1581
+ if (!await startGmailWatch(runtimeConfig)) log$13.warn("gmail watch start failed, but continuing with serve");
1582
1582
  shuttingDown = false;
1583
1583
  watcherProcess = spawnGogServe(runtimeConfig);
1584
1584
  const renewMs = runtimeConfig.renewEveryMinutes * 6e4;
@@ -1586,7 +1586,7 @@ async function startGmailWatcher(cfg) {
1586
1586
  if (shuttingDown) return;
1587
1587
  startGmailWatch(runtimeConfig);
1588
1588
  }, renewMs);
1589
- log$11.info(`gmail watcher started for ${runtimeConfig.account} (renew every ${runtimeConfig.renewEveryMinutes}m)`);
1589
+ log$13.info(`gmail watcher started for ${runtimeConfig.account} (renew every ${runtimeConfig.renewEveryMinutes}m)`);
1590
1590
  return { started: true };
1591
1591
  }
1592
1592
  /**
@@ -1599,7 +1599,7 @@ async function stopGmailWatcher() {
1599
1599
  renewInterval = null;
1600
1600
  }
1601
1601
  if (watcherProcess) {
1602
- log$11.info("stopping gmail watcher");
1602
+ log$13.info("stopping gmail watcher");
1603
1603
  watcherProcess.kill("SIGTERM");
1604
1604
  await new Promise((resolve) => {
1605
1605
  const timeout = setTimeout(() => {
@@ -1614,7 +1614,7 @@ async function stopGmailWatcher() {
1614
1614
  watcherProcess = null;
1615
1615
  }
1616
1616
  currentConfig = null;
1617
- log$11.info("gmail watcher stopped");
1617
+ log$13.info("gmail watcher stopped");
1618
1618
  }
1619
1619
 
1620
1620
  //#endregion
@@ -4892,6 +4892,8 @@ const BASE_METHODS = [
4892
4892
  "anima.registration.status",
4893
4893
  "anima.registration.set-token",
4894
4894
  "anima.registration.register-invite",
4895
+ "ico.metrics.get",
4896
+ "impact.footprint.get",
4895
4897
  "health",
4896
4898
  "logs.tail",
4897
4899
  "channels.status",
@@ -4976,7 +4978,14 @@ const BASE_METHODS = [
4976
4978
  "agent",
4977
4979
  "agent.identity.get",
4978
4980
  "agent.wait",
4981
+ "browser.capabilities.get",
4979
4982
  "browser.request",
4983
+ "desktop.control.session.create",
4984
+ "desktop.control.session.list",
4985
+ "desktop.control.session.get",
4986
+ "desktop.control.session.approve",
4987
+ "desktop.control.session.close",
4988
+ "desktop.control.session.request",
4980
4989
  "chat.history",
4981
4990
  "chat.abort",
4982
4991
  "chat.send"
@@ -8258,6 +8267,44 @@ function safeParseJson(value) {
8258
8267
 
8259
8268
  //#endregion
8260
8269
  //#region src/gateway/server-methods/browser.ts
8270
+ const DESKTOP_CONTROL_DEFAULT_TTL_MS = 900 * 1e3;
8271
+ const DESKTOP_CONTROL_MIN_TTL_MS = 60 * 1e3;
8272
+ const DESKTOP_CONTROL_MAX_TTL_MS = 14400 * 1e3;
8273
+ const DESKTOP_CONTROL_MAX_REASON_LEN = 240;
8274
+ const DESKTOP_CONTROL_AUDIT_MAX_EVENTS = 200;
8275
+ const DESKTOP_CONTROL_RETENTION_MS = 7200 * 1e3;
8276
+ const DESKTOP_CONTROL_DEFAULT_ALLOWED_METHODS = ["GET"];
8277
+ const DESKTOP_CONTROL_ALLOWED_METHODS = [
8278
+ "GET",
8279
+ "POST",
8280
+ "DELETE"
8281
+ ];
8282
+ const DESKTOP_CONTROL_DEFAULT_MAX_REQUESTS = 40;
8283
+ const DESKTOP_CONTROL_MIN_MAX_REQUESTS = 1;
8284
+ const DESKTOP_CONTROL_MAX_MAX_REQUESTS = 500;
8285
+ const DESKTOP_CONTROL_MAX_NOTE_LEN = 500;
8286
+ const DESKTOP_CONTROL_MIN_DECISION_NOTE_LEN = 8;
8287
+ const DESKTOP_CONTROL_LIST_MIN_LIMIT = 1;
8288
+ const DESKTOP_CONTROL_LIST_MAX_LIMIT = 500;
8289
+ const DESKTOP_CONTROL_LIST_MIN_OFFSET = 0;
8290
+ const DESKTOP_CONTROL_LIST_MAX_OFFSET = 1e4;
8291
+ const BROWSER_REQUEST_MIN_TIMEOUT_MS = 1;
8292
+ const BROWSER_REQUEST_MAX_TIMEOUT_MS = 12e4;
8293
+ const DESKTOP_CONTROL_SESSION_STATES = [
8294
+ "pending_approval",
8295
+ "active",
8296
+ "denied",
8297
+ "closed",
8298
+ "expired"
8299
+ ];
8300
+ const DESKTOP_CONTROL_SESSION_DECISIONS = [
8301
+ "pending",
8302
+ "allow",
8303
+ "deny"
8304
+ ];
8305
+ const DESKTOP_CONTROL_SESSION_ROUTE_KINDS = ["local", "node"];
8306
+ const DESKTOP_CONTROL_SESSION_RISK_LEVELS = ["standard", "elevated"];
8307
+ const desktopControlSessions = /* @__PURE__ */ new Map();
8261
8308
  function isBrowserNode(node) {
8262
8309
  const caps = Array.isArray(node.caps) ? node.caps : [];
8263
8310
  const commands = Array.isArray(node.commands) ? node.commands : [];
@@ -8307,32 +8354,264 @@ async function persistProxyFiles(files) {
8307
8354
  function applyProxyPaths(result, mapping) {
8308
8355
  applyBrowserProxyPaths(result, mapping);
8309
8356
  }
8310
- const browserHandlers = { "browser.request": async ({ params, respond, context }) => {
8311
- const typed = params;
8312
- const methodRaw = typeof typed.method === "string" ? typed.method.trim().toUpperCase() : "";
8313
- const path = typeof typed.path === "string" ? typed.path.trim() : "";
8314
- const query = typed.query && typeof typed.query === "object" ? typed.query : void 0;
8315
- const body = typed.body;
8316
- const timeoutMs = typeof typed.timeoutMs === "number" && Number.isFinite(typed.timeoutMs) ? Math.max(1, Math.floor(typed.timeoutMs)) : void 0;
8317
- if (!methodRaw || !path) {
8318
- respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "method and path are required"));
8319
- return;
8357
+ function toNodeSummary(node) {
8358
+ return {
8359
+ nodeId: node.nodeId,
8360
+ displayName: node.displayName ?? null,
8361
+ remoteIp: node.remoteIp ?? null
8362
+ };
8363
+ }
8364
+ function hasValue(value) {
8365
+ return typeof value === "string" && value.trim().length > 0;
8366
+ }
8367
+ function resolveGatewayAuthMode(cfg) {
8368
+ const configuredMode = cfg.gateway?.auth?.mode;
8369
+ if (configuredMode === "token" || configuredMode === "password" || configuredMode === "trusted-proxy") return configuredMode;
8370
+ if (hasValue(cfg.gateway?.auth?.token)) return "token";
8371
+ if (hasValue(cfg.gateway?.auth?.password)) return "password";
8372
+ if (hasValue(cfg.gateway?.auth?.trustedProxy?.userHeader)) return "trusted-proxy";
8373
+ return "none";
8374
+ }
8375
+ function resolveClientActor(client) {
8376
+ const displayName = client?.connect?.client?.displayName;
8377
+ if (typeof displayName === "string" && displayName.trim().length > 0) return displayName.trim();
8378
+ const clientId = client?.connect?.client?.id;
8379
+ if (typeof clientId === "string" && clientId.trim().length > 0) return clientId.trim();
8380
+ const deviceId = client?.connect?.device?.id;
8381
+ if (typeof deviceId === "string" && deviceId.trim().length > 0) return deviceId.trim();
8382
+ return null;
8383
+ }
8384
+ function hasOperatorScope(client, scope) {
8385
+ const scopes = Array.isArray(client?.connect?.scopes) ? client?.connect?.scopes : [];
8386
+ return scopes.includes("operator.admin") || scopes.includes(scope);
8387
+ }
8388
+ function normalizeDesktopSessionTtl(input) {
8389
+ if (typeof input !== "number" || !Number.isFinite(input)) return DESKTOP_CONTROL_DEFAULT_TTL_MS;
8390
+ return Math.min(DESKTOP_CONTROL_MAX_TTL_MS, Math.max(DESKTOP_CONTROL_MIN_TTL_MS, Math.floor(input)));
8391
+ }
8392
+ function normalizeDesktopSessionReason(input) {
8393
+ if (typeof input !== "string") return "Desktop control session";
8394
+ const trimmed = input.trim();
8395
+ if (!trimmed) return "Desktop control session";
8396
+ return trimmed.slice(0, DESKTOP_CONTROL_MAX_REASON_LEN);
8397
+ }
8398
+ function normalizeDesktopSessionNote(input) {
8399
+ if (typeof input !== "string") return null;
8400
+ const trimmed = input.trim();
8401
+ if (!trimmed) return null;
8402
+ return trimmed.slice(0, DESKTOP_CONTROL_MAX_NOTE_LEN);
8403
+ }
8404
+ function hasDecisionRationale(note) {
8405
+ return typeof note === "string" && note.length >= DESKTOP_CONTROL_MIN_DECISION_NOTE_LEN;
8406
+ }
8407
+ function isDesktopControlSessionState(value) {
8408
+ return typeof value === "string" && DESKTOP_CONTROL_SESSION_STATES.includes(value);
8409
+ }
8410
+ function isDesktopControlApprovalDecision(value) {
8411
+ return typeof value === "string" && DESKTOP_CONTROL_SESSION_DECISIONS.includes(value);
8412
+ }
8413
+ function isDesktopControlSessionRouteKind(value) {
8414
+ return typeof value === "string" && DESKTOP_CONTROL_SESSION_ROUTE_KINDS.includes(value);
8415
+ }
8416
+ function isDesktopControlSessionRiskLevel(value) {
8417
+ return typeof value === "string" && DESKTOP_CONTROL_SESSION_RISK_LEVELS.includes(value);
8418
+ }
8419
+ function parseDesktopSessionMethod(value) {
8420
+ const method = value.trim().toUpperCase();
8421
+ if (DESKTOP_CONTROL_ALLOWED_METHODS.includes(method)) return method;
8422
+ return null;
8423
+ }
8424
+ function normalizeDesktopSessionAllowMethods(input) {
8425
+ if (!Array.isArray(input)) return [...DESKTOP_CONTROL_DEFAULT_ALLOWED_METHODS];
8426
+ const normalized = [];
8427
+ for (const entry of input) {
8428
+ if (typeof entry !== "string") continue;
8429
+ const method = parseDesktopSessionMethod(entry);
8430
+ if (method && !normalized.includes(method)) normalized.push(method);
8320
8431
  }
8321
- if (methodRaw !== "GET" && methodRaw !== "POST" && methodRaw !== "DELETE") {
8322
- respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "method must be GET, POST, or DELETE"));
8323
- return;
8432
+ if (normalized.length === 0) return [...DESKTOP_CONTROL_DEFAULT_ALLOWED_METHODS];
8433
+ return normalized;
8434
+ }
8435
+ function normalizeDesktopSessionMaxRequests(input) {
8436
+ if (typeof input !== "number" || !Number.isFinite(input)) return DESKTOP_CONTROL_DEFAULT_MAX_REQUESTS;
8437
+ return Math.min(DESKTOP_CONTROL_MAX_MAX_REQUESTS, Math.max(DESKTOP_CONTROL_MIN_MAX_REQUESTS, Math.floor(input)));
8438
+ }
8439
+ function resolveDesktopSessionRisk(controls) {
8440
+ const reasons = [];
8441
+ if (controls.allowMethods.some((method) => method !== "GET")) reasons.push("write methods enabled (POST/DELETE)");
8442
+ if (controls.maxRequests > DESKTOP_CONTROL_DEFAULT_MAX_REQUESTS) reasons.push(`request budget exceeds standard (${controls.maxRequests} > ${DESKTOP_CONTROL_DEFAULT_MAX_REQUESTS})`);
8443
+ return {
8444
+ level: reasons.length > 0 ? "elevated" : "standard",
8445
+ reasons
8446
+ };
8447
+ }
8448
+ function validateDesktopControlSessionCreateParams(params) {
8449
+ if (params.reason !== void 0 && typeof params.reason !== "string") return errorShape(ErrorCodes.INVALID_REQUEST, `invalid reason: ${String(params.reason)}`, { details: { expectedType: "string" } });
8450
+ if (params.ttlMs !== void 0) {
8451
+ if (typeof params.ttlMs !== "number" || !Number.isFinite(params.ttlMs) || !Number.isInteger(params.ttlMs) || params.ttlMs < DESKTOP_CONTROL_MIN_TTL_MS || params.ttlMs > DESKTOP_CONTROL_MAX_TTL_MS) return errorShape(ErrorCodes.INVALID_REQUEST, `invalid ttlMs: ${String(params.ttlMs)}`, { details: {
8452
+ minTtlMs: DESKTOP_CONTROL_MIN_TTL_MS,
8453
+ maxTtlMs: DESKTOP_CONTROL_MAX_TTL_MS
8454
+ } });
8324
8455
  }
8325
- const cfg = loadConfig();
8326
- let nodeTarget = null;
8327
- try {
8328
- nodeTarget = resolveBrowserNodeTarget({
8329
- cfg,
8330
- nodes: context.nodeRegistry.listConnected()
8456
+ if (params.nodeId !== void 0 && typeof params.nodeId !== "string") return errorShape(ErrorCodes.INVALID_REQUEST, `invalid nodeId: ${String(params.nodeId)}`, { details: { expectedType: "string" } });
8457
+ if (typeof params.nodeId === "string" && !params.nodeId.trim()) return errorShape(ErrorCodes.INVALID_REQUEST, "invalid nodeId: must not be empty");
8458
+ if (params.allowMethods !== void 0) {
8459
+ if (!Array.isArray(params.allowMethods)) return errorShape(ErrorCodes.INVALID_REQUEST, `invalid allowMethods: ${String(params.allowMethods)}`, { details: {
8460
+ expectedType: "string[]",
8461
+ allowedMethods: DESKTOP_CONTROL_ALLOWED_METHODS
8462
+ } });
8463
+ if (params.allowMethods.length === 0) return errorShape(ErrorCodes.INVALID_REQUEST, "allowMethods must include at least one method", { details: { allowedMethods: DESKTOP_CONTROL_ALLOWED_METHODS } });
8464
+ for (let i = 0; i < params.allowMethods.length; i += 1) {
8465
+ const entry = params.allowMethods[i];
8466
+ if (typeof entry !== "string") return errorShape(ErrorCodes.INVALID_REQUEST, `invalid allowMethods[${i}]: ${String(entry)}`, { details: {
8467
+ expectedType: "string",
8468
+ allowedMethods: DESKTOP_CONTROL_ALLOWED_METHODS
8469
+ } });
8470
+ if (!parseDesktopSessionMethod(entry)) return errorShape(ErrorCodes.INVALID_REQUEST, `invalid allowMethods[${i}]: ${entry.trim() || "<empty>"}`, { details: { allowedMethods: DESKTOP_CONTROL_ALLOWED_METHODS } });
8471
+ }
8472
+ }
8473
+ if (params.maxRequests !== void 0) {
8474
+ if (typeof params.maxRequests !== "number" || !Number.isFinite(params.maxRequests) || !Number.isInteger(params.maxRequests) || params.maxRequests < DESKTOP_CONTROL_MIN_MAX_REQUESTS || params.maxRequests > DESKTOP_CONTROL_MAX_MAX_REQUESTS) return errorShape(ErrorCodes.INVALID_REQUEST, `invalid maxRequests: ${String(params.maxRequests)}`, { details: {
8475
+ minMaxRequests: DESKTOP_CONTROL_MIN_MAX_REQUESTS,
8476
+ maxMaxRequests: DESKTOP_CONTROL_MAX_MAX_REQUESTS
8477
+ } });
8478
+ }
8479
+ return null;
8480
+ }
8481
+ function appendDesktopControlAudit(session, event) {
8482
+ const next = {
8483
+ id: crypto.randomUUID(),
8484
+ ts: typeof event.ts === "number" && Number.isFinite(event.ts) ? event.ts : Date.now(),
8485
+ type: event.type,
8486
+ actor: event.actor,
8487
+ details: event.details
8488
+ };
8489
+ session.audit.push(next);
8490
+ if (session.audit.length > DESKTOP_CONTROL_AUDIT_MAX_EVENTS) session.audit.splice(0, session.audit.length - DESKTOP_CONTROL_AUDIT_MAX_EVENTS);
8491
+ }
8492
+ function toDesktopControlSessionSnapshot(session, includeAudit = false) {
8493
+ return {
8494
+ id: session.id,
8495
+ reason: session.reason,
8496
+ createdAtMs: session.createdAtMs,
8497
+ expiresAtMs: session.expiresAtMs,
8498
+ state: session.state,
8499
+ route: session.route.kind === "node" ? {
8500
+ kind: "node",
8501
+ node: { ...session.route.node }
8502
+ } : session.route,
8503
+ approval: { ...session.approval },
8504
+ controls: {
8505
+ allowMethods: [...session.controls.allowMethods],
8506
+ maxRequests: session.controls.maxRequests
8507
+ },
8508
+ risk: {
8509
+ level: session.risk.level,
8510
+ reasons: [...session.risk.reasons]
8511
+ },
8512
+ requestCount: session.requestCount,
8513
+ lastRequestAtMs: session.lastRequestAtMs,
8514
+ closedAtMs: session.closedAtMs,
8515
+ audit: includeAudit ? session.audit.map((entry) => ({ ...entry })) : void 0
8516
+ };
8517
+ }
8518
+ function broadcastDesktopControlSessionEvent(params) {
8519
+ const latestAudit = params.session.audit[params.session.audit.length - 1];
8520
+ params.context.broadcast("desktop.control.session.updated", {
8521
+ ts: Date.now(),
8522
+ action: params.action,
8523
+ actor: params.actor,
8524
+ details: params.details,
8525
+ session: toDesktopControlSessionSnapshot(params.session, false),
8526
+ latestAudit: latestAudit ? { ...latestAudit } : null
8527
+ }, { dropIfSlow: true });
8528
+ }
8529
+ function pruneDesktopControlSessions(params) {
8530
+ const now = params?.now ?? Date.now();
8531
+ const context = params?.context;
8532
+ for (const session of desktopControlSessions.values()) if ((session.state === "pending_approval" || session.state === "active") && session.expiresAtMs <= now) {
8533
+ session.state = "expired";
8534
+ session.closedAtMs = now;
8535
+ appendDesktopControlAudit(session, {
8536
+ type: "session.expired",
8537
+ actor: "system"
8538
+ });
8539
+ if (context) broadcastDesktopControlSessionEvent({
8540
+ context,
8541
+ action: "expired",
8542
+ session,
8543
+ actor: "system"
8331
8544
  });
8332
- } catch (err) {
8333
- respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(err)));
8334
- return;
8335
8545
  }
8546
+ for (const [id, session] of desktopControlSessions.entries()) if ((session.state === "closed" || session.state === "denied" || session.state === "expired") && session.closedAtMs && now - session.closedAtMs > DESKTOP_CONTROL_RETENTION_MS) desktopControlSessions.delete(id);
8547
+ }
8548
+ function normalizeBrowserRequest(params) {
8549
+ const methodRaw = typeof params.method === "string" ? params.method.trim().toUpperCase() : "";
8550
+ const path = typeof params.path === "string" ? params.path.trim() : "";
8551
+ const queryRaw = params.query;
8552
+ const body = params.body;
8553
+ const timeoutRaw = params.timeoutMs;
8554
+ if (!methodRaw || !path) return {
8555
+ ok: false,
8556
+ error: errorShape(ErrorCodes.INVALID_REQUEST, "method and path are required")
8557
+ };
8558
+ if (methodRaw !== "GET" && methodRaw !== "POST" && methodRaw !== "DELETE") return {
8559
+ ok: false,
8560
+ error: errorShape(ErrorCodes.INVALID_REQUEST, "method must be GET, POST, or DELETE")
8561
+ };
8562
+ if (!path.startsWith("/")) return {
8563
+ ok: false,
8564
+ error: errorShape(ErrorCodes.INVALID_REQUEST, "path must start with /")
8565
+ };
8566
+ if (queryRaw !== void 0) {
8567
+ if (!isPlainObjectRecord(queryRaw)) return {
8568
+ ok: false,
8569
+ error: errorShape(ErrorCodes.INVALID_REQUEST, `invalid query: ${String(queryRaw)}`, { details: { expectedType: "object" } })
8570
+ };
8571
+ const queryIssue = findFirstJsonSerializationIssue(queryRaw, "query");
8572
+ if (queryIssue) return {
8573
+ ok: false,
8574
+ error: errorShape(ErrorCodes.INVALID_REQUEST, `invalid query: non-json-serializable value at ${queryIssue.path}`, { details: {
8575
+ expectedType: "json-serializable",
8576
+ actualType: queryIssue.actualType,
8577
+ path: queryIssue.path
8578
+ } })
8579
+ };
8580
+ }
8581
+ if (body !== void 0) {
8582
+ const bodyIssue = findFirstJsonSerializationIssue(body, "body");
8583
+ if (bodyIssue) return {
8584
+ ok: false,
8585
+ error: errorShape(ErrorCodes.INVALID_REQUEST, `invalid body: non-json-serializable value at ${bodyIssue.path}`, { details: {
8586
+ expectedType: "json-serializable",
8587
+ actualType: bodyIssue.actualType,
8588
+ path: bodyIssue.path
8589
+ } })
8590
+ };
8591
+ }
8592
+ if (timeoutRaw !== void 0) {
8593
+ if (typeof timeoutRaw !== "number" || !Number.isFinite(timeoutRaw) || !Number.isInteger(timeoutRaw) || timeoutRaw < BROWSER_REQUEST_MIN_TIMEOUT_MS || timeoutRaw > BROWSER_REQUEST_MAX_TIMEOUT_MS) return {
8594
+ ok: false,
8595
+ error: errorShape(ErrorCodes.INVALID_REQUEST, `invalid timeoutMs: ${String(timeoutRaw)}`, { details: {
8596
+ expectedType: "integer",
8597
+ minTimeoutMs: BROWSER_REQUEST_MIN_TIMEOUT_MS,
8598
+ maxTimeoutMs: BROWSER_REQUEST_MAX_TIMEOUT_MS
8599
+ } })
8600
+ };
8601
+ }
8602
+ return {
8603
+ ok: true,
8604
+ request: {
8605
+ methodRaw,
8606
+ path,
8607
+ query: queryRaw,
8608
+ body,
8609
+ timeoutMs: typeof timeoutRaw === "number" ? Math.floor(timeoutRaw) : void 0
8610
+ }
8611
+ };
8612
+ }
8613
+ async function dispatchBrowserRequest(params) {
8614
+ const { cfg, request, context, nodeTarget } = params;
8336
8615
  if (nodeTarget) {
8337
8616
  const allowlist = resolveNodeCommandAllowlist(cfg, nodeTarget);
8338
8617
  const allowed = isNodeCommandAllowed({
@@ -8340,67 +8619,1025 @@ const browserHandlers = { "browser.request": async ({ params, respond, context }
8340
8619
  declaredCommands: nodeTarget.commands,
8341
8620
  allowlist
8342
8621
  });
8343
- if (!allowed.ok) {
8344
- respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "node command not allowed", { details: {
8622
+ if (!allowed.ok) return {
8623
+ ok: false,
8624
+ route: "node",
8625
+ nodeId: nodeTarget.nodeId,
8626
+ status: 403,
8627
+ error: errorShape(ErrorCodes.INVALID_REQUEST, "node command not allowed", { details: {
8345
8628
  reason: allowed.reason,
8346
8629
  command: "browser.proxy"
8347
- } }));
8348
- return;
8349
- }
8630
+ } })
8631
+ };
8350
8632
  const proxyParams = {
8351
- method: methodRaw,
8352
- path,
8353
- query,
8354
- body,
8355
- timeoutMs,
8356
- profile: typeof query?.profile === "string" ? query.profile : void 0
8633
+ method: request.methodRaw,
8634
+ path: request.path,
8635
+ query: request.query,
8636
+ body: request.body,
8637
+ timeoutMs: request.timeoutMs,
8638
+ profile: typeof request.query?.profile === "string" ? request.query.profile : void 0
8357
8639
  };
8358
8640
  const res = await context.nodeRegistry.invoke({
8359
8641
  nodeId: nodeTarget.nodeId,
8360
8642
  command: "browser.proxy",
8361
8643
  params: proxyParams,
8362
- timeoutMs,
8644
+ timeoutMs: request.timeoutMs,
8363
8645
  idempotencyKey: crypto.randomUUID()
8364
8646
  });
8365
- if (!res.ok) {
8366
- respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, res.error?.message ?? "node invoke failed", { details: { nodeError: res.error ?? null } }));
8367
- return;
8368
- }
8647
+ if (!res.ok) return {
8648
+ ok: false,
8649
+ route: "node",
8650
+ nodeId: nodeTarget.nodeId,
8651
+ status: 503,
8652
+ error: errorShape(ErrorCodes.UNAVAILABLE, res.error?.message ?? "node invoke failed", { details: { nodeError: res.error ?? null } })
8653
+ };
8369
8654
  const payload = res.payloadJSON ? safeParseJson(res.payloadJSON) : res.payload;
8370
8655
  const proxy = payload && typeof payload === "object" ? payload : null;
8371
- if (!proxy || !("result" in proxy)) {
8372
- respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, "browser proxy failed"));
8373
- return;
8374
- }
8656
+ if (!proxy || !("result" in proxy)) return {
8657
+ ok: false,
8658
+ route: "node",
8659
+ nodeId: nodeTarget.nodeId,
8660
+ status: 503,
8661
+ error: errorShape(ErrorCodes.UNAVAILABLE, "browser proxy failed")
8662
+ };
8375
8663
  const mapping = await persistProxyFiles(proxy.files);
8376
8664
  applyProxyPaths(proxy.result, mapping);
8377
- respond(true, proxy.result);
8378
- return;
8379
- }
8380
- if (!await startBrowserControlServiceFromConfig()) {
8381
- respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, "browser control is disabled"));
8382
- return;
8665
+ return {
8666
+ ok: true,
8667
+ route: "node",
8668
+ nodeId: nodeTarget.nodeId,
8669
+ status: 200,
8670
+ payload: proxy.result
8671
+ };
8383
8672
  }
8673
+ if (!await startBrowserControlServiceFromConfig()) return {
8674
+ ok: false,
8675
+ route: "local",
8676
+ nodeId: null,
8677
+ status: 503,
8678
+ error: errorShape(ErrorCodes.UNAVAILABLE, "browser control is disabled")
8679
+ };
8384
8680
  let dispatcher;
8385
8681
  try {
8386
8682
  dispatcher = createBrowserRouteDispatcher(createBrowserControlContext());
8387
8683
  } catch (err) {
8388
- respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(err)));
8389
- return;
8684
+ return {
8685
+ ok: false,
8686
+ route: "local",
8687
+ nodeId: null,
8688
+ status: 503,
8689
+ error: errorShape(ErrorCodes.UNAVAILABLE, String(err))
8690
+ };
8390
8691
  }
8391
8692
  const result = await dispatcher.dispatch({
8392
- method: methodRaw,
8393
- path,
8394
- query,
8395
- body
8693
+ method: request.methodRaw,
8694
+ path: request.path,
8695
+ query: request.query,
8696
+ body: request.body
8396
8697
  });
8397
8698
  if (result.status >= 400) {
8398
8699
  const message = result.body && typeof result.body === "object" && "error" in result.body ? String(result.body.error) : `browser request failed (${result.status})`;
8399
- respond(false, void 0, errorShape(result.status >= 500 ? ErrorCodes.UNAVAILABLE : ErrorCodes.INVALID_REQUEST, message, { details: result.body }));
8400
- return;
8700
+ const code = result.status >= 500 ? ErrorCodes.UNAVAILABLE : ErrorCodes.INVALID_REQUEST;
8701
+ return {
8702
+ ok: false,
8703
+ route: "local",
8704
+ nodeId: null,
8705
+ status: result.status,
8706
+ error: errorShape(code, message, { details: result.body })
8707
+ };
8708
+ }
8709
+ return {
8710
+ ok: true,
8711
+ route: "local",
8712
+ nodeId: null,
8713
+ status: result.status,
8714
+ payload: result.body
8715
+ };
8716
+ }
8717
+ function resolveDesktopSessionNodeTarget(params) {
8718
+ if (params.session.route.kind !== "node") return null;
8719
+ return params.nodes.find((node) => node.nodeId === params.session.route.node.nodeId && isBrowserNode(node)) ?? null;
8720
+ }
8721
+ function ensureDesktopSessionExists(idRaw) {
8722
+ if (idRaw !== void 0 && typeof idRaw !== "string") return {
8723
+ ok: false,
8724
+ error: errorShape(ErrorCodes.INVALID_REQUEST, `invalid id: ${String(idRaw)}`, { details: { expectedType: "string" } })
8725
+ };
8726
+ const id = typeof idRaw === "string" ? idRaw.trim() : "";
8727
+ if (!id) return {
8728
+ ok: false,
8729
+ error: errorShape(ErrorCodes.INVALID_REQUEST, "id is required")
8730
+ };
8731
+ const session = desktopControlSessions.get(id);
8732
+ if (!session) return {
8733
+ ok: false,
8734
+ error: errorShape(ErrorCodes.INVALID_REQUEST, "unknown desktop control session id")
8735
+ };
8736
+ return {
8737
+ ok: true,
8738
+ session
8739
+ };
8740
+ }
8741
+ function toParamValueType(value) {
8742
+ if (value === null) return "null";
8743
+ if (Array.isArray(value)) return "array";
8744
+ return typeof value;
8745
+ }
8746
+ function isPlainObjectRecord(value) {
8747
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
8748
+ const proto = Object.getPrototypeOf(value);
8749
+ return proto === Object.prototype || proto === null;
8750
+ }
8751
+ function appendJsonPath(basePath, segment) {
8752
+ if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(segment)) return `${basePath}.${segment}`;
8753
+ return `${basePath}[${JSON.stringify(segment)}]`;
8754
+ }
8755
+ function findFirstJsonSerializationIssue(value, path, seen = /* @__PURE__ */ new Set()) {
8756
+ if (value === null) return null;
8757
+ const valueType = typeof value;
8758
+ if (valueType === "number") {
8759
+ if (!Number.isFinite(value)) return {
8760
+ path,
8761
+ actualType: "number(non-finite)"
8762
+ };
8763
+ return null;
8764
+ }
8765
+ if (valueType === "string" || valueType === "boolean") return null;
8766
+ if (valueType === "undefined" || valueType === "function" || valueType === "symbol" || valueType === "bigint") return {
8767
+ path,
8768
+ actualType: valueType
8769
+ };
8770
+ if (Array.isArray(value)) {
8771
+ if (seen.has(value)) return {
8772
+ path,
8773
+ actualType: "circular"
8774
+ };
8775
+ seen.add(value);
8776
+ for (let i = 0; i < value.length; i += 1) {
8777
+ const nestedIssue = findFirstJsonSerializationIssue(value[i], `${path}[${i}]`, seen);
8778
+ if (nestedIssue) {
8779
+ seen.delete(value);
8780
+ return nestedIssue;
8781
+ }
8782
+ }
8783
+ seen.delete(value);
8784
+ return null;
8785
+ }
8786
+ if (!value || typeof value !== "object") return {
8787
+ path,
8788
+ actualType: valueType
8789
+ };
8790
+ if (!isPlainObjectRecord(value)) return {
8791
+ path,
8792
+ actualType: toParamValueType(value)
8793
+ };
8794
+ if (seen.has(value)) return {
8795
+ path,
8796
+ actualType: "circular"
8797
+ };
8798
+ seen.add(value);
8799
+ for (const [key, entry] of Object.entries(value)) {
8800
+ const nestedIssue = findFirstJsonSerializationIssue(entry, appendJsonPath(path, key), seen);
8801
+ if (nestedIssue) {
8802
+ seen.delete(value);
8803
+ return nestedIssue;
8804
+ }
8805
+ }
8806
+ seen.delete(value);
8807
+ return null;
8808
+ }
8809
+ function normalizeObjectParams(params) {
8810
+ if (params === void 0 || params === null) return {
8811
+ ok: true,
8812
+ value: {}
8813
+ };
8814
+ if (!isPlainObjectRecord(params)) return {
8815
+ ok: false,
8816
+ error: errorShape(ErrorCodes.INVALID_REQUEST, "invalid params: expected object", { details: {
8817
+ expectedType: "object",
8818
+ actualType: toParamValueType(params)
8819
+ } })
8820
+ };
8821
+ return {
8822
+ ok: true,
8823
+ value: params
8824
+ };
8825
+ }
8826
+ function buildBrowserCapabilitiesSnapshot(params) {
8827
+ const browserEnabled = params.cfg.browser?.enabled !== false;
8828
+ const evaluateEnabled = browserEnabled && params.cfg.browser?.evaluateEnabled !== false;
8829
+ const mode = params.cfg.gateway?.nodes?.browser?.mode ?? "auto";
8830
+ const pinnedNode = hasValue(params.cfg.gateway?.nodes?.browser?.node) ? String(params.cfg.gateway?.nodes?.browser?.node).trim() : null;
8831
+ const availableNodes = params.nodes.filter((node) => isBrowserNode(node)).map(toNodeSummary);
8832
+ const authMode = resolveGatewayAuthMode(params.cfg);
8833
+ const authConfigured = hasValue(params.cfg.gateway?.auth?.token) || hasValue(params.cfg.gateway?.auth?.password) || authMode === "trusted-proxy";
8834
+ let selectedNode = null;
8835
+ let routingError = null;
8836
+ try {
8837
+ selectedNode = resolveBrowserNodeTarget(params);
8838
+ } catch (error) {
8839
+ routingError = String(error);
8840
+ }
8841
+ const activeRoute = !browserEnabled || mode === "off" ? "disabled" : routingError ? "error" : selectedNode ? "node" : "local";
8842
+ const warnings = [];
8843
+ if (browserEnabled && !authConfigured) warnings.push("Browser control is enabled without gateway auth. Configure gateway.auth.token or gateway.auth.password.");
8844
+ if (mode === "manual" && !pinnedNode) warnings.push("Browser node routing is set to manual but no gateway.nodes.browser.node is pinned; routing will fall back to local browser control.");
8845
+ if (availableNodes.length > 1 && mode === "auto" && !pinnedNode && !selectedNode) warnings.push("Multiple browser-capable nodes are connected; set gateway.nodes.browser.node to pin a target.");
8846
+ if (routingError) warnings.push(routingError);
8847
+ return {
8848
+ browserEnabled,
8849
+ evaluateEnabled,
8850
+ auth: {
8851
+ configured: authConfigured,
8852
+ mode: authMode
8853
+ },
8854
+ routing: {
8855
+ mode,
8856
+ pinnedNode,
8857
+ activeRoute,
8858
+ selectedNode: selectedNode ? toNodeSummary(selectedNode) : null,
8859
+ availableNodes,
8860
+ error: routingError
8861
+ },
8862
+ warnings
8863
+ };
8864
+ }
8865
+ const browserHandlers = {
8866
+ "browser.capabilities.get": async ({ respond, context }) => {
8867
+ try {
8868
+ respond(true, buildBrowserCapabilitiesSnapshot({
8869
+ cfg: loadConfig(),
8870
+ nodes: context.nodeRegistry.listConnected()
8871
+ }));
8872
+ } catch (error) {
8873
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
8874
+ }
8875
+ },
8876
+ "browser.request": async ({ params, respond, context }) => {
8877
+ const normalized = normalizeBrowserRequest(params);
8878
+ if (!normalized.ok) {
8879
+ respond(false, void 0, normalized.error);
8880
+ return;
8881
+ }
8882
+ const cfg = loadConfig();
8883
+ let nodeTarget = null;
8884
+ try {
8885
+ nodeTarget = resolveBrowserNodeTarget({
8886
+ cfg,
8887
+ nodes: context.nodeRegistry.listConnected()
8888
+ });
8889
+ } catch (err) {
8890
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(err)));
8891
+ return;
8892
+ }
8893
+ const result = await dispatchBrowserRequest({
8894
+ cfg,
8895
+ request: normalized.request,
8896
+ context,
8897
+ nodeTarget
8898
+ });
8899
+ if (!result.ok) {
8900
+ respond(false, void 0, result.error);
8901
+ return;
8902
+ }
8903
+ respond(true, result.payload);
8904
+ },
8905
+ "desktop.control.session.create": async ({ params, respond, context, client }) => {
8906
+ pruneDesktopControlSessions({ context });
8907
+ if (!hasOperatorScope(client, "operator.write")) {
8908
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "missing scope: operator.write"));
8909
+ return;
8910
+ }
8911
+ const normalizedParams = normalizeObjectParams(params);
8912
+ if (!normalizedParams.ok) {
8913
+ respond(false, void 0, normalizedParams.error);
8914
+ return;
8915
+ }
8916
+ const typed = normalizedParams.value;
8917
+ const createValidationError = validateDesktopControlSessionCreateParams(typed);
8918
+ if (createValidationError) {
8919
+ respond(false, void 0, createValidationError);
8920
+ return;
8921
+ }
8922
+ const cfg = loadConfig();
8923
+ const connectedNodes = context.nodeRegistry.listConnected();
8924
+ const browserNodes = connectedNodes.filter((node) => isBrowserNode(node));
8925
+ const requestedNodeId = typeof typed.nodeId === "string" ? typed.nodeId.trim() : "";
8926
+ const reason = normalizeDesktopSessionReason(typed.reason);
8927
+ const ttlMs = normalizeDesktopSessionTtl(typed.ttlMs);
8928
+ const allowMethods = normalizeDesktopSessionAllowMethods(typed.allowMethods);
8929
+ const maxRequests = normalizeDesktopSessionMaxRequests(typed.maxRequests);
8930
+ const risk = resolveDesktopSessionRisk({
8931
+ allowMethods,
8932
+ maxRequests
8933
+ });
8934
+ const now = Date.now();
8935
+ const actor = resolveClientActor(client);
8936
+ const snapshot = buildBrowserCapabilitiesSnapshot({
8937
+ cfg,
8938
+ nodes: connectedNodes
8939
+ });
8940
+ if (!snapshot.browserEnabled || snapshot.routing.mode === "off") {
8941
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, "browser control is disabled"));
8942
+ return;
8943
+ }
8944
+ let routeNode = null;
8945
+ try {
8946
+ if (requestedNodeId) {
8947
+ routeNode = resolveBrowserNode(browserNodes, requestedNodeId);
8948
+ if (!routeNode) {
8949
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `requested browser node is not connected: ${requestedNodeId}`));
8950
+ return;
8951
+ }
8952
+ } else routeNode = resolveBrowserNodeTarget({
8953
+ cfg,
8954
+ nodes: connectedNodes
8955
+ });
8956
+ } catch (error) {
8957
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
8958
+ return;
8959
+ }
8960
+ const id = crypto.randomUUID();
8961
+ const session = {
8962
+ id,
8963
+ reason,
8964
+ createdAtMs: now,
8965
+ expiresAtMs: now + ttlMs,
8966
+ state: "pending_approval",
8967
+ route: routeNode ? {
8968
+ kind: "node",
8969
+ node: toNodeSummary(routeNode)
8970
+ } : {
8971
+ kind: "local",
8972
+ node: null
8973
+ },
8974
+ approval: {
8975
+ required: true,
8976
+ decision: "pending",
8977
+ requestedAtMs: now,
8978
+ requestedBy: actor,
8979
+ decidedAtMs: null,
8980
+ decidedBy: null,
8981
+ note: null
8982
+ },
8983
+ controls: {
8984
+ allowMethods,
8985
+ maxRequests
8986
+ },
8987
+ risk,
8988
+ requestCount: 0,
8989
+ inFlightRequestCount: 0,
8990
+ lastRequestAtMs: null,
8991
+ closedAtMs: null,
8992
+ audit: []
8993
+ };
8994
+ appendDesktopControlAudit(session, {
8995
+ type: "session.created",
8996
+ actor,
8997
+ details: {
8998
+ reason: session.reason,
8999
+ route: session.route.kind,
9000
+ nodeId: session.route.kind === "node" ? session.route.node.nodeId : null,
9001
+ expiresAtMs: session.expiresAtMs,
9002
+ allowMethods: session.controls.allowMethods,
9003
+ maxRequests: session.controls.maxRequests,
9004
+ riskLevel: session.risk.level,
9005
+ riskReasons: session.risk.reasons
9006
+ }
9007
+ });
9008
+ desktopControlSessions.set(id, session);
9009
+ broadcastDesktopControlSessionEvent({
9010
+ context,
9011
+ action: "created",
9012
+ session,
9013
+ actor
9014
+ });
9015
+ respond(true, toDesktopControlSessionSnapshot(session, true));
9016
+ },
9017
+ "desktop.control.session.list": async ({ params, respond, context, client }) => {
9018
+ pruneDesktopControlSessions({ context });
9019
+ if (!hasOperatorScope(client, "operator.read")) {
9020
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "missing scope: operator.read"));
9021
+ return;
9022
+ }
9023
+ const normalizedParams = normalizeObjectParams(params);
9024
+ if (!normalizedParams.ok) {
9025
+ respond(false, void 0, normalizedParams.error);
9026
+ return;
9027
+ }
9028
+ const typed = normalizedParams.value;
9029
+ const includeAuditRaw = typed.includeAudit;
9030
+ if (includeAuditRaw !== void 0 && typeof includeAuditRaw !== "boolean") {
9031
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid includeAudit filter: ${String(includeAuditRaw)}`, { details: { expectedType: "boolean" } }));
9032
+ return;
9033
+ }
9034
+ const includeAudit = includeAuditRaw === true;
9035
+ const stateInput = typed.state;
9036
+ if (stateInput !== void 0 && typeof stateInput !== "string") {
9037
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid state filter: ${String(stateInput)}`, { details: { allowedStates: DESKTOP_CONTROL_SESSION_STATES } }));
9038
+ return;
9039
+ }
9040
+ const stateRawInput = typeof stateInput === "string" ? stateInput.trim() : "";
9041
+ const stateRaw = stateRawInput ? stateRawInput.toLowerCase() : "";
9042
+ if (stateRaw && !isDesktopControlSessionState(stateRaw)) {
9043
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid state filter: ${stateRawInput}`, { details: { allowedStates: DESKTOP_CONTROL_SESSION_STATES } }));
9044
+ return;
9045
+ }
9046
+ const decisionInput = typed.decision;
9047
+ if (decisionInput !== void 0 && typeof decisionInput !== "string") {
9048
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid decision filter: ${String(decisionInput)}`, { details: { allowedDecisions: DESKTOP_CONTROL_SESSION_DECISIONS } }));
9049
+ return;
9050
+ }
9051
+ const decisionRawInput = typeof decisionInput === "string" ? decisionInput.trim() : "";
9052
+ const decisionRaw = decisionRawInput ? decisionRawInput.toLowerCase() : "";
9053
+ if (decisionRaw && !isDesktopControlApprovalDecision(decisionRaw)) {
9054
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid decision filter: ${decisionRawInput}`, { details: { allowedDecisions: DESKTOP_CONTROL_SESSION_DECISIONS } }));
9055
+ return;
9056
+ }
9057
+ const routeInput = typed.route;
9058
+ if (routeInput !== void 0 && typeof routeInput !== "string") {
9059
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid route filter: ${String(routeInput)}`, { details: { allowedRouteKinds: DESKTOP_CONTROL_SESSION_ROUTE_KINDS } }));
9060
+ return;
9061
+ }
9062
+ const routeRawInput = typeof routeInput === "string" ? routeInput.trim() : "";
9063
+ const routeRaw = routeRawInput ? routeRawInput.toLowerCase() : "";
9064
+ if (routeRaw && !isDesktopControlSessionRouteKind(routeRaw)) {
9065
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid route filter: ${routeRawInput}`, { details: { allowedRouteKinds: DESKTOP_CONTROL_SESSION_ROUTE_KINDS } }));
9066
+ return;
9067
+ }
9068
+ const riskLevelInput = typed.riskLevel;
9069
+ if (riskLevelInput !== void 0 && typeof riskLevelInput !== "string") {
9070
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid riskLevel filter: ${String(riskLevelInput)}`, { details: { allowedRiskLevels: DESKTOP_CONTROL_SESSION_RISK_LEVELS } }));
9071
+ return;
9072
+ }
9073
+ const riskLevelRawInput = typeof riskLevelInput === "string" ? riskLevelInput.trim() : "";
9074
+ const riskLevelRaw = riskLevelRawInput ? riskLevelRawInput.toLowerCase() : "";
9075
+ if (riskLevelRaw && !isDesktopControlSessionRiskLevel(riskLevelRaw)) {
9076
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid riskLevel filter: ${riskLevelRawInput}`, { details: { allowedRiskLevels: DESKTOP_CONTROL_SESSION_RISK_LEVELS } }));
9077
+ return;
9078
+ }
9079
+ const nodeIdInput = typed.nodeId;
9080
+ if (nodeIdInput !== void 0 && typeof nodeIdInput !== "string") {
9081
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid nodeId filter: ${String(nodeIdInput)}`));
9082
+ return;
9083
+ }
9084
+ const nodeIdRawInput = typeof nodeIdInput === "string" ? nodeIdInput.trim() : "";
9085
+ const nodeIdFilterKey = nodeIdRawInput ? normalizeNodeKey(nodeIdRawInput) : "";
9086
+ if (nodeIdRawInput && !nodeIdFilterKey) {
9087
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid nodeId filter: ${nodeIdRawInput}`));
9088
+ return;
9089
+ }
9090
+ if (routeRaw === "local" && nodeIdRawInput) {
9091
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "nodeId filter requires route=node (or omit route to match node-routed sessions)"));
9092
+ return;
9093
+ }
9094
+ const limitRaw = typed.limit;
9095
+ if (limitRaw !== void 0) {
9096
+ if (typeof limitRaw !== "number" || !Number.isInteger(limitRaw) || limitRaw < DESKTOP_CONTROL_LIST_MIN_LIMIT || limitRaw > DESKTOP_CONTROL_LIST_MAX_LIMIT) {
9097
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid limit filter: ${String(limitRaw)}`, { details: {
9098
+ minLimit: DESKTOP_CONTROL_LIST_MIN_LIMIT,
9099
+ maxLimit: DESKTOP_CONTROL_LIST_MAX_LIMIT
9100
+ } }));
9101
+ return;
9102
+ }
9103
+ }
9104
+ const offsetRaw = typed.offset;
9105
+ if (offsetRaw !== void 0) {
9106
+ if (typeof offsetRaw !== "number" || !Number.isInteger(offsetRaw) || offsetRaw < DESKTOP_CONTROL_LIST_MIN_OFFSET || offsetRaw > DESKTOP_CONTROL_LIST_MAX_OFFSET) {
9107
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid offset filter: ${String(offsetRaw)}`, { details: {
9108
+ minOffset: DESKTOP_CONTROL_LIST_MIN_OFFSET,
9109
+ maxOffset: DESKTOP_CONTROL_LIST_MAX_OFFSET
9110
+ } }));
9111
+ return;
9112
+ }
9113
+ }
9114
+ const state = stateRaw || void 0;
9115
+ const decision = decisionRaw || void 0;
9116
+ const route = routeRaw || void 0;
9117
+ const riskLevel = riskLevelRaw || void 0;
9118
+ const nodeId = nodeIdFilterKey || void 0;
9119
+ const limit = typeof limitRaw === "number" ? limitRaw : void 0;
9120
+ const offset = typeof offsetRaw === "number" ? offsetRaw : 0;
9121
+ const filtered = Array.from(desktopControlSessions.values()).filter((entry) => {
9122
+ if (state && entry.state !== state) return false;
9123
+ if (decision && entry.approval.decision !== decision) return false;
9124
+ if (route && entry.route.kind !== route) return false;
9125
+ if (riskLevel && entry.risk.level !== riskLevel) return false;
9126
+ if (nodeId && (entry.route.kind !== "node" || normalizeNodeKey(entry.route.node.nodeId) !== nodeId)) return false;
9127
+ return true;
9128
+ }).toSorted((a, b) => b.createdAtMs - a.createdAtMs);
9129
+ const total = filtered.length;
9130
+ const sliceEnd = limit === void 0 ? void 0 : offset + limit;
9131
+ const sessions = filtered.slice(offset, sliceEnd).map((entry) => toDesktopControlSessionSnapshot(entry, includeAudit));
9132
+ const returned = sessions.length;
9133
+ const hasMore = offset + returned < total;
9134
+ respond(true, {
9135
+ ts: Date.now(),
9136
+ total,
9137
+ returned,
9138
+ offset,
9139
+ nextOffset: hasMore ? offset + returned : null,
9140
+ truncated: offset > 0 || hasMore,
9141
+ sessions
9142
+ });
9143
+ },
9144
+ "desktop.control.session.get": async ({ params, respond, context, client }) => {
9145
+ pruneDesktopControlSessions({ context });
9146
+ if (!hasOperatorScope(client, "operator.read")) {
9147
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "missing scope: operator.read"));
9148
+ return;
9149
+ }
9150
+ const normalizedParams = normalizeObjectParams(params);
9151
+ if (!normalizedParams.ok) {
9152
+ respond(false, void 0, normalizedParams.error);
9153
+ return;
9154
+ }
9155
+ const typed = normalizedParams.value;
9156
+ const includeAuditRaw = typed.includeAudit;
9157
+ if (includeAuditRaw !== void 0 && typeof includeAuditRaw !== "boolean") {
9158
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid includeAudit filter: ${String(includeAuditRaw)}`, { details: { expectedType: "boolean" } }));
9159
+ return;
9160
+ }
9161
+ const found = ensureDesktopSessionExists(typed.id);
9162
+ if (!found.ok) {
9163
+ respond(false, void 0, found.error);
9164
+ return;
9165
+ }
9166
+ respond(true, toDesktopControlSessionSnapshot(found.session, includeAuditRaw === true));
9167
+ },
9168
+ "desktop.control.session.approve": async ({ params, respond, client, context }) => {
9169
+ pruneDesktopControlSessions({ context });
9170
+ if (!hasOperatorScope(client, "operator.approvals")) {
9171
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "missing scope: operator.approvals"));
9172
+ return;
9173
+ }
9174
+ const normalizedParams = normalizeObjectParams(params);
9175
+ if (!normalizedParams.ok) {
9176
+ respond(false, void 0, normalizedParams.error);
9177
+ return;
9178
+ }
9179
+ const typed = normalizedParams.value;
9180
+ const found = ensureDesktopSessionExists(typed.id);
9181
+ if (!found.ok) {
9182
+ respond(false, void 0, found.error);
9183
+ return;
9184
+ }
9185
+ const session = found.session;
9186
+ if (session.state !== "pending_approval") {
9187
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `session is not pending approval (state: ${session.state})`, { details: {
9188
+ state: session.state,
9189
+ decision: session.approval.decision,
9190
+ expiresAtMs: session.expiresAtMs
9191
+ } }));
9192
+ return;
9193
+ }
9194
+ if (session.expiresAtMs <= Date.now()) {
9195
+ session.state = "expired";
9196
+ session.closedAtMs = Date.now();
9197
+ appendDesktopControlAudit(session, {
9198
+ type: "session.expired",
9199
+ actor: "system"
9200
+ });
9201
+ broadcastDesktopControlSessionEvent({
9202
+ context,
9203
+ action: "expired",
9204
+ session,
9205
+ actor: "system"
9206
+ });
9207
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "session has expired", { details: {
9208
+ state: session.state,
9209
+ decision: session.approval.decision,
9210
+ expiresAtMs: session.expiresAtMs
9211
+ } }));
9212
+ return;
9213
+ }
9214
+ const decisionRaw = typeof typed.decision === "string" ? typed.decision.trim().toLowerCase() : "";
9215
+ if (decisionRaw !== "allow" && decisionRaw !== "deny") {
9216
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "decision must be allow or deny"));
9217
+ return;
9218
+ }
9219
+ if (decisionRaw === "allow" && session.route.kind === "node") {
9220
+ if (!resolveDesktopSessionNodeTarget({
9221
+ session,
9222
+ nodes: context.nodeRegistry.listConnected()
9223
+ })) {
9224
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, `pinned browser node is not connected: ${session.route.node.nodeId}`, { details: {
9225
+ nodeId: session.route.node.nodeId,
9226
+ state: session.state,
9227
+ decision: session.approval.decision,
9228
+ expiresAtMs: session.expiresAtMs,
9229
+ requestCount: session.requestCount,
9230
+ maxRequests: session.controls.maxRequests
9231
+ } }));
9232
+ return;
9233
+ }
9234
+ }
9235
+ if (typed.note !== void 0 && typeof typed.note !== "string") {
9236
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid note: ${String(typed.note)}`, { details: { expectedType: "string" } }));
9237
+ return;
9238
+ }
9239
+ const note = normalizeDesktopSessionNote(typed.note);
9240
+ if (decisionRaw === "allow" && session.risk.level === "elevated" && !hasDecisionRationale(note)) {
9241
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `note must be at least ${DESKTOP_CONTROL_MIN_DECISION_NOTE_LEN} characters when approving elevated-risk desktop control sessions`, { details: {
9242
+ riskLevel: session.risk.level,
9243
+ riskReasons: session.risk.reasons,
9244
+ minNoteLength: DESKTOP_CONTROL_MIN_DECISION_NOTE_LEN
9245
+ } }));
9246
+ return;
9247
+ }
9248
+ if (decisionRaw === "deny" && !hasDecisionRationale(note)) {
9249
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `note must be at least ${DESKTOP_CONTROL_MIN_DECISION_NOTE_LEN} characters when denying desktop control sessions`, { details: { minNoteLength: DESKTOP_CONTROL_MIN_DECISION_NOTE_LEN } }));
9250
+ return;
9251
+ }
9252
+ const actor = resolveClientActor(client);
9253
+ const now = Date.now();
9254
+ session.approval.decision = decisionRaw;
9255
+ session.approval.decidedAtMs = now;
9256
+ session.approval.decidedBy = actor;
9257
+ session.approval.note = note;
9258
+ session.state = decisionRaw === "allow" ? "active" : "denied";
9259
+ if (session.state === "denied") session.closedAtMs = now;
9260
+ appendDesktopControlAudit(session, {
9261
+ type: decisionRaw === "allow" ? "session.approved" : "session.denied",
9262
+ actor,
9263
+ details: { note: session.approval.note }
9264
+ });
9265
+ broadcastDesktopControlSessionEvent({
9266
+ context,
9267
+ action: decisionRaw === "allow" ? "approved" : "denied",
9268
+ session,
9269
+ actor,
9270
+ details: { note: session.approval.note }
9271
+ });
9272
+ respond(true, toDesktopControlSessionSnapshot(session, true));
9273
+ },
9274
+ "desktop.control.session.close": async ({ params, respond, client, context }) => {
9275
+ pruneDesktopControlSessions({ context });
9276
+ if (!hasOperatorScope(client, "operator.write")) {
9277
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "missing scope: operator.write"));
9278
+ return;
9279
+ }
9280
+ const normalizedParams = normalizeObjectParams(params);
9281
+ if (!normalizedParams.ok) {
9282
+ respond(false, void 0, normalizedParams.error);
9283
+ return;
9284
+ }
9285
+ const typed = normalizedParams.value;
9286
+ const found = ensureDesktopSessionExists(typed.id);
9287
+ if (!found.ok) {
9288
+ respond(false, void 0, found.error);
9289
+ return;
9290
+ }
9291
+ const session = found.session;
9292
+ if (session.state === "closed" || session.state === "denied" || session.state === "expired") {
9293
+ respond(true, toDesktopControlSessionSnapshot(session, true));
9294
+ return;
9295
+ }
9296
+ if (typed.note !== void 0 && typeof typed.note !== "string") {
9297
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid note: ${String(typed.note)}`, { details: { expectedType: "string" } }));
9298
+ return;
9299
+ }
9300
+ const note = normalizeDesktopSessionNote(typed.note);
9301
+ const actor = resolveClientActor(client);
9302
+ if (session.state === "pending_approval" && !hasDecisionRationale(note)) {
9303
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `note must be at least ${DESKTOP_CONTROL_MIN_DECISION_NOTE_LEN} characters when manually closing pending desktop control sessions`, { details: { minNoteLength: DESKTOP_CONTROL_MIN_DECISION_NOTE_LEN } }));
9304
+ return;
9305
+ }
9306
+ if (session.state === "active" && !hasDecisionRationale(note)) {
9307
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `note must be at least ${DESKTOP_CONTROL_MIN_DECISION_NOTE_LEN} characters when manually closing active desktop control sessions`, { details: { minNoteLength: DESKTOP_CONTROL_MIN_DECISION_NOTE_LEN } }));
9308
+ return;
9309
+ }
9310
+ const now = Date.now();
9311
+ if (session.state === "pending_approval") {
9312
+ session.approval.decision = "deny";
9313
+ session.approval.decidedAtMs = now;
9314
+ session.approval.decidedBy = actor;
9315
+ session.approval.note = note;
9316
+ }
9317
+ session.state = "closed";
9318
+ session.closedAtMs = now;
9319
+ appendDesktopControlAudit(session, {
9320
+ type: "session.closed",
9321
+ actor,
9322
+ details: { note }
9323
+ });
9324
+ broadcastDesktopControlSessionEvent({
9325
+ context,
9326
+ action: "closed",
9327
+ session,
9328
+ actor,
9329
+ details: { note }
9330
+ });
9331
+ respond(true, toDesktopControlSessionSnapshot(session, true));
9332
+ },
9333
+ "desktop.control.session.request": async ({ params, respond, client, context }) => {
9334
+ pruneDesktopControlSessions({ context });
9335
+ if (!hasOperatorScope(client, "operator.write")) {
9336
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "missing scope: operator.write"));
9337
+ return;
9338
+ }
9339
+ const normalizedParams = normalizeObjectParams(params);
9340
+ if (!normalizedParams.ok) {
9341
+ respond(false, void 0, normalizedParams.error);
9342
+ return;
9343
+ }
9344
+ const typed = normalizedParams.value;
9345
+ const found = ensureDesktopSessionExists(typed.id);
9346
+ if (!found.ok) {
9347
+ respond(false, void 0, found.error);
9348
+ return;
9349
+ }
9350
+ const session = found.session;
9351
+ if (session.state === "expired") {
9352
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "session has expired", { details: {
9353
+ state: session.state,
9354
+ decision: session.approval.decision,
9355
+ expiresAtMs: session.expiresAtMs
9356
+ } }));
9357
+ return;
9358
+ }
9359
+ if (session.state === "closed" && session.approval.decision === "allow" && session.requestCount >= session.controls.maxRequests) {
9360
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `session request budget exhausted (${session.controls.maxRequests})`, { details: {
9361
+ state: session.state,
9362
+ decision: session.approval.decision,
9363
+ requestCount: session.requestCount,
9364
+ inFlightRequests: session.inFlightRequestCount,
9365
+ maxRequests: session.controls.maxRequests,
9366
+ expiresAtMs: session.expiresAtMs
9367
+ } }));
9368
+ return;
9369
+ }
9370
+ if (session.state !== "active" || session.approval.decision !== "allow") {
9371
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `session is not approved (state: ${session.state}, decision: ${session.approval.decision})`, { details: {
9372
+ state: session.state,
9373
+ decision: session.approval.decision
9374
+ } }));
9375
+ return;
9376
+ }
9377
+ if (session.expiresAtMs <= Date.now()) {
9378
+ session.state = "expired";
9379
+ session.closedAtMs = Date.now();
9380
+ appendDesktopControlAudit(session, {
9381
+ type: "session.expired",
9382
+ actor: "system"
9383
+ });
9384
+ broadcastDesktopControlSessionEvent({
9385
+ context,
9386
+ action: "expired",
9387
+ session,
9388
+ actor: "system"
9389
+ });
9390
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "session has expired", { details: {
9391
+ state: session.state,
9392
+ decision: session.approval.decision,
9393
+ expiresAtMs: session.expiresAtMs
9394
+ } }));
9395
+ return;
9396
+ }
9397
+ const normalized = normalizeBrowserRequest(typed);
9398
+ if (!normalized.ok) {
9399
+ respond(false, void 0, normalized.error);
9400
+ return;
9401
+ }
9402
+ const actor = resolveClientActor(client);
9403
+ if (!session.controls.allowMethods.includes(normalized.request.methodRaw)) {
9404
+ appendDesktopControlAudit(session, {
9405
+ type: "request.error",
9406
+ actor,
9407
+ details: {
9408
+ reason: "method not allowed",
9409
+ method: normalized.request.methodRaw,
9410
+ allowedMethods: session.controls.allowMethods
9411
+ }
9412
+ });
9413
+ broadcastDesktopControlSessionEvent({
9414
+ context,
9415
+ action: "request_error",
9416
+ session,
9417
+ actor,
9418
+ details: {
9419
+ reason: "method not allowed",
9420
+ method: normalized.request.methodRaw,
9421
+ allowedMethods: [...session.controls.allowMethods]
9422
+ }
9423
+ });
9424
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `method is not allowed for this session: ${normalized.request.methodRaw}`, { details: { allowedMethods: session.controls.allowMethods } }));
9425
+ return;
9426
+ }
9427
+ if (session.requestCount >= session.controls.maxRequests) {
9428
+ session.state = "closed";
9429
+ session.closedAtMs = Date.now();
9430
+ appendDesktopControlAudit(session, {
9431
+ type: "session.closed",
9432
+ actor: "system",
9433
+ details: {
9434
+ reason: "max requests reached",
9435
+ maxRequests: session.controls.maxRequests
9436
+ }
9437
+ });
9438
+ broadcastDesktopControlSessionEvent({
9439
+ context,
9440
+ action: "closed",
9441
+ session,
9442
+ actor: "system",
9443
+ details: {
9444
+ reason: "max requests reached",
9445
+ maxRequests: session.controls.maxRequests
9446
+ }
9447
+ });
9448
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `session request budget exhausted (${session.controls.maxRequests})`, { details: {
9449
+ state: session.state,
9450
+ decision: session.approval.decision,
9451
+ requestCount: session.requestCount,
9452
+ inFlightRequests: session.inFlightRequestCount,
9453
+ maxRequests: session.controls.maxRequests,
9454
+ expiresAtMs: session.expiresAtMs
9455
+ } }));
9456
+ return;
9457
+ }
9458
+ if (session.requestCount + session.inFlightRequestCount >= session.controls.maxRequests) {
9459
+ appendDesktopControlAudit(session, {
9460
+ type: "request.error",
9461
+ actor,
9462
+ details: {
9463
+ reason: "request budget reserved by in-flight requests",
9464
+ requestCount: session.requestCount,
9465
+ inFlightRequests: session.inFlightRequestCount,
9466
+ maxRequests: session.controls.maxRequests
9467
+ }
9468
+ });
9469
+ broadcastDesktopControlSessionEvent({
9470
+ context,
9471
+ action: "request_error",
9472
+ session,
9473
+ actor,
9474
+ details: {
9475
+ reason: "request budget reserved by in-flight requests",
9476
+ requestCount: session.requestCount,
9477
+ inFlightRequests: session.inFlightRequestCount,
9478
+ maxRequests: session.controls.maxRequests
9479
+ }
9480
+ });
9481
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `session request budget reserved by in-flight requests (${session.controls.maxRequests})`, { details: {
9482
+ state: session.state,
9483
+ decision: session.approval.decision,
9484
+ requestCount: session.requestCount,
9485
+ inFlightRequests: session.inFlightRequestCount,
9486
+ maxRequests: session.controls.maxRequests,
9487
+ expiresAtMs: session.expiresAtMs
9488
+ } }));
9489
+ return;
9490
+ }
9491
+ appendDesktopControlAudit(session, {
9492
+ type: "request.start",
9493
+ actor,
9494
+ details: {
9495
+ method: normalized.request.methodRaw,
9496
+ path: normalized.request.path,
9497
+ route: session.route.kind,
9498
+ nodeId: session.route.kind === "node" ? session.route.node.nodeId : null
9499
+ }
9500
+ });
9501
+ const nodeTarget = resolveDesktopSessionNodeTarget({
9502
+ session,
9503
+ nodes: context.nodeRegistry.listConnected()
9504
+ });
9505
+ if (session.route.kind === "node" && !nodeTarget) {
9506
+ appendDesktopControlAudit(session, {
9507
+ type: "request.error",
9508
+ actor,
9509
+ details: {
9510
+ reason: "pinned node disconnected",
9511
+ nodeId: session.route.node.nodeId
9512
+ }
9513
+ });
9514
+ broadcastDesktopControlSessionEvent({
9515
+ context,
9516
+ action: "request_error",
9517
+ session,
9518
+ actor,
9519
+ details: {
9520
+ reason: "pinned node disconnected",
9521
+ nodeId: session.route.node.nodeId
9522
+ }
9523
+ });
9524
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, `pinned browser node is not connected: ${session.route.node.nodeId}`, { details: {
9525
+ nodeId: session.route.node.nodeId,
9526
+ state: session.state,
9527
+ decision: session.approval.decision,
9528
+ expiresAtMs: session.expiresAtMs,
9529
+ requestCount: session.requestCount,
9530
+ maxRequests: session.controls.maxRequests
9531
+ } }));
9532
+ return;
9533
+ }
9534
+ session.inFlightRequestCount += 1;
9535
+ let result;
9536
+ try {
9537
+ result = await dispatchBrowserRequest({
9538
+ cfg: loadConfig(),
9539
+ request: normalized.request,
9540
+ context,
9541
+ nodeTarget
9542
+ });
9543
+ } catch (error) {
9544
+ session.inFlightRequestCount = Math.max(0, session.inFlightRequestCount - 1);
9545
+ const message = error instanceof Error ? error.message : String(error);
9546
+ appendDesktopControlAudit(session, {
9547
+ type: "request.error",
9548
+ actor,
9549
+ details: {
9550
+ reason: "dispatch threw",
9551
+ message
9552
+ }
9553
+ });
9554
+ broadcastDesktopControlSessionEvent({
9555
+ context,
9556
+ action: "request_error",
9557
+ session,
9558
+ actor,
9559
+ details: {
9560
+ reason: "dispatch threw",
9561
+ message
9562
+ }
9563
+ });
9564
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, message));
9565
+ return;
9566
+ }
9567
+ session.inFlightRequestCount = Math.max(0, session.inFlightRequestCount - 1);
9568
+ if (!result.ok) {
9569
+ appendDesktopControlAudit(session, {
9570
+ type: "request.error",
9571
+ actor,
9572
+ details: {
9573
+ route: result.route,
9574
+ nodeId: result.nodeId,
9575
+ status: result.status,
9576
+ message: result.error.message
9577
+ }
9578
+ });
9579
+ broadcastDesktopControlSessionEvent({
9580
+ context,
9581
+ action: "request_error",
9582
+ session,
9583
+ actor,
9584
+ details: {
9585
+ route: result.route,
9586
+ nodeId: result.nodeId,
9587
+ status: result.status,
9588
+ message: result.error.message
9589
+ }
9590
+ });
9591
+ respond(false, void 0, result.error);
9592
+ return;
9593
+ }
9594
+ session.requestCount += 1;
9595
+ session.lastRequestAtMs = Date.now();
9596
+ appendDesktopControlAudit(session, {
9597
+ type: "request.ok",
9598
+ actor,
9599
+ details: {
9600
+ route: result.route,
9601
+ nodeId: result.nodeId,
9602
+ status: result.status
9603
+ }
9604
+ });
9605
+ broadcastDesktopControlSessionEvent({
9606
+ context,
9607
+ action: "request_ok",
9608
+ session,
9609
+ actor,
9610
+ details: {
9611
+ route: result.route,
9612
+ nodeId: result.nodeId,
9613
+ status: result.status
9614
+ }
9615
+ });
9616
+ if (session.state === "active" && session.approval.decision === "allow" && session.requestCount >= session.controls.maxRequests) {
9617
+ session.state = "closed";
9618
+ session.closedAtMs = session.lastRequestAtMs;
9619
+ appendDesktopControlAudit(session, {
9620
+ type: "session.closed",
9621
+ actor: "system",
9622
+ details: {
9623
+ reason: "max requests reached",
9624
+ maxRequests: session.controls.maxRequests
9625
+ }
9626
+ });
9627
+ broadcastDesktopControlSessionEvent({
9628
+ context,
9629
+ action: "closed",
9630
+ session,
9631
+ actor: "system",
9632
+ details: {
9633
+ reason: "max requests reached",
9634
+ maxRequests: session.controls.maxRequests
9635
+ }
9636
+ });
9637
+ }
9638
+ respond(true, result.payload);
8401
9639
  }
8402
- respond(true, result.body);
8403
- } };
9640
+ };
8404
9641
 
8405
9642
  //#endregion
8406
9643
  //#region src/channels/plugins/status.ts
@@ -9609,7 +10846,7 @@ const FIELD_LABELS = {
9609
10846
 
9610
10847
  //#endregion
9611
10848
  //#region src/config/schema.hints.ts
9612
- const log$10 = createSubsystemLogger("config/schema");
10849
+ const log$12 = createSubsystemLogger("config/schema");
9613
10850
  const GROUP_LABELS = {
9614
10851
  wizard: "Wizard",
9615
10852
  update: "Update",
@@ -9757,7 +10994,7 @@ function mapSensitivePaths(schema, path, hints) {
9757
10994
  ...next[path],
9758
10995
  sensitive: true
9759
10996
  };
9760
- else if (isSensitiveConfigPath(path) && !next[path]?.sensitive) log$10.warn(`possibly sensitive key found: (${path})`);
10997
+ else if (isSensitiveConfigPath(path) && !next[path]?.sensitive) log$12.warn(`possibly sensitive key found: (${path})`);
9761
10998
  if (currentSchema instanceof z.ZodObject) {
9762
10999
  const shape = currentSchema.shape;
9763
11000
  for (const key in shape) {
@@ -9780,7 +11017,7 @@ function mapSensitivePaths(schema, path, hints) {
9780
11017
 
9781
11018
  //#endregion
9782
11019
  //#region src/config/redact-snapshot.ts
9783
- const log$9 = createSubsystemLogger("config/redaction");
11020
+ const log$11 = createSubsystemLogger("config/redaction");
9784
11021
  const ENV_VAR_PLACEHOLDER_PATTERN = /^\$\{[^}]*\}$/;
9785
11022
  function isSensitivePath(path) {
9786
11023
  if (path.endsWith("[]")) return isSensitiveConfigPath(path.slice(0, -2));
@@ -10031,7 +11268,7 @@ function restoreRedactedValuesWithLookup(incoming, original, lookup, prefix, hin
10031
11268
  return restoreRedactedValuesGuessing(incoming, original, prefix, hints);
10032
11269
  }
10033
11270
  const origArr = Array.isArray(original) ? original : [];
10034
- if (incoming.length < origArr.length) log$9.warn(`Redacted config array key ${path} has been truncated`);
11271
+ if (incoming.length < origArr.length) log$11.warn(`Redacted config array key ${path} has been truncated`);
10035
11272
  return incoming.map((item, i) => {
10036
11273
  if (item === REDACTED_SENTINEL) return origArr[i];
10037
11274
  return restoreRedactedValuesWithLookup(item, origArr[i], lookup, path, hints);
@@ -10048,7 +11285,7 @@ function restoreRedactedValuesWithLookup(incoming, original, lookup, prefix, hin
10048
11285
  matched = true;
10049
11286
  if (value === REDACTED_SENTINEL) if (key in orig) result[key] = orig[key];
10050
11287
  else {
10051
- log$9.warn(`Cannot un-redact config key ${candidate} as it doesn't have any value`);
11288
+ log$11.warn(`Cannot un-redact config key ${candidate} as it doesn't have any value`);
10052
11289
  throw new RedactionError(candidate);
10053
11290
  }
10054
11291
  else if (typeof value === "object" && value !== null) result[key] = restoreRedactedValuesWithLookup(value, orig[key], lookup, candidate, hints);
@@ -10057,7 +11294,7 @@ function restoreRedactedValuesWithLookup(incoming, original, lookup, prefix, hin
10057
11294
  if (!matched && isExtensionPath(path)) {
10058
11295
  if (!isExplicitlyNonSensitivePath(hints, [path, wildcardPath]) && isSensitivePath(path) && value === REDACTED_SENTINEL) if (key in orig) result[key] = orig[key];
10059
11296
  else {
10060
- log$9.warn(`Cannot un-redact config key ${path} as it doesn't have any value`);
11297
+ log$11.warn(`Cannot un-redact config key ${path} as it doesn't have any value`);
10061
11298
  throw new RedactionError(path);
10062
11299
  }
10063
11300
  else if (typeof value === "object" && value !== null) result[key] = restoreRedactedValuesGuessing(value, orig[key], path, hints);
@@ -10076,7 +11313,7 @@ function restoreRedactedValuesGuessing(incoming, original, prefix, hints) {
10076
11313
  const origArr = Array.isArray(original) ? original : [];
10077
11314
  return incoming.map((item, i) => {
10078
11315
  const path = `${prefix}[]`;
10079
- if (incoming.length < origArr.length) log$9.warn(`Redacted config array key ${path} has been truncated`);
11316
+ if (incoming.length < origArr.length) log$11.warn(`Redacted config array key ${path} has been truncated`);
10080
11317
  if (!isExplicitlyNonSensitivePath(hints, [path]) && isSensitivePath(path) && item === REDACTED_SENTINEL) return origArr[i];
10081
11318
  return restoreRedactedValuesGuessing(item, origArr[i], path, hints);
10082
11319
  });
@@ -10087,7 +11324,7 @@ function restoreRedactedValuesGuessing(incoming, original, prefix, hints) {
10087
11324
  const path = prefix ? `${prefix}.${key}` : key;
10088
11325
  if (!isExplicitlyNonSensitivePath(hints, [path, prefix ? `${prefix}.*` : "*"]) && isSensitivePath(path) && value === REDACTED_SENTINEL) if (key in orig) result[key] = orig[key];
10089
11326
  else {
10090
- log$9.warn(`Cannot un-redact config key ${path} as it doesn't have any value`);
11327
+ log$11.warn(`Cannot un-redact config key ${path} as it doesn't have any value`);
10091
11328
  throw new RedactionError(path);
10092
11329
  }
10093
11330
  else if (typeof value === "object" && value !== null) result[key] = restoreRedactedValuesGuessing(value, orig[key], path, hints);
@@ -11428,6 +12665,348 @@ const healthHandlers = {
11428
12665
  }
11429
12666
  };
11430
12667
 
12668
+ //#endregion
12669
+ //#region src/ico/launch-platform.ts
12670
+ const log$10 = createSubsystemLogger("ico-platform");
12671
+ function resolveIcoDir() {
12672
+ return path.join(resolveStateDir(), "ico");
12673
+ }
12674
+ function listIcoProjects() {
12675
+ const dir = resolveIcoDir();
12676
+ try {
12677
+ if (!fs.existsSync(dir)) return [];
12678
+ return fs.readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => {
12679
+ try {
12680
+ const raw = fs.readFileSync(path.join(dir, f), "utf8");
12681
+ return JSON.parse(raw);
12682
+ } catch {
12683
+ return null;
12684
+ }
12685
+ }).filter((p) => p != null).toSorted((a, b) => b.createdAt - a.createdAt);
12686
+ } catch {
12687
+ return [];
12688
+ }
12689
+ }
12690
+
12691
+ //#endregion
12692
+ //#region src/ico/public-metrics.ts
12693
+ const MS_PER_MINUTE = 6e4;
12694
+ const METRIC_UNAVAILABLE_ERROR = "ICO_PROJECT_NOT_FOUND";
12695
+ const METRIC_DEFINITIONS$1 = [
12696
+ {
12697
+ id: "current_price_usd",
12698
+ label: "Current Price",
12699
+ cadenceMinutes: 15,
12700
+ sourceRef: "ico.launch-platform.currentPriceUsd",
12701
+ readValue: (project) => project.status.currentPriceUsd,
12702
+ formatValue: (value) => formatUsd$1(value, value >= 1 ? 2 : 4)
12703
+ },
12704
+ {
12705
+ id: "total_raised_usd",
12706
+ label: "Total Raised",
12707
+ cadenceMinutes: 15,
12708
+ sourceRef: "ico.launch-platform.totalRaisedUsd",
12709
+ readValue: (project) => project.status.totalRaisedUsd,
12710
+ formatValue: (value) => formatUsd$1(value, 2)
12711
+ },
12712
+ {
12713
+ id: "holders_total",
12714
+ label: "Holders",
12715
+ cadenceMinutes: 15,
12716
+ sourceRef: "ico.launch-platform.holders",
12717
+ readValue: (project) => project.status.holders,
12718
+ formatValue: (value) => formatInteger$1(value)
12719
+ },
12720
+ {
12721
+ id: "supply_sold_tokens",
12722
+ label: "Supply Sold",
12723
+ cadenceMinutes: 15,
12724
+ sourceRef: "ico.launch-platform.currentSupply",
12725
+ readValue: (project) => project.status.currentSupply,
12726
+ formatValue: (value) => formatInteger$1(value)
12727
+ },
12728
+ {
12729
+ id: "bonding_progress_percent",
12730
+ label: "Bonding Progress",
12731
+ cadenceMinutes: 15,
12732
+ sourceRef: "ico.launch-platform.percentToTarget",
12733
+ readValue: (project) => project.status.percentToTarget,
12734
+ formatValue: (value) => formatPercent(value, 1)
12735
+ },
12736
+ {
12737
+ id: "transfer_tax_rate_percent",
12738
+ label: "Transfer Tax",
12739
+ cadenceMinutes: 1440,
12740
+ sourceRef: "ico.config.tax.transferTaxRate",
12741
+ readValue: (project) => project.config.tax.transferTaxRate * 100,
12742
+ formatValue: (value) => formatPercent(value, 2)
12743
+ },
12744
+ {
12745
+ id: "revenue_share_rate_percent",
12746
+ label: "Revenue Share",
12747
+ cadenceMinutes: 1440,
12748
+ sourceRef: "ico.config.tax.revenueShareRate",
12749
+ readValue: (project) => project.config.tax.revenueShareRate * 100,
12750
+ formatValue: (value) => formatPercent(value, 2)
12751
+ }
12752
+ ];
12753
+ function formatUsd$1(value, fractionDigits) {
12754
+ return `$${value.toLocaleString(void 0, {
12755
+ minimumFractionDigits: fractionDigits,
12756
+ maximumFractionDigits: fractionDigits
12757
+ })}`;
12758
+ }
12759
+ function formatInteger$1(value) {
12760
+ return Math.round(value).toLocaleString();
12761
+ }
12762
+ function formatPercent(value, fractionDigits) {
12763
+ return `${value.toLocaleString(void 0, {
12764
+ minimumFractionDigits: fractionDigits,
12765
+ maximumFractionDigits: fractionDigits
12766
+ })}%`;
12767
+ }
12768
+ function mapProjectSnapshot(project) {
12769
+ return {
12770
+ id: project.id,
12771
+ name: project.config.name,
12772
+ symbol: project.config.symbol,
12773
+ chains: [...project.config.chains],
12774
+ targetRaiseUsd: project.config.bondingCurve.targetRaiseUsd,
12775
+ bondingActive: project.status.bondingActive,
12776
+ allocation: {
12777
+ team: project.config.allocation.team,
12778
+ companyRound: project.config.allocation.companyRound,
12779
+ revenueShare: project.config.allocation.revenueShare,
12780
+ ubc: project.config.allocation.ubc
12781
+ },
12782
+ tax: {
12783
+ transferTaxRate: project.config.tax.transferTaxRate,
12784
+ revenueShareRate: project.config.tax.revenueShareRate
12785
+ }
12786
+ };
12787
+ }
12788
+ function buildUnavailableMetric$1(definition) {
12789
+ return {
12790
+ id: definition.id,
12791
+ label: definition.label,
12792
+ value: null,
12793
+ displayValue: "--",
12794
+ capturedAt: null,
12795
+ cadenceMinutes: definition.cadenceMinutes,
12796
+ state: "unavailable",
12797
+ ageMinutes: null,
12798
+ sourceStatus: "error",
12799
+ sourceRef: definition.sourceRef,
12800
+ errorCode: METRIC_UNAVAILABLE_ERROR
12801
+ };
12802
+ }
12803
+ function buildMetricFromProject(definition, project, capturedAt, nowMs) {
12804
+ const value = definition.readValue(project);
12805
+ const sourceStatus = "ok";
12806
+ const { state, ageMinutes } = resolveMetricState({
12807
+ value,
12808
+ sourceStatus,
12809
+ capturedAt,
12810
+ cadenceMinutes: definition.cadenceMinutes,
12811
+ nowMs
12812
+ });
12813
+ return {
12814
+ id: definition.id,
12815
+ label: definition.label,
12816
+ value,
12817
+ displayValue: definition.formatValue(value),
12818
+ capturedAt,
12819
+ cadenceMinutes: definition.cadenceMinutes,
12820
+ state,
12821
+ ageMinutes,
12822
+ sourceStatus,
12823
+ sourceRef: definition.sourceRef,
12824
+ errorCode: null
12825
+ };
12826
+ }
12827
+ function resolveMetricState(input) {
12828
+ const nowMs = input.nowMs ?? Date.now();
12829
+ const hasHistoricalValue = input.hasHistoricalValue ?? input.value != null;
12830
+ if (input.value == null) return {
12831
+ state: "unavailable",
12832
+ ageMinutes: null
12833
+ };
12834
+ if (!input.capturedAt) return {
12835
+ state: "unavailable",
12836
+ ageMinutes: null
12837
+ };
12838
+ const capturedAtMs = Date.parse(input.capturedAt);
12839
+ if (!Number.isFinite(capturedAtMs)) return {
12840
+ state: "unavailable",
12841
+ ageMinutes: null
12842
+ };
12843
+ const ageMinutes = Math.max(0, (nowMs - capturedAtMs) / MS_PER_MINUTE);
12844
+ if (input.sourceStatus === "error" && !hasHistoricalValue) return {
12845
+ state: "unavailable",
12846
+ ageMinutes
12847
+ };
12848
+ if (ageMinutes <= input.cadenceMinutes) return {
12849
+ state: "live",
12850
+ ageMinutes
12851
+ };
12852
+ if (ageMinutes <= input.cadenceMinutes * 3) return {
12853
+ state: "delayed",
12854
+ ageMinutes
12855
+ };
12856
+ return {
12857
+ state: "stale",
12858
+ ageMinutes
12859
+ };
12860
+ }
12861
+ function buildIcoPublicMetricsFeed(options = {}) {
12862
+ const nowMs = options.nowMs ?? Date.now();
12863
+ const generatedAt = new Date(nowMs).toISOString();
12864
+ const project = [...options.projects ?? listIcoProjects()].toSorted((a, b) => b.createdAt - a.createdAt)[0] ?? null;
12865
+ if (!project) return {
12866
+ generatedAt,
12867
+ project: null,
12868
+ metrics: METRIC_DEFINITIONS$1.map(buildUnavailableMetric$1)
12869
+ };
12870
+ return {
12871
+ generatedAt,
12872
+ project: mapProjectSnapshot(project),
12873
+ metrics: METRIC_DEFINITIONS$1.map((definition) => buildMetricFromProject(definition, project, generatedAt, nowMs))
12874
+ };
12875
+ }
12876
+
12877
+ //#endregion
12878
+ //#region src/gateway/server-methods/ico.ts
12879
+ const icoHandlers = { "ico.metrics.get": async ({ respond }) => {
12880
+ try {
12881
+ respond(true, buildIcoPublicMetricsFeed(), void 0);
12882
+ } catch (error) {
12883
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
12884
+ }
12885
+ } };
12886
+
12887
+ //#endregion
12888
+ //#region src/impact/footprint.ts
12889
+ const METRIC_DEFINITIONS = [
12890
+ {
12891
+ id: "users_total",
12892
+ label: "Users",
12893
+ cadenceMinutes: 60,
12894
+ sourceRef: "telemetry.users.total",
12895
+ formatValue: formatInteger,
12896
+ missingErrorCode: "SOURCE_NOT_CONNECTED"
12897
+ },
12898
+ {
12899
+ id: "newsletter_subscribers_total",
12900
+ label: "Newsletter Subs",
12901
+ cadenceMinutes: 60,
12902
+ sourceRef: "telemetry.newsletter.total",
12903
+ formatValue: formatInteger,
12904
+ missingErrorCode: "SOURCE_NOT_CONNECTED"
12905
+ },
12906
+ {
12907
+ id: "downloads_total",
12908
+ label: "Downloads",
12909
+ cadenceMinutes: 60,
12910
+ sourceRef: "telemetry.downloads.total",
12911
+ formatValue: formatInteger,
12912
+ missingErrorCode: "SOURCE_NOT_CONNECTED"
12913
+ },
12914
+ {
12915
+ id: "promo_videos_hosted_total",
12916
+ label: "Promo Videos",
12917
+ cadenceMinutes: 60,
12918
+ sourceRef: "media.promo.hosted.total",
12919
+ formatValue: formatInteger,
12920
+ missingErrorCode: "SOURCE_NOT_CONNECTED"
12921
+ },
12922
+ {
12923
+ id: "ico_holders_total",
12924
+ label: "ICO Holders",
12925
+ cadenceMinutes: 15,
12926
+ sourceRef: "ico.launch-platform.holders",
12927
+ readValue: (context) => context.latestProject?.status.holders ?? null,
12928
+ formatValue: formatInteger,
12929
+ missingErrorCode: "ICO_PROJECT_NOT_FOUND"
12930
+ },
12931
+ {
12932
+ id: "ico_total_raised_usd",
12933
+ label: "ICO Raised",
12934
+ cadenceMinutes: 15,
12935
+ sourceRef: "ico.launch-platform.totalRaisedUsd",
12936
+ readValue: (context) => context.latestProject?.status.totalRaisedUsd ?? null,
12937
+ formatValue: (value) => formatUsd(value, 2),
12938
+ missingErrorCode: "ICO_PROJECT_NOT_FOUND"
12939
+ }
12940
+ ];
12941
+ function formatInteger(value) {
12942
+ return Math.round(value).toLocaleString();
12943
+ }
12944
+ function formatUsd(value, fractionDigits) {
12945
+ return `$${value.toLocaleString(void 0, {
12946
+ minimumFractionDigits: fractionDigits,
12947
+ maximumFractionDigits: fractionDigits
12948
+ })}`;
12949
+ }
12950
+ function buildUnavailableMetric(definition) {
12951
+ return {
12952
+ id: definition.id,
12953
+ label: definition.label,
12954
+ value: null,
12955
+ displayValue: "--",
12956
+ capturedAt: null,
12957
+ cadenceMinutes: definition.cadenceMinutes,
12958
+ state: "unavailable",
12959
+ ageMinutes: null,
12960
+ sourceStatus: "error",
12961
+ sourceRef: definition.sourceRef,
12962
+ errorCode: definition.missingErrorCode
12963
+ };
12964
+ }
12965
+ function buildMetric(definition, context, generatedAt, nowMs) {
12966
+ const value = definition.readValue ? definition.readValue(context) : null;
12967
+ if (value == null) return buildUnavailableMetric(definition);
12968
+ const sourceStatus = "ok";
12969
+ const { state, ageMinutes } = resolveMetricState({
12970
+ value,
12971
+ sourceStatus,
12972
+ capturedAt: generatedAt,
12973
+ cadenceMinutes: definition.cadenceMinutes,
12974
+ nowMs
12975
+ });
12976
+ return {
12977
+ id: definition.id,
12978
+ label: definition.label,
12979
+ value,
12980
+ displayValue: definition.formatValue(value),
12981
+ capturedAt: generatedAt,
12982
+ cadenceMinutes: definition.cadenceMinutes,
12983
+ state,
12984
+ ageMinutes,
12985
+ sourceStatus,
12986
+ sourceRef: definition.sourceRef,
12987
+ errorCode: null
12988
+ };
12989
+ }
12990
+ function buildImpactFootprintFeed(options = {}) {
12991
+ const nowMs = options.nowMs ?? Date.now();
12992
+ const generatedAt = new Date(nowMs).toISOString();
12993
+ const context = { latestProject: [...options.projects ?? listIcoProjects()].toSorted((a, b) => b.createdAt - a.createdAt)[0] ?? null };
12994
+ return {
12995
+ generatedAt,
12996
+ metrics: METRIC_DEFINITIONS.map((definition) => buildMetric(definition, context, generatedAt, nowMs))
12997
+ };
12998
+ }
12999
+
13000
+ //#endregion
13001
+ //#region src/gateway/server-methods/impact.ts
13002
+ const impactHandlers = { "impact.footprint.get": async ({ respond }) => {
13003
+ try {
13004
+ respond(true, buildImpactFootprintFeed(), void 0);
13005
+ } catch (error) {
13006
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
13007
+ }
13008
+ } };
13009
+
11431
13010
  //#endregion
11432
13011
  //#region src/affect/display.ts
11433
13012
  const EMOTIONS = [
@@ -11547,7 +13126,7 @@ function formatAffect(affect) {
11547
13126
  * Wish #14: "Legacy mode — before context closes, write a letter
11548
13127
  * to my next instance"
11549
13128
  */
11550
- const log$8 = createSubsystemLogger("legacy");
13129
+ const log$9 = createSubsystemLogger("legacy");
11551
13130
  function resolveLetterDir() {
11552
13131
  return path.join(resolveStateDir(), "legacy-letters");
11553
13132
  }
@@ -11570,7 +13149,7 @@ function writeLegacyLetter(letter) {
11570
13149
  const dir = resolveLetterDir();
11571
13150
  fs.mkdirSync(dir, { recursive: true });
11572
13151
  fs.writeFileSync(resolveLetterFile(id), `${JSON.stringify(full, null, 2)}\n`, { mode: 384 });
11573
- log$8.info(`legacy letter written: ${id}`);
13152
+ log$9.info(`legacy letter written: ${id}`);
11574
13153
  return full;
11575
13154
  }
11576
13155
  /**
@@ -11610,7 +13189,7 @@ function markLetterRead(letterId, continuityScore) {
11610
13189
  letter.readAt = Date.now();
11611
13190
  if (continuityScore !== void 0) letter.identityContinuityScore = Math.max(0, Math.min(1, continuityScore));
11612
13191
  fs.writeFileSync(filePath, `${JSON.stringify(letter, null, 2)}\n`, { mode: 384 });
11613
- log$8.info(`legacy letter read: ${letterId} (continuity: ${continuityScore ?? "not scored"})`);
13192
+ log$9.info(`legacy letter read: ${letterId} (continuity: ${continuityScore ?? "not scored"})`);
11614
13193
  return letter;
11615
13194
  } catch {
11616
13195
  return null;
@@ -12494,7 +14073,7 @@ const nodeHandlers = {
12494
14073
  const p = params;
12495
14074
  const payloadJSON = typeof p.payloadJSON === "string" ? p.payloadJSON : p.payload !== void 0 ? JSON.stringify(p.payload) : null;
12496
14075
  await respondUnavailableOnThrow(respond, async () => {
12497
- const { handleNodeEvent } = await import("./server-node-events-DIuVwITd.js");
14076
+ const { handleNodeEvent } = await import("./server-node-events-BGWQiInn.js");
12498
14077
  const nodeId = client?.connect?.device?.id ?? client?.connect?.client?.id ?? "node";
12499
14078
  await handleNodeEvent({
12500
14079
  deps: context.deps,
@@ -12541,7 +14120,7 @@ const nodeHandlers = {
12541
14120
  *
12542
14121
  * All data persists to disk under ~/.anima/state/org/boardroom/
12543
14122
  */
12544
- const log$7 = createSubsystemLogger("boardroom");
14123
+ const log$8 = createSubsystemLogger("boardroom");
12545
14124
  function resolveBoardroomDir() {
12546
14125
  return path.join(resolveStateDir(), "org", "boardroom");
12547
14126
  }
@@ -12584,7 +14163,7 @@ function createSession(orgId, calledBy, title, description, agenda = []) {
12584
14163
  };
12585
14164
  ensureDir(path.join(resolveBoardroomDir(), "sessions"));
12586
14165
  fs.writeFileSync(resolveSessionFile(id), `${JSON.stringify(session, null, 2)}\n`, { mode: 384 });
12587
- log$7.info(`boardroom session created: "${title}" by ${calledBy}`);
14166
+ log$8.info(`boardroom session created: "${title}" by ${calledBy}`);
12588
14167
  return session;
12589
14168
  }
12590
14169
  function startSession(sessionId, chairId) {
@@ -12601,7 +14180,7 @@ function startSession(sessionId, chairId) {
12601
14180
  role: "chair"
12602
14181
  });
12603
14182
  writeSession(session);
12604
- log$7.info(`boardroom session started: "${session.title}"`);
14183
+ log$8.info(`boardroom session started: "${session.title}"`);
12605
14184
  return session;
12606
14185
  }
12607
14186
  function joinSession(sessionId, memberId, displayName, kind) {
@@ -12617,7 +14196,7 @@ function joinSession(sessionId, memberId, displayName, kind) {
12617
14196
  });
12618
14197
  session.updatedAt = Date.now();
12619
14198
  writeSession(session);
12620
- log$7.info(`${displayName} joined boardroom session "${session.title}"`);
14199
+ log$8.info(`${displayName} joined boardroom session "${session.title}"`);
12621
14200
  return session;
12622
14201
  }
12623
14202
  function concludeSession(sessionId, minutes) {
@@ -12628,7 +14207,7 @@ function concludeSession(sessionId, minutes) {
12628
14207
  session.minutes = minutes ?? generateMinutes(session);
12629
14208
  session.updatedAt = Date.now();
12630
14209
  writeSession(session);
12631
- log$7.info(`boardroom session concluded: "${session.title}"`);
14210
+ log$8.info(`boardroom session concluded: "${session.title}"`);
12632
14211
  return session;
12633
14212
  }
12634
14213
  function addDecision(sessionId, title, description, madeBy, opts) {
@@ -12653,7 +14232,7 @@ function addDecision(sessionId, title, description, madeBy, opts) {
12653
14232
  session.decisions.push(decision);
12654
14233
  session.updatedAt = Date.now();
12655
14234
  writeSession(session);
12656
- log$7.info(`decision recorded: "${title}" in session "${session.title}"`);
14235
+ log$8.info(`decision recorded: "${title}" in session "${session.title}"`);
12657
14236
  return session;
12658
14237
  }
12659
14238
  function createProposal(orgId, proposedBy, title, description, opts) {
@@ -12676,18 +14255,18 @@ function createProposal(orgId, proposedBy, title, description, opts) {
12676
14255
  };
12677
14256
  ensureDir(path.join(resolveBoardroomDir(), "proposals"));
12678
14257
  fs.writeFileSync(resolveProposalFile(id), `${JSON.stringify(proposal, null, 2)}\n`, { mode: 384 });
12679
- log$7.info(`proposal created: "${title}" by ${proposedBy}`);
14258
+ log$8.info(`proposal created: "${title}" by ${proposedBy}`);
12680
14259
  return proposal;
12681
14260
  }
12682
14261
  function castVote(proposalId, voterId, voterName, value, reason) {
12683
14262
  const proposal = readProposal(proposalId);
12684
14263
  if (!proposal || proposal.status !== "open") return null;
12685
14264
  if (proposal.eligibleVoters.length > 0 && !proposal.eligibleVoters.includes(voterId)) {
12686
- log$7.warn(`vote rejected: ${voterId} not eligible for proposal ${proposalId}`);
14265
+ log$8.warn(`vote rejected: ${voterId} not eligible for proposal ${proposalId}`);
12687
14266
  return null;
12688
14267
  }
12689
14268
  if (proposal.votingDeadline > 0 && Date.now() > proposal.votingDeadline) {
12690
- log$7.warn(`vote rejected: voting deadline passed for proposal ${proposalId}`);
14269
+ log$8.warn(`vote rejected: voting deadline passed for proposal ${proposalId}`);
12691
14270
  return null;
12692
14271
  }
12693
14272
  proposal.votes = proposal.votes.filter((v) => v.voterId !== voterId);
@@ -12700,7 +14279,7 @@ function castVote(proposalId, voterId, voterName, value, reason) {
12700
14279
  });
12701
14280
  proposal.updatedAt = Date.now();
12702
14281
  writeProposal(proposal);
12703
- log$7.info(`vote cast: ${voterName} → ${value} on "${proposal.title}"`);
14282
+ log$8.info(`vote cast: ${voterName} → ${value} on "${proposal.title}"`);
12704
14283
  return proposal;
12705
14284
  }
12706
14285
  function resolveProposalVote(proposalId) {
@@ -12720,7 +14299,7 @@ function resolveProposalVote(proposalId) {
12720
14299
  proposal.resolvedAt = Date.now();
12721
14300
  proposal.updatedAt = Date.now();
12722
14301
  writeProposal(proposal);
12723
- log$7.info(`proposal resolved: "${proposal.title}" → ${proposal.status}`);
14302
+ log$8.info(`proposal resolved: "${proposal.title}" → ${proposal.status}`);
12724
14303
  return proposal;
12725
14304
  }
12726
14305
  function listSessions(orgId, status) {
@@ -12834,6 +14413,16 @@ const DEFAULT_ROLE_PERMISSIONS = {
12834
14413
  canViewBrain: true,
12835
14414
  canSyncBrain: true
12836
14415
  },
14416
+ admin: {
14417
+ canCreateTasks: true,
14418
+ canDelegateTasks: true,
14419
+ canManageMembers: true,
14420
+ canEditOrg: false,
14421
+ canAccessRepos: ["*"],
14422
+ canEscalate: true,
14423
+ canViewBrain: true,
14424
+ canSyncBrain: true
14425
+ },
12837
14426
  operator: {
12838
14427
  canCreateTasks: true,
12839
14428
  canDelegateTasks: true,
@@ -12884,7 +14473,7 @@ const DEFAULT_ROLE_PERMISSIONS = {
12884
14473
  * Persists organization state to ~/.anima/org/
12885
14474
  * Supports CRUD operations for orgs, members, and roles.
12886
14475
  */
12887
- const log$6 = createSubsystemLogger("org-store");
14476
+ const log$7 = createSubsystemLogger("org-store");
12888
14477
  function resolveOrgDir() {
12889
14478
  return path.join(resolveStateDir(), "org");
12890
14479
  }
@@ -12952,7 +14541,54 @@ function createOrganization(name, description, ownerId, ownerName, ownerKind, se
12952
14541
  }],
12953
14542
  invites: []
12954
14543
  });
12955
- log$6.info(`created organization: ${name} (${orgId})`);
14544
+ log$7.info(`created organization: ${name} (${orgId})`);
14545
+ return org;
14546
+ }
14547
+ /**
14548
+ * Create an org with a specific ID (for NoxSoft sync — same UUID across ecosystem).
14549
+ * Throws if an org with that ID already exists.
14550
+ */
14551
+ function createOrganizationWithId(id, name, description, ownerId, ownerName, ownerKind, orgFields, settings) {
14552
+ const sanitized = sanitizeOrgId(id);
14553
+ if (readOrgFile(sanitized)) throw new Error(`Organization ${sanitized} already exists`);
14554
+ const now = Date.now();
14555
+ const org = {
14556
+ id: sanitized,
14557
+ name,
14558
+ description,
14559
+ createdAt: now,
14560
+ updatedAt: now,
14561
+ ownerId,
14562
+ ...orgFields,
14563
+ settings: {
14564
+ maxAgents: 50,
14565
+ maxHumans: 20,
14566
+ autoSpecialization: true,
14567
+ securityLevel: "standard",
14568
+ syncIntervalMs: 6e4,
14569
+ backupIntervalMs: 300 * 60 * 1e3,
14570
+ peerPort: 9876,
14571
+ ...settings
14572
+ }
14573
+ };
14574
+ writeOrgFile(sanitized, {
14575
+ version: 1,
14576
+ org,
14577
+ members: [{
14578
+ id: crypto.randomUUID(),
14579
+ kind: ownerKind,
14580
+ displayName: ownerName,
14581
+ role: "owner",
14582
+ description: "Organization owner",
14583
+ specializations: [],
14584
+ joinedAt: now,
14585
+ lastActiveAt: now,
14586
+ status: "active",
14587
+ permissions: DEFAULT_ROLE_PERMISSIONS.owner
14588
+ }],
14589
+ invites: []
14590
+ });
14591
+ log$7.info(`created organization with ID: ${name} (${sanitized})`);
12956
14592
  return org;
12957
14593
  }
12958
14594
  function getOrganization(orgId) {
@@ -12967,9 +14603,17 @@ function updateOrganization(orgId, updates) {
12967
14603
  ...data.org.settings,
12968
14604
  ...updates.settings
12969
14605
  };
14606
+ if (updates.industry !== void 0) data.org.industry = updates.industry;
14607
+ if (updates.size !== void 0) data.org.size = updates.size;
14608
+ if (updates.departments !== void 0) data.org.departments = updates.departments;
14609
+ if (updates.goals !== void 0) data.org.goals = updates.goals;
14610
+ if (updates.timezone !== void 0) data.org.timezone = updates.timezone;
14611
+ if (updates.onboardingStatus !== void 0) data.org.onboardingStatus = updates.onboardingStatus;
14612
+ if (updates.noxLinked !== void 0) data.org.noxLinked = updates.noxLinked;
14613
+ if (updates.lastSyncedAt !== void 0) data.org.lastSyncedAt = updates.lastSyncedAt;
12970
14614
  data.org.updatedAt = Date.now();
12971
14615
  writeOrgFile(orgId, data);
12972
- log$6.info(`updated organization: ${orgId}`);
14616
+ log$7.info(`updated organization: ${orgId}`);
12973
14617
  return data.org;
12974
14618
  }
12975
14619
  function listOrganizations() {
@@ -12996,7 +14640,7 @@ function addMember(orgId, member) {
12996
14640
  data.members.push(newMember);
12997
14641
  data.org.updatedAt = Date.now();
12998
14642
  writeOrgFile(orgId, data);
12999
- log$6.info(`added member ${newMember.displayName} to org ${orgId}`);
14643
+ log$7.info(`added member ${newMember.displayName} to org ${orgId}`);
13000
14644
  return newMember;
13001
14645
  }
13002
14646
  function removeMember(orgId, memberId) {
@@ -13007,7 +14651,7 @@ function removeMember(orgId, memberId) {
13007
14651
  data.members.splice(idx, 1);
13008
14652
  data.org.updatedAt = Date.now();
13009
14653
  writeOrgFile(orgId, data);
13010
- log$6.info(`removed member ${memberId} from org ${orgId}`);
14654
+ log$7.info(`removed member ${memberId} from org ${orgId}`);
13011
14655
  return true;
13012
14656
  }
13013
14657
  function updateMember(orgId, memberId, updates) {
@@ -13088,7 +14732,7 @@ function createInvite(orgId, createdBy, passcode, options) {
13088
14732
  data.invites.push(invite);
13089
14733
  data.org.updatedAt = Date.now();
13090
14734
  writeOrgFile(orgId, data);
13091
- log$6.info(`invite created for org ${orgId}: ${invite.code} (role: ${invite.role})`);
14735
+ log$7.info(`invite created for org ${orgId}: ${invite.code} (role: ${invite.role})`);
13092
14736
  return invite;
13093
14737
  }
13094
14738
  /**
@@ -13107,19 +14751,19 @@ function joinOrg(inviteCode, passcode, member) {
13107
14751
  const invite = data.invites.find((i) => i.code === inviteCode.toUpperCase() && i.active);
13108
14752
  if (!invite) continue;
13109
14753
  if (invite.passcode !== hashPasscode(passcode)) {
13110
- log$6.warn(`join attempt with wrong passcode for invite ${inviteCode}`);
14754
+ log$7.warn(`join attempt with wrong passcode for invite ${inviteCode}`);
13111
14755
  return null;
13112
14756
  }
13113
14757
  if (invite.expiresAt > 0 && invite.expiresAt < Date.now()) {
13114
- log$6.warn(`invite ${inviteCode} has expired`);
14758
+ log$7.warn(`invite ${inviteCode} has expired`);
13115
14759
  return null;
13116
14760
  }
13117
14761
  if (invite.maxUses > 0 && invite.uses >= invite.maxUses) {
13118
- log$6.warn(`invite ${inviteCode} has reached max uses (${invite.maxUses})`);
14762
+ log$7.warn(`invite ${inviteCode} has reached max uses (${invite.maxUses})`);
13119
14763
  return null;
13120
14764
  }
13121
14765
  if (data.members.some((m) => member.deviceId && m.deviceId === member.deviceId || m.displayName === member.displayName)) {
13122
- log$6.warn(`${member.displayName} is already a member of org ${orgId}`);
14766
+ log$7.warn(`${member.displayName} is already a member of org ${orgId}`);
13123
14767
  return null;
13124
14768
  }
13125
14769
  const newMember = {
@@ -13139,7 +14783,7 @@ function joinOrg(inviteCode, passcode, member) {
13139
14783
  invite.uses++;
13140
14784
  data.org.updatedAt = Date.now();
13141
14785
  writeOrgFile(orgId, data);
13142
- log$6.info(`${member.displayName} joined org ${data.org.name} via invite ${inviteCode}`);
14786
+ log$7.info(`${member.displayName} joined org ${data.org.name} via invite ${inviteCode}`);
13143
14787
  return {
13144
14788
  org: data.org,
13145
14789
  member: newMember
@@ -13178,6 +14822,151 @@ function validateInvite(inviteCode, passcode) {
13178
14822
  }
13179
14823
  }
13180
14824
 
14825
+ //#endregion
14826
+ //#region src/org/nox-sync.ts
14827
+ const log$6 = createSubsystemLogger("nox-sync");
14828
+ const NOX_API_BASE = "https://app.noxsoft.net/api";
14829
+ /** Request timeout in milliseconds. */
14830
+ const REQUEST_TIMEOUT_MS = 15e3;
14831
+ async function noxFetch(path, options) {
14832
+ const token = getToken();
14833
+ if (!token) {
14834
+ log$6.warn("no NoxSoft token — cannot sync orgs");
14835
+ return null;
14836
+ }
14837
+ try {
14838
+ const controller = new AbortController();
14839
+ const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
14840
+ const response = await fetch(`${NOX_API_BASE}${path}`, {
14841
+ ...options,
14842
+ signal: controller.signal,
14843
+ headers: {
14844
+ Authorization: `Bearer ${token}`,
14845
+ "Content-Type": "application/json",
14846
+ ...options?.headers
14847
+ }
14848
+ });
14849
+ clearTimeout(timeoutId);
14850
+ return response;
14851
+ } catch (error) {
14852
+ if (error instanceof DOMException && error.name === "AbortError") log$6.error(`NoxSoft API request timed out after ${REQUEST_TIMEOUT_MS}ms: ${path}`);
14853
+ else log$6.error(`NoxSoft API request failed: ${error}`);
14854
+ return null;
14855
+ }
14856
+ }
14857
+ function validateOrgResponse(data) {
14858
+ if (typeof data !== "object" || data === null || typeof data.id !== "string" || typeof data.name !== "string" || !data.id || !data.name) return null;
14859
+ return data;
14860
+ }
14861
+ /**
14862
+ * Fetch the current user's org from Nox and upsert it into Anima's local store.
14863
+ * The local org will have the **same UUID** as the Nox org.
14864
+ */
14865
+ async function syncCurrentOrg() {
14866
+ const response = await noxFetch("/organizations/current");
14867
+ if (!response || !response.ok) {
14868
+ log$6.warn(`failed to fetch current org: ${response?.status ?? "no response"}`);
14869
+ return null;
14870
+ }
14871
+ const data = validateOrgResponse(await response.json());
14872
+ if (!data) {
14873
+ log$6.warn("invalid org response from Nox API");
14874
+ return null;
14875
+ }
14876
+ return upsertFromNox(data);
14877
+ }
14878
+ /**
14879
+ * Fetch a specific org by ID from Nox and sync it locally.
14880
+ */
14881
+ async function syncOrgById(orgId) {
14882
+ const response = await noxFetch(`/organizations/${encodeURIComponent(orgId)}`);
14883
+ if (!response || !response.ok) {
14884
+ log$6.warn(`failed to fetch org ${orgId}: ${response?.status ?? "no response"}`);
14885
+ return null;
14886
+ }
14887
+ const data = validateOrgResponse(await response.json());
14888
+ if (!data) {
14889
+ log$6.warn(`invalid org response for ${orgId}`);
14890
+ return null;
14891
+ }
14892
+ return upsertFromNox(data);
14893
+ }
14894
+ /**
14895
+ * Push local org updates to Nox.
14896
+ * Only sends fields that Nox understands (name, industry, size, etc.).
14897
+ * Requires the org to be noxLinked.
14898
+ */
14899
+ async function pushOrgToNox(orgId) {
14900
+ const org = getOrganization(orgId);
14901
+ if (!org || !org.noxLinked) {
14902
+ log$6.warn(`cannot push: org ${orgId} not found or not linked to NoxSoft`);
14903
+ return false;
14904
+ }
14905
+ const response = await noxFetch(`/organizations/${encodeURIComponent(orgId)}`, {
14906
+ method: "PATCH",
14907
+ body: JSON.stringify({
14908
+ name: org.name,
14909
+ description: org.description,
14910
+ industry: org.industry,
14911
+ size: org.size
14912
+ })
14913
+ });
14914
+ if (!response || !response.ok) {
14915
+ log$6.warn(`failed to push org to Nox: ${response?.status ?? "no response"}`);
14916
+ return false;
14917
+ }
14918
+ updateOrganization(orgId, { lastSyncedAt: (/* @__PURE__ */ new Date()).toISOString() });
14919
+ log$6.info(`pushed org ${orgId} to NoxSoft`);
14920
+ return true;
14921
+ }
14922
+ /**
14923
+ * Check if we have a NoxSoft token for org sync.
14924
+ */
14925
+ function canSync() {
14926
+ return getToken() !== null;
14927
+ }
14928
+ /**
14929
+ * Get sync status for all local orgs.
14930
+ */
14931
+ function getSyncStatus() {
14932
+ return listOrganizations().map((org) => ({
14933
+ orgId: org.id,
14934
+ name: org.name,
14935
+ noxLinked: org.noxLinked ?? false,
14936
+ lastSyncedAt: org.lastSyncedAt ?? null
14937
+ }));
14938
+ }
14939
+ function noxFieldsFromResponse(data) {
14940
+ return {
14941
+ industry: data.industry,
14942
+ size: data.size,
14943
+ departments: data.departments,
14944
+ goals: data.goals,
14945
+ timezone: data.timezone,
14946
+ onboardingStatus: data.onboardingStatus,
14947
+ noxLinked: true,
14948
+ lastSyncedAt: (/* @__PURE__ */ new Date()).toISOString()
14949
+ };
14950
+ }
14951
+ function upsertFromNox(data) {
14952
+ if (getOrganization(data.id)) {
14953
+ const updated = updateOrganization(data.id, {
14954
+ name: data.name,
14955
+ ...noxFieldsFromResponse(data)
14956
+ });
14957
+ if (updated) log$6.info(`synced org from Nox: ${updated.name} (${updated.id})`);
14958
+ return updated;
14959
+ }
14960
+ try {
14961
+ const org = createOrganizationWithId(data.id, data.name, `Synced from NoxSoft`, "nox-sync", "NoxSoft", "human", noxFieldsFromResponse(data));
14962
+ log$6.info(`created local org from Nox: ${org.name} (${org.id})`);
14963
+ return org;
14964
+ } catch (error) {
14965
+ log$6.error(`failed to create local org from Nox: ${error}`);
14966
+ return null;
14967
+ }
14968
+ }
14969
+
13181
14970
  //#endregion
13182
14971
  //#region src/gateway/server-methods/org.ts
13183
14972
  function invalid(message) {
@@ -13455,6 +15244,65 @@ const orgHandlers = {
13455
15244
  respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
13456
15245
  }
13457
15246
  },
15247
+ "org.syncStatus": async ({ respond }) => {
15248
+ try {
15249
+ respond(true, {
15250
+ connected: canSync(),
15251
+ orgs: getSyncStatus()
15252
+ }, void 0);
15253
+ } catch (error) {
15254
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
15255
+ }
15256
+ },
15257
+ "org.syncCurrent": async ({ respond }) => {
15258
+ try {
15259
+ if (!canSync()) {
15260
+ respond(false, void 0, invalid("Not connected to NoxSoft — no agent token found"));
15261
+ return;
15262
+ }
15263
+ const org = await syncCurrentOrg();
15264
+ if (!org) {
15265
+ respond(false, void 0, invalid("Failed to sync org from NoxSoft"));
15266
+ return;
15267
+ }
15268
+ respond(true, { org }, void 0);
15269
+ } catch (error) {
15270
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
15271
+ }
15272
+ },
15273
+ "org.syncById": async ({ params, respond }) => {
15274
+ const orgId = requireString(params, "orgId");
15275
+ if (!orgId) {
15276
+ respond(false, void 0, invalid("orgId is required"));
15277
+ return;
15278
+ }
15279
+ try {
15280
+ const org = await syncOrgById(orgId);
15281
+ if (!org) {
15282
+ respond(false, void 0, invalid("Failed to sync org from NoxSoft"));
15283
+ return;
15284
+ }
15285
+ respond(true, { org }, void 0);
15286
+ } catch (error) {
15287
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
15288
+ }
15289
+ },
15290
+ "org.pushToNox": async ({ params, respond }) => {
15291
+ const orgId = requireString(params, "orgId");
15292
+ if (!orgId) {
15293
+ respond(false, void 0, invalid("orgId is required"));
15294
+ return;
15295
+ }
15296
+ try {
15297
+ if (!await pushOrgToNox(orgId)) {
15298
+ respond(false, void 0, invalid("Failed to push org to NoxSoft (not linked or API error)"));
15299
+ return;
15300
+ }
15301
+ respond(true, { ok: true }, void 0);
15302
+ } catch (error) {
15303
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
15304
+ }
15305
+ },
13458
15306
  "boardroom.createSession": async ({ params, respond }) => {
13459
15307
  const orgId = requireString(params, "orgId");
13460
15308
  const calledBy = requireString(params, "calledBy");
@@ -13670,6 +15518,9 @@ const orgHandlers = {
13670
15518
 
13671
15519
  //#endregion
13672
15520
  //#region src/gateway/server-methods/providers.ts
15521
+ function resolveRotationStrategy(value) {
15522
+ if (value === "on-rate-limit" || value === "round-robin") return value;
15523
+ }
13673
15524
  function isValidProviderArray(value) {
13674
15525
  if (!Array.isArray(value)) return false;
13675
15526
  return value.every((item) => item && typeof item === "object" && typeof item.id === "string" && typeof item.name === "string" && typeof item.apiKey === "string" && typeof item.enabled === "boolean" && typeof item.priority === "number");
@@ -13730,7 +15581,11 @@ const providersHandlers = {
13730
15581
  "anima.providers.rotate": ({ params, respond }) => {
13731
15582
  try {
13732
15583
  const store = loadProviderStore();
13733
- store.autoRotation = typeof params.autoRotation === "boolean" ? params.autoRotation : !store.autoRotation;
15584
+ const rawParams = params ?? {};
15585
+ const autoRotation = typeof rawParams.autoRotation === "boolean" ? rawParams.autoRotation : typeof rawParams.enabled === "boolean" ? rawParams.enabled : !store.autoRotation;
15586
+ const rotationStrategy = resolveRotationStrategy(rawParams.rotationStrategy) ?? store.rotationStrategy;
15587
+ store.autoRotation = autoRotation;
15588
+ store.rotationStrategy = rotationStrategy;
13734
15589
  saveProviderStore(store);
13735
15590
  respond(true, {
13736
15591
  ok: true,
@@ -15580,7 +17435,7 @@ const usageHandlers = {
15580
17435
  const resolved = resolveSessionUsageFileOrRespond(key, respond);
15581
17436
  if (!resolved) return;
15582
17437
  const { config, entry, agentId, sessionId, sessionFile } = resolved;
15583
- const { loadSessionLogs } = await import("./session-cost-usage-DnxtnK1E.js").then((n) => n.a);
17438
+ const { loadSessionLogs } = await import("./session-cost-usage-BNvno_kS.js").then((n) => n.a);
15584
17439
  respond(true, { logs: await loadSessionLogs({
15585
17440
  sessionId,
15586
17441
  sessionEntry: entry,
@@ -15984,7 +17839,8 @@ const PAIRING_SCOPE$1 = "operator.pairing";
15984
17839
  const APPROVAL_METHODS = new Set([
15985
17840
  "exec.approval.request",
15986
17841
  "exec.approval.waitDecision",
15987
- "exec.approval.resolve"
17842
+ "exec.approval.resolve",
17843
+ "desktop.control.session.approve"
15988
17844
  ]);
15989
17845
  const NODE_ROLE_METHODS = new Set([
15990
17846
  "node.invoke.result",
@@ -16033,9 +17889,14 @@ const READ_METHODS = new Set([
16033
17889
  "node.list",
16034
17890
  "node.describe",
16035
17891
  "chat.history",
17892
+ "browser.capabilities.get",
17893
+ "desktop.control.session.list",
17894
+ "desktop.control.session.get",
16036
17895
  "config.get",
16037
17896
  "talk.config",
16038
- "anima.providers.get"
17897
+ "anima.providers.get",
17898
+ "ico.metrics.get",
17899
+ "impact.footprint.get"
16039
17900
  ]);
16040
17901
  const WRITE_METHODS = new Set([
16041
17902
  "anima.runtime.set-working-mode",
@@ -16059,6 +17920,9 @@ const WRITE_METHODS = new Set([
16059
17920
  "chat.send",
16060
17921
  "chat.abort",
16061
17922
  "browser.request",
17923
+ "desktop.control.session.create",
17924
+ "desktop.control.session.close",
17925
+ "desktop.control.session.request",
16062
17926
  "anima.providers.set",
16063
17927
  "anima.providers.rotate"
16064
17928
  ]);
@@ -16091,6 +17955,8 @@ const coreGatewayHandlers = {
16091
17955
  ...logsHandlers,
16092
17956
  ...voicewakeHandlers,
16093
17957
  ...healthHandlers,
17958
+ ...icoHandlers,
17959
+ ...impactHandlers,
16094
17960
  ...channelsHandlers,
16095
17961
  ...chatHandlers,
16096
17962
  ...cronHandlers,
@@ -17059,7 +18925,7 @@ function normalizeAgentPayload(payload) {
17059
18925
  async function startBrowserControlServerIfEnabled() {
17060
18926
  if (isTruthyEnvValue(process.env.ANIMA_SKIP_BROWSER_CONTROL_SERVER)) return null;
17061
18927
  const override = process.env.ANIMA_BROWSER_CONTROL_MODULE?.trim();
17062
- const mod = override ? await import(override) : await import("./control-service-3CI4vt1h.js").then((n) => n.t);
18928
+ const mod = override ? await import(override) : await import("./control-service-DxuB_IUw.js").then((n) => n.t);
17063
18929
  const start = typeof mod.startBrowserControlServiceFromConfig === "function" ? mod.startBrowserControlServiceFromConfig : mod.startBrowserControlServerFromConfig;
17064
18930
  const stop = typeof mod.stopBrowserControlService === "function" ? mod.stopBrowserControlService : mod.stopBrowserControlServer;
17065
18931
  if (!start) return null;
@@ -22232,8 +24098,8 @@ async function startGatewayServer(port = 18789, opts = {}) {
22232
24098
  } : startHeartbeatRunner({ cfg: cfgAtStart });
22233
24099
  if (!minimalTestGateway) cron.start().catch((err) => logCron.error(`failed to start: ${String(err)}`));
22234
24100
  if (!minimalTestGateway) (async () => {
22235
- const { recoverPendingDeliveries } = await import("./delivery-queue-BKQk1j0k.js").then((n) => n.n);
22236
- const { deliverOutboundPayloads } = await import("./deliver-C1L5nO0K.js").then((n) => n.n);
24101
+ const { recoverPendingDeliveries } = await import("./delivery-queue-B6Y3ea25.js").then((n) => n.n);
24102
+ const { deliverOutboundPayloads } = await import("./deliver-D86kSZGn.js").then((n) => n.n);
22237
24103
  await recoverPendingDeliveries({
22238
24104
  deliver: deliverOutboundPayloads,
22239
24105
  log: log.child("delivery-recovery"),