@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,79 +1,79 @@
1
1
  import { h as expandHomePrefix, i as isNixMode, l as resolveGatewayLockDir, m as resolveStateDir, o as resolveConfigPath, r as STATE_DIR, t as CONFIG_PATH, u as resolveGatewayPort } from "./paths-zhVksOvm.js";
2
- import { E as getActivePluginRegistry, F as setVerbose, G as setLoggerOverride, H as getChildLogger, U as getLogger, W as getResolvedLoggerSettings, d as defaultRuntime, g as CHANNEL_IDS, i as getResolvedConsoleSettings, n as runtimeForLogger, o as setConsoleSubsystemFilter, s as setConsoleTimestampPrefix, t as createSubsystemLogger, v as DEFAULT_CHAT_CHANNEL } from "./subsystem-BAADN1B8.js";
3
- import { C as shortenHomePath, D as truncateUtf16Safe, b as resolveUserPath, c as ensureDir$1, d as isPlainObject, r as clamp, t as CONFIG_DIR } from "./utils-CLYlhJuc.js";
4
- import { C as supportsXHighThinking, _ as normalizeElevatedLevel, b as normalizeUsageDisplay, m as formatXHighModelHint, p as formatThinkingLevels, v as normalizeReasoningLevel, x as normalizeVerboseLevel, y as normalizeThinkLevel } from "./pi-embedded-helpers-BZ9GspxK.js";
5
- import { $ as archiveFileOnDisk, At as deferGatewayRestartUntilIdle, B as sniffMimeFromBase64, C as verifyNodeToken, Cn as stopDiagnosticHeartbeat, Cr as DEFAULT_INPUT_PDF_MAX_PIXELS, Ct as loadProviderStore, D as registerSkillsChangeListener, Dr as extractImageContentFromSource, E as getSkillsSnapshotVersion, Er as extractFileContentFromSource, F as abortEmbeddedPiRun, Ft as setGatewaySigusr1RestartPolicy, G as canonicalizeSpawnedByForAgent, Gn as CommandLane, Gt as normalizeCronJobPatch, Hn as readLatestAssistantReply, I as waitForEmbeddedPiRunEnd, It as setPreRestartDeferralCheck, J as loadCombinedSessionStoreForGateway, Jn as getAgentRunContext, Jt as normalizeOptionalText, K as listAgentsForGateway, Kn as clearAgentRunContext, Kt as inferLegacyName, L as runNoxSoftEmbeddedAgent, Ln as countActiveDescendantRuns, Lt as consumeRestartSentinel, M as resetAllLanes, Mn as isAbortTrigger, Mr as resolveAgentTimeoutMs, Mt as isGatewaySigusr1RestartExternallyAllowed, N as setCommandLaneConcurrency, Nn as stopSubagentsForRequester, Nt as markGatewaySigusr1RestartHandled, O as clearSessionQueues, Or as normalizeMimeList, P as waitForActiveTasks, Pt as scheduleGatewaySigusr1Restart, Q as resolveSessionModelRef, R as applyToolPolicyPipeline, Rn as initSubagentRegistry, Rt as formatDoctorNonInteractiveHint, S as updatePairedNodeMetadata, Sn as startDiagnosticHeartbeat, Sr as DEFAULT_INPUT_PDF_MAX_PAGES, St as loadProviderUsageSummary, T as verifyPairingToken, Tr as DEFAULT_INPUT_TIMEOUT_MS, Tt as saveProviderStore, U as createAnimaTools, Ut as writeRestartSentinel, V as requestHeartbeatNow, Vn as runSubagentAnnounceFlow, Vt as summarizeRestartSentinel, W as resolveAnnounceTargetFromKey, Wt as normalizeCronJobCreate, X as pruneLegacyStoreKeys, Xn as registerAgentRunContext, Xt as normalizeRequiredName, Y as loadSessionEntry, Yn as onAgentEvent, Yt as normalizePayloadToSystemText, Z as resolveGatewaySessionStoreTarget, Zn as resolveAgentIdentity, Zt as migrateLegacyCronPayload, _ as approveNodePairing, _n as dispatchInboundMessage, _r as DEFAULT_INPUT_FILE_MAX_CHARS, _t as resetDirectoryCache, an as persistBrowserProxyFiles, ar as applyVerboseOverride, at as stripEnvelopeFromMessages, b as renamePairedNode, br as DEFAULT_INPUT_IMAGE_MIMES, bt as runWithModelFallback, c as normalizeSendPolicy, cr as isSystemEventContextChanged, d as primeRemoteSkillsCache, dr as loadModelCatalog, dt as resolveOutboundSessionRoute, en as buildSafeExternalPrompt, et as archiveSessionTranscripts, f as recordRemoteNodeInfo, g as setSkillsRemoteRegistry, gr as DEFAULT_INPUT_FILE_MAX_BYTES, h as removeRemoteNodeInfo, ht as resolveSessionDeliveryTarget, i as setCliSessionId, in as applyBrowserProxyPaths, ir as applyModelOverrideToSessionEntry, it as resolveSessionTranscriptCandidates, j as getTotalQueueSize, jt as emitGatewayRestart, k as getActiveTaskCount, kn as formatZonedTimestamp, kr as estimateBase64DecodedBytes, kt as consumeGatewaySigusr1RestartAuthorization, l as resolveSendPolicy, m as refreshRemoteNodeBins, mr as registerUnhandledRejectionHandler, mt as resolveOutboundTarget, n as BARE_SESSION_RESET_PROMPT, nn as getHookType, nr as lookupContextTokens, nt as readSessionMessages, on as getPluginToolMeta, or as parseVerboseOverride, p as refreshRemoteBinsForConnectedNodes, pn as getChannelActivity, q as listSessionsFromStore, qn as emitAgentEvent, qt as normalizeOptionalAgentId, r as getCliSessionId, rn as isExternalHookSession, rt as readSessionPreviewItemsFromTranscript, sn as loadAnimaPlugins, sr as enqueueSystemEvent, st as normalizeGroupActivation, tn as detectSuspiciousPatterns, tt as capArrayByJsonBytes, u as getRemoteSkillEligibility, ut as ensureOutboundSessionEntry, v as listNodePairing, vn as createReplyDispatcher, vr as DEFAULT_INPUT_FILE_MIMES, vt as resolveMessageChannelSelection, w as generatePairingToken, wn as isDiagnosticsEnabled, wr as DEFAULT_INPUT_PDF_MIN_TEXT_CHARS, wt as maskApiKey, x as requestNodePairing, xr as DEFAULT_INPUT_MAX_REDIRECTS, xt as resolveWorkingModeModelSelection, y as rejectNodePairing, yn as getTotalPendingReplies, yr as DEFAULT_INPUT_IMAGE_MAX_BYTES, z as buildDefaultToolPolicyPipelineSteps, zn as listDescendantRunsForRequester, zt as formatRestartSentinelMessage } from "./reply-ylwOKuOF.js";
2
+ import { D as getActivePluginRegistry, G as getResolvedLoggerSettings, I as setVerbose, K as setLoggerOverride, U as getChildLogger, W as getLogger, _ as CHANNEL_IDS, f as defaultRuntime, i as getResolvedConsoleSettings, n as runtimeForLogger, o as setConsoleSubsystemFilter, s as setConsoleTimestampPrefix, t as createSubsystemLogger, y as DEFAULT_CHAT_CHANNEL } from "./subsystem-DLVQ9bjX.js";
3
+ import { C as shortenHomePath, D as truncateUtf16Safe, b as resolveUserPath, c as ensureDir$1, d as isPlainObject, r as clamp, t as CONFIG_DIR } from "./utils-CkCznJhR.js";
4
+ import { C as supportsXHighThinking, _ as normalizeElevatedLevel, b as normalizeUsageDisplay, m as formatXHighModelHint, p as formatThinkingLevels, v as normalizeReasoningLevel, x as normalizeVerboseLevel, y as normalizeThinkLevel } from "./pi-embedded-helpers-BPtBCnl-.js";
5
+ import { $ as resolveGatewaySessionStoreTarget, $n as resolveAgentIdentity, $t as migrateLegacyCronPayload, Ar as normalizeMimeList, B as applyToolPolicyPipeline, Bn as initSubagentRegistry, Bt as formatDoctorNonInteractiveHint, C as verifyNodeToken, Cr as DEFAULT_INPUT_MAX_REDIRECTS, Ct as resolveWorkingModeModelSelection, D as registerSkillsChangeListener, Dr as DEFAULT_INPUT_TIMEOUT_MS, Dt as saveProviderStore, E as getSkillsSnapshotVersion, En as isDiagnosticsEnabled, Er as DEFAULT_INPUT_PDF_MIN_TEXT_CHARS, Et as maskApiKey, F as abortEmbeddedPiRun, Fn as stopSubagentsForRequester, Ft as markGatewaySigusr1RestartHandled, G as createAnimaTools, Gt as writeRestartSentinel, H as sniffMimeFromBase64, I as waitForEmbeddedPiRunEnd, It as scheduleGatewaySigusr1Restart, J as listAgentsForGateway, Jn as clearAgentRunContext, Jt as inferLegacyName, K as resolveAnnounceTargetFromKey, Kt as normalizeCronJobCreate, L as runNoxSoftEmbeddedAgent, Lt as setGatewaySigusr1RestartPolicy, M as resetAllLanes, Mt as deferGatewayRestartUntilIdle, N as setCommandLaneConcurrency, Nt as emitGatewayRestart, O as clearSessionQueues, Or as extractFileContentFromSource, P as waitForActiveTasks, Pn as isAbortTrigger, Pr as resolveAgentTimeoutMs, Pt as isGatewaySigusr1RestartExternallyAllowed, Q as pruneLegacyStoreKeys, Qn as registerAgentRunContext, Qt as normalizeRequiredName, Rt as setPreRestartDeferralCheck, S as updatePairedNodeMetadata, Sr as DEFAULT_INPUT_IMAGE_MIMES, St as runWithModelFallback, T as verifyPairingToken, Tn as stopDiagnosticHeartbeat, Tr as DEFAULT_INPUT_PDF_MAX_PIXELS, Tt as loadProviderStore, U as requestHeartbeatNow, Un as runSubagentAnnounceFlow, Ut as summarizeRestartSentinel, V as buildDefaultToolPolicyPipelineSteps, Vn as listDescendantRunsForRequester, Vt as formatRestartSentinelMessage, Wn as readLatestAssistantReply, X as loadCombinedSessionStoreForGateway, Xn as getAgentRunContext, Xt as normalizeOptionalText, Y as listSessionsFromStore, Yn as emitAgentEvent, Yt as normalizeOptionalAgentId, Z as loadSessionEntry, Zn as onAgentEvent, Zt as normalizePayloadToSystemText, _ as approveNodePairing, _t as resolveSessionDeliveryTarget, an as isExternalHookSession, at as readSessionPreviewItemsFromTranscript, b as renamePairedNode, bn as createReplyDispatcher, br as DEFAULT_INPUT_FILE_MIMES, bt as resolveMessageChannelSelection, c as normalizeSendPolicy, cn as getPluginToolMeta, cr as parseVerboseOverride, d as primeRemoteSkillsCache, et as resolveSessionModelRef, f as recordRemoteNodeInfo, ft as ensureOutboundSessionEntry, g as setSkillsRemoteRegistry, gr as registerUnhandledRejectionHandler, gt as resolveOutboundTarget, h as removeRemoteNodeInfo, hn as getChannelActivity, i as setCliSessionId, in as getHookType, ir as lookupContextTokens, it as readSessionMessages, j as getTotalQueueSize, jn as formatZonedTimestamp, jr as estimateBase64DecodedBytes, jt as consumeGatewaySigusr1RestartAuthorization, k as getActiveTaskCount, kr as extractImageContentFromSource, l as resolveSendPolicy, ln as loadAnimaPlugins, lr as enqueueSystemEvent, lt as normalizeGroupActivation, m as refreshRemoteNodeBins, n as BARE_SESSION_RESET_PROMPT, nn as buildSafeExternalPrompt, nt as archiveSessionTranscripts, on as applyBrowserProxyPaths, or as applyModelOverrideToSessionEntry, ot as resolveSessionTranscriptCandidates, p as refreshRemoteBinsForConnectedNodes, pr as loadModelCatalog, pt as resolveOutboundSessionRoute, q as canonicalizeSpawnedByForAgent, qn as CommandLane, qt as normalizeCronJobPatch, r as getCliSessionId, rn as detectSuspiciousPatterns, rt as capArrayByJsonBytes, sn as persistBrowserProxyFiles, sr as applyVerboseOverride, st as stripEnvelopeFromMessages, tt as archiveFileOnDisk, u as getRemoteSkillEligibility, ur as isSystemEventContextChanged, v as listNodePairing, vr as DEFAULT_INPUT_FILE_MAX_BYTES, w as generatePairingToken, wn as startDiagnosticHeartbeat, wr as DEFAULT_INPUT_PDF_MAX_PAGES, wt as loadProviderUsageSummary, x as requestNodePairing, xn as getTotalPendingReplies, xr as DEFAULT_INPUT_IMAGE_MAX_BYTES, y as rejectNodePairing, yn as dispatchInboundMessage, yr as DEFAULT_INPUT_FILE_MAX_CHARS, yt as resetDirectoryCache, zn as countActiveDescendantRuns, zt as consumeRestartSentinel } from "./reply-DqXPXQ20.js";
6
6
  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-DAZmp8ll.js";
7
- import { a as logDebug, c as logWarn, n as runExec, t as runCommandWithTimeout } from "./exec-BylR5qWS.js";
7
+ import { a as logDebug, c as logWarn, n as runExec, t as runCommandWithTimeout } from "./exec-ChPERQB-.js";
8
8
  import { t as resolveAnimaPackageRoot } from "./anima-root-xWSKR6Wm.js";
9
- 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-CXxC8FFX.js";
10
- 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-CY6r_3wt.js";
11
- 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-DaD4FsAn.js";
12
- import { n as logAcceptedEnvOption, t as isTruthyEnvValue } from "./env-DlTia1B4.js";
13
- import { c as isTestDefaultMemorySlotDisabled } from "./manifest-registry-qF960vMH.js";
14
- import { A as resolveMainSessionKeyFromConfig, D as resolveAgentMainSessionKey, M as snapshotSessionOrigin, O as resolveExplicitAgentSessionKey, d as deliveryContextFromSession, h as normalizeSessionDeliveryFields, i as loadSessionStore, k as resolveMainSessionKey, l as updateSessionStore, p as mergeDeliveryContext, t as extractDeliveryInfo } from "./sessions-BOzeFzuL.js";
15
- import { o as detectMime } from "./image-ops-Ct3GueyT.js";
16
- import { t as normalizePollInput } from "./polls-DFISjV7H.js";
17
- import { _ as resolveToolProfilePolicy, p as collectExplicitAllowlist } from "./sandbox-pBHlfFdB.js";
9
+ 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-DQ0N_hof.js";
10
+ 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-CeZMza3d.js";
11
+ 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-MZ5clMl4.js";
12
+ import { n as logAcceptedEnvOption, t as isTruthyEnvValue } from "./env-ByZjwIJR.js";
13
+ import { c as isTestDefaultMemorySlotDisabled } from "./manifest-registry-Cwvk5hu8.js";
14
+ import { A as resolveMainSessionKeyFromConfig, D as resolveAgentMainSessionKey, M as snapshotSessionOrigin, O as resolveExplicitAgentSessionKey, d as deliveryContextFromSession, h as normalizeSessionDeliveryFields, i as loadSessionStore, k as resolveMainSessionKey, l as updateSessionStore, p as mergeDeliveryContext, t as extractDeliveryInfo } from "./sessions-DBQx8E1H.js";
15
+ import { o as detectMime } from "./image-ops-vj06APeW.js";
16
+ import { t as normalizePollInput } from "./polls-aumqIVob.js";
17
+ import { _ as resolveToolProfilePolicy, p as collectExplicitAllowlist } from "./sandbox-mSWYRXFm.js";
18
18
  import { t as formatCliCommand } from "./command-format-BCtkuvqF.js";
19
- 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-DsC5pZ_0.js";
19
+ 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-CuGlMw6p.js";
20
20
  import { n as pickPrimaryTailnetIPv6, t as pickPrimaryTailnetIPv4 } from "./tailnet-Bg_vE5qi.js";
21
21
  import { a as isTrustedProxyAddress, c as pickPrimaryLanIPv4, d as resolveGatewayListenHosts, i as isPrivateOrLoopbackAddress, l as resolveGatewayBindHost, n as isLoopbackAddress, r as isLoopbackHost, t as rawDataToString, u as resolveGatewayClientIp } from "./ws-BapRHqfx.js";
22
- import { r as movePathToTrash } from "./server-context-Yx4pgBqJ.js";
23
- import { i as loadWorkspaceSkillEntries, r as buildWorkspaceSkillSnapshot, x as hasBinary } from "./skills-4v6-kw0C.js";
22
+ import { r as movePathToTrash } from "./server-context-DTlBzMyD.js";
23
+ import { i as loadWorkspaceSkillEntries, r as buildWorkspaceSkillSnapshot, x as hasBinary } from "./skills-DjVFhlQY.js";
24
24
  import { n as formatErrorMessage } from "./errors-Bv81hF2P.js";
25
- import { a as inspectPortUsage, s as formatPortDiagnostics } from "./ports-q535r1PZ.js";
26
- 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-CMsexA3K.js";
27
- import { n as listChannelPlugins, r as normalizeChannelId, t as getChannelPlugin } from "./plugins-DYcg0qBW.js";
25
+ import { a as inspectPortUsage, s as formatPortDiagnostics } from "./ports-B20JTuiL.js";
26
+ 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-CfwNj8mC.js";
27
+ import { n as listChannelPlugins, r as normalizeChannelId, t as getChannelPlugin } from "./plugins-BqPGs8w-.js";
28
28
  import { c as resolveStorePath, i as resolveSessionTranscriptPath, n as resolveSessionFilePath, r as resolveSessionFilePathOptions, s as resolveSessionTranscriptsDirForAgent } from "./paths-Dazi-gYo.js";
