@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
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { seatDigest } from "./seat-digest.js";
|
|
2
|
+
import { logContinuityEvent } from "./session-observability.js";
|
|
3
|
+
const MAX_DETAIL_CHARS = 200;
|
|
4
|
+
/**
|
|
5
|
+
* Writes one `account_blocked` line to session.log for every block that is saved, so a pool that later
|
|
6
|
+
* refuses a request locally has a recorded cause (senpi#4671). The account is named by its seat digest,
|
|
7
|
+
* never its name (Desktop#4753); an unknown end time is left out rather than guessed.
|
|
8
|
+
*/
|
|
9
|
+
export function logAccountBlocked(record) {
|
|
10
|
+
logContinuityEvent("account_blocked", {
|
|
11
|
+
seat: seatDigest(record.account),
|
|
12
|
+
reason: record.reason,
|
|
13
|
+
...(record.until === undefined ? {} : { until: new Date(record.until).toISOString() }),
|
|
14
|
+
shared: record.shared,
|
|
15
|
+
error: record.detail.slice(0, MAX_DETAIL_CHARS),
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=account-block-log.js.map
|
|
@@ -31,6 +31,12 @@ export type UnavailableAccount = {
|
|
|
31
31
|
};
|
|
32
32
|
/** The origin of an account pin, highest precedence first (`resolveClaudeAccountPin`). */
|
|
33
33
|
export type PinSource = "cli" | "settings" | "stored";
|
|
34
|
+
/** One pool member's state when the pool refused a request: why it is out, and until when. */
|
|
35
|
+
export type BlockedAccountState = {
|
|
36
|
+
readonly name: string;
|
|
37
|
+
readonly reason: string;
|
|
38
|
+
readonly until: number | undefined;
|
|
39
|
+
};
|
|
34
40
|
export declare class AllAccountsBlockedError extends Error {
|
|
35
41
|
readonly soonestUnblockAt: number | undefined;
|
|
36
42
|
/**
|
|
@@ -49,7 +55,9 @@ export declare class AllAccountsBlockedError extends Error {
|
|
|
49
55
|
readonly limitedModel: string | undefined;
|
|
50
56
|
/** Set only when account fallback is off, so the guidance names that account instead of the whole pool. */
|
|
51
57
|
readonly unavailableAccount: UnavailableAccount | undefined;
|
|
52
|
-
|
|
58
|
+
/** Every candidate's state, so the error names which account needs /login and which waits on a reset (senpi#4671). */
|
|
59
|
+
readonly accounts: readonly BlockedAccountState[];
|
|
60
|
+
constructor(soonestUnblockAt: number | undefined, blockReason?: "auth_error", limitedModel?: string, unavailableAccount?: UnavailableAccount, accounts?: readonly BlockedAccountState[]);
|
|
53
61
|
}
|
|
54
62
|
export declare function getAffinityKey(options: Pick<AffinityOptions, "affinityKey" | "sessionId">): string;
|
|
55
63
|
/**
|
|
@@ -2,14 +2,21 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { applyAccountOrder } from "@earendil-works/pi-ai/auth/pool/select";
|
|
3
3
|
import { activeModelBlockUntil, pruneModelBlocks } from "../../../credential-pool/model-scope.js";
|
|
4
4
|
export const DEFAULT_AFFINITY_KEY = "claude-sdk-oauth-default";
|
|
5
|
+
function describeAccountState(state) {
|
|
6
|
+
const until = state.until === undefined ? "re-login" : new Date(state.until).toISOString();
|
|
7
|
+
const login = state.reason === "auth_error" ? ` (run /login anthropic-subscription for ${state.name})` : "";
|
|
8
|
+
return `${state.name}: ${state.reason} until ${until}${login}`;
|
|
9
|
+
}
|
|
5
10
|
export class AllAccountsBlockedError extends Error {
|
|
6
|
-
constructor(soonestUnblockAt, blockReason, limitedModel, unavailableAccount) {
|
|
11
|
+
constructor(soonestUnblockAt, blockReason, limitedModel, unavailableAccount, accounts = []) {
|
|
7
12
|
const until = soonestUnblockAt === undefined ? undefined : new Date(soonestUnblockAt).toISOString();
|
|
8
|
-
|
|
13
|
+
const summary = limitedModel !== undefined && until !== undefined
|
|
9
14
|
? `All Anthropic Subscription accounts have hit the usage limit for model ${limitedModel} until ${until}.`
|
|
10
15
|
: until === undefined
|
|
11
16
|
? "All Anthropic Subscription accounts are blocked until re-login."
|
|
12
|
-
: `All Anthropic Subscription accounts are blocked until ${until}
|
|
17
|
+
: `All Anthropic Subscription accounts are blocked until ${until}.`;
|
|
18
|
+
super(accounts.length === 0 ? summary : `${summary} Accounts: ${accounts.map(describeAccountState).join("; ")}.`);
|
|
19
|
+
this.accounts = accounts;
|
|
13
20
|
this.limitedModel = limitedModel;
|
|
14
21
|
this.name = "AllAccountsBlockedError";
|
|
15
22
|
this.soonestUnblockAt = soonestUnblockAt;
|
|
@@ -119,6 +126,10 @@ export function selectAccount(accounts, options = {}) {
|
|
|
119
126
|
return afterClear;
|
|
120
127
|
throw new AllAccountsBlockedError(soonestUnblockAt(candidates, now, options.model), candidates.length > 0 && candidates.every((account) => account.blockReason === "auth_error")
|
|
121
128
|
? "auth_error"
|
|
122
|
-
: undefined, limitedModel(candidates, now, options.model), unavailableAccount)
|
|
129
|
+
: undefined, limitedModel(candidates, now, options.model), unavailableAccount, candidates.map((account) => ({
|
|
130
|
+
name: account.name,
|
|
131
|
+
reason: account.blockReason ?? (isAccountBlocked(account, now) ? "blocked" : "model_limit"),
|
|
132
|
+
until: unblockAt(account, now, options.model),
|
|
133
|
+
})));
|
|
123
134
|
}
|
|
124
135
|
//# sourceMappingURL=affinity.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CredentialStore } from "@earendil-works/pi-ai";
|
|
2
2
|
import type { AccountSlot } from "./accounts.ts";
|
|
3
|
+
import { AllAccountsBlockedError } from "./affinity.ts";
|
|
3
4
|
import type { SdkErrorClassification } from "./errors.ts";
|
|
4
5
|
export declare const MAX_RATE_LIMIT_BLOCK_MS: number;
|
|
5
6
|
export declare const DEFAULT_RATE_LIMIT_BLOCK_MS = 60000;
|
|
@@ -49,7 +50,12 @@ export declare class ClassifiedSdkError extends Error {
|
|
|
49
50
|
readonly classification: SdkErrorClassification;
|
|
50
51
|
readonly original: unknown;
|
|
51
52
|
readonly suppressTurnRetry: boolean;
|
|
52
|
-
|
|
53
|
+
/**
|
|
54
|
+
* The pool's state when this failure left no other account to try (senpi#4671). The failure stays the
|
|
55
|
+
* error; the pool refusal is context, so a refresh failure or a 401 is never hidden behind "all blocked".
|
|
56
|
+
*/
|
|
57
|
+
readonly poolState: AllAccountsBlockedError | undefined;
|
|
58
|
+
constructor(classification: SdkErrorClassification, original: unknown, suppressTurnRetry: boolean, poolState?: AllAccountsBlockedError);
|
|
53
59
|
}
|
|
54
60
|
/**
|
|
55
61
|
* Runs one attempt per account for account-level failures (a limit, billing, auth), plus at most
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AUTH_BLOCK_REPROBE_MS } from "../../../credential-pool/auth-reprobe.js";
|
|
2
2
|
import { activeModelBlockUntil, mergeModelBlocks, modelBlockKey, pruneModelBlocks, withModelBlock, } from "../../../credential-pool/model-scope.js";
|
|
3
3
|
import { usageLimitResetMs } from "../../../credential-pool/reset-time.js";
|
|
4
|
+
import { logAccountBlocked } from "./account-block-log.js";
|
|
4
5
|
import { AllAccountsBlockedError, clearExpiredBlocks } from "./affinity.js";
|
|
5
6
|
import { isConfirmedAccountUsageLimit, usageLimitBlockMs } from "./usage-limit-block.js";
|
|
6
7
|
export const MAX_RATE_LIMIT_BLOCK_MS = 48 * 60 * 60 * 1_000;
|
|
@@ -91,13 +92,14 @@ export function forgetSessionBlocksFor(name) {
|
|
|
91
92
|
return lifted;
|
|
92
93
|
}
|
|
93
94
|
export class ClassifiedSdkError extends Error {
|
|
94
|
-
constructor(classification, original, suppressTurnRetry) {
|
|
95
|
+
constructor(classification, original, suppressTurnRetry, poolState) {
|
|
95
96
|
const detail = original instanceof Error ? original.message : String(original);
|
|
96
|
-
super(`${suppressTurnRetry ? TURN_RETRY_SUPPRESSION_PREFIX : ""}${detail}
|
|
97
|
+
super(`${suppressTurnRetry ? TURN_RETRY_SUPPRESSION_PREFIX : ""}${detail}`, poolState === undefined ? undefined : { cause: poolState });
|
|
97
98
|
this.name = "ClassifiedSdkError";
|
|
98
99
|
this.classification = classification;
|
|
99
100
|
this.original = original;
|
|
100
101
|
this.suppressTurnRetry = suppressTurnRetry;
|
|
102
|
+
this.poolState = poolState;
|
|
101
103
|
}
|
|
102
104
|
}
|
|
103
105
|
function record(value) {
|
|
@@ -356,6 +358,13 @@ export async function* runFailover(options) {
|
|
|
356
358
|
attempt--;
|
|
357
359
|
continue;
|
|
358
360
|
}
|
|
361
|
+
logAccountBlocked({
|
|
362
|
+
account: blocked.name,
|
|
363
|
+
reason: blocked.blockReason ?? "model_limit",
|
|
364
|
+
until: blocked.blockedUntil ?? activeModelBlockUntil(blocked.modelBlocks, options.model, now()),
|
|
365
|
+
shared,
|
|
366
|
+
detail: errorText(error),
|
|
367
|
+
});
|
|
359
368
|
accounts = replaceAccount(accounts, blocked);
|
|
360
369
|
const event = {
|
|
361
370
|
account: blocked,
|
|
@@ -363,14 +372,22 @@ export async function* runFailover(options) {
|
|
|
363
372
|
attempt: attempt + 1,
|
|
364
373
|
visibleDeltaEmitted,
|
|
365
374
|
};
|
|
375
|
+
let poolState;
|
|
366
376
|
try {
|
|
367
377
|
if (!visibleDeltaEmitted && attempt + 1 < attemptLimit) {
|
|
368
378
|
event.nextAccount = options.selectFn(accounts);
|
|
369
379
|
}
|
|
370
380
|
}
|
|
381
|
+
catch (selectError) {
|
|
382
|
+
if (!(selectError instanceof AllAccountsBlockedError))
|
|
383
|
+
throw selectError;
|
|
384
|
+
poolState = selectError;
|
|
385
|
+
}
|
|
371
386
|
finally {
|
|
372
387
|
await options.onFailover?.(event);
|
|
373
388
|
}
|
|
389
|
+
if (poolState !== undefined)
|
|
390
|
+
throw new ClassifiedSdkError(classification, error, visibleDeltaEmitted, poolState);
|
|
374
391
|
if (visibleDeltaEmitted)
|
|
375
392
|
throw classified;
|
|
376
393
|
}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import type { PinSource, UnavailableAccount } from "./affinity.ts";
|
|
1
|
+
import type { BlockedAccountState, PinSource, UnavailableAccount } from "./affinity.ts";
|
|
2
2
|
import type { SdkErrorKind } from "./errors.ts";
|
|
3
3
|
import type { ClaudeCodeRun } from "./executable.ts";
|
|
4
4
|
export declare function noAccountGuidance(hasAnthropicCredential: boolean): string;
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* The pool context of a failure that left no other account (senpi#4671): the failure stays the error, and this
|
|
7
|
+
* names the soonest retry (which goal mode reads) and every account's state. No refusal note: the pool did not
|
|
8
|
+
* refuse the request, the account failed it.
|
|
9
|
+
*/
|
|
10
|
+
export declare function exhaustedPoolGuidance(soonestUnblockAt: number | undefined, accounts: readonly BlockedAccountState[]): string;
|
|
11
|
+
export declare function allAccountsBlockedGuidance(soonestUnblockAt: number | undefined, blockReason?: "auth_error", accounts?: readonly BlockedAccountState[]): string;
|
|
6
12
|
/**
|
|
7
13
|
* How to move off a pinned account. `/claude-account pin` only writes the stored pin, which a CLI or a
|
|
8
14
|
* settings pin outranks (`resolveClaudeAccountPin`), so for those it would change nothing (senpi#3672).
|
|
@@ -11,7 +11,29 @@ export function noAccountGuidance(hasAnthropicCredential) {
|
|
|
11
11
|
lines.push(" Or set CLAUDE_CODE_OAUTH_TOKEN (and _2.._N for more accounts),", " or log in with the claude CLI for ambient auth.");
|
|
12
12
|
return lines.join("\n");
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
/** One line per pool member, naming the account that needs /login (senpi#4671). */
|
|
15
|
+
function accountStateLines(accounts) {
|
|
16
|
+
return accounts.map((account) => {
|
|
17
|
+
const until = account.until === undefined ? "re-login" : new Date(account.until).toISOString();
|
|
18
|
+
const login = account.reason === "auth_error" ? ` - run /login ${PROVIDER} for this account` : "";
|
|
19
|
+
return ` ${account.name}: ${account.reason} until ${until}${login}`;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The pool context of a failure that left no other account (senpi#4671): the failure stays the error, and this
|
|
24
|
+
* names the soonest retry (which goal mode reads) and every account's state. No refusal note: the pool did not
|
|
25
|
+
* refuse the request, the account failed it.
|
|
26
|
+
*/
|
|
27
|
+
export function exhaustedPoolGuidance(soonestUnblockAt, accounts) {
|
|
28
|
+
const eta = soonestUnblockAt !== undefined && Number.isFinite(soonestUnblockAt)
|
|
29
|
+
? new Date(soonestUnblockAt).toISOString()
|
|
30
|
+
: "after re-login";
|
|
31
|
+
return [
|
|
32
|
+
` No other Claude account is available. Soonest automatic retry: ${eta}.`,
|
|
33
|
+
...accountStateLines(accounts),
|
|
34
|
+
].join("\n");
|
|
35
|
+
}
|
|
36
|
+
export function allAccountsBlockedGuidance(soonestUnblockAt, blockReason, accounts = []) {
|
|
15
37
|
if (blockReason === "auth_error") {
|
|
16
38
|
// omo#8383: name the authentication failure; the recovery is a re-login. Only a pool whose every
|
|
17
39
|
// account is auth-blocked says so (senpi#2081), and the outer credential pool reads the refusal note
|
|
@@ -22,6 +44,7 @@ export function allAccountsBlockedGuidance(soonestUnblockAt, blockReason) {
|
|
|
22
44
|
return [
|
|
23
45
|
`All Claude accounts for ${PROVIDER} are currently blocked (authentication error).`,
|
|
24
46
|
...recheck,
|
|
47
|
+
...accountStateLines(accounts),
|
|
25
48
|
` /login ${PROVIDER} - re-authenticate to refresh the blocked account`,
|
|
26
49
|
` /claude-account list - inspect account states`,
|
|
27
50
|
ACCOUNT_POOL_REFUSAL_NOTE,
|
|
@@ -33,6 +56,7 @@ export function allAccountsBlockedGuidance(soonestUnblockAt, blockReason) {
|
|
|
33
56
|
return [
|
|
34
57
|
`All Claude accounts for ${PROVIDER} are currently blocked (rate limit or auth errors).`,
|
|
35
58
|
` Soonest automatic retry: ${eta}.`,
|
|
59
|
+
...accountStateLines(accounts),
|
|
36
60
|
` /claude-account list - inspect account states`,
|
|
37
61
|
` /login ${PROVIDER} - add another account`,
|
|
38
62
|
ACCOUNT_POOL_REFUSAL_NOTE,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ProviderDiagnostic } from "@earendil-works/pi-ai";
|
|
2
|
+
/**
|
|
3
|
+
* The providerDiagnostic for an Anthropic Subscription turn failure (senpi#4672), mirroring the
|
|
4
|
+
* chatgpt-subscription adapter (senpi#3771). A pool the extension refused locally is `auth` when every
|
|
5
|
+
* account waits on a new login, otherwise `rate_limit` with the soonest retry; a classified SDK failure maps
|
|
6
|
+
* to its provider token. The result is revalidated against the closed vocabulary, so nothing else escapes.
|
|
7
|
+
*/
|
|
8
|
+
export declare function anthropicSubscriptionDiagnostic(error: unknown): ProviderDiagnostic | undefined;
|
|
9
|
+
//# sourceMappingURL=provider-diagnostic.d.ts.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { sanitizeProviderDiagnostic, } from "@earendil-works/pi-ai";
|
|
2
|
+
import { isThinkingBindingMismatchText } from "@earendil-works/pi-ai/api/anthropic-thinking-binding";
|
|
3
|
+
import { AllAccountsBlockedError } from "./affinity.js";
|
|
4
|
+
import { classifySdkError } from "./errors.js";
|
|
5
|
+
import { ClassifiedSdkError } from "./failover.js";
|
|
6
|
+
/** The allowlisted provider token each classified SDK failure proves; kinds that prove nothing map to none. */
|
|
7
|
+
const SDK_KIND_DIAGNOSTICS = {
|
|
8
|
+
auth_error: { category: "auth", code: "authentication_error" },
|
|
9
|
+
rate_limit: { category: "rate_limit", code: "rate_limit_error" },
|
|
10
|
+
overloaded: { category: "provider_unavailable", code: "overloaded_error" },
|
|
11
|
+
billing: { category: "unknown", code: "billing_error" },
|
|
12
|
+
org_not_allowed: { category: "unknown", code: "permission_error" },
|
|
13
|
+
};
|
|
14
|
+
const CAUSE_DEPTH = 8;
|
|
15
|
+
/** The pool refusal behind `error`: the error itself or one it carries as `cause`, so wrapping never hides it. */
|
|
16
|
+
function poolRefusal(error) {
|
|
17
|
+
let current = error;
|
|
18
|
+
for (let depth = 0; depth < CAUSE_DEPTH && current instanceof Error; depth++) {
|
|
19
|
+
if (current instanceof AllAccountsBlockedError)
|
|
20
|
+
return current;
|
|
21
|
+
current = current.cause;
|
|
22
|
+
}
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The providerDiagnostic for an Anthropic Subscription turn failure (senpi#4672), mirroring the
|
|
27
|
+
* chatgpt-subscription adapter (senpi#3771). A pool the extension refused locally is `auth` when every
|
|
28
|
+
* account waits on a new login, otherwise `rate_limit` with the soonest retry; a classified SDK failure maps
|
|
29
|
+
* to its provider token. The result is revalidated against the closed vocabulary, so nothing else escapes.
|
|
30
|
+
*/
|
|
31
|
+
export function anthropicSubscriptionDiagnostic(error) {
|
|
32
|
+
const pool = poolRefusal(error);
|
|
33
|
+
if (pool !== undefined) {
|
|
34
|
+
// A pin to an account that is no longer configured is a configuration error, not a limit: no diagnostic.
|
|
35
|
+
if (pool.unavailableAccount?.configured === false)
|
|
36
|
+
return undefined;
|
|
37
|
+
const auth = pool.blockReason === "auth_error";
|
|
38
|
+
return sanitizeProviderDiagnostic({
|
|
39
|
+
category: auth ? "auth" : "rate_limit",
|
|
40
|
+
code: auth ? "account_pool_auth_blocked" : "account_pool_blocked",
|
|
41
|
+
evidence: "structured_code",
|
|
42
|
+
...(auth || pool.soonestUnblockAt === undefined ? {} : { resetsAt: pool.soonestUnblockAt }),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
const original = error instanceof ClassifiedSdkError ? error.original : error;
|
|
46
|
+
if (original instanceof Error && isThinkingBindingMismatchText(original.message)) {
|
|
47
|
+
// senpi#5587: the API refused a replayed thinking block bound to a different conversation.
|
|
48
|
+
return sanitizeProviderDiagnostic({
|
|
49
|
+
category: "invalid_request",
|
|
50
|
+
httpStatus: 400,
|
|
51
|
+
code: "invalid_request_error",
|
|
52
|
+
evidence: "structured_code",
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const kind = error instanceof ClassifiedSdkError ? error.classification.kind : classifySdkError(error).kind;
|
|
56
|
+
const mapped = SDK_KIND_DIAGNOSTICS[kind];
|
|
57
|
+
return mapped === undefined ? undefined : sanitizeProviderDiagnostic({ ...mapped, evidence: "structured_code" });
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=provider-diagnostic.js.map
|
|
@@ -5,6 +5,13 @@ export type { SessionTurnResult } from "./session-turn-types.ts";
|
|
|
5
5
|
export declare const DEFAULT_PRE_REPLAY_MAX_MESSAGES = 64;
|
|
6
6
|
export declare const DEFAULT_PRE_REPLAY_MAX_BYTES: number;
|
|
7
7
|
export declare const SESSION_TURN_ABORT_GRACE_MS = 1000;
|
|
8
|
+
/**
|
|
9
|
+
* How long a turn submitted while the previous turn of the same session is still active waits for that turn to
|
|
10
|
+
* settle before the submission is refused. The common case settles within the abort grace above: the agent loop
|
|
11
|
+
* starts the next turn (a steer, a follow-up, a monitor notification) right after it interrupted or finished
|
|
12
|
+
* consuming the previous one, while the pump still waits for the SDK's terminal result of that turn.
|
|
13
|
+
*/
|
|
14
|
+
export declare const SESSION_TURN_ADMISSION_WAIT_MS = 10000;
|
|
8
15
|
export interface SessionTurnRequest {
|
|
9
16
|
message: SDKUserMessage["message"];
|
|
10
17
|
signal?: AbortSignal;
|
|
@@ -16,5 +23,11 @@ export declare class ConcurrentSessionTurnAdmissionError extends Error {
|
|
|
16
23
|
readonly code = "claude_sdk_oauth_concurrent_turn_admission";
|
|
17
24
|
constructor(sessionId: string);
|
|
18
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Waits for `settled`, bounded by SESSION_TURN_ADMISSION_WAIT_MS: "admitted" once it settles, "aborted" when
|
|
28
|
+
* `signal` aborts first, and a ConcurrentSessionTurnAdmissionError when the bound passes, so a stuck pump cannot
|
|
29
|
+
* hold the session's callers forever.
|
|
30
|
+
*/
|
|
31
|
+
export declare function waitForTurnAdmission(sessionId: string, settled: Promise<unknown>, signal: AbortSignal | undefined, schedule?: (callback: () => void, delayMs: number) => () => void): Promise<"admitted" | "aborted">;
|
|
19
32
|
export declare function submitSessionTurn(registry: AnthropicSubscriptionSessionRegistry, entry: AnthropicSubscriptionSessionEntry, request: SessionTurnRequest, limits?: PreReplayBufferLimits): Promise<SessionTurnResult>;
|
|
20
33
|
//# sourceMappingURL=session-registry-pump.d.ts.map
|
|
@@ -8,6 +8,13 @@ import { SessionTurnAttributionError } from "./session-turn-types.js";
|
|
|
8
8
|
export const DEFAULT_PRE_REPLAY_MAX_MESSAGES = 64;
|
|
9
9
|
export const DEFAULT_PRE_REPLAY_MAX_BYTES = 256 * 1024;
|
|
10
10
|
export const SESSION_TURN_ABORT_GRACE_MS = 1_000;
|
|
11
|
+
/**
|
|
12
|
+
* How long a turn submitted while the previous turn of the same session is still active waits for that turn to
|
|
13
|
+
* settle before the submission is refused. The common case settles within the abort grace above: the agent loop
|
|
14
|
+
* starts the next turn (a steer, a follow-up, a monitor notification) right after it interrupted or finished
|
|
15
|
+
* consuming the previous one, while the pump still waits for the SDK's terminal result of that turn.
|
|
16
|
+
*/
|
|
17
|
+
export const SESSION_TURN_ADMISSION_WAIT_MS = 10_000;
|
|
11
18
|
export class ConcurrentSessionTurnAdmissionError extends Error {
|
|
12
19
|
constructor(sessionId) {
|
|
13
20
|
super(`Concurrent Anthropic Subscription turn admission for session ${sessionId}`);
|
|
@@ -154,12 +161,66 @@ async function runPump(registry, entry) {
|
|
|
154
161
|
failTurn(registry, entry, error instanceof Error ? error : new Error(String(error)));
|
|
155
162
|
}
|
|
156
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Waits for `settled`, bounded by SESSION_TURN_ADMISSION_WAIT_MS: "admitted" once it settles, "aborted" when
|
|
166
|
+
* `signal` aborts first, and a ConcurrentSessionTurnAdmissionError when the bound passes, so a stuck pump cannot
|
|
167
|
+
* hold the session's callers forever.
|
|
168
|
+
*/
|
|
169
|
+
export function waitForTurnAdmission(sessionId, settled, signal, schedule = scheduleAbort) {
|
|
170
|
+
return new Promise((resolve, reject) => {
|
|
171
|
+
let done = false;
|
|
172
|
+
let cancelTimer;
|
|
173
|
+
const finish = (run) => {
|
|
174
|
+
if (done)
|
|
175
|
+
return;
|
|
176
|
+
done = true;
|
|
177
|
+
cancelTimer?.();
|
|
178
|
+
signal?.removeEventListener("abort", onAbort);
|
|
179
|
+
run();
|
|
180
|
+
};
|
|
181
|
+
const onAbort = () => finish(() => resolve("aborted"));
|
|
182
|
+
if (signal?.aborted) {
|
|
183
|
+
onAbort();
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
// The scheduler may fire synchronously (tests inject one); `done` then stops every later step.
|
|
187
|
+
cancelTimer = schedule(() => finish(() => reject(new ConcurrentSessionTurnAdmissionError(sessionId))), SESSION_TURN_ADMISSION_WAIT_MS);
|
|
188
|
+
if (done)
|
|
189
|
+
return;
|
|
190
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
191
|
+
const admitted = () => finish(() => resolve("admitted"));
|
|
192
|
+
void settled.then(admitted, admitted);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* A turn submitted while the session's previous turn is still active waits for that turn to settle, bounded by
|
|
197
|
+
* SESSION_TURN_ADMISSION_WAIT_MS, then submits. One SDK session runs one turn at a time, so the second request is
|
|
198
|
+
* logically after the first; refusing it (the behavior before this guard) surfaced as a provider failure and moved
|
|
199
|
+
* the session to a fallback model for no reason of the provider's. An abort of the waiting request resolves it as
|
|
200
|
+
* an aborted turn; a previous turn that does not settle in time keeps the refusal.
|
|
201
|
+
*/
|
|
202
|
+
async function admitAfter(registry, entry, active, settled, request, limits) {
|
|
203
|
+
const generation = entry.generation;
|
|
204
|
+
const outcome = await waitForTurnAdmission(entry.senpiSessionId, settled, request.signal, request.scheduleAbort);
|
|
205
|
+
if (outcome === "aborted")
|
|
206
|
+
return { uuid: createSessionUuid(), messages: [], aborted: true };
|
|
207
|
+
if (!registry.isCurrentGeneration(entry.senpiSessionId, generation)) {
|
|
208
|
+
throw new Error("Anthropic Subscription session closed while a turn waited for admission");
|
|
209
|
+
}
|
|
210
|
+
if (currentTurn(entry) === active)
|
|
211
|
+
entry.activeTurn = null;
|
|
212
|
+
return submitSessionTurn(registry, entry, request, limits);
|
|
213
|
+
}
|
|
157
214
|
export function submitSessionTurn(registry, entry, request, limits = {
|
|
158
215
|
maxMessages: DEFAULT_PRE_REPLAY_MAX_MESSAGES,
|
|
159
216
|
maxBytes: DEFAULT_PRE_REPLAY_MAX_BYTES,
|
|
160
217
|
}) {
|
|
161
|
-
|
|
162
|
-
|
|
218
|
+
const active = currentTurn(entry);
|
|
219
|
+
if (active) {
|
|
220
|
+
if (!active.settled)
|
|
221
|
+
throw new ConcurrentSessionTurnAdmissionError(entry.senpiSessionId);
|
|
222
|
+
return admitAfter(registry, entry, active, active.settled, request, limits);
|
|
223
|
+
}
|
|
163
224
|
if (entry.state === "STARTING")
|
|
164
225
|
transitionToIdleSynced(entry);
|
|
165
226
|
transitionToTurnWaiting(entry);
|
|
@@ -199,6 +260,7 @@ export function submitSessionTurn(registry, entry, request, limits = {
|
|
|
199
260
|
limits,
|
|
200
261
|
};
|
|
201
262
|
});
|
|
263
|
+
turn.settled = promise.then(() => undefined, () => undefined);
|
|
202
264
|
entry.activeTurn = turn;
|
|
203
265
|
if (!entry.pumpTask)
|
|
204
266
|
entry.pumpTask = runPump(registry, entry);
|
|
@@ -178,6 +178,13 @@ export function registerSessionRegistry(pi) {
|
|
|
178
178
|
await writeStoredBinding(sessionFile, stored);
|
|
179
179
|
});
|
|
180
180
|
pi.on("session_shutdown", (event, ctx) => {
|
|
181
|
+
// A config hot-reload keeps the session and this module's registry (session_start skips
|
|
182
|
+
// "reload" above), and the resident query captures no per-load state: its hooks and tool
|
|
183
|
+
// handlers are module constants. The next turn's fingerprint check restarts the process
|
|
184
|
+
// only when the reload changed the prompt, tools or options. Closing here re-spawned Claude
|
|
185
|
+
// Code on every reload, and on a real account re-attached the claude.ai connectors.
|
|
186
|
+
if (event.reason === "reload")
|
|
187
|
+
return;
|
|
181
188
|
closeSession(ctx.sessionManager.getSessionId(), event.reason);
|
|
182
189
|
});
|
|
183
190
|
pi.on("session_extensions_removed", async (_event, ctx) => {
|
|
@@ -12,7 +12,7 @@ import { bindingFromEntry, bindingInvalidationReason, getBinding } from "./sessi
|
|
|
12
12
|
import { closeSession, getOrCreateSession, getSession, isIdleExpired, } from "./session-registry.js";
|
|
13
13
|
import { admitRestoredBinding } from "./session-restored-admission.js";
|
|
14
14
|
import { buildDeltaPromptBlocks, configFingerprint, sentHashesForEntry, sentMessageHashes, sentMessages, } from "./session-sync.js";
|
|
15
|
-
import { createSessionTurnAttempt } from "./session-turn-attempt.js";
|
|
15
|
+
import { createSessionTurnAttempt, waitForActiveTurn } from "./session-turn-attempt.js";
|
|
16
16
|
function userMessage(content) {
|
|
17
17
|
return { role: "user", content };
|
|
18
18
|
}
|
|
@@ -46,6 +46,10 @@ async function createResidentAttempt(input, auth) {
|
|
|
46
46
|
const sessionId = input.streamOptions.sessionId;
|
|
47
47
|
const messages = sentMessages(input.context);
|
|
48
48
|
const hashes = sentMessageHashes(messages);
|
|
49
|
+
// Continuity and the delta are read from the settled previous turn, never from one still in flight.
|
|
50
|
+
const pending = getSession(sessionId);
|
|
51
|
+
if (pending)
|
|
52
|
+
await waitForActiveTurn(pending, input.streamOptions.signal);
|
|
49
53
|
const existing = getSession(sessionId);
|
|
50
54
|
const fingerprint = configFingerprint(auth.options, input.context, auth.authLane, auth.accountName);
|
|
51
55
|
const residentHashes = existing ? (sentHashesForEntry(existing) ?? hashes) : hashes;
|
|
@@ -4,6 +4,13 @@ import { type AnthropicSubscriptionSessionEntry } from "./session-registry.ts";
|
|
|
4
4
|
type StagedContinuityDecision = {
|
|
5
5
|
emit(): void;
|
|
6
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
* Holds a new attempt until the attempt running the entry's previous turn finished and recorded the sent stream
|
|
9
|
+
* (`recordSyncedStream`), bounded and abortable like the pump's own admission wait. The caller decides
|
|
10
|
+
* continuity and the delta only after this, so the delta starts after the earlier turn's message instead of
|
|
11
|
+
* sending it again (senpi#5015 review).
|
|
12
|
+
*/
|
|
13
|
+
export declare function waitForActiveTurn(entry: AnthropicSubscriptionSessionEntry, signal: AbortSignal | undefined): Promise<void>;
|
|
7
14
|
/** Claude Code's wording for a fork point absent from its transcript; the captured id is the dead one. */
|
|
8
15
|
export declare const RESUME_MESSAGE_MISSING: RegExp;
|
|
9
16
|
export declare function createSessionTurnAttempt(entry: AnthropicSubscriptionSessionEntry, message: SDKUserMessage["message"], hashes: readonly string[], signal: AbortSignal | undefined, staged: StagedContinuityDecision,
|
|
@@ -2,8 +2,24 @@ import { BoundedAsyncQueue, SESSION_STREAM_QUEUE_CAPACITY } from "./bounded-queu
|
|
|
2
2
|
import { sdkResultFailure } from "./errors.js";
|
|
3
3
|
import { bindingFromEntry, forgetBinding, rememberBinding } from "./session-reattach.js";
|
|
4
4
|
import { closeSession, isCurrentGeneration, sessionRegistry, } from "./session-registry.js";
|
|
5
|
-
import { submitSessionTurn } from "./session-registry-pump.js";
|
|
5
|
+
import { submitSessionTurn, waitForTurnAdmission } from "./session-registry-pump.js";
|
|
6
6
|
import { recordSyncedStream, sentHashPrefixDigest } from "./session-sync.js";
|
|
7
|
+
/** Pending while the attempt that submitted the entry's latest turn has not yet recorded what that turn sent. */
|
|
8
|
+
const attemptBookkeeping = new WeakMap();
|
|
9
|
+
/**
|
|
10
|
+
* Holds a new attempt until the attempt running the entry's previous turn finished and recorded the sent stream
|
|
11
|
+
* (`recordSyncedStream`), bounded and abortable like the pump's own admission wait. The caller decides
|
|
12
|
+
* continuity and the delta only after this, so the delta starts after the earlier turn's message instead of
|
|
13
|
+
* sending it again (senpi#5015 review).
|
|
14
|
+
*/
|
|
15
|
+
export async function waitForActiveTurn(entry, signal) {
|
|
16
|
+
const pending = attemptBookkeeping.get(entry);
|
|
17
|
+
if (!pending)
|
|
18
|
+
return;
|
|
19
|
+
if ((await waitForTurnAdmission(entry.senpiSessionId, pending, signal)) === "aborted") {
|
|
20
|
+
throw new Error("Anthropic Subscription turn aborted while waiting for the previous turn");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
7
23
|
function successfulTurn(messages) {
|
|
8
24
|
return messages.some((message) => message.type === "result" && message.subtype === "success" && sdkResultFailure(message) === undefined);
|
|
9
25
|
}
|
|
@@ -91,6 +107,16 @@ servedLineage) {
|
|
|
91
107
|
return {
|
|
92
108
|
messages: (async function* () {
|
|
93
109
|
const queue = new BoundedAsyncQueue(SESSION_STREAM_QUEUE_CAPACITY);
|
|
110
|
+
let markBookkept;
|
|
111
|
+
const bookkeeping = new Promise((resolve) => {
|
|
112
|
+
markBookkept = resolve;
|
|
113
|
+
});
|
|
114
|
+
attemptBookkeeping.set(entry, bookkeeping);
|
|
115
|
+
const bookkept = () => {
|
|
116
|
+
if (attemptBookkeeping.get(entry) === bookkeeping)
|
|
117
|
+
attemptBookkeeping.delete(entry);
|
|
118
|
+
markBookkept();
|
|
119
|
+
};
|
|
94
120
|
const completion = submitSessionTurn(sessionRegistry, entry, {
|
|
95
121
|
message,
|
|
96
122
|
signal,
|
|
@@ -147,6 +173,7 @@ servedLineage) {
|
|
|
147
173
|
finally {
|
|
148
174
|
// A consumer that stops reading early must not leave the pump waiting for room.
|
|
149
175
|
queue.close();
|
|
176
|
+
bookkept();
|
|
150
177
|
}
|
|
151
178
|
})(),
|
|
152
179
|
discard: () => {
|
|
@@ -23,6 +23,8 @@ export interface ActiveTurn {
|
|
|
23
23
|
resolve: (result: SessionTurnResult) => void;
|
|
24
24
|
reject: (error: Error) => void;
|
|
25
25
|
limits: PreReplayBufferLimits;
|
|
26
|
+
/** Settles (never rejects) once the turn resolved or rejected; a turn submitted behind it waits here. */
|
|
27
|
+
settled?: Promise<void>;
|
|
26
28
|
}
|
|
27
29
|
export interface PreReplayBufferLimits {
|
|
28
30
|
maxMessages: number;
|
|
@@ -2,7 +2,7 @@ import { AllAccountsBlockedError } from "./affinity.js";
|
|
|
2
2
|
import { errorAccountContext } from "./account-context.js";
|
|
3
3
|
import { classifySdkError } from "./errors.js";
|
|
4
4
|
import { ClassifiedSdkError } from "./failover.js";
|
|
5
|
-
import { allAccountsBlockedGuidance, claudeCodeVersionFloorGuidance, sdkErrorGuidance, singleAccountUnavailableGuidance, switchAccountLine, } from "./guidance.js";
|
|
5
|
+
import { allAccountsBlockedGuidance, claudeCodeVersionFloorGuidance, exhaustedPoolGuidance, sdkErrorGuidance, singleAccountUnavailableGuidance, switchAccountLine, } from "./guidance.js";
|
|
6
6
|
import { ClaudeSignInRequiredError } from "./sign-in-again.js";
|
|
7
7
|
export function withAuthGuidance(error, message, ran, now = Date.now()) {
|
|
8
8
|
// The sign-in-again prompt is the remedy; the generic auth_error hint ("token was rejected... refresh") contradicts it.
|
|
@@ -10,7 +10,7 @@ export function withAuthGuidance(error, message, ran, now = Date.now()) {
|
|
|
10
10
|
return message;
|
|
11
11
|
if (error instanceof AllAccountsBlockedError) {
|
|
12
12
|
const guidance = error.unavailableAccount === undefined
|
|
13
|
-
? allAccountsBlockedGuidance(error.soonestUnblockAt, error.blockReason)
|
|
13
|
+
? allAccountsBlockedGuidance(error.soonestUnblockAt, error.blockReason, error.accounts)
|
|
14
14
|
: singleAccountUnavailableGuidance(error.unavailableAccount, error.soonestUnblockAt, error.blockReason);
|
|
15
15
|
// The model-limit sentence is how the fallback chain learns the limit binds this model only (senpi#5007).
|
|
16
16
|
return error.limitedModel === undefined
|
|
@@ -28,7 +28,9 @@ export function withAuthGuidance(error, message, ran, now = Date.now()) {
|
|
|
28
28
|
guidance = `${selected} ${action}`;
|
|
29
29
|
}
|
|
30
30
|
const versionGuidance = claudeCodeVersionFloorGuidance(message, ran);
|
|
31
|
-
const
|
|
31
|
+
const pool = error instanceof ClassifiedSdkError ? error.poolState : undefined;
|
|
32
|
+
const poolGuidance = pool && exhaustedPoolGuidance(pool.soonestUnblockAt, pool.accounts);
|
|
33
|
+
const hints = [guidance, versionGuidance, poolGuidance].filter((hint) => hint !== undefined);
|
|
32
34
|
return hints.length > 0 ? `${message}\n${hints.join("\n")}` : message;
|
|
33
35
|
}
|
|
34
36
|
/**
|
|
@@ -13,6 +13,7 @@ import { refusalError } from "./refusal.js";
|
|
|
13
13
|
import { getSdkBoundary, loadClaudeAgentSdk } from "./sdk-boundary.js";
|
|
14
14
|
import { emitContinuityObservation } from "./session-observability.js";
|
|
15
15
|
import { forgetBinding } from "./session-reattach.js";
|
|
16
|
+
import { anthropicSubscriptionDiagnostic } from "./provider-diagnostic.js";
|
|
16
17
|
import { requireAnthropicSubscriptionCwd } from "./session-cwd.js";
|
|
17
18
|
import { residentSessionMessages } from "./session-stream.js";
|
|
18
19
|
import { loadAnthropicSubscriptionProviderSettingsFromDisk, resolveCompactionOwner, resumeModeSource, } from "./settings.js";
|
|
@@ -268,6 +269,9 @@ export function streamAnthropicSubscription(model, context, options) {
|
|
|
268
269
|
if (billed)
|
|
269
270
|
updateUsage(model, output, billed, "query");
|
|
270
271
|
output.errorMessage = withAuthGuidance(error, errorMessage(error), claudeCodeRun);
|
|
272
|
+
const diagnostic = output.stopReason === "error" ? anthropicSubscriptionDiagnostic(error) : undefined;
|
|
273
|
+
if (diagnostic !== undefined)
|
|
274
|
+
output.providerDiagnostic = diagnostic;
|
|
271
275
|
markColdSeedOverflow(output, model, coldSeedAttempt, coldSeedEstimate, options?.sessionId);
|
|
272
276
|
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
273
277
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "../../types.ts";
|
|
2
2
|
export type { BashTimeoutDefaults, BashToolInputLike } from "./timeout.ts";
|
|
3
|
-
export { applyBashTimeout, BASH_DEFAULT_TIMEOUT_SECONDS,
|
|
3
|
+
export { applyBashTimeout, BASH_DEFAULT_TIMEOUT_SECONDS, resolveBashTimeoutDefaults } from "./timeout.ts";
|
|
4
4
|
export default function bashTimeoutExtension(pi: ExtensionAPI): void;
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { resolveForegroundWindowSeconds } from "../terminal/tools/foreground-window.js";
|
|
4
|
-
import { applyBashTimeout, buildBashTimeoutPrompt, resolveBashTimeoutDefaults, } from "./timeout.js";
|
|
5
|
-
export { applyBashTimeout, BASH_DEFAULT_TIMEOUT_SECONDS, BASH_MAX_TIMEOUT_SECONDS, buildBashTimeoutPrompt, resolveBashTimeoutDefaults, } from "./timeout.js";
|
|
1
|
+
import { applyBashTimeout, resolveBashTimeoutDefaults } from "./timeout.js";
|
|
2
|
+
export { applyBashTimeout, BASH_DEFAULT_TIMEOUT_SECONDS, resolveBashTimeoutDefaults } from "./timeout.js";
|
|
6
3
|
export default function bashTimeoutExtension(pi) {
|
|
7
4
|
const env = typeof process !== "undefined" ? process.env : {};
|
|
8
5
|
const defaults = resolveBashTimeoutDefaults(env);
|
|
@@ -17,28 +14,6 @@ export default function bashTimeoutExtension(pi) {
|
|
|
17
14
|
input.timeout = timeout;
|
|
18
15
|
}
|
|
19
16
|
});
|
|
20
|
-
|
|
21
|
-
* Native Anthropic bash replaces the PTY `bash` tool and the terminal
|
|
22
|
-
* extension steps aside with it, so nothing implements the auto-detach the
|
|
23
|
-
* policy would otherwise advertise.
|
|
24
|
-
*/
|
|
25
|
-
const resolveWindow = (ctx) => {
|
|
26
|
-
if (isAnthropicBashEnabled() && ctx?.model?.api === "anthropic-messages")
|
|
27
|
-
return undefined;
|
|
28
|
-
return resolveForegroundWindowSeconds(env);
|
|
29
|
-
};
|
|
30
|
-
pi.on("before_agent_start", async (event, ctx) => {
|
|
31
|
-
// A session with no `bash` tool has nothing this policy can describe. A host that exposes
|
|
32
|
-
// only the handler surface (no getAllTools) keeps the policy, as the terminal section does.
|
|
33
|
-
if (typeof pi.getAllTools === "function" && !pi.getAllTools().some((tool) => tool.name === "bash")) {
|
|
34
|
-
return undefined;
|
|
35
|
-
}
|
|
36
|
-
const foregroundWindowSeconds = resolveWindow(ctx);
|
|
37
|
-
const prompt = buildBashTimeoutPrompt(defaults, {
|
|
38
|
-
...(foregroundWindowSeconds === undefined ? {} : { foregroundWindowSeconds }),
|
|
39
|
-
evalOnly: isEvalOnlyRouting(pi),
|
|
40
|
-
});
|
|
41
|
-
return { systemPrompt: `${event.systemPrompt}${prompt}` };
|
|
42
|
-
}, { previewSafe: true });
|
|
17
|
+
// The timeout facts reach the model through the terminal section (senpi#5335); this extension adds no prompt text.
|
|
43
18
|
}
|
|
44
19
|
//# sourceMappingURL=index.js.map
|