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
|
@@ -1,51 +1,37 @@
|
|
|
1
|
-
// MCP server configuration: add/save/remove/toggle
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
// MCP server configuration: add/save/remove/toggle of the user's servers, and
|
|
2
|
+
// the per-server intent (enabled flag) of servers registered plugins declare.
|
|
3
|
+
// Plugin servers are derived live (mcp-glue/plugin-servers.mjs) and are never
|
|
4
|
+
// written into `mcpServers`; ordinary edits refuse them.
|
|
5
5
|
import { clean } from '../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
6
6
|
import {
|
|
7
|
-
normalizePluginMcpServerConfig,
|
|
8
|
-
pluginMcpServerName,
|
|
9
|
-
pluginRawMcpServers,
|
|
10
|
-
pluginMcpEnableScript,
|
|
11
|
-
pluginServerMatcher,
|
|
12
|
-
resolveContainedPluginPath,
|
|
13
7
|
mergeMcpServerConfig,
|
|
14
8
|
MCP_TIMEOUT_FIELD_GROUPS,
|
|
15
9
|
} from '../runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs';
|
|
10
|
+
import { resolveMcpOAuthUrl } from '../runtime/agent/orchestrator/mcp/client-config.mjs';
|
|
11
|
+
import { withAdoptedCopies, withPinnedCollisionNames, withPluginServerIntent } from './mcp-glue/plugin-servers.mjs';
|
|
12
|
+
import { findRegisteredPlugin } from './resource-plugins-api.mjs';
|
|
13
|
+
import { createMcpOAuthLogins } from './mcp-oauth-login.mjs';
|
|
14
|
+
|
|
15
|
+
/** The URL a server's OAuth credentials are stored under, or null. */
|
|
16
|
+
function oauthUrlOf(cfg) {
|
|
17
|
+
try {
|
|
18
|
+
return resolveMcpOAuthUrl(cfg);
|
|
19
|
+
} catch {
|
|
20
|
+
// No valid remote URL: such a server never logged in.
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
16
24
|
|
|
17
25
|
/** The `mcpServers` map of a config as a fresh object (never the live one). */
|
|
18
26
|
function mcpServersOf(config) {
|
|
19
27
|
return config.mcpServers && typeof config.mcpServers === 'object' ? { ...config.mcpServers } : {};
|
|
20
28
|
}
|
|
21
29
|
|
|
22
|
-
function
|
|
23
|
-
return
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Manifest-declared servers replace every entry the plugin owned before; a
|
|
30
|
-
// single server keeps the bare name.
|
|
31
|
-
function manifestPluginMcpServers(existing, { rawServers, mcpRoot }, { plugin, serverName, env }) {
|
|
32
|
-
const keys = Object.keys(rawServers).filter((k) => {
|
|
33
|
-
const v = rawServers[k];
|
|
34
|
-
return v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
35
|
-
});
|
|
36
|
-
const owned = pluginServerMatcher(serverName);
|
|
37
|
-
const nextServers = {};
|
|
38
|
-
for (const [k, v] of Object.entries(existing || {})) {
|
|
39
|
-
if (owned(k)) continue;
|
|
40
|
-
nextServers[k] = v;
|
|
41
|
-
}
|
|
42
|
-
for (const serverKey of keys) {
|
|
43
|
-
const cfg = normalizePluginMcpServerConfig(rawServers[serverKey], mcpRoot);
|
|
44
|
-
cfg.env = { ...(cfg.env || {}), ...env };
|
|
45
|
-
if (plugin.enabled === false) cfg._mixdogPluginDisabled = true;
|
|
46
|
-
nextServers[keys.length === 1 ? serverName : `${serverName}--${serverKey}`] = cfg;
|
|
47
|
-
}
|
|
48
|
-
return nextServers;
|
|
30
|
+
function pluginOwnedError(name, owner) {
|
|
31
|
+
return new Error(
|
|
32
|
+
`MCP server "${name}" is provided by plugin "${owner.id}" (server "${owner.key}"); ` +
|
|
33
|
+
'enable or disable it with set_mcp_enabled, or manage the plugin instead'
|
|
34
|
+
);
|
|
49
35
|
}
|
|
50
36
|
|
|
51
37
|
const transportType = (type) => (type === 'streamable-http' ? 'http' : type);
|
|
@@ -80,24 +66,84 @@ function mergedServerInput(input, existing, originalName) {
|
|
|
80
66
|
export function createMcpResourceApi({ deps, sync, decorate }) {
|
|
81
67
|
const {
|
|
82
68
|
getConfig,
|
|
83
|
-
cfgMod,
|
|
84
|
-
STANDALONE_DATA_DIR,
|
|
85
69
|
saveConfigAndAdopt,
|
|
86
70
|
normalizeMcpServerInput,
|
|
87
71
|
mcpStatus,
|
|
88
72
|
getMcpServerConfig,
|
|
73
|
+
connectConfiguredMcp,
|
|
74
|
+
clearMcpServerOAuth,
|
|
89
75
|
reloadFullConfig,
|
|
90
76
|
awaitKeychainPrewarm,
|
|
77
|
+
pluginsStatus,
|
|
78
|
+
resolveMcpCatalog = () => ({ servers: {}, adoption: null, plugins: {}, entries: {} }),
|
|
79
|
+
resolveConfiguredMcpCatalog = resolveMcpCatalog,
|
|
80
|
+
pluginMcpServer = () => null,
|
|
81
|
+
flushSkillsSave,
|
|
82
|
+
cancelMcpLogin = () => {},
|
|
83
|
+
completeMcpLogin,
|
|
84
|
+
getMcpServerOAuthState = () => null,
|
|
85
|
+
probeMcpServerAuth,
|
|
91
86
|
} = deps;
|
|
92
87
|
|
|
93
|
-
|
|
88
|
+
// Explicit OAuth sign-in: the one interactive MCP connect. On success the
|
|
89
|
+
// other runtimes reconnect the server non-interactively with the new tokens.
|
|
90
|
+
const oauthLogins = createMcpOAuthLogins({
|
|
91
|
+
async connect(name, openBrowser) {
|
|
92
|
+
const status = await connectConfiguredMcp({ only: name, enabled: true, login: { openBrowser } });
|
|
93
|
+
const row = status?.servers?.find((server) => server.name === name);
|
|
94
|
+
return { connected: row?.connected === true, error: row?.error || null };
|
|
95
|
+
},
|
|
96
|
+
cancel: (name) => cancelMcpLogin(name),
|
|
97
|
+
completeCallback: completeMcpLogin,
|
|
98
|
+
onComplete: (name) => sync.announce('mcp', { detail: { mcpChanges: [{ name, enabled: true }] } }),
|
|
99
|
+
});
|
|
100
|
+
/** The effective config of a server that signs in with MCP OAuth (HTTP/SSE
|
|
101
|
+
* without configured authentication). */
|
|
102
|
+
const oauthServerConfig = async (name) => {
|
|
103
|
+
const serverName = clean(name);
|
|
104
|
+
if (!serverName) throw new Error('MCP server name is required');
|
|
105
|
+
await awaitKeychainPrewarm();
|
|
106
|
+
reloadFullConfig();
|
|
107
|
+
const cfg = resolveMcpCatalog().servers[serverName];
|
|
108
|
+
if (!cfg) throw new Error(`MCP server not configured: ${serverName}`);
|
|
109
|
+
if (!getMcpServerOAuthState(cfg)) throw new Error(`MCP server "${serverName}" does not use OAuth sign-in`);
|
|
110
|
+
return { serverName, cfg };
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/** The config with any adoptable plugin server copies already adopted, so
|
|
114
|
+
* every write also persists the adoption and never re-adds a copy. */
|
|
115
|
+
const adoptedConfig = () => withAdoptedCopies(getConfig(), resolveMcpCatalog().adoption);
|
|
116
|
+
|
|
117
|
+
/** Persist a new `mcpServers` map; project overrides never survive a global
|
|
118
|
+
* edit. A plugin server pushed off its name by the edit keeps the collision
|
|
119
|
+
* name it gets, so it does not flip again later. */
|
|
94
120
|
const saveServers = (servers) => {
|
|
95
|
-
const nextConfig = { ...
|
|
121
|
+
const nextConfig = { ...adoptedConfig() };
|
|
96
122
|
delete nextConfig.mcpProjectOverrides;
|
|
97
123
|
saveConfigAndAdopt({ ...nextConfig, mcpServers: servers });
|
|
124
|
+
const saved = getConfig();
|
|
125
|
+
const pinned = withPinnedCollisionNames(saved, resolveMcpCatalog());
|
|
126
|
+
if (pinned !== saved) saveConfigAndAdopt(pinned);
|
|
127
|
+
};
|
|
128
|
+
const userServers = () => mcpServersOf(adoptedConfig());
|
|
129
|
+
const refusePluginServer = (name) => {
|
|
130
|
+
const owned = name ? pluginMcpServer(name) : null;
|
|
131
|
+
if (owned) throw pluginOwnedError(name, owned.owner);
|
|
132
|
+
};
|
|
133
|
+
// Peers reload config from disk on receipt: land the write before publishing.
|
|
134
|
+
const persisted = async () => {
|
|
135
|
+
await flushSkillsSave?.();
|
|
98
136
|
};
|
|
99
137
|
|
|
100
138
|
return {
|
|
139
|
+
/** One-time, idempotent: move server copies an earlier plugin enable wrote
|
|
140
|
+
* into `mcpServers` to per-server plugin intent. Returns adopted names. */
|
|
141
|
+
migratePluginMcpCopies() {
|
|
142
|
+
const { adoption } = resolveMcpCatalog();
|
|
143
|
+
if (!adoption) return [];
|
|
144
|
+
saveConfigAndAdopt(withAdoptedCopies(getConfig(), adoption));
|
|
145
|
+
return adoption.removed;
|
|
146
|
+
},
|
|
101
147
|
mcpStatus() {
|
|
102
148
|
return decorate.mcp(mcpStatus());
|
|
103
149
|
},
|
|
@@ -112,28 +158,76 @@ export function createMcpResourceApi({ deps, sync, decorate }) {
|
|
|
112
158
|
const { enabled } = getMcpServerConfig(serverName);
|
|
113
159
|
return sync.reconnectMcpAndAnnounce({ only: serverName, enabled });
|
|
114
160
|
},
|
|
161
|
+
/** `{ flowId, state: 'pending', url }` once the browser login starts
|
|
162
|
+
* (`options.openBrowser === false` leaves opening `url` to the caller), or
|
|
163
|
+
* `{ flowId, state: 'complete' }` when stored credentials sufficed. */
|
|
164
|
+
async beginMcpOAuthLogin(name, options = {}) {
|
|
165
|
+
const { serverName, cfg } = await oauthServerConfig(name);
|
|
166
|
+
if (cfg.enabled === false) throw new Error(`MCP server is disabled: ${serverName}`);
|
|
167
|
+
return oauthLogins.begin(serverName, options);
|
|
168
|
+
},
|
|
169
|
+
/** `{ flowId, state: 'pending' | 'complete' | 'failed' | 'cancelled', error? }` */
|
|
170
|
+
getMcpOAuthLoginStatus(flowId) {
|
|
171
|
+
return oauthLogins.status(flowId);
|
|
172
|
+
},
|
|
173
|
+
cancelMcpOAuthLogin(flowId) {
|
|
174
|
+
return oauthLogins.cancel(flowId);
|
|
175
|
+
},
|
|
176
|
+
/** Remote / headless sign-in: complete the pending flow with the redirect
|
|
177
|
+
* URL pasted from the browser. `{ flowId, state: 'complete' | 'failed',
|
|
178
|
+
* error? }`; an invalid paste throws a fixed message and stays pending. */
|
|
179
|
+
completeMcpOAuthLogin(flowId, callbackUrl) {
|
|
180
|
+
return oauthLogins.complete(flowId, callbackUrl);
|
|
181
|
+
},
|
|
182
|
+
/** Forget the server's stored OAuth credentials (shared by every server
|
|
183
|
+
* with the same exact URL) and reconnect without a login, here and on
|
|
184
|
+
* peers, so it reports sign-in required. */
|
|
185
|
+
async signOutMcpServer(name) {
|
|
186
|
+
const { serverName, cfg } = await oauthServerConfig(name);
|
|
187
|
+
// A begin issued meanwhile waits until the credentials are gone.
|
|
188
|
+
return oauthLogins.cancelServer(serverName, async () => {
|
|
189
|
+
await clearMcpServerOAuth(cfg);
|
|
190
|
+
return sync.reconnectMcpAndAnnounce({ only: serverName, enabled: cfg.enabled !== false });
|
|
191
|
+
});
|
|
192
|
+
},
|
|
193
|
+
/** `{ auth: 'oauth' | 'none' | 'configured' | 'unreachable', error? }` for an
|
|
194
|
+
* HTTP/SSE config, without credentials or a browser. */
|
|
195
|
+
probeMcpServerAuth(cfg) {
|
|
196
|
+
if (!cfg || typeof cfg !== 'object' || Array.isArray(cfg)) throw new TypeError('MCP server config is required');
|
|
197
|
+
const probe = {};
|
|
198
|
+
for (const key of ['type', 'url', 'headers', 'bearer_token_env_var', 'env_http_headers']) {
|
|
199
|
+
if (cfg[key] !== undefined) probe[key] = cfg[key];
|
|
200
|
+
}
|
|
201
|
+
if (probe.type !== 'http' && probe.type !== 'sse') throw new TypeError("type must be 'http' or 'sse'");
|
|
202
|
+
return probeMcpServerAuth(probe);
|
|
203
|
+
},
|
|
115
204
|
async addMcpServer(input = {}) {
|
|
116
205
|
const { name, config: serverConfig } = normalizeMcpServerInput(input);
|
|
117
|
-
const servers =
|
|
206
|
+
const servers = userServers();
|
|
118
207
|
if (Object.hasOwn(servers, name)) throw new Error(`MCP server already exists: ${name}`);
|
|
208
|
+
const owned = pluginMcpServer(name);
|
|
209
|
+
if (owned) throw new Error(`MCP server already exists: ${name} (provided by plugin "${owned.owner.id}")`);
|
|
119
210
|
saveServers({ ...servers, [name]: serverConfig });
|
|
120
211
|
const status = await sync.reconnectMcpAndAnnounce({ only: name, enabled: serverConfig.enabled !== false });
|
|
121
212
|
return { name, status };
|
|
122
213
|
},
|
|
123
214
|
async saveMcpServer(input = {}) {
|
|
124
|
-
const servers =
|
|
215
|
+
const servers = userServers();
|
|
125
216
|
// An explicit originalName must exist; a bare name edits a matching
|
|
126
|
-
// server and otherwise creates a new one.
|
|
217
|
+
// server and otherwise creates a new one. Plugin servers are never
|
|
218
|
+
// edited, renamed or shadowed here.
|
|
127
219
|
const explicitOriginal = clean(input.originalName);
|
|
128
220
|
if (explicitOriginal && !Object.hasOwn(servers, explicitOriginal)) {
|
|
221
|
+
refusePluginServer(explicitOriginal);
|
|
129
222
|
throw new Error(`MCP server not configured: ${explicitOriginal}`);
|
|
130
223
|
}
|
|
131
224
|
const bareName = clean(input.name);
|
|
225
|
+
if (!explicitOriginal && !Object.hasOwn(servers, bareName)) refusePluginServer(bareName);
|
|
132
226
|
const originalName = explicitOriginal || (Object.hasOwn(servers, bareName) ? bareName : '');
|
|
133
227
|
const existing = originalName ? servers[originalName] : {};
|
|
134
228
|
const normalizedInput = normalizeMcpServerInput(mergedServerInput(input, existing, originalName));
|
|
135
229
|
const name = originalName && clean(input.name) === originalName ? originalName : normalizedInput.name;
|
|
136
|
-
if (name !== originalName && Object.hasOwn(servers, name)) {
|
|
230
|
+
if (name !== originalName && (Object.hasOwn(servers, name) || pluginMcpServer(name))) {
|
|
137
231
|
throw new Error(`MCP server already exists: ${name}`);
|
|
138
232
|
}
|
|
139
233
|
if (originalName && originalName !== name) delete servers[originalName];
|
|
@@ -149,21 +243,49 @@ export function createMcpResourceApi({ deps, sync, decorate }) {
|
|
|
149
243
|
async removeMcpServer(name) {
|
|
150
244
|
const serverName = clean(name);
|
|
151
245
|
if (!serverName) throw new Error('MCP server name is required');
|
|
152
|
-
const servers =
|
|
246
|
+
const servers = userServers();
|
|
153
247
|
if (!Object.hasOwn(servers, serverName)) {
|
|
248
|
+
refusePluginServer(serverName);
|
|
154
249
|
throw new Error(`MCP server not configured: ${serverName}`);
|
|
155
250
|
}
|
|
251
|
+
const removed = servers[serverName];
|
|
156
252
|
delete servers[serverName];
|
|
157
253
|
saveServers(servers);
|
|
158
|
-
|
|
254
|
+
const status = await sync.reconnectMcpAndAnnounce({ drop: [serverName] });
|
|
255
|
+
// A removed server keeps no OAuth tokens or client registration, unless
|
|
256
|
+
// another configured server (plugin or disabled ones included, even
|
|
257
|
+
// with MCP disabled for this runtime) still uses them through the same
|
|
258
|
+
// exact URL.
|
|
259
|
+
const url = oauthUrlOf(removed);
|
|
260
|
+
if (url && !Object.values(resolveConfiguredMcpCatalog().servers).some((cfg) => oauthUrlOf(cfg) === url)) {
|
|
261
|
+
await clearMcpServerOAuth(removed);
|
|
262
|
+
}
|
|
263
|
+
return status;
|
|
159
264
|
},
|
|
160
265
|
async setMcpServerEnabled(name, enabled) {
|
|
161
266
|
const serverName = clean(name);
|
|
162
267
|
if (!serverName) throw new Error('MCP server name is required');
|
|
163
268
|
const want = enabled !== false;
|
|
269
|
+
const owned = pluginMcpServer(serverName);
|
|
270
|
+
if (owned) {
|
|
271
|
+
// Server intent only: the effective state still requires the plugin.
|
|
272
|
+
// Only a choice that differs from the declared default is stored.
|
|
273
|
+
const { owner, pluginEnabled, declaredEnabled } = owned;
|
|
274
|
+
saveConfigAndAdopt(
|
|
275
|
+
withPluginServerIntent(adoptedConfig(), owner.id, owner.key, (intent) => ({
|
|
276
|
+
...intent,
|
|
277
|
+
enabled: want === (declaredEnabled !== false) ? undefined : want,
|
|
278
|
+
}))
|
|
279
|
+
);
|
|
280
|
+
await persisted();
|
|
281
|
+
const effective = want && pluginEnabled;
|
|
282
|
+
const status = await sync.scheduleMcpToggle(serverName, effective);
|
|
283
|
+
await sync.publish('mcp', { mcpChanges: [{ name: serverName, enabled: effective }] });
|
|
284
|
+
return status;
|
|
285
|
+
}
|
|
164
286
|
const shadowRow = mcpStatus().servers.find((s) => s.name === serverName);
|
|
165
287
|
if (!shadowRow) throw new Error(`MCP server not configured: ${serverName}`);
|
|
166
|
-
const servers =
|
|
288
|
+
const servers = userServers();
|
|
167
289
|
const current = servers[serverName];
|
|
168
290
|
if (!current || typeof current !== 'object' || Array.isArray(current)) {
|
|
169
291
|
throw new Error(`MCP server not configured: ${serverName}`);
|
|
@@ -174,38 +296,36 @@ export function createMcpResourceApi({ deps, sync, decorate }) {
|
|
|
174
296
|
await sync.publish('mcp', { mcpChanges: [{ name: serverName, enabled: want }] });
|
|
175
297
|
return status;
|
|
176
298
|
},
|
|
299
|
+
/** Kept for older callers: plugin servers appear on their own once the
|
|
300
|
+
* plugin is registered and enabled. This clears any per-server "off"
|
|
301
|
+
* intent of the plugin's servers and reconnects them (here and on peers);
|
|
302
|
+
* a disabled plugin stays disabled. */
|
|
177
303
|
async enablePluginMcp(plugin = {}) {
|
|
178
|
-
const
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
throw new Error(`plugin MCP script not found: ${join(root, script)}`);
|
|
195
|
-
nextConfig.mcpServers = {
|
|
196
|
-
...(nextConfig.mcpServers || {}),
|
|
197
|
-
[serverName]: {
|
|
198
|
-
command: 'node',
|
|
199
|
-
args: [scriptPath],
|
|
200
|
-
cwd: root,
|
|
201
|
-
env,
|
|
202
|
-
...(plugin.enabled === false ? { _mixdogPluginDisabled: true } : {}),
|
|
203
|
-
},
|
|
204
|
-
};
|
|
304
|
+
const registered = findRegisteredPlugin(pluginsStatus, plugin) || plugin;
|
|
305
|
+
const id = clean(registered.id || registered.name);
|
|
306
|
+
const catalog = resolveMcpCatalog();
|
|
307
|
+
const row = catalog.plugins[id];
|
|
308
|
+
if (!row) throw new Error(`plugin not registered: ${clean(plugin.id || plugin.name || plugin) || id}`);
|
|
309
|
+
if (!row.servers.length) {
|
|
310
|
+
const detail = row.errors.map((error) => error.message).join('; ');
|
|
311
|
+
throw new Error(`plugin declares no MCP servers${detail ? `: ${detail}` : ''}`);
|
|
312
|
+
}
|
|
313
|
+
let next = withAdoptedCopies(getConfig(), catalog.adoption);
|
|
314
|
+
for (const name of row.servers) {
|
|
315
|
+
const { owner, declaredEnabled } = catalog.entries[name];
|
|
316
|
+
next = withPluginServerIntent(next, id, owner.key, (intent) => ({
|
|
317
|
+
...intent,
|
|
318
|
+
enabled: declaredEnabled === false ? true : undefined,
|
|
319
|
+
}));
|
|
205
320
|
}
|
|
206
|
-
saveConfigAndAdopt(
|
|
207
|
-
|
|
208
|
-
|
|
321
|
+
saveConfigAndAdopt(next);
|
|
322
|
+
await persisted();
|
|
323
|
+
const mcpChanges = row.servers.map((name) => ({ name, enabled: row.enabled }));
|
|
324
|
+
let status;
|
|
325
|
+
for (const change of mcpChanges)
|
|
326
|
+
status = await connectConfiguredMcp({ only: change.name, enabled: change.enabled });
|
|
327
|
+
await sync.announce('mcp', { detail: { mcpChanges } });
|
|
328
|
+
return { serverName: row.servers[0], serverNames: row.servers, status };
|
|
209
329
|
},
|
|
210
330
|
};
|
|
211
331
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
// Plugin registry edits
|
|
1
|
+
// Plugin registry edits. A plugin's MCP servers are derived from the registry
|
|
2
|
+
// (mcp-glue/plugin-servers.mjs), so each edit reconciles this runtime's MCP
|
|
3
|
+
// connections and then lets peer runtimes reconcile theirs.
|
|
2
4
|
import { clean } from '../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
3
5
|
import {
|
|
4
6
|
addPlugin as registryAddPlugin,
|
|
@@ -6,7 +8,7 @@ import {
|
|
|
6
8
|
setPluginEnabled as registrySetPluginEnabled,
|
|
7
9
|
updatePlugin as registryUpdatePlugin,
|
|
8
10
|
} from './services/plugin-admin.mjs';
|
|
9
|
-
import {
|
|
11
|
+
import { withAdoptedCopies, withoutPluginIntents, withPinnedCollisionNames } from './mcp-glue/plugin-servers.mjs';
|
|
10
12
|
|
|
11
13
|
const pluginKey = (plugin) => clean(plugin.id || plugin.name || plugin);
|
|
12
14
|
|
|
@@ -24,22 +26,22 @@ export function createPluginsResourceApi({ deps, sync, decorate }) {
|
|
|
24
26
|
getConfig,
|
|
25
27
|
cfgMod,
|
|
26
28
|
saveConfigAndAdopt,
|
|
27
|
-
connectConfiguredMcp,
|
|
28
|
-
invalidatePreSessionToolSurface,
|
|
29
29
|
pluginsStatus,
|
|
30
|
+
resolveMcpCatalog = () => ({ adoption: null }),
|
|
31
|
+
flushSkillsSave,
|
|
30
32
|
} = deps;
|
|
31
33
|
const pluginData = () => cfgMod.getPluginData?.();
|
|
32
34
|
|
|
33
|
-
/**
|
|
34
|
-
*
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
35
|
+
/** Persist any adoptable copies of plugin servers while the registry still
|
|
36
|
+
* knows their plugin (a removal must not leave them stranded), and keep any
|
|
37
|
+
* collision name a plugin server was just given. */
|
|
38
|
+
async function adoptPluginServerCopies(transform = (config) => config) {
|
|
39
|
+
const current = getConfig();
|
|
40
|
+
const catalog = resolveMcpCatalog();
|
|
41
|
+
const next = transform(withPinnedCollisionNames(withAdoptedCopies(current, catalog.adoption), catalog));
|
|
42
|
+
if (next === current) return;
|
|
43
|
+
saveConfigAndAdopt(next);
|
|
44
|
+
await flushSkillsSave?.();
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
return {
|
|
@@ -47,49 +49,35 @@ export function createPluginsResourceApi({ deps, sync, decorate }) {
|
|
|
47
49
|
return decorate.plugins(pluginsStatus());
|
|
48
50
|
},
|
|
49
51
|
async reloadPlugins() {
|
|
50
|
-
await sync.
|
|
52
|
+
await sync.reconcilePluginsAndAnnounce();
|
|
51
53
|
return pluginsStatus();
|
|
52
54
|
},
|
|
53
55
|
async addPlugin(source) {
|
|
54
56
|
const plugin = registryAddPlugin(source, { dataDir: pluginData() });
|
|
55
|
-
await
|
|
57
|
+
await adoptPluginServerCopies();
|
|
58
|
+
await sync.reconcilePluginsAndAnnounce();
|
|
56
59
|
return { plugin, status: pluginsStatus() };
|
|
57
60
|
},
|
|
58
61
|
async updatePlugin(plugin = {}) {
|
|
59
62
|
const updated = registryUpdatePlugin(pluginKey(plugin), { dataDir: pluginData() });
|
|
60
|
-
await
|
|
63
|
+
await adoptPluginServerCopies();
|
|
64
|
+
await sync.reconcilePluginsAndAnnounce();
|
|
61
65
|
return { plugin: updated, status: pluginsStatus() };
|
|
62
66
|
},
|
|
63
67
|
async setPluginEnabled(plugin = {}, enabled = true) {
|
|
64
|
-
|
|
68
|
+
await adoptPluginServerCopies();
|
|
65
69
|
const updated = registrySetPluginEnabled(pluginKey(plugin), enabled, { dataDir: pluginData() });
|
|
66
|
-
await
|
|
67
|
-
const next = {};
|
|
68
|
-
for (const [name, value] of Object.entries(servers)) {
|
|
69
|
-
const config = value && typeof value === 'object' && !Array.isArray(value) ? { ...value } : value;
|
|
70
|
-
if (owned(name) && config && typeof config === 'object' && !Array.isArray(config)) {
|
|
71
|
-
if (enabled === false) config._mixdogPluginDisabled = true;
|
|
72
|
-
else delete config._mixdogPluginDisabled;
|
|
73
|
-
}
|
|
74
|
-
next[name] = config;
|
|
75
|
-
}
|
|
76
|
-
return next;
|
|
77
|
-
});
|
|
78
|
-
await sync.announce('plugins');
|
|
70
|
+
await sync.reconcilePluginsAndAnnounce();
|
|
79
71
|
return { plugin: updated, status: pluginsStatus() };
|
|
80
72
|
},
|
|
81
73
|
async removePlugin(plugin = {}) {
|
|
82
|
-
|
|
83
|
-
const
|
|
74
|
+
const owner = findRegisteredPlugin(pluginsStatus, plugin);
|
|
75
|
+
const ownerId = clean(owner?.id);
|
|
76
|
+
// Adopt first (the registry still knows the plugin), then drop the
|
|
77
|
+
// plugin's per-server intent together with the plugin.
|
|
78
|
+
await adoptPluginServerCopies((config) => (ownerId ? withoutPluginIntents(config, ownerId) : config));
|
|
84
79
|
const removed = registryRemovePlugin(pluginKey(plugin), { dataDir: pluginData() });
|
|
85
|
-
await
|
|
86
|
-
const next = { ...servers };
|
|
87
|
-
for (const name of Object.keys(next)) {
|
|
88
|
-
if (owned(name)) delete next[name];
|
|
89
|
-
}
|
|
90
|
-
return next;
|
|
91
|
-
});
|
|
92
|
-
await sync.announce('plugins');
|
|
80
|
+
await sync.reconcilePluginsAndAnnounce();
|
|
93
81
|
return { plugin: removed, status: pluginsStatus() };
|
|
94
82
|
},
|
|
95
83
|
};
|
|
@@ -7,19 +7,17 @@ import {
|
|
|
7
7
|
cwdWithinProjects,
|
|
8
8
|
extensionScopeProjects,
|
|
9
9
|
extensionScopesFromConfig,
|
|
10
|
-
pluginIdForMcpServer,
|
|
11
10
|
} from '../runtime/agent/orchestrator/runtime-core/extension-scopes.mjs';
|
|
12
11
|
|
|
13
12
|
function listOf(status, key) {
|
|
14
13
|
return Array.isArray(status?.[key]) ? status[key] : [];
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
export function createScopeDecorators({ getConfig, getCurrentCwd
|
|
18
|
-
function scopeInfo(kind, name, pluginId = '') {
|
|
16
|
+
export function createScopeDecorators({ getConfig, getCurrentCwd }) {
|
|
17
|
+
function scopeInfo(kind, name, pluginId = '', cwd = getCurrentCwd()) {
|
|
19
18
|
const scopes = extensionScopesFromConfig(getConfig());
|
|
20
19
|
const scope = extensionScopeProjects(scopes, kind, name);
|
|
21
20
|
const inheritedScope = pluginId ? extensionScopeProjects(scopes, 'plugins', pluginId) : null;
|
|
22
|
-
const cwd = getCurrentCwd();
|
|
23
21
|
const activeHere =
|
|
24
22
|
(scope ? cwdWithinProjects(cwd, scope) : true) &&
|
|
25
23
|
(inheritedScope ? cwdWithinProjects(cwd, inheritedScope) : true);
|
|
@@ -27,21 +25,21 @@ export function createScopeDecorators({ getConfig, getCurrentCwd, pluginsStatus
|
|
|
27
25
|
}
|
|
28
26
|
return {
|
|
29
27
|
mcp(status) {
|
|
30
|
-
const plugins = pluginsStatus()?.plugins || [];
|
|
31
28
|
return {
|
|
32
29
|
...status,
|
|
33
30
|
servers: listOf(status, 'servers').map((server) => ({
|
|
34
31
|
...server,
|
|
35
|
-
...scopeInfo('mcp', server.name,
|
|
32
|
+
...scopeInfo('mcp', server.name, server?.owner?.kind === 'plugin' ? clean(server.owner.id) : ''),
|
|
36
33
|
})),
|
|
37
34
|
};
|
|
38
35
|
},
|
|
39
|
-
|
|
36
|
+
/** `cwd`: decide `activeHere` for that folder instead of the current one. */
|
|
37
|
+
skills(status, cwd = getCurrentCwd()) {
|
|
40
38
|
return {
|
|
41
39
|
...status,
|
|
42
40
|
skills: listOf(status, 'skills').map((skill) => ({
|
|
43
41
|
...skill,
|
|
44
|
-
...scopeInfo('skills', skill.name, skill?.owner?.kind === 'plugin' ? clean(skill.owner.id) : ''),
|
|
42
|
+
...scopeInfo('skills', skill.name, skill?.owner?.kind === 'plugin' ? clean(skill.owner.id) : '', cwd),
|
|
45
43
|
})),
|
|
46
44
|
};
|
|
47
45
|
},
|
|
@@ -1,4 +1,23 @@
|
|
|
1
1
|
// Global Skill documents and the disabled-skill list.
|
|
2
|
+
import { statSync } from 'node:fs';
|
|
3
|
+
import { isAbsolute, resolve } from 'node:path';
|
|
4
|
+
|
|
5
|
+
/** `skillsStatus({ cwd })`: the folder to list and scope skills for, in place
|
|
6
|
+
* of the session's own. Only an existing absolute directory; it reads the
|
|
7
|
+
* same skill roots a session opened there would, nothing wider. */
|
|
8
|
+
function statusCwd(options) {
|
|
9
|
+
if (options == null) return '';
|
|
10
|
+
const cwd = options?.cwd;
|
|
11
|
+
if (typeof cwd !== 'string' || !cwd || cwd.includes('\0') || !isAbsolute(cwd)) {
|
|
12
|
+
throw new TypeError('skillsStatus cwd must be an absolute path.');
|
|
13
|
+
}
|
|
14
|
+
const folder = resolve(cwd);
|
|
15
|
+
if (!statSync(folder, { throwIfNoEntry: false })?.isDirectory()) {
|
|
16
|
+
throw new TypeError('skillsStatus cwd is not a directory.');
|
|
17
|
+
}
|
|
18
|
+
return folder;
|
|
19
|
+
}
|
|
20
|
+
|
|
2
21
|
export function createSkillsResourceApi({ deps, sync, decorate }) {
|
|
3
22
|
const {
|
|
4
23
|
skillsStatus,
|
|
@@ -11,8 +30,10 @@ export function createSkillsResourceApi({ deps, sync, decorate }) {
|
|
|
11
30
|
flushSkillsSave,
|
|
12
31
|
} = deps;
|
|
13
32
|
return {
|
|
14
|
-
skillsStatus() {
|
|
15
|
-
|
|
33
|
+
skillsStatus(options) {
|
|
34
|
+
const cwd = statusCwd(options);
|
|
35
|
+
if (!cwd) return decorate.skills(skillsStatus());
|
|
36
|
+
return decorate.skills(skillsStatus({ cwd }), cwd);
|
|
16
37
|
},
|
|
17
38
|
skillContent(name) {
|
|
18
39
|
return skillContent(name);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { registerCacheInvalidationListener } from '../runtime/agent/orchestrator/tools/builtin/cache-layers.mjs';
|
|
2
2
|
import { turnReviewReply } from '../runtime/shared/turn-review-reply.mjs';
|
|
3
3
|
import {
|
|
4
|
+
clearSessionChangeHistory,
|
|
4
5
|
getSessionReviewDiff,
|
|
5
6
|
getTurnChanges,
|
|
6
7
|
getTurnReviewDiff,
|
|
@@ -10,6 +11,17 @@ import {
|
|
|
10
11
|
revertTurnReviewFile,
|
|
11
12
|
} from '../runtime/shared/turn-snapshot.mjs';
|
|
12
13
|
import { noteTurnWorktreeChange } from '../runtime/shared/turn-worktree-snapshot.mjs';
|
|
14
|
+
import { forgetSessionChangeHistoryMarker } from '../runtime/shared/turn-snapshot-store.mjs';
|
|
15
|
+
import { forgetSessionBaselines } from '../runtime/shared/session-baseline-store.mjs';
|
|
16
|
+
import { registerSessionPurgeHook } from '../runtime/agent/orchestrator/session/store.mjs';
|
|
17
|
+
|
|
18
|
+
// A deleted history stays deleted for as long as its session exists; the
|
|
19
|
+
// session's own deletion takes the marker — and its stored first-seen file
|
|
20
|
+
// contents — with it.
|
|
21
|
+
registerSessionPurgeHook((sessionId) => {
|
|
22
|
+
void forgetSessionChangeHistoryMarker(sessionId);
|
|
23
|
+
void forgetSessionBaselines(sessionId);
|
|
24
|
+
});
|
|
13
25
|
|
|
14
26
|
// Tool writes (apply_patch, mutating shell commands, git, watcher events)
|
|
15
27
|
// reach the live review snapshot as its change signal: a review poll right
|
|
@@ -31,5 +43,6 @@ export function createRuntimeReviewApi({ getCwd, getSessionId }) {
|
|
|
31
43
|
revertTurnChanges(getSessionId(), checkpointId, file, revision),
|
|
32
44
|
reapplyTurnChanges: (checkpointId, file, revision) =>
|
|
33
45
|
reapplyTurnChanges(getSessionId(), checkpointId, file, revision),
|
|
46
|
+
clearSessionChangeHistory: () => clearSessionChangeHistory(getSessionId()),
|
|
34
47
|
};
|
|
35
48
|
}
|
|
@@ -65,7 +65,7 @@ export async function runScheduleSession(schedule, { config = null, prompt: prom
|
|
|
65
65
|
const result = await runAutomationTurns(
|
|
66
66
|
session.id,
|
|
67
67
|
() => askSession(session.id, content, null, null, cwd || undefined),
|
|
68
|
-
(completions) => askSession(session.id, completions, null, null, cwd || undefined)
|
|
68
|
+
(completions, askOpts) => askSession(session.id, completions, null, null, cwd || undefined, undefined, askOpts)
|
|
69
69
|
);
|
|
70
70
|
return { sessionId: session.id, result: String(result?.content || '') };
|
|
71
71
|
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
// Every call is idempotent (the first terminal state wins, so the outer reject
|
|
20
20
|
// path cannot double-notify) and absorbs its own errors, so reporting on a
|
|
21
21
|
// turn can never break the turn.
|
|
22
|
-
import { reconcileBackgroundTask } from '../../../runtime/shared/background-tasks.mjs';
|
|
22
|
+
import { reconcileBackgroundTask, settleCancelledBackgroundTask } from '../../../runtime/shared/background-tasks.mjs';
|
|
23
23
|
|
|
24
24
|
function reconcileJobTerminalResult(job, value) {
|
|
25
25
|
if (!job?.taskId) return;
|
|
@@ -50,6 +50,8 @@ export function terminalResultHook({ job, turnReview, completionValue, notifyEar
|
|
|
50
50
|
turnReview.complete();
|
|
51
51
|
const value = completionValue(terminalResult);
|
|
52
52
|
job._terminalResultValue = value;
|
|
53
|
+
// A cancelled job reports once, as `cancelled`, when its turn settles.
|
|
54
|
+
if (job.status === 'cancelled') return;
|
|
53
55
|
notifyEarly(job, value, notifyContext || {});
|
|
54
56
|
reconcileJobTerminalResult(job, value);
|
|
55
57
|
};
|
|
@@ -67,6 +69,16 @@ export function reconcileJobWatchdogPartial(job, value) {
|
|
|
67
69
|
} catch {}
|
|
68
70
|
}
|
|
69
71
|
|
|
72
|
+
/** The cancelled turn stopped: deliver the owner's single `cancelled`
|
|
73
|
+
* notification, carrying the output the turn produced before it stopped
|
|
74
|
+
* (header-only when it produced none). */
|
|
75
|
+
export function reconcileJobCancelled(job, value) {
|
|
76
|
+
if (!job?.taskId) return;
|
|
77
|
+
try {
|
|
78
|
+
settleCancelledBackgroundTask(job.taskId, value?.content ? { result: value } : {});
|
|
79
|
+
} catch {}
|
|
80
|
+
}
|
|
81
|
+
|
|
70
82
|
export function reconcileJobStreamStalled(job, error) {
|
|
71
83
|
if (!job?.taskId || job._terminalResultValue !== undefined) return;
|
|
72
84
|
try {
|