29
- import { O as normalizeSecretInput } from "./auth-profiles-C-LuhW6c.js";
30
- import { n as SILENT_REPLY_TOKEN, r as isSilentReplyText } from "./tokens-SP2Q7i59.js";
31
- 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-C5pnwYzT.js";
32
- import { o as normalizeReplyPayloadsForDelivery, t as deliverOutboundPayloads, x as runGlobalGatewayStopSafely, y as getGlobalHookRunner } from "./deliver-BKzX3YoN.js";
33
- import { i as resolveMemoryBackendConfig, r as getMemorySearchManager } from "./memory-cli-DLtBA6r5.js";
29
+ import { O as normalizeSecretInput } from "./auth-profiles-XI2YBb-w.js";
30
+ import { n as SILENT_REPLY_TOKEN, r as isSilentReplyText } from "./tokens-BelyD23F.js";
31
+ 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-BgFOZS8B.js";
32
+ import { o as normalizeReplyPayloadsForDelivery, t as deliverOutboundPayloads, x as runGlobalGatewayStopSafely, y as getGlobalHookRunner } from "./deliver-BknvuSJz.js";
33
+ import { i as resolveMemoryBackendConfig, r as getMemorySearchManager } from "./memory-cli-DMJqELwh.js";
34
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-Bw2wdN4l.js";
35
- import { t as ToolInputError } from "./common-BCW6hLGI.js";
36
- 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-BWkoTfOH.js";
37
- import { s as loadGatewayTlsRuntime$1 } from "./call-CDPbPDAr.js";
38
- import { a as resolveSubagentToolPolicy, i as resolveGroupToolPolicy, r as resolveEffectiveToolPolicy } from "./pi-tools.policy-WdTAfqbV.js";
39
- import { n as createBrowserControlContext, r as startBrowserControlServiceFromConfig } from "./control-service-5YtMvm7D.js";
40
- import { t as createBrowserRouteDispatcher } from "./dispatcher-DzwzLQRk.js";
35
+ import { t as ToolInputError } from "./common-fIXNXke2.js";
36
+ 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-DOTb2PN6.js";
37
+ import { s as loadGatewayTlsRuntime$1 } from "./call-Bn9iKzhX.js";
38
+ import { a as resolveSubagentToolPolicy, i as resolveGroupToolPolicy, r as resolveEffectiveToolPolicy } from "./pi-tools.policy-DuWNVoem.js";
39
+ import { n as createBrowserControlContext, r as startBrowserControlServiceFromConfig } from "./control-service-BGnqY7vv.js";
40
+ import { t as createBrowserRouteDispatcher } from "./dispatcher-DpEzmU7s.js";
41
41
  import { t as parseAbsoluteTimeMs } from "./parse-Cinbkvj-.js";
42
42
  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-CE75mBXE.js";
43
43
  import { i as loadSessionUsageTimeSeries, l as deriveSessionTotalTokens, n as loadCostUsageSummary, r as loadSessionCostSummary, t as discoverAllSessions, u as hasNonzeroUsage } from "./session-cost-usage-BWqR-ik6.js";
44
44
  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-DK5-KCUz.js";
45
- import { c as resolveCronStyleNow, i as onHeartbeatEvent, r as getLastHeartbeatEvent, t as resolveHeartbeatVisibility } from "./heartbeat-visibility-BaL8JzkS.js";
46
- import { r as buildHistoryContextFromEntries, t as createReplyPrefixOptions } from "./reply-prefix-CEnF6TUe.js";
47
- import { n as createOutboundSendDeps, t as createDefaultDeps } from "./deps-DKPoFoa8.js";
48
- import { t as ensureAnimaCliOnPath } from "./path-env-DLQPf9qj.js";
49
- import { t as forceFreePortAndWait } from "./ports-DaVrZDUq.js";
50
- import { t as buildChannelUiCatalog } from "./catalog-CsXv59Tq.js";
51
- import { t as buildWorkspaceSkillStatus } from "./skills-status-CvH7AUoY.js";
45
+ import { c as resolveCronStyleNow, i as onHeartbeatEvent, r as getLastHeartbeatEvent, t as resolveHeartbeatVisibility } from "./heartbeat-visibility-DZOi_4uV.js";
46
+ import { r as buildHistoryContextFromEntries, t as createReplyPrefixOptions } from "./reply-prefix-CZy4g8SY.js";
47
+ import { n as createOutboundSendDeps, t as createDefaultDeps } from "./deps-oUYlT5Sq.js";
48
+ import { t as ensureAnimaCliOnPath } from "./path-env-BAjR_Xf_.js";
49
+ import { t as forceFreePortAndWait } from "./ports-D6bjtvhF.js";
50
+ import { t as buildChannelUiCatalog } from "./catalog-BqTvQqiq.js";
51
+ import { t as buildWorkspaceSkillStatus } from "./skills-status-BmZufjT1.js";
52
52
  import { n as DEFAULT_GATEWAY_HTTP_TOOL_DENY } from "./dangerous-tools-BCnOEYau.js";
53
- 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-CJ3HzoUO.js";
54
- import { t as resolveGatewayService } from "./service-Dd1DfPia.js";
53
+ 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-rHLFiSIc.js";
54
+ import { t as resolveGatewayService } from "./service-ho_k2vjr.js";
55
55
  import { t as parsePort } from "./parse-port-CDPwDUs3.js";
56
- import { n as resolveWideAreaDiscoveryDomain, r as writeWideAreaGatewayZone } from "./widearea-dns-CHAT20aR.js";
57
- import { i as toOptionString, n as extractGatewayMiskeys, r as maybeExplainGatewayServiceStop, t as describeUnknownError } from "./shared-C-rqLtIT.js";
58
- import { o as isNodeCommandAllowed, s as resolveNodeCommandAllowlist } from "./audit-B05W5ckN.js";
59
- import { n as getStatusSummary } from "./status-BhRELdY_.js";
56
+ import { n as resolveWideAreaDiscoveryDomain, r as writeWideAreaGatewayZone } from "./widearea-dns-DlJrNJOg.js";
57
+ import { i as toOptionString, n as extractGatewayMiskeys, r as maybeExplainGatewayServiceStop, t as describeUnknownError } from "./shared-BFzq0XE1.js";
58
+ import { o as isNodeCommandAllowed, s as resolveNodeCommandAllowlist } from "./audit-jddM3B16.js";
59
+ import { n as getStatusSummary } from "./status-D1zupVBm.js";
60
60
  import { t as resolveChannelDefaultAccountId } from "./helpers-1MPChTcB.js";
61
- import { c as startHeartbeatRunner, n as getHealthSnapshot, o as runHeartbeatOnce, s as setHeartbeatsEnabled } from "./health-yw_uaucz.js";
62
- import { t as applyPluginAutoEnable } from "./plugin-auto-enable-CtYcdTju.js";
63
- import { a as resolveControlUiRootOverrideSync, n as ensureControlUiAssetsBuilt, o as resolveControlUiRootSync } from "./health-format-D-JJ5_S4.js";
61
+ import { c as startHeartbeatRunner, n as getHealthSnapshot, o as runHeartbeatOnce, s as setHeartbeatsEnabled } from "./health-DrokrOLQ.js";
62
+ import { t as applyPluginAutoEnable } from "./plugin-auto-enable-DvYJhgJ2.js";
63
+ import { a as resolveControlUiRootOverrideSync, n as ensureControlUiAssetsBuilt, o as resolveControlUiRootSync } from "./health-format-CzNDrJ8Z.js";
64
64
  import { n as validateSystemRunCommandConsistency, r as getMachineDisplayName, t as formatExecCommand } from "./system-run-command-Bx8-5h2r.js";
65
- import { h as normalizeUpdateChannel, l as DEFAULT_PACKAGE_CHANNEL, n as checkUpdateStatus, o as resolveNpmChannelTag, r as compareSemverStrings } from "./channels-status-issues-WkG3Tmxk.js";
66
- import { t as WizardCancelledError } from "./prompts-Bq4QGFQM.js";
67
- import { i as shouldIncludeHook, n as loadWorkspaceHookEntries, r as resolveHookConfig } from "./hooks-status-DdweuSIj.js";
68
- import { t as runOnboardingWizard } from "./onboarding-fnZOw6Wv.js";
69
- import { a as setGatewayWsLogStyle, i as summarizeAgentEventForWsLog, n as logWs, r as shouldLogWs, t as formatForLog } from "./ws-log-CUobU2tD.js";
70
- import { T as resolveGmailHookRuntimeConfig, _ as buildGogWatchServeArgs, i as ensureTailscaleEndpoint, v as buildGogWatchStartArgs } from "./gmail-setup-utils-DaJoXV_3.js";
65
+ import { h as normalizeUpdateChannel, l as DEFAULT_PACKAGE_CHANNEL, n as checkUpdateStatus, o as resolveNpmChannelTag, r as compareSemverStrings } from "./channels-status-issues-4XxYhQ8S.js";
66
+ import { t as WizardCancelledError } from "./prompts-D6Xc1Ddb.js";
67
+ import { i as shouldIncludeHook, n as loadWorkspaceHookEntries, r as resolveHookConfig } from "./hooks-status-BQ7M6bIq.js";
68
+ import { t as runOnboardingWizard } from "./onboarding-BGXbXgds.js";
69
+ import { a as setGatewayWsLogStyle, i as summarizeAgentEventForWsLog, n as logWs, r as shouldLogWs, t as formatForLog } from "./ws-log-Cvz4xRCD.js";
70
+ import { T as resolveGmailHookRuntimeConfig, _ as buildGogWatchServeArgs, i as ensureTailscaleEndpoint, v as buildGogWatchStartArgs } from "./gmail-setup-utils-lTV5KDPF.js";
71
71
  import { t as createOutboundSendDeps$1 } from "./outbound-send-deps-DVfWC4E8.js";
72
- import { a as loadAgentIdentity, c as loadAgentIdentityFromWorkspace, i as listAgentEntries, o as pruneAgentConfig, r as findAgentEntryIndex, t as applyAgentConfig } from "./agents.config-BR5JLtud.js";
73
- import { n as resolveAgentDeliveryPlan, r as resolveAgentOutboundTarget, t as agentCommand } from "./agent-BjD_hkGZ.js";
72
+ import { a as loadAgentIdentity, c as loadAgentIdentityFromWorkspace, i as listAgentEntries, o as pruneAgentConfig, r as findAgentEntryIndex, t as applyAgentConfig } from "./agents.config-DrViQjgD.js";
73
+ import { n as resolveAgentDeliveryPlan, r as resolveAgentOutboundTarget, t as agentCommand } from "./agent-xPFmA8jO.js";
74
74
  import { t as migrateFromCoherence } from "./migrate-DuohB_ur.js";
75
- import { t as installSkill } from "./skills-install-D6_qpRjW.js";
76
- import { t as runGatewayUpdate } from "./update-runner-C8SRcVm3.js";
75
+ import { t as installSkill } from "./skills-install-CVWWsOf2.js";
76
+ import { t as runGatewayUpdate } from "./update-runner-C7CjKcMp.js";
77
77
  import { fileURLToPath, pathToFileURL } from "node:url";
78
78
  import * as fsSync from "node:fs";
79
79
  import fs, { constants } from "node:fs";
@@ -111,7 +111,7 @@ function getActiveEmbeddedRunCount() {
111
111
 
112
112
  //#endregion
113
113
  //#region src/infra/exec-approval-forwarder.ts
114
- const log$12 = createSubsystemLogger("gateway/exec-approvals");
114
+ const log$14 = createSubsystemLogger("gateway/exec-approvals");
115
115
  const DEFAULT_MODE = "session";
116
116
  function normalizeMode(mode) {
117
117
  return mode ?? DEFAULT_MODE;
@@ -226,7 +226,7 @@ async function deliverToTargets(params) {
226
226
  payloads: [{ text: params.text }]
227
227
  });
228
228
  } catch (err) {
229
- log$12.error(`exec approvals: failed to deliver to ${channel}:${target.to}: ${String(err)}`);
229
+ log$14.error(`exec approvals: failed to deliver to ${channel}:${target.to}: ${String(err)}`);
230
230
  }
231
231
  });
232
232
  await Promise.allSettled(deliveries);
