mixdog 1.2.1 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/package.json +2 -1
- package/scripts/gate-local.mjs +19 -3
- package/scripts/model-catalog-audit.mjs +1 -15
- package/scripts/provider-pingpong-live.mjs +509 -0
- package/src/agents/advisor/AGENT.md +1 -1
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/reviewer/AGENT.md +3 -3
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +6 -0
- package/src/defaults/skills/setup/SKILL.md +6 -1
- package/src/defaults/skills/setup/references/actions.md +44 -22
- package/src/defaults/skills/setup/references/surfaces.md +10 -8
- package/src/headless-exec.mjs +15 -8
- package/src/lib/keychain-cjs.cjs +7 -4
- package/src/output-styles/common.md +11 -10
- package/src/repl/slash-commands.mjs +16 -1
- package/src/rules/agent/AGENT.md +5 -5
- package/src/rules/lead/LEAD.md +5 -5
- 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/agent-trace-io.mjs +92 -61
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
- package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
- package/src/runtime/agent/orchestrator/config.mjs +5 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +36 -7
- package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +49 -10
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +40 -3
- package/src/runtime/agent/orchestrator/mcp/client.mjs +230 -96
- 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/providers/account-pool.mjs +188 -29
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +98 -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 +48 -37
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +10 -7
- 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 +102 -45
- 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-turn/turn-blocks.mjs +20 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +40 -7
- 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 +88 -21
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +30 -10
- package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +106 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +94 -15
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +117 -72
- package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +75 -10
- 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 +103 -23
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +32 -6
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +27 -3
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
- package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
- package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
- package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +80 -18
- package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +46 -8
- package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +273 -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-request-body.mjs +41 -5
- 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 +369 -112
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +140 -35
- package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +70 -24
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +80 -29
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +69 -19
- package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
- package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
- package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
- package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
- package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
- 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-channel.d.mts +1 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +123 -61
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +27 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
- 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 +47 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +64 -23
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +79 -33
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +144 -15
- 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 +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +109 -26
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +27 -6
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +34 -20
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +23 -4
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +37 -28
- 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/output-items.mjs +23 -10
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +43 -15
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +5 -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 +7 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
- 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-model-capabilities.mjs +80 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +37 -4
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +12 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +12 -1
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +76 -33
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
- package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
- package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
- 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-stream/event-switch.mjs +12 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
- package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +41 -22
- package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
- package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +720 -0
- package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
- package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +123 -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/providers/transport-scope.d.mts +6 -0
- package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
- package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
- package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
- package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
- package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
- 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 +1 -97
- package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
- package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
- package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
- package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
- package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
- package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
- package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
- package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +67 -20
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +104 -19
- package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +30 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +57 -21
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +5 -10
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +16 -4
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
- package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
- package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +168 -29
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
- package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
- package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
- 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-archived-agent.mjs +34 -15
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
- package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +20 -1
- package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
- package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
- package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
- package/src/runtime/computer-bridge/action-schema.mjs +44 -21
- package/src/runtime/github/tool.mjs +92 -2
- package/src/runtime/memory/index.mjs +1 -0
- package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
- package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
- package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
- package/src/runtime/memory/lib/pg/process.mjs +65 -50
- package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
- package/src/runtime/memory/lib/pg/supervisor.mjs +124 -16
- package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
- package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
- package/src/runtime/office/README.md +2 -2
- package/src/runtime/office/authoring/html-document-author.mjs +2 -0
- package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
- package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
- package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
- package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
- package/src/runtime/office/core/office-actions-read.mjs +3 -0
- package/src/runtime/office/core/office-render-preview.mjs +2 -0
- package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
- package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
- package/src/runtime/office/core/office-sessions.mjs +5 -0
- package/src/runtime/office/core/office-transactions.mjs +3 -0
- package/src/runtime/office/core/office-write-ledger.mjs +98 -0
- package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
- package/src/runtime/office/index.mjs +30 -0
- package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
- package/src/runtime/office/pdf/pdf-render.mjs +23 -7
- package/src/runtime/office/pdf/pdf-security.mjs +2 -0
- package/src/runtime/office/portable/portable-opc.mjs +4 -1
- package/src/runtime/office/quality/visual-diff.mjs +2 -0
- package/src/runtime/office/shared/values.mjs +0 -5
- package/src/runtime/shared/background-tasks.mjs +92 -14
- package/src/runtime/shared/bounded-file-read.mjs +13 -0
- package/src/runtime/shared/bounded-line-diff.mjs +182 -0
- package/src/runtime/shared/buffered-appender.mjs +18 -0
- package/src/runtime/shared/config.mjs +78 -18
- package/src/runtime/shared/err-text.mjs +31 -0
- package/src/runtime/shared/error-presentation.mjs +159 -19
- package/src/runtime/shared/file-permissions.d.mts +6 -1
- package/src/runtime/shared/file-permissions.mjs +54 -6
- package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
- package/src/runtime/shared/llm/anthropic-effort.mjs +129 -134
- package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
- package/src/runtime/shared/llm/model-catalog.mjs +53 -40
- package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +11 -0
- package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
- package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
- package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
- package/src/runtime/shared/loopback-listener.mjs +9 -0
- package/src/runtime/shared/model-display.mjs +13 -0
- package/src/runtime/shared/provider-api-key.mjs +2 -0
- package/src/runtime/shared/quota-resume-store.mjs +11 -0
- package/src/runtime/shared/review-diff.mjs +52 -0
- package/src/runtime/shared/session-baseline-store.mjs +960 -0
- package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
- package/src/runtime/shared/session-sidebar-host.mjs +38 -0
- package/src/runtime/shared/slow-span.mjs +114 -0
- package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
- package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
- package/src/runtime/shared/task-notification-envelope.mjs +2 -2
- package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
- package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
- package/src/runtime/shared/tool-card-model.mjs +5 -2
- package/src/runtime/shared/tool-output-limit.mjs +4 -0
- package/src/runtime/shared/tool-primitives.mjs +13 -0
- package/src/runtime/shared/tool-result-summary.mjs +8 -1
- package/src/runtime/shared/tool-surface.mjs +18 -3
- package/src/runtime/shared/tool-work-units.mjs +40 -4
- package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
- package/src/runtime/shared/transcript-writer.mjs +10 -2
- package/src/runtime/shared/turn-changes.mjs +670 -274
- package/src/runtime/shared/turn-review-reply.mjs +8 -39
- package/src/runtime/shared/turn-snapshot-store.mjs +94 -2
- package/src/runtime/shared/turn-snapshot.mjs +986 -690
- package/src/runtime/shared/turn-worktree-snapshot.mjs +279 -262
- package/src/runtime/shared/user-data-guard.mjs +262 -49
- package/src/runtime/shared/worktrees/carry.mjs +531 -0
- package/src/runtime/shared/worktrees/contract.mjs +34 -24
- package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
- package/src/runtime/shared/worktrees/git-head.mjs +205 -0
- package/src/runtime/shared/worktrees/git.mjs +8 -3
- package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
- package/src/runtime/shared/worktrees/manager.mjs +156 -8
- package/src/runtime/shared/worktrees/merge.mjs +31 -21
- package/src/runtime/shared/worktrees/paths.d.mts +6 -0
- package/src/runtime/shared/worktrees/test-support.mjs +19 -4
- package/src/runtime/terminal-bridge/client.mjs +44 -11
- package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
- package/src/runtime/tidy/apply.mjs +47 -2
- package/src/runtime/tidy/run-engines.mjs +11 -5
- package/src/session-runtime/agent-tool-routing.mjs +19 -13
- package/src/session-runtime/boot/apis.mjs +19 -5
- package/src/session-runtime/boot/facade.mjs +1 -0
- package/src/session-runtime/boot/infrastructure.mjs +12 -1
- package/src/session-runtime/boot/session.mjs +0 -1
- package/src/session-runtime/boot/tools.mjs +4 -1
- package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
- package/src/session-runtime/internal-tool-executor.mjs +6 -2
- package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
- package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
- package/src/session-runtime/lifecycle/session-catalog.mjs +14 -3
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
- package/src/session-runtime/lifecycle/teardown.mjs +73 -8
- package/src/session-runtime/lifecycle-api.mjs +1 -0
- package/src/session-runtime/mcp-glue/connect.mjs +46 -14
- package/src/session-runtime/mcp-glue/server-catalog.mjs +20 -3
- package/src/session-runtime/mcp-glue.mjs +3 -0
- 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 +85 -17
- 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/native-web-search-usage.mjs +51 -0
- package/src/session-runtime/native-web-search.mjs +10 -1
- package/src/session-runtime/new-session-config.mjs +4 -2
- package/src/session-runtime/provider-auth/login.mjs +4 -0
- package/src/session-runtime/provider-models/model-meta.mjs +12 -3
- 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 +4 -0
- package/src/session-runtime/resource-mcp-api.mjs +98 -2
- package/src/session-runtime/resource-scope-decorate.mjs +10 -3
- package/src/session-runtime/runtime-review-api.mjs +21 -2
- package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
- 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/lead-worker-index/forgotten-leads.mjs +29 -0
- package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
- package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
- 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/tag-registry.mjs +15 -1
- 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-index/row-store.mjs +10 -1
- package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
- package/src/session-runtime/services/agent-tool.mjs +3 -0
- package/src/session-runtime/services/channel-admin.mjs +19 -3
- package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
- package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
- package/src/session-runtime/services/provider-admin.mjs +81 -15
- package/src/session-runtime/session-transcript-purge.mjs +32 -0
- package/src/session-runtime/session-turn-api.mjs +14 -5
- package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
- package/src/session-runtime/settings-compaction-api.mjs +1 -0
- package/src/session-runtime/setup-tool/executor.mjs +36 -6
- package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
- package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
- package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
- package/src/session-runtime/skills-api.mjs +3 -5
- package/src/session-runtime/tool-surface.mjs +5 -1
- package/src/session-runtime/turn/compaction-gate.mjs +25 -0
- package/src/session-runtime/turn/session-ops.mjs +7 -5
- package/src/session-runtime/turn/side-question-ops.mjs +22 -0
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
- package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
- package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
- package/src/session-runtime/turn/turn-run.mjs +25 -9
- package/src/session-runtime/usage-stats-api.mjs +43 -11
- package/src/session-runtime/workspace/project-branches.mjs +7 -5
- package/src/session-runtime/workspace/transition-steps.mjs +129 -31
- package/src/session-runtime/workspace/transitions.mjs +190 -15
- package/src/standalone/daemon-agent-control.mjs +9 -1
- package/src/standalone/daemon-drain-policy.mjs +8 -0
- package/src/standalone/daemon-local-session-bridge.mjs +14 -1
- package/src/standalone/daemon-owner.mjs +17 -4
- package/src/standalone/daemon-pg-stop.mjs +51 -0
- package/src/standalone/daemon-stop-budget.d.mts +2 -0
- package/src/standalone/daemon-stop-budget.mjs +18 -0
- package/src/standalone/daemon-stored-session-views.mjs +2 -0
- package/src/standalone/daemon-telemetry.mjs +74 -0
- package/src/standalone/daemon.mjs +64 -8
- package/src/standalone/desktop-service-registry.mjs +5 -0
- package/src/standalone/local-session-runtime.mjs +70 -19
- package/src/standalone/session-client.mjs +42 -0
- package/src/standalone/session-protocol.mjs +14 -0
- package/src/standalone/session-proxy/projection.mjs +41 -4
- package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
- package/src/standalone/session-runtime-inline-host.mjs +1 -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 +18 -3
- package/src/standalone/session-service-api.mjs +11 -1
- package/src/standalone/session-service.mjs +1 -0
- package/src/standalone/session-state-patch.d.mts +2 -1
- package/src/standalone/session-state-patch.mjs +41 -1
- package/src/tui/App.jsx +25 -0
- package/src/tui/app/app-view/floating-panel.jsx +26 -1
- package/src/tui/app/app-view.jsx +1 -0
- package/src/tui/app/btw-controller.mjs +118 -0
- package/src/tui/app/create-app-pickers.mjs +6 -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.mjs +2 -1
- package/src/tui/app/model-options.mjs +11 -16
- package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
- package/src/tui/app/shell-layout/surfaces.mjs +3 -1
- package/src/tui/app/slash-commands.mjs +20 -5
- package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
- package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
- package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
- package/src/tui/app/use-global-key-input.mjs +5 -12
- package/src/tui/app/use-prompt-handlers.mjs +11 -0
- package/src/tui/components/BtwPanel.jsx +53 -0
- package/src/tui/components/QuestionPanel.jsx +275 -0
- package/src/tui/components/StatusLine.jsx +2 -0
- package/src/tui/components/question-panel-model.mjs +156 -0
- 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/dist/index.mjs +3221 -1500
- package/src/tui/session/context-state.mjs +4 -2
- package/src/tui/session/quota-resume.mjs +46 -14
- package/src/tui/session/session-api/commands.mjs +43 -24
- package/src/tui/session/session-api/controls.mjs +2 -2
- package/src/tui/session/session-api/extensions.mjs +22 -0
- package/src/tui/session/session-api/integrations.mjs +16 -2
- package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
- package/src/tui/session/session-api/lifecycle.mjs +7 -2
- package/src/tui/session/session-api/routes.mjs +71 -7
- package/src/tui/session/session-api/settings.mjs +11 -14
- package/src/tui/session/session-api.mjs +1 -0
- package/src/tui/session/session-flow/drain.mjs +7 -1
- package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
- package/src/tui/session/tool-approval.mjs +10 -7
- package/src/tui/session/transcript-spill.mjs +14 -7
- package/src/tui/session/turn-stream.mjs +174 -31
- package/src/tui/session/turn.mjs +46 -16
- 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/workflows/default/WORKFLOW.md +3 -1
- package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
- package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
|
@@ -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
|
|
|
@@ -156,6 +156,19 @@ export function readBoundedFile(
|
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
+
/**
|
|
160
|
+
* A file's state for the turn review of a tool write: null when absent, its
|
|
161
|
+
* bytes (binary included) up to PATCH_EDIT_MAX_BYTES and within `budget`,
|
|
162
|
+
* otherwise an omitted marker — counted as changed, never diffed or restored.
|
|
163
|
+
* Throws ENOTREGULAR for anything but a regular file.
|
|
164
|
+
*/
|
|
165
|
+
export function reviewFileContent(path, { budget = null } = {}) {
|
|
166
|
+
const read = readBoundedFile(path, { maxBytes: PATCH_EDIT_MAX_BYTES, budget, detectBinary: false });
|
|
167
|
+
if (read.state === 'absent') return null;
|
|
168
|
+
if (read.state === 'omitted') return { omitted: true, size: read.size, reason: read.reason };
|
|
169
|
+
return read.content;
|
|
170
|
+
}
|
|
171
|
+
|
|
159
172
|
/** Human phrase for an omitted read: "binary (N bytes)", "larger than 8 MiB (N bytes)". */
|
|
160
173
|
export function describeOmittedFile({ reason, size, limit } = {}) {
|
|
161
174
|
const bytes = `${Number(size) || 0} bytes`;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// In-process line diffs for the turn-change paths, bounded the way codex
|
|
2
|
+
// bounds its own: every file gets a short timeout, every operation (one tool
|
|
3
|
+
// call, one review or seal pass) a total budget. A file over the size limits,
|
|
4
|
+
// past its timeout or past the spent budget gets one replacement hunk between
|
|
5
|
+
// its common line prefix and suffix instead — still an exact patch that
|
|
6
|
+
// applies, only not a minimal one. Results are cached by content, so the same
|
|
7
|
+
// pair is not diffed again across calls and reviews.
|
|
8
|
+
import { createHash } from 'node:crypto';
|
|
9
|
+
import { performance } from 'node:perf_hooks';
|
|
10
|
+
import { formatPatch, structuredPatch } from 'diff';
|
|
11
|
+
|
|
12
|
+
/** Longest a single file's Myers diff may run (codex's per-file value). */
|
|
13
|
+
export const LINE_DIFF_FILE_TIMEOUT_MS = 100;
|
|
14
|
+
/** Total Myers diff time one operation may spend across its files. */
|
|
15
|
+
// Kept well under the lag target: an operation also renders, hashes and
|
|
16
|
+
// bounds its patches outside the diff itself.
|
|
17
|
+
export const LINE_DIFF_OPERATION_BUDGET_MS = 150;
|
|
18
|
+
// A side over either limit is never Myers-diffed.
|
|
19
|
+
const LINE_DIFF_MAX_CHARS = 1024 * 1024;
|
|
20
|
+
const LINE_DIFF_MAX_LINES = 20_000;
|
|
21
|
+
const CONTEXT_LINES = 3;
|
|
22
|
+
const CACHE_MAX_ENTRIES = 512;
|
|
23
|
+
// Cached hunks reference their texts: bound the cache by their length.
|
|
24
|
+
const CACHE_MAX_CHARS = 32 * 1024 * 1024;
|
|
25
|
+
|
|
26
|
+
/** One operation's diff budget; pass it to every lineDiffHunks call of it. */
|
|
27
|
+
export function createLineDiffBudget(totalMs = LINE_DIFF_OPERATION_BUDGET_MS) {
|
|
28
|
+
return { remainingMs: totalMs };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const _cache = new Map();
|
|
32
|
+
let _cachedChars = 0;
|
|
33
|
+
const _hashByBytes = new WeakMap();
|
|
34
|
+
|
|
35
|
+
const sha1 = (value) => createHash('sha1').update(value).digest('hex');
|
|
36
|
+
|
|
37
|
+
/** Content hash of one side: a byte array is hashed once per object. A text
|
|
38
|
+
* hashes to the same id as its UTF-8 bytes; one that has no exact UTF-8 form
|
|
39
|
+
* (a lone surrogate) gets no id. */
|
|
40
|
+
function sideHash(source, text) {
|
|
41
|
+
if (source && typeof source === 'object') {
|
|
42
|
+
let hash = _hashByBytes.get(source);
|
|
43
|
+
if (!hash) {
|
|
44
|
+
hash = sha1(source);
|
|
45
|
+
_hashByBytes.set(source, hash);
|
|
46
|
+
}
|
|
47
|
+
return hash;
|
|
48
|
+
}
|
|
49
|
+
return text.isWellFormed() ? sha1(text) : null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function cacheKey(sources, oldText, newText) {
|
|
53
|
+
const before = sideHash(sources[0], oldText);
|
|
54
|
+
const after = before && sideHash(sources[1], newText);
|
|
55
|
+
return after ? `${before}:${after}` : null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function cacheGet(key) {
|
|
59
|
+
const entry = _cache.get(key);
|
|
60
|
+
if (!entry) return null;
|
|
61
|
+
_cache.delete(key);
|
|
62
|
+
_cache.set(key, entry);
|
|
63
|
+
return entry.result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function cacheSet(key, result, chars) {
|
|
67
|
+
if (chars > CACHE_MAX_CHARS) return;
|
|
68
|
+
_cachedChars -= _cache.get(key)?.chars || 0;
|
|
69
|
+
_cache.delete(key);
|
|
70
|
+
_cache.set(key, { result, chars });
|
|
71
|
+
_cachedChars += chars;
|
|
72
|
+
while (_cache.size > CACHE_MAX_ENTRIES || _cachedChars > CACHE_MAX_CHARS) {
|
|
73
|
+
const [oldest, entry] = _cache.entries().next().value;
|
|
74
|
+
_cache.delete(oldest);
|
|
75
|
+
_cachedChars -= entry.chars;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function overLimits(text) {
|
|
80
|
+
if (text.length > LINE_DIFF_MAX_CHARS) return true;
|
|
81
|
+
let lines = 0;
|
|
82
|
+
for (let index = text.indexOf('\n'); index >= 0; index = text.indexOf('\n', index + 1)) {
|
|
83
|
+
lines += 1;
|
|
84
|
+
if (lines > LINE_DIFF_MAX_LINES) return true;
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Lines with their `\n` (the last one may lack it), as jsdiff tokenizes. */
|
|
90
|
+
function lineTokens(text) {
|
|
91
|
+
if (!text) return [];
|
|
92
|
+
const lines = text.split('\n');
|
|
93
|
+
const tokens = lines.map((line, index) => (index < lines.length - 1 ? `${line}\n` : line));
|
|
94
|
+
if (tokens.at(-1) === '') tokens.pop();
|
|
95
|
+
return tokens;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** The one hunk replacing everything between the texts' common line prefix
|
|
99
|
+
* and suffix, with up to three context lines each side, in jsdiff's hunk
|
|
100
|
+
* shape (`` included). */
|
|
101
|
+
function replacementHunks(oldText, newText) {
|
|
102
|
+
const before = lineTokens(oldText);
|
|
103
|
+
const after = lineTokens(newText);
|
|
104
|
+
const shortest = Math.min(before.length, after.length);
|
|
105
|
+
let start = 0;
|
|
106
|
+
while (start < shortest && before[start] === after[start]) start += 1;
|
|
107
|
+
let end = 0;
|
|
108
|
+
while (end < shortest - start && before[before.length - 1 - end] === after[after.length - 1 - end]) end += 1;
|
|
109
|
+
const lead = Math.min(CONTEXT_LINES, start);
|
|
110
|
+
const trail = Math.min(CONTEXT_LINES, end);
|
|
111
|
+
const lines = [];
|
|
112
|
+
const push = (mark, tokens) => {
|
|
113
|
+
for (const token of tokens) {
|
|
114
|
+
if (token.endsWith('\n')) lines.push(mark + token.slice(0, -1));
|
|
115
|
+
else lines.push(mark + token, '\');
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
push(' ', before.slice(start - lead, start));
|
|
119
|
+
push('-', before.slice(start, before.length - end));
|
|
120
|
+
push('+', after.slice(start, after.length - end));
|
|
121
|
+
push(' ', before.slice(before.length - end, before.length - end + trail));
|
|
122
|
+
const first = start - lead;
|
|
123
|
+
return [
|
|
124
|
+
{
|
|
125
|
+
oldStart: first + 1,
|
|
126
|
+
oldLines: before.length - end + trail - first,
|
|
127
|
+
newStart: first + 1,
|
|
128
|
+
newLines: after.length - end + trail - first,
|
|
129
|
+
lines,
|
|
130
|
+
},
|
|
131
|
+
];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Hunks (context 3, jsdiff's structuredPatch shape) turning `oldText` into
|
|
136
|
+
* `newText`: jsdiff's own when its diff finishes within the file timeout and
|
|
137
|
+
* what is left of `budget` (`exact`), else the replacement hunk. `sources`
|
|
138
|
+
* are the raw sides the texts came from (bytes or the texts), used only as
|
|
139
|
+
* the cache key. The returned value is shared: never mutate it.
|
|
140
|
+
*/
|
|
141
|
+
export function lineDiffHunks(oldText, newText, budget, sources = [oldText, newText]) {
|
|
142
|
+
if (oldText === newText) return { hunks: [], exact: true };
|
|
143
|
+
const key = cacheKey(sources, oldText, newText);
|
|
144
|
+
const cached = key ? cacheGet(key) || budget.fallbacks?.get(key) : null;
|
|
145
|
+
if (cached) return cached;
|
|
146
|
+
let result = null;
|
|
147
|
+
// A fallback forced by the operation's spent budget is not this pair's own
|
|
148
|
+
// outcome: it is not cached, so a later operation can still diff it.
|
|
149
|
+
let repeatable = true;
|
|
150
|
+
if (!overLimits(oldText) && !overLimits(newText)) {
|
|
151
|
+
if (budget.remainingMs > 0) {
|
|
152
|
+
const timeout = Math.min(LINE_DIFF_FILE_TIMEOUT_MS, budget.remainingMs);
|
|
153
|
+
const startedAt = performance.now();
|
|
154
|
+
const patch = structuredPatch('', '', oldText, newText, '', '', { context: CONTEXT_LINES, timeout });
|
|
155
|
+
budget.remainingMs -= performance.now() - startedAt;
|
|
156
|
+
if (patch) result = { hunks: patch.hunks, exact: true };
|
|
157
|
+
else repeatable = timeout >= LINE_DIFF_FILE_TIMEOUT_MS;
|
|
158
|
+
} else {
|
|
159
|
+
repeatable = false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
result ||= { hunks: replacementHunks(oldText, newText), exact: false };
|
|
163
|
+
if (key && repeatable) cacheSet(key, result, oldText.length + newText.length);
|
|
164
|
+
// Within its own operation it is final: the budget never grows back.
|
|
165
|
+
else if (key) (budget.fallbacks ||= new Map()).set(key, result);
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** The `--- `/`+++ ` headers and hunks of `hunks`, as jsdiff formats them,
|
|
170
|
+
* ending in exactly one newline. */
|
|
171
|
+
export function unifiedHunksBody(oldHeader, newHeader, hunks) {
|
|
172
|
+
const generated = formatPatch({ oldFileName: oldHeader, newFileName: newHeader, oldHeader: '', newHeader: '', hunks });
|
|
173
|
+
let end = generated.length;
|
|
174
|
+
// Linear trim: a /\n*$/ regex rescans from every position of a large patch.
|
|
175
|
+
while (end > 0 && generated.charCodeAt(end - 1) === 10) end -= 1;
|
|
176
|
+
return `${generated.slice(generated.search(/^--- /m), end)}\n`;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function _resetLineDiffCacheForTest() {
|
|
180
|
+
_cache.clear();
|
|
181
|
+
_cachedChars = 0;
|
|
182
|
+
}
|
|
@@ -175,6 +175,24 @@ export function appendBuffered(path, text) {
|
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Drop every not-yet-written chunk for `path` (its file is being deleted, so a
|
|
180
|
+
* later flush must not recreate it). A write already handed to the OS cannot
|
|
181
|
+
* be recalled; callers unlink after this and it lands before or is removed.
|
|
182
|
+
*/
|
|
183
|
+
export function discardBuffered(path) {
|
|
184
|
+
const q = queues.get(path);
|
|
185
|
+
if (!q) return;
|
|
186
|
+
if (q.timer) {
|
|
187
|
+
clearTimeout(q.timer);
|
|
188
|
+
q.timer = null;
|
|
189
|
+
}
|
|
190
|
+
q.chunks = [];
|
|
191
|
+
q.bytes = 0;
|
|
192
|
+
q.failCount = 0;
|
|
193
|
+
deleteIfIdle(path, q);
|
|
194
|
+
}
|
|
195
|
+
|
|
178
196
|
/** Observable overflow counters for buffered append queues. */
|
|
179
197
|
export function getBufferedAppenderStats(path) {
|
|
180
198
|
const q = queues.get(path);
|
|
@@ -18,8 +18,10 @@ import {
|
|
|
18
18
|
backupUserData,
|
|
19
19
|
backupUserDataAsync,
|
|
20
20
|
markUserDataInitialized,
|
|
21
|
+
ensureUserDataInitialized,
|
|
21
22
|
loadLatestMixdogConfigFromBackup,
|
|
22
|
-
|
|
23
|
+
isUserDataRecoveryExpected,
|
|
24
|
+
findLegacyUserDataEvidence,
|
|
23
25
|
} from './user-data-guard.mjs';
|
|
24
26
|
import { AGENT_PROVIDER_ENV, AGENT_PROVIDER_ENV_ALIASES, getAgentApiKey } from './provider-api-key.mjs';
|
|
25
27
|
|
|
@@ -236,7 +238,7 @@ function readConfigFile() {
|
|
|
236
238
|
}
|
|
237
239
|
}
|
|
238
240
|
|
|
239
|
-
function writeConfigFile(data) {
|
|
241
|
+
function writeConfigFile(data, postBackupReason = 'post-config-write') {
|
|
240
242
|
// R4 data-at-rest: mixdog-config.json holds provider apiKeys; clamp to
|
|
241
243
|
// owner-only on POSIX via 0o600/0o700 mode bits, AND fail-closed on
|
|
242
244
|
// Windows where those bits are advisory — `secret: true` makes the
|
|
@@ -261,29 +263,76 @@ function writeConfigFile(data) {
|
|
|
261
263
|
markUserDataInitialized(resolvePluginData());
|
|
262
264
|
} catch {}
|
|
263
265
|
try {
|
|
264
|
-
backupUserData(resolvePluginData(),
|
|
266
|
+
backupUserData(resolvePluginData(), postBackupReason);
|
|
265
267
|
} catch {}
|
|
266
268
|
}
|
|
267
269
|
|
|
270
|
+
// Config paths whose restore could not be persisted: the in-memory restore is
|
|
271
|
+
// still served, but the failure is logged (and the write retried) only once
|
|
272
|
+
// per process instead of on every read.
|
|
273
|
+
const _restorePersistFailed = new Set();
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Write a config restored on a plain read back to disk through the normal save
|
|
277
|
+
* path (atomic write + backups), so later reads hit the file instead of
|
|
278
|
+
* restoring again. Try-once lock: a contended lock means a writer (possibly
|
|
279
|
+
* this process's own outer RMW) is about to persist, so the next read retries.
|
|
280
|
+
*/
|
|
281
|
+
function persistRestoredConfig(restored) {
|
|
282
|
+
const path = configPath();
|
|
283
|
+
if (_restorePersistFailed.has(path)) return;
|
|
284
|
+
try {
|
|
285
|
+
const wrote = withFileLockSync(
|
|
286
|
+
`${path}.lock`,
|
|
287
|
+
() => {
|
|
288
|
+
if (existsSync(path)) return false;
|
|
289
|
+
writeAll(restored, 'post-restore');
|
|
290
|
+
return true;
|
|
291
|
+
},
|
|
292
|
+
{ timeoutMs: 0 }
|
|
293
|
+
);
|
|
294
|
+
if (wrote) {
|
|
295
|
+
process.stderr.write(
|
|
296
|
+
'[config] read: restored mixdog-config.json from latest user-data backup (missing after init) and saved it\n'
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
} catch (err) {
|
|
300
|
+
if (err?.code === 'ELOCKCONTENDED') return;
|
|
301
|
+
_restorePersistFailed.add(path);
|
|
302
|
+
process.stderr.write(
|
|
303
|
+
`[config] read: restored mixdog-config.json from latest user-data backup (missing after init); saving it failed, serving it from memory: ${err?.message || err}\n`
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
268
308
|
function readAll() {
|
|
269
309
|
const parsed = readConfigFile();
|
|
270
|
-
if (parsed != null)
|
|
310
|
+
if (parsed != null) {
|
|
311
|
+
// A data dir from before the in-dir init marker gets one (plus a first
|
|
312
|
+
// scoped snapshot) once per process, so its config stays recoverable.
|
|
313
|
+
try {
|
|
314
|
+
ensureUserDataInitialized(resolvePluginData());
|
|
315
|
+
} catch {}
|
|
316
|
+
return canonicalizeUnifiedConfig(parsed);
|
|
317
|
+
}
|
|
271
318
|
// Symmetric with readAllForRmW(): a missing/unreadable config on a data
|
|
272
319
|
// dir that was previously initialized means the file was LOST (deleted,
|
|
273
|
-
// failed write), not a fresh install.
|
|
320
|
+
// failed write), not a fresh install. A recreated data dir has no marker
|
|
321
|
+
// and starts fresh. Self-heal from this data dir's newest
|
|
274
322
|
// structurally-complete backup instead of silently collapsing to {} —
|
|
275
323
|
// which callers (readSection/getCapabilities) merge with in-memory
|
|
276
|
-
// defaults, dropping the user's presets/agent routes/sections.
|
|
277
|
-
//
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
|
|
324
|
+
// defaults, dropping the user's presets/agent routes/sections. The restore
|
|
325
|
+
// is persisted under the config lock (only if the file is still missing) so
|
|
326
|
+
// later reads hit the file instead of restoring and logging again.
|
|
327
|
+
// An upgraded data dir (legacy marker / matching legacy backup, no in-dir
|
|
328
|
+
// marker yet) is a recovery case too; without a verifiable backup reads stay
|
|
329
|
+
// empty and RMW writes refuse (see readAllForRmW).
|
|
330
|
+
if (isUserDataRecoveryExpected(resolvePluginData())) {
|
|
281
331
|
const restored = loadLatestMixdogConfigFromBackup(resolvePluginData());
|
|
282
332
|
if (restored && isPlainObject(restored)) {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
return canonicalizeUnifiedConfig(restored);
|
|
333
|
+
const config = canonicalizeUnifiedConfig(restored);
|
|
334
|
+
persistRestoredConfig(config);
|
|
335
|
+
return config;
|
|
287
336
|
}
|
|
288
337
|
}
|
|
289
338
|
return {};
|
|
@@ -300,11 +349,22 @@ function quarantineMalformedConfig(parseErr) {
|
|
|
300
349
|
}
|
|
301
350
|
|
|
302
351
|
function restoreAllForRmWOrThrow(reason) {
|
|
303
|
-
const restored = loadLatestMixdogConfigFromBackup(resolvePluginData());
|
|
352
|
+
const restored = loadLatestMixdogConfigFromBackup(resolvePluginData(), { fresh: true });
|
|
304
353
|
if (restored && isPlainObject(restored)) {
|
|
305
354
|
process.stderr.write(`[config] RMW read: restored mixdog-config.json from latest user-data backup (${reason})\n`);
|
|
306
355
|
return restored;
|
|
307
356
|
}
|
|
357
|
+
const legacy = findLegacyUserDataEvidence(resolvePluginData(), { fresh: true });
|
|
358
|
+
if (legacy) {
|
|
359
|
+
const err = new Error(
|
|
360
|
+
`[config] mixdog-config.json is missing but this data dir (${resolvePluginData()}) was initialized by an older ` +
|
|
361
|
+
`Mixdog build and no backup verified to belong to it was found; refusing to write a fresh config over a ` +
|
|
362
|
+
`recoverable state. Restore mixdog-config.json from a backup under ${legacy.roots.join(' or ')}, or delete ` +
|
|
363
|
+
`the legacy marker(s) to start fresh: ${legacy.markers.join(', ') || '(none; matching legacy backups are incomplete)'}`
|
|
364
|
+
);
|
|
365
|
+
err.code = 'EUSERDATARECOVERY';
|
|
366
|
+
throw err;
|
|
367
|
+
}
|
|
308
368
|
throw new Error(
|
|
309
369
|
`[config] mixdog-config.json is unreadable and no valid backup was found (${reason}); refusing section write that would wipe other sections`
|
|
310
370
|
);
|
|
@@ -321,7 +381,7 @@ function readAllForRmW() {
|
|
|
321
381
|
raw = readFileSync(configPath(), 'utf8');
|
|
322
382
|
} catch (err) {
|
|
323
383
|
if (err.code === 'ENOENT') {
|
|
324
|
-
if (
|
|
384
|
+
if (isUserDataRecoveryExpected(resolvePluginData(), { fresh: true })) {
|
|
325
385
|
return restoreAllForRmWOrThrow('config file missing after user-data was initialized');
|
|
326
386
|
}
|
|
327
387
|
return {};
|
|
@@ -402,8 +462,8 @@ export function subscribeConfigChange(listener) {
|
|
|
402
462
|
};
|
|
403
463
|
}
|
|
404
464
|
|
|
405
|
-
function writeAll(data) {
|
|
406
|
-
writeConfigFile(canonicalizeUnifiedConfig(data));
|
|
465
|
+
function writeAll(data, postBackupReason) {
|
|
466
|
+
writeConfigFile(canonicalizeUnifiedConfig(data), postBackupReason);
|
|
407
467
|
notifyConfigChanged();
|
|
408
468
|
}
|
|
409
469
|
|
|
@@ -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;
|
|
@@ -190,6 +215,12 @@ export function presentErrorText(error, options = {}) {
|
|
|
190
215
|
const name = error && typeof error === 'object' ? String(error.name || '') : '';
|
|
191
216
|
const code = error && typeof error === 'object' ? String(error.code || '') : '';
|
|
192
217
|
const status = errorHttpStatus(error);
|
|
218
|
+
// The fixed request overhead error is actionable as written (sizes,
|
|
219
|
+
// contributors, remedy): keep its lines instead of a generic "Context too
|
|
220
|
+
// large." that would suggest compacting.
|
|
221
|
+
if (code === 'TOOL_SURFACE_EXCEEDS_CONTEXT' || /\(TOOL_SURFACE_EXCEEDS_CONTEXT\)/.test(text)) {
|
|
222
|
+
return stripErrorPrefix(text);
|
|
223
|
+
}
|
|
193
224
|
const jsonError = extractJsonError(text);
|
|
194
225
|
if (jsonError) text = jsonError;
|
|
195
226
|
const embeddedError = extractEmbeddedError(text);
|