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