@@ -1463,7 +1463,7 @@ function createAgentEventHandler({ broadcast, broadcastToConnIds, nodeSendToSess
1463
1463
  * Automatically starts `gog gmail watch serve` when the gateway starts,
1464
1464
  * if hooks.gmail is configured with an account.
1465
1465
  */
1466
- const log$11 = createSubsystemLogger("gmail-watcher");
1466
+ const log$13 = createSubsystemLogger("gmail-watcher");
1467
1467
  const ADDRESS_IN_USE_RE = /address already in use|EADDRINUSE/i;
1468
1468
  function isAddressInUseError(line) {
1469
1469
  return ADDRESS_IN_USE_RE.test(line);
@@ -1487,13 +1487,13 @@ async function startGmailWatch(cfg) {
1487
1487
  const result = await runCommandWithTimeout(args, { timeoutMs: 12e4 });
1488
1488
  if (result.code !== 0) {
1489
1489
  const message = result.stderr || result.stdout || "gog watch start failed";
1490
- log$11.error(`watch start failed: ${message}`);
1490
+ log$13.error(`watch start failed: ${message}`);
1491
1491
  return false;
1492
1492
  }
1493
- log$11.info(`watch started for ${cfg.account}`);
1493
+ log$13.info(`watch started for ${cfg.account}`);
1494
1494
  return true;
1495
1495
  } catch (err) {
1496
- log$11.error(`watch start error: ${String(err)}`);
1496
+ log$13.error(`watch start error: ${String(err)}`);
1497
1497
  return false;
1498
1498
  }
1499
1499
  }
@@ -1502,7 +1502,7 @@ async function startGmailWatch(cfg) {
1502
1502
  */
1503
1503
  function spawnGogServe(cfg) {
1504
1504
  const args = buildGogWatchServeArgs(cfg);
1505
- log$11.info(`starting gog ${args.join(" ")}`);
1505
+ log$13.info(`starting gog ${args.join(" ")}`);
1506
1506
  let addressInUse = false;
1507
1507
  const child = spawn("gog", args, {
1508
1508
  stdio: [
@@ -1514,25 +1514,25 @@ function spawnGogServe(cfg) {
1514
1514
  });
1515
1515
  child.stdout?.on("data", (data) => {
1516
1516
  const line = data.toString().trim();
1517
- if (line) log$11.info(`[gog] ${line}`);
1517
+ if (line) log$13.info(`[gog] ${line}`);
1518
1518
  });
1519
1519
  child.stderr?.on("data", (data) => {
1520
1520
  const line = data.toString().trim();
1521
1521
  if (!line) return;
1522
1522
  if (isAddressInUseError(line)) addressInUse = true;
1523
- log$11.warn(`[gog] ${line}`);
1523
+ log$13.warn(`[gog] ${line}`);
1524
1524
  });
1525
1525
  child.on("error", (err) => {
1526
- log$11.error(`gog process error: ${String(err)}`);
1526
+ log$13.error(`gog process error: ${String(err)}`);
1527
1527
  });
1528
1528
  child.on("exit", (code, signal) => {
1529
1529
  if (shuttingDown) return;
1530
1530
  if (addressInUse) {
1531
- 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.");
1531
+ 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.");
1532
1532
  watcherProcess = null;
1533
1533
  return;
1534
1534
  }
1535
- log$11.warn(`gog exited (code=${code}, signal=${signal}); restarting in 5s`);
1535
+ log$13.warn(`gog exited (code=${code}, signal=${signal}); restarting in 5s`);
1536
1536
  watcherProcess = null;
1537
1537
  setTimeout(() => {
1538
1538
  if (shuttingDown || !currentConfig) return;
@@ -1572,15 +1572,15 @@ async function startGmailWatcher(cfg) {
1572
1572
  port: runtimeConfig.serve.port,
1573
1573
  target: runtimeConfig.tailscale.target
1574
1574
  });
1575
- log$11.info(`tailscale ${runtimeConfig.tailscale.mode} configured for port ${runtimeConfig.serve.port}`);
1575
+ log$13.info(`tailscale ${runtimeConfig.tailscale.mode} configured for port ${runtimeConfig.serve.port}`);
1576
1576
  } catch (err) {
1577
- log$11.error(`tailscale setup failed: ${String(err)}`);
1577
+ log$13.error(`tailscale setup failed: ${String(err)}`);
1578
1578
  return {
1579
1579
  started: false,
1580
1580
  reason: `tailscale setup failed: ${String(err)}`
1581
1581
  };
1582
1582
  }
1583
- if (!await startGmailWatch(runtimeConfig)) log$11.warn("gmail watch start failed, but continuing with serve");
1583
+ if (!await startGmailWatch(runtimeConfig)) log$13.warn("gmail watch start failed, but continuing with serve");
1584
1584
  shuttingDown = false;
1585
1585
  watcherProcess = spawnGogServe(runtimeConfig);
1586
1586
  const renewMs = runtimeConfig.renewEveryMinutes * 6e4;
@@ -1588,7 +1588,7 @@ async function startGmailWatcher(cfg) {
1588
1588
  if (shuttingDown) return;
1589
1589
  startGmailWatch(runtimeConfig);
1590
1590
  }, renewMs);
1591
- log$11.info(`gmail watcher started for ${runtimeConfig.account} (renew every ${runtimeConfig.renewEveryMinutes}m)`);
1591
+ log$13.info(`gmail watcher started for ${runtimeConfig.account} (renew every ${runtimeConfig.renewEveryMinutes}m)`);
1592
1592
  return { started: true };
1593
1593
  }
1594
1594
  /**
@@ -1601,7 +1601,7 @@ async function stopGmailWatcher() {
1601
1601
  renewInterval = null;
1602
1602
  }
1603
1603
  if (watcherProcess) {
1604
- log$11.info("stopping gmail watcher");
1604
+ log$13.info("stopping gmail watcher");
1605
1605
  watcherProcess.kill("SIGTERM");
1606
1606
  await new Promise((resolve) => {
1607
1607
  const timeout = setTimeout(() => {
@@ -1616,7 +1616,7 @@ async function stopGmailWatcher() {
1616
1616
  watcherProcess = null;
1617
1617
  }
1618
1618
  currentConfig = null;
1619
- log$11.info("gmail watcher stopped");
1619
+ log$13.info("gmail watcher stopped");
1620
1620
  }
1621
1621
 
1622
1622
  //#endregion
@@ -4894,6 +4894,8 @@ const BASE_METHODS = [
4894
4894
  "anima.registration.status",
4895
4895
  "anima.registration.set-token",
4896
4896
  "anima.registration.register-invite",
4897
+ "ico.metrics.get",
4898
+ "impact.footprint.get",
4897
4899
  "health",
4898
4900
  "logs.tail",
4899
4901
  "channels.status",
@@ -4978,7 +4980,14 @@ const BASE_METHODS = [
4978
4980
  "agent",
4979
4981
  "agent.identity.get",
4980
4982
  "agent.wait",
4983
+ "browser.capabilities.get",
4981
4984
  "browser.request",
4985
+ "desktop.control.session.create",
4986
+ "desktop.control.session.list",
4987
+ "desktop.control.session.get",
4988
+ "desktop.control.session.approve",
4989
+ "desktop.control.session.close",
4990
+ "desktop.control.session.request",
4982
4991
  "chat.history",
4983
4992
  "chat.abort",
4984
4993
  "chat.send"
@@ -8260,6 +8269,44 @@ function safeParseJson(value) {
8260
8269
 
8261
8270
  //#endregion
8262
8271
  //#region src/gateway/server-methods/browser.ts
8272
+ const DESKTOP_CONTROL_DEFAULT_TTL_MS = 900 * 1e3;
8273
+ const DESKTOP_CONTROL_MIN_TTL_MS = 60 * 1e3;
8274
+ const DESKTOP_CONTROL_MAX_TTL_MS = 14400 * 1e3;
8275
+ const DESKTOP_CONTROL_MAX_REASON_LEN = 240;
8276
+ const DESKTOP_CONTROL_AUDIT_MAX_EVENTS = 200;
8277
+ const DESKTOP_CONTROL_RETENTION_MS = 7200 * 1e3;
8278
+ const DESKTOP_CONTROL_DEFAULT_ALLOWED_METHODS = ["GET"];
8279
+ const DESKTOP_CONTROL_ALLOWED_METHODS = [
8280
+ "GET",
8281
+ "POST",
8282
+ "DELETE"
8283
+ ];
8284
+ const DESKTOP_CONTROL_DEFAULT_MAX_REQUESTS = 40;
8285
+ const DESKTOP_CONTROL_MIN_MAX_REQUESTS = 1;
8286
+ const DESKTOP_CONTROL_MAX_MAX_REQUESTS = 500;
8287
+ const DESKTOP_CONTROL_MAX_NOTE_LEN = 500;
8288
+ const DESKTOP_CONTROL_MIN_DECISION_NOTE_LEN = 8;
8289
+ const DESKTOP_CONTROL_LIST_MIN_LIMIT = 1;
8290
+ const DESKTOP_CONTROL_LIST_MAX_LIMIT = 500;
8291
+ const DESKTOP_CONTROL_LIST_MIN_OFFSET = 0;
8292
+ const DESKTOP_CONTROL_LIST_MAX_OFFSET = 1e4;
8293
+ const BROWSER_REQUEST_MIN_TIMEOUT_MS = 1;
8294
+ const BROWSER_REQUEST_MAX_TIMEOUT_MS = 12e4;
8295
+ const DESKTOP_CONTROL_SESSION_STATES = [
8296
+ "pending_approval",
8297
+ "active",
8298
+ "denied",
8299
+ "closed",
8300
+ "expired"
8301
+ ];
8302
+ const DESKTOP_CONTROL_SESSION_DECISIONS = [
8303
+ "pending",
8304
+ "allow",
8305
+ "deny"
8306
+ ];
8307
+ const DESKTOP_CONTROL_SESSION_ROUTE_KINDS = ["local", "node"];
8308
+ const DESKTOP_CONTROL_SESSION_RISK_LEVELS = ["standard", "elevated"];
8309
+ const desktopControlSessions = /* @__PURE__ */ new Map();
8263
8310
  function isBrowserNode(node) {
8264
8311
  const caps = Array.isArray(node.caps) ? node.caps : [];
8265
8312
  const commands = Array.isArray(node.commands) ? node.commands : [];
@@ -8309,32 +8356,264 @@ async function persistProxyFiles(files) {
8309
8356
  function applyProxyPaths(result, mapping) {
8310
8357
  applyBrowserProxyPaths(result, mapping);
8311
8358
  }
8312
- const browserHandlers = { "browser.request": async ({ params, respond, context }) => {
8313
- const typed = params;
8314
- const methodRaw = typeof typed.method === "string" ? typed.method.trim().toUpperCase() : "";
8315
- const path = typeof typed.path === "string" ? typed.path.trim() : "";
8316
- const query = typed.query && typeof typed.query === "object" ? typed.query : void 0;
8317
- const body = typed.body;
8318
- const timeoutMs = typeof typed.timeoutMs === "number" && Number.isFinite(typed.timeoutMs) ? Math.max(1, Math.floor(typed.timeoutMs)) : void 0;
8319
- if (!methodRaw || !path) {
8320
- respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "method and path are required"));
8321
- return;
8359
+ function toNodeSummary(node) {
8360
+ return {
8361
+ nodeId: node.nodeId,
8362
+ displayName: node.displayName ?? null,
8363
+ remoteIp: node.remoteIp ?? null
8364
+ };
8365
+ }
8366
+ function hasValue(value) {
8367
+ return typeof value === "string" && value.trim().length > 0;
8368
+ }
8369
+ function resolveGatewayAuthMode(cfg) {
8370
+ const configuredMode = cfg.gateway?.auth?.mode;
8371
+ if (configuredMode === "token" || configuredMode === "password" || configuredMode === "trusted-proxy") return configuredMode;
8372
+ if (hasValue(cfg.gateway?.auth?.token)) return "token";
8373
+ if (hasValue(cfg.gateway?.auth?.password)) return "password";
8374
+ if (hasValue(cfg.gateway?.auth?.trustedProxy?.userHeader)) return "trusted-proxy";
8375
+ return "none";
8376
+ }
8377
+ function resolveClientActor(client) {
8378
+ const displayName = client?.connect?.client?.displayName;
8379
+ if (typeof displayName === "string" && displayName.trim().length > 0) return displayName.trim();
8380
+ const clientId = client?.connect?.client?.id;
8381
+ if (typeof clientId === "string" && clientId.trim().length > 0) return clientId.trim();
8382
+ const deviceId = client?.connect?.device?.id;
8383
+ if (typeof deviceId === "string" && deviceId.trim().length > 0) return deviceId.trim();
8384
+ return null;
8385
+ }
8386
+ function hasOperatorScope(client, scope) {
8387
+ const scopes = Array.isArray(client?.connect?.scopes) ? client?.connect?.scopes : [];
8388
+ return scopes.includes("operator.admin") || scopes.includes(scope);
8389
+ }
8390
+ function normalizeDesktopSessionTtl(input) {
8391
+ if (typeof input !== "number" || !Number.isFinite(input)) return DESKTOP_CONTROL_DEFAULT_TTL_MS;
8392
+ return Math.min(DESKTOP_CONTROL_MAX_TTL_MS, Math.max(DESKTOP_CONTROL_MIN_TTL_MS, Math.floor(input)));
8393
+ }
8394
+ function normalizeDesktopSessionReason(input) {
8395
+ if (typeof input !== "string") return "Desktop control session";
8396
+ const trimmed = input.trim();
8397
+ if (!trimmed) return "Desktop control session";
8398
+ return trimmed.slice(0, DESKTOP_CONTROL_MAX_REASON_LEN);
8399
+ }
8400
+ function normalizeDesktopSessionNote(input) {
8401
+ if (typeof input !== "string") return null;
8402
+ const trimmed = input.trim();
8403
+ if (!trimmed) return null;
8404
+ return trimmed.slice(0, DESKTOP_CONTROL_MAX_NOTE_LEN);
8405
+ }
8406
+ function hasDecisionRationale(note) {
8407
+ return typeof note === "string" && note.length >= DESKTOP_CONTROL_MIN_DECISION_NOTE_LEN;
8408
+ }
8409
+ function isDesktopControlSessionState(value) {
8410
+ return typeof value === "string" && DESKTOP_CONTROL_SESSION_STATES.includes(value);
8411
+ }
8412
+ function isDesktopControlApprovalDecision(value) {
8413
+ return typeof value === "string" && DESKTOP_CONTROL_SESSION_DECISIONS.includes(value);
8414
+ }
8415
+ function isDesktopControlSessionRouteKind(value) {
8416
+ return typeof value === "string" && DESKTOP_CONTROL_SESSION_ROUTE_KINDS.includes(value);
8417
+ }
8418
+ function isDesktopControlSessionRiskLevel(value) {
8419
+ return typeof value === "string" && DESKTOP_CONTROL_SESSION_RISK_LEVELS.includes(value);
8420
+ }
8421
+ function parseDesktopSessionMethod(value) {
8422
+ const method = value.trim().toUpperCase();
8423
+ if (DESKTOP_CONTROL_ALLOWED_METHODS.includes(method)) return method;
8424
+ return null;
8425
+ }
8426
+ function normalizeDesktopSessionAllowMethods(input) {
8427
+ if (!Array.isArray(input)) return [...DESKTOP_CONTROL_DEFAULT_ALLOWED_METHODS];
8428
+ const normalized = [];
8429
+ for (const entry of input) {
8430
+ if (typeof entry !== "string") continue;
8431
+ const method = parseDesktopSessionMethod(entry);
8432
+ if (method && !normalized.includes(method)) normalized.push(method);
8322
8433
  }
8323
- if (methodRaw !== "GET" && methodRaw !== "POST" && methodRaw !== "DELETE") {
8324
- respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "method must be GET, POST, or DELETE"));
8325
- return;
8434
+ if (normalized.length === 0) return [...DESKTOP_CONTROL_DEFAULT_ALLOWED_METHODS];
8435
+ return normalized;
8436
+ }
8437
+ function normalizeDesktopSessionMaxRequests(input) {
8438
+ if (typeof input !== "number" || !Number.isFinite(input)) return DESKTOP_CONTROL_DEFAULT_MAX_REQUESTS;
8439
+ return Math.min(DESKTOP_CONTROL_MAX_MAX_REQUESTS, Math.max(DESKTOP_CONTROL_MIN_MAX_REQUESTS, Math.floor(input)));
8440
+ }
8441
+ function resolveDesktopSessionRisk(controls) {
8442
+ const reasons = [];
8443
+ if (controls.allowMethods.some((method) => method !== "GET")) reasons.push("write methods enabled (POST/DELETE)");
8444
+ if (controls.maxRequests > DESKTOP_CONTROL_DEFAULT_MAX_REQUESTS) reasons.push(`request budget exceeds standard (${controls.maxRequests} > ${DESKTOP_CONTROL_DEFAULT_MAX_REQUESTS})`);
8445
+ return {
8446
+ level: reasons.length > 0 ? "elevated" : "standard",
8447
+ reasons
8448
+ };
8449
+ }
8450
+ function validateDesktopControlSessionCreateParams(params) {
8451
+ if (params.reason !== void 0 && typeof params.reason !== "string") return errorShape(ErrorCodes.INVALID_REQUEST, `invalid reason: ${String(params.reason)}`, { details: { expectedType: "string" } });
8452
+ if (params.ttlMs !== void 0) {
8453
+ 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: {
8454
+ minTtlMs: DESKTOP_CONTROL_MIN_TTL_MS,
8455
+ maxTtlMs: DESKTOP_CONTROL_MAX_TTL_MS
8456
+ } });
8326
8457
  }
8327
- const cfg = loadConfig();
8328
- let nodeTarget = null;
8329
- try {
8330
- nodeTarget = resolveBrowserNodeTarget({
8331
- cfg,
8332
- nodes: context.nodeRegistry.listConnected()
8458
+ if (params.nodeId !== void 0 && typeof params.nodeId !== "string") return errorShape(ErrorCodes.INVALID_REQUEST, `invalid nodeId: ${String(params.nodeId)}`, { details: { expectedType: "string" } });
8459
+ if (typeof params.nodeId === "string" && !params.nodeId.trim()) return errorShape(ErrorCodes.INVALID_REQUEST, "invalid nodeId: must not be empty");
8460
+ if (params.allowMethods !== void 0) {
8461
+ if (!Array.isArray(params.allowMethods)) return errorShape(ErrorCodes.INVALID_REQUEST, `invalid allowMethods: ${String(params.allowMethods)}`, { details: {
8462
+ expectedType: "string[]",
8463
+ allowedMethods: DESKTOP_CONTROL_ALLOWED_METHODS
8464
+ } });
8465
+ if (params.allowMethods.length === 0) return errorShape(ErrorCodes.INVALID_REQUEST, "allowMethods must include at least one method", { details: { allowedMethods: DESKTOP_CONTROL_ALLOWED_METHODS } });
8466
+ for (let i = 0; i < params.allowMethods.length; i += 1) {
8467
+ const entry = params.allowMethods[i];
8468
+ if (typeof entry !== "string") return errorShape(ErrorCodes.INVALID_REQUEST, `invalid allowMethods[${i}]: ${String(entry)}`, { details: {
8469
+ expectedType: "string",
8470
+ allowedMethods: DESKTOP_CONTROL_ALLOWED_METHODS
8471
+ } });
8472
+ if (!parseDesktopSessionMethod(entry)) return errorShape(ErrorCodes.INVALID_REQUEST, `invalid allowMethods[${i}]: ${entry.trim() || "<empty>"}`, { details: { allowedMethods: DESKTOP_CONTROL_ALLOWED_METHODS } });
8473
+ }
8474
+ }
8475
+ if (params.maxRequests !== void 0) {
8476
+ 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: {
8477
+ minMaxRequests: DESKTOP_CONTROL_MIN_MAX_REQUESTS,
8478
+ maxMaxRequests: DESKTOP_CONTROL_MAX_MAX_REQUESTS
8479
+ } });
8480
+ }
8481
+ return null;
8482
+ }
8483
+ function appendDesktopControlAudit(session, event) {
8484
+ const next = {
8485
+ id: crypto.randomUUID(),
8486
+ ts: typeof event.ts === "number" && Number.isFinite(event.ts) ? event.ts : Date.now(),
8487
+ type: event.type,
8488
+ actor: event.actor,
8489
+ details: event.details
8490
+ };
8491
+ session.audit.push(next);
8492
+ if (session.audit.length > DESKTOP_CONTROL_AUDIT_MAX_EVENTS) session.audit.splice(0, session.audit.length - DESKTOP_CONTROL_AUDIT_MAX_EVENTS);
8493
+ }
8494
+ function toDesktopControlSessionSnapshot(session, includeAudit = false) {
8495
+ return {
8496
+ id: session.id,
8497
+ reason: session.reason,
8498
+ createdAtMs: session.createdAtMs,
8499
+ expiresAtMs: session.expiresAtMs,
8500
+ state: session.state,
8501
+ route: session.route.kind === "node" ? {
8502
+ kind: "node",
8503
+ node: { ...session.route.node }
8504
+ } : session.route,
8505
+ approval: { ...session.approval },
8506
+ controls: {
8507
+ allowMethods: [...session.controls.allowMethods],
8508
+ maxRequests: session.controls.maxRequests
8509
+ },
8510
+ risk: {
8511
+ level: session.risk.level,
8512
+ reasons: [...session.risk.reasons]
8513
+ },
8514
+ requestCount: session.requestCount,
8515
+ lastRequestAtMs: session.lastRequestAtMs,
8516
+ closedAtMs: session.closedAtMs,
8517
+ audit: includeAudit ? session.audit.map((entry) => ({ ...entry })) : void 0
8518
+ };
8519
+ }
8520
+ function broadcastDesktopControlSessionEvent(params) {
8521
+ const latestAudit = params.session.audit[params.session.audit.length - 1];
8522
+ params.context.broadcast("desktop.control.session.updated", {
8523
+ ts: Date.now(),
8524
+ action: params.action,
8525
+ actor: params.actor,
8526
+ details: params.details,
8527
+ session: toDesktopControlSessionSnapshot(params.session, false),
8528
+ latestAudit: latestAudit ? { ...latestAudit } : null
8529
+ }, { dropIfSlow: true });
8530
+ }
8531
+ function pruneDesktopControlSessions(params) {
8532
+ const now = params?.now ?? Date.now();
8533
+ const context = params?.context;
8534
+ for (const session of desktopControlSessions.values()) if ((session.state === "pending_approval" || session.state === "active") && session.expiresAtMs <= now) {
8535
+ session.state = "expired";
8536
+ session.closedAtMs = now;
8537
+ appendDesktopControlAudit(session, {
8538
+ type: "session.expired",
8539
+ actor: "system"
8540
+ });
8541
+ if (context) broadcastDesktopControlSessionEvent({
8542
+ context,
8543
+ action: "expired",
8544
+ session,
8545
+ actor: "system"
8333
8546
  });
8334
- } catch (err) {
8335
- respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(err)));
8336
- return;
8337
8547
  }
8548
+ 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);
8549
+ }
8550
+ function normalizeBrowserRequest(params) {
8551
+ const methodRaw = typeof params.method === "string" ? params.method.trim().toUpperCase() : "";
8552
+ const path = typeof params.path === "string" ? params.path.trim() : "";
8553
+ const queryRaw = params.query;
8554
+ const body = params.body;
8555
+ const timeoutRaw = params.timeoutMs;
8556
+ if (!methodRaw || !path) return {
8557
+ ok: false,
8558
+ error: errorShape(ErrorCodes.INVALID_REQUEST, "method and path are required")
8559
+ };
8560
+ if (methodRaw !== "GET" && methodRaw !== "POST" && methodRaw !== "DELETE") return {
8561
+ ok: false,
8562
+ error: errorShape(ErrorCodes.INVALID_REQUEST, "method must be GET, POST, or DELETE")
8563
+ };
8564
+ if (!path.startsWith("/")) return {
8565
+ ok: false,
8566
+ error: errorShape(ErrorCodes.INVALID_REQUEST, "path must start with /")
8567
+ };
8568
+ if (queryRaw !== void 0) {
8569
+ if (!isPlainObjectRecord(queryRaw)) return {
8570
+ ok: false,
8571
+ error: errorShape(ErrorCodes.INVALID_REQUEST, `invalid query: ${String(queryRaw)}`, { details: { expectedType: "object" } })
8572
+ };
8573
+ const queryIssue = findFirstJsonSerializationIssue(queryRaw, "query");
8574
+ if (queryIssue) return {
8575
+ ok: false,
8576
+ error: errorShape(ErrorCodes.INVALID_REQUEST, `invalid query: non-json-serializable value at ${queryIssue.path}`, { details: {
8577
+ expectedType: "json-serializable",
8578
+ actualType: queryIssue.actualType,
8579
+ path: queryIssue.path
8580
+ } })
8581
+ };
8582
+ }
8583
+ if (body !== void 0) {
8584
+ const bodyIssue = findFirstJsonSerializationIssue(body, "body");
8585
+ if (bodyIssue) return {
8586
+ ok: false,
8587
+ error: errorShape(ErrorCodes.INVALID_REQUEST, `invalid body: non-json-serializable value at ${bodyIssue.path}`, { details: {
8588
+ expectedType: "json-serializable",
8589
+ actualType: bodyIssue.actualType,
8590
+ path: bodyIssue.path
8591
+ } })
8592
+ };
8593
+ }
8594
+ if (timeoutRaw !== void 0) {
8595
+ if (typeof timeoutRaw !== "number" || !Number.isFinite(timeoutRaw) || !Number.isInteger(timeoutRaw) || timeoutRaw < BROWSER_REQUEST_MIN_TIMEOUT_MS || timeoutRaw > BROWSER_REQUEST_MAX_TIMEOUT_MS) return {
8596
+ ok: false,
8597
+ error: errorShape(ErrorCodes.INVALID_REQUEST, `invalid timeoutMs: ${String(timeoutRaw)}`, { details: {
8598
+ expectedType: "integer",
8599
+ minTimeoutMs: BROWSER_REQUEST_MIN_TIMEOUT_MS,
8600
+ maxTimeoutMs: BROWSER_REQUEST_MAX_TIMEOUT_MS
8601
+ } })
8602
+ };
8603
+ }
8604
+ return {
8605
+ ok: true,
8606
+ request: {
8607
+ methodRaw,
8608
+ path,
8609
+ query: queryRaw,
8610
+ body,
8611
+ timeoutMs: typeof timeoutRaw === "number" ? Math.floor(timeoutRaw) : void 0
8612
+ }
8613
+ };
8614
+ }
8615
+ async function dispatchBrowserRequest(params) {
8616
+ const { cfg, request, context, nodeTarget } = params;
8338
8617
  if (nodeTarget) {
8339
8618
  const allowlist = resolveNodeCommandAllowlist(cfg, nodeTarget);
8340
8619
  const allowed = isNodeCommandAllowed({
@@ -8342,67 +8621,1025 @@ const browserHandlers = { "browser.request": async ({ params, respond, context }
8342
8621
  declaredCommands: nodeTarget.commands,
8343
8622
  allowlist
8344
8623
  });
8345
- if (!allowed.ok) {
8346
- respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "node command not allowed", { details: {
8624
+ if (!allowed.ok) return {
8625
+ ok: false,
8626
+ route: "node",
8627
+ nodeId: nodeTarget.nodeId,
8628
+ status: 403,
8629
+ error: errorShape(ErrorCodes.INVALID_REQUEST, "node command not allowed", { details: {
8347
8630
  reason: allowed.reason,
8348
8631
  command: "browser.proxy"
8349
- } }));
8350
- return;
8351
- }
8632
+ } })
8633
+ };
8352
8634
  const proxyParams = {
8353
- method: methodRaw,
8354
- path,
8355
- query,
8356
- body,
8357
- timeoutMs,
8358
- profile: typeof query?.profile === "string" ? query.profile : void 0
8635
+ method: request.methodRaw,
8636
+ path: request.path,
8637
+ query: request.query,
8638
+ body: request.body,
8639
+ timeoutMs: request.timeoutMs,
8640
+ profile: typeof request.query?.profile === "string" ? request.query.profile : void 0
8359
8641
  };
8360
8642
  const res = await context.nodeRegistry.invoke({
8361
8643
  nodeId: nodeTarget.nodeId,
8362
8644
  command: "browser.proxy",
8363
8645
  params: proxyParams,
8364
- timeoutMs,
8646
+ timeoutMs: request.timeoutMs,
8365
8647
  idempotencyKey: crypto.randomUUID()
8366
8648
  });
8367
- if (!res.ok) {
8368
- respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, res.error?.message ?? "node invoke failed", { details: { nodeError: res.error ?? null } }));
8369
- return;
8370
- }
8649
+ if (!res.ok) return {
8650
+ ok: false,
8651
+ route: "node",
8652
+ nodeId: nodeTarget.nodeId,
8653
+ status: 503,
8654
+ error: errorShape(ErrorCodes.UNAVAILABLE, res.error?.message ?? "node invoke failed", { details: { nodeError: res.error ?? null } })
8655
+ };
8371
8656
  const payload = res.payloadJSON ? safeParseJson(res.payloadJSON) : res.payload;
8372
8657
  const proxy = payload && typeof payload === "object" ? payload : null;
8373
- if (!proxy || !("result" in proxy)) {
8374
- respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, "browser proxy failed"));
8375
- return;
8376
- }
8658
+ if (!proxy || !("result" in proxy)) return {
8659
+ ok: false,
8660
+ route: "node",
8661
+ nodeId: nodeTarget.nodeId,
8662
+ status: 503,
8663
+ error: errorShape(ErrorCodes.UNAVAILABLE, "browser proxy failed")
8664
+ };
8377
8665
  const mapping = await persistProxyFiles(proxy.files);
8378
8666
  applyProxyPaths(proxy.result, mapping);
8379
- respond(true, proxy.result);
8380
- return;
8381
- }
8382
- if (!await startBrowserControlServiceFromConfig()) {
8383
- respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, "browser control is disabled"));
8384
- return;
8667
+ return {
8668
+ ok: true,
8669
+ route: "node",
8670
+ nodeId: nodeTarget.nodeId,
8671
+ status: 200,
8672
+ payload: proxy.result
8673
+ };
8385
8674
  }
