@code-yeongyu/senpi 2026.11.2-3 → 2026.11.3-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +55 -0
- package/dist/bundle/chunks/anthropic-messages-LJAKRKMX.js +11 -0
- package/dist/bundle/chunks/{args-AOI4NEA6.js → args-GQTXDYS3.js} +1 -1
- package/dist/bundle/chunks/{azure-openai-responses-YLBBQXI7.js → azure-openai-responses-HDEKTPMZ.js} +1 -1
- package/dist/bundle/chunks/chatgpt-subscription.js +10 -2
- package/dist/bundle/chunks/{chunk-ED7VJGL4.js → chunk-2PGSRQBF.js} +1 -1
- package/dist/bundle/chunks/{chunk-LMIETUPG.js → chunk-3LDASCJN.js} +1 -1
- package/dist/bundle/chunks/{chunk-PIAY636U.js → chunk-3QPE75AR.js} +1 -1
- package/dist/bundle/chunks/{chunk-FQZZGSYH.js → chunk-4ZGQUOBV.js} +1 -1
- package/dist/bundle/chunks/{chunk-S2M5D5GS.js → chunk-5BMIET5O.js} +2 -2
- package/dist/bundle/chunks/{chunk-XLLQJALL.js → chunk-67M7HKXO.js} +1 -1
- package/dist/bundle/chunks/chunk-6ISOXWH2.js +2 -0
- package/dist/bundle/chunks/{chunk-IWM5QRAE.js → chunk-6NPK2O3C.js} +2 -2
- package/dist/bundle/chunks/{chunk-FO56LSUK.js → chunk-7C4W5HMU.js} +1 -1
- package/dist/bundle/chunks/chunk-7KIHKE2T.js +2 -0
- package/dist/bundle/chunks/{chunk-BW4YXS7X.js → chunk-A4KOQUHT.js} +1 -1
- package/dist/bundle/chunks/{chunk-FJSJUVQQ.js → chunk-A5PZGQCP.js} +3 -3
- package/dist/bundle/chunks/{chunk-TBARMJ75.js → chunk-AVP6DDBF.js} +1 -1
- package/dist/bundle/chunks/{chunk-KVPRQ5KN.js → chunk-B3GTID4P.js} +1 -1
- package/dist/bundle/chunks/{chunk-2XBKE2BZ.js → chunk-BIWFWGUA.js} +1 -1
- package/dist/bundle/chunks/{chunk-6LDUM5CL.js → chunk-DCI4QOUX.js} +1 -1
- package/dist/bundle/chunks/{chunk-2YFPDNNP.js → chunk-DNZKKG4V.js} +1 -1
- package/dist/bundle/chunks/{chunk-W2V7RIBF.js → chunk-E7SA75PP.js} +1 -1
- package/dist/bundle/chunks/{chunk-YWD54RHU.js → chunk-EBZ6IP4V.js} +1 -1
- package/dist/bundle/chunks/{chunk-N4TSAHRL.js → chunk-EVTTLPIY.js} +1 -1
- package/dist/bundle/chunks/{chunk-J2OBN7TI.js → chunk-G5XUGK4B.js} +1 -1
- package/dist/bundle/chunks/{chunk-IHOQR7TU.js → chunk-GKP34H3C.js} +2 -2
- package/dist/bundle/chunks/{chunk-PP52OWBB.js → chunk-GLTOBXZY.js} +1 -1
- package/dist/bundle/chunks/{chunk-ZSVWKOAJ.js → chunk-IJGXAACA.js} +263 -237
- package/dist/bundle/chunks/{chunk-LGO25HPL.js → chunk-JCTODLUP.js} +1 -1
- package/dist/bundle/chunks/{chunk-3ESZE3DG.js → chunk-KHBCZ6TR.js} +1 -1
- package/dist/bundle/chunks/chunk-KJR3XXMI.js +2 -0
- package/dist/bundle/chunks/{chunk-TVMW2SUP.js → chunk-KY4V3TSO.js} +2 -2
- package/dist/bundle/chunks/{chunk-T5ZJ2Q4O.js → chunk-MCXOJHN2.js} +1 -1
- package/dist/bundle/chunks/{chunk-GIY7PGOH.js → chunk-NKI7L5UM.js} +3 -3
- package/dist/bundle/chunks/{chunk-L3V65XW7.js → chunk-OD7RT7G7.js} +1 -1
- package/dist/bundle/chunks/{chunk-NYXXKS6D.js → chunk-OOU3BRUY.js} +3 -2
- package/dist/bundle/chunks/{chunk-LPHUMR6R.js → chunk-OT6ALXSJ.js} +1 -1
- package/dist/bundle/chunks/{chunk-XGBRBCIQ.js → chunk-Q5CKFBQT.js} +1 -1
- package/dist/bundle/chunks/{chunk-F7GBSQRV.js → chunk-QPYDQ4QK.js} +1 -1
- package/dist/bundle/chunks/{chunk-7FUO655J.js → chunk-QSMT5KVJ.js} +1 -1
- package/dist/bundle/chunks/{chunk-SAZ6E74O.js → chunk-RUOTFZQR.js} +1 -1
- package/dist/bundle/chunks/chunk-RWF6IJQL.js +448 -0
- package/dist/bundle/chunks/{chunk-P4AT7SBE.js → chunk-S5Y7NEHB.js} +1 -1
- package/dist/bundle/chunks/{chunk-QLTQ3UUI.js → chunk-SCBTASM4.js} +1 -1
- package/dist/bundle/chunks/chunk-SJWTZ3Z2.js +2 -0
- package/dist/bundle/chunks/{chunk-ISZ4EWIS.js → chunk-SODMQEHO.js} +1 -1
- package/dist/bundle/chunks/{chunk-WEGTCUO3.js → chunk-SQAQEITV.js} +1 -1
- package/dist/bundle/chunks/{chunk-UFVZTQKN.js → chunk-TQQG5L4D.js} +1 -1
- package/dist/bundle/chunks/{chunk-662SCMTH.js → chunk-U6A4X3FV.js} +1 -1
- package/dist/bundle/chunks/{chunk-ACIFXWJ6.js → chunk-UHUM55TR.js} +1 -1
- package/dist/bundle/chunks/{chunk-L5OFGHDA.js → chunk-USKWGPA6.js} +1 -1
- package/dist/bundle/chunks/{chunk-7ORS33CE.js → chunk-VDDJADPV.js} +1 -1
- package/dist/bundle/chunks/{chunk-R65P6LAT.js → chunk-VIHXG53S.js} +1 -1
- package/dist/bundle/chunks/{chunk-SGS76663.js → chunk-VPVD5G32.js} +1 -1
- package/dist/bundle/chunks/chunk-WO6I5PRF.js +3 -0
- package/dist/bundle/chunks/{chunk-ETCYVVVO.js → chunk-WVEIJ437.js} +1 -1
- package/dist/bundle/chunks/{chunk-VRWJJMHO.js → chunk-XKFG4N3Z.js} +1 -1
- package/dist/bundle/chunks/{chunk-57MRFI6E.js → chunk-XMWPCJU6.js} +1 -1
- package/dist/bundle/chunks/{chunk-GDPWQJDQ.js → chunk-XPSXUKSD.js} +1 -1
- package/dist/bundle/chunks/{chunk-FNBEICAA.js → chunk-YI6KRJDC.js} +1 -1
- package/dist/bundle/chunks/{chunk-UURGXV5B.js → chunk-YP47G4YP.js} +1 -1
- package/dist/bundle/chunks/{chunk-TXOR5BQL.js → chunk-YRYDCKUI.js} +1 -1
- package/dist/bundle/chunks/{chunk-QAM6AXA2.js → chunk-YTKZSGMQ.js} +12 -9
- package/dist/bundle/chunks/{chunk-V36CXIIB.js → chunk-YXL3PNTL.js} +1 -1
- package/dist/bundle/chunks/chunk-Z7HTHT6K.js +2 -0
- package/dist/bundle/chunks/{chunk-27XEDYQA.js → chunk-ZTPG27EJ.js} +1 -1
- package/dist/bundle/chunks/{cli-main-534A3WSC.js → cli-main-RN7YB427.js} +1 -1
- package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-FC7QLRU2.js → cloudflare-workers-ai-system-one-N5KFNKK4.js} +1 -1
- package/dist/bundle/chunks/credential-accounts-BJX55MTT.js +2 -0
- package/dist/bundle/chunks/devin.js +10 -2
- package/dist/bundle/chunks/{dispatch-UY6LBJJE.js → dispatch-M7UAPGVY.js} +1 -1
- package/dist/bundle/chunks/{google-generative-ai-7PQ4QRHJ.js → google-generative-ai-2TZSCSIS.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-DY7EO4EJ.js → google-vertex-7NJJOI7V.js} +1 -1
- package/dist/bundle/chunks/{health-write-EB4CPHXN.js → health-write-YUSPVH7U.js} +1 -1
- package/dist/bundle/chunks/{help-fast-path-U2PSNNWO.js → help-fast-path-DWCA77QP.js} +1 -1
- package/dist/bundle/chunks/host-command-KJXUTSQ7.js +2 -0
- package/dist/bundle/chunks/{host-lifecycle-TGG7KGQH.js → host-lifecycle-QHIJ4G2K.js} +1 -1
- package/dist/bundle/chunks/host-lifecycle.js +1 -1
- package/dist/bundle/chunks/{host-session-command-PWVPQ2OV.js → host-session-command-IPH3WXSG.js} +1 -1
- package/dist/bundle/chunks/{host-socket-request-F2R5P34M.js → host-socket-request-XPXJV3CS.js} +1 -1
- package/dist/bundle/chunks/interactive-mode-XUXMDYLA.js +2 -0
- package/dist/bundle/chunks/{list-tips-3D3A6GFK.js → list-tips-XJY7EL5S.js} +1 -1
- package/dist/bundle/chunks/{login-health-7G2DZVOV.js → login-health-226NO44U.js} +1 -1
- package/dist/bundle/chunks/main-P7PKMJUG.js +2 -0
- package/dist/bundle/chunks/{mistral-conversations-6F2RAIB2.js → mistral-conversations-QMHMHSUF.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-7E26R5JF.js → multi-session-host-ZQY4AN46.js} +4 -4
- package/dist/bundle/chunks/{native-loader-NMDTMHMA.js → native-loader-A6DNMGCK.js} +1 -1
- package/dist/bundle/chunks/openai-chatgpt.js +11 -3
- package/dist/bundle/chunks/{openai-codex-responses-VNBMMIL3.js → openai-codex-responses-GUAHKQE2.js} +1 -1
- package/dist/bundle/chunks/{openai-completions-JLR32APM.js → openai-completions-UPRTFM54.js} +1 -1
- package/dist/bundle/chunks/{openai-images-LEBNERSM.js → openai-images-IKWNS6VB.js} +1 -1
- package/dist/bundle/chunks/{openai-responses-JCDUNMHA.js → openai-responses-AXN5NUHH.js} +1 -1
- package/dist/bundle/chunks/openrouter.js +10 -2
- package/dist/bundle/chunks/{package-manager-cli-CBSDV36M.js → package-manager-cli-PP7L2Q5M.js} +1 -1
- package/dist/bundle/chunks/radius.js +10 -2
- package/dist/bundle/chunks/{rg-engine-JDUYBM6L.js → rg-engine-VRSXT6HG.js} +1 -1
- package/dist/bundle/chunks/{role-LP6LVNCY.js → role-L5J7ZPCF.js} +1 -1
- package/dist/bundle/chunks/rotation-stream-6INZXQFC.js +2 -0
- package/dist/bundle/chunks/rpc-mode-W4UATRAT.js +2 -0
- package/dist/bundle/chunks/{rpc-monitor-source-5TUR27NY.js → rpc-monitor-source-RMMUPBMS.js} +1 -1
- package/dist/bundle/chunks/{run-attached-tui-PVLUHHJX.js → run-attached-tui-RLXFGCEP.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-W45NYTTK.js → schedule-command-ZNFEJNTT.js} +1 -1
- package/dist/bundle/chunks/{session-control-endpoint-LFLUNALC.js → session-control-endpoint-TWTONJWF.js} +1 -1
- package/dist/bundle/chunks/{session-picker-OZUINLD7.js → session-picker-KRUVCHOV.js} +1 -1
- package/dist/bundle/chunks/session-slot-NJOZCOHQ.js +2 -0
- package/dist/bundle/chunks/session-worker.js +492 -461
- package/dist/bundle/chunks/{state-store-SZARKD36.js → state-store-ZAFZ4JOM.js} +1 -1
- package/dist/bundle/chunks/{typesafe-system-one-5JYDJK6S.js → typesafe-system-one-CICIRAYN.js} +1 -1
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/host-supervisor.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/bundle/runtime-manifest.json +1 -1
- package/dist/core/agent-session.d.ts +8 -0
- package/dist/core/agent-session.js +73 -63
- package/dist/core/auth-storage.d.ts +19 -0
- package/dist/core/auth-storage.js +99 -24
- package/dist/core/auth-store-load-error.d.ts +29 -0
- package/dist/core/auth-store-load-error.js +74 -0
- package/dist/core/brand.d.ts +2 -0
- package/dist/core/brand.js +1 -0
- package/dist/core/credential-pool/classify.d.ts +3 -2
- package/dist/core/credential-pool/classify.js +10 -3
- package/dist/core/credential-pool/failover.d.ts +8 -0
- package/dist/core/credential-pool/failover.js +18 -5
- package/dist/core/credential-pool/rotation-stream.d.ts +1 -1
- package/dist/core/credential-pool/rotation-stream.js +2 -7
- package/dist/core/credential-pool/session-slot.d.ts +20 -0
- package/dist/core/credential-pool/session-slot.js +26 -0
- package/dist/core/credential-recovery-revision.d.ts +10 -0
- package/dist/core/credential-recovery-revision.js +19 -0
- package/dist/core/dynamic-prompt/build.d.ts +2 -1
- package/dist/core/dynamic-prompt/build.js +1 -2
- package/dist/core/dynamic-prompt/handoff.d.ts +1 -1
- package/dist/core/dynamic-prompt/handoff.js +9 -9
- package/dist/core/dynamic-prompt/identity.js +1 -1
- package/dist/core/dynamic-prompt/intent-gate.d.ts +1 -1
- package/dist/core/dynamic-prompt/intent-gate.js +8 -8
- package/dist/core/dynamic-prompt/policies.d.ts +1 -1
- package/dist/core/dynamic-prompt/policies.js +5 -7
- package/dist/core/dynamic-prompt/style.js +5 -5
- package/dist/core/dynamic-prompt/tool-section.d.ts +5 -0
- package/dist/core/dynamic-prompt/tool-section.js +8 -6
- package/dist/core/dynamic-prompt/verification.d.ts +6 -6
- package/dist/core/dynamic-prompt/verification.js +12 -12
- package/dist/core/dynamic-prompt/working-task.d.ts +1 -1
- package/dist/core/dynamic-prompt/working-task.js +3 -3
- package/dist/core/dynamic-prompt/workstation.js +1 -1
- package/dist/core/execution/executor-body.d.ts +22 -0
- package/dist/core/execution/executor-body.js +73 -0
- package/dist/core/execution/executor-freeze.d.ts +17 -0
- package/dist/core/execution/executor-freeze.js +53 -0
- package/dist/core/execution/executor-pipeline.d.ts +9 -0
- package/dist/core/execution/executor-pipeline.js +25 -0
- package/dist/core/execution/executor-types.d.ts +82 -0
- package/dist/core/execution/executor-types.js +2 -0
- package/dist/core/execution/executor.d.ts +8 -0
- package/dist/core/execution/executor.js +216 -0
- package/dist/core/extensions/builtin/anthropic-subscription/account-block-log.d.ts +15 -0
- package/dist/core/extensions/builtin/anthropic-subscription/account-block-log.js +18 -0
- package/dist/core/extensions/builtin/anthropic-subscription/affinity.d.ts +9 -1
- package/dist/core/extensions/builtin/anthropic-subscription/affinity.js +15 -4
- package/dist/core/extensions/builtin/anthropic-subscription/failover.d.ts +7 -1
- package/dist/core/extensions/builtin/anthropic-subscription/failover.js +19 -2
- package/dist/core/extensions/builtin/anthropic-subscription/guidance.d.ts +8 -2
- package/dist/core/extensions/builtin/anthropic-subscription/guidance.js +25 -1
- package/dist/core/extensions/builtin/anthropic-subscription/provider-diagnostic.d.ts +9 -0
- package/dist/core/extensions/builtin/anthropic-subscription/provider-diagnostic.js +59 -0
- package/dist/core/extensions/builtin/anthropic-subscription/session-registry-pump.d.ts +13 -0
- package/dist/core/extensions/builtin/anthropic-subscription/session-registry-pump.js +64 -2
- package/dist/core/extensions/builtin/anthropic-subscription/session-registry-wiring.js +7 -0
- package/dist/core/extensions/builtin/anthropic-subscription/session-stream.js +5 -1
- package/dist/core/extensions/builtin/anthropic-subscription/session-turn-attempt.d.ts +7 -0
- package/dist/core/extensions/builtin/anthropic-subscription/session-turn-attempt.js +28 -1
- package/dist/core/extensions/builtin/anthropic-subscription/session-turn-types.d.ts +2 -0
- package/dist/core/extensions/builtin/anthropic-subscription/stream-guidance.js +5 -3
- package/dist/core/extensions/builtin/anthropic-subscription/stream.js +4 -0
- package/dist/core/extensions/builtin/bash-timeout/index.d.ts +1 -1
- package/dist/core/extensions/builtin/bash-timeout/index.js +3 -28
- package/dist/core/extensions/builtin/bash-timeout/timeout.d.ts +0 -11
- package/dist/core/extensions/builtin/bash-timeout/timeout.js +0 -11
- package/dist/core/extensions/builtin/btw/index.js +3 -1
- package/dist/core/extensions/builtin/cache-keepalive/index.js +3 -1
- package/dist/core/extensions/builtin/compaction/index.js +1 -1
- package/dist/core/extensions/builtin/compaction/openai-remote.d.ts +3 -1
- package/dist/core/extensions/builtin/compaction/openai-remote.js +1 -1
- package/dist/core/extensions/builtin/compaction/speculative.js +3 -2
- package/dist/core/extensions/builtin/cursor-cli-oauth/account-command.js +3 -1
- package/dist/core/extensions/builtin/cursor-cli-oauth/native-bootstrap.js +3 -1
- package/dist/core/extensions/builtin/imagegen/index.d.ts +0 -1
- package/dist/core/extensions/builtin/imagegen/index.js +0 -11
- package/dist/core/extensions/builtin/look-at/runner.js +3 -1
- package/dist/core/extensions/builtin/mcp/auth/callback.js +3 -4
- package/dist/core/extensions/builtin/mcp/auth/oauth-provider.js +2 -1
- package/dist/core/extensions/builtin/prompt-preset/execution-tooling.d.ts +5 -5
- package/dist/core/extensions/builtin/prompt-preset/execution-tooling.js +5 -5
- package/dist/core/extensions/builtin/prompt-preset/glm-5.d.ts +1 -1
- package/dist/core/extensions/builtin/prompt-preset/glm-5.js +1 -1
- package/dist/core/extensions/builtin/terminal/extension.js +8 -1
- package/dist/core/extensions/builtin/terminal/notify.js +9 -3
- package/dist/core/extensions/builtin/terminal/prompt.d.ts +7 -1
- package/dist/core/extensions/builtin/terminal/prompt.js +27 -60
- package/dist/core/extensions/builtin/terminal/tools/bash.js +10 -2
- package/dist/core/extensions/builtin/todotools/normalize.d.ts +20 -3
- package/dist/core/extensions/builtin/todotools/normalize.js +251 -5
- package/dist/core/extensions/builtin/todotools/prompt.d.ts +2 -2
- package/dist/core/extensions/builtin/todotools/prompt.js +5 -5
- package/dist/core/extensions/builtin/todotools/tools/todo.js +9 -8
- package/dist/core/extensions/builtin/webfetch/webfetch/tool.js +0 -5
- package/dist/core/extensions/builtin/websearch/index.js +9 -4
- package/dist/core/extensions/builtin/websearch/websearch/tool.d.ts +2 -0
- package/dist/core/extensions/builtin/websearch/websearch/tool.js +3 -1
- package/dist/core/model-registry.d.ts +10 -2
- package/dist/core/model-registry.js +12 -4
- package/dist/core/model-runtime.d.ts +8 -0
- package/dist/core/model-runtime.js +39 -1
- package/dist/core/provider-failure.d.ts +6 -0
- package/dist/core/provider-failure.js +6 -2
- package/dist/core/retry-fallback/controller-types.d.ts +7 -0
- package/dist/core/retry-fallback/controller.d.ts +2 -0
- package/dist/core/retry-fallback/controller.js +13 -4
- package/dist/core/retry-fallback/credential-recovery.d.ts +18 -0
- package/dist/core/retry-fallback/credential-recovery.js +32 -0
- package/dist/core/retry-fallback/exhaustion.d.ts +18 -0
- package/dist/core/retry-fallback/exhaustion.js +20 -0
- package/dist/core/retry-fallback/settings.d.ts +8 -1
- package/dist/core/retry-fallback/settings.js +12 -6
- package/dist/core/session-log.js +1 -1
- package/dist/core/settings-manager.js +4 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/tools/bash.d.ts +3 -1
- package/dist/core/tools/bash.js +14 -4
- package/dist/core/tools/edit.d.ts +1 -1
- package/dist/core/tools/edit.js +1 -6
- package/dist/core/tools/grep/index.js +2 -3
- package/dist/core/tools/powershell.d.ts +1 -1
- package/dist/core/tools/powershell.js +1 -1
- package/dist/core/tools/read.d.ts +1 -1
- package/dist/core/tools/read.js +1 -1
- package/dist/core/tools/write.d.ts +1 -1
- package/dist/core/tools/write.js +1 -1
- package/dist/engine-trust/shell-trust.d.ts +36 -0
- package/dist/engine-trust/shell-trust.js +44 -0
- package/dist/engine-trust/transport-failure.d.ts +12 -0
- package/dist/engine-trust/transport-failure.js +48 -0
- package/dist/modes/interactive/interactive-mode.js +9 -3
- package/dist/modes/print-mode.js +2 -1
- package/dist/modes/rpc/compact-catalog-families.d.ts +5 -2
- package/dist/modes/rpc/compact-catalog-families.js +5 -2
- package/dist/modes/rpc/compact-catalog-registry.d.ts +9 -1
- package/dist/modes/rpc/compact-catalog-registry.js +9 -2
- package/dist/modes/rpc/compact-recovery-manifest-kinds.d.ts +17 -0
- package/dist/modes/rpc/compact-recovery-manifest-kinds.js +21 -0
- package/dist/modes/rpc/compact-recovery-manifest-shape.d.ts +7 -0
- package/dist/modes/rpc/compact-recovery-manifest.js +11 -3
- package/dist/modes/rpc/compact-socket-commands.js +6 -0
- package/dist/modes/rpc/connection-handler.js +24 -6
- package/dist/modes/rpc/connection-question-bridge.d.ts +3 -1
- package/dist/modes/rpc/connection-question-bridge.js +4 -1
- package/dist/modes/rpc/connection-roles.d.ts +8 -0
- package/dist/modes/rpc/connection-roles.js +18 -0
- package/dist/modes/rpc/effect-commands.d.ts +1 -0
- package/dist/modes/rpc/loopless-execute-grant.d.ts +20 -0
- package/dist/modes/rpc/loopless-execute-grant.js +26 -0
- package/dist/modes/rpc/loopless-runtime-settings.d.ts +30 -0
- package/dist/modes/rpc/loopless-runtime-settings.js +69 -0
- package/dist/modes/rpc/loopless-tool-call.d.ts +12 -0
- package/dist/modes/rpc/loopless-tool-call.js +22 -0
- package/dist/modes/rpc/method-classes-schema-session.d.ts +4 -0
- package/dist/modes/rpc/method-classes-schema-session.js +1 -0
- package/dist/modes/rpc/method-classes-schema.d.ts +4 -0
- package/dist/modes/rpc/protocol-identity.js +2 -0
- package/dist/modes/rpc/remote-origin.d.ts +31 -0
- package/dist/modes/rpc/remote-origin.js +58 -0
- package/dist/modes/rpc/rpc-protocol-info-types.d.ts +8 -0
- package/dist/modes/rpc/rpc-question-types.d.ts +7 -0
- package/dist/modes/rpc/rpc-question-types.js +0 -3
- package/dist/modes/rpc/rpc-read-response-types.d.ts +2 -1
- package/dist/modes/rpc/rpc-session-command-types.d.ts +3 -0
- package/dist/modes/rpc/rpc-session-state-types.d.ts +10 -0
- package/dist/modes/rpc/rpc-types.d.ts +1 -1
- package/dist/modes/rpc/runtime-factory-loopless.d.ts +57 -0
- package/dist/modes/rpc/runtime-factory-loopless.js +131 -0
- package/dist/modes/rpc/session-registry.js +12 -3
- package/dist/modes/rpc/session-worker-client.js +2 -0
- package/dist/modes/rpc/session-worker-protocol.d.ts +3 -0
- package/dist/modes/rpc/session-worker.js +2 -0
- package/docs/development.md +1 -1
- package/docs/engine-socket/fixtures/admission-routes/c-baseline.json +3 -3
- package/docs/engine-socket/fixtures/admission-routes/h-legacy.json +1 -1
- package/docs/engine-socket/fixtures/admission-routes/i-reset-stream.json +3 -3
- package/docs/engine-socket/fixtures/recovery-manifest/index.json +32 -0
- package/docs/engine-socket/fixtures/recovery-manifest/one-partial-family.json +118 -0
- package/docs/rpc.md +95 -3
- package/package.json +6 -6
- package/dist/bundle/chunks/anthropic-messages-WUPLDYD6.js +0 -10
- package/dist/bundle/chunks/chunk-7UC4W2T2.js +0 -2
- package/dist/bundle/chunks/chunk-O4GRBX4R.js +0 -3
- package/dist/bundle/chunks/chunk-R23WXN4L.js +0 -448
- package/dist/bundle/chunks/chunk-W5NLCRB3.js +0 -2
- package/dist/bundle/chunks/credential-accounts-OAK2E5O2.js +0 -2
- package/dist/bundle/chunks/host-command-WJIMRBGN.js +0 -2
- package/dist/bundle/chunks/interactive-mode-NPHFDPGH.js +0 -2
- package/dist/bundle/chunks/main-I6FJAFUP.js +0 -2
- package/dist/bundle/chunks/rotation-stream-ZDCNHIBE.js +0 -2
- package/dist/bundle/chunks/rpc-mode-GBBTN2WP.js +0 -2
|
@@ -51,6 +51,7 @@ import { CompactionLifecycleCoordinator } from "./compaction/lifecycle.js";
|
|
|
51
51
|
import { isTurnStuckOnContextOverflow } from "./compaction/stuck-overflow.js";
|
|
52
52
|
import { isWarmSummaryAnchorValid } from "./compaction/warm-anchor.js";
|
|
53
53
|
import { CONTINUE_FROM_LEAF_CUSTOM_TYPE, CONTINUE_FROM_LEAF_DIRECTIVE, ContinueFromLeafError, trackTurnAdmission, } from "./continue-from-leaf.js";
|
|
54
|
+
import { credentialRecoveryRevision } from "./credential-recovery-revision.js";
|
|
54
55
|
import { admitCursorHistory, cursorAdmissionBudgetBytes } from "./cursor-history-admission.js";
|
|
55
56
|
import { DEFAULT_THINKING_LEVEL } from "./defaults.js";
|
|
56
57
|
import { resolveDiscoveredResourcePaths } from "./discovered-resource-scope.js";
|
|
@@ -128,6 +129,7 @@ import { createModelConfigErrorReporter, isModelConfigFailure, } from "./retry-f
|
|
|
128
129
|
import { ProbeBackScheduler } from "./retry-fallback/probe-scheduler.js";
|
|
129
130
|
import { REQUEST_SHAPE_FAILURE_TEXT, REQUEST_SHAPE_RECOVERY_ENTRY_TYPE, REQUEST_SHAPE_RECOVERY_NOTE, RequestShapeRecovery, } from "./retry-fallback/request-shape.js";
|
|
130
131
|
import { AccountUsageLimitError, describeUsageLimitEntry, describeUsageLimitMessage, usageLimitScope, } from "./retry-fallback/usage-limit.js";
|
|
132
|
+
import { recordRungFailure } from "./retry-fallback/exhaustion.js";
|
|
131
133
|
import { validateFallbackChains } from "./retry-fallback/validate.js";
|
|
132
134
|
import { RunHolds } from "./run-holds.js";
|
|
133
135
|
import { startRunResumeTurn } from "./run-resume-turn.js";
|
|
@@ -610,6 +612,8 @@ export class AgentSession {
|
|
|
610
612
|
this._userActivity = createUserActivitySource();
|
|
611
613
|
this._extensionMode = "print";
|
|
612
614
|
this._providerRequiredNoticed = false;
|
|
615
|
+
// Every rung that failed this turn, in order: the exhaustion event leads with the first (senpi#4084).
|
|
616
|
+
this._fallbackTurnFailures = [];
|
|
613
617
|
this._probeBackLaneSeq = 0;
|
|
614
618
|
// Tool registry for extension getTools/setTools
|
|
615
619
|
this._toolRegistry = new Map();
|
|
@@ -901,6 +905,7 @@ export class AgentSession {
|
|
|
901
905
|
emit: (event) => this._emit(event),
|
|
902
906
|
getCurrentSelector: () => (this.model ? { model: this.model, thinkingLevel: this.thinkingLevel } : undefined),
|
|
903
907
|
isAuthAvailable: (provider) => this._modelRuntime.hasConfiguredAuth(provider),
|
|
908
|
+
recoveryRevision: (provider) => credentialRecoveryRevision(this._modelRuntime.authStorage, provider),
|
|
904
909
|
});
|
|
905
910
|
this._unfollowProviderAccountChanges = followProviderAccountChanges(this._retryFallback);
|
|
906
911
|
this._probeBackScheduler = new ProbeBackScheduler({
|
|
@@ -1749,6 +1754,16 @@ export class AgentSession {
|
|
|
1749
1754
|
this.agent.state.messages = this.sessionManager.buildSessionContext().messages;
|
|
1750
1755
|
this._emitEntryAppended(entry.id);
|
|
1751
1756
|
}
|
|
1757
|
+
_emitFallbackExhausted(chainKey, lastError) {
|
|
1758
|
+
const failures = [...this._fallbackTurnFailures];
|
|
1759
|
+
const primaryError = failures[0];
|
|
1760
|
+
this._emit({
|
|
1761
|
+
type: "retry_fallback_exhausted",
|
|
1762
|
+
chainKey,
|
|
1763
|
+
lastError,
|
|
1764
|
+
...(primaryError === undefined ? {} : { primaryError, failures }),
|
|
1765
|
+
});
|
|
1766
|
+
}
|
|
1752
1767
|
_emit(event, captureSource = event) {
|
|
1753
1768
|
this._recoveryIdentity?.observe(event);
|
|
1754
1769
|
const produced = event;
|
|
@@ -1761,11 +1776,8 @@ export class AgentSession {
|
|
|
1761
1776
|
if (event.type === "entry_appended") {
|
|
1762
1777
|
event = { ...event, entry: describeUsageLimitEntry(event.entry) };
|
|
1763
1778
|
}
|
|
1764
|
-
if (event.type === "retry_fallback_exhausted"
|
|
1765
|
-
event =
|
|
1766
|
-
...event,
|
|
1767
|
-
lastError: new AccountUsageLimitError(this.model?.provider ?? "", event.lastError).message,
|
|
1768
|
-
};
|
|
1779
|
+
if (event.type === "retry_fallback_exhausted") {
|
|
1780
|
+
event = describeExhaustedFailures(event, this.model?.provider ?? "");
|
|
1769
1781
|
}
|
|
1770
1782
|
if (event.type === "agent_end") {
|
|
1771
1783
|
event = {
|
|
@@ -2556,6 +2568,7 @@ export class AgentSession {
|
|
|
2556
2568
|
if (event.type === "message_start" && event.message.role === "user") {
|
|
2557
2569
|
this._overflowRecoveryRungs = 0;
|
|
2558
2570
|
this._retryFallback.resetTurn();
|
|
2571
|
+
this._fallbackTurnFailures = [];
|
|
2559
2572
|
const messageText = userMessageText(event.message.content);
|
|
2560
2573
|
// Image-only input has no text to match: find it by the message the queue handed to the agent (#3592).
|
|
2561
2574
|
const imageOnlyQueued = messageText
|
|
@@ -4107,7 +4120,10 @@ export class AgentSession {
|
|
|
4107
4120
|
const promptGuidelines = [];
|
|
4108
4121
|
for (const name of contributingToolNames) {
|
|
4109
4122
|
const snippet = this._toolPromptSnippets.get(name);
|
|
4110
|
-
|
|
4123
|
+
// A model-facing tool whose schema description the model already reads gets no snippet line;
|
|
4124
|
+
// withheld eval-only tools keep theirs (senpi#5335).
|
|
4125
|
+
const describedToModel = validToolNames.includes(name) && (this._toolRegistry.get(name)?.description.trim() ?? "") !== "";
|
|
4126
|
+
if (snippet && !describedToModel) {
|
|
4111
4127
|
toolSnippets[name] = snippet;
|
|
4112
4128
|
}
|
|
4113
4129
|
const toolGuidelines = this._toolPromptGuidelines.get(name);
|
|
@@ -4130,38 +4146,40 @@ export class AgentSession {
|
|
|
4130
4146
|
customPrompt: loaderSystemPrompt,
|
|
4131
4147
|
appendSystemPrompt: loaderAppendSystemPrompt.length > 0 ? loaderAppendSystemPrompt.join("\n\n") : undefined,
|
|
4132
4148
|
};
|
|
4149
|
+
const evalOnlyArmed = this._isEvalOnlyPolicyArmed();
|
|
4150
|
+
const armed = evalOnlyArmed ? (this._evalOnlyToolNames ?? new Set()) : new Set();
|
|
4151
|
+
const registered = new Set([...armed].filter((name) => this._toolRegistry.has(name)));
|
|
4152
|
+
// The eval-only paragraph below states the grep rule for this render, so the grep snippet that
|
|
4153
|
+
// renders the eval-only grep guideline stays out of it (senpi#5335).
|
|
4154
|
+
const { grep: _grepSnippet, ...snippetsWithoutGrep } = toolSnippets;
|
|
4133
4155
|
const prompt = buildDynamicSystemPrompt({
|
|
4134
4156
|
...this._baseSystemPromptOptions,
|
|
4157
|
+
...(registered.has("grep") ? { toolSnippets: snippetsWithoutGrep } : {}),
|
|
4135
4158
|
onParts: (parts) => {
|
|
4136
4159
|
this._baseSystemPromptParts = parts;
|
|
4137
4160
|
},
|
|
4138
4161
|
});
|
|
4139
|
-
if (!
|
|
4162
|
+
if (!evalOnlyArmed)
|
|
4140
4163
|
return prompt;
|
|
4141
|
-
const
|
|
4142
|
-
const registered = new Set([...armed].filter((name) => this._toolRegistry.has(name)));
|
|
4143
|
-
const sentences = [];
|
|
4164
|
+
const helpers = [];
|
|
4144
4165
|
const shellHelpers = ["bash", "powershell"].filter((name) => registered.has(name)).map(evalHelperCall);
|
|
4145
|
-
if (shellHelpers.length > 0)
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
sentences.push(`The workflow tool runs ONLY inside eval cells via ${evalHelperCall("workflow")}; hooks and permissions still apply.`);
|
|
4150
|
-
}
|
|
4166
|
+
if (shellHelpers.length > 0)
|
|
4167
|
+
helpers.push(`${shellHelpers.join(" / ")} shell`);
|
|
4168
|
+
if (registered.has("workflow"))
|
|
4169
|
+
helpers.push(evalHelperCall("workflow"));
|
|
4151
4170
|
// Declared tools and SDK overrides outside the built-in groups still need eval guidance.
|
|
4152
|
-
|
|
4171
|
+
helpers.push(...[...registered]
|
|
4153
4172
|
.filter((name) => name !== "bash" && name !== "powershell" && name !== "workflow" && name !== "grep" && name !== "glob")
|
|
4154
|
-
.map(evalHelperCall);
|
|
4155
|
-
if (otherHelpers.length > 0) {
|
|
4156
|
-
sentences.push(`These tools run ONLY inside eval cells via ${otherHelpers.join(" or ")}; hooks and permissions still apply.`);
|
|
4157
|
-
}
|
|
4173
|
+
.map(evalHelperCall));
|
|
4158
4174
|
if (registered.has("glob")) {
|
|
4159
|
-
|
|
4175
|
+
helpers.push(`${evalHelperCall("glob")} file-name search (glob like **/*.ts, respects .gitignore; over find/ls)`);
|
|
4160
4176
|
}
|
|
4161
4177
|
if (registered.has("grep")) {
|
|
4162
|
-
|
|
4178
|
+
helpers.push(`${evalHelperCall("grep")} text search (structured, respects .gitignore; over rg/grep; page full -> skip, narrow with glob/path)`);
|
|
4163
4179
|
}
|
|
4164
|
-
return
|
|
4180
|
+
return helpers.length > 0
|
|
4181
|
+
? `${prompt}\n\nEval-only tools (hooks + permissions still apply): ${helpers.join("; ")}.`
|
|
4182
|
+
: prompt;
|
|
4165
4183
|
}
|
|
4166
4184
|
/**
|
|
4167
4185
|
* Run `input` extension handlers for queued (steer / follow-up) input.
|
|
@@ -4481,6 +4499,7 @@ export class AgentSession {
|
|
|
4481
4499
|
const model = this.model;
|
|
4482
4500
|
if (model && !this._pendingModelSwitch && this._retryFallback.isProviderSpent(model.provider)) {
|
|
4483
4501
|
this._retryFallback.resetTurn();
|
|
4502
|
+
this._fallbackTurnFailures = [];
|
|
4484
4503
|
const errorMessage = this._retryFallback.accountError(model.provider);
|
|
4485
4504
|
// Routing around a remembered failure did not observe another provider failure.
|
|
4486
4505
|
if (!(await this._retryFallback.tryFallback("transient", { errorMessage }, false))) {
|
|
@@ -10427,11 +10446,7 @@ export class AgentSession {
|
|
|
10427
10446
|
const finishRetryAttempt = (attempt, finalError) => {
|
|
10428
10447
|
const exhaustedChainKey = this._retryFallback.exhaustedChainKey;
|
|
10429
10448
|
if (exhaustedChainKey) {
|
|
10430
|
-
this.
|
|
10431
|
-
type: "retry_fallback_exhausted",
|
|
10432
|
-
chainKey: exhaustedChainKey,
|
|
10433
|
-
lastError: errorMessage,
|
|
10434
|
-
});
|
|
10449
|
+
this._emitFallbackExhausted(exhaustedChainKey, errorMessage);
|
|
10435
10450
|
}
|
|
10436
10451
|
this._emit({
|
|
10437
10452
|
type: "auto_retry_end",
|
|
@@ -10494,6 +10509,11 @@ export class AgentSession {
|
|
|
10494
10509
|
let is429TierRouted = false;
|
|
10495
10510
|
let hintTierDelayMs;
|
|
10496
10511
|
const tryFallback = async (reason, failure) => {
|
|
10512
|
+
recordRungFailure(this._fallbackTurnFailures, {
|
|
10513
|
+
model: `${message.provider}/${message.model}`,
|
|
10514
|
+
reason,
|
|
10515
|
+
error: errorMessage,
|
|
10516
|
+
});
|
|
10497
10517
|
try {
|
|
10498
10518
|
return await this._retryFallback.tryFallback(reason, failure);
|
|
10499
10519
|
}
|
|
@@ -10513,7 +10533,7 @@ export class AgentSession {
|
|
|
10513
10533
|
if (!switchedFallback) {
|
|
10514
10534
|
const chainKey = this._retryFallback.exhaustedChainKey;
|
|
10515
10535
|
if (chainKey)
|
|
10516
|
-
this.
|
|
10536
|
+
this._emitFallbackExhausted(chainKey, errorMessage);
|
|
10517
10537
|
if (this._retryAttempt > 0) {
|
|
10518
10538
|
this._emit({
|
|
10519
10539
|
type: "auto_retry_end",
|
|
@@ -10570,11 +10590,7 @@ export class AgentSession {
|
|
|
10570
10590
|
if (!switchedFallback) {
|
|
10571
10591
|
const exhaustedChainKey = this._retryFallback.exhaustedChainKey;
|
|
10572
10592
|
if (exhaustedChainKey) {
|
|
10573
|
-
this.
|
|
10574
|
-
type: "retry_fallback_exhausted",
|
|
10575
|
-
chainKey: exhaustedChainKey,
|
|
10576
|
-
lastError: errorMessage,
|
|
10577
|
-
});
|
|
10593
|
+
this._emitFallbackExhausted(exhaustedChainKey, errorMessage);
|
|
10578
10594
|
}
|
|
10579
10595
|
this._resolveRetry();
|
|
10580
10596
|
return "not-handled";
|
|
@@ -10604,11 +10620,7 @@ export class AgentSession {
|
|
|
10604
10620
|
if (!switchedFallback) {
|
|
10605
10621
|
const exhaustedChainKey = this._retryFallback.exhaustedChainKey;
|
|
10606
10622
|
if (exhaustedChainKey) {
|
|
10607
|
-
this.
|
|
10608
|
-
type: "retry_fallback_exhausted",
|
|
10609
|
-
chainKey: exhaustedChainKey,
|
|
10610
|
-
lastError: errorMessage,
|
|
10611
|
-
});
|
|
10623
|
+
this._emitFallbackExhausted(exhaustedChainKey, errorMessage);
|
|
10612
10624
|
}
|
|
10613
10625
|
if (this._retryAttempt > 0) {
|
|
10614
10626
|
this._emit({
|
|
@@ -10669,11 +10681,7 @@ export class AgentSession {
|
|
|
10669
10681
|
else {
|
|
10670
10682
|
const exhaustedChainKey = this._retryFallback.exhaustedChainKey;
|
|
10671
10683
|
if (exhaustedChainKey) {
|
|
10672
|
-
this.
|
|
10673
|
-
type: "retry_fallback_exhausted",
|
|
10674
|
-
chainKey: exhaustedChainKey,
|
|
10675
|
-
lastError: errorMessage,
|
|
10676
|
-
});
|
|
10684
|
+
this._emitFallbackExhausted(exhaustedChainKey, errorMessage);
|
|
10677
10685
|
}
|
|
10678
10686
|
this._emit({
|
|
10679
10687
|
type: "auto_retry_end",
|
|
@@ -10721,11 +10729,7 @@ export class AgentSession {
|
|
|
10721
10729
|
else {
|
|
10722
10730
|
const exhaustedChainKey = this._retryFallback.exhaustedChainKey;
|
|
10723
10731
|
if (exhaustedChainKey) {
|
|
10724
|
-
this.
|
|
10725
|
-
type: "retry_fallback_exhausted",
|
|
10726
|
-
chainKey: exhaustedChainKey,
|
|
10727
|
-
lastError: errorMessage,
|
|
10728
|
-
});
|
|
10732
|
+
this._emitFallbackExhausted(exhaustedChainKey, errorMessage);
|
|
10729
10733
|
}
|
|
10730
10734
|
this._emit({
|
|
10731
10735
|
type: "auto_retry_end",
|
|
@@ -10762,11 +10766,7 @@ export class AgentSession {
|
|
|
10762
10766
|
else {
|
|
10763
10767
|
const exhaustedChainKey = this._retryFallback.exhaustedChainKey;
|
|
10764
10768
|
if (exhaustedChainKey) {
|
|
10765
|
-
this.
|
|
10766
|
-
type: "retry_fallback_exhausted",
|
|
10767
|
-
chainKey: exhaustedChainKey,
|
|
10768
|
-
lastError: errorMessage,
|
|
10769
|
-
});
|
|
10769
|
+
this._emitFallbackExhausted(exhaustedChainKey, errorMessage);
|
|
10770
10770
|
}
|
|
10771
10771
|
this._emit({
|
|
10772
10772
|
type: "auto_retry_end",
|
|
@@ -10822,11 +10822,7 @@ export class AgentSession {
|
|
|
10822
10822
|
else {
|
|
10823
10823
|
const exhaustedChainKey = this._retryFallback.exhaustedChainKey;
|
|
10824
10824
|
if (exhaustedChainKey) {
|
|
10825
|
-
this.
|
|
10826
|
-
type: "retry_fallback_exhausted",
|
|
10827
|
-
chainKey: exhaustedChainKey,
|
|
10828
|
-
lastError: errorMessage,
|
|
10829
|
-
});
|
|
10825
|
+
this._emitFallbackExhausted(exhaustedChainKey, errorMessage);
|
|
10830
10826
|
}
|
|
10831
10827
|
this._emit({
|
|
10832
10828
|
type: "auto_retry_end",
|
|
@@ -11109,8 +11105,8 @@ export class AgentSession {
|
|
|
11109
11105
|
else {
|
|
11110
11106
|
// Add to agent state immediately
|
|
11111
11107
|
this.agent.state.messages.push(bashMessage);
|
|
11112
|
-
// Save to session
|
|
11113
|
-
this.sessionManager.appendMessage(bashMessage);
|
|
11108
|
+
// Save to session; every RPC observer learns of it the way it learns of any persisted entry (senpi#5576).
|
|
11109
|
+
this._emitEntryAppended(this.sessionManager.appendMessage(bashMessage));
|
|
11114
11110
|
this._incrementMessageRevision();
|
|
11115
11111
|
}
|
|
11116
11112
|
}
|
|
@@ -11145,7 +11141,7 @@ export class AgentSession {
|
|
|
11145
11141
|
// Add to agent state
|
|
11146
11142
|
this.agent.state.messages.push(bashMessage);
|
|
11147
11143
|
// Save to session
|
|
11148
|
-
this.sessionManager.appendMessage(bashMessage);
|
|
11144
|
+
this._emitEntryAppended(this.sessionManager.appendMessage(bashMessage));
|
|
11149
11145
|
this._incrementMessageRevision();
|
|
11150
11146
|
}
|
|
11151
11147
|
this._pendingBashMessages = [];
|
|
@@ -11802,4 +11798,18 @@ function messageFingerprint(message) {
|
|
|
11802
11798
|
const requestContext = usage?.contextUsage;
|
|
11803
11799
|
return `${size}:${usage?.input ?? ""}:${usage?.output ?? ""}:${usage?.totalTokens ?? ""}:${requestContext?.input}:${requestContext?.output}:${requestContext === null}`;
|
|
11804
11800
|
}
|
|
11801
|
+
// Clients see each rung's provider text through the same account-limit description as `lastError`.
|
|
11802
|
+
function describeExhaustedFailures(event, currentProvider) {
|
|
11803
|
+
const describe = (error, provider) => usageLimitScope(error) === "account" ? new AccountUsageLimitError(provider, error).message : error;
|
|
11804
|
+
const failures = event.failures?.map((failure) => ({
|
|
11805
|
+
...failure,
|
|
11806
|
+
error: describe(failure.error, failure.model.slice(0, Math.max(0, failure.model.indexOf("/")))),
|
|
11807
|
+
}));
|
|
11808
|
+
const primaryError = failures?.[0];
|
|
11809
|
+
return {
|
|
11810
|
+
...event,
|
|
11811
|
+
lastError: describe(event.lastError, currentProvider),
|
|
11812
|
+
...(failures === undefined || primaryError === undefined ? {} : { failures, primaryError }),
|
|
11813
|
+
};
|
|
11814
|
+
}
|
|
11805
11815
|
//# sourceMappingURL=agent-session.js.map
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import type { ApiKeyCredential, AuthOperationOptions, Credential, CredentialInfo, CredentialStore, OAuthAuth, OAuthCredential, OAuthLoginCallbacks } from "@earendil-works/pi-ai";
|
|
6
6
|
import { type CredentialKind } from "@earendil-works/pi-ai/auth/pool/kinds";
|
|
7
7
|
import { type CredentialSlot } from "@earendil-works/pi-ai/auth/pool/slots";
|
|
8
|
+
import { type AuthStoreLoadError } from "./auth-store-load-error.ts";
|
|
8
9
|
type AuthStorageData = Record<string, Credential>;
|
|
9
10
|
/** A credential problem the user should see once per change: `id` changes when the problem does. */
|
|
10
11
|
export type AuthNotice = {
|
|
@@ -101,6 +102,7 @@ export declare class AuthStorage implements CredentialStore {
|
|
|
101
102
|
private busyReads;
|
|
102
103
|
private dataLoaded;
|
|
103
104
|
private dataFromBusyRead;
|
|
105
|
+
private loadError;
|
|
104
106
|
private constructor();
|
|
105
107
|
static create(authPath?: string): AuthStorage;
|
|
106
108
|
getStoragePath(): string | undefined;
|
|
@@ -125,6 +127,10 @@ export declare class AuthStorage implements CredentialStore {
|
|
|
125
127
|
*/
|
|
126
128
|
private backupAuthFile;
|
|
127
129
|
private updateReadState;
|
|
130
|
+
/** The shared read state holds the store's current contents: this instance answers from it again. */
|
|
131
|
+
private adoptReadState;
|
|
132
|
+
/** A sync write that parsed and saved the locked store proves it loads again. */
|
|
133
|
+
private writeLocked;
|
|
128
134
|
/**
|
|
129
135
|
* Reload credentials from storage.
|
|
130
136
|
*/
|
|
@@ -135,6 +141,17 @@ export declare class AuthStorage implements CredentialStore {
|
|
|
135
141
|
* store, or a busy read after a successful load, is not busy.
|
|
136
142
|
*/
|
|
137
143
|
isCredentialStoreBusy(): boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Why the store could not be loaded on its last read, or undefined once any read or write of this
|
|
146
|
+
* instance finds it good again (senpi#4413). While set, the in-memory credentials are not the store's
|
|
147
|
+
* contents; a store that cannot be read or parsed also refuses every write.
|
|
148
|
+
*/
|
|
149
|
+
getLoadError(): AuthStoreLoadError | undefined;
|
|
150
|
+
/**
|
|
151
|
+
* Records a failed read; returns false when it repeats the load error already reported, so a store
|
|
152
|
+
* that stays broken is not re-recorded on every status read that retries it.
|
|
153
|
+
*/
|
|
154
|
+
private noteLoadFailure;
|
|
138
155
|
/**
|
|
139
156
|
* Monotonic count of reads (sync or async) that found the store locked before it ever
|
|
140
157
|
* loaded and answered with the empty placeholder. A change across an operation means
|
|
@@ -176,6 +193,7 @@ export declare class AuthStorage implements CredentialStore {
|
|
|
176
193
|
private noteReplacement;
|
|
177
194
|
remove(provider: string): void;
|
|
178
195
|
listSlots(provider: string): CredentialSlot[];
|
|
196
|
+
/** Adding a new slot is a sign-in and stamps a fresh `loginId`; updating an existing slot keeps it (senpi#4099). */
|
|
179
197
|
setSlot(provider: string, slot: CredentialSlot): void;
|
|
180
198
|
removeSlot(provider: string, name: string): void;
|
|
181
199
|
has(provider: string): boolean;
|
|
@@ -184,6 +202,7 @@ export declare class AuthStorage implements CredentialStore {
|
|
|
184
202
|
getAll(): AuthStorageData;
|
|
185
203
|
drainErrors(): Error[];
|
|
186
204
|
private reloadFromStorageAsync;
|
|
205
|
+
private reloadLockedAsync;
|
|
187
206
|
private readLatestData;
|
|
188
207
|
read(provider: string, options?: AuthOperationOptions): Promise<Credential | undefined>;
|
|
189
208
|
readSlot(provider: string, slotName: string, options?: AuthOperationOptions): Promise<Credential | undefined>;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { findEnvKeys, getEnvApiKey, readByProviderId } from "@earendil-works/pi-ai";
|
|
6
6
|
import { slotKind, unusedSlotKinds } from "@earendil-works/pi-ai/auth/pool/kinds";
|
|
7
|
+
import { stampLogin } from "@earendil-works/pi-ai/auth/pool/login-id";
|
|
7
8
|
import { appendLoginSlot, listSlots, projectSlot, removeSlot, repairManagedSentinelSlots, upsertSlot, } from "@earendil-works/pi-ai/auth/pool/slots";
|
|
8
9
|
import { builtinProviders } from "@earendil-works/pi-ai/providers/all";
|
|
9
10
|
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "fs";
|
|
@@ -16,6 +17,7 @@ import { stripBom } from "../utils/text.js";
|
|
|
16
17
|
import { signOutLegacyClaudeLogins } from "./anthropic-legacy-sign-out.js";
|
|
17
18
|
import { resolveReadOnlyCredential, resolveStoredCredential, resolveStoredSlot, validateReadOnlyAuthData, } from "./auth-credential-values.js";
|
|
18
19
|
import { migrateLegacyProviderKeys } from "./auth-provider-key-migration.js";
|
|
20
|
+
import { describeAuthStoreLoadFailure, failureAfterRead, parseAuthDocument, } from "./auth-store-load-error.js";
|
|
19
21
|
import { ANTHROPIC_SUBSCRIPTION_PROVIDER_ID } from "./extensions/builtin/anthropic-subscription/provider-id.js";
|
|
20
22
|
import { signInAgainMessage, signInRequiredNames } from "./extensions/builtin/anthropic-subscription/sign-in-again.js";
|
|
21
23
|
import { lockWithLossHandling } from "./file-lock.js";
|
|
@@ -392,7 +394,7 @@ export class AuthStorage {
|
|
|
392
394
|
// Mutation paths keep the stored keys as-is: the key migration (and its
|
|
393
395
|
// pre-write backup) belongs to the load seam, so a write can never drop a
|
|
394
396
|
// legacy entry without the backup that preserves it.
|
|
395
|
-
return repairPoisonedPoolSlots(
|
|
397
|
+
return repairPoisonedPoolSlots(parseAuthDocument(content)).data;
|
|
396
398
|
}
|
|
397
399
|
/**
|
|
398
400
|
* Reports whether the parse healed poisoned pool slots or moved legacy
|
|
@@ -406,7 +408,7 @@ export class AuthStorage {
|
|
|
406
408
|
if (!content) {
|
|
407
409
|
return { data: {}, repaired: false, migrated: false };
|
|
408
410
|
}
|
|
409
|
-
const repaired = repairPoisonedPoolSlots(
|
|
411
|
+
const repaired = repairPoisonedPoolSlots(parseAuthDocument(content));
|
|
410
412
|
const migrated = migrateLegacyProviderKeys(repaired.data);
|
|
411
413
|
const moved = signOutLegacyClaudeLogins(migrated.data);
|
|
412
414
|
if (moved.skipped && !this.reportedMigrationSkips.has(moved.skipped)) {
|
|
@@ -444,19 +446,37 @@ export class AuthStorage {
|
|
|
444
446
|
this.data = data;
|
|
445
447
|
this.dataLoaded = true;
|
|
446
448
|
this.dataFromBusyRead = false;
|
|
449
|
+
this.loadError = undefined;
|
|
447
450
|
this.readState.data = data;
|
|
448
451
|
this.readState.loaded = true;
|
|
449
452
|
this.readState.revision = revision;
|
|
450
453
|
}
|
|
454
|
+
/** The shared read state holds the store's current contents: this instance answers from it again. */
|
|
455
|
+
adoptReadState(data) {
|
|
456
|
+
this.data = data;
|
|
457
|
+
this.dataLoaded = true;
|
|
458
|
+
this.dataFromBusyRead = false;
|
|
459
|
+
this.loadError = undefined;
|
|
460
|
+
return data;
|
|
461
|
+
}
|
|
462
|
+
/** A sync write that parsed and saved the locked store proves it loads again. */
|
|
463
|
+
writeLocked(fn) {
|
|
464
|
+
const result = this.storage.withLock(fn);
|
|
465
|
+
this.loadError = undefined;
|
|
466
|
+
return result;
|
|
467
|
+
}
|
|
451
468
|
/**
|
|
452
469
|
* Reload credentials from storage.
|
|
453
470
|
*/
|
|
454
471
|
reload() {
|
|
455
472
|
let data = {};
|
|
456
473
|
let revision;
|
|
474
|
+
const load = { parsed: false, writeBack: false };
|
|
457
475
|
try {
|
|
458
476
|
this.storage.withLock((current) => {
|
|
459
477
|
const parsed = this.parseStorageContent(current);
|
|
478
|
+
load.parsed = true;
|
|
479
|
+
load.writeBack = parsed.repaired || parsed.migrated;
|
|
460
480
|
data = parsed.data;
|
|
461
481
|
// A written repair or migration invalidates the revision read before
|
|
462
482
|
// it; leaving it unset makes the next reader re-read instead of
|
|
@@ -472,9 +492,17 @@ export class AuthStorage {
|
|
|
472
492
|
this.updateReadState(data, revision);
|
|
473
493
|
return "loaded";
|
|
474
494
|
}
|
|
475
|
-
catch (
|
|
476
|
-
|
|
477
|
-
|
|
495
|
+
catch (rawError) {
|
|
496
|
+
const error = failureAfterRead(rawError, load);
|
|
497
|
+
const recorded = this.noteLoadFailure(error);
|
|
498
|
+
// auth.json parsed and only a later step failed (a write-back or a lost lock): its parsed
|
|
499
|
+
// credentials stand, as on the async path. A failure before the parse keeps the last snapshot.
|
|
500
|
+
if (load.parsed) {
|
|
501
|
+
this.updateReadState(data, revision);
|
|
502
|
+
this.loadError = describeAuthStoreLoadFailure(error);
|
|
503
|
+
}
|
|
504
|
+
if (!recorded)
|
|
505
|
+
return "failed";
|
|
478
506
|
if (!(error instanceof CredentialStoreBusyError))
|
|
479
507
|
return "failed";
|
|
480
508
|
if (!this.dataLoaded) {
|
|
@@ -492,6 +520,30 @@ export class AuthStorage {
|
|
|
492
520
|
isCredentialStoreBusy() {
|
|
493
521
|
return this.dataFromBusyRead;
|
|
494
522
|
}
|
|
523
|
+
/**
|
|
524
|
+
* Why the store could not be loaded on its last read, or undefined once any read or write of this
|
|
525
|
+
* instance finds it good again (senpi#4413). While set, the in-memory credentials are not the store's
|
|
526
|
+
* contents; a store that cannot be read or parsed also refuses every write.
|
|
527
|
+
*/
|
|
528
|
+
getLoadError() {
|
|
529
|
+
return this.loadError;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Records a failed read; returns false when it repeats the load error already reported, so a store
|
|
533
|
+
* that stays broken is not re-recorded on every status read that retries it.
|
|
534
|
+
*/
|
|
535
|
+
noteLoadFailure(error) {
|
|
536
|
+
const loadError = describeAuthStoreLoadFailure(error);
|
|
537
|
+
const repeated = loadError !== undefined &&
|
|
538
|
+
this.loadError?.kind === loadError.kind &&
|
|
539
|
+
this.loadError.reason === loadError.reason;
|
|
540
|
+
if (loadError)
|
|
541
|
+
this.loadError = loadError;
|
|
542
|
+
if (repeated)
|
|
543
|
+
return false;
|
|
544
|
+
this.recordError(error);
|
|
545
|
+
return true;
|
|
546
|
+
}
|
|
495
547
|
/**
|
|
496
548
|
* Monotonic count of reads (sync or async) that found the store locked before it ever
|
|
497
549
|
* loaded and answered with the empty placeholder. A change across an operation means
|
|
@@ -524,12 +576,12 @@ export class AuthStorage {
|
|
|
524
576
|
* `takeReplacement`, so no credential disappears without the user being told where it went.
|
|
525
577
|
*/
|
|
526
578
|
set(provider, credential) {
|
|
527
|
-
return this.
|
|
579
|
+
return this.writeLocked((content) => {
|
|
528
580
|
const currentData = this.parseStorageData(content);
|
|
529
581
|
const replacement = this.noteReplacement(provider, currentData[provider], credential, content);
|
|
530
|
-
const next = appendLoginSlot(currentData[provider], credential, undefined, {
|
|
582
|
+
const next = stampLogin(appendLoginSlot(currentData[provider], credential, undefined, {
|
|
531
583
|
accountIdentity: this.oauthAuth(provider)?.accountIdentity,
|
|
532
|
-
});
|
|
584
|
+
}));
|
|
533
585
|
const nextData = { ...currentData, [provider]: next };
|
|
534
586
|
this.data = nextData;
|
|
535
587
|
return { result: replacement, next: JSON.stringify(nextData, null, 2) };
|
|
@@ -609,7 +661,7 @@ export class AuthStorage {
|
|
|
609
661
|
return replacement;
|
|
610
662
|
}
|
|
611
663
|
remove(provider) {
|
|
612
|
-
this.
|
|
664
|
+
this.writeLocked((content) => {
|
|
613
665
|
const nextData = { ...this.parseStorageData(content) };
|
|
614
666
|
delete nextData[provider];
|
|
615
667
|
this.data = nextData;
|
|
@@ -619,17 +671,21 @@ export class AuthStorage {
|
|
|
619
671
|
listSlots(provider) {
|
|
620
672
|
return listSlots(readByProviderId(this.data, provider));
|
|
621
673
|
}
|
|
674
|
+
/** Adding a new slot is a sign-in and stamps a fresh `loginId`; updating an existing slot keeps it (senpi#4099). */
|
|
622
675
|
setSlot(provider, slot) {
|
|
623
|
-
this.
|
|
676
|
+
this.writeLocked((content) => {
|
|
624
677
|
const currentData = this.parseStorageData(content);
|
|
625
|
-
const
|
|
678
|
+
const current = currentData[provider];
|
|
679
|
+
const upserted = upsertSlot(current, slot);
|
|
680
|
+
const adds = !listSlots(current).some((existing) => existing.name === slot.name);
|
|
681
|
+
const next = adds ? stampLogin(upserted) : upserted;
|
|
626
682
|
const nextData = { ...currentData, [provider]: next };
|
|
627
683
|
this.data = nextData;
|
|
628
684
|
return { result: undefined, next: JSON.stringify(nextData, null, 2) };
|
|
629
685
|
});
|
|
630
686
|
}
|
|
631
687
|
removeSlot(provider, name) {
|
|
632
|
-
this.
|
|
688
|
+
this.writeLocked((content) => {
|
|
633
689
|
const currentData = this.parseStorageData(content);
|
|
634
690
|
const next = removeSlot(currentData[provider], name);
|
|
635
691
|
const nextData = { ...currentData };
|
|
@@ -666,16 +722,34 @@ export class AuthStorage {
|
|
|
666
722
|
return errors;
|
|
667
723
|
}
|
|
668
724
|
async reloadFromStorageAsync(options) {
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
if (
|
|
674
|
-
this.
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
725
|
+
try {
|
|
726
|
+
return await this.reloadLockedAsync(options);
|
|
727
|
+
}
|
|
728
|
+
catch (error) {
|
|
729
|
+
if (!options?.signal?.aborted)
|
|
730
|
+
this.loadError = describeAuthStoreLoadFailure(error) ?? this.loadError;
|
|
731
|
+
throw error;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
async reloadLockedAsync(options) {
|
|
735
|
+
const load = { parsed: false, writeBack: false };
|
|
736
|
+
try {
|
|
737
|
+
return await this.storage.withLockAsync(async (content) => {
|
|
738
|
+
const parsed = this.parseStorageContent(content);
|
|
739
|
+
load.parsed = true;
|
|
740
|
+
load.writeBack = parsed.repaired || parsed.migrated;
|
|
741
|
+
const revision = parsed.repaired || parsed.migrated || !this.authPath ? undefined : getFileContentRevision(this.authPath);
|
|
742
|
+
this.updateReadState(parsed.data, revision);
|
|
743
|
+
if (parsed.migrated)
|
|
744
|
+
this.backupAuthFile(content);
|
|
745
|
+
return parsed.repaired || parsed.migrated
|
|
746
|
+
? { result: parsed.data, next: JSON.stringify(parsed.data, null, 2) }
|
|
747
|
+
: { result: parsed.data };
|
|
748
|
+
}, options);
|
|
749
|
+
}
|
|
750
|
+
catch (error) {
|
|
751
|
+
throw failureAfterRead(error, load);
|
|
752
|
+
}
|
|
679
753
|
}
|
|
680
754
|
async readLatestData(options) {
|
|
681
755
|
options?.signal?.throwIfAborted();
|
|
@@ -692,7 +766,7 @@ export class AuthStorage {
|
|
|
692
766
|
}
|
|
693
767
|
const revision = getFileContentRevision(this.authPath);
|
|
694
768
|
if (revision !== undefined && revision === this.readState.revision)
|
|
695
|
-
return this.readState.data;
|
|
769
|
+
return this.adoptReadState(this.readState.data);
|
|
696
770
|
if (!this.readState.reload) {
|
|
697
771
|
const controller = new AbortController();
|
|
698
772
|
const reload = {
|
|
@@ -715,10 +789,11 @@ export class AuthStorage {
|
|
|
715
789
|
reload.readers++;
|
|
716
790
|
try {
|
|
717
791
|
try {
|
|
718
|
-
return await raceWithAbortSignal(reload.promise, options?.signal);
|
|
792
|
+
return this.adoptReadState(await raceWithAbortSignal(reload.promise, options?.signal));
|
|
719
793
|
}
|
|
720
794
|
catch (error) {
|
|
721
795
|
options?.signal?.throwIfAborted();
|
|
796
|
+
this.loadError = describeAuthStoreLoadFailure(error) ?? this.loadError;
|
|
722
797
|
this.noteBusyFallback(error);
|
|
723
798
|
return this.readState.data;
|
|
724
799
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type AuthStoreLoadErrorKind = "malformed_json" | "invalid_format" | "unreadable" | "write_back_failed";
|
|
2
|
+
/**
|
|
3
|
+
* Why an existing auth.json could not be loaded (senpi#4413). `reason` is safe to show and send to
|
|
4
|
+
* clients: it never carries the file's path or contents.
|
|
5
|
+
*/
|
|
6
|
+
export interface AuthStoreLoadError {
|
|
7
|
+
readonly kind: AuthStoreLoadErrorKind;
|
|
8
|
+
readonly reason: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class AuthStoreUnreadableError extends Error {
|
|
11
|
+
readonly loadError: AuthStoreLoadError;
|
|
12
|
+
constructor(loadError: AuthStoreLoadError);
|
|
13
|
+
}
|
|
14
|
+
/** The top-level object of an auth.json document; anything else is refused rather than read as empty. */
|
|
15
|
+
export declare function parseAuthDocument(content: string): Record<string, unknown>;
|
|
16
|
+
/**
|
|
17
|
+
* The load error a failed store read stands for, or undefined when the failure says nothing about
|
|
18
|
+
* the file: a lock held by another writer, a read the caller aborted, or a lock lost after a clean read.
|
|
19
|
+
*/
|
|
20
|
+
export declare function describeAuthStoreLoadFailure(error: unknown): AuthStoreLoadError | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* The error a store load surfaces: once auth.json parsed, a later failure (a write-back or a lost lock)
|
|
23
|
+
* becomes an AuthStoreAfterReadError so it is never reported as an unreadable file. Aborts pass through.
|
|
24
|
+
*/
|
|
25
|
+
export declare function failureAfterRead(error: unknown, load: {
|
|
26
|
+
parsed: boolean;
|
|
27
|
+
writeBack: boolean;
|
|
28
|
+
}): unknown;
|
|
29
|
+
//# sourceMappingURL=auth-store-load-error.d.ts.map
|