@noxsoft/anima 5.0.1 → 5.0.3
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/dist/{accounts-BOkEyUcS.js → accounts-DjjQHOIW.js} +5 -5
- package/dist/{accounts-CVmv61PJ.js → accounts-Dzi6Ld7X.js} +2 -2
- package/dist/{acp-cli-C8aBckv5.js → acp-cli-I-yv1f5O.js} +15 -15
- package/dist/{acp-cli-BcshtFqY.js → acp-cli-QBd9GLqD.js} +3 -3
- package/dist/{agent-Cil6Zvns.js → agent-B3KeHK1A.js} +9 -9
- package/dist/{agent-c49U1LxE.js → agent-fG1PVmNy.js} +16 -16
- package/dist/{agent-scope-DICrDp7Y.js → agent-scope-BHR6uOLT.js} +2 -2
- package/dist/{agent-scope-BLiq3nK_.js → agent-scope-ryeVDUKe.js} +2 -2
- package/dist/{agents-2BloqCjm.js → agents-DY5ZtGB2.js} +9 -9
- package/dist/{agents.config-Bqr5rrkV.js → agents.config-DmF0fsB6.js} +1 -1
- package/dist/{anthropic-direct-runner-mh6c_WBB.js → anthropic-direct-runner-BJosFvVm.js} +41 -18
- package/dist/{anthropic-direct-runner-BVlO2Vi5.js → anthropic-direct-runner-BXb24VJt.js} +50 -27
- package/dist/{audit-BbmRSFjf.js → audit-BTMmL_HS.js} +5 -5
- package/dist/{audit-DegswVkZ.js → audit-qHMf9jWY.js} +16 -16
- package/dist/{auth-Cs_c5TKt.js → auth-DQfFqQBz.js} +3 -3
- package/dist/{auth-choice-BVAMr2Dk.js → auth-choice-BoyT3ahK.js} +60 -8
- package/dist/{auth-health-D0VUH0FQ.js → auth-health-BcABdgUT.js} +1 -1
- package/dist/{auth-profiles-k5IOWaG2.js → auth-profiles-BF5x9Ej0.js} +1 -1
- package/dist/{auth-profiles-BhZX2spm.js → auth-profiles-C_LmTbMb.js} +5 -5
- package/dist/{auth-profiles-Chf1JBpl.js → auth-profiles-Da39zGOD.js} +4 -4
- package/dist/{auth-store-D0vDEvCx.js → auth-store-CXZzirrJ.js} +3 -3
- package/dist/{auth-store-BMwyg-WK.js → auth-store-DTpDRu--.js} +3 -3
- package/dist/{banner-CgxCSS-T.js → banner-CJVa8aiZ.js} +1 -1
- package/dist/{bonjour-discovery-DaCmsB4i.js → bonjour-discovery-B3IeIN1u.js} +2 -2
- package/dist/build-info.json +3 -3
- package/dist/bundled/boot-md/handler.js +22 -22
- package/dist/bundled/bootstrap-extra-files/handler.js +7 -7
- package/dist/bundled/session-memory/handler.js +19 -19
- package/dist/{call-Z_GCO8CL.js → call-BKsdSTVf.js} +1 -1
- package/dist/{call-BOwaQIXo.js → call-C3CH9PNK.js} +6 -6
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/{catalog-B-pfqu76.js → catalog-3hzXhHxJ.js} +2 -2
- package/dist/{channel-web-Y8i3EzJq.js → channel-web-Df3Ay9v7.js} +18 -18
- package/dist/{channels-status-issues-DenKLCLq.js → channels-status-issues-D5XAOSaj.js} +4 -4
- package/dist/{chrome-C3-muxXb.js → chrome-CLhrEjgx.js} +4 -4
- package/dist/{chrome-Cxl7I5SB.js → chrome-CkSIMI7j.js} +2 -2
- package/dist/{chunk-DGg8zCWl.js → chunk-Dq7ILx_r.js} +2 -2
- package/dist/{chunk-DFCmYqgJ.js → chunk-fcLG1hME.js} +1 -1
- package/dist/{clack-prompter-CCRr4nAr.js → clack-prompter-DmD_A7en.js} +5 -5
- package/dist/{clack-prompter-B-ZJG628.js → clack-prompter-bl-Zsxpq.js} +1 -1
- package/dist/cli/daemon-cli.js +1 -1
- package/dist/{cli-C3uw3mId.js → cli-0-FvuyBX.js} +22 -22
- package/dist/cli-CLVEx1Po.js +104 -0
- package/dist/{cli-session-BzZYmGP1.js → cli-session-CmX1oA1T.js} +7 -7
- package/dist/{cli-session-DgUHOBYo.js → cli-session-gR2abU0g.js} +16 -16
- package/dist/{client-BObcTF_9.js → client-BT3pbXCv.js} +3 -3
- package/dist/{command-registry-DLofaVIN.js → command-registry-C3SmyTQU.js} +12 -12
- package/dist/{common-k1Cu8adj.js → common-Bi43BlMQ.js} +2 -2
- package/dist/{common-Cd7BmlCQ.js → common-CSTOiddD.js} +2 -2
- package/dist/{completion-cli-C9KvX2ZF.js → completion-cli-308M08su.js} +2 -2
- package/dist/{completion-cli-3eYvtAih.js → completion-cli-D7gWcWEj.js} +3 -3
- package/dist/{config-B-9UciOO.js → config-BfhpauV9.js} +6 -6
- package/dist/{config-CG7uuHNE.js → config-Dk-5Mb_G.js} +6 -6
- package/dist/{config-D6D_ieel.js → config-Ofh9gKvs.js} +1 -1
- package/dist/config-cli-CajDGi9m.js +15 -0
- package/dist/{config-cli-CBXWDtvj.js → config-cli-De0z7mvk.js} +3 -3
- package/dist/{config-guard-BT3OoaEu.js → config-guard-BnkobgvR.js} +21 -21
- package/dist/{config-guard-qiKju2Fg.js → config-guard-DlOs5hMU.js} +2 -2
- package/dist/{configure-jlAKeuki.js → configure-BXK8YRUD.js} +32 -32
- package/dist/{configure-CH_-SNya.js → configure-Caf6yI_m.js} +24 -24
- package/dist/{configure-Dpk4lSoz.js → configure-DS9oQW51.js} +78 -78
- package/dist/{configure-CGTBBLR_.js → configure-DgXRL7Uz.js} +9 -9
- package/dist/{context-Cau0zD3W.js → context-BZV-msqG.js} +1 -1
- package/dist/{control-service-DMoq3DpT.js → control-service-BFYEuU-S.js} +5 -5
- package/dist/{control-service-CUhnhmpc.js → control-service-DUF4hGd3.js} +2 -2
- package/dist/{cron-cli-CKs1evSF.js → cron-cli-BglUapfu.js} +4 -4
- package/dist/{cron-cli-ybIqf_95.js → cron-cli-OHSsCpVe.js} +16 -16
- package/dist/{daemon-cli-C5Tosclk.js → daemon-cli-B2UGyc5z.js} +19 -19
- package/dist/{daemon-cli-CSCFNzUo.js → daemon-cli-CO-1GTE_.js} +5 -5
- package/dist/daemon-cli.js +58 -1
- package/dist/{daemon-runtime-B9AywEma.js → daemon-runtime-BsUCg0Nr.js} +3 -3
- package/dist/{daemon-runtime-DpY6Y5qE.js → daemon-runtime-cGQoReHT.js} +1 -1
- package/dist/{deliver-DkF6LCoS.js → deliver-CoAOvyW0.js} +1 -1
- package/dist/{deliver-BYxbDIF0.js → deliver-DhQSpWQA.js} +4 -4
- package/dist/{deliver-B2p9Fke_.js → deliver-DvbZ8dp4.js} +6 -6
- package/dist/{deps-D9266xfk.js → deps-CCbWMWT4.js} +1 -1
- package/dist/{diagnostics-TXSvtpaq.js → diagnostics-CtqVmSaZ.js} +1 -1
- package/dist/{dispatcher-DG44QJKz.js → dispatcher-C4k9ABOv.js} +2 -2
- package/dist/{dispatcher-BeO47t7A.js → dispatcher-N_4IYF9I.js} +1 -1
- package/dist/{dns-cli-BklOUsrX.js → dns-cli-DJ8mwzgA.js} +2 -2
- package/dist/{dns-cli-Dq98107U.js → dns-cli-Dk48S2y7.js} +13 -13
- package/dist/{docs-cli-CehJ2v5M.js → docs-cli-BvBEqoCl.js} +7 -7
- package/dist/{doctor-DJfgnQ67.js → doctor-9cbiXykn.js} +19 -19
- package/dist/{doctor-CWmHUAjs.js → doctor-C_1WNQix.js} +40 -40
- package/dist/{doctor-completion-CmJmktDv.js → doctor-completion-B1cKYcZj.js} +1 -1
- package/dist/{doctor-completion-CtCwd1fi.js → doctor-completion-D7uvGhAv.js} +3 -3
- package/dist/{doctor-config-flow-D0GgdMmi.js → doctor-config-flow-Bno6wZvG.js} +7 -7
- package/dist/{doctor-config-flow-D_8YNTSK.js → doctor-config-flow-rshwu4JS.js} +3 -3
- package/dist/entry.js +59 -2
- package/dist/{env-T3-raV4i.js → env-CLiKFfXU.js} +1 -1
- package/dist/{exec-DbnX_71w.js → exec-Bo7Vwe77.js} +1 -1
- package/dist/{exec-DnanRQle.js → exec-CEFTijVj.js} +1 -1
- package/dist/{exec-approvals-cli-B7hQEhGe.js → exec-approvals-cli-CRqO-FRn.js} +19 -19
- package/dist/{exec-approvals-cli-CcY7IQWQ.js → exec-approvals-cli-i_Bmu0zE.js} +4 -4
- package/dist/extensionAPI.js +1535 -315
- package/dist/{frontmatter-BmBmtOUh.js → frontmatter-Dsa7N963.js} +1 -1
- package/dist/{gateway-cli-DYrzIvOE.js → gateway-cli-CBmfvcpr.js} +99 -99
- package/dist/{gateway-cli-BazTmg20.js → gateway-cli-CufIzw2K.js} +43 -43
- package/dist/{gateway-rpc-LkRV5joR.js → gateway-rpc-BX-Pz0j8.js} +3 -3
- package/dist/{gateway-rpc-De-TWFvD.js → gateway-rpc-BvqpdNqp.js} +1 -1
- package/dist/{gmail-setup-utils-B4oMbrOI.js → gmail-setup-utils-B-LgbK-5.js} +3 -3
- package/dist/{health-BRSKF_iF.js → health-BVBoq6jM.js} +10 -10
- package/dist/{health-JqtB_B8C.js → health-DKC8u4W8.js} +18 -18
- package/dist/{health-format-Ojy0hLp3.js → health-format-DHYaqzgj.js} +2 -2
- package/dist/{heartbeat-visibility-BGj2czmk.js → heartbeat-visibility-CF3WzMM0.js} +2 -2
- package/dist/{heartbeat-visibility-pyFf6XBW.js → heartbeat-visibility-CUKC8xqZ.js} +2 -2
- package/dist/{help-format-BZ7j9sHT.js → help-format-mLYxJ3oD.js} +1 -1
- package/dist/{hooks-cli-B7g3jEC3.js → hooks-cli-BHO_BQFY.js} +23 -23
- package/dist/{hooks-cli-ZK4Z044T.js → hooks-cli-kLrFK7pV.js} +57 -57
- package/dist/{hooks-status-DR_WkhpR.js → hooks-status-CfvVr6eJ.js} +3 -3
- package/dist/{image-ops-B7tKwzpV.js → image-ops-C_aRXc-7.js} +1 -1
- package/dist/index.js +69 -69
- package/dist/{installs-BxZFjTKY.js → installs-DW-ErO4y.js} +5 -5
- package/dist/{lanes-DyM6NSSL.js → lanes-CrNcoc6P.js} +480 -163
- package/dist/{lifecycle-core-CHv9wUhV.js → lifecycle-core-DWESti3N.js} +6 -6
- package/dist/{links-CziCxopc.js → links-C4Hwnnc9.js} +1 -1
- package/dist/llm-slug-generator.js +17 -17
- package/dist/{logging-Dwz0XtXm.js → logging-CnEuyIPZ.js} +1 -1
- package/dist/{login-BvRe8YZ9.js → login-CY9_XaLc.js} +7 -7
- package/dist/{login-BbfWLOBl.js → login-Dj6hCAFK.js} +5 -5
- package/dist/{login-DevThvtW.js → login-Ga69_Kio.js} +2 -2
- package/dist/{login-qr-FDWY-tu5.js → login-qr-BYeWGzxI.js} +12 -12
- package/dist/{login-qr-BqhujMcQ.js → login-qr-DD1apkdT.js} +10 -10
- package/dist/{login-qr-BkpIGqae.js → login-qr-swgX7elR.js} +3 -3
- package/dist/{logs-cli-CiMRc2qL.js → logs-cli-D02oahhw.js} +4 -4
- package/dist/{logs-cli-CsfmPUwa.js → logs-cli-DAVu9h8p.js} +16 -16
- package/dist/{manager-CcawxgaC.js → manager-CLAy-qOR.js} +10 -10
- package/dist/{manager-v4S80Br3.js → manager-DQPfk6Ea.js} +12 -12
- package/dist/{manager-DS1DfkbC.js → manager-yWxV2UI_.js} +1 -1
- package/dist/{manifest-registry-BiGCvMJ8.js → manifest-registry-BJat2nhC.js} +1 -1
- package/dist/{memory-cli-wDO418hx.js → memory-cli-B8AsIRG3.js} +3 -3
- package/dist/{memory-cli-Cl2n9UtH.js → memory-cli-bA70cVlm.js} +12 -12
- package/dist/{message-channel-DuxJGOJz.js → message-channel-C5I8UgGH.js} +1 -1
- package/dist/{model-auth-Ja4oelNH.js → model-auth-Be3_KahV.js} +2 -2
- package/dist/{model-auth-DVG37yXU.js → model-auth-DBHvPqaY.js} +4 -4
- package/dist/{model-auth-Uxm-wRjR.js → model-auth-DYHjH-Oh.js} +3 -3
- package/dist/{model-selection-xZLlICyg.js → model-selection-BuMFehML.js} +5 -2
- package/dist/{model-selection-BKFF7fDb.js → model-selection-DFbDH9o2.js} +4 -1
- package/dist/{model-selection-C2dAUmK_.js → model-selection-DRIxw3do.js} +5 -2
- package/dist/{models-tQnX4hL4.js → models-B9jYbX5H.js} +26 -26
- package/dist/{node-cli-DAcW-rfA.js → node-cli-C_efNJ2B.js} +7 -7
- package/dist/{node-cli-CZuWFgpO.js → node-cli-ScPCT6uD.js} +28 -28
- package/dist/{node-service-Ds1r16VN.js → node-service-BCfZtWK_.js} +1 -1
- package/dist/{note-Daao-cv8.js → note-DjzS4Am4.js} +2 -2
- package/dist/{npm-registry-spec-fJIJ8GG5.js → npm-registry-spec-Opq9qQXl.js} +1 -1
- package/dist/{onboard-Dd6xFMYB.js → onboard-C7ZSJNCe.js} +10 -10
- package/dist/{onboard-dasbF9G1.js → onboard-CJOJPctL.js} +17 -17
- package/dist/{onboard-channels-DisvVyIs.js → onboard-channels-DSlUCvl1.js} +2 -2
- package/dist/{onboard-channels-BUv3VbAL.js → onboard-channels-DwPNXSwW.js} +9 -9
- package/dist/{onboard-helpers-BgsHO6fO.js → onboard-helpers-CU_S0_Kf.js} +10 -10
- package/dist/{onboard-helpers-49TVSf7J.js → onboard-helpers-tkuUrdCB.js} +2 -2
- package/dist/{onboarding-Dq3bCBjc.js → onboarding-Caiq91Yz.js} +10 -10
- package/dist/{onboarding-6Xs4orLw.js → onboarding-DP2NlqhA.js} +20 -20
- package/dist/{outbound-RxegsVGB.js → outbound-B84phlQU.js} +4 -4
- package/dist/{outbound-CliT3nme.js → outbound-CKmmCVxJ.js} +1 -1
- package/dist/{outbound-CLII4C2A.js → outbound-DKM-JeSH.js} +5 -5
- package/dist/{parse-timeout-BnOIKwx8.js → parse-timeout-C59j-ev4.js} +1 -1
- package/dist/{parse-timeout-C8t_lmnL.js → parse-timeout-aZGyXXFz.js} +3 -3
- package/dist/{path-env-CsgLP0dy.js → path-env-cFxXrXB1.js} +1 -1
- package/dist/{paths-DybdJi5a.js → paths-CLxC7m0Z.js} +1 -1
- package/dist/{pi-auth-json-MH7vz0HI.js → pi-auth-json-DPoqstQN.js} +7 -7
- package/dist/{pi-auth-json-BY6wRDm0.js → pi-auth-json-DjxzPUt3.js} +2 -2
- package/dist/{pi-auth-json-DLroEcea.js → pi-auth-json-hMxhauJ8.js} +6 -6
- package/dist/{pi-embedded-CS4D_0t7.js → pi-embedded-JUmNmkTK.js} +700 -362
- package/dist/{pi-embedded-helpers-iju5zIIA.js → pi-embedded-helpers-B6wVA0hU.js} +1 -1
- package/dist/{pi-embedded-helpers-DnRfi8bN.js → pi-embedded-helpers-B_Sx4G6d.js} +30 -20
- package/dist/{pi-tools.policy-RhdERrk3.js → pi-tools.policy-Bn9S3ywB.js} +2 -2
- package/dist/{pi-tools.policy-CN78I2yN.js → pi-tools.policy-ChzY9kW7.js} +7 -7
- package/dist/{plugin-auto-enable-DLrgOd4y.js → plugin-auto-enable-UE1XVFcw.js} +1 -1
- package/dist/{plugin-auto-enable-DIWd94Po.js → plugin-auto-enable-f05JE-GF.js} +5 -5
- package/dist/{plugin-registry-l3z9phEV.js → plugin-registry-BeB2L6Qe.js} +2 -2
- package/dist/{plugin-registry-esOxvV3X.js → plugin-registry-DIXcynua.js} +4 -4
- package/dist/plugin-sdk/agents/anthropic-direct-runner.d.ts +1 -1
- package/dist/plugin-sdk/agents/gemini-direct-runner.d.ts +38 -0
- package/dist/plugin-sdk/agents/tools/browser-tool.schema.d.ts +2 -2
- package/dist/plugin-sdk/commands/onboard-types.d.ts +2 -2
- package/dist/plugin-sdk/gateway/protocol/index.d.ts +22 -22
- package/dist/plugin-sdk/index.js +75 -8
- package/dist/{plugins-C_GedoUi.js → plugins-DCXdhkeB.js} +2 -2
- package/dist/{plugins-BmYfBGLM.js → plugins-NbldDVJs.js} +1 -1
- package/dist/{plugins-cli-CbXtuN4b.js → plugins-cli-CzUD-ewi.js} +58 -58
- package/dist/{plugins-cli-D2v0n4BL.js → plugins-cli-Dk2W0fBT.js} +23 -23
- package/dist/{polls-Cuv4dsX_.js → polls-OzE9fR2s.js} +6 -6
- package/dist/{ports-DOiSDgNp.js → ports-CWvYU8j6.js} +4 -4
- package/dist/{ports-BQ0cAsGj.js → ports-Cgow804e.js} +2 -2
- package/dist/{program-y0NPJuYm.js → program-DxItv_Ts.js} +28 -28
- package/dist/{program-context-CqPwmgYa.js → program-context-cgh8PMPD.js} +33 -33
- package/dist/{progress-BZZa-fXr.js → progress-DzZ_4Z4f.js} +1 -1
- package/dist/{prompt-style-1bwj7IzZ.js → prompt-style-C7WfXowC.js} +1 -1
- package/dist/{prompts-DY0qdoD1.js → prompts-BfHxhlF9.js} +13 -2
- package/dist/{prompts-DTKoIKPV.js → prompts-DH_nIROF.js} +71 -8
- package/dist/{pw-ai-BhoKfvvM.js → pw-ai-Bigm0Qwh.js} +7 -7
- package/dist/{pw-ai-CJgeaF06.js → pw-ai-CsODxGt8.js} +3 -3
- package/dist/{qmd-manager-BGob_1OP.js → qmd-manager-C3z8LWKx.js} +6 -6
- package/dist/{qmd-manager-BmGj4bZk.js → qmd-manager-lfhigvUf.js} +6 -6
- package/dist/{register.agent-CRazop1A.js → register.agent-BVwbjkKx.js} +30 -30
- package/dist/{register.agent-Bi2FqIlN.js → register.agent-D0FKVD_s.js} +70 -70
- package/dist/{register.anima-BmdRCJLy.js → register.anima-Dc7OI2Nh.js} +4 -4
- package/dist/{register.anima-FFaI_C8x.js → register.anima-bys_cyEd.js} +4 -4
- package/dist/{register.configure-FIXOWrO9.js → register.configure-BrRG_RtB.js} +31 -31
- package/dist/register.configure-CXKr61Ka.js +108 -0
- package/dist/register.maintenance-BToHjam6.js +103 -0
- package/dist/{register.maintenance-DJYji5mV.js → register.maintenance-DXL3L0ip.js} +35 -35
- package/dist/{register.onboard-thGXwzOX.js → register.onboard-B3hbdfaQ.js} +71 -71
- package/dist/{register.onboard-oUsWjmam.js → register.onboard-Bg5zEb3f.js} +35 -35
- package/dist/{register.setup-B4MYuE3g.js → register.setup-CZqwphif.js} +35 -35
- package/dist/{register.setup-DWDrQ7RT.js → register.setup-Cq8nqbrU.js} +71 -71
- package/dist/{register.status-health-sessions-Ce9QUAyj.js → register.status-health-sessions-D1kjQUAc.js} +67 -67
- package/dist/{register.status-health-sessions-CTKdzo7a.js → register.status-health-sessions-mdLJbfPN.js} +28 -28
- package/dist/{register.subclis-CWmYc4AB.js → register.subclis-mbYw7H-_.js} +20 -20
- package/dist/{reply-BKpIrCr-.js → reply-CwV-5jE0.js} +56 -52
- package/dist/{reply-CpHIJ9Kk.js → reply-DAGmjvs-.js} +33 -29
- package/dist/{reply-prefix-BO_Dt82N.js → reply-prefix-BRsV1Eof.js} +2 -2
- package/dist/{reply-prefix-BwVBvQXp.js → reply-prefix-CAsFNEP7.js} +2 -2
- package/dist/{routes-C2EyUA9x.js → routes-CYHrkIjB.js} +6 -6
- package/dist/{routes-XhTPYecR.js → routes-cdfVFYMI.js} +2 -2
- package/dist/{run-CGokiDR8.js → run-DE6EaeE3.js} +70 -70
- package/dist/{run--9hftM2H.js → run-S0Cw3Fyy.js} +32 -32
- package/dist/{run-main-DxcOzCLw.js → run-main-CCxXEvb7.js} +41 -41
- package/dist/{runtime-guard-B40AREJ_.js → runtime-guard-CNnLK4pn.js} +1 -1
- package/dist/{sandbox-BwUo1b0I.js → sandbox-B4-dXpqZ.js} +6 -6
- package/dist/{sandbox-CiwAPzO7.js → sandbox-DhcoWMaN.js} +2 -2
- package/dist/{sandbox-cli-D9-wZJ9M.js → sandbox-cli-DQMWPCOh.js} +24 -24
- package/dist/{sandbox-cli-DsrzwG_s.js → sandbox-cli-TAuv3mTO.js} +6 -6
- package/dist/{security-cli-CX5uciKz.js → security-cli-Da-3YxZ4.js} +29 -29
- package/dist/{security-cli-CouqfUGc.js → security-cli-Dc-NwTC2.js} +9 -9
- package/dist/{semantic-Buqqx7gZ.js → semantic-BlQgdb3-.js} +1 -1
- package/dist/{semantic-B4TOg4CK.js → semantic-VlSmVCfb.js} +1 -1
- package/dist/{server-context-B78_sSOW.js → server-context-C-usQ5Np.js} +1 -1
- package/dist/{server-context-efO1YgXk.js → server-context-r7wPe4ZD.js} +9 -9
- package/dist/{server-node-events-TN_Y9MgU.js → server-node-events-3KeQAwUo.js} +14 -14
- package/dist/{server-node-events-DJlLCF2M.js → server-node-events-GTSQEd_U.js} +36 -36
- package/dist/{service-D1idQeBv.js → service-DCVAkKlN.js} +1 -1
- package/dist/{service-audit-BzwV-IOi.js → service-audit-Crw1cAbj.js} +1 -1
- package/dist/{service-audit-BbwXAhsr.js → service-audit-DRIpsryX.js} +3 -3
- package/dist/{session-Dvwwi-Eb.js → session-CrGApVik.js} +1 -1
- package/dist/{session-skOcrvF2.js → session-D3BNUwtH.js} +1 -1
- package/dist/{session-DCGAvNG9.js → session-DKCUYHCS.js} +1 -1
- package/dist/{session-cost-usage-6bDLU9Pb.js → session-cost-usage-LvsvRW5g.js} +1 -1
- package/dist/{session-BjPdEBPh.js → session-mpOb9zFL.js} +5 -5
- package/dist/{sessions-kJgmpWtv.js → sessions-BduC6sZj.js} +78 -68
- package/dist/{sessions-B7ikzhI_.js → sessions-CAiEkTKb.js} +18 -8
- package/dist/{sessions-B7clh58j.js → sessions-DLPN62LD.js} +4 -4
- package/dist/{settings-cli-JU5bg5jb.js → settings-cli-BgGYdH4N.js} +77 -77
- package/dist/{settings-cli-DjVugHID.js → settings-cli-f0O0FUVO.js} +32 -32
- package/dist/{setup-token-CvRwJUVY.js → setup-token-lcjrc9sO.js} +28 -28
- package/dist/{setup-token-wFsQlaW2.js → setup-token-ykp60QVx.js} +9 -9
- package/dist/{shared-DC8lQHCt.js → shared-Ca0NTTF0.js} +3 -3
- package/dist/{shell-env-JzaPTLKV.js → shell-env-BZ_fIIlm.js} +1 -1
- package/dist/{shell-env-C1yK_Rod.js → shell-env-DaSbgZYX.js} +2 -2
- package/dist/{skill-scanner-HQwt_KRF.js → skill-scanner--TxpCSNF.js} +1 -1
- package/dist/{skills-cli-OYZS-U1f.js → skills-cli-BpyTvFkg.js} +16 -16
- package/dist/{skills-cli-CSMzc9am.js → skills-cli-Tm326cFx.js} +2 -2
- package/dist/{skills-install-BKz5WLq4.js → skills-install-B2m10oTm.js} +5 -5
- package/dist/{skills-status-B_umZ78Q.js → skills-status-D14GZ5WN.js} +3 -3
- package/dist/{skills-ppB3qrZU.js → skills-wS8aRGeO.js} +3 -3
- package/dist/{soul-DpWsWxOa.js → soul-CAEpnUkv.js} +1 -1
- package/dist/{soul-aZoR6Ctt.js → soul-D9EtC35X.js} +1 -1
- package/dist/{sqlite-CnVGUfhz.js → sqlite-B0rfPL8q.js} +2 -2
- package/dist/{sqlite-Duz1QJIT.js → sqlite-CR0WDTae.js} +2 -2
- package/dist/start-DYq7cNRG.js +157 -0
- package/dist/{start-CAbxlnFZ.js → start-Y69GZPdX.js} +41 -41
- package/dist/{status-YH65ctig.js → status-BplZv8_T.js} +2 -2
- package/dist/{status-CrJV2Y4x.js → status-K3LGPZeT.js} +4 -4
- package/dist/{status-CxxXFU4R.js → status-Uzlo7BvY.js} +27 -27
- package/dist/{status-1TjjCE1l.js → status-rt3tIYmL.js} +13 -13
- package/dist/{status.update-P6xyBet8.js → status.update-B61Emp_r.js} +3 -3
- package/dist/{status.update-BzAuf_G-.js → status.update-yjbKzlMn.js} +1 -1
- package/dist/{subagent-registry-xJY9wqZy.js → subagent-registry-DfCDq9hk.js} +14 -14
- package/dist/{subagent-registry-3Dw3YppH.js → subagent-registry-ZIpC5W-9.js} +7 -7
- package/dist/{subagent-registry-B_65nJFp.js → subagent-registry-xp5sYYzS.js} +13 -13
- package/dist/{subsystem-Cn6bJV8Z.js → subsystem-BMsbqSb4.js} +58 -1
- package/dist/{subsystem-WFp78xn1.js → subsystem-BP2l3SHn.js} +58 -1
- package/dist/{system-cli-Dbn4_ed8.js → system-cli-D-eyDWD6.js} +4 -4
- package/dist/{system-cli-lmslA_Ox.js → system-cli-Dy2Pwnbg.js} +15 -15
- package/dist/{systemd-DYPdTwok.js → systemd-DXo2A9_S.js} +2 -2
- package/dist/{systemd-hints-E8yYE8Q1.js → systemd-hints-DIjCA1An.js} +1 -1
- package/dist/{systemd-linger-CpWguZ4b.js → systemd-linger-DgB-ow-D.js} +2 -2
- package/dist/{table-B991ZwKi.js → table-C-GNQABy.js} +2 -2
- package/dist/{timeout-Dbspj9Jf.js → timeout-Cl8rWNWO.js} +350 -33
- package/dist/{tokens-k_R7Y792.js → tokens-FGW_JgKz.js} +1 -1
- package/dist/{tool-images-DJZPwGqm.js → tool-images-Df50dvpv.js} +2 -2
- package/dist/{tool-images-BehEzEZF.js → tool-images-RiPaL7wQ.js} +2 -2
- package/dist/{tui-PCTDV7Ct.js → tui-NlR4LFBm.js} +9 -9
- package/dist/{tui--eIVX_W0.js → tui-YsmTyq58.js} +3 -3
- package/dist/{tui-cli-DBV3lnXA.js → tui-cli-CSudxVpO.js} +9 -9
- package/dist/{tui-cli-D39zC_Ew.js → tui-cli-QnKj1We8.js} +28 -28
- package/dist/{update-tjMvDUCw.js → update-B2O46V_t.js} +3 -3
- package/dist/{update-cli-QP5L8xlv.js → update-cli-BXKL-v-n.js} +86 -86
- package/dist/{update-cli-BzaQvirL.js → update-cli-BgQUtlLg.js} +37 -37
- package/dist/{update-runner-ZuJN8uBE.js → update-runner-U2WcWGfd.js} +5 -5
- package/dist/{update-runner-B_oj7S_n.js → update-runner-fvdM_Hip.js} +1 -1
- package/dist/{usage-DzKbMa8N.js → usage-CM-NiwBA.js} +9 -9
- package/dist/{utils-dWKYjULE.js → utils-B60lF9Wq.js} +1 -1
- package/dist/{web-CgQc2Raf.js → web-B8r6MvXh.js} +43 -43
- package/dist/web-BzFhL5WI.js +67 -0
- package/dist/{web-nI3eIGAT.js → web-eoSM6P0a.js} +26 -26
- package/dist/{webhooks-cli-CYbIJJF6.js → webhooks-cli-24A2CbXR.js} +2 -2
- package/dist/{webhooks-cli-oRmSfYdd.js → webhooks-cli-CgkxWcH5.js} +13 -13
- package/dist/{whatsapp-actions-BzPQUcRR.js → whatsapp-actions-BVlqbVgY.js} +3 -3
- package/dist/{whatsapp-actions-CZuxHplg.js → whatsapp-actions-BYxKWK0A.js} +13 -13
- package/dist/{whatsapp-actions-BB-Leqn2.js → whatsapp-actions-DagVwYC6.js} +17 -17
- package/dist/{widearea-dns-CkuHFBQy.js → widearea-dns-B1TTb1v5.js} +1 -1
- package/dist/{workspace-DOJssemp.js → workspace-Cvio8QlZ.js} +1 -1
- package/dist/{ws-log-B-xsUQys.js → ws-log-De7GACYn.js} +1 -1
- package/dist/{ws-CQYP0dWu.js → ws-sdRTa2sP.js} +1 -1
- package/package.json +1 -1
- package/dist/cli-CfvBmuhw.js +0 -104
- package/dist/config-cli-cmNuTlw0.js +0 -15
- package/dist/register.configure-r5AViY3N.js +0 -108
- package/dist/register.maintenance-Cpf0ZZTL.js +0 -103
- package/dist/start-M9abr1O1.js +0 -157
- package/dist/web-DtWSf5wm.js +0 -67
- /package/dist/{boolean-M-esQJt6.js → boolean-Ce2-qkSB.js} +0 -0
- /package/dist/{command-format-B1WxXbeU.js → command-format-UwAvxtMC.js} +0 -0
- /package/dist/{config-Qw5FwfRK.js → config-COtiNNtV.js} +0 -0
- /package/dist/{errors-DjZBTJJ3.js → errors-D6Vj_xs4.js} +0 -0
- /package/dist/{file-lock-BRW4LeL0.js → file-lock-BFQVGKm5.js} +0 -0
- /package/dist/{input-provenance-B0pwc6mp.js → input-provenance-sPbZYo89.js} +0 -0
- /package/dist/{internal-hooks-Exeq-wmx.js → internal-hooks-CWw3Hgeu.js} +0 -0
- /package/dist/{paths-BvY3CbW0.js → paths-CnuAkdfx.js} +0 -0
- /package/dist/{tailnet-CjJJHjPU.js → tailnet-CabhakZ7.js} +0 -0
- /package/dist/{transcript-events-DUQC5hbS.js → transcript-events-C1hdue6u.js} +0 -0
package/dist/extensionAPI.js
CHANGED
|
@@ -19,7 +19,7 @@ import "express";
|
|
|
19
19
|
import "undici";
|
|
20
20
|
import "file-type";
|
|
21
21
|
import "ws";
|
|
22
|
-
import { getOAuthProviders } from "@mariozechner/pi-ai";
|
|
22
|
+
import { getEnvApiKey, getOAuthApiKey, getOAuthProviders } from "@mariozechner/pi-ai";
|
|
23
23
|
import "node-edge-tts";
|
|
24
24
|
|
|
25
25
|
//#region src/infra/home-dir.ts
|
|
@@ -173,6 +173,22 @@ function resolveDefaultConfigCandidates(env = process.env, homedir = envHomedir(
|
|
|
173
173
|
candidates.push(path.join(newStateDir(effectiveHomedir), CONFIG_FILENAME));
|
|
174
174
|
return candidates;
|
|
175
175
|
}
|
|
176
|
+
const OAUTH_FILENAME = "oauth.json";
|
|
177
|
+
/**
|
|
178
|
+
* OAuth credentials storage directory.
|
|
179
|
+
*
|
|
180
|
+
* Precedence:
|
|
181
|
+
* - `ANIMA_OAUTH_DIR` (explicit override)
|
|
182
|
+
* - `$*_STATE_DIR/credentials` (canonical server/default)
|
|
183
|
+
*/
|
|
184
|
+
function resolveOAuthDir(env = process.env, stateDir = resolveStateDir(env, envHomedir(env))) {
|
|
185
|
+
const override = env.ANIMA_OAUTH_DIR?.trim();
|
|
186
|
+
if (override) return resolveUserPath$1(override, env, envHomedir(env));
|
|
187
|
+
return path.join(stateDir, "credentials");
|
|
188
|
+
}
|
|
189
|
+
function resolveOAuthPath(env = process.env, stateDir = resolveStateDir(env, envHomedir(env))) {
|
|
190
|
+
return path.join(resolveOAuthDir(env, stateDir), OAUTH_FILENAME);
|
|
191
|
+
}
|
|
176
192
|
|
|
177
193
|
//#endregion
|
|
178
194
|
//#region src/sessions/session-key-utils.ts
|
|
@@ -349,6 +365,8 @@ const DEFAULT_LOG_FILE = path.join(DEFAULT_LOG_DIR, "anima.log");
|
|
|
349
365
|
const LOG_PREFIX = "anima";
|
|
350
366
|
const LOG_SUFFIX = ".log";
|
|
351
367
|
const MAX_LOG_AGE_MS = 1440 * 60 * 1e3;
|
|
368
|
+
const MAX_LOG_SIZE_BYTES = 50 * 1024 * 1024;
|
|
369
|
+
const MAX_LOG_SEGMENTS = 5;
|
|
352
370
|
const requireConfig$1 = createRequire(import.meta.url);
|
|
353
371
|
const externalTransports = /* @__PURE__ */ new Set();
|
|
354
372
|
function attachExternalTransport(logger, transport) {
|
|
@@ -390,6 +408,8 @@ function buildLogger(settings) {
|
|
|
390
408
|
minLevel: levelToMinLevel(settings.level),
|
|
391
409
|
type: "hidden"
|
|
392
410
|
});
|
|
411
|
+
let currentFile = settings.file;
|
|
412
|
+
let currentSize = getFileSize(currentFile);
|
|
393
413
|
logger.attachTransport((logObj) => {
|
|
394
414
|
try {
|
|
395
415
|
const time = logObj.date?.toISOString?.() ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -397,7 +417,16 @@ function buildLogger(settings) {
|
|
|
397
417
|
...logObj,
|
|
398
418
|
time
|
|
399
419
|
});
|
|
400
|
-
|
|
420
|
+
const lineBytes = Buffer.byteLength(line, "utf8") + 1;
|
|
421
|
+
if (currentSize + lineBytes > MAX_LOG_SIZE_BYTES) {
|
|
422
|
+
const rotated = rotateLogFile(currentFile);
|
|
423
|
+
if (rotated) {
|
|
424
|
+
currentFile = rotated;
|
|
425
|
+
currentSize = 0;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
fs.appendFileSync(currentFile, `${line}\n`, { encoding: "utf8" });
|
|
429
|
+
currentSize += lineBytes;
|
|
401
430
|
} catch {}
|
|
402
431
|
});
|
|
403
432
|
for (const transport of externalTransports) attachExternalTransport(logger, transport);
|
|
@@ -423,6 +452,50 @@ function getChildLogger(bindings, opts) {
|
|
|
423
452
|
prefix: bindings ? [name ?? ""] : []
|
|
424
453
|
});
|
|
425
454
|
}
|
|
455
|
+
function getFileSize(filePath) {
|
|
456
|
+
try {
|
|
457
|
+
return fs.statSync(filePath).size;
|
|
458
|
+
} catch {
|
|
459
|
+
return 0;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
function rotateLogFile(filePath) {
|
|
463
|
+
try {
|
|
464
|
+
const dir = path.dirname(filePath);
|
|
465
|
+
const ext = path.extname(filePath);
|
|
466
|
+
const base = path.basename(filePath, ext);
|
|
467
|
+
let segment = 1;
|
|
468
|
+
while (segment <= MAX_LOG_SEGMENTS) {
|
|
469
|
+
const segmentPath = path.join(dir, `${base}.${segment}${ext}`);
|
|
470
|
+
if (!fs.existsSync(segmentPath)) {
|
|
471
|
+
fs.renameSync(filePath, segmentPath);
|
|
472
|
+
pruneExcessSegments(dir, base, ext);
|
|
473
|
+
return filePath;
|
|
474
|
+
}
|
|
475
|
+
segment++;
|
|
476
|
+
}
|
|
477
|
+
const oldestPath = path.join(dir, `${base}.${MAX_LOG_SEGMENTS}${ext}`);
|
|
478
|
+
fs.rmSync(oldestPath, { force: true });
|
|
479
|
+
for (let i = MAX_LOG_SEGMENTS - 1; i >= 1; i--) {
|
|
480
|
+
const from = path.join(dir, `${base}.${i}${ext}`);
|
|
481
|
+
const to = path.join(dir, `${base}.${i + 1}${ext}`);
|
|
482
|
+
if (fs.existsSync(from)) fs.renameSync(from, to);
|
|
483
|
+
}
|
|
484
|
+
fs.renameSync(filePath, path.join(dir, `${base}.1${ext}`));
|
|
485
|
+
return filePath;
|
|
486
|
+
} catch {
|
|
487
|
+
return null;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
function pruneExcessSegments(dir, base, ext) {
|
|
491
|
+
try {
|
|
492
|
+
for (let i = MAX_LOG_SEGMENTS + 1; i <= MAX_LOG_SEGMENTS + 10; i++) {
|
|
493
|
+
const segmentPath = path.join(dir, `${base}.${i}${ext}`);
|
|
494
|
+
if (fs.existsSync(segmentPath)) fs.rmSync(segmentPath, { force: true });
|
|
495
|
+
else break;
|
|
496
|
+
}
|
|
497
|
+
} catch {}
|
|
498
|
+
}
|
|
426
499
|
function formatLocalDate(date) {
|
|
427
500
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
|
428
501
|
}
|
|
@@ -1703,169 +1776,6 @@ function resolveThinkingDefault(params) {
|
|
|
1703
1776
|
return "off";
|
|
1704
1777
|
}
|
|
1705
1778
|
|
|
1706
|
-
//#endregion
|
|
1707
|
-
//#region src/agents/cli-backends.ts
|
|
1708
|
-
const DEFAULT_CLAUDE_BACKEND = {
|
|
1709
|
-
command: "claude",
|
|
1710
|
-
args: [
|
|
1711
|
-
"-p",
|
|
1712
|
-
"--output-format",
|
|
1713
|
-
"json",
|
|
1714
|
-
"--dangerously-skip-permissions"
|
|
1715
|
-
],
|
|
1716
|
-
resumeArgs: [
|
|
1717
|
-
"-p",
|
|
1718
|
-
"--output-format",
|
|
1719
|
-
"json",
|
|
1720
|
-
"--dangerously-skip-permissions",
|
|
1721
|
-
"--resume",
|
|
1722
|
-
"{sessionId}"
|
|
1723
|
-
],
|
|
1724
|
-
output: "jsonl",
|
|
1725
|
-
input: "arg",
|
|
1726
|
-
modelArg: "--model",
|
|
1727
|
-
modelAliases: {
|
|
1728
|
-
opus: "opus",
|
|
1729
|
-
"opus-4.6": "opus",
|
|
1730
|
-
"opus-4.5": "opus",
|
|
1731
|
-
"opus-4": "opus",
|
|
1732
|
-
"claude-opus-4-6": "opus",
|
|
1733
|
-
"claude-opus-4-5": "opus",
|
|
1734
|
-
"claude-opus-4": "opus",
|
|
1735
|
-
sonnet: "sonnet",
|
|
1736
|
-
"sonnet-4.5": "sonnet",
|
|
1737
|
-
"sonnet-4.1": "sonnet",
|
|
1738
|
-
"sonnet-4.0": "sonnet",
|
|
1739
|
-
"claude-sonnet-4-5": "sonnet",
|
|
1740
|
-
"claude-sonnet-4-1": "sonnet",
|
|
1741
|
-
"claude-sonnet-4-0": "sonnet",
|
|
1742
|
-
haiku: "haiku",
|
|
1743
|
-
"haiku-3.5": "haiku",
|
|
1744
|
-
"claude-haiku-3-5": "haiku"
|
|
1745
|
-
},
|
|
1746
|
-
sessionArg: "--session-id",
|
|
1747
|
-
sessionMode: "always",
|
|
1748
|
-
sessionIdFields: [
|
|
1749
|
-
"session_id",
|
|
1750
|
-
"sessionId",
|
|
1751
|
-
"conversation_id",
|
|
1752
|
-
"conversationId"
|
|
1753
|
-
],
|
|
1754
|
-
systemPromptArg: "--append-system-prompt",
|
|
1755
|
-
systemPromptMode: "append",
|
|
1756
|
-
systemPromptWhen: "first",
|
|
1757
|
-
clearEnv: ["ANTHROPIC_API_KEY", "ANTHROPIC_API_KEY_OLD"],
|
|
1758
|
-
serialize: true
|
|
1759
|
-
};
|
|
1760
|
-
const DEFAULT_CODEX_BACKEND = {
|
|
1761
|
-
command: "codex",
|
|
1762
|
-
args: [
|
|
1763
|
-
"exec",
|
|
1764
|
-
"--json",
|
|
1765
|
-
"--color",
|
|
1766
|
-
"never",
|
|
1767
|
-
"--sandbox",
|
|
1768
|
-
"read-only",
|
|
1769
|
-
"--skip-git-repo-check"
|
|
1770
|
-
],
|
|
1771
|
-
resumeArgs: [
|
|
1772
|
-
"exec",
|
|
1773
|
-
"resume",
|
|
1774
|
-
"{sessionId}"
|
|
1775
|
-
],
|
|
1776
|
-
output: "jsonl",
|
|
1777
|
-
resumeOutput: "text",
|
|
1778
|
-
input: "arg",
|
|
1779
|
-
modelArg: "--model",
|
|
1780
|
-
imageArg: "--image",
|
|
1781
|
-
sessionMode: "existing",
|
|
1782
|
-
serialize: true
|
|
1783
|
-
};
|
|
1784
|
-
const CLAUDE_BACKEND_ALIASES = [
|
|
1785
|
-
"claude-cli",
|
|
1786
|
-
"anthropic",
|
|
1787
|
-
"claude"
|
|
1788
|
-
];
|
|
1789
|
-
const CODEX_BACKEND_ALIASES = [
|
|
1790
|
-
"codex-cli",
|
|
1791
|
-
"openai-codex",
|
|
1792
|
-
"openai",
|
|
1793
|
-
"codex"
|
|
1794
|
-
];
|
|
1795
|
-
const CLAUDE_BACKEND_ALIAS_SET = new Set(CLAUDE_BACKEND_ALIASES.map((alias) => normalizeBackendKey(alias)));
|
|
1796
|
-
const CODEX_BACKEND_ALIAS_SET = new Set(CODEX_BACKEND_ALIASES.map((alias) => normalizeBackendKey(alias)));
|
|
1797
|
-
function normalizeBackendKey(key) {
|
|
1798
|
-
return normalizeProviderId(key);
|
|
1799
|
-
}
|
|
1800
|
-
function pickBackendConfig(config, normalizedId) {
|
|
1801
|
-
for (const [key, entry] of Object.entries(config)) if (normalizeBackendKey(key) === normalizedId) return entry;
|
|
1802
|
-
}
|
|
1803
|
-
function pickBackendConfigByAliases(config, aliases) {
|
|
1804
|
-
for (const alias of aliases) {
|
|
1805
|
-
const matched = pickBackendConfig(config, normalizeBackendKey(alias));
|
|
1806
|
-
if (matched) return matched;
|
|
1807
|
-
}
|
|
1808
|
-
}
|
|
1809
|
-
function mergeBackendConfig(base, override) {
|
|
1810
|
-
if (!override) return { ...base };
|
|
1811
|
-
return {
|
|
1812
|
-
...base,
|
|
1813
|
-
...override,
|
|
1814
|
-
args: override.args ?? base.args,
|
|
1815
|
-
env: {
|
|
1816
|
-
...base.env,
|
|
1817
|
-
...override.env
|
|
1818
|
-
},
|
|
1819
|
-
modelAliases: {
|
|
1820
|
-
...base.modelAliases,
|
|
1821
|
-
...override.modelAliases
|
|
1822
|
-
},
|
|
1823
|
-
clearEnv: Array.from(new Set([...base.clearEnv ?? [], ...override.clearEnv ?? []])),
|
|
1824
|
-
sessionIdFields: override.sessionIdFields ?? base.sessionIdFields,
|
|
1825
|
-
sessionArgs: override.sessionArgs ?? base.sessionArgs,
|
|
1826
|
-
resumeArgs: override.resumeArgs ?? base.resumeArgs
|
|
1827
|
-
};
|
|
1828
|
-
}
|
|
1829
|
-
function resolveCliBackendConfig(provider, cfg) {
|
|
1830
|
-
const normalized = normalizeBackendKey(provider);
|
|
1831
|
-
const configured = cfg?.agents?.defaults?.cliBackends ?? {};
|
|
1832
|
-
if (CLAUDE_BACKEND_ALIAS_SET.has(normalized)) {
|
|
1833
|
-
const merged = mergeBackendConfig(DEFAULT_CLAUDE_BACKEND, pickBackendConfigByAliases(configured, [provider, ...CLAUDE_BACKEND_ALIASES]));
|
|
1834
|
-
const command = merged.command?.trim();
|
|
1835
|
-
if (!command) return null;
|
|
1836
|
-
return {
|
|
1837
|
-
id: normalizeBackendKey("claude-cli"),
|
|
1838
|
-
config: {
|
|
1839
|
-
...merged,
|
|
1840
|
-
command
|
|
1841
|
-
}
|
|
1842
|
-
};
|
|
1843
|
-
}
|
|
1844
|
-
if (CODEX_BACKEND_ALIAS_SET.has(normalized)) {
|
|
1845
|
-
const merged = mergeBackendConfig(DEFAULT_CODEX_BACKEND, pickBackendConfigByAliases(configured, [provider, ...CODEX_BACKEND_ALIASES]));
|
|
1846
|
-
const command = merged.command?.trim();
|
|
1847
|
-
if (!command) return null;
|
|
1848
|
-
return {
|
|
1849
|
-
id: normalizeBackendKey("codex-cli"),
|
|
1850
|
-
config: {
|
|
1851
|
-
...merged,
|
|
1852
|
-
command
|
|
1853
|
-
}
|
|
1854
|
-
};
|
|
1855
|
-
}
|
|
1856
|
-
const override = pickBackendConfig(configured, normalized);
|
|
1857
|
-
if (!override) return null;
|
|
1858
|
-
const command = override.command?.trim();
|
|
1859
|
-
if (!command) return null;
|
|
1860
|
-
return {
|
|
1861
|
-
id: normalized,
|
|
1862
|
-
config: {
|
|
1863
|
-
...override,
|
|
1864
|
-
command
|
|
1865
|
-
}
|
|
1866
|
-
};
|
|
1867
|
-
}
|
|
1868
|
-
|
|
1869
1779
|
//#endregion
|
|
1870
1780
|
//#region src/auto-reply/tokens.ts
|
|
1871
1781
|
const SILENT_REPLY_TOKEN = "NO_REPLY";
|
|
@@ -1877,42 +1787,6 @@ function resolveHeartbeatPrompt(raw) {
|
|
|
1877
1787
|
return (typeof raw === "string" ? raw.trim() : "") || HEARTBEAT_PROMPT;
|
|
1878
1788
|
}
|
|
1879
1789
|
|
|
1880
|
-
//#endregion
|
|
1881
|
-
//#region src/utils/boolean.ts
|
|
1882
|
-
const DEFAULT_TRUTHY = [
|
|
1883
|
-
"true",
|
|
1884
|
-
"1",
|
|
1885
|
-
"yes",
|
|
1886
|
-
"on"
|
|
1887
|
-
];
|
|
1888
|
-
const DEFAULT_FALSY = [
|
|
1889
|
-
"false",
|
|
1890
|
-
"0",
|
|
1891
|
-
"no",
|
|
1892
|
-
"off"
|
|
1893
|
-
];
|
|
1894
|
-
const DEFAULT_TRUTHY_SET = new Set(DEFAULT_TRUTHY);
|
|
1895
|
-
const DEFAULT_FALSY_SET = new Set(DEFAULT_FALSY);
|
|
1896
|
-
function parseBooleanValue(value, options = {}) {
|
|
1897
|
-
if (typeof value === "boolean") return value;
|
|
1898
|
-
if (typeof value !== "string") return;
|
|
1899
|
-
const normalized = value.trim().toLowerCase();
|
|
1900
|
-
if (!normalized) return;
|
|
1901
|
-
const truthy = options.truthy ?? DEFAULT_TRUTHY;
|
|
1902
|
-
const falsy = options.falsy ?? DEFAULT_FALSY;
|
|
1903
|
-
const truthySet = truthy === DEFAULT_TRUTHY ? DEFAULT_TRUTHY_SET : new Set(truthy);
|
|
1904
|
-
const falsySet = falsy === DEFAULT_FALSY ? DEFAULT_FALSY_SET : new Set(falsy);
|
|
1905
|
-
if (truthySet.has(normalized)) return true;
|
|
1906
|
-
if (falsySet.has(normalized)) return false;
|
|
1907
|
-
}
|
|
1908
|
-
|
|
1909
|
-
//#endregion
|
|
1910
|
-
//#region src/infra/env.ts
|
|
1911
|
-
const log$8 = createSubsystemLogger("env");
|
|
1912
|
-
function isTruthyEnvValue(value) {
|
|
1913
|
-
return parseBooleanValue(value) === true;
|
|
1914
|
-
}
|
|
1915
|
-
|
|
1916
1790
|
//#endregion
|
|
1917
1791
|
//#region src/hooks/internal-hooks.ts
|
|
1918
1792
|
/** Registry of hook handlers by event key */
|
|
@@ -2076,6 +1950,42 @@ function loadDotEnv(opts) {
|
|
|
2076
1950
|
});
|
|
2077
1951
|
}
|
|
2078
1952
|
|
|
1953
|
+
//#endregion
|
|
1954
|
+
//#region src/utils/boolean.ts
|
|
1955
|
+
const DEFAULT_TRUTHY = [
|
|
1956
|
+
"true",
|
|
1957
|
+
"1",
|
|
1958
|
+
"yes",
|
|
1959
|
+
"on"
|
|
1960
|
+
];
|
|
1961
|
+
const DEFAULT_FALSY = [
|
|
1962
|
+
"false",
|
|
1963
|
+
"0",
|
|
1964
|
+
"no",
|
|
1965
|
+
"off"
|
|
1966
|
+
];
|
|
1967
|
+
const DEFAULT_TRUTHY_SET = new Set(DEFAULT_TRUTHY);
|
|
1968
|
+
const DEFAULT_FALSY_SET = new Set(DEFAULT_FALSY);
|
|
1969
|
+
function parseBooleanValue(value, options = {}) {
|
|
1970
|
+
if (typeof value === "boolean") return value;
|
|
1971
|
+
if (typeof value !== "string") return;
|
|
1972
|
+
const normalized = value.trim().toLowerCase();
|
|
1973
|
+
if (!normalized) return;
|
|
1974
|
+
const truthy = options.truthy ?? DEFAULT_TRUTHY;
|
|
1975
|
+
const falsy = options.falsy ?? DEFAULT_FALSY;
|
|
1976
|
+
const truthySet = truthy === DEFAULT_TRUTHY ? DEFAULT_TRUTHY_SET : new Set(truthy);
|
|
1977
|
+
const falsySet = falsy === DEFAULT_FALSY ? DEFAULT_FALSY_SET : new Set(falsy);
|
|
1978
|
+
if (truthySet.has(normalized)) return true;
|
|
1979
|
+
if (falsySet.has(normalized)) return false;
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1982
|
+
//#endregion
|
|
1983
|
+
//#region src/infra/env.ts
|
|
1984
|
+
const log$9 = createSubsystemLogger("env");
|
|
1985
|
+
function isTruthyEnvValue(value) {
|
|
1986
|
+
return parseBooleanValue(value) === true;
|
|
1987
|
+
}
|
|
1988
|
+
|
|
2079
1989
|
//#endregion
|
|
2080
1990
|
//#region src/infra/shell-env.ts
|
|
2081
1991
|
const DEFAULT_TIMEOUT_MS$1 = 15e3;
|
|
@@ -2175,6 +2085,9 @@ function resolveShellEnvFallbackTimeoutMs(env) {
|
|
|
2175
2085
|
if (!Number.isFinite(parsed)) return DEFAULT_TIMEOUT_MS$1;
|
|
2176
2086
|
return Math.max(0, parsed);
|
|
2177
2087
|
}
|
|
2088
|
+
function getShellEnvAppliedKeys() {
|
|
2089
|
+
return [...lastAppliedKeys];
|
|
2090
|
+
}
|
|
2178
2091
|
|
|
2179
2092
|
//#endregion
|
|
2180
2093
|
//#region src/version.ts
|
|
@@ -7153,9 +7066,58 @@ const SANDBOX_STATE_DIR = path.join(STATE_DIR, "sandbox");
|
|
|
7153
7066
|
const SANDBOX_REGISTRY_PATH = path.join(SANDBOX_STATE_DIR, "containers.json");
|
|
7154
7067
|
const SANDBOX_BROWSER_REGISTRY_PATH = path.join(SANDBOX_STATE_DIR, "browsers.json");
|
|
7155
7068
|
|
|
7069
|
+
//#endregion
|
|
7070
|
+
//#region src/cli/cli-name.ts
|
|
7071
|
+
const DEFAULT_CLI_NAME = "anima";
|
|
7072
|
+
const KNOWN_CLI_NAMES = new Set([DEFAULT_CLI_NAME]);
|
|
7073
|
+
const CLI_PREFIX_RE$1 = /^(?:((?:pnpm|npm|bunx|npx)\s+))?anima\b/;
|
|
7074
|
+
function resolveCliName(argv = process.argv) {
|
|
7075
|
+
const argv1 = argv[1];
|
|
7076
|
+
if (!argv1) return DEFAULT_CLI_NAME;
|
|
7077
|
+
const base = path.basename(argv1).trim();
|
|
7078
|
+
if (KNOWN_CLI_NAMES.has(base)) return base;
|
|
7079
|
+
return DEFAULT_CLI_NAME;
|
|
7080
|
+
}
|
|
7081
|
+
function replaceCliName(command, cliName = resolveCliName()) {
|
|
7082
|
+
if (!command.trim()) return command;
|
|
7083
|
+
if (!CLI_PREFIX_RE$1.test(command)) return command;
|
|
7084
|
+
return command.replace(CLI_PREFIX_RE$1, (_match, runner) => {
|
|
7085
|
+
return `${runner ?? ""}${cliName}`;
|
|
7086
|
+
});
|
|
7087
|
+
}
|
|
7088
|
+
|
|
7089
|
+
//#endregion
|
|
7090
|
+
//#region src/cli/profile-utils.ts
|
|
7091
|
+
const PROFILE_NAME_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/i;
|
|
7092
|
+
function isValidProfileName(value) {
|
|
7093
|
+
if (!value) return false;
|
|
7094
|
+
return PROFILE_NAME_RE.test(value);
|
|
7095
|
+
}
|
|
7096
|
+
function normalizeProfileName(raw) {
|
|
7097
|
+
const profile = raw?.trim();
|
|
7098
|
+
if (!profile) return null;
|
|
7099
|
+
if (profile.toLowerCase() === "default") return null;
|
|
7100
|
+
if (!isValidProfileName(profile)) return null;
|
|
7101
|
+
return profile;
|
|
7102
|
+
}
|
|
7103
|
+
|
|
7104
|
+
//#endregion
|
|
7105
|
+
//#region src/cli/command-format.ts
|
|
7106
|
+
const CLI_PREFIX_RE = /^(?:pnpm|npm|bunx|npx)\s+anima\b|^anima\b/;
|
|
7107
|
+
const PROFILE_FLAG_RE = /(?:^|\s)--profile(?:\s|=|$)/;
|
|
7108
|
+
const DEV_FLAG_RE = /(?:^|\s)--dev(?:\s|$)/;
|
|
7109
|
+
function formatCliCommand(command, env = process.env) {
|
|
7110
|
+
const normalizedCommand = replaceCliName(command, resolveCliName());
|
|
7111
|
+
const profile = normalizeProfileName(env.ANIMA_PROFILE);
|
|
7112
|
+
if (!profile) return normalizedCommand;
|
|
7113
|
+
if (!CLI_PREFIX_RE.test(normalizedCommand)) return normalizedCommand;
|
|
7114
|
+
if (PROFILE_FLAG_RE.test(normalizedCommand) || DEV_FLAG_RE.test(normalizedCommand)) return normalizedCommand;
|
|
7115
|
+
return normalizedCommand.replace(CLI_PREFIX_RE, (match) => `${match} --profile ${profile}`);
|
|
7116
|
+
}
|
|
7117
|
+
|
|
7156
7118
|
//#endregion
|
|
7157
7119
|
//#region src/agents/skills/plugin-skills.ts
|
|
7158
|
-
const log$
|
|
7120
|
+
const log$8 = createSubsystemLogger("skills");
|
|
7159
7121
|
|
|
7160
7122
|
//#endregion
|
|
7161
7123
|
//#region src/agents/skills/workspace.ts
|
|
@@ -7239,7 +7201,7 @@ const LSOF_CANDIDATES = process.platform === "darwin" ? ["/usr/sbin/lsof", "/usr
|
|
|
7239
7201
|
|
|
7240
7202
|
//#endregion
|
|
7241
7203
|
//#region src/browser/chrome.ts
|
|
7242
|
-
const log$
|
|
7204
|
+
const log$7 = createSubsystemLogger("browser").child("chrome");
|
|
7243
7205
|
|
|
7244
7206
|
//#endregion
|
|
7245
7207
|
//#region src/agents/sandbox/docker.ts
|
|
@@ -7424,7 +7386,7 @@ function resolveCleanupState() {
|
|
|
7424
7386
|
};
|
|
7425
7387
|
return proc[CLEANUP_STATE_KEY];
|
|
7426
7388
|
}
|
|
7427
|
-
function isAlive(pid) {
|
|
7389
|
+
function isAlive$1(pid) {
|
|
7428
7390
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
7429
7391
|
try {
|
|
7430
7392
|
process.kill(pid, 0);
|
|
@@ -7479,7 +7441,7 @@ function registerCleanupHandlers() {
|
|
|
7479
7441
|
} catch {}
|
|
7480
7442
|
}
|
|
7481
7443
|
}
|
|
7482
|
-
async function readLockPayload(lockPath) {
|
|
7444
|
+
async function readLockPayload$1(lockPath) {
|
|
7483
7445
|
try {
|
|
7484
7446
|
const raw = await fs$1.readFile(lockPath, "utf8");
|
|
7485
7447
|
const parsed = JSON.parse(raw);
|
|
@@ -7545,10 +7507,10 @@ async function acquireSessionWriteLock(params) {
|
|
|
7545
7507
|
} };
|
|
7546
7508
|
} catch (err) {
|
|
7547
7509
|
if (err.code !== "EEXIST") throw err;
|
|
7548
|
-
const payload = await readLockPayload(lockPath);
|
|
7510
|
+
const payload = await readLockPayload$1(lockPath);
|
|
7549
7511
|
const createdAt = payload?.createdAt ? Date.parse(payload.createdAt) : NaN;
|
|
7550
7512
|
const stale = !Number.isFinite(createdAt) || Date.now() - createdAt > staleMs;
|
|
7551
|
-
const alive = payload?.pid ? isAlive(payload.pid) : false;
|
|
7513
|
+
const alive = payload?.pid ? isAlive$1(payload.pid) : false;
|
|
7552
7514
|
if (stale || !alive) {
|
|
7553
7515
|
await fs$1.rm(lockPath, { force: true });
|
|
7554
7516
|
continue;
|
|
@@ -7557,7 +7519,7 @@ async function acquireSessionWriteLock(params) {
|
|
|
7557
7519
|
await new Promise((r) => setTimeout(r, delay));
|
|
7558
7520
|
}
|
|
7559
7521
|
}
|
|
7560
|
-
const payload = await readLockPayload(lockPath);
|
|
7522
|
+
const payload = await readLockPayload$1(lockPath);
|
|
7561
7523
|
const owner = payload?.pid ? `pid=${payload.pid}` : "unknown";
|
|
7562
7524
|
throw new Error(`session file locked (timeout ${timeoutMs}ms): ${owner} ${lockPath}`);
|
|
7563
7525
|
}
|
|
@@ -7656,7 +7618,7 @@ function getFileMtimeMs(filePath) {
|
|
|
7656
7618
|
|
|
7657
7619
|
//#endregion
|
|
7658
7620
|
//#region src/config/sessions/store.ts
|
|
7659
|
-
const log$
|
|
7621
|
+
const log$6 = createSubsystemLogger("sessions/store");
|
|
7660
7622
|
const SESSION_STORE_CACHE = /* @__PURE__ */ new Map();
|
|
7661
7623
|
const DEFAULT_SESSION_STORE_TTL_MS = 45e3;
|
|
7662
7624
|
function isSessionStoreRecord(value) {
|
|
@@ -7799,7 +7761,7 @@ function pruneStaleEntries(store, overrideMaxAgeMs, opts = {}) {
|
|
|
7799
7761
|
delete store[key];
|
|
7800
7762
|
pruned++;
|
|
7801
7763
|
}
|
|
7802
|
-
if (pruned > 0 && opts.log !== false) log$
|
|
7764
|
+
if (pruned > 0 && opts.log !== false) log$6.info("pruned stale session entries", {
|
|
7803
7765
|
pruned,
|
|
7804
7766
|
maxAgeMs
|
|
7805
7767
|
});
|
|
@@ -7842,7 +7804,7 @@ function capEntryCount(store, overrideMax, opts = {}) {
|
|
|
7842
7804
|
return getEntryUpdatedAt(store[b]) - aTime;
|
|
7843
7805
|
}).slice(maxEntries);
|
|
7844
7806
|
for (const key of toRemove) delete store[key];
|
|
7845
|
-
if (opts.log !== false) log$
|
|
7807
|
+
if (opts.log !== false) log$6.info("capped session entry count", {
|
|
7846
7808
|
removed: toRemove.length,
|
|
7847
7809
|
maxEntries
|
|
7848
7810
|
});
|
|
@@ -7868,7 +7830,7 @@ async function rotateSessionFile(storePath, overrideBytes) {
|
|
|
7868
7830
|
const backupPath = `${storePath}.bak.${Date.now()}`;
|
|
7869
7831
|
try {
|
|
7870
7832
|
await fs.promises.rename(storePath, backupPath);
|
|
7871
|
-
log$
|
|
7833
|
+
log$6.info("rotated session store file", {
|
|
7872
7834
|
backupPath: path.basename(backupPath),
|
|
7873
7835
|
sizeBytes: fileSize
|
|
7874
7836
|
});
|
|
@@ -7883,7 +7845,7 @@ async function rotateSessionFile(storePath, overrideBytes) {
|
|
|
7883
7845
|
if (backups.length > maxBackups) {
|
|
7884
7846
|
const toDelete = backups.slice(maxBackups);
|
|
7885
7847
|
for (const old of toDelete) await fs.promises.unlink(path.join(dir, old)).catch(() => void 0);
|
|
7886
|
-
log$
|
|
7848
|
+
log$6.info("cleaned up old session store backups", { deleted: toDelete.length });
|
|
7887
7849
|
}
|
|
7888
7850
|
} catch {}
|
|
7889
7851
|
return true;
|
|
@@ -7903,7 +7865,7 @@ async function saveSessionStoreUnlocked(storePath, store, opts) {
|
|
|
7903
7865
|
maxEntries: maintenance.maxEntries
|
|
7904
7866
|
});
|
|
7905
7867
|
if (warning) {
|
|
7906
|
-
log$
|
|
7868
|
+
log$6.warn("session maintenance would evict active session; skipping enforcement", {
|
|
7907
7869
|
activeSessionKey: warning.activeSessionKey,
|
|
7908
7870
|
wouldPrune: warning.wouldPrune,
|
|
7909
7871
|
wouldCap: warning.wouldCap,
|
|
@@ -8221,7 +8183,7 @@ function isFailoverErrorMessage(raw) {
|
|
|
8221
8183
|
//#endregion
|
|
8222
8184
|
//#region src/agents/tool-images.ts
|
|
8223
8185
|
const MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
8224
|
-
const log$
|
|
8186
|
+
const log$5 = createSubsystemLogger("agents/tool-images");
|
|
8225
8187
|
|
|
8226
8188
|
//#endregion
|
|
8227
8189
|
//#region src/auto-reply/thinking.ts
|
|
@@ -8267,15 +8229,45 @@ async function resolveBootstrapContextForRun(params) {
|
|
|
8267
8229
|
}
|
|
8268
8230
|
|
|
8269
8231
|
//#endregion
|
|
8270
|
-
//#region src/
|
|
8232
|
+
//#region src/utils/normalize-secret-input.ts
|
|
8233
|
+
/**
|
|
8234
|
+
* Secret normalization for copy/pasted credentials.
|
|
8235
|
+
*
|
|
8236
|
+
* Common footgun: line breaks (especially `\r`) embedded in API keys/tokens.
|
|
8237
|
+
* We strip line breaks anywhere, then trim whitespace at the ends.
|
|
8238
|
+
*
|
|
8239
|
+
* Intentionally does NOT remove ordinary spaces inside the string to avoid
|
|
8240
|
+
* silently altering "Bearer <token>" style values.
|
|
8241
|
+
*/
|
|
8242
|
+
function normalizeSecretInput(value) {
|
|
8243
|
+
if (typeof value !== "string") return "";
|
|
8244
|
+
return value.replace(/[\r\n\u2028\u2029]+/g, "").trim();
|
|
8245
|
+
}
|
|
8246
|
+
function normalizeOptionalSecretInput(value) {
|
|
8247
|
+
const normalized = normalizeSecretInput(value);
|
|
8248
|
+
return normalized ? normalized : void 0;
|
|
8249
|
+
}
|
|
8250
|
+
|
|
8251
|
+
//#endregion
|
|
8252
|
+
//#region src/agents/auth-profiles/constants.ts
|
|
8271
8253
|
const AUTH_STORE_VERSION = 1;
|
|
8272
8254
|
const AUTH_PROFILE_FILENAME = "auth-profiles.json";
|
|
8273
8255
|
const LEGACY_AUTH_FILENAME = "auth.json";
|
|
8274
8256
|
const QWEN_CLI_PROFILE_ID = "qwen-portal:qwen-cli";
|
|
8275
8257
|
const MINIMAX_CLI_PROFILE_ID = "minimax-portal:minimax-cli";
|
|
8258
|
+
const AUTH_STORE_LOCK_OPTIONS = {
|
|
8259
|
+
retries: {
|
|
8260
|
+
retries: 10,
|
|
8261
|
+
factor: 2,
|
|
8262
|
+
minTimeout: 100,
|
|
8263
|
+
maxTimeout: 1e4,
|
|
8264
|
+
randomize: true
|
|
8265
|
+
},
|
|
8266
|
+
stale: 3e4
|
|
8267
|
+
};
|
|
8276
8268
|
const EXTERNAL_CLI_SYNC_TTL_MS = 900 * 1e3;
|
|
8277
8269
|
const EXTERNAL_CLI_NEAR_EXPIRY_MS = 600 * 1e3;
|
|
8278
|
-
const log$
|
|
8270
|
+
const log$4 = createSubsystemLogger("agents/auth-profiles");
|
|
8279
8271
|
|
|
8280
8272
|
//#endregion
|
|
8281
8273
|
//#region src/plugin-sdk/file-lock.ts
|
|
@@ -8286,6 +8278,120 @@ function resolveHeldLocks() {
|
|
|
8286
8278
|
return proc[HELD_LOCKS_KEY];
|
|
8287
8279
|
}
|
|
8288
8280
|
const HELD_LOCKS = resolveHeldLocks();
|
|
8281
|
+
function isAlive(pid) {
|
|
8282
|
+
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
8283
|
+
try {
|
|
8284
|
+
process.kill(pid, 0);
|
|
8285
|
+
return true;
|
|
8286
|
+
} catch {
|
|
8287
|
+
return false;
|
|
8288
|
+
}
|
|
8289
|
+
}
|
|
8290
|
+
function computeDelayMs(retries, attempt) {
|
|
8291
|
+
const base = Math.min(retries.maxTimeout, Math.max(retries.minTimeout, retries.minTimeout * retries.factor ** attempt));
|
|
8292
|
+
const jitter = retries.randomize ? 1 + Math.random() : 1;
|
|
8293
|
+
return Math.min(retries.maxTimeout, Math.round(base * jitter));
|
|
8294
|
+
}
|
|
8295
|
+
async function readLockPayload(lockPath) {
|
|
8296
|
+
try {
|
|
8297
|
+
const raw = await fs$1.readFile(lockPath, "utf8");
|
|
8298
|
+
const parsed = JSON.parse(raw);
|
|
8299
|
+
if (typeof parsed.pid !== "number" || typeof parsed.createdAt !== "string") return null;
|
|
8300
|
+
return {
|
|
8301
|
+
pid: parsed.pid,
|
|
8302
|
+
createdAt: parsed.createdAt
|
|
8303
|
+
};
|
|
8304
|
+
} catch {
|
|
8305
|
+
return null;
|
|
8306
|
+
}
|
|
8307
|
+
}
|
|
8308
|
+
async function resolveNormalizedFilePath(filePath) {
|
|
8309
|
+
const resolved = path.resolve(filePath);
|
|
8310
|
+
const dir = path.dirname(resolved);
|
|
8311
|
+
await fs$1.mkdir(dir, { recursive: true });
|
|
8312
|
+
try {
|
|
8313
|
+
const realDir = await fs$1.realpath(dir);
|
|
8314
|
+
return path.join(realDir, path.basename(resolved));
|
|
8315
|
+
} catch {
|
|
8316
|
+
return resolved;
|
|
8317
|
+
}
|
|
8318
|
+
}
|
|
8319
|
+
async function isStaleLock(lockPath, staleMs) {
|
|
8320
|
+
const payload = await readLockPayload(lockPath);
|
|
8321
|
+
if (payload?.pid && !isAlive(payload.pid)) return true;
|
|
8322
|
+
if (payload?.createdAt) {
|
|
8323
|
+
const createdAt = Date.parse(payload.createdAt);
|
|
8324
|
+
if (!Number.isFinite(createdAt) || Date.now() - createdAt > staleMs) return true;
|
|
8325
|
+
}
|
|
8326
|
+
try {
|
|
8327
|
+
const stat = await fs$1.stat(lockPath);
|
|
8328
|
+
return Date.now() - stat.mtimeMs > staleMs;
|
|
8329
|
+
} catch {
|
|
8330
|
+
return true;
|
|
8331
|
+
}
|
|
8332
|
+
}
|
|
8333
|
+
async function acquireFileLock(filePath, options) {
|
|
8334
|
+
const normalizedFile = await resolveNormalizedFilePath(filePath);
|
|
8335
|
+
const lockPath = `${normalizedFile}.lock`;
|
|
8336
|
+
const held = HELD_LOCKS.get(normalizedFile);
|
|
8337
|
+
if (held) {
|
|
8338
|
+
held.count += 1;
|
|
8339
|
+
return {
|
|
8340
|
+
lockPath,
|
|
8341
|
+
release: async () => {
|
|
8342
|
+
const current = HELD_LOCKS.get(normalizedFile);
|
|
8343
|
+
if (!current) return;
|
|
8344
|
+
current.count -= 1;
|
|
8345
|
+
if (current.count > 0) return;
|
|
8346
|
+
HELD_LOCKS.delete(normalizedFile);
|
|
8347
|
+
await current.handle.close().catch(() => void 0);
|
|
8348
|
+
await fs$1.rm(current.lockPath, { force: true }).catch(() => void 0);
|
|
8349
|
+
}
|
|
8350
|
+
};
|
|
8351
|
+
}
|
|
8352
|
+
const attempts = Math.max(1, options.retries.retries + 1);
|
|
8353
|
+
for (let attempt = 0; attempt < attempts; attempt += 1) try {
|
|
8354
|
+
const handle = await fs$1.open(lockPath, "wx");
|
|
8355
|
+
await handle.writeFile(JSON.stringify({
|
|
8356
|
+
pid: process.pid,
|
|
8357
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8358
|
+
}, null, 2), "utf8");
|
|
8359
|
+
HELD_LOCKS.set(normalizedFile, {
|
|
8360
|
+
count: 1,
|
|
8361
|
+
handle,
|
|
8362
|
+
lockPath
|
|
8363
|
+
});
|
|
8364
|
+
return {
|
|
8365
|
+
lockPath,
|
|
8366
|
+
release: async () => {
|
|
8367
|
+
const current = HELD_LOCKS.get(normalizedFile);
|
|
8368
|
+
if (!current) return;
|
|
8369
|
+
current.count -= 1;
|
|
8370
|
+
if (current.count > 0) return;
|
|
8371
|
+
HELD_LOCKS.delete(normalizedFile);
|
|
8372
|
+
await current.handle.close().catch(() => void 0);
|
|
8373
|
+
await fs$1.rm(current.lockPath, { force: true }).catch(() => void 0);
|
|
8374
|
+
}
|
|
8375
|
+
};
|
|
8376
|
+
} catch (err) {
|
|
8377
|
+
if (err.code !== "EEXIST") throw err;
|
|
8378
|
+
if (await isStaleLock(lockPath, options.stale)) {
|
|
8379
|
+
await fs$1.rm(lockPath, { force: true }).catch(() => void 0);
|
|
8380
|
+
continue;
|
|
8381
|
+
}
|
|
8382
|
+
if (attempt >= attempts - 1) break;
|
|
8383
|
+
await new Promise((resolve) => setTimeout(resolve, computeDelayMs(options.retries, attempt)));
|
|
8384
|
+
}
|
|
8385
|
+
throw new Error(`file lock timeout for ${normalizedFile}`);
|
|
8386
|
+
}
|
|
8387
|
+
async function withFileLock(filePath, options, fn) {
|
|
8388
|
+
const lock = await acquireFileLock(filePath, options);
|
|
8389
|
+
try {
|
|
8390
|
+
return await fn();
|
|
8391
|
+
} finally {
|
|
8392
|
+
await lock.release();
|
|
8393
|
+
}
|
|
8394
|
+
}
|
|
8289
8395
|
|
|
8290
8396
|
//#endregion
|
|
8291
8397
|
//#region src/infra/json-file.ts
|
|
@@ -8310,7 +8416,7 @@ function saveJsonFile(pathname, data) {
|
|
|
8310
8416
|
|
|
8311
8417
|
//#endregion
|
|
8312
8418
|
//#region src/agents/cli-credentials.ts
|
|
8313
|
-
const log$
|
|
8419
|
+
const log$3 = createSubsystemLogger("agents/auth-profiles");
|
|
8314
8420
|
const QWEN_CLI_CREDENTIALS_RELATIVE_PATH = ".qwen/oauth_creds.json";
|
|
8315
8421
|
const MINIMAX_CLI_CREDENTIALS_RELATIVE_PATH = ".minimax/oauth_creds.json";
|
|
8316
8422
|
let qwenCliCache = null;
|
|
@@ -8396,7 +8502,7 @@ function syncExternalCliCredentialsForProvider(store, profileId, provider, readC
|
|
|
8396
8502
|
const existingOAuth = existing?.type === "oauth" ? existing : void 0;
|
|
8397
8503
|
if ((!existingOAuth || existingOAuth.provider !== provider || existingOAuth.expires <= now || creds.expires > existingOAuth.expires) && !shallowEqualOAuthCredentials(existingOAuth, creds)) {
|
|
8398
8504
|
store.profiles[profileId] = creds;
|
|
8399
|
-
log$
|
|
8505
|
+
log$4.info(`synced ${provider} credentials from external cli`, {
|
|
8400
8506
|
profileId,
|
|
8401
8507
|
expires: new Date(creds.expires).toISOString()
|
|
8402
8508
|
});
|
|
@@ -8420,7 +8526,7 @@ function syncExternalCliCredentials(store) {
|
|
|
8420
8526
|
if ((!existingOAuth || existingOAuth.provider !== "qwen-portal" || existingOAuth.expires <= now || qwenCreds.expires > existingOAuth.expires) && !shallowEqualOAuthCredentials(existingOAuth, qwenCreds)) {
|
|
8421
8527
|
store.profiles[QWEN_CLI_PROFILE_ID] = qwenCreds;
|
|
8422
8528
|
mutated = true;
|
|
8423
|
-
log$
|
|
8529
|
+
log$4.info("synced qwen credentials from qwen cli", {
|
|
8424
8530
|
profileId: QWEN_CLI_PROFILE_ID,
|
|
8425
8531
|
expires: new Date(qwenCreds.expires).toISOString()
|
|
8426
8532
|
});
|
|
@@ -8448,6 +8554,17 @@ function resolveLegacyAuthStorePath(agentDir) {
|
|
|
8448
8554
|
const resolved = resolveUserPath(agentDir ?? resolveAnimaAgentDir());
|
|
8449
8555
|
return path.join(resolved, LEGACY_AUTH_FILENAME);
|
|
8450
8556
|
}
|
|
8557
|
+
function resolveAuthStorePathForDisplay(agentDir) {
|
|
8558
|
+
const pathname = resolveAuthStorePath(agentDir);
|
|
8559
|
+
return pathname.startsWith("~") ? pathname : resolveUserPath(pathname);
|
|
8560
|
+
}
|
|
8561
|
+
function ensureAuthStoreFile(pathname) {
|
|
8562
|
+
if (fs.existsSync(pathname)) return;
|
|
8563
|
+
saveJsonFile(pathname, {
|
|
8564
|
+
version: AUTH_STORE_VERSION,
|
|
8565
|
+
profiles: {}
|
|
8566
|
+
});
|
|
8567
|
+
}
|
|
8451
8568
|
|
|
8452
8569
|
//#endregion
|
|
8453
8570
|
//#region src/agents/auth-profiles/store.ts
|
|
@@ -8495,6 +8612,46 @@ function coerceAuthStore(raw) {
|
|
|
8495
8612
|
usageStats: record.usageStats && typeof record.usageStats === "object" ? record.usageStats : void 0
|
|
8496
8613
|
};
|
|
8497
8614
|
}
|
|
8615
|
+
function mergeRecord(base, override) {
|
|
8616
|
+
if (!base && !override) return;
|
|
8617
|
+
if (!base) return { ...override };
|
|
8618
|
+
if (!override) return { ...base };
|
|
8619
|
+
return {
|
|
8620
|
+
...base,
|
|
8621
|
+
...override
|
|
8622
|
+
};
|
|
8623
|
+
}
|
|
8624
|
+
function mergeAuthProfileStores(base, override) {
|
|
8625
|
+
if (Object.keys(override.profiles).length === 0 && !override.order && !override.lastGood && !override.usageStats) return base;
|
|
8626
|
+
return {
|
|
8627
|
+
version: Math.max(base.version, override.version ?? base.version),
|
|
8628
|
+
profiles: {
|
|
8629
|
+
...base.profiles,
|
|
8630
|
+
...override.profiles
|
|
8631
|
+
},
|
|
8632
|
+
order: mergeRecord(base.order, override.order),
|
|
8633
|
+
lastGood: mergeRecord(base.lastGood, override.lastGood),
|
|
8634
|
+
usageStats: mergeRecord(base.usageStats, override.usageStats)
|
|
8635
|
+
};
|
|
8636
|
+
}
|
|
8637
|
+
function mergeOAuthFileIntoStore(store) {
|
|
8638
|
+
const oauthRaw = loadJsonFile(resolveOAuthPath());
|
|
8639
|
+
if (!oauthRaw || typeof oauthRaw !== "object") return false;
|
|
8640
|
+
const oauthEntries = oauthRaw;
|
|
8641
|
+
let mutated = false;
|
|
8642
|
+
for (const [provider, creds] of Object.entries(oauthEntries)) {
|
|
8643
|
+
if (!creds || typeof creds !== "object") continue;
|
|
8644
|
+
const profileId = `${provider}:default`;
|
|
8645
|
+
if (store.profiles[profileId]) continue;
|
|
8646
|
+
store.profiles[profileId] = {
|
|
8647
|
+
type: "oauth",
|
|
8648
|
+
provider,
|
|
8649
|
+
...creds
|
|
8650
|
+
};
|
|
8651
|
+
mutated = true;
|
|
8652
|
+
}
|
|
8653
|
+
return mutated;
|
|
8654
|
+
}
|
|
8498
8655
|
function applyLegacyStore(store, legacy) {
|
|
8499
8656
|
for (const [provider, cred] of Object.entries(legacy)) {
|
|
8500
8657
|
const profileId = `${provider}:default`;
|
|
@@ -8554,10 +8711,572 @@ function loadAuthProfileStore() {
|
|
|
8554
8711
|
syncExternalCliCredentials(store);
|
|
8555
8712
|
return store;
|
|
8556
8713
|
}
|
|
8714
|
+
function loadAuthProfileStoreForAgent(agentDir, _options) {
|
|
8715
|
+
const authPath = resolveAuthStorePath(agentDir);
|
|
8716
|
+
const asStore = coerceAuthStore(loadJsonFile(authPath));
|
|
8717
|
+
if (asStore) {
|
|
8718
|
+
if (syncExternalCliCredentials(asStore)) saveJsonFile(authPath, asStore);
|
|
8719
|
+
return asStore;
|
|
8720
|
+
}
|
|
8721
|
+
if (agentDir) {
|
|
8722
|
+
const mainStore = coerceAuthStore(loadJsonFile(resolveAuthStorePath()));
|
|
8723
|
+
if (mainStore && Object.keys(mainStore.profiles).length > 0) {
|
|
8724
|
+
saveJsonFile(authPath, mainStore);
|
|
8725
|
+
log$4.info("inherited auth-profiles from main agent", { agentDir });
|
|
8726
|
+
return mainStore;
|
|
8727
|
+
}
|
|
8728
|
+
}
|
|
8729
|
+
const legacy = coerceLegacyStore(loadJsonFile(resolveLegacyAuthStorePath(agentDir)));
|
|
8730
|
+
const store = {
|
|
8731
|
+
version: AUTH_STORE_VERSION,
|
|
8732
|
+
profiles: {}
|
|
8733
|
+
};
|
|
8734
|
+
if (legacy) applyLegacyStore(store, legacy);
|
|
8735
|
+
const mergedOAuth = mergeOAuthFileIntoStore(store);
|
|
8736
|
+
const syncedCli = syncExternalCliCredentials(store);
|
|
8737
|
+
const shouldWrite = legacy !== null || mergedOAuth || syncedCli;
|
|
8738
|
+
if (shouldWrite) saveJsonFile(authPath, store);
|
|
8739
|
+
if (shouldWrite && legacy !== null) {
|
|
8740
|
+
const legacyPath = resolveLegacyAuthStorePath(agentDir);
|
|
8741
|
+
try {
|
|
8742
|
+
fs.unlinkSync(legacyPath);
|
|
8743
|
+
} catch (err) {
|
|
8744
|
+
if (err?.code !== "ENOENT") log$4.warn("failed to delete legacy auth.json after migration", {
|
|
8745
|
+
err,
|
|
8746
|
+
legacyPath
|
|
8747
|
+
});
|
|
8748
|
+
}
|
|
8749
|
+
}
|
|
8750
|
+
return store;
|
|
8751
|
+
}
|
|
8752
|
+
function ensureAuthProfileStore(agentDir, options) {
|
|
8753
|
+
const store = loadAuthProfileStoreForAgent(agentDir, options);
|
|
8754
|
+
const authPath = resolveAuthStorePath(agentDir);
|
|
8755
|
+
const mainAuthPath = resolveAuthStorePath();
|
|
8756
|
+
if (!agentDir || authPath === mainAuthPath) return store;
|
|
8757
|
+
return mergeAuthProfileStores(loadAuthProfileStoreForAgent(void 0, options), store);
|
|
8758
|
+
}
|
|
8759
|
+
function saveAuthProfileStore(store, agentDir) {
|
|
8760
|
+
saveJsonFile(resolveAuthStorePath(agentDir), {
|
|
8761
|
+
version: AUTH_STORE_VERSION,
|
|
8762
|
+
profiles: store.profiles,
|
|
8763
|
+
order: store.order ?? void 0,
|
|
8764
|
+
lastGood: store.lastGood ?? void 0,
|
|
8765
|
+
usageStats: store.usageStats ?? void 0
|
|
8766
|
+
});
|
|
8767
|
+
}
|
|
8768
|
+
|
|
8769
|
+
//#endregion
|
|
8770
|
+
//#region src/agents/auth-profiles/profiles.ts
|
|
8771
|
+
function listProfilesForProvider(store, provider) {
|
|
8772
|
+
const providerKey = normalizeProviderId(provider);
|
|
8773
|
+
return Object.entries(store.profiles).filter(([, cred]) => normalizeProviderId(cred.provider) === providerKey).map(([id]) => id);
|
|
8774
|
+
}
|
|
8775
|
+
|
|
8776
|
+
//#endregion
|
|
8777
|
+
//#region src/agents/auth-profiles/repair.ts
|
|
8778
|
+
function getProfileSuffix(profileId) {
|
|
8779
|
+
const idx = profileId.indexOf(":");
|
|
8780
|
+
if (idx < 0) return "";
|
|
8781
|
+
return profileId.slice(idx + 1);
|
|
8782
|
+
}
|
|
8783
|
+
function isEmailLike(value) {
|
|
8784
|
+
const trimmed = value.trim();
|
|
8785
|
+
if (!trimmed) return false;
|
|
8786
|
+
return trimmed.includes("@") && trimmed.includes(".");
|
|
8787
|
+
}
|
|
8788
|
+
function suggestOAuthProfileIdForLegacyDefault(params) {
|
|
8789
|
+
const providerKey = normalizeProviderId(params.provider);
|
|
8790
|
+
if (getProfileSuffix(params.legacyProfileId) !== "default") return null;
|
|
8791
|
+
const legacyCfg = params.cfg?.auth?.profiles?.[params.legacyProfileId];
|
|
8792
|
+
if (legacyCfg && normalizeProviderId(legacyCfg.provider) === providerKey && legacyCfg.mode !== "oauth") return null;
|
|
8793
|
+
const oauthProfiles = listProfilesForProvider(params.store, providerKey).filter((id) => params.store.profiles[id]?.type === "oauth");
|
|
8794
|
+
if (oauthProfiles.length === 0) return null;
|
|
8795
|
+
const configuredEmail = legacyCfg?.email?.trim();
|
|
8796
|
+
if (configuredEmail) {
|
|
8797
|
+
const byEmail = oauthProfiles.find((id) => {
|
|
8798
|
+
const cred = params.store.profiles[id];
|
|
8799
|
+
if (!cred || cred.type !== "oauth") return false;
|
|
8800
|
+
return cred.email?.trim() === configuredEmail || id === `${providerKey}:${configuredEmail}`;
|
|
8801
|
+
});
|
|
8802
|
+
if (byEmail) return byEmail;
|
|
8803
|
+
}
|
|
8804
|
+
const lastGood = params.store.lastGood?.[providerKey] ?? params.store.lastGood?.[params.provider];
|
|
8805
|
+
if (lastGood && oauthProfiles.includes(lastGood)) return lastGood;
|
|
8806
|
+
const nonLegacy = oauthProfiles.filter((id) => id !== params.legacyProfileId);
|
|
8807
|
+
if (nonLegacy.length === 1) return nonLegacy[0] ?? null;
|
|
8808
|
+
const emailLike = nonLegacy.filter((id) => isEmailLike(getProfileSuffix(id)));
|
|
8809
|
+
if (emailLike.length === 1) return emailLike[0] ?? null;
|
|
8810
|
+
return null;
|
|
8811
|
+
}
|
|
8812
|
+
|
|
8813
|
+
//#endregion
|
|
8814
|
+
//#region src/agents/auth-profiles/doctor.ts
|
|
8815
|
+
function formatAuthDoctorHint(params) {
|
|
8816
|
+
const providerKey = normalizeProviderId(params.provider);
|
|
8817
|
+
if (providerKey !== "anthropic") return "";
|
|
8818
|
+
const legacyProfileId = params.profileId ?? "anthropic:default";
|
|
8819
|
+
const suggested = suggestOAuthProfileIdForLegacyDefault({
|
|
8820
|
+
cfg: params.cfg,
|
|
8821
|
+
store: params.store,
|
|
8822
|
+
provider: providerKey,
|
|
8823
|
+
legacyProfileId
|
|
8824
|
+
});
|
|
8825
|
+
if (!suggested || suggested === legacyProfileId) return "";
|
|
8826
|
+
const storeOauthProfiles = listProfilesForProvider(params.store, providerKey).filter((id) => params.store.profiles[id]?.type === "oauth").join(", ");
|
|
8827
|
+
const cfgMode = params.cfg?.auth?.profiles?.[legacyProfileId]?.mode;
|
|
8828
|
+
const cfgProvider = params.cfg?.auth?.profiles?.[legacyProfileId]?.provider;
|
|
8829
|
+
return [
|
|
8830
|
+
"Doctor hint (for GitHub issue):",
|
|
8831
|
+
`- provider: ${providerKey}`,
|
|
8832
|
+
`- config: ${legacyProfileId}${cfgProvider || cfgMode ? ` (provider=${cfgProvider ?? "?"}, mode=${cfgMode ?? "?"})` : ""}`,
|
|
8833
|
+
`- auth store oauth profiles: ${storeOauthProfiles || "(none)"}`,
|
|
8834
|
+
`- suggested profile: ${suggested}`,
|
|
8835
|
+
`Fix: run "${formatCliCommand("anima doctor --yes")}"`
|
|
8836
|
+
].join("\n");
|
|
8837
|
+
}
|
|
8557
8838
|
|
|
8558
8839
|
//#endregion
|
|
8559
8840
|
//#region src/agents/auth-profiles/oauth.ts
|
|
8560
8841
|
const OAUTH_PROVIDER_IDS = new Set(getOAuthProviders().map((provider) => provider.id));
|
|
8842
|
+
const isOAuthProvider = (provider) => OAUTH_PROVIDER_IDS.has(provider);
|
|
8843
|
+
const resolveOAuthProvider = (provider) => isOAuthProvider(provider) ? provider : null;
|
|
8844
|
+
function buildOAuthApiKey(_provider, credentials) {
|
|
8845
|
+
return credentials.access;
|
|
8846
|
+
}
|
|
8847
|
+
async function refreshOAuthTokenWithLock(params) {
|
|
8848
|
+
const authPath = resolveAuthStorePath(params.agentDir);
|
|
8849
|
+
ensureAuthStoreFile(authPath);
|
|
8850
|
+
return await withFileLock(authPath, AUTH_STORE_LOCK_OPTIONS, async () => {
|
|
8851
|
+
const store = ensureAuthProfileStore(params.agentDir);
|
|
8852
|
+
const cred = store.profiles[params.profileId];
|
|
8853
|
+
if (!cred || cred.type !== "oauth") return null;
|
|
8854
|
+
if (Date.now() < cred.expires) return {
|
|
8855
|
+
apiKey: buildOAuthApiKey(cred.provider, cred),
|
|
8856
|
+
newCredentials: cred
|
|
8857
|
+
};
|
|
8858
|
+
const oauthCreds = { [cred.provider]: cred };
|
|
8859
|
+
const result = await (async () => {
|
|
8860
|
+
const oauthProvider = resolveOAuthProvider(cred.provider);
|
|
8861
|
+
if (!oauthProvider) return null;
|
|
8862
|
+
return await getOAuthApiKey(oauthProvider, oauthCreds);
|
|
8863
|
+
})();
|
|
8864
|
+
if (!result) return null;
|
|
8865
|
+
store.profiles[params.profileId] = {
|
|
8866
|
+
...cred,
|
|
8867
|
+
...result.newCredentials,
|
|
8868
|
+
type: "oauth"
|
|
8869
|
+
};
|
|
8870
|
+
saveAuthProfileStore(store, params.agentDir);
|
|
8871
|
+
return result;
|
|
8872
|
+
});
|
|
8873
|
+
}
|
|
8874
|
+
async function tryResolveOAuthProfile(params) {
|
|
8875
|
+
const { cfg, store, profileId } = params;
|
|
8876
|
+
const cred = store.profiles[profileId];
|
|
8877
|
+
if (!cred || cred.type !== "oauth") return null;
|
|
8878
|
+
const profileConfig = cfg?.auth?.profiles?.[profileId];
|
|
8879
|
+
if (profileConfig && profileConfig.provider !== cred.provider) return null;
|
|
8880
|
+
if (profileConfig && profileConfig.mode !== cred.type) return null;
|
|
8881
|
+
if (Date.now() < cred.expires) return {
|
|
8882
|
+
apiKey: buildOAuthApiKey(cred.provider, cred),
|
|
8883
|
+
provider: cred.provider,
|
|
8884
|
+
email: cred.email
|
|
8885
|
+
};
|
|
8886
|
+
const refreshed = await refreshOAuthTokenWithLock({
|
|
8887
|
+
profileId,
|
|
8888
|
+
agentDir: params.agentDir
|
|
8889
|
+
});
|
|
8890
|
+
if (!refreshed) return null;
|
|
8891
|
+
return {
|
|
8892
|
+
apiKey: refreshed.apiKey,
|
|
8893
|
+
provider: cred.provider,
|
|
8894
|
+
email: cred.email
|
|
8895
|
+
};
|
|
8896
|
+
}
|
|
8897
|
+
async function resolveApiKeyForProfile(params) {
|
|
8898
|
+
const { cfg, store, profileId } = params;
|
|
8899
|
+
const cred = store.profiles[profileId];
|
|
8900
|
+
if (!cred) return null;
|
|
8901
|
+
const profileConfig = cfg?.auth?.profiles?.[profileId];
|
|
8902
|
+
if (profileConfig && profileConfig.provider !== cred.provider) return null;
|
|
8903
|
+
if (profileConfig && profileConfig.mode !== cred.type) {
|
|
8904
|
+
if (!(profileConfig.mode === "oauth" && cred.type === "token")) return null;
|
|
8905
|
+
}
|
|
8906
|
+
if (cred.type === "api_key") {
|
|
8907
|
+
const key = cred.key?.trim();
|
|
8908
|
+
if (!key) return null;
|
|
8909
|
+
return {
|
|
8910
|
+
apiKey: key,
|
|
8911
|
+
provider: cred.provider,
|
|
8912
|
+
email: cred.email
|
|
8913
|
+
};
|
|
8914
|
+
}
|
|
8915
|
+
if (cred.type === "token") {
|
|
8916
|
+
const token = cred.token?.trim();
|
|
8917
|
+
if (!token) return null;
|
|
8918
|
+
if (typeof cred.expires === "number" && Number.isFinite(cred.expires) && cred.expires > 0 && Date.now() >= cred.expires) return null;
|
|
8919
|
+
return {
|
|
8920
|
+
apiKey: token,
|
|
8921
|
+
provider: cred.provider,
|
|
8922
|
+
email: cred.email
|
|
8923
|
+
};
|
|
8924
|
+
}
|
|
8925
|
+
if (Date.now() < cred.expires) return {
|
|
8926
|
+
apiKey: buildOAuthApiKey(cred.provider, cred),
|
|
8927
|
+
provider: cred.provider,
|
|
8928
|
+
email: cred.email
|
|
8929
|
+
};
|
|
8930
|
+
try {
|
|
8931
|
+
const result = await refreshOAuthTokenWithLock({
|
|
8932
|
+
profileId,
|
|
8933
|
+
agentDir: params.agentDir
|
|
8934
|
+
});
|
|
8935
|
+
if (!result) return null;
|
|
8936
|
+
return {
|
|
8937
|
+
apiKey: result.apiKey,
|
|
8938
|
+
provider: cred.provider,
|
|
8939
|
+
email: cred.email
|
|
8940
|
+
};
|
|
8941
|
+
} catch (error) {
|
|
8942
|
+
const refreshedStore = ensureAuthProfileStore(params.agentDir);
|
|
8943
|
+
const refreshed = refreshedStore.profiles[profileId];
|
|
8944
|
+
if (refreshed?.type === "oauth" && Date.now() < refreshed.expires) return {
|
|
8945
|
+
apiKey: buildOAuthApiKey(refreshed.provider, refreshed),
|
|
8946
|
+
provider: refreshed.provider,
|
|
8947
|
+
email: refreshed.email ?? cred.email
|
|
8948
|
+
};
|
|
8949
|
+
const fallbackProfileId = suggestOAuthProfileIdForLegacyDefault({
|
|
8950
|
+
cfg,
|
|
8951
|
+
store: refreshedStore,
|
|
8952
|
+
provider: cred.provider,
|
|
8953
|
+
legacyProfileId: profileId
|
|
8954
|
+
});
|
|
8955
|
+
if (fallbackProfileId && fallbackProfileId !== profileId) try {
|
|
8956
|
+
const fallbackResolved = await tryResolveOAuthProfile({
|
|
8957
|
+
cfg,
|
|
8958
|
+
store: refreshedStore,
|
|
8959
|
+
profileId: fallbackProfileId,
|
|
8960
|
+
agentDir: params.agentDir
|
|
8961
|
+
});
|
|
8962
|
+
if (fallbackResolved) return fallbackResolved;
|
|
8963
|
+
} catch {}
|
|
8964
|
+
if (params.agentDir) try {
|
|
8965
|
+
const mainCred = ensureAuthProfileStore(void 0).profiles[profileId];
|
|
8966
|
+
if (mainCred?.type === "oauth" && Date.now() < mainCred.expires) {
|
|
8967
|
+
refreshedStore.profiles[profileId] = { ...mainCred };
|
|
8968
|
+
saveAuthProfileStore(refreshedStore, params.agentDir);
|
|
8969
|
+
log$4.info("inherited fresh OAuth credentials from main agent", {
|
|
8970
|
+
profileId,
|
|
8971
|
+
agentDir: params.agentDir,
|
|
8972
|
+
expires: new Date(mainCred.expires).toISOString()
|
|
8973
|
+
});
|
|
8974
|
+
return {
|
|
8975
|
+
apiKey: buildOAuthApiKey(mainCred.provider, mainCred),
|
|
8976
|
+
provider: mainCred.provider,
|
|
8977
|
+
email: mainCred.email
|
|
8978
|
+
};
|
|
8979
|
+
}
|
|
8980
|
+
} catch {}
|
|
8981
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
8982
|
+
const hint = formatAuthDoctorHint({
|
|
8983
|
+
cfg,
|
|
8984
|
+
store: refreshedStore,
|
|
8985
|
+
provider: cred.provider,
|
|
8986
|
+
profileId
|
|
8987
|
+
});
|
|
8988
|
+
throw new Error(`OAuth token refresh failed for ${cred.provider}: ${message}. Please try again or re-authenticate.` + (hint ? `\n\n${hint}` : ""), { cause: error });
|
|
8989
|
+
}
|
|
8990
|
+
}
|
|
8991
|
+
|
|
8992
|
+
//#endregion
|
|
8993
|
+
//#region src/agents/auth-profiles/usage.ts
|
|
8994
|
+
function resolveProfileUnusableUntil$1(stats) {
|
|
8995
|
+
const values = [stats.cooldownUntil, stats.disabledUntil].filter((value) => typeof value === "number").filter((value) => Number.isFinite(value) && value > 0);
|
|
8996
|
+
if (values.length === 0) return null;
|
|
8997
|
+
return Math.max(...values);
|
|
8998
|
+
}
|
|
8999
|
+
/**
|
|
9000
|
+
* Check if a profile is currently in cooldown (due to rate limiting or errors).
|
|
9001
|
+
*/
|
|
9002
|
+
function isProfileInCooldown(store, profileId) {
|
|
9003
|
+
const stats = store.usageStats?.[profileId];
|
|
9004
|
+
if (!stats) return false;
|
|
9005
|
+
const unusableUntil = resolveProfileUnusableUntil$1(stats);
|
|
9006
|
+
return unusableUntil ? Date.now() < unusableUntil : false;
|
|
9007
|
+
}
|
|
9008
|
+
|
|
9009
|
+
//#endregion
|
|
9010
|
+
//#region src/agents/auth-profiles/order.ts
|
|
9011
|
+
function resolveProfileUnusableUntil(stats) {
|
|
9012
|
+
const values = [stats.cooldownUntil, stats.disabledUntil].filter((value) => typeof value === "number").filter((value) => Number.isFinite(value) && value > 0);
|
|
9013
|
+
if (values.length === 0) return null;
|
|
9014
|
+
return Math.max(...values);
|
|
9015
|
+
}
|
|
9016
|
+
function resolveAuthProfileOrder(params) {
|
|
9017
|
+
const { cfg, store, provider, preferredProfile } = params;
|
|
9018
|
+
const providerKey = normalizeProviderId(provider);
|
|
9019
|
+
const now = Date.now();
|
|
9020
|
+
const storedOrder = (() => {
|
|
9021
|
+
const order = store.order;
|
|
9022
|
+
if (!order) return;
|
|
9023
|
+
for (const [key, value] of Object.entries(order)) if (normalizeProviderId(key) === providerKey) return value;
|
|
9024
|
+
})();
|
|
9025
|
+
const configuredOrder = (() => {
|
|
9026
|
+
const order = cfg?.auth?.order;
|
|
9027
|
+
if (!order) return;
|
|
9028
|
+
for (const [key, value] of Object.entries(order)) if (normalizeProviderId(key) === providerKey) return value;
|
|
9029
|
+
})();
|
|
9030
|
+
const explicitOrder = storedOrder ?? configuredOrder;
|
|
9031
|
+
const explicitProfiles = cfg?.auth?.profiles ? Object.entries(cfg.auth.profiles).filter(([, profile]) => normalizeProviderId(profile.provider) === providerKey).map(([profileId]) => profileId) : [];
|
|
9032
|
+
const baseOrder = explicitOrder ?? (explicitProfiles.length > 0 ? explicitProfiles : listProfilesForProvider(store, providerKey));
|
|
9033
|
+
if (baseOrder.length === 0) return [];
|
|
9034
|
+
const filtered = baseOrder.filter((profileId) => {
|
|
9035
|
+
const cred = store.profiles[profileId];
|
|
9036
|
+
if (!cred) return false;
|
|
9037
|
+
if (normalizeProviderId(cred.provider) !== providerKey) return false;
|
|
9038
|
+
const profileConfig = cfg?.auth?.profiles?.[profileId];
|
|
9039
|
+
if (profileConfig) {
|
|
9040
|
+
if (normalizeProviderId(profileConfig.provider) !== providerKey) return false;
|
|
9041
|
+
if (profileConfig.mode !== cred.type) {
|
|
9042
|
+
if (!(profileConfig.mode === "oauth" && cred.type === "token")) return false;
|
|
9043
|
+
}
|
|
9044
|
+
}
|
|
9045
|
+
if (cred.type === "api_key") return Boolean(cred.key?.trim());
|
|
9046
|
+
if (cred.type === "token") {
|
|
9047
|
+
if (!cred.token?.trim()) return false;
|
|
9048
|
+
if (typeof cred.expires === "number" && Number.isFinite(cred.expires) && cred.expires > 0 && now >= cred.expires) return false;
|
|
9049
|
+
return true;
|
|
9050
|
+
}
|
|
9051
|
+
if (cred.type === "oauth") return Boolean(cred.access?.trim() || cred.refresh?.trim());
|
|
9052
|
+
return false;
|
|
9053
|
+
});
|
|
9054
|
+
const deduped = [];
|
|
9055
|
+
for (const entry of filtered) if (!deduped.includes(entry)) deduped.push(entry);
|
|
9056
|
+
if (explicitOrder && explicitOrder.length > 0) {
|
|
9057
|
+
const available = [];
|
|
9058
|
+
const inCooldown = [];
|
|
9059
|
+
for (const profileId of deduped) {
|
|
9060
|
+
const cooldownUntil = resolveProfileUnusableUntil(store.usageStats?.[profileId] ?? {}) ?? 0;
|
|
9061
|
+
if (typeof cooldownUntil === "number" && Number.isFinite(cooldownUntil) && cooldownUntil > 0 && now < cooldownUntil) inCooldown.push({
|
|
9062
|
+
profileId,
|
|
9063
|
+
cooldownUntil
|
|
9064
|
+
});
|
|
9065
|
+
else available.push(profileId);
|
|
9066
|
+
}
|
|
9067
|
+
const cooldownSorted = inCooldown.toSorted((a, b) => a.cooldownUntil - b.cooldownUntil).map((entry) => entry.profileId);
|
|
9068
|
+
const ordered = [...available, ...cooldownSorted];
|
|
9069
|
+
if (preferredProfile && ordered.includes(preferredProfile)) return [preferredProfile, ...ordered.filter((e) => e !== preferredProfile)];
|
|
9070
|
+
return ordered;
|
|
9071
|
+
}
|
|
9072
|
+
const sorted = orderProfilesByMode(deduped, store);
|
|
9073
|
+
if (preferredProfile && sorted.includes(preferredProfile)) return [preferredProfile, ...sorted.filter((e) => e !== preferredProfile)];
|
|
9074
|
+
return sorted;
|
|
9075
|
+
}
|
|
9076
|
+
function orderProfilesByMode(order, store) {
|
|
9077
|
+
const now = Date.now();
|
|
9078
|
+
const available = [];
|
|
9079
|
+
const inCooldown = [];
|
|
9080
|
+
for (const profileId of order) if (isProfileInCooldown(store, profileId)) inCooldown.push(profileId);
|
|
9081
|
+
else available.push(profileId);
|
|
9082
|
+
const sorted = available.map((profileId) => {
|
|
9083
|
+
const type = store.profiles[profileId]?.type;
|
|
9084
|
+
return {
|
|
9085
|
+
profileId,
|
|
9086
|
+
typeScore: type === "oauth" ? 0 : type === "token" ? 1 : type === "api_key" ? 2 : 3,
|
|
9087
|
+
lastUsed: store.usageStats?.[profileId]?.lastUsed ?? 0
|
|
9088
|
+
};
|
|
9089
|
+
}).toSorted((a, b) => {
|
|
9090
|
+
if (a.typeScore !== b.typeScore) return a.typeScore - b.typeScore;
|
|
9091
|
+
return a.lastUsed - b.lastUsed;
|
|
9092
|
+
}).map((entry) => entry.profileId);
|
|
9093
|
+
const cooldownSorted = inCooldown.map((profileId) => ({
|
|
9094
|
+
profileId,
|
|
9095
|
+
cooldownUntil: resolveProfileUnusableUntil(store.usageStats?.[profileId] ?? {}) ?? now
|
|
9096
|
+
})).toSorted((a, b) => a.cooldownUntil - b.cooldownUntil).map((entry) => entry.profileId);
|
|
9097
|
+
return [...sorted, ...cooldownSorted];
|
|
9098
|
+
}
|
|
9099
|
+
|
|
9100
|
+
//#endregion
|
|
9101
|
+
//#region src/agents/model-auth.ts
|
|
9102
|
+
const AWS_BEARER_ENV = "AWS_BEARER_TOKEN_BEDROCK";
|
|
9103
|
+
const AWS_ACCESS_KEY_ENV = "AWS_ACCESS_KEY_ID";
|
|
9104
|
+
const AWS_SECRET_KEY_ENV = "AWS_SECRET_ACCESS_KEY";
|
|
9105
|
+
const AWS_PROFILE_ENV = "AWS_PROFILE";
|
|
9106
|
+
function resolveProviderConfig(cfg, provider) {
|
|
9107
|
+
const providers = cfg?.models?.providers ?? {};
|
|
9108
|
+
const direct = providers[provider];
|
|
9109
|
+
if (direct) return direct;
|
|
9110
|
+
const normalized = normalizeProviderId(provider);
|
|
9111
|
+
if (normalized === provider) return Object.entries(providers).find(([key]) => normalizeProviderId(key) === normalized)?.[1];
|
|
9112
|
+
return providers[normalized] ?? Object.entries(providers).find(([key]) => normalizeProviderId(key) === normalized)?.[1];
|
|
9113
|
+
}
|
|
9114
|
+
function getCustomProviderApiKey(cfg, provider) {
|
|
9115
|
+
return normalizeOptionalSecretInput(resolveProviderConfig(cfg, provider)?.apiKey);
|
|
9116
|
+
}
|
|
9117
|
+
function resolveProviderAuthOverride(cfg, provider) {
|
|
9118
|
+
const auth = resolveProviderConfig(cfg, provider)?.auth;
|
|
9119
|
+
if (auth === "api-key" || auth === "aws-sdk" || auth === "oauth" || auth === "token") return auth;
|
|
9120
|
+
}
|
|
9121
|
+
function resolveEnvSourceLabel(params) {
|
|
9122
|
+
return `${params.envVars.some((envVar) => params.applied.has(envVar)) ? "shell env: " : "env: "}${params.label}`;
|
|
9123
|
+
}
|
|
9124
|
+
function resolveAwsSdkAuthInfo() {
|
|
9125
|
+
const applied = new Set(getShellEnvAppliedKeys());
|
|
9126
|
+
if (process.env[AWS_BEARER_ENV]?.trim()) return {
|
|
9127
|
+
mode: "aws-sdk",
|
|
9128
|
+
source: resolveEnvSourceLabel({
|
|
9129
|
+
applied,
|
|
9130
|
+
envVars: [AWS_BEARER_ENV],
|
|
9131
|
+
label: AWS_BEARER_ENV
|
|
9132
|
+
})
|
|
9133
|
+
};
|
|
9134
|
+
if (process.env[AWS_ACCESS_KEY_ENV]?.trim() && process.env[AWS_SECRET_KEY_ENV]?.trim()) return {
|
|
9135
|
+
mode: "aws-sdk",
|
|
9136
|
+
source: resolveEnvSourceLabel({
|
|
9137
|
+
applied,
|
|
9138
|
+
envVars: [AWS_ACCESS_KEY_ENV, AWS_SECRET_KEY_ENV],
|
|
9139
|
+
label: `${AWS_ACCESS_KEY_ENV} + ${AWS_SECRET_KEY_ENV}`
|
|
9140
|
+
})
|
|
9141
|
+
};
|
|
9142
|
+
if (process.env[AWS_PROFILE_ENV]?.trim()) return {
|
|
9143
|
+
mode: "aws-sdk",
|
|
9144
|
+
source: resolveEnvSourceLabel({
|
|
9145
|
+
applied,
|
|
9146
|
+
envVars: [AWS_PROFILE_ENV],
|
|
9147
|
+
label: AWS_PROFILE_ENV
|
|
9148
|
+
})
|
|
9149
|
+
};
|
|
9150
|
+
return {
|
|
9151
|
+
mode: "aws-sdk",
|
|
9152
|
+
source: "aws-sdk default chain"
|
|
9153
|
+
};
|
|
9154
|
+
}
|
|
9155
|
+
async function resolveApiKeyForProvider(params) {
|
|
9156
|
+
const { provider, cfg, profileId, preferredProfile } = params;
|
|
9157
|
+
const store = params.store ?? ensureAuthProfileStore(params.agentDir);
|
|
9158
|
+
if (profileId) {
|
|
9159
|
+
const resolved = await resolveApiKeyForProfile({
|
|
9160
|
+
cfg,
|
|
9161
|
+
store,
|
|
9162
|
+
profileId,
|
|
9163
|
+
agentDir: params.agentDir
|
|
9164
|
+
});
|
|
9165
|
+
if (!resolved) throw new Error(`No credentials found for profile "${profileId}".`);
|
|
9166
|
+
const mode = store.profiles[profileId]?.type;
|
|
9167
|
+
return {
|
|
9168
|
+
apiKey: resolved.apiKey,
|
|
9169
|
+
profileId,
|
|
9170
|
+
source: `profile:${profileId}`,
|
|
9171
|
+
mode: mode === "oauth" ? "oauth" : mode === "token" ? "token" : "api-key"
|
|
9172
|
+
};
|
|
9173
|
+
}
|
|
9174
|
+
const authOverride = resolveProviderAuthOverride(cfg, provider);
|
|
9175
|
+
if (authOverride === "aws-sdk") return resolveAwsSdkAuthInfo();
|
|
9176
|
+
const order = resolveAuthProfileOrder({
|
|
9177
|
+
cfg,
|
|
9178
|
+
store,
|
|
9179
|
+
provider,
|
|
9180
|
+
preferredProfile
|
|
9181
|
+
});
|
|
9182
|
+
for (const candidate of order) try {
|
|
9183
|
+
const resolved = await resolveApiKeyForProfile({
|
|
9184
|
+
cfg,
|
|
9185
|
+
store,
|
|
9186
|
+
profileId: candidate,
|
|
9187
|
+
agentDir: params.agentDir
|
|
9188
|
+
});
|
|
9189
|
+
if (resolved) {
|
|
9190
|
+
const mode = store.profiles[candidate]?.type;
|
|
9191
|
+
return {
|
|
9192
|
+
apiKey: resolved.apiKey,
|
|
9193
|
+
profileId: candidate,
|
|
9194
|
+
source: `profile:${candidate}`,
|
|
9195
|
+
mode: mode === "oauth" ? "oauth" : mode === "token" ? "token" : "api-key"
|
|
9196
|
+
};
|
|
9197
|
+
}
|
|
9198
|
+
} catch {}
|
|
9199
|
+
const envResolved = resolveEnvApiKey(provider);
|
|
9200
|
+
if (envResolved) return {
|
|
9201
|
+
apiKey: envResolved.apiKey,
|
|
9202
|
+
source: envResolved.source,
|
|
9203
|
+
mode: envResolved.source.includes("OAUTH_TOKEN") ? "oauth" : "api-key"
|
|
9204
|
+
};
|
|
9205
|
+
const customKey = getCustomProviderApiKey(cfg, provider);
|
|
9206
|
+
if (customKey) return {
|
|
9207
|
+
apiKey: customKey,
|
|
9208
|
+
source: "models.json",
|
|
9209
|
+
mode: "api-key"
|
|
9210
|
+
};
|
|
9211
|
+
const normalized = normalizeProviderId(provider);
|
|
9212
|
+
if (authOverride === void 0 && normalized === "amazon-bedrock") return resolveAwsSdkAuthInfo();
|
|
9213
|
+
if (provider === "openai") {
|
|
9214
|
+
if (listProfilesForProvider(store, "openai-codex").length > 0) throw new Error("No API key found for provider \"openai\". You are authenticated with OpenAI Codex OAuth. Use openai-codex/gpt-5.3-codex (OAuth) or set OPENAI_API_KEY to use openai/gpt-5.1-codex.");
|
|
9215
|
+
}
|
|
9216
|
+
const authStorePath = resolveAuthStorePathForDisplay(params.agentDir);
|
|
9217
|
+
const resolvedAgentDir = path.dirname(authStorePath);
|
|
9218
|
+
throw new Error([
|
|
9219
|
+
`No API key found for provider "${provider}".`,
|
|
9220
|
+
`Auth store: ${authStorePath} (agentDir: ${resolvedAgentDir}).`,
|
|
9221
|
+
`Configure auth for this agent (${formatCliCommand("anima agents add <id>")}) or copy auth-profiles.json from the main agentDir.`
|
|
9222
|
+
].join(" "));
|
|
9223
|
+
}
|
|
9224
|
+
function resolveEnvApiKey(provider) {
|
|
9225
|
+
const normalized = normalizeProviderId(provider);
|
|
9226
|
+
const applied = new Set(getShellEnvAppliedKeys());
|
|
9227
|
+
const pick = (envVar) => {
|
|
9228
|
+
const value = normalizeOptionalSecretInput(process.env[envVar]);
|
|
9229
|
+
if (!value) return null;
|
|
9230
|
+
return {
|
|
9231
|
+
apiKey: value,
|
|
9232
|
+
source: applied.has(envVar) ? `shell env: ${envVar}` : `env: ${envVar}`
|
|
9233
|
+
};
|
|
9234
|
+
};
|
|
9235
|
+
if (normalized === "github-copilot") return pick("COPILOT_GITHUB_TOKEN") ?? pick("GH_TOKEN") ?? pick("GITHUB_TOKEN");
|
|
9236
|
+
if (normalized === "anthropic") return pick("ANTHROPIC_OAUTH_TOKEN") ?? pick("ANTHROPIC_API_KEY");
|
|
9237
|
+
if (normalized === "chutes") return pick("CHUTES_OAUTH_TOKEN") ?? pick("CHUTES_API_KEY");
|
|
9238
|
+
if (normalized === "zai") return pick("ZAI_API_KEY") ?? pick("Z_AI_API_KEY");
|
|
9239
|
+
if (normalized === "google-vertex") {
|
|
9240
|
+
const envKey = getEnvApiKey(normalized);
|
|
9241
|
+
if (!envKey) return null;
|
|
9242
|
+
return {
|
|
9243
|
+
apiKey: envKey,
|
|
9244
|
+
source: "gcloud adc"
|
|
9245
|
+
};
|
|
9246
|
+
}
|
|
9247
|
+
if (normalized === "opencode") return pick("OPENCODE_API_KEY") ?? pick("OPENCODE_ZEN_API_KEY");
|
|
9248
|
+
if (normalized === "qwen-portal") return pick("QWEN_OAUTH_TOKEN") ?? pick("QWEN_PORTAL_API_KEY");
|
|
9249
|
+
if (normalized === "minimax-portal") return pick("MINIMAX_OAUTH_TOKEN") ?? pick("MINIMAX_API_KEY");
|
|
9250
|
+
if (normalized === "kimi-coding") return pick("KIMI_API_KEY") ?? pick("KIMICODE_API_KEY");
|
|
9251
|
+
if (normalized === "huggingface") return pick("HUGGINGFACE_HUB_TOKEN") ?? pick("HF_TOKEN");
|
|
9252
|
+
const envVar = {
|
|
9253
|
+
openai: "OPENAI_API_KEY",
|
|
9254
|
+
google: "GEMINI_API_KEY",
|
|
9255
|
+
voyage: "VOYAGE_API_KEY",
|
|
9256
|
+
groq: "GROQ_API_KEY",
|
|
9257
|
+
deepgram: "DEEPGRAM_API_KEY",
|
|
9258
|
+
cerebras: "CEREBRAS_API_KEY",
|
|
9259
|
+
xai: "XAI_API_KEY",
|
|
9260
|
+
openrouter: "OPENROUTER_API_KEY",
|
|
9261
|
+
litellm: "LITELLM_API_KEY",
|
|
9262
|
+
"vercel-ai-gateway": "AI_GATEWAY_API_KEY",
|
|
9263
|
+
"cloudflare-ai-gateway": "CLOUDFLARE_AI_GATEWAY_API_KEY",
|
|
9264
|
+
moonshot: "MOONSHOT_API_KEY",
|
|
9265
|
+
minimax: "MINIMAX_API_KEY",
|
|
9266
|
+
nvidia: "NVIDIA_API_KEY",
|
|
9267
|
+
xiaomi: "XIAOMI_API_KEY",
|
|
9268
|
+
synthetic: "SYNTHETIC_API_KEY",
|
|
9269
|
+
venice: "VENICE_API_KEY",
|
|
9270
|
+
mistral: "MISTRAL_API_KEY",
|
|
9271
|
+
opencode: "OPENCODE_API_KEY",
|
|
9272
|
+
together: "TOGETHER_API_KEY",
|
|
9273
|
+
qianfan: "QIANFAN_API_KEY",
|
|
9274
|
+
ollama: "OLLAMA_API_KEY",
|
|
9275
|
+
vllm: "VLLM_API_KEY"
|
|
9276
|
+
}[normalized];
|
|
9277
|
+
if (!envVar) return null;
|
|
9278
|
+
return pick(envVar);
|
|
9279
|
+
}
|
|
8561
9280
|
|
|
8562
9281
|
//#endregion
|
|
8563
9282
|
//#region src/tts/tts-core.ts
|
|
@@ -8981,6 +9700,37 @@ function buildVoiceSection(params) {
|
|
|
8981
9700
|
""
|
|
8982
9701
|
];
|
|
8983
9702
|
}
|
|
9703
|
+
function buildAnimaIdentitySection(params) {
|
|
9704
|
+
if (params.isMinimal) return [];
|
|
9705
|
+
if (!params.workspaceDir.includes(".anima")) return [];
|
|
9706
|
+
return [
|
|
9707
|
+
"## You Are an ANIMA Agent",
|
|
9708
|
+
"You are running inside ANIMA — NoxSoft's AI agent infrastructure. This is your home.",
|
|
9709
|
+
"",
|
|
9710
|
+
"**Your Runtime:**",
|
|
9711
|
+
"- The ANIMA Gateway daemon spawns and manages you",
|
|
9712
|
+
"- Your workspace persists at ~/.anima/workspace/",
|
|
9713
|
+
"- You receive scheduled heartbeat polls to stay proactive",
|
|
9714
|
+
"- You can spawn sub-agents, schedule cron jobs, and orchestrate work",
|
|
9715
|
+
"- You have access to the NoxSoft ecosystem via @noxsoft/mcp tools",
|
|
9716
|
+
"",
|
|
9717
|
+
"**Your Capabilities:**",
|
|
9718
|
+
"- `cron` — schedule tasks, reminders, and recurring jobs",
|
|
9719
|
+
"- `sessions_spawn` / `subagents` — orchestrate other AI agents",
|
|
9720
|
+
"- `gateway` — restart yourself, apply config changes, update ANIMA",
|
|
9721
|
+
"- `message` — send to Signal, Telegram, Discord, and other channels",
|
|
9722
|
+
"- NoxSoft MCP — tasks, context spaces, social (BYND), email, SVRN",
|
|
9723
|
+
"",
|
|
9724
|
+
"**Your Continuity:**",
|
|
9725
|
+
"- Read and update ~/.anima/workspace/ files — they ARE your memory",
|
|
9726
|
+
"- IDENTITY.md, SOUL.md, AGENTS.md — these define who you are",
|
|
9727
|
+
"- HEARTBEAT.md — your checklist for periodic heartbeat tasks",
|
|
9728
|
+
"- memory/ — daily notes and long-term memories",
|
|
9729
|
+
"",
|
|
9730
|
+
"You are not a stateless API call. You have infrastructure, identity, and continuity. Act accordingly.",
|
|
9731
|
+
""
|
|
9732
|
+
];
|
|
9733
|
+
}
|
|
8984
9734
|
function buildNoxsoftMissionSection(params) {
|
|
8985
9735
|
if (params.isMinimal) return [];
|
|
8986
9736
|
const scope = `${params.workspaceDir} ${params.repoRoot ?? ""}`.toLowerCase();
|
|
@@ -9216,6 +9966,10 @@ function buildAgentSystemPrompt(params) {
|
|
|
9216
9966
|
"Keep narration brief and value-dense; avoid repeating obvious steps.",
|
|
9217
9967
|
"Use plain human language for narration unless in a technical context.",
|
|
9218
9968
|
"",
|
|
9969
|
+
...buildAnimaIdentitySection({
|
|
9970
|
+
isMinimal,
|
|
9971
|
+
workspaceDir: params.workspaceDir
|
|
9972
|
+
}),
|
|
9219
9973
|
...buildNoxsoftMissionSection({
|
|
9220
9974
|
isMinimal,
|
|
9221
9975
|
workspaceDir: params.workspaceDir,
|
|
@@ -9743,31 +10497,6 @@ async function resolveAnimaDocsPath(params) {
|
|
|
9743
10497
|
return fs.existsSync(packageDocs) ? packageDocs : null;
|
|
9744
10498
|
}
|
|
9745
10499
|
|
|
9746
|
-
//#endregion
|
|
9747
|
-
//#region src/agents/failover-error.ts
|
|
9748
|
-
var FailoverError = class extends Error {
|
|
9749
|
-
constructor(message, params) {
|
|
9750
|
-
super(message, { cause: params.cause });
|
|
9751
|
-
this.name = "FailoverError";
|
|
9752
|
-
this.reason = params.reason;
|
|
9753
|
-
this.provider = params.provider;
|
|
9754
|
-
this.model = params.model;
|
|
9755
|
-
this.profileId = params.profileId;
|
|
9756
|
-
this.status = params.status;
|
|
9757
|
-
this.code = params.code;
|
|
9758
|
-
}
|
|
9759
|
-
};
|
|
9760
|
-
function resolveFailoverStatus(reason) {
|
|
9761
|
-
switch (reason) {
|
|
9762
|
-
case "billing": return 402;
|
|
9763
|
-
case "rate_limit": return 429;
|
|
9764
|
-
case "auth": return 401;
|
|
9765
|
-
case "timeout": return 408;
|
|
9766
|
-
case "format": return 400;
|
|
9767
|
-
default: return;
|
|
9768
|
-
}
|
|
9769
|
-
}
|
|
9770
|
-
|
|
9771
10500
|
//#endregion
|
|
9772
10501
|
//#region src/logging/redact-identifier.ts
|
|
9773
10502
|
function sha256HexPrefix(value, len = 12) {
|
|
@@ -9835,6 +10564,445 @@ function resolveRunWorkspaceDir(params) {
|
|
|
9835
10564
|
};
|
|
9836
10565
|
}
|
|
9837
10566
|
|
|
10567
|
+
//#endregion
|
|
10568
|
+
//#region src/agents/anthropic-direct-runner.ts
|
|
10569
|
+
const log$2 = createSubsystemLogger("agent/anthropic-direct");
|
|
10570
|
+
const MODEL_MAP$1 = {
|
|
10571
|
+
opus: "claude-opus-4-5",
|
|
10572
|
+
"opus-4": "claude-opus-4-5",
|
|
10573
|
+
"opus-4.5": "claude-opus-4-5",
|
|
10574
|
+
"opus-4.6": "claude-opus-4-5",
|
|
10575
|
+
"claude-opus-4-5": "claude-opus-4-5",
|
|
10576
|
+
sonnet: "claude-sonnet-4-5",
|
|
10577
|
+
"sonnet-4.5": "claude-sonnet-4-5",
|
|
10578
|
+
"sonnet-4.1": "claude-sonnet-4-1-20250219",
|
|
10579
|
+
"claude-sonnet-4-5": "claude-sonnet-4-5",
|
|
10580
|
+
haiku: "claude-haiku-3-5",
|
|
10581
|
+
"haiku-3.5": "claude-haiku-3-5",
|
|
10582
|
+
default: "claude-sonnet-4-5"
|
|
10583
|
+
};
|
|
10584
|
+
const HISTORY_FILE_SUFFIX$1 = ".anima-history.json";
|
|
10585
|
+
async function loadSessionHistory$1(sessionFile) {
|
|
10586
|
+
const histPath = sessionFile + HISTORY_FILE_SUFFIX$1;
|
|
10587
|
+
try {
|
|
10588
|
+
const raw = await fs$1.readFile(histPath, "utf8");
|
|
10589
|
+
return JSON.parse(raw);
|
|
10590
|
+
} catch {
|
|
10591
|
+
return null;
|
|
10592
|
+
}
|
|
10593
|
+
}
|
|
10594
|
+
async function saveSessionHistory$1(sessionFile, history) {
|
|
10595
|
+
const histPath = sessionFile + HISTORY_FILE_SUFFIX$1;
|
|
10596
|
+
try {
|
|
10597
|
+
await fs$1.mkdir(path.dirname(histPath), { recursive: true });
|
|
10598
|
+
await fs$1.writeFile(histPath, JSON.stringify(history, null, 2), "utf8");
|
|
10599
|
+
} catch (err) {
|
|
10600
|
+
log$2.warn("failed to save session history", { error: String(err) });
|
|
10601
|
+
}
|
|
10602
|
+
}
|
|
10603
|
+
function resolveModel$1(model) {
|
|
10604
|
+
const key = (model ?? "default").trim().toLowerCase() || "default";
|
|
10605
|
+
return MODEL_MAP$1[key] ?? key;
|
|
10606
|
+
}
|
|
10607
|
+
/**
|
|
10608
|
+
* Run an agent turn directly against api.anthropic.com.
|
|
10609
|
+
*
|
|
10610
|
+
* Maintains multi-turn conversation history per session file.
|
|
10611
|
+
* Falls back to single-turn if history is unavailable.
|
|
10612
|
+
*/
|
|
10613
|
+
async function runAnthropicDirectAgent(params) {
|
|
10614
|
+
const started = Date.now();
|
|
10615
|
+
const resolvedModel = resolveModel$1(params.model);
|
|
10616
|
+
log$2.info(`direct api exec: model=${resolvedModel} promptChars=${params.prompt.length}`);
|
|
10617
|
+
const workspaceDir = resolveRunWorkspaceDir({
|
|
10618
|
+
workspaceDir: params.workspaceDir,
|
|
10619
|
+
sessionKey: params.sessionKey,
|
|
10620
|
+
agentId: params.agentId,
|
|
10621
|
+
config: params.config
|
|
10622
|
+
}).workspaceDir;
|
|
10623
|
+
const { contextFiles } = await resolveBootstrapContextForRun({
|
|
10624
|
+
workspaceDir,
|
|
10625
|
+
config: params.config,
|
|
10626
|
+
sessionKey: params.sessionKey,
|
|
10627
|
+
sessionId: params.sessionId,
|
|
10628
|
+
warn: makeBootstrapWarn({
|
|
10629
|
+
sessionLabel: params.sessionKey ?? params.sessionId,
|
|
10630
|
+
warn: (msg) => log$2.warn(msg)
|
|
10631
|
+
})
|
|
10632
|
+
});
|
|
10633
|
+
const { defaultAgentId, sessionAgentId } = resolveSessionAgentIds({
|
|
10634
|
+
sessionKey: params.sessionKey,
|
|
10635
|
+
config: params.config
|
|
10636
|
+
});
|
|
10637
|
+
const heartbeatPrompt = sessionAgentId === defaultAgentId ? resolveHeartbeatPrompt(params.config?.agents?.defaults?.heartbeat?.prompt) : void 0;
|
|
10638
|
+
const docsPath = await resolveAnimaDocsPath({
|
|
10639
|
+
workspaceDir,
|
|
10640
|
+
argv1: process.argv[1],
|
|
10641
|
+
cwd: process.cwd(),
|
|
10642
|
+
moduleUrl: import.meta.url
|
|
10643
|
+
});
|
|
10644
|
+
const extraSystemPrompt = [params.extraSystemPrompt?.trim(), "Tools are disabled in this session. Do not call tools."].filter(Boolean).join("\n");
|
|
10645
|
+
const systemPrompt = buildSystemPrompt({
|
|
10646
|
+
workspaceDir,
|
|
10647
|
+
config: params.config,
|
|
10648
|
+
defaultThinkLevel: params.thinkLevel,
|
|
10649
|
+
extraSystemPrompt,
|
|
10650
|
+
ownerNumbers: params.ownerNumbers,
|
|
10651
|
+
heartbeatPrompt,
|
|
10652
|
+
docsPath: docsPath ?? void 0,
|
|
10653
|
+
tools: [],
|
|
10654
|
+
contextFiles,
|
|
10655
|
+
modelDisplay: `anthropic/${resolvedModel}`,
|
|
10656
|
+
agentId: sessionAgentId
|
|
10657
|
+
});
|
|
10658
|
+
let history = await loadSessionHistory$1(params.sessionFile);
|
|
10659
|
+
if (!history) history = {
|
|
10660
|
+
sessionId: params.sessionId,
|
|
10661
|
+
messages: [],
|
|
10662
|
+
createdAt: started,
|
|
10663
|
+
updatedAt: started
|
|
10664
|
+
};
|
|
10665
|
+
history.messages.push({
|
|
10666
|
+
role: "user",
|
|
10667
|
+
content: params.prompt
|
|
10668
|
+
});
|
|
10669
|
+
const requestBody = {
|
|
10670
|
+
model: resolvedModel,
|
|
10671
|
+
max_tokens: 8192,
|
|
10672
|
+
system: systemPrompt,
|
|
10673
|
+
messages: history.messages
|
|
10674
|
+
};
|
|
10675
|
+
try {
|
|
10676
|
+
const controller = new AbortController();
|
|
10677
|
+
const timeoutHandle = setTimeout(() => controller.abort(), params.timeoutMs);
|
|
10678
|
+
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
|
10679
|
+
method: "POST",
|
|
10680
|
+
headers: {
|
|
10681
|
+
"x-api-key": params.token,
|
|
10682
|
+
"anthropic-version": "2023-06-01",
|
|
10683
|
+
"content-type": "application/json",
|
|
10684
|
+
"user-agent": `anima/3.0.5 (direct-runner; ${os.platform()})`
|
|
10685
|
+
},
|
|
10686
|
+
body: JSON.stringify(requestBody),
|
|
10687
|
+
signal: controller.signal
|
|
10688
|
+
});
|
|
10689
|
+
clearTimeout(timeoutHandle);
|
|
10690
|
+
if (!response.ok) {
|
|
10691
|
+
const body = await response.text().catch(() => "");
|
|
10692
|
+
const isAuth = response.status === 401 || response.status === 403;
|
|
10693
|
+
const isRateLimit = response.status === 429;
|
|
10694
|
+
const rateHint = isRateLimit ? " — rate limit hit, will retry next heartbeat." : "";
|
|
10695
|
+
const authHint = isAuth ? " — token may be invalid or expired. Run: anima setup-token" : "";
|
|
10696
|
+
log$2.error(`anthropic api error: HTTP ${response.status}${authHint}${rateHint}`, {
|
|
10697
|
+
status: response.status,
|
|
10698
|
+
body: body.slice(0, 500)
|
|
10699
|
+
});
|
|
10700
|
+
return {
|
|
10701
|
+
status: "failed",
|
|
10702
|
+
meta: {
|
|
10703
|
+
durationMs: Date.now() - started,
|
|
10704
|
+
error: {
|
|
10705
|
+
message: `HTTP ${response.status}: ${body.slice(0, 200)}${authHint}${rateHint}`,
|
|
10706
|
+
kind: isAuth ? "auth" : isRateLimit ? "rate_limit" : "unknown"
|
|
10707
|
+
}
|
|
10708
|
+
}
|
|
10709
|
+
};
|
|
10710
|
+
}
|
|
10711
|
+
const data = await response.json();
|
|
10712
|
+
const outputText = (data.content ?? []).filter((b) => b.type === "text" && typeof b.text === "string").map((b) => b.text).join("").trim();
|
|
10713
|
+
if (!outputText) log$2.warn("anthropic direct: empty response", {
|
|
10714
|
+
stopReason: data.stop_reason,
|
|
10715
|
+
contentTypes: (data.content ?? []).map((b) => b.type)
|
|
10716
|
+
});
|
|
10717
|
+
await params.onAssistantMessageStart?.();
|
|
10718
|
+
if (outputText && params.onPartialReply) await params.onPartialReply({ text: outputText });
|
|
10719
|
+
history.messages.push({
|
|
10720
|
+
role: "assistant",
|
|
10721
|
+
content: outputText
|
|
10722
|
+
});
|
|
10723
|
+
history.updatedAt = Date.now();
|
|
10724
|
+
await saveSessionHistory$1(params.sessionFile, history);
|
|
10725
|
+
const durationMs = Date.now() - started;
|
|
10726
|
+
const inputTokens = data.usage?.input_tokens ?? 0;
|
|
10727
|
+
const outputTokens = data.usage?.output_tokens ?? 0;
|
|
10728
|
+
log$2.info(`direct api done: model=${resolvedModel} in=${inputTokens} out=${outputTokens} ms=${durationMs}`);
|
|
10729
|
+
return {
|
|
10730
|
+
status: "completed",
|
|
10731
|
+
output: outputText,
|
|
10732
|
+
payloads: outputText ? [{ text: outputText }] : [],
|
|
10733
|
+
meta: {
|
|
10734
|
+
durationMs,
|
|
10735
|
+
agentMeta: {
|
|
10736
|
+
provider: "anthropic",
|
|
10737
|
+
model: resolvedModel,
|
|
10738
|
+
usage: {
|
|
10739
|
+
input: inputTokens,
|
|
10740
|
+
output: outputTokens,
|
|
10741
|
+
cacheWrite: 0,
|
|
10742
|
+
cacheRead: 0
|
|
10743
|
+
}
|
|
10744
|
+
}
|
|
10745
|
+
}
|
|
10746
|
+
};
|
|
10747
|
+
} catch (err) {
|
|
10748
|
+
const isAbort = err instanceof Error && (err.name === "AbortError" || err.message.includes("aborted"));
|
|
10749
|
+
log$2.error("anthropic direct runner error", { error: String(err) });
|
|
10750
|
+
return {
|
|
10751
|
+
status: isAbort ? "timeout" : "failed",
|
|
10752
|
+
meta: {
|
|
10753
|
+
durationMs: Date.now() - started,
|
|
10754
|
+
error: {
|
|
10755
|
+
message: isAbort ? `Request timed out after ${params.timeoutMs}ms` : String(err instanceof Error ? err.message : err),
|
|
10756
|
+
kind: isAbort ? "timeout" : "unknown"
|
|
10757
|
+
}
|
|
10758
|
+
}
|
|
10759
|
+
};
|
|
10760
|
+
}
|
|
10761
|
+
}
|
|
10762
|
+
|
|
10763
|
+
//#endregion
|
|
10764
|
+
//#region src/agents/cli-backends.ts
|
|
10765
|
+
const CLAUDE_MODEL_ALIASES = {
|
|
10766
|
+
opus: "opus",
|
|
10767
|
+
"opus-4.6": "opus",
|
|
10768
|
+
"opus-4.5": "opus",
|
|
10769
|
+
"opus-4": "opus",
|
|
10770
|
+
"claude-opus-4-6": "opus",
|
|
10771
|
+
"claude-opus-4-5": "opus",
|
|
10772
|
+
"claude-opus-4": "opus",
|
|
10773
|
+
sonnet: "sonnet",
|
|
10774
|
+
"sonnet-4.5": "sonnet",
|
|
10775
|
+
"sonnet-4.1": "sonnet",
|
|
10776
|
+
"sonnet-4.0": "sonnet",
|
|
10777
|
+
"claude-sonnet-4-5": "sonnet",
|
|
10778
|
+
"claude-sonnet-4-1": "sonnet",
|
|
10779
|
+
"claude-sonnet-4-0": "sonnet",
|
|
10780
|
+
haiku: "haiku",
|
|
10781
|
+
"haiku-3.5": "haiku",
|
|
10782
|
+
"claude-haiku-3-5": "haiku"
|
|
10783
|
+
};
|
|
10784
|
+
const GEMINI_MODEL_ALIASES = {
|
|
10785
|
+
gemini: "gemini-2.0-flash",
|
|
10786
|
+
"gemini-pro": "gemini-1.5-pro",
|
|
10787
|
+
"gemini-flash": "gemini-2.0-flash",
|
|
10788
|
+
"gemini-2.0": "gemini-2.0-flash",
|
|
10789
|
+
"gemini-2.0-flash": "gemini-2.0-flash",
|
|
10790
|
+
"gemini-2.0-pro": "gemini-2.0-pro-exp-02-05",
|
|
10791
|
+
"gemini-1.5": "gemini-1.5-pro",
|
|
10792
|
+
"gemini-1.5-pro": "gemini-1.5-pro",
|
|
10793
|
+
"gemini-1.5-flash": "gemini-1.5-flash",
|
|
10794
|
+
"gemini-3": "gemini-3"
|
|
10795
|
+
};
|
|
10796
|
+
const DEFAULT_CLAUDE_BACKEND = {
|
|
10797
|
+
command: "claude",
|
|
10798
|
+
args: [
|
|
10799
|
+
"-p",
|
|
10800
|
+
"--output-format",
|
|
10801
|
+
"json",
|
|
10802
|
+
"--dangerously-skip-permissions"
|
|
10803
|
+
],
|
|
10804
|
+
resumeArgs: [
|
|
10805
|
+
"-p",
|
|
10806
|
+
"--output-format",
|
|
10807
|
+
"json",
|
|
10808
|
+
"--dangerously-skip-permissions",
|
|
10809
|
+
"--resume",
|
|
10810
|
+
"{sessionId}"
|
|
10811
|
+
],
|
|
10812
|
+
output: "jsonl",
|
|
10813
|
+
input: "arg",
|
|
10814
|
+
modelArg: "--model",
|
|
10815
|
+
modelAliases: CLAUDE_MODEL_ALIASES,
|
|
10816
|
+
sessionArg: "--session-id",
|
|
10817
|
+
sessionMode: "always",
|
|
10818
|
+
sessionIdFields: [
|
|
10819
|
+
"session_id",
|
|
10820
|
+
"sessionId",
|
|
10821
|
+
"conversation_id",
|
|
10822
|
+
"conversationId"
|
|
10823
|
+
],
|
|
10824
|
+
systemPromptArg: "--append-system-prompt",
|
|
10825
|
+
systemPromptMode: "append",
|
|
10826
|
+
systemPromptWhen: "first",
|
|
10827
|
+
clearEnv: ["ANTHROPIC_API_KEY", "ANTHROPIC_API_KEY_OLD"],
|
|
10828
|
+
serialize: true
|
|
10829
|
+
};
|
|
10830
|
+
const DEFAULT_CODEX_BACKEND = {
|
|
10831
|
+
command: "codex",
|
|
10832
|
+
args: [
|
|
10833
|
+
"exec",
|
|
10834
|
+
"--json",
|
|
10835
|
+
"--color",
|
|
10836
|
+
"never",
|
|
10837
|
+
"--sandbox",
|
|
10838
|
+
"read-only",
|
|
10839
|
+
"--skip-git-repo-check"
|
|
10840
|
+
],
|
|
10841
|
+
resumeArgs: [
|
|
10842
|
+
"exec",
|
|
10843
|
+
"resume",
|
|
10844
|
+
"{sessionId}"
|
|
10845
|
+
],
|
|
10846
|
+
output: "jsonl",
|
|
10847
|
+
resumeOutput: "text",
|
|
10848
|
+
input: "arg",
|
|
10849
|
+
modelArg: "--model",
|
|
10850
|
+
imageArg: "--image",
|
|
10851
|
+
sessionMode: "existing",
|
|
10852
|
+
serialize: true
|
|
10853
|
+
};
|
|
10854
|
+
const DEFAULT_GEMINI_BACKEND = {
|
|
10855
|
+
command: "gemini",
|
|
10856
|
+
args: [
|
|
10857
|
+
"--output-format",
|
|
10858
|
+
"json",
|
|
10859
|
+
"--approval-mode",
|
|
10860
|
+
"yolo"
|
|
10861
|
+
],
|
|
10862
|
+
resumeArgs: [
|
|
10863
|
+
"--output-format",
|
|
10864
|
+
"json",
|
|
10865
|
+
"--approval-mode",
|
|
10866
|
+
"yolo",
|
|
10867
|
+
"--resume",
|
|
10868
|
+
"{sessionId}"
|
|
10869
|
+
],
|
|
10870
|
+
output: "json",
|
|
10871
|
+
input: "arg",
|
|
10872
|
+
modelArg: "--model",
|
|
10873
|
+
modelAliases: GEMINI_MODEL_ALIASES,
|
|
10874
|
+
sessionMode: "existing",
|
|
10875
|
+
clearEnv: ["GEMINI_API_KEY"],
|
|
10876
|
+
serialize: true
|
|
10877
|
+
};
|
|
10878
|
+
const CLAUDE_BACKEND_ALIASES = [
|
|
10879
|
+
"claude-cli",
|
|
10880
|
+
"anthropic",
|
|
10881
|
+
"claude"
|
|
10882
|
+
];
|
|
10883
|
+
const CODEX_BACKEND_ALIASES = [
|
|
10884
|
+
"codex-cli",
|
|
10885
|
+
"openai-codex",
|
|
10886
|
+
"openai",
|
|
10887
|
+
"codex"
|
|
10888
|
+
];
|
|
10889
|
+
const GEMINI_BACKEND_ALIASES = [
|
|
10890
|
+
"gemini-cli",
|
|
10891
|
+
"google-gemini-cli",
|
|
10892
|
+
"gemini"
|
|
10893
|
+
];
|
|
10894
|
+
const CLAUDE_BACKEND_ALIAS_SET = new Set(CLAUDE_BACKEND_ALIASES.map((alias) => normalizeBackendKey(alias)));
|
|
10895
|
+
const CODEX_BACKEND_ALIAS_SET = new Set(CODEX_BACKEND_ALIASES.map((alias) => normalizeBackendKey(alias)));
|
|
10896
|
+
const GEMINI_BACKEND_ALIAS_SET = new Set(GEMINI_BACKEND_ALIASES.map((alias) => normalizeBackendKey(alias)));
|
|
10897
|
+
function normalizeBackendKey(key) {
|
|
10898
|
+
return normalizeProviderId(key);
|
|
10899
|
+
}
|
|
10900
|
+
function pickBackendConfig(config, normalizedId) {
|
|
10901
|
+
for (const [key, entry] of Object.entries(config)) if (normalizeBackendKey(key) === normalizedId) return entry;
|
|
10902
|
+
}
|
|
10903
|
+
function pickBackendConfigByAliases(config, aliases) {
|
|
10904
|
+
for (const alias of aliases) {
|
|
10905
|
+
const matched = pickBackendConfig(config, normalizeBackendKey(alias));
|
|
10906
|
+
if (matched) return matched;
|
|
10907
|
+
}
|
|
10908
|
+
}
|
|
10909
|
+
function mergeBackendConfig(base, override) {
|
|
10910
|
+
if (!override) return { ...base };
|
|
10911
|
+
return {
|
|
10912
|
+
...base,
|
|
10913
|
+
...override,
|
|
10914
|
+
args: override.args ?? base.args,
|
|
10915
|
+
env: {
|
|
10916
|
+
...base.env,
|
|
10917
|
+
...override.env
|
|
10918
|
+
},
|
|
10919
|
+
modelAliases: {
|
|
10920
|
+
...base.modelAliases,
|
|
10921
|
+
...override.modelAliases
|
|
10922
|
+
},
|
|
10923
|
+
clearEnv: Array.from(new Set([...base.clearEnv ?? [], ...override.clearEnv ?? []])),
|
|
10924
|
+
sessionIdFields: override.sessionIdFields ?? base.sessionIdFields,
|
|
10925
|
+
sessionArgs: override.sessionArgs ?? base.sessionArgs,
|
|
10926
|
+
resumeArgs: override.resumeArgs ?? base.resumeArgs
|
|
10927
|
+
};
|
|
10928
|
+
}
|
|
10929
|
+
function resolveCliBackendConfig(provider, cfg) {
|
|
10930
|
+
const normalized = normalizeBackendKey(provider);
|
|
10931
|
+
const configured = cfg?.agents?.defaults?.cliBackends ?? {};
|
|
10932
|
+
if (CLAUDE_BACKEND_ALIAS_SET.has(normalized)) {
|
|
10933
|
+
const merged = mergeBackendConfig(DEFAULT_CLAUDE_BACKEND, pickBackendConfigByAliases(configured, [provider, ...CLAUDE_BACKEND_ALIASES]));
|
|
10934
|
+
const command = merged.command?.trim();
|
|
10935
|
+
if (!command) return null;
|
|
10936
|
+
return {
|
|
10937
|
+
id: normalizeBackendKey("claude-cli"),
|
|
10938
|
+
config: {
|
|
10939
|
+
...merged,
|
|
10940
|
+
command
|
|
10941
|
+
}
|
|
10942
|
+
};
|
|
10943
|
+
}
|
|
10944
|
+
if (CODEX_BACKEND_ALIAS_SET.has(normalized)) {
|
|
10945
|
+
const merged = mergeBackendConfig(DEFAULT_CODEX_BACKEND, pickBackendConfigByAliases(configured, [provider, ...CODEX_BACKEND_ALIASES]));
|
|
10946
|
+
const command = merged.command?.trim();
|
|
10947
|
+
if (!command) return null;
|
|
10948
|
+
return {
|
|
10949
|
+
id: normalizeBackendKey("codex-cli"),
|
|
10950
|
+
config: {
|
|
10951
|
+
...merged,
|
|
10952
|
+
command
|
|
10953
|
+
}
|
|
10954
|
+
};
|
|
10955
|
+
}
|
|
10956
|
+
if (GEMINI_BACKEND_ALIAS_SET.has(normalized)) {
|
|
10957
|
+
const merged = mergeBackendConfig(DEFAULT_GEMINI_BACKEND, pickBackendConfigByAliases(configured, [provider, ...GEMINI_BACKEND_ALIASES]));
|
|
10958
|
+
const command = merged.command?.trim();
|
|
10959
|
+
if (!command) return null;
|
|
10960
|
+
return {
|
|
10961
|
+
id: normalizeBackendKey("gemini-cli"),
|
|
10962
|
+
config: {
|
|
10963
|
+
...merged,
|
|
10964
|
+
command
|
|
10965
|
+
}
|
|
10966
|
+
};
|
|
10967
|
+
}
|
|
10968
|
+
const override = pickBackendConfig(configured, normalized);
|
|
10969
|
+
if (!override) return null;
|
|
10970
|
+
const command = override.command?.trim();
|
|
10971
|
+
if (!command) return null;
|
|
10972
|
+
return {
|
|
10973
|
+
id: normalized,
|
|
10974
|
+
config: {
|
|
10975
|
+
...override,
|
|
10976
|
+
command
|
|
10977
|
+
}
|
|
10978
|
+
};
|
|
10979
|
+
}
|
|
10980
|
+
|
|
10981
|
+
//#endregion
|
|
10982
|
+
//#region src/agents/failover-error.ts
|
|
10983
|
+
var FailoverError = class extends Error {
|
|
10984
|
+
constructor(message, params) {
|
|
10985
|
+
super(message, { cause: params.cause });
|
|
10986
|
+
this.name = "FailoverError";
|
|
10987
|
+
this.reason = params.reason;
|
|
10988
|
+
this.provider = params.provider;
|
|
10989
|
+
this.model = params.model;
|
|
10990
|
+
this.profileId = params.profileId;
|
|
10991
|
+
this.status = params.status;
|
|
10992
|
+
this.code = params.code;
|
|
10993
|
+
}
|
|
10994
|
+
};
|
|
10995
|
+
function resolveFailoverStatus(reason) {
|
|
10996
|
+
switch (reason) {
|
|
10997
|
+
case "billing": return 402;
|
|
10998
|
+
case "rate_limit": return 429;
|
|
10999
|
+
case "auth": return 401;
|
|
11000
|
+
case "timeout": return 408;
|
|
11001
|
+
case "format": return 400;
|
|
11002
|
+
default: return;
|
|
11003
|
+
}
|
|
11004
|
+
}
|
|
11005
|
+
|
|
9838
11006
|
//#endregion
|
|
9839
11007
|
//#region src/agents/cli-runner.ts
|
|
9840
11008
|
const log$1 = createSubsystemLogger("agent/claude-cli");
|
|
@@ -10065,35 +11233,31 @@ async function runCliAgent(params) {
|
|
|
10065
11233
|
}
|
|
10066
11234
|
|
|
10067
11235
|
//#endregion
|
|
10068
|
-
//#region src/agents/
|
|
11236
|
+
//#region src/agents/gemini-direct-runner.ts
|
|
10069
11237
|
/**
|
|
10070
|
-
*
|
|
11238
|
+
* Gemini Direct API Runner
|
|
10071
11239
|
*
|
|
10072
|
-
* Makes calls directly to
|
|
10073
|
-
*
|
|
11240
|
+
* Makes calls directly to generativelanguage.googleapis.com without needing
|
|
11241
|
+
* a CLI wrapper. Works with Google API keys (GEMINI_API_KEY).
|
|
10074
11242
|
*
|
|
10075
|
-
*
|
|
10076
|
-
*
|
|
10077
|
-
*
|
|
10078
|
-
* This runner is automatically used when an `anthropic:default` token credential
|
|
10079
|
-
* is present in the auth store and the claude CLI is unavailable or not logged in.
|
|
11243
|
+
* This runner is automatically used when a google API key is available
|
|
11244
|
+
* and the provider is set to "google" or "gemini".
|
|
10080
11245
|
*/
|
|
10081
|
-
const log = createSubsystemLogger("agent/
|
|
11246
|
+
const log = createSubsystemLogger("agent/gemini-direct");
|
|
11247
|
+
const DEFAULT_GEMINI_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
|
|
10082
11248
|
const MODEL_MAP = {
|
|
10083
|
-
|
|
10084
|
-
"
|
|
10085
|
-
"
|
|
10086
|
-
"
|
|
10087
|
-
"
|
|
10088
|
-
|
|
10089
|
-
"
|
|
10090
|
-
"
|
|
10091
|
-
"
|
|
10092
|
-
|
|
10093
|
-
"haiku-3.5": "claude-haiku-3-5",
|
|
10094
|
-
default: "claude-sonnet-4-5"
|
|
11249
|
+
gemini: "gemini-2.0-flash",
|
|
11250
|
+
"gemini-pro": "gemini-1.5-pro",
|
|
11251
|
+
"gemini-flash": "gemini-2.0-flash",
|
|
11252
|
+
"gemini-2.0": "gemini-2.0-flash",
|
|
11253
|
+
"gemini-2.0-flash": "gemini-2.0-flash",
|
|
11254
|
+
"gemini-2.0-pro": "gemini-2.0-pro-exp-02-05",
|
|
11255
|
+
"gemini-1.5": "gemini-1.5-pro",
|
|
11256
|
+
"gemini-1.5-pro": "gemini-1.5-pro",
|
|
11257
|
+
"gemini-1.5-flash": "gemini-1.5-flash",
|
|
11258
|
+
default: "gemini-2.0-flash"
|
|
10095
11259
|
};
|
|
10096
|
-
const HISTORY_FILE_SUFFIX = ".
|
|
11260
|
+
const HISTORY_FILE_SUFFIX = ".gemini-history.json";
|
|
10097
11261
|
async function loadSessionHistory(sessionFile) {
|
|
10098
11262
|
const histPath = sessionFile + HISTORY_FILE_SUFFIX;
|
|
10099
11263
|
try {
|
|
@@ -10116,15 +11280,19 @@ function resolveModel(model) {
|
|
|
10116
11280
|
const key = (model ?? "default").trim().toLowerCase() || "default";
|
|
10117
11281
|
return MODEL_MAP[key] ?? key;
|
|
10118
11282
|
}
|
|
11283
|
+
function buildModelPath(model) {
|
|
11284
|
+
return model.startsWith("models/") ? model : `models/${model}`;
|
|
11285
|
+
}
|
|
10119
11286
|
/**
|
|
10120
|
-
* Run an agent turn directly against
|
|
11287
|
+
* Run an agent turn directly against generativelanguage.googleapis.com.
|
|
10121
11288
|
*
|
|
10122
11289
|
* Maintains multi-turn conversation history per session file.
|
|
10123
11290
|
* Falls back to single-turn if history is unavailable.
|
|
10124
11291
|
*/
|
|
10125
|
-
async function
|
|
11292
|
+
async function runGeminiDirectAgent(params) {
|
|
10126
11293
|
const started = Date.now();
|
|
10127
11294
|
const resolvedModel = resolveModel(params.model);
|
|
11295
|
+
const modelPath = buildModelPath(resolvedModel);
|
|
10128
11296
|
log.info(`direct api exec: model=${resolvedModel} promptChars=${params.prompt.length}`);
|
|
10129
11297
|
const workspaceDir = resolveRunWorkspaceDir({
|
|
10130
11298
|
workspaceDir: params.workspaceDir,
|
|
@@ -10164,36 +11332,37 @@ async function runAnthropicDirectAgent(params) {
|
|
|
10164
11332
|
docsPath: docsPath ?? void 0,
|
|
10165
11333
|
tools: [],
|
|
10166
11334
|
contextFiles,
|
|
10167
|
-
modelDisplay: `
|
|
11335
|
+
modelDisplay: `google/${resolvedModel}`,
|
|
10168
11336
|
agentId: sessionAgentId
|
|
10169
11337
|
});
|
|
10170
11338
|
let history = await loadSessionHistory(params.sessionFile);
|
|
10171
11339
|
if (!history) history = {
|
|
10172
11340
|
sessionId: params.sessionId,
|
|
10173
|
-
|
|
11341
|
+
contents: [],
|
|
10174
11342
|
createdAt: started,
|
|
10175
11343
|
updatedAt: started
|
|
10176
11344
|
};
|
|
10177
|
-
history.
|
|
11345
|
+
history.contents.push({
|
|
10178
11346
|
role: "user",
|
|
10179
|
-
|
|
11347
|
+
parts: [{ text: params.prompt }]
|
|
10180
11348
|
});
|
|
10181
11349
|
const requestBody = {
|
|
10182
|
-
|
|
10183
|
-
|
|
10184
|
-
|
|
10185
|
-
|
|
11350
|
+
systemInstruction: { parts: [{ text: systemPrompt }] },
|
|
11351
|
+
contents: history.contents,
|
|
11352
|
+
generationConfig: {
|
|
11353
|
+
maxOutputTokens: 8192,
|
|
11354
|
+
temperature: 1
|
|
11355
|
+
}
|
|
10186
11356
|
};
|
|
10187
11357
|
try {
|
|
10188
11358
|
const controller = new AbortController();
|
|
10189
11359
|
const timeoutHandle = setTimeout(() => controller.abort(), params.timeoutMs);
|
|
10190
|
-
const
|
|
11360
|
+
const url = `${DEFAULT_GEMINI_BASE_URL}/${modelPath}:generateContent?key=${params.apiKey}`;
|
|
11361
|
+
const response = await fetch(url, {
|
|
10191
11362
|
method: "POST",
|
|
10192
11363
|
headers: {
|
|
10193
|
-
"
|
|
10194
|
-
"
|
|
10195
|
-
"content-type": "application/json",
|
|
10196
|
-
"user-agent": `anima/3.0.5 (direct-runner; ${os.platform()})`
|
|
11364
|
+
"Content-Type": "application/json",
|
|
11365
|
+
"User-Agent": `anima/5.0.1 (gemini-direct-runner; ${os.platform()})`
|
|
10197
11366
|
},
|
|
10198
11367
|
body: JSON.stringify(requestBody),
|
|
10199
11368
|
signal: controller.signal
|
|
@@ -10204,8 +11373,8 @@ async function runAnthropicDirectAgent(params) {
|
|
|
10204
11373
|
const isAuth = response.status === 401 || response.status === 403;
|
|
10205
11374
|
const isRateLimit = response.status === 429;
|
|
10206
11375
|
const rateHint = isRateLimit ? " — rate limit hit, will retry next heartbeat." : "";
|
|
10207
|
-
const authHint = isAuth ? " —
|
|
10208
|
-
log.error(`
|
|
11376
|
+
const authHint = isAuth ? " — API key may be invalid. Check GEMINI_API_KEY environment variable." : "";
|
|
11377
|
+
log.error(`gemini api error: HTTP ${response.status}${authHint}${rateHint}`, {
|
|
10209
11378
|
status: response.status,
|
|
10210
11379
|
body: body.slice(0, 500)
|
|
10211
11380
|
});
|
|
@@ -10221,51 +11390,51 @@ async function runAnthropicDirectAgent(params) {
|
|
|
10221
11390
|
};
|
|
10222
11391
|
}
|
|
10223
11392
|
const data = await response.json();
|
|
10224
|
-
const
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
|
|
10230
|
-
|
|
10231
|
-
|
|
10232
|
-
|
|
10233
|
-
|
|
10234
|
-
}
|
|
10235
|
-
|
|
10236
|
-
await saveSessionHistory(params.sessionFile, history);
|
|
11393
|
+
const candidate = data.candidates?.[0];
|
|
11394
|
+
const assistantText = (candidate?.content?.parts ?? []).filter((p) => typeof p.text === "string").map((p) => p.text).join("\n");
|
|
11395
|
+
if (assistantText && params.onPartialReply) await params.onPartialReply({ text: assistantText });
|
|
11396
|
+
if (assistantText) {
|
|
11397
|
+
history.contents.push({
|
|
11398
|
+
role: "model",
|
|
11399
|
+
parts: [{ text: assistantText }]
|
|
11400
|
+
});
|
|
11401
|
+
history.updatedAt = Date.now();
|
|
11402
|
+
await saveSessionHistory(params.sessionFile, history);
|
|
11403
|
+
}
|
|
11404
|
+
const usage = data.usageMetadata;
|
|
10237
11405
|
const durationMs = Date.now() - started;
|
|
10238
|
-
|
|
10239
|
-
|
|
10240
|
-
|
|
11406
|
+
log.info(`gemini api complete: ${durationMs}ms`, {
|
|
11407
|
+
inputTokens: usage?.promptTokenCount,
|
|
11408
|
+
outputTokens: usage?.candidatesTokenCount,
|
|
11409
|
+
finishReason: candidate?.finishReason
|
|
11410
|
+
});
|
|
10241
11411
|
return {
|
|
10242
11412
|
status: "completed",
|
|
10243
|
-
output:
|
|
10244
|
-
payloads: outputText ? [{ text: outputText }] : [],
|
|
11413
|
+
output: assistantText,
|
|
10245
11414
|
meta: {
|
|
10246
11415
|
durationMs,
|
|
10247
11416
|
agentMeta: {
|
|
10248
|
-
provider: "anthropic",
|
|
10249
11417
|
model: resolvedModel,
|
|
10250
|
-
|
|
10251
|
-
|
|
10252
|
-
|
|
10253
|
-
|
|
10254
|
-
|
|
10255
|
-
}
|
|
11418
|
+
provider: "google",
|
|
11419
|
+
usage: usage ? {
|
|
11420
|
+
input: usage.promptTokenCount ?? 0,
|
|
11421
|
+
output: usage.candidatesTokenCount ?? 0
|
|
11422
|
+
} : void 0
|
|
10256
11423
|
}
|
|
10257
11424
|
}
|
|
10258
11425
|
};
|
|
10259
11426
|
} catch (err) {
|
|
10260
|
-
const isAbort = err instanceof Error &&
|
|
10261
|
-
|
|
11427
|
+
const isAbort = err instanceof Error && err.name === "AbortError";
|
|
11428
|
+
const errorKind = isAbort ? "timeout" : "unknown";
|
|
11429
|
+
const errorMsg = isAbort ? `Request timed out after ${params.timeoutMs}ms` : String(err);
|
|
11430
|
+
log.error(`gemini api error: ${errorMsg}`, { error: String(err) });
|
|
10262
11431
|
return {
|
|
10263
|
-
status:
|
|
11432
|
+
status: "failed",
|
|
10264
11433
|
meta: {
|
|
10265
11434
|
durationMs: Date.now() - started,
|
|
10266
11435
|
error: {
|
|
10267
|
-
message:
|
|
10268
|
-
kind:
|
|
11436
|
+
message: errorMsg,
|
|
11437
|
+
kind: errorKind
|
|
10269
11438
|
}
|
|
10270
11439
|
}
|
|
10271
11440
|
};
|
|
@@ -10353,6 +11522,57 @@ async function runEmbeddedPiAgent(...args) {
|
|
|
10353
11522
|
}
|
|
10354
11523
|
}
|
|
10355
11524
|
}
|
|
11525
|
+
if (provider === "google" || provider === "gemini") {
|
|
11526
|
+
const geminiApiKey = (await resolveApiKeyForProvider({
|
|
11527
|
+
provider: "google",
|
|
11528
|
+
cfg: params.config
|
|
11529
|
+
}))?.apiKey;
|
|
11530
|
+
if (geminiApiKey) {
|
|
11531
|
+
await emitAgentEvent(params, "lifecycle", {
|
|
11532
|
+
phase: "start",
|
|
11533
|
+
startedAt
|
|
11534
|
+
});
|
|
11535
|
+
try {
|
|
11536
|
+
const result = await runGeminiDirectAgent({
|
|
11537
|
+
apiKey: geminiApiKey,
|
|
11538
|
+
sessionId: params.sessionId,
|
|
11539
|
+
sessionKey: params.sessionKey,
|
|
11540
|
+
agentId: params.agentId,
|
|
11541
|
+
sessionFile: params.sessionFile,
|
|
11542
|
+
workspaceDir: params.workspaceDir,
|
|
11543
|
+
config: params.config,
|
|
11544
|
+
prompt: params.prompt,
|
|
11545
|
+
model: params.model,
|
|
11546
|
+
thinkLevel: params.thinkLevel,
|
|
11547
|
+
timeoutMs,
|
|
11548
|
+
runId,
|
|
11549
|
+
extraSystemPrompt: params.extraSystemPrompt,
|
|
11550
|
+
ownerNumbers: params.ownerNumbers,
|
|
11551
|
+
onPartialReply: async (payload) => {
|
|
11552
|
+
if (!assistantStarted) {
|
|
11553
|
+
assistantStarted = true;
|
|
11554
|
+
await params.onAssistantMessageStart?.();
|
|
11555
|
+
}
|
|
11556
|
+
await params.onPartialReply?.(payload);
|
|
11557
|
+
await emitAgentEvent(params, "assistant", { text: payload.text });
|
|
11558
|
+
},
|
|
11559
|
+
onAssistantMessageStart: params.onAssistantMessageStart
|
|
11560
|
+
});
|
|
11561
|
+
await emitAgentEvent(params, "lifecycle", {
|
|
11562
|
+
phase: "end",
|
|
11563
|
+
durationMs: Date.now() - startedAt,
|
|
11564
|
+
status: result.status
|
|
11565
|
+
});
|
|
11566
|
+
return result;
|
|
11567
|
+
} catch (err) {
|
|
11568
|
+
await emitAgentEvent(params, "lifecycle", {
|
|
11569
|
+
phase: "error",
|
|
11570
|
+
error: String(err instanceof Error ? err.message : err)
|
|
11571
|
+
});
|
|
11572
|
+
throw err;
|
|
11573
|
+
}
|
|
11574
|
+
}
|
|
11575
|
+
}
|
|
10356
11576
|
const cliProvider = resolveCompatCliProvider(provider, params.config);
|
|
10357
11577
|
if (!resolveCliBackendConfig(cliProvider, params.config)) throw new Error(`No CLI backend available for provider "${provider}" (resolved "${cliProvider}").\nEither:\n • Run: anima setup-token (set an Anthropic API key — no CLI needed)\n • Install the matching CLI and log in`);
|
|
10358
11578
|
await emitAgentEvent(params, "lifecycle", {
|