mixdog 1.2.0 → 1.2.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/README.md +7 -5
- package/package.json +1 -1
- package/scripts/gate-local.mjs +19 -3
- package/scripts/model-catalog-audit.mjs +1 -15
- package/src/agents/reviewer/AGENT.md +3 -3
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +5 -0
- package/src/defaults/skills/pptx/SKILL.md +6 -6
- package/src/defaults/skills/pptx/references/review.md +6 -4
- package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
- package/src/defaults/skills/setup/references/actions.md +13 -3
- package/src/defaults/skills/visualize/SKILL.md +12 -9
- package/src/repl/slash-commands.mjs +16 -1
- package/src/rules/shared/60-verification.md +3 -1
- package/src/rules/shared/70-delivery.md +4 -2
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
- package/src/runtime/agent/orchestrator/config.mjs +10 -4
- package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +122 -15
- package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +54 -11
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +104 -9
- package/src/runtime/agent/orchestrator/mcp/client.mjs +358 -140
- package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
- package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +294 -44
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +96 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +25 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +73 -35
- package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +8 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +53 -18
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +30 -14
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +93 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +82 -9
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +447 -0
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +38 -5
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +102 -23
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +29 -6
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +18 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +86 -19
- package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +29 -8
- package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +191 -0
- package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +21 -82
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -12
- package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +21 -20
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +97 -51
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +68 -19
- package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +15 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +35 -0
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +12 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +22 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +23 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +16 -8
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +94 -13
- package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +6 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +23 -14
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +26 -6
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +42 -25
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +18 -11
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +1 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +2 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
- package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +34 -3
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +5 -0
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +5 -9
- package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
- package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +35 -24
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +581 -0
- package/src/runtime/agent/orchestrator/providers/registry.mjs +35 -9
- package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
- package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +118 -219
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
- package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
- package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
- package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
- package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +268 -181
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
- package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +270 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
- package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -4
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +102 -18
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +42 -5
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +14 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +20 -12
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +50 -23
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +22 -14
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
- package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +155 -29
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +819 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +22 -12
- package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +183 -374
- package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +41 -3
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +38 -17
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +173 -22
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +5 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +15 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
- package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
- package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
- package/src/runtime/attachments/store.d.mts +3 -0
- package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
- package/src/runtime/channels/lib/worker-main.mjs +17 -14
- package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
- package/src/runtime/effort-judge/judge-client.mjs +56 -18
- package/src/runtime/memory/lib/memory.mjs +1 -1
- package/src/runtime/memory/lib/pg/process.mjs +34 -24
- package/src/runtime/memory/lib/pg/supervisor.mjs +16 -13
- package/src/runtime/memory/lib/session-ingest.mjs +2 -2
- package/src/runtime/office/README.md +1 -1
- package/src/runtime/office/shared/values.mjs +0 -5
- package/src/runtime/shared/atomic-file.mjs +25 -4
- package/src/runtime/shared/background-tasks.mjs +92 -14
- package/src/runtime/shared/err-text.mjs +25 -0
- package/src/runtime/shared/error-presentation.mjs +159 -19
- package/src/runtime/shared/extension-scopes.mjs +5 -3
- package/src/runtime/shared/file-lock.mjs +37 -11
- package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
- package/src/runtime/shared/llm/anthropic-effort.mjs +134 -131
- package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
- package/src/runtime/shared/llm/model-catalog.mjs +53 -52
- package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +17 -0
- package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
- package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
- package/src/runtime/shared/model-display.mjs +13 -0
- package/src/runtime/shared/plugin-manifest.mjs +18 -9
- package/src/runtime/shared/pristine-execution-contract.json +9 -2
- package/src/runtime/shared/pristine-execution.mjs +28 -4
- package/src/runtime/shared/provider-accounts.mjs +124 -20
- package/src/runtime/shared/provider-api-key.mjs +12 -0
- package/src/runtime/shared/quota-resume-store.mjs +11 -0
- package/src/runtime/shared/session-baseline-store.mjs +960 -0
- package/src/runtime/shared/shell-display.mjs +9 -3
- package/src/runtime/shared/skill-mentions.d.mts +10 -0
- package/src/runtime/shared/skill-mentions.mjs +133 -0
- package/src/runtime/shared/skill-script-runtime.mjs +264 -0
- package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
- package/src/runtime/shared/task-notification-envelope.mjs +2 -2
- package/src/runtime/shared/tool-primitives.mjs +35 -2
- package/src/runtime/shared/turn-changes.mjs +447 -219
- package/src/runtime/shared/turn-snapshot-store.mjs +182 -1
- package/src/runtime/shared/turn-snapshot.mjs +170 -48
- package/src/runtime/shared/turn-worktree-snapshot.mjs +160 -51
- package/src/runtime/shared/worker-requests.mjs +15 -2
- package/src/runtime/shared/worktrees/contract.mjs +0 -24
- package/src/runtime/shared/worktrees/test-support.mjs +19 -4
- package/src/session-runtime/automation-agents.mjs +8 -2
- package/src/session-runtime/boot/apis.mjs +61 -0
- package/src/session-runtime/boot/config.mjs +5 -2
- package/src/session-runtime/boot/facade.mjs +1 -0
- package/src/session-runtime/boot/infrastructure.mjs +35 -18
- package/src/session-runtime/conversation-import/discovery.mjs +698 -0
- package/src/session-runtime/conversation-import/service.mjs +369 -0
- package/src/session-runtime/cwd-plugins/cwd-apply.mjs +10 -5
- package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
- package/src/session-runtime/lifecycle/session-catalog.mjs +2 -0
- package/src/session-runtime/lifecycle/teardown.mjs +1 -1
- package/src/session-runtime/mcp-glue/connect.mjs +83 -16
- package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
- package/src/session-runtime/mcp-glue/server-catalog.mjs +135 -33
- package/src/session-runtime/mcp-glue.mjs +25 -2
- package/src/session-runtime/mcp-oauth-login.mjs +174 -0
- package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
- package/src/session-runtime/model-route/set-route.mjs +83 -15
- package/src/session-runtime/model-route/web-search-route.mjs +1 -1
- package/src/session-runtime/native-web-search/routes.mjs +22 -3
- package/src/session-runtime/new-session-config.mjs +3 -2
- package/src/session-runtime/notification-bus.mjs +9 -2
- package/src/session-runtime/provider-auth/accounts.mjs +33 -15
- package/src/session-runtime/provider-models/model-meta.mjs +12 -3
- package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
- package/src/session-runtime/provider-readiness.mjs +16 -10
- package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
- package/src/session-runtime/quick-web-search-models.mjs +13 -38
- package/src/session-runtime/resource-extension-sync.mjs +24 -5
- package/src/session-runtime/resource-mcp-api.mjs +198 -78
- package/src/session-runtime/resource-plugins-api.mjs +29 -41
- package/src/session-runtime/resource-scope-decorate.mjs +6 -8
- package/src/session-runtime/resource-skills-api.mjs +23 -2
- package/src/session-runtime/runtime-review-api.mjs +13 -0
- package/src/session-runtime/schedule-session-run.mjs +1 -1
- package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
- package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
- package/src/session-runtime/services/channel-session-router.mjs +4 -1
- package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
- package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
- package/src/session-runtime/services/provider-admin.mjs +64 -18
- package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
- package/src/session-runtime/settings-compaction-api.mjs +1 -0
- package/src/session-runtime/setup-tool/executor.mjs +12 -1
- package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +1 -0
- package/src/session-runtime/setup-tool/tool-defs.mjs +7 -1
- package/src/session-runtime/skills-api.mjs +7 -3
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/webhook-session-run.mjs +16 -4
- package/src/skill-script-entry.mjs +36 -0
- package/src/standalone/daemon-drain-policy.mjs +8 -0
- package/src/standalone/daemon-stored-session-views.mjs +11 -3
- package/src/standalone/daemon-telemetry.mjs +55 -0
- package/src/standalone/daemon.mjs +44 -11
- package/src/standalone/session-protocol.mjs +12 -0
- package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
- package/src/standalone/session-service/agent-tree.mjs +12 -0
- package/src/standalone/session-service/quota-resume.mjs +8 -0
- package/src/standalone/session-service/retention/busy.mjs +15 -1
- package/src/standalone/session-service/session-calls/session-action.mjs +6 -1
- package/src/standalone/session-service-api.mjs +5 -0
- package/src/standalone/session-service.mjs +1 -0
- package/src/tui/App.jsx +9 -1
- package/src/tui/app/app-view/floating-panel.jsx +9 -1
- package/src/tui/app/app-view.jsx +7 -0
- package/src/tui/app/create-app-pickers.mjs +4 -0
- package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
- package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
- package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
- package/src/tui/app/extension-pickers.mjs +2 -1
- package/src/tui/app/model-options.mjs +13 -16
- package/src/tui/app/skill-mention-palette.mjs +88 -0
- package/src/tui/app/slash-commands.mjs +7 -2
- package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
- package/src/tui/app/slash-palette.mjs +23 -7
- package/src/tui/app/transcript-row-estimate.mjs +11 -3
- package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
- package/src/tui/app/use-prompt-state.mjs +5 -0
- package/src/tui/components/Message.jsx +22 -1
- package/src/tui/components/PromptInput.jsx +21 -3
- package/src/tui/components/SlashCommandPalette.jsx +12 -3
- package/src/tui/components/StatusLine.jsx +2 -0
- package/src/tui/components/TranscriptItem.jsx +9 -1
- package/src/tui/components/prompt-input/key-handler.mjs +21 -8
- package/src/tui/components/status-line/local-line.mjs +5 -2
- package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
- package/src/tui/components/user-message-skills.mjs +38 -0
- package/src/tui/dist/index.mjs +1323 -214
- package/src/tui/session/queue-helpers.mjs +7 -2
- package/src/tui/session/quota-resume.mjs +46 -14
- package/src/tui/session/session-api/commands.mjs +33 -24
- package/src/tui/session/session-api/extensions.mjs +26 -2
- package/src/tui/session/session-api/integrations.mjs +7 -0
- package/src/tui/session/session-api/lifecycle.mjs +5 -1
- package/src/tui/session/session-api/routes.mjs +71 -7
- package/src/tui/session/session-api/settings.mjs +12 -14
- package/src/tui/session/session-flow/drain.mjs +21 -5
- package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
- package/src/tui/session/tui-steering-persist.mjs +25 -9
- package/src/tui/session/turn.mjs +55 -15
- package/src/tui/statusline-ansi-bridge.mjs +1 -1
- package/src/ui/statusline-agents.mjs +15 -4
- package/src/ui/statusline.mjs +7 -3
- package/src/ui/streaming-markdown-heal.mjs +34 -3
- package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
- package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
- package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
- package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
- package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
} from 'node:fs/promises';
|
|
22
22
|
import { dirname, basename, join } from 'node:path';
|
|
23
23
|
import { randomBytes } from 'node:crypto';
|
|
24
|
-
import { DEFAULT_BACKOFFS_MS, withFileLock, withFileLockSync } from './file-lock.mjs';
|
|
24
|
+
import { DEFAULT_BACKOFFS_MS, recordLockTiming, withFileLock, withFileLockSync } from './file-lock.mjs';
|
|
25
25
|
import {
|
|
26
26
|
enforceOwnerOnlyAclWin32 as _enforceOwnerOnlyAclWin32,
|
|
27
27
|
enforceOwnerOnlyAclWin32Async as _enforceOwnerOnlyAclWin32Async,
|
|
@@ -321,9 +321,30 @@ export async function writeFileAtomicAsync(filePath, data, opts = {}) {
|
|
|
321
321
|
};
|
|
322
322
|
// Acquire the file lock before occupying an I/O slot. Otherwise a waiter can
|
|
323
323
|
// exhaust the gate while the current lock owner needs it to finish its write.
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
324
|
+
if (opts.lock !== true) return _runAdaptiveFileIo(run);
|
|
325
|
+
const lockPath = `${filePath}.lock`;
|
|
326
|
+
return withFileLock(
|
|
327
|
+
lockPath,
|
|
328
|
+
async () => {
|
|
329
|
+
const queuedAt = Date.now();
|
|
330
|
+
let startedAt = 0;
|
|
331
|
+
try {
|
|
332
|
+
return await _runAdaptiveFileIo(() => {
|
|
333
|
+
startedAt = Date.now();
|
|
334
|
+
return run();
|
|
335
|
+
});
|
|
336
|
+
} finally {
|
|
337
|
+
const now = Date.now();
|
|
338
|
+
// Recorded from this (lock-owner) context so the held warning can
|
|
339
|
+
// split the hold into gate wait vs. the write itself.
|
|
340
|
+
recordLockTiming(lockPath, {
|
|
341
|
+
ioGateWaitMs: (startedAt || now) - queuedAt,
|
|
342
|
+
writeMs: startedAt ? now - startedAt : 0,
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
opts
|
|
347
|
+
);
|
|
327
348
|
}
|
|
328
349
|
|
|
329
350
|
export function writeJsonAtomicAsync(filePath, value, opts = {}) {
|
|
@@ -18,6 +18,10 @@ export { TOOL_ASYNC_EXECUTION_CONTRACT, TOOL_MANUAL_CONTROL_CONTRACT, TOOL_SYNC_
|
|
|
18
18
|
const TASK_TTL_MS = 30 * 60_000;
|
|
19
19
|
const MAX_TASKS = 300;
|
|
20
20
|
const TERMINAL_STATUSES = new Set(['completed', 'failed', 'cancelled']);
|
|
21
|
+
// A `notifyOnCancel` task reports its cancellation to the owner once, after its
|
|
22
|
+
// run settles, so the notification can carry what the run produced before it
|
|
23
|
+
// stopped. A run that never settles still reports, header-only, after this grace.
|
|
24
|
+
const CANCEL_NOTIFY_GRACE_MS = 10_000;
|
|
21
25
|
const tasks = new Map();
|
|
22
26
|
let seq = 0;
|
|
23
27
|
|
|
@@ -151,6 +155,7 @@ export function registerBackgroundTask({
|
|
|
151
155
|
resultType,
|
|
152
156
|
renderResult,
|
|
153
157
|
cancel,
|
|
158
|
+
notifyOnCancel = false,
|
|
154
159
|
} = {}) {
|
|
155
160
|
pruneTasks();
|
|
156
161
|
const explicitId = clean(taskId);
|
|
@@ -189,6 +194,7 @@ export function registerBackgroundTask({
|
|
|
189
194
|
resultType: clean(resultType) || null,
|
|
190
195
|
renderResult: typeof renderResult === 'function' ? renderResult : null,
|
|
191
196
|
cancel: typeof cancel === 'function' ? cancel : null,
|
|
197
|
+
notifyOnCancel: notifyOnCancel === true,
|
|
192
198
|
};
|
|
193
199
|
tasks.set(id, task);
|
|
194
200
|
return task;
|
|
@@ -200,10 +206,14 @@ export function startBackgroundTask(options = {}) {
|
|
|
200
206
|
.then(() => options.run?.())
|
|
201
207
|
.then((result) => {
|
|
202
208
|
completeBackgroundTask(task.taskId, { status: 'completed', result, terminalReason: 'run-resolved' });
|
|
209
|
+
deliverCancelledNotification(task);
|
|
203
210
|
return result;
|
|
204
211
|
})
|
|
205
212
|
.catch((error) => {
|
|
206
|
-
if (task.status === 'cancelled')
|
|
213
|
+
if (task.status === 'cancelled') {
|
|
214
|
+
deliverCancelledNotification(task);
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
207
217
|
completeBackgroundTask(task.taskId, {
|
|
208
218
|
status: 'failed',
|
|
209
219
|
error,
|
|
@@ -258,15 +268,62 @@ export function cleanupBackgroundTasks(options = {}) {
|
|
|
258
268
|
return { removed: before - after, tasks: after };
|
|
259
269
|
}
|
|
260
270
|
|
|
261
|
-
|
|
271
|
+
// `notify`: true notifies immediately, false never notifies (owner teardown).
|
|
272
|
+
// Left unset, a `notifyOnCancel` task defers its single `cancelled`
|
|
273
|
+
// notification until its run settles (see settleCancelledBackgroundTask); any
|
|
274
|
+
// other task stays silent.
|
|
275
|
+
function cancelRunningTask(task, reason, notify) {
|
|
276
|
+
try {
|
|
277
|
+
task.cancel?.();
|
|
278
|
+
} catch {}
|
|
279
|
+
completeBackgroundTask(task.taskId, { status: 'cancelled', error: reason, notify: notify === true });
|
|
280
|
+
if (task.notifyOnCancel !== true || notify === true || task.status !== 'cancelled' || task.cancelNotify) return;
|
|
281
|
+
if (notify === false) {
|
|
282
|
+
task.cancelNotify = 'silent';
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
task.cancelNotify = 'pending';
|
|
286
|
+
task.cancelNotifyTimer = setTimeout(() => deliverCancelledNotification(task), CANCEL_NOTIFY_GRACE_MS);
|
|
287
|
+
task.cancelNotifyTimer.unref?.();
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Owner teardown/delete (`notify: false`) also silences a cancellation that is
|
|
291
|
+
// still waiting for its run to settle.
|
|
292
|
+
function resolvePendingCancelNotify(task, next) {
|
|
293
|
+
if (task.cancelNotify !== 'pending') return false;
|
|
294
|
+
clearTimeout(task.cancelNotifyTimer);
|
|
295
|
+
task.cancelNotifyTimer = null;
|
|
296
|
+
task.cancelNotify = next;
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function silenceCancelledNotification(task) {
|
|
301
|
+
resolvePendingCancelNotify(task, 'silent');
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function deliverCancelledNotification(task) {
|
|
305
|
+
if (!resolvePendingCancelNotify(task, 'delivered')) return false;
|
|
306
|
+
if (tasks.get(task.taskId) !== task) return false;
|
|
307
|
+
task.meta = sanitizeTaskMeta(task.meta);
|
|
308
|
+
return notifyTaskCompletion(task, task.notificationInstruction);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export function cancelBackgroundTask(taskId, reason = 'cancelled', { notify } = {}) {
|
|
262
312
|
const task = getBackgroundTask(taskId);
|
|
263
313
|
if (!task) return null;
|
|
264
|
-
if (!TERMINAL_STATUSES.has(task.status))
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
314
|
+
if (!TERMINAL_STATUSES.has(task.status)) cancelRunningTask(task, reason, notify);
|
|
315
|
+
else if (notify === false) silenceCancelledNotification(task);
|
|
316
|
+
return task;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/** The cancelled run has stopped: attach what it produced before stopping (if
|
|
320
|
+
* any) and deliver the task's single deferred `cancelled` notification. A
|
|
321
|
+
* no-op unless that notification is still pending. */
|
|
322
|
+
export function settleCancelledBackgroundTask(taskId, { result } = {}) {
|
|
323
|
+
const task = getBackgroundTask(taskId);
|
|
324
|
+
if (task?.status !== 'cancelled' || task.cancelNotify !== 'pending') return null;
|
|
325
|
+
if (result !== undefined) task.result = result;
|
|
326
|
+
deliverCancelledNotification(task);
|
|
270
327
|
return task;
|
|
271
328
|
}
|
|
272
329
|
|
|
@@ -280,11 +337,11 @@ export function cancelBackgroundTasks(options = {}) {
|
|
|
280
337
|
// visible/recoverable, but may not be claimed by whichever session happens
|
|
281
338
|
// to close first.
|
|
282
339
|
if (!taskMatchesScope(task, options, { includeUnattributed: false })) continue;
|
|
283
|
-
if (TERMINAL_STATUSES.has(task.status))
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
|
|
340
|
+
if (TERMINAL_STATUSES.has(task.status)) {
|
|
341
|
+
if (options.notify === false) silenceCancelledNotification(task);
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
cancelRunningTask(task, reason, options.notify);
|
|
288
345
|
cancelled += 1;
|
|
289
346
|
}
|
|
290
347
|
return { cancelled };
|
|
@@ -358,10 +415,26 @@ export function completeBackgroundTask(
|
|
|
358
415
|
return task;
|
|
359
416
|
}
|
|
360
417
|
|
|
418
|
+
// Surfaces whose later reads consume the structured result object itself:
|
|
419
|
+
// shell `task read` re-reads output via result paths and renders exit_code /
|
|
420
|
+
// timed_out / signal; agent job views return `job.result`. They keep it for the
|
|
421
|
+
// TTL; every other surface keeps only resultText + metadata once delivered.
|
|
422
|
+
const RESULT_KEPT_SURFACES = new Set(['shell', 'agent']);
|
|
423
|
+
|
|
424
|
+
function releaseDeliveredResult(task, body) {
|
|
425
|
+
if (task.result === undefined || RESULT_KEPT_SURFACES.has(task.surface)) return;
|
|
426
|
+
// Pin the rendered body first so re-renders and retries stay identical.
|
|
427
|
+
if (!task.resultText) task.resultText = body;
|
|
428
|
+
task.result = undefined;
|
|
429
|
+
}
|
|
430
|
+
|
|
361
431
|
export function notifyTaskCompletion(task, instruction) {
|
|
362
432
|
if (!task) return false;
|
|
363
433
|
if (!TERMINAL_STATUSES.has(task.status)) return false;
|
|
364
434
|
if (task.completionAcknowledged === true) return false;
|
|
435
|
+
// A deferred cancellation is delivered only by deliverCancelledNotification;
|
|
436
|
+
// a silent (owner-teardown) cancellation never notifies.
|
|
437
|
+
if (task.cancelNotify === 'pending' || task.cancelNotify === 'silent') return false;
|
|
365
438
|
// `notified` tracks whether *any* completion notification was sent (e.g. an
|
|
366
439
|
// early header-only preview from the agent surface). A later call that can
|
|
367
440
|
// finally include the result body must still fire once, otherwise the owner
|
|
@@ -396,7 +469,10 @@ export function notifyTaskCompletion(task, instruction) {
|
|
|
396
469
|
});
|
|
397
470
|
if (sent) {
|
|
398
471
|
task.notified = true;
|
|
399
|
-
if (hasBody)
|
|
472
|
+
if (hasBody) {
|
|
473
|
+
task.notifiedWithBody = true;
|
|
474
|
+
releaseDeliveredResult(task, body);
|
|
475
|
+
}
|
|
400
476
|
}
|
|
401
477
|
return sent;
|
|
402
478
|
}
|
|
@@ -457,6 +533,8 @@ export function renderBackgroundTaskNotification(task) {
|
|
|
457
533
|
status: task.status,
|
|
458
534
|
result,
|
|
459
535
|
error: task.error,
|
|
536
|
+
// A cancelled Agent's header names the cancel reason.
|
|
537
|
+
detail: task.surface === 'agent' && task.status === 'cancelled' ? task.error : null,
|
|
460
538
|
});
|
|
461
539
|
}
|
|
462
540
|
|
|
@@ -180,9 +180,34 @@ export function isCancelLikeError(error) {
|
|
|
180
180
|
);
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
+
// One-line reason per provider kind. Fixed sentences (optionally with a
|
|
184
|
+
// parenthesised value) are the renderer's translation keys.
|
|
185
|
+
const KIND_LINES = {
|
|
186
|
+
overloaded: 'Provider is busy at capacity.',
|
|
187
|
+
rate_limited: ({ retryAfterMs }) =>
|
|
188
|
+
retryAfterMs ? `Provider is rate-limited (retry in ${formatDurationMs(retryAfterMs)}).` : 'Provider is rate-limited.',
|
|
189
|
+
quota_exhausted: 'Provider usage limit reached.',
|
|
190
|
+
entitlement: 'Not included in your plan.',
|
|
191
|
+
billing: 'Out of credits or at spend limit.',
|
|
192
|
+
permission: 'Access denied by the provider.',
|
|
193
|
+
policy: 'Refused by the provider safety policy.',
|
|
194
|
+
auth: 'Provider authentication failed.',
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
// Typed evidence: a persisted descriptor or structured status/code fields.
|
|
198
|
+
// A bare message carries none, so its wording keeps the legacy text path.
|
|
199
|
+
function hasTypedEvidence(error) {
|
|
200
|
+
if (!error || typeof error !== 'object') return false;
|
|
201
|
+
return Boolean(error.errorKind?.kind) || errorHttpStatus(error) > 0 || Boolean(error.code) || Boolean(error.retryAfterMs);
|
|
202
|
+
}
|
|
203
|
+
|
|
183
204
|
export function presentErrorText(error, options = {}) {
|
|
184
205
|
const presentation = describeError(error);
|
|
185
206
|
if (['image-size', 'payload-size', 'request'].includes(presentation.kind)) return presentation.summary;
|
|
207
|
+
const kindLine = hasTypedEvidence(error) ? KIND_LINES[presentation.providerKind] : null;
|
|
208
|
+
if (kindLine && presentation.kind !== 'unknown') {
|
|
209
|
+
return typeof kindLine === 'function' ? kindLine(presentation) : kindLine;
|
|
210
|
+
}
|
|
186
211
|
const surface = options.surface || options.tool || '';
|
|
187
212
|
const subject = subjectForSurface(surface);
|
|
188
213
|
const max = options.max ?? 240;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PROVIDER_ERROR_KINDS, providerErrorKind } from '../agent/orchestrator/providers/provider-error-kind.mjs';
|
|
1
2
|
import { transportErrorText } from './transport-error-text.mjs';
|
|
2
3
|
|
|
3
4
|
const DETAILS_LIMIT = 12_000;
|
|
@@ -72,34 +73,167 @@ export function isRejected429(value) {
|
|
|
72
73
|
return /\bAPI 429 request rejected\b/.test(messageOf(value));
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
// Provider kind → presentation. Summaries are also the persisted form of a
|
|
77
|
+
// failure, so each maps back to its kind when only the text survives.
|
|
78
|
+
const KIND_COPY = {
|
|
79
|
+
overloaded: ['overloaded', 'The provider is busy right now.', 'Try again later or choose another model.'],
|
|
80
|
+
rate_limited: ['rate-limit', 'The provider is temporarily rate-limiting requests.', 'Try again shortly.'],
|
|
81
|
+
quota_exhausted: [
|
|
82
|
+
'quota',
|
|
83
|
+
'The provider usage limit was reached.',
|
|
84
|
+
'Wait for the limit to reset or choose another account.',
|
|
85
|
+
],
|
|
86
|
+
entitlement: [
|
|
87
|
+
'entitlement',
|
|
88
|
+
"This model isn't included in your plan.",
|
|
89
|
+
'Upgrade your plan, or choose another model or provider.',
|
|
90
|
+
],
|
|
91
|
+
billing: [
|
|
92
|
+
'billing',
|
|
93
|
+
'The provider account is out of credits or at its spend limit.',
|
|
94
|
+
'Check your billing with the provider, then try again.',
|
|
95
|
+
],
|
|
96
|
+
permission: [
|
|
97
|
+
'permission',
|
|
98
|
+
"You don't have access to this resource.",
|
|
99
|
+
'Check your account permissions, or choose another model.',
|
|
100
|
+
],
|
|
101
|
+
context_overflow: [
|
|
102
|
+
'context-overflow',
|
|
103
|
+
'The conversation is too long for this model.',
|
|
104
|
+
'Compact the conversation or start a new one.',
|
|
105
|
+
],
|
|
106
|
+
request_too_large: [
|
|
107
|
+
'payload-size',
|
|
108
|
+
'The request exceeds the size limit.',
|
|
109
|
+
'Reduce the attachments or request size, then try again.',
|
|
110
|
+
],
|
|
111
|
+
policy: [
|
|
112
|
+
'policy',
|
|
113
|
+
'The provider refused this request under its safety policy.',
|
|
114
|
+
'Rephrase the request or choose another model.',
|
|
115
|
+
],
|
|
116
|
+
service_tier_unavailable: [
|
|
117
|
+
'service-tier',
|
|
118
|
+
'The requested service tier is unavailable right now.',
|
|
119
|
+
'Switch to the standard tier or try again later.',
|
|
120
|
+
],
|
|
121
|
+
};
|
|
122
|
+
const SUMMARY_KINDS = new Map(Object.entries(KIND_COPY).map(([providerKind, [, summary]]) => [summary, providerKind]));
|
|
123
|
+
|
|
124
|
+
function waitLabel(ms) {
|
|
125
|
+
const seconds = Math.max(1, Math.ceil(ms / 1000));
|
|
126
|
+
if (seconds < 60) return `${seconds}s`;
|
|
127
|
+
const minutes = Math.ceil(seconds / 60);
|
|
128
|
+
if (minutes < 60) return `${minutes}m`;
|
|
129
|
+
const hours = Math.floor(minutes / 60);
|
|
130
|
+
return minutes % 60 ? `${hours}h ${minutes % 60}m` : `${hours}h`;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Local HH:mm, prefixed with month/day when the reset is not today. */
|
|
134
|
+
function resetLabel(resetAt) {
|
|
135
|
+
const reset = new Date(resetAt);
|
|
136
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
137
|
+
const time = `${pad(reset.getHours())}:${pad(reset.getMinutes())}`;
|
|
138
|
+
return reset.toDateString() === new Date().toDateString() ? time : `${reset.getMonth() + 1}/${reset.getDate()} ${time}`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Only legacy items (no persisted descriptor) and untyped strings reach this.
|
|
142
|
+
const LEGACY_TEXT_KINDS = [
|
|
143
|
+
[/The provider usage limit was reached|quota.*(?:hit|exceed)|usage limit/i, 'quota_exhausted'],
|
|
144
|
+
[/rate[_ -]?limit|too many requests/i, 'rate_limited'],
|
|
145
|
+
];
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* The provider kind descriptor: the persisted one, else typed evidence, else
|
|
149
|
+
* wording. `typed` is true when the kind came from a persisted descriptor or a
|
|
150
|
+
* typed error: wording heuristics must then never override it.
|
|
151
|
+
*/
|
|
152
|
+
function classify(value, raw, clean, status, code) {
|
|
153
|
+
const persisted = value?.errorKind;
|
|
154
|
+
if (persisted && PROVIDER_ERROR_KINDS.includes(persisted.kind)) {
|
|
155
|
+
return { descriptor: persisted, typed: persisted.kind !== 'unknown' };
|
|
156
|
+
}
|
|
157
|
+
const hasTypedFields =
|
|
158
|
+
value &&
|
|
159
|
+
typeof value === 'object' &&
|
|
160
|
+
Boolean(value.status || value.httpStatus || value.response?.status || value.code || value.retryAfterMs);
|
|
161
|
+
if (!hasTypedFields) {
|
|
162
|
+
// Legacy persisted strings: their wording (and wait) is the only evidence.
|
|
163
|
+
const legacy = SUMMARY_KINDS.get(clean) ?? LEGACY_TEXT_KINDS.find(([re]) => re.test(clean))?.[1];
|
|
164
|
+
if (legacy) {
|
|
165
|
+
const wait = /retryAfter=(\d+)(ms|s|m)\b/i.exec(raw);
|
|
166
|
+
const retryAfterMs = wait ? Number(wait[1]) * { ms: 1, s: 1000, m: 60_000 }[wait[2].toLowerCase()] : undefined;
|
|
167
|
+
return { descriptor: { kind: legacy, ...(retryAfterMs ? { retryAfterMs } : {}) }, typed: false };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
let descriptor = value && typeof value === 'object' ? providerErrorKind(value) : null;
|
|
171
|
+
const typed = Boolean(descriptor) && descriptor.kind !== 'unknown';
|
|
172
|
+
if (!descriptor || descriptor.kind === 'unknown') {
|
|
173
|
+
descriptor = providerErrorKind(
|
|
174
|
+
Object.assign(new Error(raw), { ...(status ? { status } : {}), ...(code ? { code } : {}) })
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
if (descriptor.kind === 'unknown') {
|
|
178
|
+
const known = SUMMARY_KINDS.get(clean);
|
|
179
|
+
const legacy = known ?? LEGACY_TEXT_KINDS.find(([re]) => re.test(clean))?.[1];
|
|
180
|
+
if (legacy) return { descriptor: { ...descriptor, kind: legacy }, typed: false };
|
|
181
|
+
}
|
|
182
|
+
return { descriptor, typed };
|
|
183
|
+
}
|
|
184
|
+
|
|
75
185
|
/** Presentation only: never changes retry policy or the underlying failure. */
|
|
76
186
|
export function describeError(value) {
|
|
77
|
-
const { raw, message, status, code } = unwrap(value);
|
|
78
|
-
const rejected429 = isRejected429(value);
|
|
187
|
+
const { raw, message, status: textStatus, code: textCode } = unwrap(value);
|
|
79
188
|
const details = safeErrorDetails(raw);
|
|
80
189
|
const clean = safeErrorDetails(message)
|
|
81
190
|
.replace(/^(?:Error invoking remote method ['"][^'"]+['"]:\s*)?(?:Error:\s*)?/i, '')
|
|
82
191
|
.trim();
|
|
192
|
+
const { descriptor, typed } = classify(value, raw, clean, textStatus, textCode);
|
|
193
|
+
// A typed or persisted kind owns the verdict: its own status and code stand
|
|
194
|
+
// in for the text-derived ones, and wording below may only refine it.
|
|
195
|
+
const status = typed ? Number(descriptor.status) || 0 : textStatus;
|
|
196
|
+
const code = typed ? String(descriptor.code || '') : textCode;
|
|
197
|
+
// A 429 refusal without quota headers refines a rate limit, nothing else.
|
|
198
|
+
const rejected429 = isRejected429(value) && (!typed || descriptor.kind === 'rate_limited');
|
|
199
|
+
const copy = KIND_COPY[descriptor.kind];
|
|
200
|
+
const retryAfterMs = Number(descriptor.retryAfterMs) > 0 ? Number(descriptor.retryAfterMs) : null;
|
|
201
|
+
const resetAt = Number(descriptor.resetAt) > 0 ? Number(descriptor.resetAt) : null;
|
|
83
202
|
let kind = 'unknown';
|
|
84
203
|
let summary = '';
|
|
85
204
|
let recovery = '';
|
|
86
|
-
|
|
205
|
+
// Localization hook: a recovery that carries a value is given as a template.
|
|
206
|
+
let recoveryTemplate = '';
|
|
207
|
+
let params = null;
|
|
208
|
+
// A persisted descriptor keeps the status and errno code, not the cause
|
|
209
|
+
// chain: rebuild the transport evidence from them. Wording only reads for
|
|
210
|
+
// untyped failures and transient ones (a bare "fetch failed" is that evidence).
|
|
211
|
+
const transport =
|
|
212
|
+
transportErrorText(value) ||
|
|
213
|
+
(typed && transportErrorText({ code: code.toUpperCase(), status })) ||
|
|
214
|
+
(!typed || descriptor.kind === 'transient' ? transportErrorText(raw) : null);
|
|
87
215
|
if (
|
|
88
216
|
value?.reauthRequired === true ||
|
|
89
|
-
|
|
217
|
+
(!typed &&
|
|
218
|
+
/invalid_grant|refresh token (?:expired|revoked|not available)|sign in again|sign-in expired|Reauth Required/i.test(raw))
|
|
90
219
|
) {
|
|
91
220
|
kind = 'reauth';
|
|
92
221
|
summary = 'Sign-in expired.';
|
|
93
222
|
recovery = 'Sign in again from Providers.';
|
|
94
223
|
} else if (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
224
|
+
descriptor.kind === 'auth' ||
|
|
225
|
+
(descriptor.kind === 'unknown' &&
|
|
226
|
+
/\b(?:invalid|expired)\s+(?:api[ _-]?key|access token|credentials?)\b|Provider authentication failed/i.test(clean))
|
|
98
227
|
) {
|
|
99
228
|
kind = 'authentication';
|
|
100
229
|
summary = 'Provider authentication failed';
|
|
101
230
|
recovery = 'Check your sign-in or API key, then try again.';
|
|
231
|
+
} else if (rejected429) {
|
|
232
|
+
kind = 'request';
|
|
233
|
+
summary = 'The provider rejected this request.';
|
|
234
|
+
recovery = 'Review the request details before trying again.';
|
|
102
235
|
} else if (
|
|
236
|
+
['invalid_request', 'unknown', 'request_too_large'].includes(descriptor.kind) &&
|
|
103
237
|
/image.*dimensions.*exceed|image.*(?:too large|maximum.*(?:size|dimension))|many-image requests|An attached image exceeds the provider limit/i.test(
|
|
104
238
|
clean
|
|
105
239
|
)
|
|
@@ -108,20 +242,21 @@ export function describeError(value) {
|
|
|
108
242
|
summary = 'An attached image exceeds the provider limit.';
|
|
109
243
|
recovery = 'Reduce the image dimensions or number of images, then try again.';
|
|
110
244
|
} else if (
|
|
111
|
-
|
|
245
|
+
descriptor.kind === 'unknown' &&
|
|
112
246
|
/payload too large|request (?:body )?too large|The request exceeds the size limit/i.test(clean)
|
|
113
247
|
) {
|
|
114
|
-
kind =
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
248
|
+
[kind, summary, recovery] = KIND_COPY.request_too_large;
|
|
249
|
+
} else if (copy) {
|
|
250
|
+
[kind, summary, recovery] = copy;
|
|
251
|
+
if (descriptor.kind === 'rate_limited' && retryAfterMs) {
|
|
252
|
+
recovery = `Try again in ${waitLabel(retryAfterMs)}.`;
|
|
253
|
+
recoveryTemplate = 'Try again in {{wait}}.';
|
|
254
|
+
params = { wait: waitLabel(retryAfterMs) };
|
|
255
|
+
} else if (descriptor.kind === 'quota_exhausted' && resetAt) {
|
|
256
|
+
recovery = `It resets at ${resetLabel(resetAt)}. Switch accounts or providers to continue now.`;
|
|
257
|
+
recoveryTemplate = 'It resets at {{time}}. Switch accounts or providers to continue now.';
|
|
258
|
+
params = { time: resetLabel(resetAt) };
|
|
259
|
+
}
|
|
125
260
|
} else if (transport) {
|
|
126
261
|
kind = 'connection';
|
|
127
262
|
summary = transport.replace(/\.$/, '');
|
|
@@ -150,6 +285,11 @@ export function describeError(value) {
|
|
|
150
285
|
kind,
|
|
151
286
|
summary,
|
|
152
287
|
recovery,
|
|
288
|
+
recoveryTemplate,
|
|
289
|
+
params,
|
|
290
|
+
providerKind: descriptor.kind,
|
|
291
|
+
resetAt,
|
|
292
|
+
retryAfterMs,
|
|
153
293
|
details,
|
|
154
294
|
// Known structured failures ignore volatile indexes; unknown failures
|
|
155
295
|
// retain their diagnostic identity rather than merging unrelated work.
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { resolve, sep } from 'node:path';
|
|
17
17
|
import { clean } from './clean.mjs';
|
|
18
18
|
import { isPlainObject } from './object.mjs';
|
|
19
|
+
import { parseMcpToolName } from './tool-primitives.mjs';
|
|
19
20
|
|
|
20
21
|
export const EXTENSION_SCOPE_KINDS = Object.freeze(['skills', 'mcp', 'plugins']);
|
|
21
22
|
|
|
@@ -123,9 +124,10 @@ export function skillAllowedForCwd(scopes, skill, cwd) {
|
|
|
123
124
|
return true;
|
|
124
125
|
}
|
|
125
126
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
/** Server of an MCP tool definition or name (metadata first; see parseMcpToolName). */
|
|
128
|
+
export function mcpServerNameOfTool(toolOrName) {
|
|
129
|
+
const value = toolOrName && typeof toolOrName === 'object' ? toolOrName : clean(toolOrName);
|
|
130
|
+
return clean(parseMcpToolName(value)?.server);
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
/** New config with one entry replaced; `projects` null/empty removes it (global). */
|
|
@@ -177,16 +177,38 @@ function warnLockRateLimited(warnedAt, lockPath, line) {
|
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
function
|
|
180
|
+
function formatLockTiming(timing) {
|
|
181
|
+
return Object.entries(timing || {})
|
|
182
|
+
.filter(([, ms]) => Number.isFinite(ms))
|
|
183
|
+
.map(([name, ms]) => ` ${name}=${ms}ms`)
|
|
184
|
+
.join('');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Lets a lock owner's callback attribute its time (io gate wait, write) to the
|
|
188
|
+
// held-warning of the lock it runs under.
|
|
189
|
+
export function recordLockTiming(lockPath, fields) {
|
|
190
|
+
const lease = heldLockPaths.getStore()?.get(lockPath);
|
|
191
|
+
if (lease?.active) Object.assign(lease.timing, fields);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function reportLockWait(lockPath, waitedMs, mode, timing) {
|
|
181
195
|
if (waitedMs < LOCK_WAIT_WARN_MS) return;
|
|
182
|
-
warnLockRateLimited(
|
|
196
|
+
warnLockRateLimited(
|
|
197
|
+
lockWaitWarnedAt,
|
|
198
|
+
lockPath,
|
|
199
|
+
`[atomic-file] ${mode} lock wait ${waitedMs}ms:${formatLockTiming(timing)} ${lockPath}\n`
|
|
200
|
+
);
|
|
183
201
|
}
|
|
184
202
|
|
|
185
203
|
// A lock held this long starves every waiter (they time out at 2s), so the
|
|
186
204
|
// holder's duration is reported once released.
|
|
187
|
-
function reportLockHeld(lockPath, heldMs, mode) {
|
|
205
|
+
function reportLockHeld(lockPath, heldMs, mode, timing) {
|
|
188
206
|
if (heldMs < LOCK_HELD_WARN_MS) return;
|
|
189
|
-
warnLockRateLimited(
|
|
207
|
+
warnLockRateLimited(
|
|
208
|
+
lockHeldWarnedAt,
|
|
209
|
+
lockPath,
|
|
210
|
+
`[atomic-file] ${mode} lock held ${heldMs}ms:${formatLockTiming(timing)} ${lockPath}\n`
|
|
211
|
+
);
|
|
190
212
|
}
|
|
191
213
|
|
|
192
214
|
function* tryAcquireReclaimGuard(lockPath) {
|
|
@@ -387,7 +409,7 @@ export function sweepStagedLockFiles(lockPath, now = Date.now()) {
|
|
|
387
409
|
return removed;
|
|
388
410
|
}
|
|
389
411
|
|
|
390
|
-
function* acquireLock(lockPath, opts, mode, markHeld) {
|
|
412
|
+
function* acquireLock(lockPath, opts, mode, markHeld, timing = null) {
|
|
391
413
|
const timeoutMs = lockTimeoutMs(opts);
|
|
392
414
|
const staleMs = lockStaleMs(opts);
|
|
393
415
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -415,7 +437,9 @@ function* acquireLock(lockPath, opts, mode, markHeld) {
|
|
|
415
437
|
attempt += 1;
|
|
416
438
|
continue;
|
|
417
439
|
}
|
|
418
|
-
|
|
440
|
+
const osMs = Date.now() - waitStartedAt;
|
|
441
|
+
if (timing) timing.osAcquireMs = osMs;
|
|
442
|
+
reportLockWait(lockPath, osMs, mode, timing);
|
|
419
443
|
return;
|
|
420
444
|
}
|
|
421
445
|
throw timeoutError(lockPath, timeoutMs, lastError, yield* describeLockHolder(lockPath));
|
|
@@ -444,13 +468,15 @@ export function withFileLockSync(lockPath, fn, opts = {}) {
|
|
|
444
468
|
export async function withFileLock(lockPath, fn, opts = {}) {
|
|
445
469
|
if (heldLockPaths.getStore()?.get(lockPath)?.active) return fn();
|
|
446
470
|
if (lockTimeoutMs(opts) <= 0) return withOsFileLock(lockPath, fn, opts);
|
|
447
|
-
|
|
471
|
+
const enqueuedAt = Date.now();
|
|
472
|
+
return lockQueue(lockPath, () => withOsFileLock(lockPath, fn, opts, Date.now() - enqueuedAt));
|
|
448
473
|
}
|
|
449
474
|
|
|
450
|
-
async function withOsFileLock(lockPath, fn, opts = {}) {
|
|
451
|
-
|
|
475
|
+
async function withOsFileLock(lockPath, fn, opts = {}, queueWaitMs = 0) {
|
|
476
|
+
const timing = { queueWaitMs };
|
|
477
|
+
await runAsync(acquireLock(lockPath, opts, 'async', true, timing));
|
|
452
478
|
const heldSince = Date.now();
|
|
453
|
-
const lease = { active: false };
|
|
479
|
+
const lease = { active: false, timing };
|
|
454
480
|
try {
|
|
455
481
|
if (opts.secret === true) await enforceOwnerOnlyAclWin32Async(lockPath, { fresh: true });
|
|
456
482
|
// Async descendants inherit a reference to this lease, not permanent
|
|
@@ -464,7 +490,7 @@ async function withOsFileLock(lockPath, fn, opts = {}) {
|
|
|
464
490
|
try {
|
|
465
491
|
await runAsync(releaseLock(lockPath));
|
|
466
492
|
} finally {
|
|
467
|
-
reportLockHeld(lockPath, Date.now() - heldSince, 'async');
|
|
493
|
+
reportLockHeld(lockPath, Date.now() - heldSince, 'async', timing);
|
|
468
494
|
// Unmark only once the lock file is gone: a sync waiter arriving while
|
|
469
495
|
// the release is still pending must fail fast, not block its completion.
|
|
470
496
|
unmarkOsHeld(lockPath);
|
|
@@ -13,12 +13,13 @@ export const SERVER_SIDE_FALLBACK_BETA_HEADER = 'server-side-fallback-2026-07-01
|
|
|
13
13
|
// `speed: "fast"` and Opus 4.6 silently runs at standard speed.
|
|
14
14
|
const KNOWN_FAST_MODE_MODELS = /^claude-opus-(?:4-8|5)(?:$|[-@])/;
|
|
15
15
|
|
|
16
|
-
// The
|
|
17
|
-
//
|
|
16
|
+
// The catalog's declaration (true or false) decides; the id pattern is only
|
|
17
|
+
// the offline floor for a model the catalog says nothing about.
|
|
18
18
|
export function supportsAnthropicFastMode(model) {
|
|
19
19
|
const id = normalizeClaudeModelId(model);
|
|
20
20
|
if (!id) return false;
|
|
21
|
-
|
|
21
|
+
const declared = getModelMetadataSync(id, 'anthropic')?.supportsFastMode;
|
|
22
|
+
return typeof declared === 'boolean' ? declared : KNOWN_FAST_MODE_MODELS.test(id);
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export function buildAnthropicBetaHeaders({
|