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