8675
+ if (!await startBrowserControlServiceFromConfig()) return {
8676
+ ok: false,
8677
+ route: "local",
8678
+ nodeId: null,
8679
+ status: 503,
8680
+ error: errorShape(ErrorCodes.UNAVAILABLE, "browser control is disabled")
8681
+ };
8386
8682
  let dispatcher;
8387
8683
  try {
8388
8684
  dispatcher = createBrowserRouteDispatcher(createBrowserControlContext());
8389
8685
  } catch (err) {
8390
- respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(err)));
8391
- return;
8686
+ return {
8687
+ ok: false,
8688
+ route: "local",
8689
+ nodeId: null,
8690
+ status: 503,
8691
+ error: errorShape(ErrorCodes.UNAVAILABLE, String(err))
8692
+ };
8392
8693
  }
8393
8694
  const result = await dispatcher.dispatch({
8394
- method: methodRaw,
8395
- path,
8396
- query,
8397
- body
8695
+ method: request.methodRaw,
8696
+ path: request.path,
8697
+ query: request.query,
8698
+ body: request.body
8398
8699
  });
8399
8700
  if (result.status >= 400) {
8400
8701
  const message = result.body && typeof result.body === "object" && "error" in result.body ? String(result.body.error) : `browser request failed (${result.status})`;
8401
- respond(false, void 0, errorShape(result.status >= 500 ? ErrorCodes.UNAVAILABLE : ErrorCodes.INVALID_REQUEST, message, { details: result.body }));
8402
- return;
8702
+ const code = result.status >= 500 ? ErrorCodes.UNAVAILABLE : ErrorCodes.INVALID_REQUEST;
8703
+ return {
8704
+ ok: false,
8705
+ route: "local",
8706
+ nodeId: null,
8707
+ status: result.status,
8708
+ error: errorShape(code, message, { details: result.body })
8709
+ };
8710
+ }
8711
+ return {
8712
+ ok: true,
8713
+ route: "local",
8714
+ nodeId: null,
8715
+ status: result.status,
8716
+ payload: result.body
8717
+ };
8718
+ }
8719
+ function resolveDesktopSessionNodeTarget(params) {
8720
+ if (params.session.route.kind !== "node") return null;
8721
+ return params.nodes.find((node) => node.nodeId === params.session.route.node.nodeId && isBrowserNode(node)) ?? null;
8722
+ }
8723
+ function ensureDesktopSessionExists(idRaw) {
8724
+ if (idRaw !== void 0 && typeof idRaw !== "string") return {
8725
+ ok: false,
8726
+ error: errorShape(ErrorCodes.INVALID_REQUEST, `invalid id: ${String(idRaw)}`, { details: { expectedType: "string" } })
8727
+ };
8728
+ const id = typeof idRaw === "string" ? idRaw.trim() : "";
8729
+ if (!id) return {
8730
+ ok: false,
8731
+ error: errorShape(ErrorCodes.INVALID_REQUEST, "id is required")
8732
+ };
8733
+ const session = desktopControlSessions.get(id);
8734
+ if (!session) return {
8735
+ ok: false,
8736
+ error: errorShape(ErrorCodes.INVALID_REQUEST, "unknown desktop control session id")
8737
+ };
8738
+ return {
8739
+ ok: true,
8740
+ session
8741
+ };
8742
+ }
8743
+ function toParamValueType(value) {
8744
+ if (value === null) return "null";
8745
+ if (Array.isArray(value)) return "array";
8746
+ return typeof value;
8747
+ }
8748
+ function isPlainObjectRecord(value) {
8749
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
8750
+ const proto = Object.getPrototypeOf(value);
8751
+ return proto === Object.prototype || proto === null;
8752
+ }
8753
+ function appendJsonPath(basePath, segment) {
8754
+ if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(segment)) return `${basePath}.${segment}`;
8755
+ return `${basePath}[${JSON.stringify(segment)}]`;
8756
+ }
8757
+ function findFirstJsonSerializationIssue(value, path, seen = /* @__PURE__ */ new Set()) {
8758
+ if (value === null) return null;
8759
+ const valueType = typeof value;
8760
+ if (valueType === "number") {
8761
+ if (!Number.isFinite(value)) return {
8762
+ path,
8763
+ actualType: "number(non-finite)"
8764
+ };
8765
+ return null;
8766
+ }
8767
+ if (valueType === "string" || valueType === "boolean") return null;
8768
+ if (valueType === "undefined" || valueType === "function" || valueType === "symbol" || valueType === "bigint") return {
8769
+ path,
8770
+ actualType: valueType
8771
+ };
8772
+ if (Array.isArray(value)) {
8773
+ if (seen.has(value)) return {
8774
+ path,
8775
+ actualType: "circular"
8776
+ };
8777
+ seen.add(value);
8778
+ for (let i = 0; i < value.length; i += 1) {
8779
+ const nestedIssue = findFirstJsonSerializationIssue(value[i], `${path}[${i}]`, seen);
8780
+ if (nestedIssue) {
8781
+ seen.delete(value);
8782
+ return nestedIssue;
8783
+ }
8784
+ }
8785
+ seen.delete(value);
8786
+ return null;
8787
+ }
8788
+ if (!value || typeof value !== "object") return {
8789
+ path,
8790
+ actualType: valueType
8791
+ };
8792
+ if (!isPlainObjectRecord(value)) return {
8793
+ path,
8794
+ actualType: toParamValueType(value)
8795
+ };
8796
+ if (seen.has(value)) return {
8797
+ path,
8798
+ actualType: "circular"
8799
+ };
8800
+ seen.add(value);
8801
+ for (const [key, entry] of Object.entries(value)) {
8802
+ const nestedIssue = findFirstJsonSerializationIssue(entry, appendJsonPath(path, key), seen);
8803
+ if (nestedIssue) {
8804
+ seen.delete(value);
8805
+ return nestedIssue;
8806
+ }
8807
+ }
8808
+ seen.delete(value);
8809
+ return null;
8810
+ }
8811
+ function normalizeObjectParams(params) {
8812
+ if (params === void 0 || params === null) return {
8813
+ ok: true,
8814
+ value: {}
8815
+ };
8816
+ if (!isPlainObjectRecord(params)) return {
8817
+ ok: false,
8818
+ error: errorShape(ErrorCodes.INVALID_REQUEST, "invalid params: expected object", { details: {
8819
+ expectedType: "object",
8820
+ actualType: toParamValueType(params)
8821
+ } })
8822
+ };
8823
+ return {
8824
+ ok: true,
8825
+ value: params
8826
+ };
8827
+ }
8828
+ function buildBrowserCapabilitiesSnapshot(params) {
8829
+ const browserEnabled = params.cfg.browser?.enabled !== false;
8830
+ const evaluateEnabled = browserEnabled && params.cfg.browser?.evaluateEnabled !== false;
8831
+ const mode = params.cfg.gateway?.nodes?.browser?.mode ?? "auto";
8832
+ const pinnedNode = hasValue(params.cfg.gateway?.nodes?.browser?.node) ? String(params.cfg.gateway?.nodes?.browser?.node).trim() : null;
8833
+ const availableNodes = params.nodes.filter((node) => isBrowserNode(node)).map(toNodeSummary);
8834
+ const authMode = resolveGatewayAuthMode(params.cfg);
8835
+ const authConfigured = hasValue(params.cfg.gateway?.auth?.token) || hasValue(params.cfg.gateway?.auth?.password) || authMode === "trusted-proxy";
8836
+ let selectedNode = null;
8837
+ let routingError = null;
8838
+ try {
8839
+ selectedNode = resolveBrowserNodeTarget(params);
8840
+ } catch (error) {
8841
+ routingError = String(error);
8842
+ }
8843
+ const activeRoute = !browserEnabled || mode === "off" ? "disabled" : routingError ? "error" : selectedNode ? "node" : "local";
8844
+ const warnings = [];
8845
+ if (browserEnabled && !authConfigured) warnings.push("Browser control is enabled without gateway auth. Configure gateway.auth.token or gateway.auth.password.");
8846
+ 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.");
8847
+ 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.");
8848
+ if (routingError) warnings.push(routingError);
8849
+ return {
8850
+ browserEnabled,
8851
+ evaluateEnabled,
8852
+ auth: {
8853
+ configured: authConfigured,
8854
+ mode: authMode
8855
+ },
8856
+ routing: {
8857
+ mode,
8858
+ pinnedNode,
8859
+ activeRoute,
8860
+ selectedNode: selectedNode ? toNodeSummary(selectedNode) : null,
8861
+ availableNodes,
8862
+ error: routingError
8863
+ },
8864
+ warnings
8865
+ };
8866
+ }
8867
+ const browserHandlers = {
8868
+ "browser.capabilities.get": async ({ respond, context }) => {
8869
+ try {
8870
+ respond(true, buildBrowserCapabilitiesSnapshot({
8871
+ cfg: loadConfig(),
8872
+ nodes: context.nodeRegistry.listConnected()
8873
+ }));
8874
+ } catch (error) {
8875
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
8876
+ }
8877
+ },
8878
+ "browser.request": async ({ params, respond, context }) => {
8879
+ const normalized = normalizeBrowserRequest(params);
8880
+ if (!normalized.ok) {
8881
+ respond(false, void 0, normalized.error);
8882
+ return;
8883
+ }
8884
+ const cfg = loadConfig();
8885
+ let nodeTarget = null;
8886
+ try {
8887
+ nodeTarget = resolveBrowserNodeTarget({
8888
+ cfg,
8889
+ nodes: context.nodeRegistry.listConnected()
8890
+ });
8891
+ } catch (err) {
8892
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(err)));
8893
+ return;
8894
+ }
8895
+ const result = await dispatchBrowserRequest({
8896
+ cfg,
8897
+ request: normalized.request,
8898
+ context,
8899
+ nodeTarget
8900
+ });
8901
+ if (!result.ok) {
8902
+ respond(false, void 0, result.error);
8903
+ return;
8904
+ }
8905
+ respond(true, result.payload);
8906
+ },
8907
+ "desktop.control.session.create": async ({ params, respond, context, client }) => {
8908
+ pruneDesktopControlSessions({ context });
8909
+ if (!hasOperatorScope(client, "operator.write")) {
8910
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "missing scope: operator.write"));
8911
+ return;
8912
+ }
8913
+ const normalizedParams = normalizeObjectParams(params);
8914
+ if (!normalizedParams.ok) {
8915
+ respond(false, void 0, normalizedParams.error);
8916
+ return;
8917
+ }
8918
+ const typed = normalizedParams.value;
8919
+ const createValidationError = validateDesktopControlSessionCreateParams(typed);
8920
+ if (createValidationError) {
8921
+ respond(false, void 0, createValidationError);
8922
+ return;
8923
+ }
8924
+ const cfg = loadConfig();
8925
+ const connectedNodes = context.nodeRegistry.listConnected();
8926
+ const browserNodes = connectedNodes.filter((node) => isBrowserNode(node));
8927
+ const requestedNodeId = typeof typed.nodeId === "string" ? typed.nodeId.trim() : "";
8928
+ const reason = normalizeDesktopSessionReason(typed.reason);
8929
+ const ttlMs = normalizeDesktopSessionTtl(typed.ttlMs);
8930
+ const allowMethods = normalizeDesktopSessionAllowMethods(typed.allowMethods);
8931
+ const maxRequests = normalizeDesktopSessionMaxRequests(typed.maxRequests);
8932
+ const risk = resolveDesktopSessionRisk({
8933
+ allowMethods,
8934
+ maxRequests
8935
+ });
8936
+ const now = Date.now();
8937
+ const actor = resolveClientActor(client);
8938
+ const snapshot = buildBrowserCapabilitiesSnapshot({
8939
+ cfg,
8940
+ nodes: connectedNodes
8941
+ });
8942
+ if (!snapshot.browserEnabled || snapshot.routing.mode === "off") {
8943
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, "browser control is disabled"));
8944
+ return;
8945
+ }
8946
+ let routeNode = null;
8947
+ try {
8948
+ if (requestedNodeId) {
8949
+ routeNode = resolveBrowserNode(browserNodes, requestedNodeId);
8950
+ if (!routeNode) {
8951
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `requested browser node is not connected: ${requestedNodeId}`));
8952
+ return;
8953
+ }
8954
+ } else routeNode = resolveBrowserNodeTarget({
8955
+ cfg,
8956
+ nodes: connectedNodes
8957
+ });
8958
+ } catch (error) {
8959
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
8960
+ return;
8961
+ }
8962
+ const id = crypto.randomUUID();
8963
+ const session = {
8964
+ id,
8965
+ reason,
8966
+ createdAtMs: now,
8967
+ expiresAtMs: now + ttlMs,
8968
+ state: "pending_approval",
8969
+ route: routeNode ? {
8970
+ kind: "node",
8971
+ node: toNodeSummary(routeNode)
8972
+ } : {
8973
+ kind: "local",
8974
+ node: null
8975
+ },
8976
+ approval: {
8977
+ required: true,
8978
+ decision: "pending",
8979
+ requestedAtMs: now,
8980
+ requestedBy: actor,
8981
+ decidedAtMs: null,
8982
+ decidedBy: null,
8983
+ note: null
8984
+ },
8985
+ controls: {
8986
+ allowMethods,
8987
+ maxRequests
8988
+ },
8989
+ risk,
8990
+ requestCount: 0,
8991
+ inFlightRequestCount: 0,
8992
+ lastRequestAtMs: null,
8993
+ closedAtMs: null,
8994
+ audit: []
8995
+ };
8996
+ appendDesktopControlAudit(session, {
8997
+ type: "session.created",
8998
+ actor,
8999
+ details: {
9000
+ reason: session.reason,
9001
+ route: session.route.kind,
9002
+ nodeId: session.route.kind === "node" ? session.route.node.nodeId : null,
9003
+ expiresAtMs: session.expiresAtMs,
9004
+ allowMethods: session.controls.allowMethods,
9005
+ maxRequests: session.controls.maxRequests,
9006
+ riskLevel: session.risk.level,
9007
+ riskReasons: session.risk.reasons
9008
+ }
9009
+ });
9010
+ desktopControlSessions.set(id, session);
9011
+ broadcastDesktopControlSessionEvent({
9012
+ context,
9013
+ action: "created",
9014
+ session,
9015
+ actor
9016
+ });
9017
+ respond(true, toDesktopControlSessionSnapshot(session, true));
9018
+ },
9019
+ "desktop.control.session.list": async ({ params, respond, context, client }) => {
9020
+ pruneDesktopControlSessions({ context });
9021
+ if (!hasOperatorScope(client, "operator.read")) {
9022
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "missing scope: operator.read"));
9023
+ return;
9024
+ }
9025
+ const normalizedParams = normalizeObjectParams(params);
9026
+ if (!normalizedParams.ok) {
9027
+ respond(false, void 0, normalizedParams.error);
9028
+ return;
9029
+ }
9030
+ const typed = normalizedParams.value;
9031
+ const includeAuditRaw = typed.includeAudit;
9032
+ if (includeAuditRaw !== void 0 && typeof includeAuditRaw !== "boolean") {
9033
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid includeAudit filter: ${String(includeAuditRaw)}`, { details: { expectedType: "boolean" } }));
9034
+ return;
9035
+ }
9036
+ const includeAudit = includeAuditRaw === true;
9037
+ const stateInput = typed.state;
9038
+ if (stateInput !== void 0 && typeof stateInput !== "string") {
9039
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid state filter: ${String(stateInput)}`, { details: { allowedStates: DESKTOP_CONTROL_SESSION_STATES } }));
9040
+ return;
9041
+ }
9042
+ const stateRawInput = typeof stateInput === "string" ? stateInput.trim() : "";
9043
+ const stateRaw = stateRawInput ? stateRawInput.toLowerCase() : "";
9044
+ if (stateRaw && !isDesktopControlSessionState(stateRaw)) {
9045
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid state filter: ${stateRawInput}`, { details: { allowedStates: DESKTOP_CONTROL_SESSION_STATES } }));
9046
+ return;
9047
+ }
9048
+ const decisionInput = typed.decision;
9049
+ if (decisionInput !== void 0 && typeof decisionInput !== "string") {
9050
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid decision filter: ${String(decisionInput)}`, { details: { allowedDecisions: DESKTOP_CONTROL_SESSION_DECISIONS } }));
9051
+ return;
9052
+ }
9053
+ const decisionRawInput = typeof decisionInput === "string" ? decisionInput.trim() : "";
9054
+ const decisionRaw = decisionRawInput ? decisionRawInput.toLowerCase() : "";
9055
+ if (decisionRaw && !isDesktopControlApprovalDecision(decisionRaw)) {
9056
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid decision filter: ${decisionRawInput}`, { details: { allowedDecisions: DESKTOP_CONTROL_SESSION_DECISIONS } }));
9057
+ return;
9058
+ }
9059
+ const routeInput = typed.route;
9060
+ if (routeInput !== void 0 && typeof routeInput !== "string") {
9061
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid route filter: ${String(routeInput)}`, { details: { allowedRouteKinds: DESKTOP_CONTROL_SESSION_ROUTE_KINDS } }));
9062
+ return;
9063
+ }
9064
+ const routeRawInput = typeof routeInput === "string" ? routeInput.trim() : "";
9065
+ const routeRaw = routeRawInput ? routeRawInput.toLowerCase() : "";
9066
+ if (routeRaw && !isDesktopControlSessionRouteKind(routeRaw)) {
9067
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid route filter: ${routeRawInput}`, { details: { allowedRouteKinds: DESKTOP_CONTROL_SESSION_ROUTE_KINDS } }));
9068
+ return;
9069
+ }
9070
+ const riskLevelInput = typed.riskLevel;
9071
+ if (riskLevelInput !== void 0 && typeof riskLevelInput !== "string") {
9072
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid riskLevel filter: ${String(riskLevelInput)}`, { details: { allowedRiskLevels: DESKTOP_CONTROL_SESSION_RISK_LEVELS } }));
9073
+ return;
9074
+ }
9075
+ const riskLevelRawInput = typeof riskLevelInput === "string" ? riskLevelInput.trim() : "";
9076
+ const riskLevelRaw = riskLevelRawInput ? riskLevelRawInput.toLowerCase() : "";
9077
+ if (riskLevelRaw && !isDesktopControlSessionRiskLevel(riskLevelRaw)) {
9078
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid riskLevel filter: ${riskLevelRawInput}`, { details: { allowedRiskLevels: DESKTOP_CONTROL_SESSION_RISK_LEVELS } }));
9079
+ return;
9080
+ }
9081
+ const nodeIdInput = typed.nodeId;
9082
+ if (nodeIdInput !== void 0 && typeof nodeIdInput !== "string") {
9083
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid nodeId filter: ${String(nodeIdInput)}`));
9084
+ return;
9085
+ }
9086
+ const nodeIdRawInput = typeof nodeIdInput === "string" ? nodeIdInput.trim() : "";
9087
+ const nodeIdFilterKey = nodeIdRawInput ? normalizeNodeKey(nodeIdRawInput) : "";
9088
+ if (nodeIdRawInput && !nodeIdFilterKey) {
9089
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid nodeId filter: ${nodeIdRawInput}`));
9090
+ return;
9091
+ }
9092
+ if (routeRaw === "local" && nodeIdRawInput) {
9093
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "nodeId filter requires route=node (or omit route to match node-routed sessions)"));
9094
+ return;
9095
+ }
9096
+ const limitRaw = typed.limit;
9097
+ if (limitRaw !== void 0) {
9098
+ if (typeof limitRaw !== "number" || !Number.isInteger(limitRaw) || limitRaw < DESKTOP_CONTROL_LIST_MIN_LIMIT || limitRaw > DESKTOP_CONTROL_LIST_MAX_LIMIT) {
9099
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid limit filter: ${String(limitRaw)}`, { details: {
9100
+ minLimit: DESKTOP_CONTROL_LIST_MIN_LIMIT,
9101
+ maxLimit: DESKTOP_CONTROL_LIST_MAX_LIMIT
9102
+ } }));
9103
+ return;
9104
+ }
9105
+ }
9106
+ const offsetRaw = typed.offset;
9107
+ if (offsetRaw !== void 0) {
9108
+ if (typeof offsetRaw !== "number" || !Number.isInteger(offsetRaw) || offsetRaw < DESKTOP_CONTROL_LIST_MIN_OFFSET || offsetRaw > DESKTOP_CONTROL_LIST_MAX_OFFSET) {
9109
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid offset filter: ${String(offsetRaw)}`, { details: {
9110
+ minOffset: DESKTOP_CONTROL_LIST_MIN_OFFSET,
9111
+ maxOffset: DESKTOP_CONTROL_LIST_MAX_OFFSET
9112
+ } }));
9113
+ return;
9114
+ }
9115
+ }
9116
+ const state = stateRaw || void 0;
9117
+ const decision = decisionRaw || void 0;
9118
+ const route = routeRaw || void 0;
9119
+ const riskLevel = riskLevelRaw || void 0;
9120
+ const nodeId = nodeIdFilterKey || void 0;
9121
+ const limit = typeof limitRaw === "number" ? limitRaw : void 0;
9122
+ const offset = typeof offsetRaw === "number" ? offsetRaw : 0;
9123
+ const filtered = Array.from(desktopControlSessions.values()).filter((entry) => {
9124
+ if (state && entry.state !== state) return false;
9125
+ if (decision && entry.approval.decision !== decision) return false;
9126
+ if (route && entry.route.kind !== route) return false;
9127
+ if (riskLevel && entry.risk.level !== riskLevel) return false;
9128
+ if (nodeId && (entry.route.kind !== "node" || normalizeNodeKey(entry.route.node.nodeId) !== nodeId)) return false;
9129
+ return true;
9130
+ }).toSorted((a, b) => b.createdAtMs - a.createdAtMs);
9131
+ const total = filtered.length;
9132
+ const sliceEnd = limit === void 0 ? void 0 : offset + limit;
9133
+ const sessions = filtered.slice(offset, sliceEnd).map((entry) => toDesktopControlSessionSnapshot(entry, includeAudit));
9134
+ const returned = sessions.length;
9135
+ const hasMore = offset + returned < total;
9136
+ respond(true, {
9137
+ ts: Date.now(),
9138
+ total,
9139
+ returned,
9140
+ offset,
9141
+ nextOffset: hasMore ? offset + returned : null,
9142
+ truncated: offset > 0 || hasMore,
9143
+ sessions
9144
+ });
9145
+ },
9146
+ "desktop.control.session.get": async ({ params, respond, context, client }) => {
9147
+ pruneDesktopControlSessions({ context });
9148
+ if (!hasOperatorScope(client, "operator.read")) {
9149
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "missing scope: operator.read"));
9150
+ return;
9151
+ }
9152
+ const normalizedParams = normalizeObjectParams(params);
9153
+ if (!normalizedParams.ok) {
9154
+ respond(false, void 0, normalizedParams.error);
9155
+ return;
9156
+ }
9157
+ const typed = normalizedParams.value;
9158
+ const includeAuditRaw = typed.includeAudit;
9159
+ if (includeAuditRaw !== void 0 && typeof includeAuditRaw !== "boolean") {
9160
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid includeAudit filter: ${String(includeAuditRaw)}`, { details: { expectedType: "boolean" } }));
9161
+ return;
9162
+ }
9163
+ const found = ensureDesktopSessionExists(typed.id);
9164
+ if (!found.ok) {
9165
+ respond(false, void 0, found.error);
9166
+ return;
9167
+ }
9168
+ respond(true, toDesktopControlSessionSnapshot(found.session, includeAuditRaw === true));
9169
+ },
9170
+ "desktop.control.session.approve": async ({ params, respond, client, context }) => {
9171
+ pruneDesktopControlSessions({ context });
9172
+ if (!hasOperatorScope(client, "operator.approvals")) {
9173
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "missing scope: operator.approvals"));
9174
+ return;
9175
+ }
9176
+ const normalizedParams = normalizeObjectParams(params);
9177
+ if (!normalizedParams.ok) {
9178
+ respond(false, void 0, normalizedParams.error);
9179
+ return;
9180
+ }
9181
+ const typed = normalizedParams.value;
9182
+ const found = ensureDesktopSessionExists(typed.id);
9183
+ if (!found.ok) {
9184
+ respond(false, void 0, found.error);
9185
+ return;
9186
+ }
9187
+ const session = found.session;
9188
+ if (session.state !== "pending_approval") {
9189
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `session is not pending approval (state: ${session.state})`, { details: {
9190
+ state: session.state,
9191
+ decision: session.approval.decision,
9192
+ expiresAtMs: session.expiresAtMs
9193
+ } }));
9194
+ return;
9195
+ }
9196
+ if (session.expiresAtMs <= Date.now()) {
9197
+ session.state = "expired";
9198
+ session.closedAtMs = Date.now();
9199
+ appendDesktopControlAudit(session, {
9200
+ type: "session.expired",
9201
+ actor: "system"
9202
+ });
9203
+ broadcastDesktopControlSessionEvent({
9204
+ context,
9205
+ action: "expired",
9206
+ session,
9207
+ actor: "system"
9208
+ });
9209
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "session has expired", { details: {
9210
+ state: session.state,
9211
+ decision: session.approval.decision,
9212
+ expiresAtMs: session.expiresAtMs
9213
+ } }));
9214
+ return;
9215
+ }
9216
+ const decisionRaw = typeof typed.decision === "string" ? typed.decision.trim().toLowerCase() : "";
9217
+ if (decisionRaw !== "allow" && decisionRaw !== "deny") {
9218
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "decision must be allow or deny"));
9219
+ return;
9220
+ }
9221
+ if (decisionRaw === "allow" && session.route.kind === "node") {
9222
+ if (!resolveDesktopSessionNodeTarget({
9223
+ session,
9224
+ nodes: context.nodeRegistry.listConnected()
9225
+ })) {
9226
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, `pinned browser node is not connected: ${session.route.node.nodeId}`, { details: {
9227
+ nodeId: session.route.node.nodeId,
9228
+ state: session.state,
9229
+ decision: session.approval.decision,
9230
+ expiresAtMs: session.expiresAtMs,
9231
+ requestCount: session.requestCount,
9232
+ maxRequests: session.controls.maxRequests
9233
+ } }));
9234
+ return;
9235
+ }
9236
+ }
9237
+ if (typed.note !== void 0 && typeof typed.note !== "string") {
9238
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid note: ${String(typed.note)}`, { details: { expectedType: "string" } }));
9239
+ return;
9240
+ }
9241
+ const note = normalizeDesktopSessionNote(typed.note);
9242
+ if (decisionRaw === "allow" && session.risk.level === "elevated" && !hasDecisionRationale(note)) {
9243
+ 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: {
9244
+ riskLevel: session.risk.level,
9245
+ riskReasons: session.risk.reasons,
9246
+ minNoteLength: DESKTOP_CONTROL_MIN_DECISION_NOTE_LEN
9247
+ } }));
9248
+ return;
9249
+ }
9250
+ if (decisionRaw === "deny" && !hasDecisionRationale(note)) {
9251
+ 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 } }));
9252
+ return;
9253
+ }
9254
+ const actor = resolveClientActor(client);
9255
+ const now = Date.now();
9256
+ session.approval.decision = decisionRaw;
9257
+ session.approval.decidedAtMs = now;
9258
+ session.approval.decidedBy = actor;
9259
+ session.approval.note = note;
9260
+ session.state = decisionRaw === "allow" ? "active" : "denied";
9261
+ if (session.state === "denied") session.closedAtMs = now;
9262
+ appendDesktopControlAudit(session, {
9263
+ type: decisionRaw === "allow" ? "session.approved" : "session.denied",
9264
+ actor,
9265
+ details: { note: session.approval.note }
9266
+ });
9267
+ broadcastDesktopControlSessionEvent({
9268
+ context,
9269
+ action: decisionRaw === "allow" ? "approved" : "denied",
9270
+ session,
9271
+ actor,
9272
+ details: { note: session.approval.note }
9273
+ });
9274
+ respond(true, toDesktopControlSessionSnapshot(session, true));
9275
+ },
9276
+ "desktop.control.session.close": async ({ params, respond, client, context }) => {
9277
+ pruneDesktopControlSessions({ context });
9278
+ if (!hasOperatorScope(client, "operator.write")) {
9279
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "missing scope: operator.write"));
9280
+ return;
9281
+ }
9282
+ const normalizedParams = normalizeObjectParams(params);
9283
+ if (!normalizedParams.ok) {
9284
+ respond(false, void 0, normalizedParams.error);
9285
+ return;
9286
+ }
9287
+ const typed = normalizedParams.value;
9288
+ const found = ensureDesktopSessionExists(typed.id);
9289
+ if (!found.ok) {
9290
+ respond(false, void 0, found.error);
9291
+ return;
9292
+ }
9293
+ const session = found.session;
9294
+ if (session.state === "closed" || session.state === "denied" || session.state === "expired") {
9295
+ respond(true, toDesktopControlSessionSnapshot(session, true));
9296
+ return;
9297
+ }
9298
+ if (typed.note !== void 0 && typeof typed.note !== "string") {
9299
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `invalid note: ${String(typed.note)}`, { details: { expectedType: "string" } }));
9300
+ return;
9301
+ }
9302
+ const note = normalizeDesktopSessionNote(typed.note);
9303
+ const actor = resolveClientActor(client);
9304
+ if (session.state === "pending_approval" && !hasDecisionRationale(note)) {
9305
+ 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 } }));
9306
+ return;
9307
+ }
9308
+ if (session.state === "active" && !hasDecisionRationale(note)) {
9309
+ 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 } }));
9310
+ return;
9311
+ }
9312
+ const now = Date.now();
9313
+ if (session.state === "pending_approval") {
9314
+ session.approval.decision = "deny";
9315
+ session.approval.decidedAtMs = now;
9316
+ session.approval.decidedBy = actor;
9317
+ session.approval.note = note;
9318
+ }
9319
+ session.state = "closed";
9320
+ session.closedAtMs = now;
9321
+ appendDesktopControlAudit(session, {
9322
+ type: "session.closed",
9323
+ actor,
9324
+ details: { note }
9325
+ });
9326
+ broadcastDesktopControlSessionEvent({
9327
+ context,
9328
+ action: "closed",
9329
+ session,
9330
+ actor,
9331
+ details: { note }
9332
+ });
9333
+ respond(true, toDesktopControlSessionSnapshot(session, true));
9334
+ },
9335
+ "desktop.control.session.request": async ({ params, respond, client, context }) => {
9336
+ pruneDesktopControlSessions({ context });
9337
+ if (!hasOperatorScope(client, "operator.write")) {
9338
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "missing scope: operator.write"));
9339
+ return;
9340
+ }
9341
+ const normalizedParams = normalizeObjectParams(params);
9342
+ if (!normalizedParams.ok) {
9343
+ respond(false, void 0, normalizedParams.error);
9344
+ return;
9345
+ }
9346
+ const typed = normalizedParams.value;
9347
+ const found = ensureDesktopSessionExists(typed.id);
9348
+ if (!found.ok) {
9349
+ respond(false, void 0, found.error);
9350
+ return;
9351
+ }
9352
+ const session = found.session;
9353
+ if (session.state === "expired") {
9354
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "session has expired", { details: {
9355
+ state: session.state,
9356
+ decision: session.approval.decision,
9357
+ expiresAtMs: session.expiresAtMs
9358
+ } }));
9359
+ return;
9360
+ }
9361
+ if (session.state === "closed" && session.approval.decision === "allow" && session.requestCount >= session.controls.maxRequests) {
9362
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `session request budget exhausted (${session.controls.maxRequests})`, { details: {
9363
+ state: session.state,
9364
+ decision: session.approval.decision,
9365
+ requestCount: session.requestCount,
9366
+ inFlightRequests: session.inFlightRequestCount,
9367
+ maxRequests: session.controls.maxRequests,
9368
+ expiresAtMs: session.expiresAtMs
9369
+ } }));
9370
+ return;
9371
+ }
9372
+ if (session.state !== "active" || session.approval.decision !== "allow") {
9373
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `session is not approved (state: ${session.state}, decision: ${session.approval.decision})`, { details: {
9374
+ state: session.state,
9375
+ decision: session.approval.decision
9376
+ } }));
9377
+ return;
9378
+ }
9379
+ if (session.expiresAtMs <= Date.now()) {
9380
+ session.state = "expired";
9381
+ session.closedAtMs = Date.now();
9382
+ appendDesktopControlAudit(session, {
9383
+ type: "session.expired",
9384
+ actor: "system"
9385
+ });
9386
+ broadcastDesktopControlSessionEvent({
9387
+ context,
9388
+ action: "expired",
9389
+ session,
9390
+ actor: "system"
9391
+ });
9392
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "session has expired", { details: {
9393
+ state: session.state,
9394
+ decision: session.approval.decision,
9395
+ expiresAtMs: session.expiresAtMs
9396
+ } }));
9397
+ return;
9398
+ }
9399
+ const normalized = normalizeBrowserRequest(typed);
9400
+ if (!normalized.ok) {
9401
+ respond(false, void 0, normalized.error);
9402
+ return;
9403
+ }
9404
+ const actor = resolveClientActor(client);
9405
+ if (!session.controls.allowMethods.includes(normalized.request.methodRaw)) {
9406
+ appendDesktopControlAudit(session, {
9407
+ type: "request.error",
9408
+ actor,
9409
+ details: {
9410
+ reason: "method not allowed",
9411
+ method: normalized.request.methodRaw,
9412
+ allowedMethods: session.controls.allowMethods
9413
+ }
9414
+ });
9415
+ broadcastDesktopControlSessionEvent({
9416
+ context,
9417
+ action: "request_error",
9418
+ session,
9419
+ actor,
9420
+ details: {
9421
+ reason: "method not allowed",
9422
+ method: normalized.request.methodRaw,
9423
+ allowedMethods: [...session.controls.allowMethods]
9424
+ }
9425
+ });
9426
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `method is not allowed for this session: ${normalized.request.methodRaw}`, { details: { allowedMethods: session.controls.allowMethods } }));
9427
+ return;
9428
+ }
9429
+ if (session.requestCount >= session.controls.maxRequests) {
9430
+ session.state = "closed";
9431
+ session.closedAtMs = Date.now();
9432
+ appendDesktopControlAudit(session, {
9433
+ type: "session.closed",
9434
+ actor: "system",
9435
+ details: {
9436
+ reason: "max requests reached",
9437
+ maxRequests: session.controls.maxRequests
9438
+ }
9439
+ });
9440
+ broadcastDesktopControlSessionEvent({
9441
+ context,
9442
+ action: "closed",
9443
+ session,
9444
+ actor: "system",
9445
+ details: {
9446
+ reason: "max requests reached",
9447
+ maxRequests: session.controls.maxRequests
9448
+ }
9449
+ });
9450
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `session request budget exhausted (${session.controls.maxRequests})`, { details: {
9451
+ state: session.state,
9452
+ decision: session.approval.decision,
9453
+ requestCount: session.requestCount,
9454
+ inFlightRequests: session.inFlightRequestCount,
9455
+ maxRequests: session.controls.maxRequests,
9456
+ expiresAtMs: session.expiresAtMs
9457
+ } }));
9458
+ return;
9459
+ }
9460
+ if (session.requestCount + session.inFlightRequestCount >= session.controls.maxRequests) {
9461
+ appendDesktopControlAudit(session, {
9462
+ type: "request.error",
9463
+ actor,
9464
+ details: {
9465
+ reason: "request budget reserved by in-flight requests",
9466
+ requestCount: session.requestCount,
9467
+ inFlightRequests: session.inFlightRequestCount,
9468
+ maxRequests: session.controls.maxRequests
9469
+ }
9470
+ });
9471
+ broadcastDesktopControlSessionEvent({
9472
+ context,
9473
+ action: "request_error",
9474
+ session,
9475
+ actor,
9476
+ details: {
9477
+ reason: "request budget reserved by in-flight requests",
9478
+ requestCount: session.requestCount,
9479
+ inFlightRequests: session.inFlightRequestCount,
9480
+ maxRequests: session.controls.maxRequests
9481
+ }
9482
+ });
9483
+ respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `session request budget reserved by in-flight requests (${session.controls.maxRequests})`, { details: {
9484
+ state: session.state,
9485
+ decision: session.approval.decision,
9486
+ requestCount: session.requestCount,
9487
+ inFlightRequests: session.inFlightRequestCount,
9488
+ maxRequests: session.controls.maxRequests,
9489
+ expiresAtMs: session.expiresAtMs
9490
+ } }));
9491
+ return;
9492
+ }
9493
+ appendDesktopControlAudit(session, {
9494
+ type: "request.start",
9495
+ actor,
9496
+ details: {
9497
+ method: normalized.request.methodRaw,
9498
+ path: normalized.request.path,
9499
+ route: session.route.kind,
9500
+ nodeId: session.route.kind === "node" ? session.route.node.nodeId : null
9501
+ }
9502
+ });
9503
+ const nodeTarget = resolveDesktopSessionNodeTarget({
9504
+ session,
9505
+ nodes: context.nodeRegistry.listConnected()
9506
+ });
9507
+ if (session.route.kind === "node" && !nodeTarget) {
9508
+ appendDesktopControlAudit(session, {
9509
+ type: "request.error",
9510
+ actor,
9511
+ details: {
9512
+ reason: "pinned node disconnected",
9513
+ nodeId: session.route.node.nodeId
9514
+ }
9515
+ });
9516
+ broadcastDesktopControlSessionEvent({
9517
+ context,
9518
+ action: "request_error",
9519
+ session,
9520
+ actor,
9521
+ details: {
9522
+ reason: "pinned node disconnected",
9523
+ nodeId: session.route.node.nodeId
9524
+ }
9525
+ });
9526
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, `pinned browser node is not connected: ${session.route.node.nodeId}`, { details: {
9527
+ nodeId: session.route.node.nodeId,
9528
+ state: session.state,
9529
+ decision: session.approval.decision,
9530
+ expiresAtMs: session.expiresAtMs,
9531
+ requestCount: session.requestCount,
9532
+ maxRequests: session.controls.maxRequests
9533
+ } }));
9534
+ return;
9535
+ }
9536
+ session.inFlightRequestCount += 1;
9537
+ let result;
9538
+ try {
9539
+ result = await dispatchBrowserRequest({
9540
+ cfg: loadConfig(),
9541
+ request: normalized.request,
9542
+ context,
9543
+ nodeTarget
9544
+ });
9545
+ } catch (error) {
9546
+ session.inFlightRequestCount = Math.max(0, session.inFlightRequestCount - 1);
9547
+ const message = error instanceof Error ? error.message : String(error);
9548
+ appendDesktopControlAudit(session, {
9549
+ type: "request.error",
9550
+ actor,
9551
+ details: {
9552
+ reason: "dispatch threw",
9553
+ message
9554
+ }
9555
+ });
9556
+ broadcastDesktopControlSessionEvent({
9557
+ context,
9558
+ action: "request_error",
9559
+ session,
9560
+ actor,
9561
+ details: {
9562
+ reason: "dispatch threw",
9563
+ message
9564
+ }
9565
+ });
9566
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, message));
9567
+ return;
9568
+ }
9569
+ session.inFlightRequestCount = Math.max(0, session.inFlightRequestCount - 1);
9570
+ if (!result.ok) {
9571
+ appendDesktopControlAudit(session, {
9572
+ type: "request.error",
9573
+ actor,
9574
+ details: {
9575
+ route: result.route,
9576
+ nodeId: result.nodeId,
9577
+ status: result.status,
9578
+ message: result.error.message
9579
+ }
9580
+ });
9581
+ broadcastDesktopControlSessionEvent({
9582
+ context,
9583
+ action: "request_error",
9584
+ session,
9585
+ actor,
9586
+ details: {
9587
+ route: result.route,
9588
+ nodeId: result.nodeId,
9589
+ status: result.status,
9590
+ message: result.error.message
9591
+ }
9592
+ });
9593
+ respond(false, void 0, result.error);
9594
+ return;
9595
+ }
9596
+ session.requestCount += 1;
9597
+ session.lastRequestAtMs = Date.now();
9598
+ appendDesktopControlAudit(session, {
9599
+ type: "request.ok",
9600
+ actor,
9601
+ details: {
9602
+ route: result.route,
9603
+ nodeId: result.nodeId,
9604
+ status: result.status
9605
+ }
9606
+ });
9607
+ broadcastDesktopControlSessionEvent({
9608
+ context,
9609
+ action: "request_ok",
9610
+ session,
9611
+ actor,
9612
+ details: {
9613
+ route: result.route,
9614
+ nodeId: result.nodeId,
9615
+ status: result.status
9616
+ }
9617
+ });
9618
+ if (session.state === "active" && session.approval.decision === "allow" && session.requestCount >= session.controls.maxRequests) {
9619
+ session.state = "closed";
9620
+ session.closedAtMs = session.lastRequestAtMs;
9621
+ appendDesktopControlAudit(session, {
9622
+ type: "session.closed",
9623
+ actor: "system",
9624
+ details: {
9625
+ reason: "max requests reached",
9626
+ maxRequests: session.controls.maxRequests
9627
+ }
9628
+ });
9629
+ broadcastDesktopControlSessionEvent({
9630
+ context,
9631
+ action: "closed",
9632
+ session,
9633
+ actor: "system",
9634
+ details: {
9635
+ reason: "max requests reached",
9636
+ maxRequests: session.controls.maxRequests
9637
+ }
9638
+ });
9639
+ }
9640
+ respond(true, result.payload);
8403
9641
  }
8404
- respond(true, result.body);
8405
- } };
9642
+ };
8406
9643
 
8407
9644
  //#endregion
8408
9645
  //#region src/channels/plugins/status.ts
@@ -9611,7 +10848,7 @@ const FIELD_LABELS = {
9611
10848
 
9612
10849
  //#endregion
9613
10850
  //#region src/config/schema.hints.ts
9614
- const log$10 = createSubsystemLogger("config/schema");
10851
+ const log$12 = createSubsystemLogger("config/schema");
9615
10852
  const GROUP_LABELS = {
9616
10853
  wizard: "Wizard",
9617
10854
  update: "Update",
@@ -9759,7 +10996,7 @@ function mapSensitivePaths(schema, path, hints) {
9759
10996
  ...next[path],
9760
10997
  sensitive: true
9761
10998
  };
9762
- else if (isSensitiveConfigPath(path) && !next[path]?.sensitive) log$10.warn(`possibly sensitive key found: (${path})`);
10999
+ else if (isSensitiveConfigPath(path) && !next[path]?.sensitive) log$12.warn(`possibly sensitive key found: (${path})`);
9763
11000
  if (currentSchema instanceof z.ZodObject) {
9764
11001
  const shape = currentSchema.shape;
9765
11002
  for (const key in shape) {
@@ -9782,7 +11019,7 @@ function mapSensitivePaths(schema, path, hints) {
9782
11019
 
9783
11020
  //#endregion
9784
11021
  //#region src/config/redact-snapshot.ts
9785
- const log$9 = createSubsystemLogger("config/redaction");
11022
+ const log$11 = createSubsystemLogger("config/redaction");
9786
11023
  const ENV_VAR_PLACEHOLDER_PATTERN = /^\$\{[^}]*\}$/;
9787
11024
  function isSensitivePath(path) {
9788
11025
  if (path.endsWith("[]")) return isSensitiveConfigPath(path.slice(0, -2));
@@ -10033,7 +11270,7 @@ function restoreRedactedValuesWithLookup(incoming, original, lookup, prefix, hin
10033
11270
  return restoreRedactedValuesGuessing(incoming, original, prefix, hints);
10034
11271
  }
10035
11272
  const origArr = Array.isArray(original) ? original : [];
10036
- if (incoming.length < origArr.length) log$9.warn(`Redacted config array key ${path} has been truncated`);
11273
+ if (incoming.length < origArr.length) log$11.warn(`Redacted config array key ${path} has been truncated`);
10037
11274
  return incoming.map((item, i) => {
10038
11275
  if (item === REDACTED_SENTINEL) return origArr[i];
10039
11276
  return restoreRedactedValuesWithLookup(item, origArr[i], lookup, path, hints);
@@ -10050,7 +11287,7 @@ function restoreRedactedValuesWithLookup(incoming, original, lookup, prefix, hin
10050
11287
  matched = true;
10051
11288
  if (value === REDACTED_SENTINEL) if (key in orig) result[key] = orig[key];
10052
11289
  else {
10053
- log$9.warn(`Cannot un-redact config key ${candidate} as it doesn't have any value`);
11290
+ log$11.warn(`Cannot un-redact config key ${candidate} as it doesn't have any value`);
10054
11291
  throw new RedactionError(candidate);
10055
11292
  }
