@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.
Files changed (323) hide show
  1. package/dist/{accounts-BOkEyUcS.js → accounts-DjjQHOIW.js} +5 -5
  2. package/dist/{accounts-CVmv61PJ.js → accounts-Dzi6Ld7X.js} +2 -2
  3. package/dist/{acp-cli-C8aBckv5.js → acp-cli-I-yv1f5O.js} +15 -15
  4. package/dist/{acp-cli-BcshtFqY.js → acp-cli-QBd9GLqD.js} +3 -3
  5. package/dist/{agent-Cil6Zvns.js → agent-B3KeHK1A.js} +9 -9
  6. package/dist/{agent-c49U1LxE.js → agent-fG1PVmNy.js} +16 -16
  7. package/dist/{agent-scope-DICrDp7Y.js → agent-scope-BHR6uOLT.js} +2 -2
  8. package/dist/{agent-scope-BLiq3nK_.js → agent-scope-ryeVDUKe.js} +2 -2
  9. package/dist/{agents-2BloqCjm.js → agents-DY5ZtGB2.js} +9 -9
  10. package/dist/{agents.config-Bqr5rrkV.js → agents.config-DmF0fsB6.js} +1 -1
  11. package/dist/{anthropic-direct-runner-mh6c_WBB.js → anthropic-direct-runner-BJosFvVm.js} +41 -18
  12. package/dist/{anthropic-direct-runner-BVlO2Vi5.js → anthropic-direct-runner-BXb24VJt.js} +50 -27
  13. package/dist/{audit-BbmRSFjf.js → audit-BTMmL_HS.js} +5 -5
  14. package/dist/{audit-DegswVkZ.js → audit-qHMf9jWY.js} +16 -16
  15. package/dist/{auth-Cs_c5TKt.js → auth-DQfFqQBz.js} +3 -3
  16. package/dist/{auth-choice-BVAMr2Dk.js → auth-choice-BoyT3ahK.js} +60 -8
  17. package/dist/{auth-health-D0VUH0FQ.js → auth-health-BcABdgUT.js} +1 -1
  18. package/dist/{auth-profiles-k5IOWaG2.js → auth-profiles-BF5x9Ej0.js} +1 -1
  19. package/dist/{auth-profiles-BhZX2spm.js → auth-profiles-C_LmTbMb.js} +5 -5
  20. package/dist/{auth-profiles-Chf1JBpl.js → auth-profiles-Da39zGOD.js} +4 -4
  21. package/dist/{auth-store-D0vDEvCx.js → auth-store-CXZzirrJ.js} +3 -3
  22. package/dist/{auth-store-BMwyg-WK.js → auth-store-DTpDRu--.js} +3 -3
  23. package/dist/{banner-CgxCSS-T.js → banner-CJVa8aiZ.js} +1 -1
  24. package/dist/{bonjour-discovery-DaCmsB4i.js → bonjour-discovery-B3IeIN1u.js} +2 -2
  25. package/dist/build-info.json +3 -3
  26. package/dist/bundled/boot-md/handler.js +22 -22
  27. package/dist/bundled/bootstrap-extra-files/handler.js +7 -7
  28. package/dist/bundled/session-memory/handler.js +19 -19
  29. package/dist/{call-Z_GCO8CL.js → call-BKsdSTVf.js} +1 -1
  30. package/dist/{call-BOwaQIXo.js → call-C3CH9PNK.js} +6 -6
  31. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  32. package/dist/{catalog-B-pfqu76.js → catalog-3hzXhHxJ.js} +2 -2
  33. package/dist/{channel-web-Y8i3EzJq.js → channel-web-Df3Ay9v7.js} +18 -18
  34. package/dist/{channels-status-issues-DenKLCLq.js → channels-status-issues-D5XAOSaj.js} +4 -4
  35. package/dist/{chrome-C3-muxXb.js → chrome-CLhrEjgx.js} +4 -4
  36. package/dist/{chrome-Cxl7I5SB.js → chrome-CkSIMI7j.js} +2 -2
  37. package/dist/{chunk-DGg8zCWl.js → chunk-Dq7ILx_r.js} +2 -2
  38. package/dist/{chunk-DFCmYqgJ.js → chunk-fcLG1hME.js} +1 -1
  39. package/dist/{clack-prompter-CCRr4nAr.js → clack-prompter-DmD_A7en.js} +5 -5
  40. package/dist/{clack-prompter-B-ZJG628.js → clack-prompter-bl-Zsxpq.js} +1 -1
  41. package/dist/cli/daemon-cli.js +1 -1
  42. package/dist/{cli-C3uw3mId.js → cli-0-FvuyBX.js} +22 -22
  43. package/dist/cli-CLVEx1Po.js +104 -0
  44. package/dist/{cli-session-BzZYmGP1.js → cli-session-CmX1oA1T.js} +7 -7
  45. package/dist/{cli-session-DgUHOBYo.js → cli-session-gR2abU0g.js} +16 -16
  46. package/dist/{client-BObcTF_9.js → client-BT3pbXCv.js} +3 -3
  47. package/dist/{command-registry-DLofaVIN.js → command-registry-C3SmyTQU.js} +12 -12
  48. package/dist/{common-k1Cu8adj.js → common-Bi43BlMQ.js} +2 -2
  49. package/dist/{common-Cd7BmlCQ.js → common-CSTOiddD.js} +2 -2
  50. package/dist/{completion-cli-C9KvX2ZF.js → completion-cli-308M08su.js} +2 -2
  51. package/dist/{completion-cli-3eYvtAih.js → completion-cli-D7gWcWEj.js} +3 -3
  52. package/dist/{config-B-9UciOO.js → config-BfhpauV9.js} +6 -6
  53. package/dist/{config-CG7uuHNE.js → config-Dk-5Mb_G.js} +6 -6
  54. package/dist/{config-D6D_ieel.js → config-Ofh9gKvs.js} +1 -1
  55. package/dist/config-cli-CajDGi9m.js +15 -0
  56. package/dist/{config-cli-CBXWDtvj.js → config-cli-De0z7mvk.js} +3 -3
  57. package/dist/{config-guard-BT3OoaEu.js → config-guard-BnkobgvR.js} +21 -21
  58. package/dist/{config-guard-qiKju2Fg.js → config-guard-DlOs5hMU.js} +2 -2
  59. package/dist/{configure-jlAKeuki.js → configure-BXK8YRUD.js} +32 -32
  60. package/dist/{configure-CH_-SNya.js → configure-Caf6yI_m.js} +24 -24
  61. package/dist/{configure-Dpk4lSoz.js → configure-DS9oQW51.js} +78 -78
  62. package/dist/{configure-CGTBBLR_.js → configure-DgXRL7Uz.js} +9 -9
  63. package/dist/{context-Cau0zD3W.js → context-BZV-msqG.js} +1 -1
  64. package/dist/{control-service-DMoq3DpT.js → control-service-BFYEuU-S.js} +5 -5
  65. package/dist/{control-service-CUhnhmpc.js → control-service-DUF4hGd3.js} +2 -2
  66. package/dist/{cron-cli-CKs1evSF.js → cron-cli-BglUapfu.js} +4 -4
  67. package/dist/{cron-cli-ybIqf_95.js → cron-cli-OHSsCpVe.js} +16 -16
  68. package/dist/{daemon-cli-C5Tosclk.js → daemon-cli-B2UGyc5z.js} +19 -19
  69. package/dist/{daemon-cli-CSCFNzUo.js → daemon-cli-CO-1GTE_.js} +5 -5
  70. package/dist/daemon-cli.js +58 -1
  71. package/dist/{daemon-runtime-B9AywEma.js → daemon-runtime-BsUCg0Nr.js} +3 -3
  72. package/dist/{daemon-runtime-DpY6Y5qE.js → daemon-runtime-cGQoReHT.js} +1 -1
  73. package/dist/{deliver-DkF6LCoS.js → deliver-CoAOvyW0.js} +1 -1
  74. package/dist/{deliver-BYxbDIF0.js → deliver-DhQSpWQA.js} +4 -4
  75. package/dist/{deliver-B2p9Fke_.js → deliver-DvbZ8dp4.js} +6 -6
  76. package/dist/{deps-D9266xfk.js → deps-CCbWMWT4.js} +1 -1
  77. package/dist/{diagnostics-TXSvtpaq.js → diagnostics-CtqVmSaZ.js} +1 -1
  78. package/dist/{dispatcher-DG44QJKz.js → dispatcher-C4k9ABOv.js} +2 -2
  79. package/dist/{dispatcher-BeO47t7A.js → dispatcher-N_4IYF9I.js} +1 -1
  80. package/dist/{dns-cli-BklOUsrX.js → dns-cli-DJ8mwzgA.js} +2 -2
  81. package/dist/{dns-cli-Dq98107U.js → dns-cli-Dk48S2y7.js} +13 -13
  82. package/dist/{docs-cli-CehJ2v5M.js → docs-cli-BvBEqoCl.js} +7 -7
  83. package/dist/{doctor-DJfgnQ67.js → doctor-9cbiXykn.js} +19 -19
  84. package/dist/{doctor-CWmHUAjs.js → doctor-C_1WNQix.js} +40 -40
  85. package/dist/{doctor-completion-CmJmktDv.js → doctor-completion-B1cKYcZj.js} +1 -1
  86. package/dist/{doctor-completion-CtCwd1fi.js → doctor-completion-D7uvGhAv.js} +3 -3
  87. package/dist/{doctor-config-flow-D0GgdMmi.js → doctor-config-flow-Bno6wZvG.js} +7 -7
  88. package/dist/{doctor-config-flow-D_8YNTSK.js → doctor-config-flow-rshwu4JS.js} +3 -3
  89. package/dist/entry.js +59 -2
  90. package/dist/{env-T3-raV4i.js → env-CLiKFfXU.js} +1 -1
  91. package/dist/{exec-DbnX_71w.js → exec-Bo7Vwe77.js} +1 -1
  92. package/dist/{exec-DnanRQle.js → exec-CEFTijVj.js} +1 -1
  93. package/dist/{exec-approvals-cli-B7hQEhGe.js → exec-approvals-cli-CRqO-FRn.js} +19 -19
  94. package/dist/{exec-approvals-cli-CcY7IQWQ.js → exec-approvals-cli-i_Bmu0zE.js} +4 -4
  95. package/dist/extensionAPI.js +1535 -315
  96. package/dist/{frontmatter-BmBmtOUh.js → frontmatter-Dsa7N963.js} +1 -1
  97. package/dist/{gateway-cli-DYrzIvOE.js → gateway-cli-CBmfvcpr.js} +99 -99
  98. package/dist/{gateway-cli-BazTmg20.js → gateway-cli-CufIzw2K.js} +43 -43
  99. package/dist/{gateway-rpc-LkRV5joR.js → gateway-rpc-BX-Pz0j8.js} +3 -3
  100. package/dist/{gateway-rpc-De-TWFvD.js → gateway-rpc-BvqpdNqp.js} +1 -1
  101. package/dist/{gmail-setup-utils-B4oMbrOI.js → gmail-setup-utils-B-LgbK-5.js} +3 -3
  102. package/dist/{health-BRSKF_iF.js → health-BVBoq6jM.js} +10 -10
  103. package/dist/{health-JqtB_B8C.js → health-DKC8u4W8.js} +18 -18
  104. package/dist/{health-format-Ojy0hLp3.js → health-format-DHYaqzgj.js} +2 -2
  105. package/dist/{heartbeat-visibility-BGj2czmk.js → heartbeat-visibility-CF3WzMM0.js} +2 -2
  106. package/dist/{heartbeat-visibility-pyFf6XBW.js → heartbeat-visibility-CUKC8xqZ.js} +2 -2
  107. package/dist/{help-format-BZ7j9sHT.js → help-format-mLYxJ3oD.js} +1 -1
  108. package/dist/{hooks-cli-B7g3jEC3.js → hooks-cli-BHO_BQFY.js} +23 -23
  109. package/dist/{hooks-cli-ZK4Z044T.js → hooks-cli-kLrFK7pV.js} +57 -57
  110. package/dist/{hooks-status-DR_WkhpR.js → hooks-status-CfvVr6eJ.js} +3 -3
  111. package/dist/{image-ops-B7tKwzpV.js → image-ops-C_aRXc-7.js} +1 -1
  112. package/dist/index.js +69 -69
  113. package/dist/{installs-BxZFjTKY.js → installs-DW-ErO4y.js} +5 -5
  114. package/dist/{lanes-DyM6NSSL.js → lanes-CrNcoc6P.js} +480 -163
  115. package/dist/{lifecycle-core-CHv9wUhV.js → lifecycle-core-DWESti3N.js} +6 -6
  116. package/dist/{links-CziCxopc.js → links-C4Hwnnc9.js} +1 -1
  117. package/dist/llm-slug-generator.js +17 -17
  118. package/dist/{logging-Dwz0XtXm.js → logging-CnEuyIPZ.js} +1 -1
  119. package/dist/{login-BvRe8YZ9.js → login-CY9_XaLc.js} +7 -7
  120. package/dist/{login-BbfWLOBl.js → login-Dj6hCAFK.js} +5 -5
  121. package/dist/{login-DevThvtW.js → login-Ga69_Kio.js} +2 -2
  122. package/dist/{login-qr-FDWY-tu5.js → login-qr-BYeWGzxI.js} +12 -12
  123. package/dist/{login-qr-BqhujMcQ.js → login-qr-DD1apkdT.js} +10 -10
  124. package/dist/{login-qr-BkpIGqae.js → login-qr-swgX7elR.js} +3 -3
  125. package/dist/{logs-cli-CiMRc2qL.js → logs-cli-D02oahhw.js} +4 -4
  126. package/dist/{logs-cli-CsfmPUwa.js → logs-cli-DAVu9h8p.js} +16 -16
  127. package/dist/{manager-CcawxgaC.js → manager-CLAy-qOR.js} +10 -10
  128. package/dist/{manager-v4S80Br3.js → manager-DQPfk6Ea.js} +12 -12
  129. package/dist/{manager-DS1DfkbC.js → manager-yWxV2UI_.js} +1 -1
  130. package/dist/{manifest-registry-BiGCvMJ8.js → manifest-registry-BJat2nhC.js} +1 -1
  131. package/dist/{memory-cli-wDO418hx.js → memory-cli-B8AsIRG3.js} +3 -3
  132. package/dist/{memory-cli-Cl2n9UtH.js → memory-cli-bA70cVlm.js} +12 -12
  133. package/dist/{message-channel-DuxJGOJz.js → message-channel-C5I8UgGH.js} +1 -1
  134. package/dist/{model-auth-Ja4oelNH.js → model-auth-Be3_KahV.js} +2 -2
  135. package/dist/{model-auth-DVG37yXU.js → model-auth-DBHvPqaY.js} +4 -4
  136. package/dist/{model-auth-Uxm-wRjR.js → model-auth-DYHjH-Oh.js} +3 -3
  137. package/dist/{model-selection-xZLlICyg.js → model-selection-BuMFehML.js} +5 -2
  138. package/dist/{model-selection-BKFF7fDb.js → model-selection-DFbDH9o2.js} +4 -1
  139. package/dist/{model-selection-C2dAUmK_.js → model-selection-DRIxw3do.js} +5 -2
  140. package/dist/{models-tQnX4hL4.js → models-B9jYbX5H.js} +26 -26
  141. package/dist/{node-cli-DAcW-rfA.js → node-cli-C_efNJ2B.js} +7 -7
  142. package/dist/{node-cli-CZuWFgpO.js → node-cli-ScPCT6uD.js} +28 -28
  143. package/dist/{node-service-Ds1r16VN.js → node-service-BCfZtWK_.js} +1 -1
  144. package/dist/{note-Daao-cv8.js → note-DjzS4Am4.js} +2 -2
  145. package/dist/{npm-registry-spec-fJIJ8GG5.js → npm-registry-spec-Opq9qQXl.js} +1 -1
  146. package/dist/{onboard-Dd6xFMYB.js → onboard-C7ZSJNCe.js} +10 -10
  147. package/dist/{onboard-dasbF9G1.js → onboard-CJOJPctL.js} +17 -17
  148. package/dist/{onboard-channels-DisvVyIs.js → onboard-channels-DSlUCvl1.js} +2 -2
  149. package/dist/{onboard-channels-BUv3VbAL.js → onboard-channels-DwPNXSwW.js} +9 -9
  150. package/dist/{onboard-helpers-BgsHO6fO.js → onboard-helpers-CU_S0_Kf.js} +10 -10
  151. package/dist/{onboard-helpers-49TVSf7J.js → onboard-helpers-tkuUrdCB.js} +2 -2
  152. package/dist/{onboarding-Dq3bCBjc.js → onboarding-Caiq91Yz.js} +10 -10
  153. package/dist/{onboarding-6Xs4orLw.js → onboarding-DP2NlqhA.js} +20 -20
  154. package/dist/{outbound-RxegsVGB.js → outbound-B84phlQU.js} +4 -4
  155. package/dist/{outbound-CliT3nme.js → outbound-CKmmCVxJ.js} +1 -1
  156. package/dist/{outbound-CLII4C2A.js → outbound-DKM-JeSH.js} +5 -5
  157. package/dist/{parse-timeout-BnOIKwx8.js → parse-timeout-C59j-ev4.js} +1 -1
  158. package/dist/{parse-timeout-C8t_lmnL.js → parse-timeout-aZGyXXFz.js} +3 -3
  159. package/dist/{path-env-CsgLP0dy.js → path-env-cFxXrXB1.js} +1 -1
  160. package/dist/{paths-DybdJi5a.js → paths-CLxC7m0Z.js} +1 -1
  161. package/dist/{pi-auth-json-MH7vz0HI.js → pi-auth-json-DPoqstQN.js} +7 -7
  162. package/dist/{pi-auth-json-BY6wRDm0.js → pi-auth-json-DjxzPUt3.js} +2 -2
  163. package/dist/{pi-auth-json-DLroEcea.js → pi-auth-json-hMxhauJ8.js} +6 -6
  164. package/dist/{pi-embedded-CS4D_0t7.js → pi-embedded-JUmNmkTK.js} +700 -362
  165. package/dist/{pi-embedded-helpers-iju5zIIA.js → pi-embedded-helpers-B6wVA0hU.js} +1 -1
  166. package/dist/{pi-embedded-helpers-DnRfi8bN.js → pi-embedded-helpers-B_Sx4G6d.js} +30 -20
  167. package/dist/{pi-tools.policy-RhdERrk3.js → pi-tools.policy-Bn9S3ywB.js} +2 -2
  168. package/dist/{pi-tools.policy-CN78I2yN.js → pi-tools.policy-ChzY9kW7.js} +7 -7
  169. package/dist/{plugin-auto-enable-DLrgOd4y.js → plugin-auto-enable-UE1XVFcw.js} +1 -1
  170. package/dist/{plugin-auto-enable-DIWd94Po.js → plugin-auto-enable-f05JE-GF.js} +5 -5
  171. package/dist/{plugin-registry-l3z9phEV.js → plugin-registry-BeB2L6Qe.js} +2 -2
  172. package/dist/{plugin-registry-esOxvV3X.js → plugin-registry-DIXcynua.js} +4 -4
  173. package/dist/plugin-sdk/agents/anthropic-direct-runner.d.ts +1 -1
  174. package/dist/plugin-sdk/agents/gemini-direct-runner.d.ts +38 -0
  175. package/dist/plugin-sdk/agents/tools/browser-tool.schema.d.ts +2 -2
  176. package/dist/plugin-sdk/commands/onboard-types.d.ts +2 -2
  177. package/dist/plugin-sdk/gateway/protocol/index.d.ts +22 -22
  178. package/dist/plugin-sdk/index.js +75 -8
  179. package/dist/{plugins-C_GedoUi.js → plugins-DCXdhkeB.js} +2 -2
  180. package/dist/{plugins-BmYfBGLM.js → plugins-NbldDVJs.js} +1 -1
  181. package/dist/{plugins-cli-CbXtuN4b.js → plugins-cli-CzUD-ewi.js} +58 -58
  182. package/dist/{plugins-cli-D2v0n4BL.js → plugins-cli-Dk2W0fBT.js} +23 -23
  183. package/dist/{polls-Cuv4dsX_.js → polls-OzE9fR2s.js} +6 -6
  184. package/dist/{ports-DOiSDgNp.js → ports-CWvYU8j6.js} +4 -4
  185. package/dist/{ports-BQ0cAsGj.js → ports-Cgow804e.js} +2 -2
  186. package/dist/{program-y0NPJuYm.js → program-DxItv_Ts.js} +28 -28
  187. package/dist/{program-context-CqPwmgYa.js → program-context-cgh8PMPD.js} +33 -33
  188. package/dist/{progress-BZZa-fXr.js → progress-DzZ_4Z4f.js} +1 -1
  189. package/dist/{prompt-style-1bwj7IzZ.js → prompt-style-C7WfXowC.js} +1 -1
  190. package/dist/{prompts-DY0qdoD1.js → prompts-BfHxhlF9.js} +13 -2
  191. package/dist/{prompts-DTKoIKPV.js → prompts-DH_nIROF.js} +71 -8
  192. package/dist/{pw-ai-BhoKfvvM.js → pw-ai-Bigm0Qwh.js} +7 -7
  193. package/dist/{pw-ai-CJgeaF06.js → pw-ai-CsODxGt8.js} +3 -3
  194. package/dist/{qmd-manager-BGob_1OP.js → qmd-manager-C3z8LWKx.js} +6 -6
  195. package/dist/{qmd-manager-BmGj4bZk.js → qmd-manager-lfhigvUf.js} +6 -6
  196. package/dist/{register.agent-CRazop1A.js → register.agent-BVwbjkKx.js} +30 -30
  197. package/dist/{register.agent-Bi2FqIlN.js → register.agent-D0FKVD_s.js} +70 -70
  198. package/dist/{register.anima-BmdRCJLy.js → register.anima-Dc7OI2Nh.js} +4 -4
  199. package/dist/{register.anima-FFaI_C8x.js → register.anima-bys_cyEd.js} +4 -4
  200. package/dist/{register.configure-FIXOWrO9.js → register.configure-BrRG_RtB.js} +31 -31
  201. package/dist/register.configure-CXKr61Ka.js +108 -0
  202. package/dist/register.maintenance-BToHjam6.js +103 -0
  203. package/dist/{register.maintenance-DJYji5mV.js → register.maintenance-DXL3L0ip.js} +35 -35
  204. package/dist/{register.onboard-thGXwzOX.js → register.onboard-B3hbdfaQ.js} +71 -71
  205. package/dist/{register.onboard-oUsWjmam.js → register.onboard-Bg5zEb3f.js} +35 -35
  206. package/dist/{register.setup-B4MYuE3g.js → register.setup-CZqwphif.js} +35 -35
  207. package/dist/{register.setup-DWDrQ7RT.js → register.setup-Cq8nqbrU.js} +71 -71
  208. package/dist/{register.status-health-sessions-Ce9QUAyj.js → register.status-health-sessions-D1kjQUAc.js} +67 -67
  209. package/dist/{register.status-health-sessions-CTKdzo7a.js → register.status-health-sessions-mdLJbfPN.js} +28 -28
  210. package/dist/{register.subclis-CWmYc4AB.js → register.subclis-mbYw7H-_.js} +20 -20
  211. package/dist/{reply-BKpIrCr-.js → reply-CwV-5jE0.js} +56 -52
  212. package/dist/{reply-CpHIJ9Kk.js → reply-DAGmjvs-.js} +33 -29
  213. package/dist/{reply-prefix-BO_Dt82N.js → reply-prefix-BRsV1Eof.js} +2 -2
  214. package/dist/{reply-prefix-BwVBvQXp.js → reply-prefix-CAsFNEP7.js} +2 -2
  215. package/dist/{routes-C2EyUA9x.js → routes-CYHrkIjB.js} +6 -6
  216. package/dist/{routes-XhTPYecR.js → routes-cdfVFYMI.js} +2 -2
  217. package/dist/{run-CGokiDR8.js → run-DE6EaeE3.js} +70 -70
  218. package/dist/{run--9hftM2H.js → run-S0Cw3Fyy.js} +32 -32
  219. package/dist/{run-main-DxcOzCLw.js → run-main-CCxXEvb7.js} +41 -41
  220. package/dist/{runtime-guard-B40AREJ_.js → runtime-guard-CNnLK4pn.js} +1 -1
  221. package/dist/{sandbox-BwUo1b0I.js → sandbox-B4-dXpqZ.js} +6 -6
  222. package/dist/{sandbox-CiwAPzO7.js → sandbox-DhcoWMaN.js} +2 -2
  223. package/dist/{sandbox-cli-D9-wZJ9M.js → sandbox-cli-DQMWPCOh.js} +24 -24
  224. package/dist/{sandbox-cli-DsrzwG_s.js → sandbox-cli-TAuv3mTO.js} +6 -6
  225. package/dist/{security-cli-CX5uciKz.js → security-cli-Da-3YxZ4.js} +29 -29
  226. package/dist/{security-cli-CouqfUGc.js → security-cli-Dc-NwTC2.js} +9 -9
  227. package/dist/{semantic-Buqqx7gZ.js → semantic-BlQgdb3-.js} +1 -1
  228. package/dist/{semantic-B4TOg4CK.js → semantic-VlSmVCfb.js} +1 -1
  229. package/dist/{server-context-B78_sSOW.js → server-context-C-usQ5Np.js} +1 -1
  230. package/dist/{server-context-efO1YgXk.js → server-context-r7wPe4ZD.js} +9 -9
  231. package/dist/{server-node-events-TN_Y9MgU.js → server-node-events-3KeQAwUo.js} +14 -14
  232. package/dist/{server-node-events-DJlLCF2M.js → server-node-events-GTSQEd_U.js} +36 -36
  233. package/dist/{service-D1idQeBv.js → service-DCVAkKlN.js} +1 -1
  234. package/dist/{service-audit-BzwV-IOi.js → service-audit-Crw1cAbj.js} +1 -1
  235. package/dist/{service-audit-BbwXAhsr.js → service-audit-DRIpsryX.js} +3 -3
  236. package/dist/{session-Dvwwi-Eb.js → session-CrGApVik.js} +1 -1
  237. package/dist/{session-skOcrvF2.js → session-D3BNUwtH.js} +1 -1
  238. package/dist/{session-DCGAvNG9.js → session-DKCUYHCS.js} +1 -1
  239. package/dist/{session-cost-usage-6bDLU9Pb.js → session-cost-usage-LvsvRW5g.js} +1 -1
  240. package/dist/{session-BjPdEBPh.js → session-mpOb9zFL.js} +5 -5
  241. package/dist/{sessions-kJgmpWtv.js → sessions-BduC6sZj.js} +78 -68
  242. package/dist/{sessions-B7ikzhI_.js → sessions-CAiEkTKb.js} +18 -8
  243. package/dist/{sessions-B7clh58j.js → sessions-DLPN62LD.js} +4 -4
  244. package/dist/{settings-cli-JU5bg5jb.js → settings-cli-BgGYdH4N.js} +77 -77
  245. package/dist/{settings-cli-DjVugHID.js → settings-cli-f0O0FUVO.js} +32 -32
  246. package/dist/{setup-token-CvRwJUVY.js → setup-token-lcjrc9sO.js} +28 -28
  247. package/dist/{setup-token-wFsQlaW2.js → setup-token-ykp60QVx.js} +9 -9
  248. package/dist/{shared-DC8lQHCt.js → shared-Ca0NTTF0.js} +3 -3
  249. package/dist/{shell-env-JzaPTLKV.js → shell-env-BZ_fIIlm.js} +1 -1
  250. package/dist/{shell-env-C1yK_Rod.js → shell-env-DaSbgZYX.js} +2 -2
  251. package/dist/{skill-scanner-HQwt_KRF.js → skill-scanner--TxpCSNF.js} +1 -1
  252. package/dist/{skills-cli-OYZS-U1f.js → skills-cli-BpyTvFkg.js} +16 -16
  253. package/dist/{skills-cli-CSMzc9am.js → skills-cli-Tm326cFx.js} +2 -2
  254. package/dist/{skills-install-BKz5WLq4.js → skills-install-B2m10oTm.js} +5 -5
  255. package/dist/{skills-status-B_umZ78Q.js → skills-status-D14GZ5WN.js} +3 -3
  256. package/dist/{skills-ppB3qrZU.js → skills-wS8aRGeO.js} +3 -3
  257. package/dist/{soul-DpWsWxOa.js → soul-CAEpnUkv.js} +1 -1
  258. package/dist/{soul-aZoR6Ctt.js → soul-D9EtC35X.js} +1 -1
  259. package/dist/{sqlite-CnVGUfhz.js → sqlite-B0rfPL8q.js} +2 -2
  260. package/dist/{sqlite-Duz1QJIT.js → sqlite-CR0WDTae.js} +2 -2
  261. package/dist/start-DYq7cNRG.js +157 -0
  262. package/dist/{start-CAbxlnFZ.js → start-Y69GZPdX.js} +41 -41
  263. package/dist/{status-YH65ctig.js → status-BplZv8_T.js} +2 -2
  264. package/dist/{status-CrJV2Y4x.js → status-K3LGPZeT.js} +4 -4
  265. package/dist/{status-CxxXFU4R.js → status-Uzlo7BvY.js} +27 -27
  266. package/dist/{status-1TjjCE1l.js → status-rt3tIYmL.js} +13 -13
  267. package/dist/{status.update-P6xyBet8.js → status.update-B61Emp_r.js} +3 -3
  268. package/dist/{status.update-BzAuf_G-.js → status.update-yjbKzlMn.js} +1 -1
  269. package/dist/{subagent-registry-xJY9wqZy.js → subagent-registry-DfCDq9hk.js} +14 -14
  270. package/dist/{subagent-registry-3Dw3YppH.js → subagent-registry-ZIpC5W-9.js} +7 -7
  271. package/dist/{subagent-registry-B_65nJFp.js → subagent-registry-xp5sYYzS.js} +13 -13
  272. package/dist/{subsystem-Cn6bJV8Z.js → subsystem-BMsbqSb4.js} +58 -1
  273. package/dist/{subsystem-WFp78xn1.js → subsystem-BP2l3SHn.js} +58 -1
  274. package/dist/{system-cli-Dbn4_ed8.js → system-cli-D-eyDWD6.js} +4 -4
  275. package/dist/{system-cli-lmslA_Ox.js → system-cli-Dy2Pwnbg.js} +15 -15
  276. package/dist/{systemd-DYPdTwok.js → systemd-DXo2A9_S.js} +2 -2
  277. package/dist/{systemd-hints-E8yYE8Q1.js → systemd-hints-DIjCA1An.js} +1 -1
  278. package/dist/{systemd-linger-CpWguZ4b.js → systemd-linger-DgB-ow-D.js} +2 -2
  279. package/dist/{table-B991ZwKi.js → table-C-GNQABy.js} +2 -2
  280. package/dist/{timeout-Dbspj9Jf.js → timeout-Cl8rWNWO.js} +350 -33
  281. package/dist/{tokens-k_R7Y792.js → tokens-FGW_JgKz.js} +1 -1
  282. package/dist/{tool-images-DJZPwGqm.js → tool-images-Df50dvpv.js} +2 -2
  283. package/dist/{tool-images-BehEzEZF.js → tool-images-RiPaL7wQ.js} +2 -2
  284. package/dist/{tui-PCTDV7Ct.js → tui-NlR4LFBm.js} +9 -9
  285. package/dist/{tui--eIVX_W0.js → tui-YsmTyq58.js} +3 -3
  286. package/dist/{tui-cli-DBV3lnXA.js → tui-cli-CSudxVpO.js} +9 -9
  287. package/dist/{tui-cli-D39zC_Ew.js → tui-cli-QnKj1We8.js} +28 -28
  288. package/dist/{update-tjMvDUCw.js → update-B2O46V_t.js} +3 -3
  289. package/dist/{update-cli-QP5L8xlv.js → update-cli-BXKL-v-n.js} +86 -86
  290. package/dist/{update-cli-BzaQvirL.js → update-cli-BgQUtlLg.js} +37 -37
  291. package/dist/{update-runner-ZuJN8uBE.js → update-runner-U2WcWGfd.js} +5 -5
  292. package/dist/{update-runner-B_oj7S_n.js → update-runner-fvdM_Hip.js} +1 -1
  293. package/dist/{usage-DzKbMa8N.js → usage-CM-NiwBA.js} +9 -9
  294. package/dist/{utils-dWKYjULE.js → utils-B60lF9Wq.js} +1 -1
  295. package/dist/{web-CgQc2Raf.js → web-B8r6MvXh.js} +43 -43
  296. package/dist/web-BzFhL5WI.js +67 -0
  297. package/dist/{web-nI3eIGAT.js → web-eoSM6P0a.js} +26 -26
  298. package/dist/{webhooks-cli-CYbIJJF6.js → webhooks-cli-24A2CbXR.js} +2 -2
  299. package/dist/{webhooks-cli-oRmSfYdd.js → webhooks-cli-CgkxWcH5.js} +13 -13
  300. package/dist/{whatsapp-actions-BzPQUcRR.js → whatsapp-actions-BVlqbVgY.js} +3 -3
  301. package/dist/{whatsapp-actions-CZuxHplg.js → whatsapp-actions-BYxKWK0A.js} +13 -13
  302. package/dist/{whatsapp-actions-BB-Leqn2.js → whatsapp-actions-DagVwYC6.js} +17 -17
  303. package/dist/{widearea-dns-CkuHFBQy.js → widearea-dns-B1TTb1v5.js} +1 -1
  304. package/dist/{workspace-DOJssemp.js → workspace-Cvio8QlZ.js} +1 -1
  305. package/dist/{ws-log-B-xsUQys.js → ws-log-De7GACYn.js} +1 -1
  306. package/dist/{ws-CQYP0dWu.js → ws-sdRTa2sP.js} +1 -1
  307. package/package.json +1 -1
  308. package/dist/cli-CfvBmuhw.js +0 -104
  309. package/dist/config-cli-cmNuTlw0.js +0 -15
  310. package/dist/register.configure-r5AViY3N.js +0 -108
  311. package/dist/register.maintenance-Cpf0ZZTL.js +0 -103
  312. package/dist/start-M9abr1O1.js +0 -157
  313. package/dist/web-DtWSf5wm.js +0 -67
  314. /package/dist/{boolean-M-esQJt6.js → boolean-Ce2-qkSB.js} +0 -0
  315. /package/dist/{command-format-B1WxXbeU.js → command-format-UwAvxtMC.js} +0 -0
  316. /package/dist/{config-Qw5FwfRK.js → config-COtiNNtV.js} +0 -0
  317. /package/dist/{errors-DjZBTJJ3.js → errors-D6Vj_xs4.js} +0 -0
  318. /package/dist/{file-lock-BRW4LeL0.js → file-lock-BFQVGKm5.js} +0 -0
  319. /package/dist/{input-provenance-B0pwc6mp.js → input-provenance-sPbZYo89.js} +0 -0
  320. /package/dist/{internal-hooks-Exeq-wmx.js → internal-hooks-CWw3Hgeu.js} +0 -0
  321. /package/dist/{paths-BvY3CbW0.js → paths-CnuAkdfx.js} +0 -0
  322. /package/dist/{tailnet-CjJJHjPU.js → tailnet-CabhakZ7.js} +0 -0
  323. /package/dist/{transcript-events-DUQC5hbS.js → transcript-events-C1hdue6u.js} +0 -0
