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,4 +1,5 @@
|
|
|
1
1
|
// Deferred-pool and MCP-instruction manifests injected into BP2.
|
|
2
|
+
import { parseMcpToolName } from '../../../shared/tool-primitives.mjs';
|
|
2
3
|
|
|
3
4
|
export function compactPromptManifestText(value, max = 250) {
|
|
4
5
|
const text = String(value || '')
|
|
@@ -100,16 +101,21 @@ function sanitizeMcpInstructionText(text, max = MCP_INSTRUCTION_MAX_CHARS) {
|
|
|
100
101
|
* names per server doubled the MCP share of the BP2 prefix (2026-08-05 audit).
|
|
101
102
|
* Server membership stays evident from the mcp__<server>__ name prefix.
|
|
102
103
|
*/
|
|
103
|
-
function buildMcpInstructionsManifest(mcpServerInstructions, poolNames) {
|
|
104
|
+
function buildMcpInstructionsManifest(mcpServerInstructions, poolNames, catalog = []) {
|
|
104
105
|
const map = mcpServerInstructions && typeof mcpServerInstructions === 'object' ? mcpServerInstructions : {};
|
|
105
106
|
const pool = [
|
|
106
107
|
...new Set((Array.isArray(poolNames) ? poolNames : []).map((name) => sanitizeManifestName(name)).filter(Boolean)),
|
|
107
108
|
];
|
|
109
|
+
// Tool definitions carry their server (shortened names cannot be parsed).
|
|
110
|
+
const byName = new Map();
|
|
111
|
+
for (const tool of Array.isArray(catalog) ? catalog : []) {
|
|
112
|
+
const name = String(tool?.name || '').trim();
|
|
113
|
+
if (name && !byName.has(name)) byName.set(name, tool);
|
|
114
|
+
}
|
|
108
115
|
const deferredServers = new Set();
|
|
109
116
|
for (const name of pool) {
|
|
110
|
-
const
|
|
111
|
-
if (
|
|
112
|
-
deferredServers.add(match[1]);
|
|
117
|
+
const server = parseMcpToolName(byName.get(name) || name)?.server;
|
|
118
|
+
if (server) deferredServers.add(server);
|
|
113
119
|
}
|
|
114
120
|
const servers = [...deferredServers]
|
|
115
121
|
.filter((server) => sanitizeManifestName(server) && sanitizeMcpInstructionText(map[server]))
|
|
@@ -170,7 +176,7 @@ function composeDeferredBp2Manifest(session, pool) {
|
|
|
170
176
|
const parts = [];
|
|
171
177
|
const deferredManifest = buildDeferredToolManifest(deferredManifestEntries(session, pool));
|
|
172
178
|
if (deferredManifest) parts.push(deferredManifest);
|
|
173
|
-
const mcpManifest = buildMcpInstructionsManifest(session.mcpServerInstructions, pool);
|
|
179
|
+
const mcpManifest = buildMcpInstructionsManifest(session.mcpServerInstructions, pool, session.deferredToolCatalog);
|
|
174
180
|
if (mcpManifest) parts.push(mcpManifest);
|
|
175
181
|
return parts.join('\n\n');
|
|
176
182
|
}
|
|
@@ -3,15 +3,16 @@
|
|
|
3
3
|
|
|
4
4
|
import { readFileSync, existsSync, readdirSync } from 'node:fs';
|
|
5
5
|
import { basename, dirname, join } from 'node:path';
|
|
6
|
-
import { maxMtimeRecursive } from '../cache-mtime.mjs';
|
|
6
|
+
import { maxMtimeRecursive, mtimeSignatureRecursive } from '../cache-mtime.mjs';
|
|
7
7
|
import { mixdogHome, resolvePluginData, mixdogRoot } from '../../../shared/plugin-paths.mjs';
|
|
8
|
-
import { pluginSkillsRoots } from '../../../shared/plugin-manifest.mjs';
|
|
8
|
+
import { PLUGIN_MANIFEST_FILES, pluginSkillsRoots } from '../../../shared/plugin-manifest.mjs';
|
|
9
9
|
import {
|
|
10
10
|
parseSkillDocument,
|
|
11
11
|
SKILL_TRIGGER_LISTING_MAX,
|
|
12
12
|
SKILL_TRIGGER_LISTING_MIN,
|
|
13
13
|
} from '../../../shared/skill-document.mjs';
|
|
14
14
|
import { readSkillToolDependencies, skillToolDependenciesRoot } from '../../../shared/skill-tool-dependencies.mjs';
|
|
15
|
+
import { SKILL_LAUNCHER_COMMAND } from '../../../shared/skill-script-runtime.mjs';
|
|
15
16
|
import { loadConfig, normalizeSkillsConfig } from '../config.mjs';
|
|
16
17
|
import { builtinFeatureActive, withGrandfatheredBuiltins } from '../runtime-core/builtin-features.mjs';
|
|
17
18
|
import { SKILL_TOOL } from '../runtime-core/tool-defs.mjs';
|
|
@@ -88,6 +89,32 @@ function pluginSkillDirs() {
|
|
|
88
89
|
return dirs;
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
/** Paths whose own mtime (no recursion) gates the skill list for enabled
|
|
93
|
+
* registered plugins: every manifest file, plus the nearest existing ancestor
|
|
94
|
+
* of each candidate skills root (so a skills dir created later is noticed). */
|
|
95
|
+
function pluginShallowWatchPaths() {
|
|
96
|
+
const registryPath = pluginRegistryPath();
|
|
97
|
+
let registry;
|
|
98
|
+
try {
|
|
99
|
+
registry = JSON.parse(readFileSync(registryPath, 'utf-8'));
|
|
100
|
+
} catch {
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
const paths = [];
|
|
104
|
+
for (const entry of Array.isArray(registry?.plugins) ? registry.plugins : []) {
|
|
105
|
+
if (entry?.enabled === false) continue;
|
|
106
|
+
const root = entry && typeof entry.root === 'string' ? entry.root : null;
|
|
107
|
+
if (!root || !existsSync(root)) continue;
|
|
108
|
+
for (const rel of PLUGIN_MANIFEST_FILES) paths.push(join(root, ...rel.split('/')));
|
|
109
|
+
for (const skillsDir of pluginSkillsRoots(root)) {
|
|
110
|
+
let dir = skillsDir;
|
|
111
|
+
while (!existsSync(dir) && dirname(dir) !== dir) dir = dirname(dir);
|
|
112
|
+
paths.push(dir);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return paths;
|
|
116
|
+
}
|
|
117
|
+
|
|
91
118
|
export function readSafe(path) {
|
|
92
119
|
try {
|
|
93
120
|
if (!existsSync(path)) return null;
|
|
@@ -216,24 +243,39 @@ function followsBuiltinFeature(skill) {
|
|
|
216
243
|
return skill?.source === 'builtin' && Array.isArray(skill.requires) && skill.requires.length > 0;
|
|
217
244
|
}
|
|
218
245
|
|
|
219
|
-
function findCachedSkillByKey(key) {
|
|
220
|
-
return collectSkillsCached(null).find((entry) => normalizeSkillNameKey(entry.name) === key);
|
|
246
|
+
function findCachedSkillByKey(key, skills = null) {
|
|
247
|
+
return (skills || collectSkillsCached(null)).find((entry) => normalizeSkillNameKey(entry.name) === key);
|
|
221
248
|
}
|
|
222
249
|
|
|
223
|
-
|
|
250
|
+
/** `skills`: optional snapshot from one collectSkillsCached() call, reused so a
|
|
251
|
+
* batch of per-skill checks scans the disk once. */
|
|
252
|
+
export function isSkillDisabled(name, config = null, skills = null) {
|
|
224
253
|
const n = normalizeSkillNameKey(name);
|
|
225
254
|
if (!n) return false;
|
|
226
|
-
const skill = findCachedSkillByKey(n);
|
|
255
|
+
const skill = findCachedSkillByKey(n, skills);
|
|
227
256
|
if (!followsBuiltinFeature(skill) && getDisabledSkillNameSet(config).has(n)) return true;
|
|
228
257
|
return Boolean(skill && missingFeature(skill, featureConfig(config)));
|
|
229
258
|
}
|
|
230
259
|
|
|
231
260
|
/** The built-in feature a skill needs that is not active, or null. */
|
|
232
|
-
export function skillMissingFeature(name, config = null) {
|
|
233
|
-
const skill = findCachedSkillByKey(normalizeSkillNameKey(name));
|
|
261
|
+
export function skillMissingFeature(name, config = null, skills = null) {
|
|
262
|
+
const skill = findCachedSkillByKey(normalizeSkillNameKey(name), skills);
|
|
234
263
|
return skill ? missingFeature(skill, featureConfig(config)) : null;
|
|
235
264
|
}
|
|
236
265
|
|
|
266
|
+
/** True when an installed skill exists but its (or its plugin's) project scope
|
|
267
|
+
* excludes `cwd` — the same scope rule filterSkillsExcludingDisabled applies. */
|
|
268
|
+
export function skillOutsideScope(name, cwd, config = null, skills = null) {
|
|
269
|
+
const skill = findCachedSkillByKey(normalizeSkillNameKey(name), skills);
|
|
270
|
+
if (!skill) return false;
|
|
271
|
+
return !skillAllowedForCwd(extensionScopesFromConfig(featureConfig(config)), skill, cwd);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/** The Skill tool result for a skill skillOutsideScope refuses. */
|
|
275
|
+
export function skillOutsideScopeError(name) {
|
|
276
|
+
return `Error: skill "${name}" is not available in this project (its project scope excludes the current folder)`;
|
|
277
|
+
}
|
|
278
|
+
|
|
237
279
|
/**
|
|
238
280
|
* Skills a session may see: not switched off, feature available, and — when
|
|
239
281
|
* `cwd` is given — inside the skill's (or its plugin's) project scope. Without
|
|
@@ -260,8 +302,6 @@ export function collectPromptSkillsCached(cwd, config = null) {
|
|
|
260
302
|
}
|
|
261
303
|
// --- Global skill cache (mtime-based) ---
|
|
262
304
|
const _skillsCache = new Map();
|
|
263
|
-
const _mtimeCache = new Map();
|
|
264
|
-
const _MTIME_TTL_MS = 2000;
|
|
265
305
|
|
|
266
306
|
export function collectSkillsCached(cwd) {
|
|
267
307
|
if (skillsDisabled()) return [];
|
|
@@ -273,32 +313,41 @@ export function collectSkillsCached(cwd) {
|
|
|
273
313
|
skillsDirs.push(...pluginSkillDirs().map(({ dir }) => dir), ...builtinSkillDirs());
|
|
274
314
|
// registry.json itself gates plugin add/remove: removal deletes the
|
|
275
315
|
// plugin's skills dir (so no dir mtime advances), but saveRegistry()
|
|
276
|
-
// always rewrites this file.
|
|
316
|
+
// always rewrites this file. mtimeSignatureRecursive stats plain files directly.
|
|
277
317
|
const registryPath = pluginRegistryPath();
|
|
278
318
|
if (registryPath) skillsDirs.push(registryPath);
|
|
279
|
-
|
|
319
|
+
// Exact, un-timed gate: stat every call. The shallow watch list covers
|
|
320
|
+
// manifest edits and skill roots that do not exist yet.
|
|
321
|
+
const signature = `${mtimeSignatureRecursive(skillsDirs)}|${mtimeSignatureRecursive(pluginShallowWatchPaths(), 0)}`;
|
|
280
322
|
const entry = _skillsCache.get(key);
|
|
281
|
-
if (entry && entry.
|
|
323
|
+
if (entry && entry.signature === signature) {
|
|
282
324
|
return entry.value;
|
|
283
325
|
}
|
|
284
326
|
const skills = collectSkills(cwd);
|
|
285
|
-
_skillsCache.set(key, { value: skills,
|
|
327
|
+
_skillsCache.set(key, { value: skills, signature });
|
|
286
328
|
capMapSize(_skillsCache);
|
|
287
329
|
return skills;
|
|
288
330
|
}
|
|
289
331
|
export function invalidateSkillsCache(cwd) {
|
|
290
332
|
void cwd;
|
|
291
333
|
_skillsCache.clear();
|
|
292
|
-
_mtimeCache.clear();
|
|
293
334
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Directory the model hands to external processes for a skill. A packaged
|
|
338
|
+
* desktop runtime reads built-in skills from inside `runtime.asar`, which only
|
|
339
|
+
* Electron can open; the build ships them as real files beside the archive
|
|
340
|
+
* under `runtime.asar.unpacked`, so a built-in skill's directory points there.
|
|
341
|
+
* Every other source keeps its own on-disk directory.
|
|
342
|
+
*/
|
|
343
|
+
export function skillExecutionDir(dir, source) {
|
|
344
|
+
if (source !== 'builtin') return dir;
|
|
345
|
+
return String(dir).replace(/([\\/])runtime\.asar(?=[\\/]|$)/, '$1runtime.asar.unpacked');
|
|
298
346
|
}
|
|
299
347
|
|
|
300
348
|
/**
|
|
301
|
-
* Load full skill content plus its on-disk directory (for base-dir + ${MIXDOG_SKILL_DIR}
|
|
349
|
+
* Load full skill content plus its on-disk directory (for base-dir + ${MIXDOG_SKILL_DIR};
|
|
350
|
+
* ${MIXDOG_SKILL_NODE} is resolved at render time in buildSkillResultEnvelope).
|
|
302
351
|
*/
|
|
303
352
|
export function loadSkillResource(name, cwd) {
|
|
304
353
|
const skillName = String(name || '').trim();
|
|
@@ -311,7 +360,7 @@ export function loadSkillResource(name, cwd) {
|
|
|
311
360
|
try {
|
|
312
361
|
return {
|
|
313
362
|
content: parseSkillDocument(content).body,
|
|
314
|
-
dir: dirname(skill.filePath),
|
|
363
|
+
dir: skillExecutionDir(dirname(skill.filePath), skill.source),
|
|
315
364
|
filePath: skill.filePath,
|
|
316
365
|
source: skill.source || 'global',
|
|
317
366
|
toolDependencies: skill.toolDependencies || [],
|
|
@@ -335,6 +384,10 @@ export function buildSkillResultEnvelope(name, content, skillDir) {
|
|
|
335
384
|
const escapedName = escapeSkillXmlText(name);
|
|
336
385
|
let body = String(content == null ? '' : content);
|
|
337
386
|
let dirLine = '';
|
|
387
|
+
// `${MIXDOG_SKILL_NODE}` runs a bundled script on this daemon's own runtime
|
|
388
|
+
// (plain node cannot load runtime internals from a packaged archive). It is
|
|
389
|
+
// one shell-neutral command name that model shells find on their PATH.
|
|
390
|
+
body = body.replace(/\$\{MIXDOG_SKILL_NODE\}/g, SKILL_LAUNCHER_COMMAND);
|
|
338
391
|
if (skillDir) {
|
|
339
392
|
const normDir = String(skillDir).replace(/\\/g, '/');
|
|
340
393
|
body = body.replace(/\$\{MIXDOG_SKILL_DIR\}/g, normDir);
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* kind, URL policy, env expansion, stdio environment, HTTP headers, timeouts,
|
|
4
4
|
* and the log scrubbing that keeps credentials out of connection messages.
|
|
5
5
|
*/
|
|
6
|
+
import { createHash } from 'node:crypto';
|
|
7
|
+
import { rememberMcpToolIdentity } from '../../../shared/tool-primitives.mjs';
|
|
6
8
|
|
|
7
9
|
/** Known auto-detect targets: the discovery-advert service name and the MCP
|
|
8
10
|
* endpoint path on its port.
|
|
@@ -77,20 +79,41 @@ export function mcpUrlForLog(raw) {
|
|
|
77
79
|
|
|
78
80
|
function replaceSecret(text, value) {
|
|
79
81
|
const secret = String(value || '');
|
|
80
|
-
return secret
|
|
82
|
+
return secret ? text.split(secret).join('[redacted]') : text;
|
|
81
83
|
}
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
// Configured URL parts and header values shorter than 4 characters are left
|
|
86
|
+
// alone: redacting e.g. the `1` of `?v=1` would mangle every message. Known
|
|
87
|
+
// connection secrets (OAuth tokens) are redacted at any length.
|
|
88
|
+
function replaceConfiguredSecret(text, value) {
|
|
89
|
+
return String(value || '').length >= 4 ? replaceSecret(text, value) : text;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** `value` with every one of `secrets` redacted from its strings, recursing
|
|
93
|
+
* into arrays and plain objects (tool results, JSON-RPC error data). */
|
|
94
|
+
export function scrubMcpSecrets(value, secrets) {
|
|
95
|
+
if (secrets.length === 0) return value;
|
|
96
|
+
if (typeof value === 'string') return secrets.reduce(replaceSecret, value);
|
|
97
|
+
if (Array.isArray(value)) return value.map((item) => scrubMcpSecrets(item, secrets));
|
|
98
|
+
const proto = value && typeof value === 'object' ? Object.getPrototypeOf(value) : undefined;
|
|
99
|
+
if (proto !== Object.prototype && proto !== null) return value;
|
|
100
|
+
return Object.fromEntries(
|
|
101
|
+
Object.entries(value).map(([key, item]) => [scrubMcpSecrets(key, secrets), scrubMcpSecrets(item, secrets)])
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** `secrets` are values known only to the live connection (its OAuth tokens). */
|
|
106
|
+
export function scrubMcpConnectionMessage(value, cfg = {}, secrets = []) {
|
|
107
|
+
let text = scrubMcpSecrets(String(value || ''), secrets);
|
|
85
108
|
const rawUrl = expandEnvVars(String(cfg?.url || ''));
|
|
86
109
|
if (rawUrl) {
|
|
87
110
|
text = text.split(rawUrl).join(mcpUrlForLog(rawUrl));
|
|
88
111
|
try {
|
|
89
112
|
const parsed = new URL(rawUrl);
|
|
90
|
-
text =
|
|
91
|
-
text =
|
|
113
|
+
text = replaceConfiguredSecret(text, parsed.username);
|
|
114
|
+
text = replaceConfiguredSecret(text, parsed.password);
|
|
92
115
|
for (const paramValue of parsed.searchParams.values()) {
|
|
93
|
-
text =
|
|
116
|
+
text = replaceConfiguredSecret(text, paramValue);
|
|
94
117
|
}
|
|
95
118
|
} catch {
|
|
96
119
|
/* invalid URL is reported without echoing it */
|
|
@@ -99,7 +122,7 @@ export function scrubMcpConnectionMessage(value, cfg = {}) {
|
|
|
99
122
|
const headers = resolveMcpHttpHeaders(cfg);
|
|
100
123
|
for (const [name, headerValue] of Object.entries(headers)) {
|
|
101
124
|
if (/authorization|cookie|token|secret|api[-_]?key|signature/i.test(name)) {
|
|
102
|
-
text =
|
|
125
|
+
text = replaceConfiguredSecret(text, headerValue);
|
|
103
126
|
}
|
|
104
127
|
}
|
|
105
128
|
return text
|
|
@@ -108,30 +131,106 @@ export function scrubMcpConnectionMessage(value, cfg = {}) {
|
|
|
108
131
|
}
|
|
109
132
|
|
|
110
133
|
/**
|
|
111
|
-
* Expand `${VAR}` and `${
|
|
112
|
-
* provided env map (defaults to process.env). Recurses into
|
|
113
|
-
*
|
|
134
|
+
* Expand `${VAR}`, `${env:VAR}` and `${VAR:-default}` references in string
|
|
135
|
+
* values using the provided env map (defaults to process.env). Recurses into
|
|
136
|
+
* arrays/objects. The default (possibly empty) applies only when the variable
|
|
137
|
+
* is unset, and runs to the first `}`. An unset variable without a default
|
|
138
|
+
* expands to an empty string and, when `missing` (a Set) is given, its name is
|
|
139
|
+
* recorded there. No shell execution.
|
|
114
140
|
*/
|
|
115
|
-
export function expandEnvVars(value, env = process.env) {
|
|
141
|
+
export function expandEnvVars(value, env = process.env, missing) {
|
|
116
142
|
if (typeof value === 'string') {
|
|
117
|
-
return value.replace(/\$\{(?:env:)?([A-Za-z_][A-Za-z0-9_]*)
|
|
143
|
+
return value.replace(/\$\{(?:env:)?([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g, (_m, name, fallback) => {
|
|
118
144
|
const v = env?.[name];
|
|
119
|
-
|
|
145
|
+
if (v != null) return String(v);
|
|
146
|
+
if (fallback !== undefined) return fallback;
|
|
147
|
+
missing?.add(name);
|
|
148
|
+
return '';
|
|
120
149
|
});
|
|
121
150
|
}
|
|
122
151
|
if (Array.isArray(value)) {
|
|
123
|
-
return value.map((v) => expandEnvVars(v, env));
|
|
152
|
+
return value.map((v) => expandEnvVars(v, env, missing));
|
|
124
153
|
}
|
|
125
154
|
if (value && typeof value === 'object') {
|
|
126
155
|
const out = {};
|
|
127
156
|
for (const [k, v] of Object.entries(value)) {
|
|
128
|
-
out[k] = expandEnvVars(v, env);
|
|
157
|
+
out[k] = expandEnvVars(v, env, missing);
|
|
129
158
|
}
|
|
130
159
|
return out;
|
|
131
160
|
}
|
|
132
161
|
return value;
|
|
133
162
|
}
|
|
134
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Names (deduplicated, first-seen order) of variables a server config needs
|
|
166
|
+
* that are unset: `${VAR}` references without a default in command, args,
|
|
167
|
+
* env, url, headers and cwd, plus the variables named directly by
|
|
168
|
+
* `bearer_token_env_var`, `env_http_headers` values and `env_vars`. Names
|
|
169
|
+
* only — never values.
|
|
170
|
+
*/
|
|
171
|
+
export function findMissingMcpEnvVars(cfg = {}, env = process.env) {
|
|
172
|
+
const missing = new Set();
|
|
173
|
+
expandEnvVars([cfg.command, cfg.args, cfg.env, cfg.url, cfg.headers, cfg.cwd], env, missing);
|
|
174
|
+
const named = [
|
|
175
|
+
cfg.bearer_token_env_var,
|
|
176
|
+
...(cfg.env_http_headers && typeof cfg.env_http_headers === 'object' && !Array.isArray(cfg.env_http_headers)
|
|
177
|
+
? Object.values(cfg.env_http_headers)
|
|
178
|
+
: []),
|
|
179
|
+
...(Array.isArray(cfg.env_vars) ? cfg.env_vars : []),
|
|
180
|
+
];
|
|
181
|
+
for (const value of named) {
|
|
182
|
+
const name = typeof value === 'string' ? value.trim() : '';
|
|
183
|
+
if (name && envValue(env, name) == null) missing.add(name);
|
|
184
|
+
}
|
|
185
|
+
return [...missing];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Windows variable names are case-insensitive.
|
|
189
|
+
function envValue(env, name) {
|
|
190
|
+
if (process.platform !== 'win32') return env?.[name];
|
|
191
|
+
const actual = Object.keys(env || {}).find((key) => key.toLowerCase() === name.toLowerCase());
|
|
192
|
+
return actual ? env[actual] : undefined;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Provider tool names: at most 64 characters of [A-Za-z0-9_-] (the strictest
|
|
196
|
+
// limit among the providers Mixdog talks to).
|
|
197
|
+
const PROVIDER_TOOL_NAME_MAX = 64;
|
|
198
|
+
const PROVIDER_TOOL_NAME_RE = /^[A-Za-z0-9_-]+$/;
|
|
199
|
+
const KEPT_SERVER_PART_MAX = 40;
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* `mcp__<server>__<tool>` when that already fits provider limits (unchanged
|
|
203
|
+
* for every name that fits today). Otherwise a deterministic short form:
|
|
204
|
+
* the server part kept when it is safe (sanitized and cut short when not),
|
|
205
|
+
* the tool part sanitized and cut, and a hash of the full name appended so
|
|
206
|
+
* distinct tools never meet. Callers keep the original tool name alongside
|
|
207
|
+
* to dispatch the call.
|
|
208
|
+
*/
|
|
209
|
+
export function providerSafeMcpToolName(serverName, toolName) {
|
|
210
|
+
const server = String(serverName || '');
|
|
211
|
+
const tool = String(toolName || '');
|
|
212
|
+
const full = `mcp__${server}__${tool}`;
|
|
213
|
+
if (full.length <= PROVIDER_TOOL_NAME_MAX && PROVIDER_TOOL_NAME_RE.test(full)) return full;
|
|
214
|
+
const hash = createHash('sha1').update(full).digest('hex').slice(0, 8);
|
|
215
|
+
const serverPart =
|
|
216
|
+
/^[A-Za-z0-9-]+(?:_[A-Za-z0-9-]+)*$/.test(server) && server.length <= KEPT_SERVER_PART_MAX
|
|
217
|
+
? server
|
|
218
|
+
: server
|
|
219
|
+
.replace(/[^A-Za-z0-9-]+/g, '-')
|
|
220
|
+
.replace(/^-+|-+$/g, '')
|
|
221
|
+
.slice(0, 24)
|
|
222
|
+
.replace(/-+$/, '') || 'server';
|
|
223
|
+
const room = PROVIDER_TOOL_NAME_MAX - `mcp__${serverPart}__`.length - hash.length - 1;
|
|
224
|
+
const toolPart = tool
|
|
225
|
+
.replace(/[^A-Za-z0-9_-]+/g, '_')
|
|
226
|
+
.slice(0, Math.max(0, room))
|
|
227
|
+
.replace(/_+$/, '');
|
|
228
|
+
const safe = `mcp__${serverPart}__${toolPart ? `${toolPart}_` : ''}${hash}`;
|
|
229
|
+
// Name-only consumers in this process (display, guards) resolve it back.
|
|
230
|
+
rememberMcpToolIdentity(safe, server, tool);
|
|
231
|
+
return safe;
|
|
232
|
+
}
|
|
233
|
+
|
|
135
234
|
const DEFAULT_STDIO_ENV_KEYS =
|
|
136
235
|
process.platform === 'win32'
|
|
137
236
|
? [
|
|
@@ -208,6 +307,14 @@ export function resolveMcpTransportKind(cfg) {
|
|
|
208
307
|
throw new Error(`Invalid config: need autoDetect, type (stdio/http/sse/ws), url (http), or command (stdio)`);
|
|
209
308
|
}
|
|
210
309
|
|
|
310
|
+
/** The exact URL OAuth credentials of an HTTP/SSE server config are stored
|
|
311
|
+
* under; null for other transports. */
|
|
312
|
+
export function resolveMcpOAuthUrl(cfg) {
|
|
313
|
+
const kind = resolveMcpTransportKind(cfg);
|
|
314
|
+
if (kind !== 'http' && kind !== 'sse') return null;
|
|
315
|
+
return normalizeMcpTransportUrl(expandEnvVars(String(cfg.url ?? '')), kind);
|
|
316
|
+
}
|
|
317
|
+
|
|
211
318
|
// MCP per-tool-call timeout. Default 2min: a hung/unresponsive MCP server
|
|
212
319
|
// (e.g. a busy editor) must not stall a tool call indefinitely. Genuinely
|
|
213
320
|
// long-running tools can raise/disable it via MIXDOG_MCP_CALL_TIMEOUT_MS or a
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { markServiceUnreachable, isConnRefuseError } from '../../../shared/service-discovery.mjs';
|
|
7
7
|
import { MCP_MAX_TIMER_MS, resolveMcpStartupTimeoutMs } from './client-config.mjs';
|
|
8
8
|
import { appendMcpStderrTail } from './client-transport.mjs';
|
|
9
|
+
import { MCP_OAUTH_TIMEOUT_MS } from './oauth.mjs';
|
|
9
10
|
|
|
10
11
|
// tools/list pagination bounds: a server that never stops handing out cursors
|
|
11
12
|
// (or repeats one) cannot loop the client forever.
|
|
@@ -15,12 +16,15 @@ const MAX_MCP_TOOL_PAGES = 100;
|
|
|
15
16
|
* Every tool of a server: follows `nextCursor` until it is exhausted, repeats,
|
|
16
17
|
* or MAX_MCP_TOOL_PAGES is reached. A page with an invalid shape is returned
|
|
17
18
|
* as-is so the caller's shape validation reports it.
|
|
19
|
+
* The SDK rebuilds its output validators from each page alone, so after a
|
|
20
|
+
* paginated listing they are rebuilt once from every page's tools.
|
|
18
21
|
*/
|
|
19
22
|
export async function listAllMcpTools(client, requestOptions = undefined) {
|
|
20
23
|
const tools = [];
|
|
21
24
|
const seen = new Set();
|
|
22
25
|
let cursor = null;
|
|
23
|
-
|
|
26
|
+
let pages = 0;
|
|
27
|
+
for (; pages < MAX_MCP_TOOL_PAGES; pages += 1) {
|
|
24
28
|
const result = await client.listTools(cursor ? { cursor } : undefined, requestOptions);
|
|
25
29
|
if (!result || !Array.isArray(result.tools)) return result;
|
|
26
30
|
tools.push(...result.tools);
|
|
@@ -29,6 +33,7 @@ export async function listAllMcpTools(client, requestOptions = undefined) {
|
|
|
29
33
|
seen.add(next);
|
|
30
34
|
cursor = next;
|
|
31
35
|
}
|
|
36
|
+
if (pages > 0) client.cacheToolMetadata?.(tools);
|
|
32
37
|
return { tools };
|
|
33
38
|
}
|
|
34
39
|
|
|
@@ -49,6 +54,15 @@ function startupTimeoutError(name, startupTimeoutMs) {
|
|
|
49
54
|
return err;
|
|
50
55
|
}
|
|
51
56
|
|
|
57
|
+
const oauthLoginError = () => new Error('MCP OAuth login failed, cancelled, or timed out');
|
|
58
|
+
|
|
59
|
+
/** Code of a connect cancelled (login cancel, disconnect, shutdown) before any
|
|
60
|
+
* interactive login started. */
|
|
61
|
+
export const MCP_CONNECT_CANCELLED = 'EMCPCONNECTCANCELLED';
|
|
62
|
+
function connectCancelledError(name) {
|
|
63
|
+
return Object.assign(new Error(`MCP server "${name}" connect cancelled`), { code: MCP_CONNECT_CANCELLED });
|
|
64
|
+
}
|
|
65
|
+
|
|
52
66
|
/**
|
|
53
67
|
* Bound the connect + listTools handshake so a slow/hung server can't stall
|
|
54
68
|
* boot or the first turn. On expiry the pending transport/child is torn down
|
|
@@ -69,17 +83,43 @@ export async function runBoundedHandshake({
|
|
|
69
83
|
}) {
|
|
70
84
|
const startupTimeoutMs = resolveMcpStartupTimeoutMs(cfg);
|
|
71
85
|
const guard = { timer: null, timedOut: false };
|
|
86
|
+
let rejectDeadline;
|
|
87
|
+
// True once an interactive login actually started (the server challenged
|
|
88
|
+
// and a browser sign-in was allowed).
|
|
89
|
+
let loginStarted = false;
|
|
90
|
+
const armDeadline = (ms, error = () => startupTimeoutError(name, ms)) => {
|
|
91
|
+
if (guard.timer) clearTimeout(guard.timer);
|
|
92
|
+
guard.timer = setTimeout(() => {
|
|
93
|
+
guard.timedOut = true;
|
|
94
|
+
rejectDeadline(error());
|
|
95
|
+
}, ms);
|
|
96
|
+
};
|
|
97
|
+
const deadline = new Promise((_, reject) => {
|
|
98
|
+
rejectDeadline = reject;
|
|
99
|
+
});
|
|
100
|
+
// A closed OAuth connection (login cancel, disconnect, shutdown) settles a
|
|
101
|
+
// handshake that would otherwise wait forever (an SSE stream closed while
|
|
102
|
+
// starting never settles). The SDK also closes the transport — and with it
|
|
103
|
+
// the OAuth connection — right before rethrowing a connect failure of its
|
|
104
|
+
// own (e.g. connection refused): deferring past the pending microtasks lets
|
|
105
|
+
// that real failure settle the race first.
|
|
106
|
+
const cancelOAuth = () =>
|
|
107
|
+
setImmediate(() => rejectDeadline(loginStarted ? oauthLoginError() : connectCancelledError(name)));
|
|
108
|
+
transport.oauth?.signal.addEventListener('abort', cancelOAuth, { once: true });
|
|
109
|
+
if (transport.oauth?.signal.aborted) cancelOAuth();
|
|
110
|
+
if (startupTimeoutMs > 0) armDeadline(startupTimeoutMs);
|
|
111
|
+
// Human authorization gets a separate, finite budget. The ordinary startup
|
|
112
|
+
// budget still applies until the server actually challenges authentication.
|
|
113
|
+
if (transport.oauth) {
|
|
114
|
+
transport.oauth.onStart = () => {
|
|
115
|
+
loginStarted = true;
|
|
116
|
+
armDeadline(MCP_OAUTH_TIMEOUT_MS, oauthLoginError);
|
|
117
|
+
};
|
|
118
|
+
}
|
|
72
119
|
const handshake = performHandshake(client, transport, {
|
|
73
|
-
timeout: startupTimeoutMs > 0 ? startupTimeoutMs : MCP_MAX_TIMER_MS,
|
|
120
|
+
timeout: !transport.oauth && startupTimeoutMs > 0 ? startupTimeoutMs : MCP_MAX_TIMER_MS,
|
|
74
121
|
});
|
|
75
122
|
try {
|
|
76
|
-
if (startupTimeoutMs <= 0) return await handshake;
|
|
77
|
-
const deadline = new Promise((_, rej) => {
|
|
78
|
-
guard.timer = setTimeout(() => {
|
|
79
|
-
guard.timedOut = true;
|
|
80
|
-
rej(startupTimeoutError(name, startupTimeoutMs));
|
|
81
|
-
}, startupTimeoutMs);
|
|
82
|
-
});
|
|
83
123
|
return await Promise.race([handshake, deadline]);
|
|
84
124
|
} catch (err) {
|
|
85
125
|
// A discovery-advert port that fails to connect is a corpse (recycled
|
|
@@ -88,7 +128,7 @@ export async function runBoundedHandshake({
|
|
|
88
128
|
// ONLY — a startup/handshake timeout is a slow-but-alive server.
|
|
89
129
|
if (autoDetectAdvert && isConnRefuseError(err))
|
|
90
130
|
markServiceUnreachable(autoDetectAdvert.service, autoDetectAdvert.port);
|
|
91
|
-
if (guard.timedOut) {
|
|
131
|
+
if (guard.timedOut || transport.oauth?.signal.aborted) {
|
|
92
132
|
// Tear down the pending transport/child so a hung handshake never
|
|
93
133
|
// leaks a stdio process or socket — fire-and-forget (like the
|
|
94
134
|
// tool-call timeout path) so a slow tree-kill never delays this
|
|
@@ -96,7 +136,7 @@ export async function runBoundedHandshake({
|
|
|
96
136
|
try {
|
|
97
137
|
closeServer({ client, transport }).catch(() => {});
|
|
98
138
|
} catch {
|
|
99
|
-
|
|
139
|
+
// Teardown is best effort: the handshake failure below is what gets reported.
|
|
100
140
|
}
|
|
101
141
|
// Never let the late handshake settle into an unhandled rejection.
|
|
102
142
|
handshake.catch(() => {});
|
|
@@ -108,6 +148,9 @@ export async function runBoundedHandshake({
|
|
|
108
148
|
}
|
|
109
149
|
throw tail ? new Error(appendMcpStderrTail(String(err), tail)) : err;
|
|
110
150
|
} finally {
|
|
151
|
+
transport.oauth?.finishConnect();
|
|
111
152
|
if (guard.timer) clearTimeout(guard.timer);
|
|
153
|
+
transport.oauth?.signal.removeEventListener('abort', cancelOAuth);
|
|
154
|
+
if (transport.oauth) transport.oauth.onStart = () => {};
|
|
112
155
|
}
|
|
113
156
|
}
|