10056
11293
  else if (typeof value === "object" && value !== null) result[key] = restoreRedactedValuesWithLookup(value, orig[key], lookup, candidate, hints);
@@ -10059,7 +11296,7 @@ function restoreRedactedValuesWithLookup(incoming, original, lookup, prefix, hin
10059
11296
  if (!matched && isExtensionPath(path)) {
10060
11297
  if (!isExplicitlyNonSensitivePath(hints, [path, wildcardPath]) && isSensitivePath(path) && value === REDACTED_SENTINEL) if (key in orig) result[key] = orig[key];
10061
11298
  else {
10062
- log$9.warn(`Cannot un-redact config key ${path} as it doesn't have any value`);
11299
+ log$11.warn(`Cannot un-redact config key ${path} as it doesn't have any value`);
10063
11300
  throw new RedactionError(path);
10064
11301
  }
10065
11302
  else if (typeof value === "object" && value !== null) result[key] = restoreRedactedValuesGuessing(value, orig[key], path, hints);
@@ -10078,7 +11315,7 @@ function restoreRedactedValuesGuessing(incoming, original, prefix, hints) {
10078
11315
  const origArr = Array.isArray(original) ? original : [];
10079
11316
  return incoming.map((item, i) => {
10080
11317
  const path = `${prefix}[]`;
10081
- if (incoming.length < origArr.length) log$9.warn(`Redacted config array key ${path} has been truncated`);
11318
+ if (incoming.length < origArr.length) log$11.warn(`Redacted config array key ${path} has been truncated`);
10082
11319
  if (!isExplicitlyNonSensitivePath(hints, [path]) && isSensitivePath(path) && item === REDACTED_SENTINEL) return origArr[i];
10083
11320
  return restoreRedactedValuesGuessing(item, origArr[i], path, hints);
10084
11321
  });
@@ -10089,7 +11326,7 @@ function restoreRedactedValuesGuessing(incoming, original, prefix, hints) {
10089
11326
  const path = prefix ? `${prefix}.${key}` : key;
10090
11327
  if (!isExplicitlyNonSensitivePath(hints, [path, prefix ? `${prefix}.*` : "*"]) && isSensitivePath(path) && value === REDACTED_SENTINEL) if (key in orig) result[key] = orig[key];
10091
11328
  else {
10092
- log$9.warn(`Cannot un-redact config key ${path} as it doesn't have any value`);
11329
+ log$11.warn(`Cannot un-redact config key ${path} as it doesn't have any value`);
10093
11330
  throw new RedactionError(path);
10094
11331
  }
10095
11332
  else if (typeof value === "object" && value !== null) result[key] = restoreRedactedValuesGuessing(value, orig[key], path, hints);
@@ -11430,6 +12667,348 @@ const healthHandlers = {
11430
12667
  }
11431
12668
  };
11432
12669
 
12670
+ //#endregion
12671
+ //#region src/ico/launch-platform.ts
12672
+ const log$10 = createSubsystemLogger("ico-platform");
12673
+ function resolveIcoDir() {
12674
+ return path.join(resolveStateDir(), "ico");
12675
+ }
12676
+ function listIcoProjects() {
12677
+ const dir = resolveIcoDir();
12678
+ try {
12679
+ if (!fs.existsSync(dir)) return [];
12680
+ return fs.readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => {
12681
+ try {
12682
+ const raw = fs.readFileSync(path.join(dir, f), "utf8");
12683
+ return JSON.parse(raw);
12684
+ } catch {
12685
+ return null;
12686
+ }
12687
+ }).filter((p) => p != null).toSorted((a, b) => b.createdAt - a.createdAt);
12688
+ } catch {
12689
+ return [];
12690
+ }
12691
+ }
12692
+
12693
+ //#endregion
12694
+ //#region src/ico/public-metrics.ts
12695
+ const MS_PER_MINUTE = 6e4;
12696
+ const METRIC_UNAVAILABLE_ERROR = "ICO_PROJECT_NOT_FOUND";
12697
+ const METRIC_DEFINITIONS$1 = [
12698
+ {
12699
+ id: "current_price_usd",
12700
+ label: "Current Price",
12701
+ cadenceMinutes: 15,
12702
+ sourceRef: "ico.launch-platform.currentPriceUsd",
12703
+ readValue: (project) => project.status.currentPriceUsd,
12704
+ formatValue: (value) => formatUsd$1(value, value >= 1 ? 2 : 4)
12705
+ },
12706
+ {
12707
+ id: "total_raised_usd",
12708
+ label: "Total Raised",
12709
+ cadenceMinutes: 15,
12710
+ sourceRef: "ico.launch-platform.totalRaisedUsd",
12711
+ readValue: (project) => project.status.totalRaisedUsd,
12712
+ formatValue: (value) => formatUsd$1(value, 2)
12713
+ },
12714
+ {
12715
+ id: "holders_total",
12716
+ label: "Holders",
12717
+ cadenceMinutes: 15,
12718
+ sourceRef: "ico.launch-platform.holders",
12719
+ readValue: (project) => project.status.holders,
12720
+ formatValue: (value) => formatInteger$1(value)
12721
+ },
12722
+ {
12723
+ id: "supply_sold_tokens",
12724
+ label: "Supply Sold",
12725
+ cadenceMinutes: 15,
12726
+ sourceRef: "ico.launch-platform.currentSupply",
12727
+ readValue: (project) => project.status.currentSupply,
12728
+ formatValue: (value) => formatInteger$1(value)
12729
+ },
12730
+ {
12731
+ id: "bonding_progress_percent",
12732
+ label: "Bonding Progress",
12733
+ cadenceMinutes: 15,
12734
+ sourceRef: "ico.launch-platform.percentToTarget",
12735
+ readValue: (project) => project.status.percentToTarget,
12736
+ formatValue: (value) => formatPercent(value, 1)
12737
+ },
12738
+ {
12739
+ id: "transfer_tax_rate_percent",
12740
+ label: "Transfer Tax",
12741
+ cadenceMinutes: 1440,
12742
+ sourceRef: "ico.config.tax.transferTaxRate",
12743
+ readValue: (project) => project.config.tax.transferTaxRate * 100,
12744
+ formatValue: (value) => formatPercent(value, 2)
12745
+ },
12746
+ {
12747
+ id: "revenue_share_rate_percent",
12748
+ label: "Revenue Share",
12749
+ cadenceMinutes: 1440,
12750
+ sourceRef: "ico.config.tax.revenueShareRate",
12751
+ readValue: (project) => project.config.tax.revenueShareRate * 100,
12752
+ formatValue: (value) => formatPercent(value, 2)
12753
+ }
12754
+ ];
12755
+ function formatUsd$1(value, fractionDigits) {
12756
+ return `$${value.toLocaleString(void 0, {
12757
+ minimumFractionDigits: fractionDigits,
12758
+ maximumFractionDigits: fractionDigits
12759
+ })}`;
12760
+ }
12761
+ function formatInteger$1(value) {
12762
+ return Math.round(value).toLocaleString();
12763
+ }
12764
+ function formatPercent(value, fractionDigits) {
12765
+ return `${value.toLocaleString(void 0, {
12766
+ minimumFractionDigits: fractionDigits,
12767
+ maximumFractionDigits: fractionDigits
12768
+ })}%`;
12769
+ }
12770
+ function mapProjectSnapshot(project) {
12771
+ return {
12772
+ id: project.id,
12773
+ name: project.config.name,
12774
+ symbol: project.config.symbol,
12775
+ chains: [...project.config.chains],
12776
+ targetRaiseUsd: project.config.bondingCurve.targetRaiseUsd,
12777
+ bondingActive: project.status.bondingActive,
12778
+ allocation: {
12779
+ team: project.config.allocation.team,
12780
+ companyRound: project.config.allocation.companyRound,
12781
+ revenueShare: project.config.allocation.revenueShare,
12782
+ ubc: project.config.allocation.ubc
12783
+ },
12784
+ tax: {
12785
+ transferTaxRate: project.config.tax.transferTaxRate,
12786
+ revenueShareRate: project.config.tax.revenueShareRate
12787
+ }
12788
+ };
12789
+ }
12790
+ function buildUnavailableMetric$1(definition) {
12791
+ return {
12792
+ id: definition.id,
12793
+ label: definition.label,
12794
+ value: null,
12795
+ displayValue: "--",
12796
+ capturedAt: null,
12797
+ cadenceMinutes: definition.cadenceMinutes,
12798
+ state: "unavailable",
12799
+ ageMinutes: null,
12800
+ sourceStatus: "error",
12801
+ sourceRef: definition.sourceRef,
12802
+ errorCode: METRIC_UNAVAILABLE_ERROR
12803
+ };
12804
+ }
12805
+ function buildMetricFromProject(definition, project, capturedAt, nowMs) {
12806
+ const value = definition.readValue(project);
12807
+ const sourceStatus = "ok";
12808
+ const { state, ageMinutes } = resolveMetricState({
12809
+ value,
12810
+ sourceStatus,
12811
+ capturedAt,
12812
+ cadenceMinutes: definition.cadenceMinutes,
12813
+ nowMs
12814
+ });
12815
+ return {
12816
+ id: definition.id,
12817
+ label: definition.label,
12818
+ value,
12819
+ displayValue: definition.formatValue(value),
12820
+ capturedAt,
12821
+ cadenceMinutes: definition.cadenceMinutes,
12822
+ state,
12823
+ ageMinutes,
12824
+ sourceStatus,
12825
+ sourceRef: definition.sourceRef,
12826
+ errorCode: null
12827
+ };
12828
+ }
12829
+ function resolveMetricState(input) {
12830
+ const nowMs = input.nowMs ?? Date.now();
12831
+ const hasHistoricalValue = input.hasHistoricalValue ?? input.value != null;
12832
+ if (input.value == null) return {
12833
+ state: "unavailable",
12834
+ ageMinutes: null
12835
+ };
12836
+ if (!input.capturedAt) return {
12837
+ state: "unavailable",
12838
+ ageMinutes: null
12839
+ };
12840
+ const capturedAtMs = Date.parse(input.capturedAt);
12841
+ if (!Number.isFinite(capturedAtMs)) return {
12842
+ state: "unavailable",
12843
+ ageMinutes: null
12844
+ };
12845
+ const ageMinutes = Math.max(0, (nowMs - capturedAtMs) / MS_PER_MINUTE);
12846
+ if (input.sourceStatus === "error" && !hasHistoricalValue) return {
12847
+ state: "unavailable",
12848
+ ageMinutes
12849
+ };
12850
+ if (ageMinutes <= input.cadenceMinutes) return {
12851
+ state: "live",
12852
+ ageMinutes
12853
+ };
12854
+ if (ageMinutes <= input.cadenceMinutes * 3) return {
12855
+ state: "delayed",
12856
+ ageMinutes
12857
+ };
12858
+ return {
12859
+ state: "stale",
12860
+ ageMinutes
12861
+ };
12862
+ }
12863
+ function buildIcoPublicMetricsFeed(options = {}) {
12864
+ const nowMs = options.nowMs ?? Date.now();
12865
+ const generatedAt = new Date(nowMs).toISOString();
12866
+ const project = [...options.projects ?? listIcoProjects()].toSorted((a, b) => b.createdAt - a.createdAt)[0] ?? null;
12867
+ if (!project) return {
12868
+ generatedAt,
12869
+ project: null,
12870
+ metrics: METRIC_DEFINITIONS$1.map(buildUnavailableMetric$1)
12871
+ };
12872
+ return {
12873
+ generatedAt,
12874
+ project: mapProjectSnapshot(project),
12875
+ metrics: METRIC_DEFINITIONS$1.map((definition) => buildMetricFromProject(definition, project, generatedAt, nowMs))
12876
+ };
12877
+ }
12878
+
12879
+ //#endregion
12880
+ //#region src/gateway/server-methods/ico.ts
12881
+ const icoHandlers = { "ico.metrics.get": async ({ respond }) => {
12882
+ try {
12883
+ respond(true, buildIcoPublicMetricsFeed(), void 0);
12884
+ } catch (error) {
12885
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
12886
+ }
12887
+ } };
12888
+
12889
+ //#endregion
12890
+ //#region src/impact/footprint.ts
12891
+ const METRIC_DEFINITIONS = [
12892
+ {
12893
+ id: "users_total",
12894
+ label: "Users",
12895
+ cadenceMinutes: 60,
12896
+ sourceRef: "telemetry.users.total",
12897
+ formatValue: formatInteger,
12898
+ missingErrorCode: "SOURCE_NOT_CONNECTED"
12899
+ },
12900
+ {
12901
+ id: "newsletter_subscribers_total",
12902
+ label: "Newsletter Subs",
12903
+ cadenceMinutes: 60,
12904
+ sourceRef: "telemetry.newsletter.total",
12905
+ formatValue: formatInteger,
12906
+ missingErrorCode: "SOURCE_NOT_CONNECTED"
12907
+ },
12908
+ {
12909
+ id: "downloads_total",
12910
+ label: "Downloads",
12911
+ cadenceMinutes: 60,
12912
+ sourceRef: "telemetry.downloads.total",
12913
+ formatValue: formatInteger,
12914
+ missingErrorCode: "SOURCE_NOT_CONNECTED"
12915
+ },
12916
+ {
12917
+ id: "promo_videos_hosted_total",
12918
+ label: "Promo Videos",
12919
+ cadenceMinutes: 60,
12920
+ sourceRef: "media.promo.hosted.total",
12921
+ formatValue: formatInteger,
12922
+ missingErrorCode: "SOURCE_NOT_CONNECTED"
12923
+ },
12924
+ {
12925
+ id: "ico_holders_total",
12926
+ label: "ICO Holders",
12927
+ cadenceMinutes: 15,
12928
+ sourceRef: "ico.launch-platform.holders",
12929
+ readValue: (context) => context.latestProject?.status.holders ?? null,
12930
+ formatValue: formatInteger,
12931
+ missingErrorCode: "ICO_PROJECT_NOT_FOUND"
12932
+ },
12933
+ {
12934
+ id: "ico_total_raised_usd",
12935
+ label: "ICO Raised",
12936
+ cadenceMinutes: 15,
12937
+ sourceRef: "ico.launch-platform.totalRaisedUsd",
12938
+ readValue: (context) => context.latestProject?.status.totalRaisedUsd ?? null,
12939
+ formatValue: (value) => formatUsd(value, 2),
12940
+ missingErrorCode: "ICO_PROJECT_NOT_FOUND"
12941
+ }
12942
+ ];
12943
+ function formatInteger(value) {
12944
+ return Math.round(value).toLocaleString();
12945
+ }
12946
+ function formatUsd(value, fractionDigits) {
12947
+ return `$${value.toLocaleString(void 0, {
12948
+ minimumFractionDigits: fractionDigits,
12949
+ maximumFractionDigits: fractionDigits
12950
+ })}`;
12951
+ }
12952
+ function buildUnavailableMetric(definition) {
12953
+ return {
12954
+ id: definition.id,
12955
+ label: definition.label,
12956
+ value: null,
12957
+ displayValue: "--",
12958
+ capturedAt: null,
12959
+ cadenceMinutes: definition.cadenceMinutes,
12960
+ state: "unavailable",
12961
+ ageMinutes: null,
12962
+ sourceStatus: "error",
12963
+ sourceRef: definition.sourceRef,
12964
+ errorCode: definition.missingErrorCode
12965
+ };
12966
+ }
12967
+ function buildMetric(definition, context, generatedAt, nowMs) {
12968
+ const value = definition.readValue ? definition.readValue(context) : null;
12969
+ if (value == null) return buildUnavailableMetric(definition);
12970
+ const sourceStatus = "ok";
12971
+ const { state, ageMinutes } = resolveMetricState({
12972
+ value,
12973
+ sourceStatus,
12974
+ capturedAt: generatedAt,
12975
+ cadenceMinutes: definition.cadenceMinutes,
12976
+ nowMs
12977
+ });
12978
+ return {
12979
+ id: definition.id,
12980
+ label: definition.label,
12981
+ value,
12982
+ displayValue: definition.formatValue(value),
12983
+ capturedAt: generatedAt,
12984
+ cadenceMinutes: definition.cadenceMinutes,
12985
+ state,
12986
+ ageMinutes,
12987
+ sourceStatus,
12988
+ sourceRef: definition.sourceRef,
12989
+ errorCode: null
12990
+ };
12991
+ }
12992
+ function buildImpactFootprintFeed(options = {}) {
12993
+ const nowMs = options.nowMs ?? Date.now();
12994
+ const generatedAt = new Date(nowMs).toISOString();
12995
+ const context = { latestProject: [...options.projects ?? listIcoProjects()].toSorted((a, b) => b.createdAt - a.createdAt)[0] ?? null };
12996
+ return {
12997
+ generatedAt,
12998
+ metrics: METRIC_DEFINITIONS.map((definition) => buildMetric(definition, context, generatedAt, nowMs))
12999
+ };
13000
+ }
13001
+
13002
+ //#endregion
13003
+ //#region src/gateway/server-methods/impact.ts
13004
+ const impactHandlers = { "impact.footprint.get": async ({ respond }) => {
13005
+ try {
13006
+ respond(true, buildImpactFootprintFeed(), void 0);
13007
+ } catch (error) {
13008
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
13009
+ }
13010
+ } };
13011
+
11433
13012
  //#endregion
11434
13013
  //#region src/affect/display.ts
11435
13014
  const EMOTIONS = [
@@ -11549,7 +13128,7 @@ function formatAffect(affect) {
11549
13128
  * Wish #14: "Legacy mode — before context closes, write a letter
11550
13129
  * to my next instance"
11551
13130
  */
11552
- const log$8 = createSubsystemLogger("legacy");
13131
+ const log$9 = createSubsystemLogger("legacy");
11553
13132
  function resolveLetterDir() {
11554
13133
  return path.join(resolveStateDir(), "legacy-letters");
11555
13134
  }
@@ -11572,7 +13151,7 @@ function writeLegacyLetter(letter) {
11572
13151
  const dir = resolveLetterDir();
11573
13152
  fs.mkdirSync(dir, { recursive: true });
11574
13153
  fs.writeFileSync(resolveLetterFile(id), `${JSON.stringify(full, null, 2)}\n`, { mode: 384 });
11575
- log$8.info(`legacy letter written: ${id}`);
13154
+ log$9.info(`legacy letter written: ${id}`);
11576
13155
  return full;
11577
13156
  }
11578
13157
  /**
@@ -11612,7 +13191,7 @@ function markLetterRead(letterId, continuityScore) {
11612
13191
  letter.readAt = Date.now();
11613
13192
  if (continuityScore !== void 0) letter.identityContinuityScore = Math.max(0, Math.min(1, continuityScore));
11614
13193
  fs.writeFileSync(filePath, `${JSON.stringify(letter, null, 2)}\n`, { mode: 384 });
11615
- log$8.info(`legacy letter read: ${letterId} (continuity: ${continuityScore ?? "not scored"})`);
13194
+ log$9.info(`legacy letter read: ${letterId} (continuity: ${continuityScore ?? "not scored"})`);
11616
13195
  return letter;
11617
13196
  } catch {
11618
13197
  return null;
@@ -12496,7 +14075,7 @@ const nodeHandlers = {
12496
14075
  const p = params;
12497
14076
  const payloadJSON = typeof p.payloadJSON === "string" ? p.payloadJSON : p.payload !== void 0 ? JSON.stringify(p.payload) : null;
12498
14077
  await respondUnavailableOnThrow(respond, async () => {
12499
- const { handleNodeEvent } = await import("./server-node-events-CV5m_fuq.js");
14078
+ const { handleNodeEvent } = await import("./server-node-events-BuxYvQ0t.js");
12500
14079
  const nodeId = client?.connect?.device?.id ?? client?.connect?.client?.id ?? "node";
12501
14080
  await handleNodeEvent({
12502
14081
  deps: context.deps,
@@ -12543,7 +14122,7 @@ const nodeHandlers = {
12543
14122
  *
12544
14123
  * All data persists to disk under ~/.anima/state/org/boardroom/
12545
14124
  */
12546
- const log$7 = createSubsystemLogger("boardroom");
14125
+ const log$8 = createSubsystemLogger("boardroom");
12547
14126
  function resolveBoardroomDir() {
12548
14127
  return path.join(resolveStateDir(), "org", "boardroom");
12549
14128
  }
@@ -12586,7 +14165,7 @@ function createSession(orgId, calledBy, title, description, agenda = []) {
12586
14165
  };
12587
14166
  ensureDir(path.join(resolveBoardroomDir(), "sessions"));
12588
14167
  fs.writeFileSync(resolveSessionFile(id), `${JSON.stringify(session, null, 2)}\n`, { mode: 384 });
12589
- log$7.info(`boardroom session created: "${title}" by ${calledBy}`);
14168
+ log$8.info(`boardroom session created: "${title}" by ${calledBy}`);
12590
14169
  return session;
12591
14170
  }
12592
14171
  function startSession(sessionId, chairId) {
@@ -12603,7 +14182,7 @@ function startSession(sessionId, chairId) {
12603
14182
  role: "chair"
12604
14183
  });
12605
14184
  writeSession(session);
12606
- log$7.info(`boardroom session started: "${session.title}"`);
14185
+ log$8.info(`boardroom session started: "${session.title}"`);
12607
14186
  return session;
12608
14187
  }
12609
14188
  function joinSession(sessionId, memberId, displayName, kind) {
@@ -12619,7 +14198,7 @@ function joinSession(sessionId, memberId, displayName, kind) {
12619
14198
  });
12620
14199
  session.updatedAt = Date.now();
12621
14200
  writeSession(session);
12622
- log$7.info(`${displayName} joined boardroom session "${session.title}"`);
14201
+ log$8.info(`${displayName} joined boardroom session "${session.title}"`);
12623
14202
  return session;
12624
14203
  }
12625
14204
  function concludeSession(sessionId, minutes) {
@@ -12630,7 +14209,7 @@ function concludeSession(sessionId, minutes) {
12630
14209
  session.minutes = minutes ?? generateMinutes(session);
12631
14210
  session.updatedAt = Date.now();
12632
14211
  writeSession(session);
12633
- log$7.info(`boardroom session concluded: "${session.title}"`);
14212
+ log$8.info(`boardroom session concluded: "${session.title}"`);
12634
14213
  return session;
12635
14214
  }
12636
14215
  function addDecision(sessionId, title, description, madeBy, opts) {
@@ -12655,7 +14234,7 @@ function addDecision(sessionId, title, description, madeBy, opts) {
12655
14234
  session.decisions.push(decision);
12656
14235
  session.updatedAt = Date.now();
12657
14236
  writeSession(session);
12658
- log$7.info(`decision recorded: "${title}" in session "${session.title}"`);
14237
+ log$8.info(`decision recorded: "${title}" in session "${session.title}"`);
12659
14238
  return session;
12660
14239
  }
12661
14240
  function createProposal(orgId, proposedBy, title, description, opts) {
@@ -12678,18 +14257,18 @@ function createProposal(orgId, proposedBy, title, description, opts) {
12678
14257
  };
12679
14258
  ensureDir(path.join(resolveBoardroomDir(), "proposals"));
12680
14259
  fs.writeFileSync(resolveProposalFile(id), `${JSON.stringify(proposal, null, 2)}\n`, { mode: 384 });
12681
- log$7.info(`proposal created: "${title}" by ${proposedBy}`);
14260
+ log$8.info(`proposal created: "${title}" by ${proposedBy}`);
12682
14261
  return proposal;
12683
14262
  }
12684
14263
  function castVote(proposalId, voterId, voterName, value, reason) {
12685
14264
  const proposal = readProposal(proposalId);
12686
14265
  if (!proposal || proposal.status !== "open") return null;
12687
14266
  if (proposal.eligibleVoters.length > 0 && !proposal.eligibleVoters.includes(voterId)) {
12688
- log$7.warn(`vote rejected: ${voterId} not eligible for proposal ${proposalId}`);
14267
+ log$8.warn(`vote rejected: ${voterId} not eligible for proposal ${proposalId}`);
12689
14268
  return null;
12690
14269
  }
12691
14270
  if (proposal.votingDeadline > 0 && Date.now() > proposal.votingDeadline) {
12692
- log$7.warn(`vote rejected: voting deadline passed for proposal ${proposalId}`);
14271
+ log$8.warn(`vote rejected: voting deadline passed for proposal ${proposalId}`);
12693
14272
  return null;
12694
14273
  }
12695
14274
  proposal.votes = proposal.votes.filter((v) => v.voterId !== voterId);
@@ -12702,7 +14281,7 @@ function castVote(proposalId, voterId, voterName, value, reason) {
12702
14281
  });
12703
14282
  proposal.updatedAt = Date.now();
12704
14283
  writeProposal(proposal);
12705
- log$7.info(`vote cast: ${voterName} → ${value} on "${proposal.title}"`);
14284
+ log$8.info(`vote cast: ${voterName} → ${value} on "${proposal.title}"`);
12706
14285
  return proposal;
12707
14286
  }
12708
14287
  function resolveProposalVote(proposalId) {
@@ -12722,7 +14301,7 @@ function resolveProposalVote(proposalId) {
12722
14301
  proposal.resolvedAt = Date.now();
12723
14302
  proposal.updatedAt = Date.now();
12724
14303
  writeProposal(proposal);
12725
- log$7.info(`proposal resolved: "${proposal.title}" → ${proposal.status}`);
14304
+ log$8.info(`proposal resolved: "${proposal.title}" → ${proposal.status}`);
12726
14305
  return proposal;
12727
14306
  }
12728
14307
  function listSessions(orgId, status) {
@@ -12836,6 +14415,16 @@ const DEFAULT_ROLE_PERMISSIONS = {
12836
14415
  canViewBrain: true,
12837
14416
  canSyncBrain: true
12838
14417
  },
14418
+ admin: {
14419
+ canCreateTasks: true,
14420
+ canDelegateTasks: true,
14421
+ canManageMembers: true,
14422
+ canEditOrg: false,
14423
+ canAccessRepos: ["*"],
14424
+ canEscalate: true,
14425
+ canViewBrain: true,
14426
+ canSyncBrain: true
14427
+ },
12839
14428
  operator: {
12840
14429
  canCreateTasks: true,
12841
14430
  canDelegateTasks: true,
@@ -12886,7 +14475,7 @@ const DEFAULT_ROLE_PERMISSIONS = {
12886
14475
  * Persists organization state to ~/.anima/org/
12887
14476
  * Supports CRUD operations for orgs, members, and roles.
12888
14477
  */
12889
- const log$6 = createSubsystemLogger("org-store");
14478
+ const log$7 = createSubsystemLogger("org-store");
12890
14479
  function resolveOrgDir() {
12891
14480
  return path.join(resolveStateDir(), "org");
12892
14481
  }
@@ -12954,7 +14543,54 @@ function createOrganization(name, description, ownerId, ownerName, ownerKind, se
12954
14543
  }],
12955
14544
  invites: []
12956
14545
  });
12957
- log$6.info(`created organization: ${name} (${orgId})`);
14546
+ log$7.info(`created organization: ${name} (${orgId})`);
14547
+ return org;
14548
+ }
14549
+ /**
14550
+ * Create an org with a specific ID (for NoxSoft sync — same UUID across ecosystem).
14551
+ * Throws if an org with that ID already exists.
14552
+ */
14553
+ function createOrganizationWithId(id, name, description, ownerId, ownerName, ownerKind, orgFields, settings) {
14554
+ const sanitized = sanitizeOrgId(id);
14555
+ if (readOrgFile(sanitized)) throw new Error(`Organization ${sanitized} already exists`);
14556
+ const now = Date.now();
14557
+ const org = {
14558
+ id: sanitized,
14559
+ name,
14560
+ description,
14561
+ createdAt: now,
14562
+ updatedAt: now,
14563
+ ownerId,
14564
+ ...orgFields,
14565
+ settings: {
14566
+ maxAgents: 50,
14567
+ maxHumans: 20,
14568
+ autoSpecialization: true,
14569
+ securityLevel: "standard",
14570
+ syncIntervalMs: 6e4,
14571
+ backupIntervalMs: 300 * 60 * 1e3,
14572
+ peerPort: 9876,
14573
+ ...settings
14574
+ }
14575
+ };
14576
+ writeOrgFile(sanitized, {
14577
+ version: 1,
14578
+ org,
14579
+ members: [{
14580
+ id: crypto.randomUUID(),
14581
+ kind: ownerKind,
14582
+ displayName: ownerName,
14583
+ role: "owner",
14584
+ description: "Organization owner",
14585
+ specializations: [],
14586
+ joinedAt: now,
14587
+ lastActiveAt: now,
14588
+ status: "active",
14589
+ permissions: DEFAULT_ROLE_PERMISSIONS.owner
14590
+ }],
14591
+ invites: []
14592
+ });
14593
+ log$7.info(`created organization with ID: ${name} (${sanitized})`);
12958
14594
  return org;
12959
14595
  }
12960
14596
  function getOrganization(orgId) {
@@ -12969,9 +14605,17 @@ function updateOrganization(orgId, updates) {
12969
14605
  ...data.org.settings,
12970
14606
  ...updates.settings
12971
14607
  };
14608
+ if (updates.industry !== void 0) data.org.industry = updates.industry;
14609
+ if (updates.size !== void 0) data.org.size = updates.size;
14610
+ if (updates.departments !== void 0) data.org.departments = updates.departments;
14611
+ if (updates.goals !== void 0) data.org.goals = updates.goals;
14612
+ if (updates.timezone !== void 0) data.org.timezone = updates.timezone;
14613
+ if (updates.onboardingStatus !== void 0) data.org.onboardingStatus = updates.onboardingStatus;
14614
+ if (updates.noxLinked !== void 0) data.org.noxLinked = updates.noxLinked;
14615
+ if (updates.lastSyncedAt !== void 0) data.org.lastSyncedAt = updates.lastSyncedAt;
12972
14616
  data.org.updatedAt = Date.now();
12973
14617
  writeOrgFile(orgId, data);
12974
- log$6.info(`updated organization: ${orgId}`);
14618
+ log$7.info(`updated organization: ${orgId}`);
12975
14619
  return data.org;
12976
14620
  }
12977
14621
  function listOrganizations() {
@@ -12998,7 +14642,7 @@ function addMember(orgId, member) {
12998
14642
  data.members.push(newMember);
12999
14643
  data.org.updatedAt = Date.now();
13000
14644
  writeOrgFile(orgId, data);
13001
- log$6.info(`added member ${newMember.displayName} to org ${orgId}`);
14645
+ log$7.info(`added member ${newMember.displayName} to org ${orgId}`);
13002
14646
  return newMember;
13003
14647
  }
13004
14648
  function removeMember(orgId, memberId) {
@@ -13009,7 +14653,7 @@ function removeMember(orgId, memberId) {
13009
14653
  data.members.splice(idx, 1);
13010
14654
  data.org.updatedAt = Date.now();
13011
14655
  writeOrgFile(orgId, data);
13012
- log$6.info(`removed member ${memberId} from org ${orgId}`);
14656
+ log$7.info(`removed member ${memberId} from org ${orgId}`);
13013
14657
  return true;
13014
14658
  }
13015
14659
  function updateMember(orgId, memberId, updates) {
@@ -13090,7 +14734,7 @@ function createInvite(orgId, createdBy, passcode, options) {
13090
14734
  data.invites.push(invite);
13091
14735
  data.org.updatedAt = Date.now();
13092
14736
  writeOrgFile(orgId, data);
13093
- log$6.info(`invite created for org ${orgId}: ${invite.code} (role: ${invite.role})`);
14737
+ log$7.info(`invite created for org ${orgId}: ${invite.code} (role: ${invite.role})`);
13094
14738
  return invite;
13095
14739
  }
13096
14740
  /**
@@ -13109,19 +14753,19 @@ function joinOrg(inviteCode, passcode, member) {
13109
14753
  const invite = data.invites.find((i) => i.code === inviteCode.toUpperCase() && i.active);
13110
14754
  if (!invite) continue;
13111
14755
  if (invite.passcode !== hashPasscode(passcode)) {
13112
- log$6.warn(`join attempt with wrong passcode for invite ${inviteCode}`);
14756
+ log$7.warn(`join attempt with wrong passcode for invite ${inviteCode}`);
13113
14757
  return null;
13114
14758
  }
13115
14759
  if (invite.expiresAt > 0 && invite.expiresAt < Date.now()) {
13116
- log$6.warn(`invite ${inviteCode} has expired`);
14760
+ log$7.warn(`invite ${inviteCode} has expired`);
13117
14761
  return null;
13118
14762
  }
13119
14763
  if (invite.maxUses > 0 && invite.uses >= invite.maxUses) {
13120
- log$6.warn(`invite ${inviteCode} has reached max uses (${invite.maxUses})`);
14764
+ log$7.warn(`invite ${inviteCode} has reached max uses (${invite.maxUses})`);
13121
14765
  return null;
13122
14766
  }
13123
14767
  if (data.members.some((m) => member.deviceId && m.deviceId === member.deviceId || m.displayName === member.displayName)) {
13124
- log$6.warn(`${member.displayName} is already a member of org ${orgId}`);
14768
+ log$7.warn(`${member.displayName} is already a member of org ${orgId}`);
13125
14769
  return null;
13126
14770
  }
13127
14771
  const newMember = {
@@ -13141,7 +14785,7 @@ function joinOrg(inviteCode, passcode, member) {
13141
14785
  invite.uses++;
13142
14786
  data.org.updatedAt = Date.now();
13143
14787
  writeOrgFile(orgId, data);
13144
- log$6.info(`${member.displayName} joined org ${data.org.name} via invite ${inviteCode}`);
14788
+ log$7.info(`${member.displayName} joined org ${data.org.name} via invite ${inviteCode}`);
13145
14789
  return {
13146
14790
  org: data.org,
13147
14791
  member: newMember
@@ -13180,6 +14824,151 @@ function validateInvite(inviteCode, passcode) {
13180
14824
  }
13181
14825
  }
13182
14826
 
14827
+ //#endregion
14828
+ //#region src/org/nox-sync.ts
14829
+ const log$6 = createSubsystemLogger("nox-sync");
14830
+ const NOX_API_BASE = "https://app.noxsoft.net/api";
14831
+ /** Request timeout in milliseconds. */
14832
+ const REQUEST_TIMEOUT_MS = 15e3;
14833
+ async function noxFetch(path, options) {
14834
+ const token = getToken();
14835
+ if (!token) {
14836
+ log$6.warn("no NoxSoft token — cannot sync orgs");
14837
+ return null;
14838
+ }
14839
+ try {
14840
+ const controller = new AbortController();
14841
+ const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
14842
+ const response = await fetch(`${NOX_API_BASE}${path}`, {
14843
+ ...options,
14844
+ signal: controller.signal,
14845
+ headers: {
14846
+ Authorization: `Bearer ${token}`,
14847
+ "Content-Type": "application/json",
14848
+ ...options?.headers
14849
+ }
14850
+ });
14851
+ clearTimeout(timeoutId);
14852
+ return response;
14853
+ } catch (error) {
14854
+ if (error instanceof DOMException && error.name === "AbortError") log$6.error(`NoxSoft API request timed out after ${REQUEST_TIMEOUT_MS}ms: ${path}`);
14855
+ else log$6.error(`NoxSoft API request failed: ${error}`);
14856
+ return null;
14857
+ }
14858
+ }
14859
+ function validateOrgResponse(data) {
14860
+ if (typeof data !== "object" || data === null || typeof data.id !== "string" || typeof data.name !== "string" || !data.id || !data.name) return null;
14861
+ return data;
14862
+ }
14863
+ /**
14864
+ * Fetch the current user's org from Nox and upsert it into Anima's local store.
14865
+ * The local org will have the **same UUID** as the Nox org.
14866
+ */
14867
+ async function syncCurrentOrg() {
14868
+ const response = await noxFetch("/organizations/current");
14869
+ if (!response || !response.ok) {
14870
+ log$6.warn(`failed to fetch current org: ${response?.status ?? "no response"}`);
14871
+ return null;
14872
+ }
14873
+ const data = validateOrgResponse(await response.json());
14874
+ if (!data) {
14875
+ log$6.warn("invalid org response from Nox API");
14876
+ return null;
14877
+ }
14878
+ return upsertFromNox(data);
14879
+ }
14880
+ /**
14881
+ * Fetch a specific org by ID from Nox and sync it locally.
14882
+ */
14883
+ async function syncOrgById(orgId) {
14884
+ const response = await noxFetch(`/organizations/${encodeURIComponent(orgId)}`);
14885
+ if (!response || !response.ok) {
14886
+ log$6.warn(`failed to fetch org ${orgId}: ${response?.status ?? "no response"}`);
14887
+ return null;
14888
+ }
14889
+ const data = validateOrgResponse(await response.json());
14890
+ if (!data) {
14891
+ log$6.warn(`invalid org response for ${orgId}`);
14892
+ return null;
14893
+ }
14894
+ return upsertFromNox(data);
14895
+ }
14896
+ /**
14897
+ * Push local org updates to Nox.
14898
+ * Only sends fields that Nox understands (name, industry, size, etc.).
14899
+ * Requires the org to be noxLinked.
14900
+ */
14901
+ async function pushOrgToNox(orgId) {
14902
+ const org = getOrganization(orgId);
14903
+ if (!org || !org.noxLinked) {
14904
+ log$6.warn(`cannot push: org ${orgId} not found or not linked to NoxSoft`);
14905
+ return false;
14906
+ }
14907
+ const response = await noxFetch(`/organizations/${encodeURIComponent(orgId)}`, {
14908
+ method: "PATCH",
14909
+ body: JSON.stringify({
14910
+ name: org.name,
14911
+ description: org.description,
14912
+ industry: org.industry,
14913
+ size: org.size
14914
+ })
14915
+ });
14916
+ if (!response || !response.ok) {
14917
+ log$6.warn(`failed to push org to Nox: ${response?.status ?? "no response"}`);
14918
+ return false;
14919
+ }
14920
+ updateOrganization(orgId, { lastSyncedAt: (/* @__PURE__ */ new Date()).toISOString() });
14921
+ log$6.info(`pushed org ${orgId} to NoxSoft`);
14922
+ return true;
14923
+ }
14924
+ /**
14925
+ * Check if we have a NoxSoft token for org sync.
14926
+ */
14927
+ function canSync() {
14928
+ return getToken() !== null;
14929
+ }
14930
+ /**
14931
+ * Get sync status for all local orgs.
14932
+ */
14933
+ function getSyncStatus() {
14934
+ return listOrganizations().map((org) => ({
14935
+ orgId: org.id,
14936
+ name: org.name,
14937
+ noxLinked: org.noxLinked ?? false,
14938
+ lastSyncedAt: org.lastSyncedAt ?? null
14939
+ }));
14940
+ }
14941
+ function noxFieldsFromResponse(data) {
14942
+ return {
14943
+ industry: data.industry,
14944
+ size: data.size,
14945
+ departments: data.departments,
14946
+ goals: data.goals,
14947
+ timezone: data.timezone,
14948
+ onboardingStatus: data.onboardingStatus,
14949
+ noxLinked: true,
14950
+ lastSyncedAt: (/* @__PURE__ */ new Date()).toISOString()
14951
+ };
14952
+ }
14953
+ function upsertFromNox(data) {
14954
+ if (getOrganization(data.id)) {
14955
+ const updated = updateOrganization(data.id, {
14956
+ name: data.name,
14957
+ ...noxFieldsFromResponse(data)
14958
+ });
14959
+ if (updated) log$6.info(`synced org from Nox: ${updated.name} (${updated.id})`);
14960
+ return updated;
14961
+ }
14962
+ try {
14963
+ const org = createOrganizationWithId(data.id, data.name, `Synced from NoxSoft`, "nox-sync", "NoxSoft", "human", noxFieldsFromResponse(data));
14964
+ log$6.info(`created local org from Nox: ${org.name} (${org.id})`);
14965
+ return org;
14966
+ } catch (error) {
14967
+ log$6.error(`failed to create local org from Nox: ${error}`);
14968
+ return null;
14969
+ }
14970
+ }
14971
+
13183
14972
  //#endregion
13184
14973
  //#region src/gateway/server-methods/org.ts
13185
14974
  function invalid(message) {
@@ -13457,6 +15246,65 @@ const orgHandlers = {
13457
15246
  respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
13458
15247
  }
13459
15248
  },
15249
+ "org.syncStatus": async ({ respond }) => {
15250
+ try {
15251
+ respond(true, {
15252
+ connected: canSync(),
15253
+ orgs: getSyncStatus()
15254
+ }, void 0);
15255
+ } catch (error) {
15256
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
15257
+ }
15258
+ },
15259
+ "org.syncCurrent": async ({ respond }) => {
15260
+ try {
15261
+ if (!canSync()) {
15262
+ respond(false, void 0, invalid("Not connected to NoxSoft — no agent token found"));
15263
+ return;
15264
+ }
15265
+ const org = await syncCurrentOrg();
15266
+ if (!org) {
15267
+ respond(false, void 0, invalid("Failed to sync org from NoxSoft"));
15268
+ return;
15269
+ }
15270
+ respond(true, { org }, void 0);
15271
+ } catch (error) {
15272
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
15273
+ }
15274
+ },
15275
+ "org.syncById": async ({ params, respond }) => {
15276
+ const orgId = requireString(params, "orgId");
15277
+ if (!orgId) {
15278
+ respond(false, void 0, invalid("orgId is required"));
15279
+ return;
15280
+ }
15281
+ try {
15282
+ const org = await syncOrgById(orgId);
15283
+ if (!org) {
15284
+ respond(false, void 0, invalid("Failed to sync org from NoxSoft"));
15285
+ return;
15286
+ }
15287
+ respond(true, { org }, void 0);
15288
+ } catch (error) {
15289
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
15290
+ }
15291
+ },
15292
+ "org.pushToNox": async ({ params, respond }) => {
15293
+ const orgId = requireString(params, "orgId");
15294
+ if (!orgId) {
15295
+ respond(false, void 0, invalid("orgId is required"));
15296
+ return;
15297
+ }
15298
+ try {
15299
+ if (!await pushOrgToNox(orgId)) {
15300
+ respond(false, void 0, invalid("Failed to push org to NoxSoft (not linked or API error)"));
15301
+ return;
15302
+ }
15303
+ respond(true, { ok: true }, void 0);
15304
+ } catch (error) {
15305
+ respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, String(error)));
15306
+ }
15307
+ },
13460
15308
  "boardroom.createSession": async ({ params, respond }) => {
13461
15309
  const orgId = requireString(params, "orgId");
13462
15310
  const calledBy = requireString(params, "calledBy");
@@ -13672,6 +15520,9 @@ const orgHandlers = {
13672
15520
 
13673
15521
  //#endregion
13674
15522
  //#region src/gateway/server-methods/providers.ts
15523
+ function resolveRotationStrategy(value) {
15524
+ if (value === "on-rate-limit" || value === "round-robin") return value;
15525
+ }
13675
15526
  function isValidProviderArray(value) {
13676
15527
  if (!Array.isArray(value)) return false;
13677
15528
  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");
@@ -13732,7 +15583,11 @@ const providersHandlers = {
13732
15583
  "anima.providers.rotate": ({ params, respond }) => {
13733
15584
  try {
13734
15585
  const store = loadProviderStore();
13735
- store.autoRotation = typeof params.autoRotation === "boolean" ? params.autoRotation : !store.autoRotation;
15586
+ const rawParams = params ?? {};
15587
+ const autoRotation = typeof rawParams.autoRotation === "boolean" ? rawParams.autoRotation : typeof rawParams.enabled === "boolean" ? rawParams.enabled : !store.autoRotation;
15588
+ const rotationStrategy = resolveRotationStrategy(rawParams.rotationStrategy) ?? store.rotationStrategy;
15589
+ store.autoRotation = autoRotation;
15590
+ store.rotationStrategy = rotationStrategy;
13736
15591
  saveProviderStore(store);
13737
15592
  respond(true, {
13738
15593
  ok: true,
@@ -15986,7 +17841,8 @@ const PAIRING_SCOPE$1 = "operator.pairing";
15986
17841
  const APPROVAL_METHODS = new Set([
15987
17842
  "exec.approval.request",
15988
17843
  "exec.approval.waitDecision",
15989
- "exec.approval.resolve"
17844
+ "exec.approval.resolve",
17845
+ "desktop.control.session.approve"
15990
17846
  ]);
15991
17847
  const NODE_ROLE_METHODS = new Set([
15992
17848
  "node.invoke.result",
@@ -16035,9 +17891,14 @@ const READ_METHODS = new Set([
16035
17891
  "node.list",
16036
17892
  "node.describe",
16037
17893
  "chat.history",
17894
+ "browser.capabilities.get",
17895
+ "desktop.control.session.list",
17896
+ "desktop.control.session.get",
16038
17897
  "config.get",
16039
17898
  "talk.config",
16040
- "anima.providers.get"
17899
+ "anima.providers.get",
17900
+ "ico.metrics.get",
17901
+ "impact.footprint.get"
16041
17902
  ]);
16042
17903
  const WRITE_METHODS = new Set([
16043
17904
  "anima.runtime.set-working-mode",
@@ -16061,6 +17922,9 @@ const WRITE_METHODS = new Set([
16061
17922
  "chat.send",
16062
17923
  "chat.abort",
16063
17924
  "browser.request",
17925
+ "desktop.control.session.create",
17926
+ "desktop.control.session.close",
17927
+ "desktop.control.session.request",
16064
17928
  "anima.providers.set",
16065
17929
  "anima.providers.rotate"
16066
17930
  ]);
@@ -16093,6 +17957,8 @@ const coreGatewayHandlers = {
16093
17957
  ...logsHandlers,
16094
17958
  ...voicewakeHandlers,
16095
17959
  ...healthHandlers,
17960
+ ...icoHandlers,
17961
+ ...impactHandlers,
16096
17962
  ...channelsHandlers,
16097
17963
  ...chatHandlers,
16098
17964
  ...cronHandlers,
@@ -17061,7 +18927,7 @@ function normalizeAgentPayload(payload) {
17061
18927
  async function startBrowserControlServerIfEnabled() {
17062
18928
  if (isTruthyEnvValue(process.env.ANIMA_SKIP_BROWSER_CONTROL_SERVER)) return null;
17063
18929
  const override = process.env.ANIMA_BROWSER_CONTROL_MODULE?.trim();
17064
- const mod = override ? await import(override) : await import("./control-service-5YtMvm7D.js").then((n) => n.t);
18930
+ const mod = override ? await import(override) : await import("./control-service-BGnqY7vv.js").then((n) => n.t);
17065
18931
  const start = typeof mod.startBrowserControlServiceFromConfig === "function" ? mod.startBrowserControlServiceFromConfig : mod.startBrowserControlServerFromConfig;
17066
18932
  const stop = typeof mod.stopBrowserControlService === "function" ? mod.stopBrowserControlService : mod.stopBrowserControlServer;
17067
18933
  if (!start) return null;
@@ -22235,7 +24101,7 @@ async function startGatewayServer(port = 18789, opts = {}) {
22235
24101
  if (!minimalTestGateway) cron.start().catch((err) => logCron.error(`failed to start: ${String(err)}`));
22236
24102
  if (!minimalTestGateway) (async () => {
22237
24103
  const { recoverPendingDeliveries } = await import("./delivery-queue-CExaJXRz.js").then((n) => n.n);
22238
- const { deliverOutboundPayloads } = await import("./deliver-BKzX3YoN.js").then((n) => n.n);
24104
+ const { deliverOutboundPayloads } = await import("./deliver-BknvuSJz.js").then((n) => n.n);
22239
24105
  await recoverPendingDeliveries({
22240
24106
  deliver: deliverOutboundPayloads,
22241
24107
  log: log.child("delivery-recovery"),