mixdog 1.3.4 → 1.4.0
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/LICENSES/oh-my-pi-MIT.txt +23 -0
- package/NOTICE.md +17 -2
- package/README.md +11 -0
- package/package.json +3 -11
- package/scripts/daemon-stub.mjs +1 -1
- package/scripts/embed-google-oauth-client.mjs +49 -0
- package/scripts/gate-local.mjs +4 -2
- package/scripts/lib/test-spawn-ledger.mjs +46 -1
- package/scripts/native-release-status.mjs +2 -2
- package/scripts/recall-history-cases.json +1 -1
- package/scripts/suite-health.mjs +10 -1
- package/scripts/test.mjs +12 -11
- package/src/agents/reviewer/AGENT.md +7 -11
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +25 -1
- package/src/defaults/skills/browser-use/SKILL.md +77 -17
- package/src/defaults/skills/code-tidy/SKILL.md +142 -270
- package/src/defaults/skills/code-tidy/references/agent-cleanup.md +4 -4
- package/src/defaults/skills/code-tidy/references/cleanup-report.md +31 -76
- package/src/defaults/skills/code-tidy/references/dead-code.md +6 -12
- package/src/defaults/skills/computer-use/SKILL.md +33 -9
- package/src/defaults/skills/setup/SKILL.md +29 -2
- package/src/defaults/skills/setup/references/actions.md +117 -28
- package/src/defaults/skills/setup/references/surfaces.md +77 -35
- package/src/defaults/skills/setup-guide/SKILL.md +3 -3
- package/src/defaults/skills/visualize/SKILL.md +2 -1
- package/src/lib/keychain-cjs.cjs +359 -29
- package/src/lib/rules-builder.cjs +10 -8
- package/src/rules/agent/AGENT.md +6 -6
- package/src/rules/agent-mode/AGENT_MODE.md +10 -2
- package/src/rules/agent-mode/MIXY.md +12 -0
- package/src/rules/lead/LEAD.md +18 -20
- package/src/rules/shared/05-tool-calls.md +5 -6
- package/src/rules/shared/10-tool-workflow.md +2 -0
- package/src/rules/shared/60-verification.md +7 -5
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
- package/src/runtime/agent/orchestrator/agent-runtime/heartbeat-completion.mjs +193 -0
- package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +3 -1
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
- package/src/runtime/agent/orchestrator/config.mjs +34 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +72 -67
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +54 -1
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +177 -73
- package/src/runtime/agent/orchestrator/mcp/client.mjs +25 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +31 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +16 -3
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +42 -7
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +21 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +23 -0
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +11 -1
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +230 -137
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +64 -7
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +18 -5
- package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +14 -14
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +160 -69
- package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +64 -33
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +52 -8
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +22 -6
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +15 -4
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +17 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +142 -104
- package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +10 -4
- package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +10 -217
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +22 -6
- package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +409 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-families.mjs +187 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-identity.mjs +342 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-models.mjs +541 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-protobuf.mjs +305 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-request.mjs +558 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-schema.mjs +880 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-session.mjs +190 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-tool-args.mjs +351 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +560 -0
- package/src/runtime/agent/orchestrator/providers/devin.mjs +491 -0
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/gemini-output-limit.mjs +46 -0
- package/src/runtime/agent/orchestrator/providers/gemini-reasoning-relay.mjs +30 -0
- package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +7 -11
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +61 -22
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -4
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +25 -2
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +96 -5
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
- package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +23 -5
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -10
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +8 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +11 -3
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +19 -1
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +39 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +6 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -9
- package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +22 -3
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +43 -5
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +6 -3
- package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/provider-availability.mjs +19 -0
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +65 -1
- package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +38 -12
- package/src/runtime/agent/orchestrator/providers/registry.mjs +43 -3
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +39 -7
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/wire-protobuf-codec.mjs +368 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +12 -7
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/compaction-config-keys.mjs +62 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +37 -16
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +100 -23
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs +133 -0
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +23 -5
- package/src/runtime/agent/orchestrator/runtime-core/tool-profile.mjs +35 -10
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +57 -10
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +9 -6
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +18 -0
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +0 -3
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +10 -4
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +792 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +148 -25
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +475 -58
- package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +42 -17
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +47 -9
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +14 -2
- package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +18 -22
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +32 -3
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +51 -3
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +17 -3
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/after-hook.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +14 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +23 -5
- package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +60 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +19 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +31 -4
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -18
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +23 -13
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +129 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +20 -2
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +18 -5
- package/src/runtime/agent/orchestrator/session/message-ids.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/message-reactions.mjs +89 -0
- package/src/runtime/agent/orchestrator/session/message-reactions.test-support.mjs +75 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +19 -8
- package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +127 -0
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +0 -2
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +47 -11
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +20 -2
- package/src/runtime/agent/orchestrator/session/sensitive-projection.mjs +100 -0
- package/src/runtime/agent/orchestrator/session/sensitive-values.mjs +257 -0
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +20 -7
- package/src/runtime/agent/orchestrator/session/side-question.mjs +18 -0
- package/src/runtime/agent/orchestrator/session/skill-update-notice.mjs +60 -0
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/store/save-delta.mjs +9 -5
- package/src/runtime/agent/orchestrator/session/store/serialize.mjs +9 -8
- package/src/runtime/agent/orchestrator/session/store/session-persistence-events.mjs +29 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-header-cache.mjs +85 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +133 -18
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +12 -2
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -14
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +84 -3
- package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
- package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/thinking-binding.mjs +108 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +25 -2
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +9 -7
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-text.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/turn-failure.mjs +5 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +5 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +12 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +240 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/shell-cwd.mjs +38 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +25 -5
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +65 -7
- package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +36 -13
- package/src/runtime/browser-bridge/action-schema.mjs +13 -2
- package/src/runtime/browser-bridge/client.mjs +73 -8
- package/src/runtime/browser-bridge/input-fields.mjs +8 -9
- package/src/runtime/browser-bridge/mail-links.mjs +107 -0
- package/src/runtime/browser-bridge/tool-defs.mjs +1 -1
- package/src/runtime/channels/lib/config.mjs +6 -61
- package/src/runtime/channels/lib/crash-log.mjs +1 -1
- package/src/runtime/channels/lib/event-pipeline.mjs +4 -19
- package/src/runtime/channels/lib/event-queue.mjs +3 -18
- package/src/runtime/channels/lib/owned-runtime/automation-services.mjs +2 -2
- package/src/runtime/channels/lib/owned-runtime/automation-start.mjs +3 -4
- package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +4 -59
- package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +33 -115
- package/src/runtime/channels/lib/owned-runtime/owned-stop.mjs +5 -22
- package/src/runtime/channels/lib/owned-runtime/state.mjs +2 -8
- package/src/runtime/channels/lib/owned-runtime.mjs +6 -23
- package/src/runtime/channels/lib/parent-bridge.mjs +2 -2
- package/src/runtime/channels/lib/runtime-paths.mjs +4 -43
- package/src/runtime/channels/lib/schedule-errors.mjs +51 -0
- package/src/runtime/channels/lib/scheduler.mjs +135 -154
- package/src/runtime/channels/lib/schedules-db.mjs +83 -11
- package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
- package/src/runtime/channels/lib/tool-dispatch.mjs +14 -2
- package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
- package/src/runtime/channels/lib/worker-bootstrap.mjs +0 -1
- package/src/runtime/channels/lib/worker-ipc.mjs +0 -1
- package/src/runtime/channels/lib/worker-main.mjs +19 -34
- package/src/runtime/computer-bridge/action-schema.mjs +42 -1
- package/src/runtime/computer-bridge/actions.mjs +9 -1
- package/src/runtime/computer-bridge/client.mjs +180 -8
- package/src/runtime/computer-bridge/core-actions.mjs +2 -2
- package/src/runtime/computer-bridge/error-recovery.mjs +27 -2
- package/src/runtime/computer-bridge/linux-readiness.mjs +65 -23
- package/src/runtime/computer-bridge/pending-continuation.mjs +1 -1
- package/src/runtime/connectors/connector-accounts-mcp.mjs +230 -0
- package/src/runtime/connectors/gmail-app-password.mjs +172 -39
- package/src/runtime/connectors/google-mcp.mjs +10 -12
- package/src/runtime/memory/lib/pg/adapter.mjs +77 -70
- package/src/runtime/memory/lib/pg/supervisor.mjs +24 -12
- package/src/runtime/memory/lib/runtime-fetcher.mjs +23 -5
- package/src/runtime/office/com/com-adapter.mjs +17 -1
- package/src/runtime/office/com/office-com-host.ps1 +51 -1
- package/src/runtime/office/pdf/cfb-fixture.mjs +328 -0
- package/src/runtime/office/pdf/cfb-protection.mjs +311 -0
- package/src/runtime/office/pdf/document-preview.mjs +326 -8
- package/src/runtime/office/pdf/ooxml-crypto.mjs +469 -0
- package/src/runtime/office/pdf/ooxml-key-worker.mjs +14 -0
- package/src/runtime/office/portable/portable-soffice.mjs +45 -5
- package/src/runtime/session-search/session-search-db.mjs +73 -9
- package/src/runtime/session-search/session-search-ingest.mjs +110 -20
- package/src/runtime/shared/abort-race.mjs +89 -0
- package/src/runtime/shared/agent-avatar.d.mts +0 -1
- package/src/runtime/shared/agent-kind.mjs +4 -3
- package/src/runtime/shared/bot-hops.mjs +62 -2
- package/src/runtime/shared/bounded-download.mjs +8 -3
- package/src/runtime/shared/config.mjs +51 -35
- package/src/runtime/shared/connector-accounts.mjs +20 -10
- package/src/runtime/shared/connector-catalog.d.mts +33 -2
- package/src/runtime/shared/connector-catalog.mjs +166 -8
- package/src/runtime/shared/connector-triggers.mjs +22 -19
- package/src/runtime/shared/defaults-separation.mjs +2 -14
- package/src/runtime/shared/delegated-approval-host.mjs +103 -11
- package/src/runtime/shared/developer-options.mjs +32 -1
- package/src/runtime/shared/err-text.mjs +24 -15
- package/src/runtime/shared/file-permissions.d.mts +0 -8
- package/src/runtime/shared/file-permissions.mjs +0 -11
- package/src/runtime/shared/git-direct.test-support.mjs +19 -0
- package/src/runtime/shared/google-oauth-client.generated.json +4 -0
- package/src/runtime/shared/google-oauth-client.mjs +34 -9
- package/src/runtime/shared/heartbeat-interval.d.mts +4 -0
- package/src/runtime/shared/heartbeat-interval.mjs +19 -0
- package/src/runtime/shared/idle-auto-clear-gate.mjs +104 -0
- package/src/runtime/shared/llm/anthropic-betas.mjs +7 -0
- package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +12 -0
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +1 -0
- package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
- package/src/runtime/shared/llm/well-formed.mjs +66 -0
- package/src/runtime/shared/mixy-presence.mjs +22 -0
- package/src/runtime/shared/orchestration.d.mts +2 -0
- package/src/runtime/shared/pg-schema-db.mjs +27 -16
- package/src/runtime/shared/profile-config.cjs +1 -1
- package/src/runtime/shared/prompt-origin.d.mts +4 -0
- package/src/runtime/shared/prompt-origin.mjs +21 -0
- package/src/runtime/shared/provider-accounts.mjs +231 -59
- package/src/runtime/shared/provider-api-key.mjs +19 -8
- package/src/runtime/shared/provider-display-name.mjs +29 -0
- package/src/runtime/shared/provider-timeout-phase.mjs +2 -0
- package/src/runtime/shared/routine-trigger.d.mts +2 -0
- package/src/runtime/shared/routine-trigger.mjs +52 -0
- package/src/runtime/shared/sensitive-path-rules.d.mts +2 -10
- package/src/runtime/shared/sensitive-path-rules.mjs +19 -41
- package/src/runtime/shared/session-activity-signal.mjs +34 -1
- package/src/runtime/shared/session-sidebar-host.d.mts +1 -1
- package/src/runtime/shared/session-sidebar-host.mjs +7 -3
- package/src/runtime/shared/session-turn-prelude.mjs +18 -0
- package/src/runtime/shared/tool-execution-contract.mjs +2 -0
- package/src/runtime/shared/tool-result-summary.mjs +1 -14
- package/src/runtime/shared/transcript-metadata.mjs +38 -0
- package/src/runtime/shared/user-data-guard.mjs +30 -2
- package/src/runtime/shared/worktrees/activity-gate.mjs +12 -5
- package/src/runtime/shared/worktrees/test-support.mjs +9 -4
- package/src/runtime/terminal-bridge/client.mjs +10 -1
- package/src/runtime/visualize-bridge/client.mjs +27 -8
- package/src/runtime/visualize-bridge/tool-defs.mjs +22 -8
- package/src/runtime/visualize-bridge/tool-meta.d.mts +5 -0
- package/src/runtime/visualize-bridge/tool-meta.mjs +22 -0
- package/src/runtime/web-search/lib/fetch-pipeline.mjs +2 -2
- package/src/session-runtime/agent-home-delivery.mjs +486 -179
- package/src/session-runtime/agent-room-delivery.mjs +28 -1
- package/src/session-runtime/agent-task-sessions.mjs +561 -199
- package/src/session-runtime/boot/apis.mjs +9 -0
- package/src/session-runtime/boot/begin.mjs +3 -2
- package/src/session-runtime/boot/infrastructure.mjs +4 -0
- package/src/session-runtime/boot/providers.mjs +3 -0
- package/src/session-runtime/boot/tools.mjs +8 -1
- package/src/session-runtime/bot-chain.mjs +32 -0
- package/src/session-runtime/bot-status.mjs +7 -4
- package/src/session-runtime/channel-config-api.mjs +63 -17
- package/src/session-runtime/config-lifecycle.mjs +6 -0
- package/src/session-runtime/connector-merge-migration.mjs +305 -0
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +132 -28
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +2 -0
- package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +45 -0
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +72 -5
- package/src/session-runtime/internal-tool-executor.mjs +4 -0
- package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
- package/src/session-runtime/lifecycle/session-catalog.mjs +3 -1
- package/src/session-runtime/lifecycle/teardown/runtime-stops.mjs +50 -4
- package/src/session-runtime/lifecycle/teardown.mjs +23 -5
- package/src/session-runtime/mcp-glue/server-catalog.mjs +61 -3
- package/src/session-runtime/mcp-oauth-login.mjs +5 -3
- package/src/session-runtime/mixy-heartbeat.mjs +927 -0
- package/src/session-runtime/model-route/route-tuning.mjs +10 -6
- package/src/session-runtime/notification-bus.mjs +31 -117
- package/src/session-runtime/notification-completion-queue.mjs +54 -0
- package/src/session-runtime/notification-listeners.mjs +76 -0
- package/src/session-runtime/owned-automation-run.mjs +35 -13
- package/src/session-runtime/prewarm/channel-start.mjs +3 -7
- package/src/session-runtime/provider-auth/login.mjs +7 -0
- package/src/session-runtime/provider-models/row-hydration.mjs +13 -2
- package/src/session-runtime/resource-mcp-api.mjs +143 -224
- package/src/session-runtime/resource-mcp-connector-accounts.mjs +163 -0
- package/src/session-runtime/resource-mcp-oauth-api.mjs +217 -0
- package/src/session-runtime/resource-mcp-secrets.mjs +82 -0
- package/src/session-runtime/resource-mcp-servers.mjs +78 -0
- package/src/session-runtime/resource-mcp-store.mjs +49 -0
- package/src/session-runtime/routine-home-turn.mjs +33 -6
- package/src/session-runtime/routine-owner.mjs +40 -9
- package/src/session-runtime/schedule-session-run.mjs +7 -3
- package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +8 -12
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +7 -2
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
- package/src/session-runtime/services/agent-tool/worker-index/awaiting-user-sync.mjs +51 -0
- package/src/session-runtime/services/agent-tool/worker-index/disposal.mjs +55 -0
- package/src/session-runtime/services/agent-tool/worker-index/released-store.mjs +123 -0
- package/src/session-runtime/services/agent-tool/worker-index/restart-settlement.mjs +112 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-reads.mjs +36 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +17 -4
- package/src/session-runtime/services/agent-tool/worker-index/row-writes.mjs +58 -0
- package/src/session-runtime/services/agent-tool/worker-index.mjs +41 -241
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +3 -0
- package/src/session-runtime/services/channel-admin.mjs +73 -31
- package/src/session-runtime/services/channel-session-router.mjs +4 -2
- package/src/session-runtime/services/channel-worker.mjs +1 -1
- package/src/session-runtime/services/provider-admin.mjs +128 -25
- package/src/session-runtime/services/schedule-access.mjs +14 -0
- package/src/session-runtime/services/seeds.mjs +0 -28
- package/src/session-runtime/services/usage-dashboard-model.mjs +1 -0
- package/src/session-runtime/session-compaction-sync.mjs +27 -0
- package/src/session-runtime/session-create/session-options.mjs +8 -4
- package/src/session-runtime/settings-builtin-tools-api.mjs +11 -0
- package/src/session-runtime/settings-compaction-api.mjs +2 -40
- package/src/session-runtime/settings-system-api.mjs +28 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
- package/src/session-runtime/setup-tool/executor.mjs +187 -29
- package/src/session-runtime/setup-tool/extended-actions.mjs +33 -2
- package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +68 -6
- package/src/session-runtime/setup-tool/tool-defs.mjs +92 -6
- package/src/session-runtime/task-session-route.mjs +99 -0
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
- package/src/session-runtime/tool-policy/policy-stage.mjs +21 -4
- package/src/session-runtime/tool-policy/surface-helpers.mjs +2 -3
- package/src/session-runtime/tool-surface.mjs +4 -0
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +98 -21
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -1
- package/src/session-runtime/workspace/transitions.mjs +10 -2
- package/src/standalone/channel-transport/client-registry/client-records.mjs +65 -0
- package/src/standalone/channel-transport/client-registry/client-registration.mjs +118 -0
- package/src/standalone/channel-transport/client-registry.mjs +24 -163
- package/src/standalone/channel-transport.mjs +1 -1
- package/src/standalone/daemon-channels-loader.mjs +10 -8
- package/src/standalone/daemon-session-control/list-page.mjs +72 -0
- package/src/standalone/daemon-session-control/request.mjs +51 -0
- package/src/standalone/daemon-session-control/room-host.mjs +57 -0
- package/src/standalone/daemon-session-control/route-control.mjs +48 -0
- package/src/standalone/daemon-session-control/send-turn.mjs +60 -0
- package/src/standalone/daemon-session-control/worktree-control.mjs +40 -0
- package/src/standalone/daemon-session-control.mjs +161 -157
- package/src/standalone/daemon.mjs +33 -2
- package/src/standalone/session-client.mjs +7 -3
- package/src/standalone/session-protocol.mjs +10 -0
- package/src/standalone/session-service/agent-tree/agent-cancel.mjs +6 -2
- package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
- package/src/standalone/session-service/quota-resume.mjs +3 -0
- package/src/standalone/session-service/retention/busy.mjs +65 -1
- package/src/standalone/session-service/session-calls/session-action.mjs +23 -2
- package/src/standalone/session-service/session-calls/session-turns.mjs +6 -0
- package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
- package/src/standalone/session-service.mjs +13 -0
- package/src/standalone/session-tool-output.mjs +21 -10
- package/src/tui/app/model-options.mjs +4 -27
- package/src/tui/dist/index.mjs +81 -65
- package/src/tui/session/agent-job-feed/model-notification.mjs +3 -0
- package/src/tui/session/initial-state.mjs +3 -0
- package/src/tui/session/notice-surface.mjs +23 -1
- package/src/tui/session/queue-helpers.mjs +3 -42
- package/src/tui/session/session-api/integrations.mjs +1 -0
- package/src/tui/session/session-api/lifecycle.mjs +8 -0
- package/src/tui/session/session-api/routes-agent-definitions.mjs +14 -2
- package/src/tui/session/session-api/routes-write.mjs +5 -1
- package/src/tui/session/session-api/routes.mjs +1 -0
- package/src/tui/session/session-api/settings.mjs +30 -2
- package/src/tui/session/session-flow/auto-clear.mjs +4 -33
- package/src/tui/session/session-flow/drain-closed-queue.mjs +38 -0
- package/src/tui/session/session-flow/drain-enqueue.mjs +86 -0
- package/src/tui/session/session-flow/drain-retry.mjs +35 -0
- package/src/tui/session/session-flow/drain.mjs +118 -149
- package/src/tui/session/session-flow/queue/entry-shape.mjs +5 -0
- package/src/tui/session/session-flow/queue/take-entries.mjs +5 -2
- package/src/tui/session/tool-approval-delegation.mjs +64 -0
- package/src/tui/session/tool-approval-request.mjs +39 -0
- package/src/tui/session/tool-approval-settle.mjs +62 -0
- package/src/tui/session/tool-approval.mjs +69 -115
- package/src/tui/session/tui-steering-persist.mjs +8 -1
- package/src/tui/session/turn-stream.mjs +36 -3
- package/src/tui/session/turn.mjs +23 -2
- package/src/vendor/statusline/bin/statusline-route.mjs +1 -219
- package/src/vendor/statusline/src/gateway/route-meta.mjs +35 -13
- package/scripts/code-graph-description-contract.mjs +0 -188
- package/src/runtime/channels/lib/owned-runtime/ownership-refresh.mjs +0 -36
|
@@ -2,69 +2,31 @@
|
|
|
2
2
|
// the per-server intent (enabled flag) of servers registered plugins declare.
|
|
3
3
|
// Plugin servers are derived live (mcp-glue/plugin-servers.mjs) and are never
|
|
4
4
|
// written into `mcpServers`; ordinary edits refuse them.
|
|
5
|
+
// The units it is assembled from: resource-mcp-store.mjs (the `mcpServers`
|
|
6
|
+
// registry), resource-mcp-secrets.mjs (keychain side), resource-mcp-connector-
|
|
7
|
+
// accounts.mjs (multi-account connector accounts), resource-mcp-oauth-api.mjs
|
|
8
|
+
// (sign-in / sign-out) and resource-mcp-servers.mjs (pure map reads).
|
|
5
9
|
import { clean } from '../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
MCP_TIMEOUT_FIELD_GROUPS,
|
|
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';
|
|
10
|
+
import { mergeMcpServerConfig } from '../runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs';
|
|
11
|
+
import { withAdoptedCopies, withPluginServerIntent } from './mcp-glue/plugin-servers.mjs';
|
|
12
12
|
import { findRegisteredPlugin } from './resource-plugins-api.mjs';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import { migrateMergedConnectorServers } from './connector-merge-migration.mjs';
|
|
14
|
+
import {
|
|
15
|
+
connectorAccountServers,
|
|
16
|
+
connectorAccountsOf,
|
|
17
|
+
connectorById,
|
|
18
|
+
connectorMultiAccount,
|
|
19
|
+
gmailAppPasswordAccount,
|
|
20
|
+
mergeConnectorAccountServers,
|
|
21
|
+
} from '../runtime/shared/connector-catalog.mjs';
|
|
15
22
|
import { saveMcpOAuthClientSecret } from '../runtime/agent/orchestrator/mcp/oauth-client.mjs';
|
|
16
23
|
import { forgetGmailAppPassword, saveGmailAppPassword } from '../runtime/connectors/gmail-app-password.mjs';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
// No valid remote URL: such a server never logged in.
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/** The `mcpServers` map of a config as a fresh object (never the live one). */
|
|
29
|
-
function mcpServersOf(config) {
|
|
30
|
-
return config.mcpServers && typeof config.mcpServers === 'object' ? { ...config.mcpServers } : {};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function pluginOwnedError(name, owner) {
|
|
34
|
-
return new Error(
|
|
35
|
-
`MCP server "${name}" is provided by plugin "${owner.id}" (server "${owner.key}"); ` +
|
|
36
|
-
'enable or disable it with set_mcp_enabled, or manage the plugin instead'
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const transportType = (type) => (type === 'streamable-http' ? 'http' : type);
|
|
41
|
-
|
|
42
|
-
/** UI editors send complete transports; setup may send a partial patch. Merge
|
|
43
|
-
* the patch over the existing entry, keeping omitted fields (including
|
|
44
|
-
* credentials) unless the transport itself changed. */
|
|
45
|
-
function mergedServerInput(input, existing, originalName) {
|
|
46
|
-
const transportChanged =
|
|
47
|
-
(input.type && transportType(input.type) !== transportType(existing.type || (existing.url ? 'http' : 'stdio'))) ||
|
|
48
|
-
(input.command && existing.url) ||
|
|
49
|
-
(input.url && !existing.url);
|
|
50
|
-
const maps = {};
|
|
51
|
-
if (!transportChanged) {
|
|
52
|
-
for (const key of ['env', 'headers', 'env_http_headers']) {
|
|
53
|
-
if (Object.hasOwn(input, key)) maps[key] = { ...(existing[key] || {}), ...input[key] };
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
// Existing timeouts are kept by mergeMcpServerConfig; the normalizer must only
|
|
57
|
-
// see (and validate) newly supplied ones, so a stored 0/'off' never blocks
|
|
58
|
-
// an unrelated save.
|
|
59
|
-
const { ...base } = transportChanged ? {} : existing;
|
|
60
|
-
for (const field of MCP_TIMEOUT_FIELD_GROUPS.flat()) delete base[field];
|
|
61
|
-
return {
|
|
62
|
-
...base,
|
|
63
|
-
...input,
|
|
64
|
-
...maps,
|
|
65
|
-
name: clean(input.name) || originalName,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
24
|
+
import { extensionScopesFromConfig, withExtensionScope } from '../runtime/shared/extension-scopes.mjs';
|
|
25
|
+
import { accountTarget, mcpServersOf, mergedServerInput, nameTakenError } from './resource-mcp-servers.mjs';
|
|
26
|
+
import { createMcpServerStore } from './resource-mcp-store.mjs';
|
|
27
|
+
import { createMcpServerSecrets } from './resource-mcp-secrets.mjs';
|
|
28
|
+
import { createConnectorAccountEdits, editsServerItself } from './resource-mcp-connector-accounts.mjs';
|
|
29
|
+
import { createMcpOAuthApi } from './resource-mcp-oauth-api.mjs';
|
|
68
30
|
|
|
69
31
|
export function createMcpResourceApi({ deps, sync, decorate }) {
|
|
70
32
|
const {
|
|
@@ -92,121 +54,82 @@ export function createMcpResourceApi({ deps, sync, decorate }) {
|
|
|
92
54
|
saveOAuthClientSecret = saveMcpOAuthClientSecret,
|
|
93
55
|
} = deps;
|
|
94
56
|
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
57
|
+
const oauthApi = createMcpOAuthApi({
|
|
58
|
+
sync,
|
|
59
|
+
mcpStatus,
|
|
60
|
+
connectConfiguredMcp,
|
|
61
|
+
clearMcpServerOAuth,
|
|
62
|
+
reloadFullConfig,
|
|
63
|
+
awaitKeychainPrewarm,
|
|
64
|
+
resolveMcpCatalog,
|
|
65
|
+
cancelMcpLogin,
|
|
66
|
+
completeMcpLogin,
|
|
67
|
+
getMcpServerOAuthState,
|
|
68
|
+
probeMcpServerAuth,
|
|
69
|
+
startMcpServerOAuthSwitch,
|
|
70
|
+
commitMcpServerOAuthSwitch,
|
|
71
|
+
});
|
|
72
|
+
const { adoptedConfig, saveServers, userServers, freeName, refusePluginServer } = createMcpServerStore({
|
|
73
|
+
getConfig,
|
|
74
|
+
saveConfigAndAdopt,
|
|
75
|
+
resolveMcpCatalog,
|
|
76
|
+
pluginMcpServer,
|
|
77
|
+
});
|
|
78
|
+
const { storeOAuthClientSecret, storeGmailAppPassword, releaseOAuth, forgetUnusedGmailAppPassword, releaseAccount } =
|
|
79
|
+
createMcpServerSecrets({
|
|
80
|
+
gmailAppPassword,
|
|
81
|
+
saveOAuthClientSecret,
|
|
82
|
+
clearMcpServerOAuth,
|
|
83
|
+
resolveConfiguredMcpCatalog,
|
|
84
|
+
});
|
|
85
|
+
const { addConnectorAccount, saveConnectorAccount, setConnectorAccountEnabled } = createConnectorAccountEdits({
|
|
86
|
+
normalizeMcpServerInput,
|
|
87
|
+
pluginMcpServer,
|
|
88
|
+
sync,
|
|
89
|
+
saveServers,
|
|
90
|
+
freeName,
|
|
91
|
+
storeOAuthClientSecret,
|
|
92
|
+
storeGmailAppPassword,
|
|
93
|
+
forgetUnusedGmailAppPassword,
|
|
94
|
+
releaseOAuth,
|
|
127
95
|
});
|
|
128
|
-
/** The effective config of a server that signs in with MCP OAuth (HTTP/SSE
|
|
129
|
-
* without configured authentication). */
|
|
130
|
-
const oauthServerConfig = async (name) => {
|
|
131
|
-
const serverName = clean(name);
|
|
132
|
-
if (!serverName) throw new Error('MCP server name is required');
|
|
133
|
-
await awaitKeychainPrewarm();
|
|
134
|
-
reloadFullConfig();
|
|
135
|
-
const cfg = resolveMcpCatalog().servers[serverName];
|
|
136
|
-
if (!cfg) throw new Error(`MCP server not configured: ${serverName}`);
|
|
137
|
-
if (!getMcpServerOAuthState(cfg)) throw new Error(`MCP server "${serverName}" does not use OAuth sign-in`);
|
|
138
|
-
return { serverName, cfg };
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
/** The config with any adoptable plugin server copies already adopted, so
|
|
142
|
-
* every write also persists the adoption and never re-adds a copy. */
|
|
143
|
-
const adoptedConfig = () => withAdoptedCopies(getConfig(), resolveMcpCatalog().adoption);
|
|
144
|
-
|
|
145
|
-
/** Persist a new `mcpServers` map; project overrides never survive a global
|
|
146
|
-
* edit. A plugin server pushed off its name by the edit keeps the collision
|
|
147
|
-
* name it gets, so it does not flip again later. */
|
|
148
|
-
const saveServers = (servers) => {
|
|
149
|
-
const nextConfig = { ...adoptedConfig() };
|
|
150
|
-
delete nextConfig.mcpProjectOverrides;
|
|
151
|
-
saveConfigAndAdopt({ ...nextConfig, mcpServers: servers });
|
|
152
|
-
const saved = getConfig();
|
|
153
|
-
const pinned = withPinnedCollisionNames(saved, resolveMcpCatalog());
|
|
154
|
-
if (pinned !== saved) saveConfigAndAdopt(pinned);
|
|
155
|
-
};
|
|
156
|
-
const userServers = () => mcpServersOf(adoptedConfig());
|
|
157
|
-
const refusePluginServer = (name) => {
|
|
158
|
-
const owned = name ? pluginMcpServer(name) : null;
|
|
159
|
-
if (owned) throw pluginOwnedError(name, owned.owner);
|
|
160
|
-
};
|
|
161
|
-
// The user's OAuth client secret (custom connector → 고급 설정 → 비밀값)
|
|
162
|
-
// goes to the keychain only; clearing the client id forgets it.
|
|
163
|
-
const storeOAuthClientSecret = async (input, cfg, previous = {}) => {
|
|
164
|
-
if (!cfg?.url) return;
|
|
165
|
-
const secret = typeof input.oauthClientSecret === 'string' ? input.oauthClientSecret.trim() : '';
|
|
166
|
-
if (cfg.oauthClientId && secret) await saveOAuthClientSecret(cfg.url, secret);
|
|
167
|
-
else if (!cfg.oauthClientId && previous.oauthClientId) await saveOAuthClientSecret(previous.url || cfg.url, '');
|
|
168
|
-
};
|
|
169
|
-
// Gmail with an app password (connector-catalog.mjs GMAIL_APP_PASSWORD): the
|
|
170
|
-
// password is checked with Gmail before anything is saved and goes to the
|
|
171
|
-
// keychain only. A new connection needs one; an edit without one keeps it.
|
|
172
|
-
const storeGmailAppPassword = async (input, cfg, required) => {
|
|
173
|
-
const account = gmailAppPasswordAccount(cfg);
|
|
174
|
-
if (!account) return;
|
|
175
|
-
const password = gmailAppPasswordValue(input.appPassword);
|
|
176
|
-
if (password) await gmailAppPassword.save(account, password);
|
|
177
|
-
else if (required || input.appPassword !== undefined) {
|
|
178
|
-
throw new Error('GMAIL_APP_PASSWORD_FORMAT: An app password has 16 characters.');
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
// A server's OAuth tokens and client registration go with it, unless another
|
|
182
|
-
// configured server (plugin or disabled ones included, even with MCP
|
|
183
|
-
// disabled for this runtime) still uses them through the same exact URL.
|
|
184
|
-
// `signIn` tells the caller what happened to the sign-in: `removed` (local
|
|
185
|
-
// secrets deleted, `revoked` when the provider confirmed the revocation
|
|
186
|
-
// too), `shared` (another server still uses it), or none (null).
|
|
187
|
-
const releaseOAuth = async (cfg) => {
|
|
188
|
-
const url = oauthUrlOf(cfg);
|
|
189
|
-
if (!url) return null;
|
|
190
|
-
if (Object.values(resolveConfiguredMcpCatalog().servers).some((other) => oauthUrlOf(other) === url)) {
|
|
191
|
-
return { signIn: 'shared', revoked: false };
|
|
192
|
-
}
|
|
193
|
-
const { revoked = false } = (await clearMcpServerOAuth(cfg, { revoke: true })) || {};
|
|
194
|
-
return { signIn: 'removed', revoked };
|
|
195
|
-
};
|
|
196
|
-
// An app password is deleted once no configured server uses its account.
|
|
197
|
-
const forgetUnusedGmailAppPassword = async (account) => {
|
|
198
|
-
if (!account) return false;
|
|
199
|
-
const servers = Object.values(resolveConfiguredMcpCatalog().servers);
|
|
200
|
-
if (servers.some((cfg) => gmailAppPasswordAccount(cfg) === account)) return false;
|
|
201
|
-
await gmailAppPassword.forget(account);
|
|
202
|
-
return true;
|
|
203
|
-
};
|
|
204
96
|
// Peers reload config from disk on receipt: land the write before publishing.
|
|
205
97
|
const persisted = async () => {
|
|
206
98
|
await flushSkillsSave?.();
|
|
207
99
|
};
|
|
208
100
|
|
|
209
101
|
return {
|
|
102
|
+
/** One-time, idempotent: merge the one-account servers of a multi-account
|
|
103
|
+
* connector (`gmail`, `gmail-2`…) into one server holding the accounts
|
|
104
|
+
* (connector-catalog.mjs mergeConnectorAccountServers). Every account
|
|
105
|
+
* keeps its address, so its stored sign-in and app password stay as
|
|
106
|
+
* they are. Settings keyed by a merged-away server name go with it:
|
|
107
|
+
* scopes (`extensionScopes.mcp`) are dropped, and the accounts of a
|
|
108
|
+
* server that was off stay off (`enabled: false` on the account);
|
|
109
|
+
* per-agent / per-project connector settings and data-dir hooks move to
|
|
110
|
+
* the surviving server first (connector-merge-migration.mjs); a store
|
|
111
|
+
* that fails stays in a pending record that every start retries.
|
|
112
|
+
* Returns what was merged. */
|
|
113
|
+
migrateConnectorAccounts() {
|
|
114
|
+
const config = getConfig();
|
|
115
|
+
const { servers, merged } = mergeConnectorAccountServers(mcpServersOf(config));
|
|
116
|
+
// Also retries, without a merge, what an earlier start could not migrate.
|
|
117
|
+
const settings = migrateMergedConnectorServers(
|
|
118
|
+
deps.cfgMod?.getPluginData?.() || deps.STANDALONE_DATA_DIR,
|
|
119
|
+
merged
|
|
120
|
+
);
|
|
121
|
+
if (!merged.length) return merged;
|
|
122
|
+
// Neither migrated nor recorded for a retry: merging again next start is the retry.
|
|
123
|
+
if (settings.unrecorded && settings.failed.length) return [];
|
|
124
|
+
let next = { ...config, mcpServers: servers };
|
|
125
|
+
const scoped = extensionScopesFromConfig(config).mcp;
|
|
126
|
+
for (const { name, from } of merged) {
|
|
127
|
+
for (const gone of from)
|
|
128
|
+
if (gone !== name && Object.hasOwn(scoped, gone)) next = withExtensionScope(next, 'mcp', gone, null);
|
|
129
|
+
}
|
|
130
|
+
saveConfigAndAdopt(next);
|
|
131
|
+
return merged;
|
|
132
|
+
},
|
|
210
133
|
/** One-time, idempotent: move server copies an earlier plugin enable wrote
|
|
211
134
|
* into `mcpServers` to per-server plugin intent. Returns adopted names. */
|
|
212
135
|
migratePluginMcpCopies() {
|
|
@@ -224,62 +147,14 @@ export function createMcpResourceApi({ deps, sync, decorate }) {
|
|
|
224
147
|
async reconnectMcp(name) {
|
|
225
148
|
await awaitKeychainPrewarm();
|
|
226
149
|
reloadFullConfig();
|
|
227
|
-
|
|
150
|
+
// An account reconnects with its server.
|
|
151
|
+
const serverName = accountTarget(resolveMcpCatalog().servers, clean(name))?.serverName || clean(name);
|
|
228
152
|
if (!serverName) return sync.reconnectMcpAndAnnounce();
|
|
229
153
|
const { enabled } = getMcpServerConfig(serverName);
|
|
230
154
|
return sync.reconnectMcpAndAnnounce({ only: serverName, enabled });
|
|
231
155
|
},
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
* `{ flowId, state: 'complete' }` when stored credentials sufficed. */
|
|
235
|
-
async beginMcpOAuthLogin(name, options = {}) {
|
|
236
|
-
const { serverName, cfg } = await oauthServerConfig(name);
|
|
237
|
-
if (cfg.enabled === false) throw new Error(`MCP server is disabled: ${serverName}`);
|
|
238
|
-
// `mode`: `connect` (a normal authorization), `reauth` (repair the same
|
|
239
|
-
// connection; a refresh is tried first) or `switch` (계정 바꾸기).
|
|
240
|
-
if (options?.mode === 'switch' && !getMcpServerOAuthState(cfg)?.signedIn) {
|
|
241
|
-
throw new Error(`MCP server "${serverName}" is not signed in`);
|
|
242
|
-
}
|
|
243
|
-
return oauthLogins.begin(serverName, options);
|
|
244
|
-
},
|
|
245
|
-
/** `{ flowId, state: 'pending' | 'complete' | 'failed' | 'cancelled',
|
|
246
|
-
* step?, error?, reason? }`; with `{ since, waitMs }` it resolves on the
|
|
247
|
-
* flow's next change (mcp-oauth-login.mjs). */
|
|
248
|
-
getMcpOAuthLoginStatus(flowId, options) {
|
|
249
|
-
return oauthLogins.status(flowId, options);
|
|
250
|
-
},
|
|
251
|
-
cancelMcpOAuthLogin(flowId) {
|
|
252
|
-
return oauthLogins.cancel(flowId);
|
|
253
|
-
},
|
|
254
|
-
/** Remote / headless sign-in: complete the pending flow with the redirect
|
|
255
|
-
* URL pasted from the browser. `{ flowId, state: 'complete' | 'failed',
|
|
256
|
-
* error? }`; an invalid paste throws a fixed message and stays pending. */
|
|
257
|
-
completeMcpOAuthLogin(flowId, callbackUrl) {
|
|
258
|
-
return oauthLogins.complete(flowId, callbackUrl);
|
|
259
|
-
},
|
|
260
|
-
/** Forget the server's stored OAuth credentials (shared by every server
|
|
261
|
-
* with the same exact URL) and reconnect without a login, here and on
|
|
262
|
-
* peers, so it reports sign-in required. */
|
|
263
|
-
async signOutMcpServer(name) {
|
|
264
|
-
const { serverName, cfg } = await oauthServerConfig(name);
|
|
265
|
-
// A begin issued meanwhile waits until the credentials are gone.
|
|
266
|
-
return oauthLogins.cancelServer(serverName, async () => {
|
|
267
|
-
const { revoked = false } = (await clearMcpServerOAuth(cfg, { revoke: true })) || {};
|
|
268
|
-
const status = await sync.reconnectMcpAndAnnounce({ only: serverName, enabled: cfg.enabled !== false });
|
|
269
|
-
return { ...status, revoked };
|
|
270
|
-
});
|
|
271
|
-
},
|
|
272
|
-
/** `{ auth: 'oauth' | 'none' | 'configured' | 'unreachable', error? }` for an
|
|
273
|
-
* HTTP/SSE config, without credentials or a browser. */
|
|
274
|
-
probeMcpServerAuth(cfg) {
|
|
275
|
-
if (!cfg || typeof cfg !== 'object' || Array.isArray(cfg)) throw new TypeError('MCP server config is required');
|
|
276
|
-
const probe = {};
|
|
277
|
-
for (const key of ['type', 'url', 'headers', 'bearer_token_env_var', 'env_http_headers']) {
|
|
278
|
-
if (cfg[key] !== undefined) probe[key] = cfg[key];
|
|
279
|
-
}
|
|
280
|
-
if (probe.type !== 'http' && probe.type !== 'sse') throw new TypeError("type must be 'http' or 'sse'");
|
|
281
|
-
return probeMcpServerAuth(probe);
|
|
282
|
-
},
|
|
156
|
+
// Sign-in / sign-out (resource-mcp-oauth-api.mjs), in this key position.
|
|
157
|
+
...oauthApi,
|
|
283
158
|
async addMcpServer(input = {}) {
|
|
284
159
|
const { name, config: serverConfig } = normalizeMcpServerInput(input);
|
|
285
160
|
// A catalog connector's server keeps its catalog id (connector-catalog.mjs).
|
|
@@ -289,7 +164,14 @@ export function createMcpResourceApi({ deps, sync, decorate }) {
|
|
|
289
164
|
serverConfig.connector = connector;
|
|
290
165
|
}
|
|
291
166
|
const servers = userServers();
|
|
292
|
-
|
|
167
|
+
// A multi-account connector's account (as its own server config) joins
|
|
168
|
+
// that connector's one server.
|
|
169
|
+
if (connector && connectorMultiAccount(connectorById(connector)) && !Array.isArray(input.accounts)) {
|
|
170
|
+
return addConnectorAccount(servers, connector, name, serverConfig, input);
|
|
171
|
+
}
|
|
172
|
+
if (Object.hasOwn(servers, name) || accountTarget(servers, name)) {
|
|
173
|
+
throw nameTakenError(servers, name);
|
|
174
|
+
}
|
|
293
175
|
const owned = pluginMcpServer(name);
|
|
294
176
|
if (owned) throw new Error(`MCP server already exists: ${name} (provided by plugin "${owned.owner.id}")`);
|
|
295
177
|
await storeOAuthClientSecret(input, serverConfig);
|
|
@@ -300,6 +182,9 @@ export function createMcpResourceApi({ deps, sync, decorate }) {
|
|
|
300
182
|
},
|
|
301
183
|
async saveMcpServer(input = {}) {
|
|
302
184
|
const servers = userServers();
|
|
185
|
+
// A name of a multi-account connector's account edits that account.
|
|
186
|
+
const accountOf = accountTarget(servers, clean(input.originalName) || clean(input.name));
|
|
187
|
+
if (accountOf && !editsServerItself(accountOf, input)) return saveConnectorAccount(servers, accountOf, input);
|
|
303
188
|
// An explicit originalName must exist; a bare name edits a matching
|
|
304
189
|
// server and otherwise creates a new one. Plugin servers are never
|
|
305
190
|
// edited, renamed or shadowed here.
|
|
@@ -314,8 +199,11 @@ export function createMcpResourceApi({ deps, sync, decorate }) {
|
|
|
314
199
|
const existing = originalName ? servers[originalName] : {};
|
|
315
200
|
const normalizedInput = normalizeMcpServerInput(mergedServerInput(input, existing, originalName));
|
|
316
201
|
const name = originalName && clean(input.name) === originalName ? originalName : normalizedInput.name;
|
|
317
|
-
if (
|
|
318
|
-
|
|
202
|
+
if (
|
|
203
|
+
name !== originalName &&
|
|
204
|
+
(Object.hasOwn(servers, name) || pluginMcpServer(name) || accountTarget(servers, name))
|
|
205
|
+
) {
|
|
206
|
+
throw nameTakenError(servers, name);
|
|
319
207
|
}
|
|
320
208
|
if (originalName && originalName !== name) delete servers[originalName];
|
|
321
209
|
servers[name] = mergeMcpServerConfig(existing, normalizedInput.config);
|
|
@@ -338,6 +226,20 @@ export function createMcpResourceApi({ deps, sync, decorate }) {
|
|
|
338
226
|
const serverName = clean(name);
|
|
339
227
|
if (!serverName) throw new Error('MCP server name is required');
|
|
340
228
|
const servers = userServers();
|
|
229
|
+
// A name of a multi-account connector's account removes that account;
|
|
230
|
+
// the server goes with its last one.
|
|
231
|
+
const target = accountTarget(servers, serverName);
|
|
232
|
+
if (target) {
|
|
233
|
+
const rest = connectorAccountsOf(target.cfg).filter((entry) => entry.name !== serverName);
|
|
234
|
+
if (rest.length) servers[target.serverName] = { ...target.cfg, accounts: rest };
|
|
235
|
+
else delete servers[target.serverName];
|
|
236
|
+
saveServers(servers);
|
|
237
|
+
const status = rest.length
|
|
238
|
+
? await sync.reconnectMcpAndAnnounce({ only: target.serverName, enabled: target.cfg.enabled !== false })
|
|
239
|
+
: await sync.reconnectMcpAndAnnounce({ drop: [target.serverName] });
|
|
240
|
+
const released = await releaseAccount(target.accountCfg);
|
|
241
|
+
return released ? { ...status, ...released } : status;
|
|
242
|
+
}
|
|
341
243
|
if (!Object.hasOwn(servers, serverName)) {
|
|
342
244
|
refusePluginServer(serverName);
|
|
343
245
|
throw new Error(`MCP server not configured: ${serverName}`);
|
|
@@ -346,6 +248,17 @@ export function createMcpResourceApi({ deps, sync, decorate }) {
|
|
|
346
248
|
delete servers[serverName];
|
|
347
249
|
saveServers(servers);
|
|
348
250
|
const status = await sync.reconnectMcpAndAnnounce({ drop: [serverName] });
|
|
251
|
+
// The server of a multi-account connector takes every account's sign-in with it.
|
|
252
|
+
const accountCfgs = connectorAccountServers(removed);
|
|
253
|
+
if (accountCfgs.length) {
|
|
254
|
+
const released = (await Promise.all(accountCfgs.map(releaseAccount))).filter(Boolean);
|
|
255
|
+
if (!released.length) return status;
|
|
256
|
+
return {
|
|
257
|
+
...status,
|
|
258
|
+
signIn: released.every((one) => one.signIn === 'removed') ? 'removed' : 'shared',
|
|
259
|
+
revoked: released.every((one) => one.revoked === true),
|
|
260
|
+
};
|
|
261
|
+
}
|
|
349
262
|
// A removed server keeps no sign-in another server does not share: an
|
|
350
263
|
// app password leaves the keychain (it is revoked at Google only).
|
|
351
264
|
const account = gmailAppPasswordAccount(removed);
|
|
@@ -357,7 +270,13 @@ export function createMcpResourceApi({ deps, sync, decorate }) {
|
|
|
357
270
|
return released ? { ...status, ...released } : status;
|
|
358
271
|
},
|
|
359
272
|
async setMcpServerEnabled(name, enabled) {
|
|
360
|
-
|
|
273
|
+
// A name a multi-account connector holds as an account switches that
|
|
274
|
+
// account (and, on, its server) rather than the whole server; the
|
|
275
|
+
// account sharing the server's name is switched off with the server.
|
|
276
|
+
const requested = clean(name);
|
|
277
|
+
const servers = userServers();
|
|
278
|
+
const held = accountTarget(servers, requested);
|
|
279
|
+
const serverName = held?.serverName || requested;
|
|
361
280
|
if (!serverName) throw new Error('MCP server name is required');
|
|
362
281
|
const want = enabled !== false;
|
|
363
282
|
const owned = pluginMcpServer(serverName);
|
|
@@ -379,11 +298,11 @@ export function createMcpResourceApi({ deps, sync, decorate }) {
|
|
|
379
298
|
}
|
|
380
299
|
const shadowRow = mcpStatus().servers.find((s) => s.name === serverName);
|
|
381
300
|
if (!shadowRow) throw new Error(`MCP server not configured: ${serverName}`);
|
|
382
|
-
const servers = userServers();
|
|
383
301
|
const current = servers[serverName];
|
|
384
302
|
if (!current || typeof current !== 'object' || Array.isArray(current)) {
|
|
385
303
|
throw new Error(`MCP server not configured: ${serverName}`);
|
|
386
304
|
}
|
|
305
|
+
if (held && (want || serverName !== requested)) return setConnectorAccountEnabled(servers, held, want);
|
|
387
306
|
servers[serverName] = { ...current, enabled: want };
|
|
388
307
|
saveServers(servers);
|
|
389
308
|
const status = await sync.scheduleMcpToggle(serverName, want);
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
// The accounts of a multi-account connector server as the MCP server API
|
|
2
|
+
// edits them: adding one more account (into its server, or a new server
|
|
3
|
+
// holding it) and editing one account's transport, app password or client.
|
|
4
|
+
import { clean } from '../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
5
|
+
import {
|
|
6
|
+
mergeMcpServerConfig,
|
|
7
|
+
MCP_TIMEOUT_FIELD_GROUPS,
|
|
8
|
+
} from '../runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs';
|
|
9
|
+
import {
|
|
10
|
+
connectorAccountEnabled,
|
|
11
|
+
connectorAccountEntry,
|
|
12
|
+
connectorAccountServer,
|
|
13
|
+
connectorAccountServers,
|
|
14
|
+
connectorAccountsOf,
|
|
15
|
+
connectorAccountsUrl,
|
|
16
|
+
connectorById,
|
|
17
|
+
connectorOfServer,
|
|
18
|
+
gmailAppPasswordAccount,
|
|
19
|
+
withConnectorAccountEnabled,
|
|
20
|
+
} from '../runtime/shared/connector-catalog.mjs';
|
|
21
|
+
import { forgetConnectorAccountHealth } from '../runtime/connectors/connector-accounts-mcp.mjs';
|
|
22
|
+
import { accountTarget, mergedServerInput, nameTakenError, oauthUrlOf } from './resource-mcp-servers.mjs';
|
|
23
|
+
|
|
24
|
+
/** The server of multi-account connector `connector` in `servers`, or ''. */
|
|
25
|
+
function connectorServerName(servers, connector) {
|
|
26
|
+
return (
|
|
27
|
+
Object.keys(servers).find(
|
|
28
|
+
(name) => connectorOfServer(servers[name]) === connector && connectorAccountsOf(servers[name]).length > 0
|
|
29
|
+
) || ''
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Whether `input` edits the server `target` belongs to rather than the
|
|
34
|
+
* account: the account carries the server's name and the input the
|
|
35
|
+
* server's own address (its config editor). */
|
|
36
|
+
export const editsServerItself = (target, input) => {
|
|
37
|
+
if (target.serverName !== target.account.name || !clean(input.url)) return false;
|
|
38
|
+
try {
|
|
39
|
+
return oauthUrlOf({ type: input.type || 'http', url: input.url }) === oauthUrlOf(target.cfg);
|
|
40
|
+
} catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export function createConnectorAccountEdits({
|
|
46
|
+
normalizeMcpServerInput,
|
|
47
|
+
pluginMcpServer,
|
|
48
|
+
sync,
|
|
49
|
+
saveServers,
|
|
50
|
+
freeName,
|
|
51
|
+
storeOAuthClientSecret,
|
|
52
|
+
storeGmailAppPassword,
|
|
53
|
+
forgetUnusedGmailAppPassword,
|
|
54
|
+
releaseOAuth,
|
|
55
|
+
}) {
|
|
56
|
+
/** One more account of multi-account connector `connector` (one-account
|
|
57
|
+
* config `accountCfg` as normalized from `input`): into its server, or a
|
|
58
|
+
* new server named `name` holding it. The same Gmail address again takes
|
|
59
|
+
* the new app password. Resolves `{ name, account, status }`. */
|
|
60
|
+
async function addConnectorAccount(servers, connector, name, accountCfg, input) {
|
|
61
|
+
const serverName = connectorServerName(servers, connector);
|
|
62
|
+
const address = gmailAppPasswordAccount(accountCfg);
|
|
63
|
+
const cfg = serverName ? servers[serverName] : null;
|
|
64
|
+
const same =
|
|
65
|
+
cfg && address
|
|
66
|
+
? connectorAccountsOf(cfg).find(
|
|
67
|
+
(account) => gmailAppPasswordAccount(connectorAccountServer(cfg, account)) === address
|
|
68
|
+
)
|
|
69
|
+
: null;
|
|
70
|
+
if (same) {
|
|
71
|
+
await storeGmailAppPassword(input, accountCfg, true);
|
|
72
|
+
const status = await sync.reconnectMcpAndAnnounce({ only: serverName, enabled: cfg.enabled !== false });
|
|
73
|
+
return { name: serverName, account: same.name, status };
|
|
74
|
+
}
|
|
75
|
+
if (!serverName && (Object.hasOwn(servers, name) || pluginMcpServer(name) || accountTarget(servers, name))) {
|
|
76
|
+
throw nameTakenError(servers, name);
|
|
77
|
+
}
|
|
78
|
+
const accountName = serverName ? freeName(servers, name) : name;
|
|
79
|
+
const account = connectorAccountEntry(accountName, accountCfg);
|
|
80
|
+
// Sign-in tokens are stored per exact URL: another account needs its own.
|
|
81
|
+
const backendUrl = connectorById(connector)?.backend?.url;
|
|
82
|
+
if (
|
|
83
|
+
!address &&
|
|
84
|
+
cfg &&
|
|
85
|
+
connectorAccountServers(cfg).some((other) => oauthUrlOf(other) === oauthUrlOf({ type: 'http', url: account.url }))
|
|
86
|
+
) {
|
|
87
|
+
account.url = `${backendUrl}?account=${encodeURIComponent(accountName)}`;
|
|
88
|
+
}
|
|
89
|
+
const storedCfg = connectorAccountServer({ connector }, account);
|
|
90
|
+
await storeOAuthClientSecret(input, storedCfg);
|
|
91
|
+
await storeGmailAppPassword(input, storedCfg, true);
|
|
92
|
+
forgetConnectorAccountHealth(accountName);
|
|
93
|
+
let target = serverName;
|
|
94
|
+
if (cfg) {
|
|
95
|
+
servers[serverName] = { ...cfg, accounts: [...connectorAccountsOf(cfg), account] };
|
|
96
|
+
} else {
|
|
97
|
+
// The server's own settings (timeouts, enabled) ride on the input.
|
|
98
|
+
const { type: _type, url: _url, headers: _headers, oauthClientId: _client, ...rest } = accountCfg;
|
|
99
|
+
target = name;
|
|
100
|
+
servers[name] = { ...rest, type: 'http', url: connectorAccountsUrl(connector), connector, accounts: [account] };
|
|
101
|
+
}
|
|
102
|
+
saveServers(servers);
|
|
103
|
+
const status = await sync.reconnectMcpAndAnnounce({ only: target, enabled: servers[target].enabled !== false });
|
|
104
|
+
return { name: target, account: accountName, status };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** An edit of one account (`target` from accountTarget): its transport,
|
|
108
|
+
* app password or own client, as an edit of its one-account server was. */
|
|
109
|
+
async function saveConnectorAccount(servers, target, input) {
|
|
110
|
+
const { serverName, cfg, account, accountCfg } = target;
|
|
111
|
+
const { config } = normalizeMcpServerInput(
|
|
112
|
+
mergedServerInput({ ...input, name: account.name }, accountCfg, account.name)
|
|
113
|
+
);
|
|
114
|
+
const next = mergeMcpServerConfig(accountCfg, config);
|
|
115
|
+
next.connector = cfg.connector;
|
|
116
|
+
await storeOAuthClientSecret(input, next, accountCfg);
|
|
117
|
+
await storeGmailAppPassword(input, next, false);
|
|
118
|
+
// Settings that are not the account's transport (timeouts) are the server's.
|
|
119
|
+
const { type: _type, url: _url, headers: _headers, oauthClientId: _client, ...serverFields } = config;
|
|
120
|
+
const server = { ...cfg };
|
|
121
|
+
for (const group of MCP_TIMEOUT_FIELD_GROUPS) {
|
|
122
|
+
if (group.some((field) => Object.hasOwn(serverFields, field))) for (const field of group) delete server[field];
|
|
123
|
+
}
|
|
124
|
+
servers[serverName] = {
|
|
125
|
+
...server,
|
|
126
|
+
...serverFields,
|
|
127
|
+
accounts: connectorAccountsOf(cfg).map((entry) =>
|
|
128
|
+
entry.name === account.name
|
|
129
|
+
? {
|
|
130
|
+
...connectorAccountEntry(account.name, next),
|
|
131
|
+
...(connectorAccountEnabled(entry) ? {} : { enabled: false }),
|
|
132
|
+
}
|
|
133
|
+
: entry
|
|
134
|
+
),
|
|
135
|
+
};
|
|
136
|
+
saveServers(servers);
|
|
137
|
+
forgetConnectorAccountHealth(account.name);
|
|
138
|
+
const previousAddress = gmailAppPasswordAccount(accountCfg);
|
|
139
|
+
const address = gmailAppPasswordAccount(next);
|
|
140
|
+
if (previousAddress !== address) await forgetUnusedGmailAppPassword(previousAddress);
|
|
141
|
+
// An account switched from the Google sign-in to an app password keeps no sign-in.
|
|
142
|
+
if (address && !previousAddress) await releaseOAuth(accountCfg);
|
|
143
|
+
const status = await sync.reconnectMcpAndAnnounce({ only: serverName, enabled: cfg.enabled !== false });
|
|
144
|
+
return { name: serverName, account: account.name, source: 'config', status };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Switch one account (`target` from accountTarget) on or off by itself and
|
|
148
|
+
* reconnect its server. Switching an account on switches its server on;
|
|
149
|
+
* switching its last live account off switches the server off. */
|
|
150
|
+
async function setConnectorAccountEnabled(servers, target, enabled) {
|
|
151
|
+
const { serverName, cfg, account } = target;
|
|
152
|
+
const next = withConnectorAccountEnabled(cfg, account.name, enabled);
|
|
153
|
+
servers[serverName] = next;
|
|
154
|
+
saveServers(servers);
|
|
155
|
+
forgetConnectorAccountHealth(account.name);
|
|
156
|
+
const serverOn = next.enabled !== false;
|
|
157
|
+
const status = await sync.scheduleMcpToggle(serverName, serverOn);
|
|
158
|
+
await sync.publish('mcp', { mcpChanges: [{ name: serverName, enabled: serverOn }] });
|
|
159
|
+
return status;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return { addConnectorAccount, saveConnectorAccount, setConnectorAccountEnabled };
|
|
163
|
+
}
|