@@ -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
- fs.appendFileSync(settings.file, `${line}\n`, { encoding: "utf8" });
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$7 = createSubsystemLogger("skills");
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$6 = createSubsystemLogger("browser").child("chrome");
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$5 = createSubsystemLogger("sessions/store");
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$5.info("pruned stale session entries", {
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$5.info("capped session entry count", {
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$5.info("rotated session store file", {
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$5.info("cleaned up old session store backups", { deleted: toDelete.length });
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$5.warn("session maintenance would evict active session; skipping enforcement", {
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$4 = createSubsystemLogger("agents/tool-images");
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/agents/auth-profiles/constants.ts
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$3 = createSubsystemLogger("agents/auth-profiles");
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$2 = createSubsystemLogger("agents/auth-profiles");
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$3.info(`synced ${provider} credentials from external cli`, {
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$3.info("synced qwen credentials from qwen cli", {
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/anthropic-direct-runner.ts
11236
+ //#region src/agents/gemini-direct-runner.ts
10069
11237
  /**
10070
- * Anthropic Direct API Runner
11238
+ * Gemini Direct API Runner
10071
11239
  *
10072
- * Makes calls directly to api.anthropic.com without needing the claude CLI
10073
- * binary to be installed or logged in. Works with any valid token:
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
- * sk-ant-api01-... (Console API key)
10076
- * sk-ant-oat01-... (Claude Code OAuth access token)
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/anthropic-direct");
11246
+ const log = createSubsystemLogger("agent/gemini-direct");
11247
+ const DEFAULT_GEMINI_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
10082
11248
  const MODEL_MAP = {
10083
- opus: "claude-opus-4-5",
10084
- "opus-4": "claude-opus-4-5",
10085
- "opus-4.5": "claude-opus-4-5",
10086
- "opus-4.6": "claude-opus-4-5",
10087
- "claude-opus-4-5": "claude-opus-4-5",
10088
- sonnet: "claude-sonnet-4-5",
10089
- "sonnet-4.5": "claude-sonnet-4-5",
10090
- "sonnet-4.1": "claude-sonnet-4-1-20250219",
10091
- "claude-sonnet-4-5": "claude-sonnet-4-5",
10092
- haiku: "claude-haiku-3-5",
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 = ".anima-history.json";
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 api.anthropic.com.
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 runAnthropicDirectAgent(params) {
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: `anthropic/${resolvedModel}`,
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
- messages: [],
11341
+ contents: [],
10174
11342
  createdAt: started,
10175
11343
  updatedAt: started
10176
11344
  };
10177
- history.messages.push({
11345
+ history.contents.push({
10178
11346
  role: "user",
10179
- content: params.prompt
11347
+ parts: [{ text: params.prompt }]
10180
11348
  });
10181
11349
  const requestBody = {
10182
- model: resolvedModel,
10183
- max_tokens: 8192,
10184
- system: systemPrompt,
10185
- messages: history.messages
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 response = await fetch("https://api.anthropic.com/v1/messages", {
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
- "x-api-key": params.token,
10194
- "anthropic-version": "2023-06-01",
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 ? " — token may be invalid or expired. Run: anima setup-token" : "";
10208
- log.error(`anthropic api error: HTTP ${response.status}${authHint}${rateHint}`, {
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 outputText = (data.content ?? []).filter((b) => b.type === "text" && typeof b.text === "string").map((b) => b.text).join("").trim();
10225
- if (!outputText) log.warn("anthropic direct: empty response", {
10226
- stopReason: data.stop_reason,
10227
- contentTypes: (data.content ?? []).map((b) => b.type)
10228
- });
10229
- await params.onAssistantMessageStart?.();
10230
- if (outputText && params.onPartialReply) await params.onPartialReply({ text: outputText });
10231
- history.messages.push({
10232
- role: "assistant",
10233
- content: outputText
10234
- });
10235
- history.updatedAt = Date.now();
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
- const inputTokens = data.usage?.input_tokens ?? 0;
10239
- const outputTokens = data.usage?.output_tokens ?? 0;
10240
- log.info(`direct api done: model=${resolvedModel} in=${inputTokens} out=${outputTokens} ms=${durationMs}`);
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: outputText,
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
- usage: {
10251
- inputTokens,
10252
- outputTokens,
10253
- cacheCreationInputTokens: 0,
10254
- cacheReadInputTokens: 0
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 && (err.name === "AbortError" || err.message.includes("aborted"));
10261
- log.error("anthropic direct runner error", { error: String(err) });
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: isAbort ? "timeout" : "failed",
11432
+ status: "failed",
10264
11433
  meta: {
10265
11434
  durationMs: Date.now() - started,
10266
11435
  error: {
10267
- message: isAbort ? `Request timed out after ${params.timeoutMs}ms` : String(err instanceof Error ? err.message : err),
10268
- kind: isAbort ? "timeout" : "unknown"
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", {