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
|
@@ -107,8 +107,17 @@ export function wireApis(boot) {
|
|
|
107
107
|
try {
|
|
108
108
|
boot.resourceApi.migratePluginMcpCopies();
|
|
109
109
|
} catch (error) {
|
|
110
|
+
console.warn(`[mcp] adopting plugin MCP copies failed: ${error?.message || error}`);
|
|
110
111
|
bootProfile('plugin-mcp:adopt-failed', { error: error?.message || String(error) });
|
|
111
112
|
}
|
|
113
|
+
// One server per multi-account connector: `gmail`, `gmail-2`… merge into
|
|
114
|
+
// `gmail` holding the accounts (their sign-ins and app passwords stay).
|
|
115
|
+
try {
|
|
116
|
+
boot.resourceApi.migrateConnectorAccounts();
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.warn(`[connectors] merging connector accounts failed: ${error?.message || error}`);
|
|
119
|
+
bootProfile('connector-accounts:merge-failed', { error: error?.message || String(error) });
|
|
120
|
+
}
|
|
112
121
|
}
|
|
113
122
|
boot.disposeGlobalExtensionSubscription = () => {
|
|
114
123
|
boot.disposeConfigSync?.();
|
|
@@ -8,7 +8,7 @@ import { createProviderReadiness } from '../provider-readiness.mjs';
|
|
|
8
8
|
import { createRoutePreparationGate } from '../route-preparation.mjs';
|
|
9
9
|
import { createRuntimeFeatureGates } from '../runtime-feature-gates.mjs';
|
|
10
10
|
import { createLazyRuntimeModules } from '../runtime-modules.mjs';
|
|
11
|
-
import {
|
|
11
|
+
import { sessionToolProfile } from '../../runtime/agent/orchestrator/runtime-core/tool-profile.mjs';
|
|
12
12
|
|
|
13
13
|
// The boot record: `rt` (shared mutable runtime state, promoted from closure
|
|
14
14
|
// `let`s so extracted modules read/write live values through one reference),
|
|
@@ -18,13 +18,14 @@ import { normalizeToolProfile } from '../../runtime/agent/orchestrator/runtime-c
|
|
|
18
18
|
export function beginBoot(params) {
|
|
19
19
|
const { provider, model, toolMode, cwd, toolProfile, approvalMode, disallowDelegation } = params;
|
|
20
20
|
const rt = {};
|
|
21
|
-
rt.toolProfile = normalizeToolProfile(toolProfile);
|
|
22
21
|
rt.approvalMode = approvalMode === 'implicit' ? 'implicit' : null;
|
|
23
22
|
rt.disallowDelegation = disallowDelegation === true;
|
|
24
23
|
rt.mcpScopeId = randomUUID();
|
|
25
24
|
rt.desktopSession = params.desktopSession;
|
|
26
25
|
rt.sessionProfile =
|
|
27
26
|
params.sessionProfile && typeof params.sessionProfile === 'object' ? { ...params.sessionProfile } : null;
|
|
27
|
+
// A heartbeat run's session is fenced to its few tools (tool-profile.mjs).
|
|
28
|
+
rt.toolProfile = sessionToolProfile({ toolProfile, sessionProfile: rt.sessionProfile });
|
|
28
29
|
bootProfile('session-runtime:start', { provider, model, toolMode, cwd });
|
|
29
30
|
// Last assistant text handed to the transcript writer (via onAssistantText),
|
|
30
31
|
// so the post-turn final-content append can skip an exact duplicate.
|
|
@@ -20,6 +20,7 @@ import { listProjectsStrict } from '../../runtime/shared/projects.mjs';
|
|
|
20
20
|
import { isWithin } from '../../runtime/shared/worktrees/paths.mjs';
|
|
21
21
|
import { standaloneDataDir } from '../runtime-paths.mjs';
|
|
22
22
|
import { SessionAddressError, isAdmissionOpen, ownerLifecycle } from '../session-address.mjs';
|
|
23
|
+
import { syncSessionCompaction, usesInjectedConfig } from '../session-compaction-sync.mjs';
|
|
23
24
|
import { dataDirOf } from './shared.mjs';
|
|
24
25
|
|
|
25
26
|
export function wireInfrastructure(boot) {
|
|
@@ -187,6 +188,9 @@ export function sessionAdopter(boot) {
|
|
|
187
188
|
}
|
|
188
189
|
}
|
|
189
190
|
rt.session = v;
|
|
191
|
+
// A resumed or swapped-in session keeps the compaction it was saved with
|
|
192
|
+
// unless it follows the current global settings (not on an injected config).
|
|
193
|
+
if (v?.id && !usesInjectedConfig(boot.params)) syncSessionCompaction(v, rt.config);
|
|
190
194
|
// The PreToolUse/PostToolUse bridge is a non-enumerable property that
|
|
191
195
|
// neither the store nor a resumed record carries: every session installed
|
|
192
196
|
// here (create, resume, route swap, clear, the manager's copy) gets it, so
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
} from '../model-recency.mjs';
|
|
32
32
|
import { createNativeWebSearch } from '../native-web-search.mjs';
|
|
33
33
|
import { createConfigLifecycle } from '../config-lifecycle.mjs';
|
|
34
|
+
import { usesInjectedConfig } from '../session-compaction-sync.mjs';
|
|
34
35
|
import { createQuickModelRows } from '../quick-model-rows.mjs';
|
|
35
36
|
import { createProviderModels } from '../provider-models.mjs';
|
|
36
37
|
import { createProviderUsage } from '../provider-usage.mjs';
|
|
@@ -66,6 +67,8 @@ function wireConfigLifecycle(boot) {
|
|
|
66
67
|
rt.configHasSecrets = next;
|
|
67
68
|
},
|
|
68
69
|
getRoute: () => rt.route,
|
|
70
|
+
getSession: () => rt.session,
|
|
71
|
+
fixedSessionCompaction: usesInjectedConfig(boot.params),
|
|
69
72
|
setRouteState: (next) => {
|
|
70
73
|
rt.route = next;
|
|
71
74
|
},
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
channelNotificationSessionId,
|
|
10
10
|
} from '../../runtime/shared/channel-notification-routing.mjs';
|
|
11
11
|
import { CHANNEL_NOTIFICATION_METHOD } from '../services/channel-session-router.mjs';
|
|
12
|
+
import { PROMPT_ORIGIN_CHANNEL } from '../../runtime/agent/orchestrator/session/manager/pending-message-entry.mjs';
|
|
12
13
|
import { envFlag } from '../../runtime/shared/env.mjs';
|
|
13
14
|
// Desktop-app bridges: tiny fs/fetch clients, so a static import adds no
|
|
14
15
|
// meaningful boot cost. The tools themselves are gated per session by the
|
|
@@ -22,6 +23,7 @@ import { TOOL_DEFS as MEDIA_TOOL_DEFS } from '../../runtime/media/tool-defs.mjs'
|
|
|
22
23
|
import { TOOL_DEFS as TIDY_TOOL_DEFS } from '../../runtime/tidy/tool-defs.mjs';
|
|
23
24
|
import { TOOL_DEFS as VISUALIZE_BRIDGE_TOOL_DEFS } from '../../runtime/visualize-bridge/tool-defs.mjs';
|
|
24
25
|
import { ASK_USER_TOOL_DEFS } from '../../runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs';
|
|
26
|
+
import { REACTION_TOOL_DEFS } from '../../runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs';
|
|
25
27
|
import { SETUP_TOOL_DEFS } from '../setup-tool/tool-defs.mjs';
|
|
26
28
|
import { createSetupToolExecutor } from '../setup-tool/executor.mjs';
|
|
27
29
|
import { bootProfile } from '../boot-profile.mjs';
|
|
@@ -143,7 +145,9 @@ function wireChannels(boot) {
|
|
|
143
145
|
const meta = p.meta && typeof p.meta === 'object' ? p.meta : {};
|
|
144
146
|
const content = channelNotificationModelContent(p);
|
|
145
147
|
if (!content) return;
|
|
146
|
-
notifySession(channelNotificationSessionId(rt.session, rt.reservedSessionId), content, meta
|
|
148
|
+
notifySession(channelNotificationSessionId(rt.session, rt.reservedSessionId), content, meta, {
|
|
149
|
+
origin: PROMPT_ORIGIN_CHANNEL,
|
|
150
|
+
});
|
|
147
151
|
},
|
|
148
152
|
});
|
|
149
153
|
bootProfile('channels:worker-ready', { ms: (performance.now() - channelsStartedAt).toFixed(1) });
|
|
@@ -167,6 +171,7 @@ function wireToolSurface(boot) {
|
|
|
167
171
|
visualizeToolDefs: VISUALIZE_BRIDGE_TOOL_DEFS,
|
|
168
172
|
setupToolDefs: SETUP_TOOL_DEFS,
|
|
169
173
|
askUserToolDefs: ASK_USER_TOOL_DEFS,
|
|
174
|
+
reactionToolDefs: REACTION_TOOL_DEFS,
|
|
170
175
|
goalTools: goalRuntime.tools,
|
|
171
176
|
agentTools: agentTool.tools,
|
|
172
177
|
skillToolEnabled: !envFlag('MIXDOG_DISABLE_SKILLS'),
|
|
@@ -232,6 +237,8 @@ function wireInternalTools(boot) {
|
|
|
232
237
|
getCallerSession: (sessionId) =>
|
|
233
238
|
sessionId === rt.session?.id ? rt.session : boot.mgr?.getSession?.(sessionId) || null,
|
|
234
239
|
flushSettings: () => boot.flushAllConfigSavesAsync({ requireSaved: true }),
|
|
240
|
+
// Another session's route and quota actions (daemon-session-control.mjs); null without a daemon.
|
|
241
|
+
executeSessionControl: boot.params.executeSessionControl || null,
|
|
235
242
|
});
|
|
236
243
|
const disposeInternalTools = internalTools.setInternalToolsProvider({
|
|
237
244
|
scopeId: rt.mcpScopeId,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// The bot-to-bot chain a session acts in (bot-hops.mjs botChainOf), from
|
|
2
|
+
// trusted runtime state only: the session's own turn chain (stamped from the
|
|
3
|
+
// submission that started it) and its delegation ancestry (parentSessionId /
|
|
4
|
+
// ownerSessionId), never from tool input.
|
|
5
|
+
import { resolveSessionMode } from '../runtime/agent/orchestrator/session/agent-mode.mjs';
|
|
6
|
+
import { botChainOf, turnBotChainOf } from '../runtime/shared/bot-hops.mjs';
|
|
7
|
+
|
|
8
|
+
const clean = (value) => String(value ?? '').trim();
|
|
9
|
+
|
|
10
|
+
/** The agent `session` acts as, by the session-mode resolver: a Lead its
|
|
11
|
+
* resolved agent (a coding Lead Mixy), a delegated worker its role. */
|
|
12
|
+
export function actingAgentOf(session, sessionId = '') {
|
|
13
|
+
const { agentId } = resolveSessionMode({ session, sessionId });
|
|
14
|
+
return clean(agentId || session?.agent);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** The chain session `sessionId` acts in, oldest first, ending with the agent
|
|
18
|
+
* it acts as (when it has one): walking parentSessionId/ownerSessionId up
|
|
19
|
+
* from it, each session contributes its current turn's chain, then the
|
|
20
|
+
* agent it acts as. The visited set ends a malformed cycle. */
|
|
21
|
+
export function delegationChainOf(sessionId, getSession = () => null) {
|
|
22
|
+
const chain = [];
|
|
23
|
+
const seen = new Set();
|
|
24
|
+
for (let id = clean(sessionId); id && !seen.has(id); ) {
|
|
25
|
+
seen.add(id);
|
|
26
|
+
const session = getSession(id) || null;
|
|
27
|
+
const acting = actingAgentOf(session, id);
|
|
28
|
+
chain.unshift(...turnBotChainOf(session), ...(acting ? [acting] : []));
|
|
29
|
+
id = clean(session?.parentSessionId || session?.ownerSessionId);
|
|
30
|
+
}
|
|
31
|
+
return botChainOf(chain);
|
|
32
|
+
}
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
* — the human's own sessions (Mixy's home, an ordinary Lead session) see every
|
|
21
21
|
* bot; a bot's chat, a room seat or an unattended run (a routine, even one in
|
|
22
22
|
* Mixy's own chat) only its own bot; a background run none. `session list`
|
|
23
|
-
*
|
|
23
|
+
* names every session for every scope, but gives previews and bot details
|
|
24
|
+
* only for the sessions the scope sees here (a background run none).
|
|
24
25
|
*
|
|
25
26
|
* Titles and previews are other bots' words: tag-shaped text is escaped and
|
|
26
27
|
* the answer says they are data, not instructions (UNTRUSTED_NOTE).
|
|
@@ -63,8 +64,10 @@ const cut = (text, max) => (text.length > max ? `${text.slice(0, Math.max(0, max
|
|
|
63
64
|
export const quotedText = (value, max) => cut(escapeHarnessTags(oneLine(value)), max);
|
|
64
65
|
const plural = (count, word) => `${count} ${word}${count === 1 ? '' : 's'}`;
|
|
65
66
|
const outputBytes = (value) => Buffer.byteLength(JSON.stringify(value), 'utf8');
|
|
66
|
-
|
|
67
|
-
const
|
|
67
|
+
/** A catalog row whose session runs a turn now. */
|
|
68
|
+
export const isWorking = (row) => row?.working === true || row?.agentWorking === true;
|
|
69
|
+
/** A catalog row's last activity (epoch ms), 0 when unknown. */
|
|
70
|
+
export const activityOf = (row) => Number(row?.lastUsedAt) || Number(row?.updatedAt) || 0;
|
|
68
71
|
|
|
69
72
|
/** The bot a catalog row belongs to: its home chat, room seat or task origin; '' for none. */
|
|
70
73
|
export function sessionBotOf(row) {
|
|
@@ -309,7 +312,7 @@ export function createBotStatus({
|
|
|
309
312
|
const parts = [`${quotedText(bot.name, 40)} (${bot.id})`, `chat ${state.homeId}`];
|
|
310
313
|
if (bot.self) parts.push('you');
|
|
311
314
|
parts.push(state.working ? 'working' : 'idle');
|
|
312
|
-
if (state.flags.length) parts.push(
|
|
315
|
+
if (state.flags.length) parts.push(`attention: ${state.flags.join('; ')}`);
|
|
313
316
|
parts.push(state.lastAt ? `last ${ago(state.lastAt, now)}` : 'no chat yet');
|
|
314
317
|
if (state.running.length) {
|
|
315
318
|
const [first] = state.running;
|
|
@@ -3,19 +3,22 @@ import {
|
|
|
3
3
|
deleteSchedule,
|
|
4
4
|
deleteWebhook,
|
|
5
5
|
getWebhookSecret,
|
|
6
|
+
renameScheduleHere,
|
|
6
7
|
saveSchedule,
|
|
7
8
|
saveWebhook,
|
|
8
9
|
setScheduleEnabled,
|
|
9
10
|
setWebhookEnabled,
|
|
10
11
|
setWebhookConfigAsync,
|
|
11
12
|
testWebhook,
|
|
13
|
+
withScheduleRenameReserved,
|
|
12
14
|
} from './services/channel-admin.mjs';
|
|
13
|
-
import { getSchedule, markScheduleFailure, markScheduleSuccess } from '../runtime/channels/lib/schedules-db.mjs';
|
|
15
|
+
import { getSchedule, markScheduleFailure, markScheduleSkipped, markScheduleSuccess } from '../runtime/channels/lib/schedules-db.mjs';
|
|
16
|
+
import { scheduleRenameUncertainError } from '../runtime/channels/lib/schedule-errors.mjs';
|
|
14
17
|
import { loadEndpointConfig, readEndpointLastPayload } from '../runtime/channels/lib/webhooks-db.mjs';
|
|
15
18
|
import { webhookEventSummary, webhookRunPrompt } from '../runtime/channels/lib/webhook/session-dispatch.mjs';
|
|
16
19
|
import { runScheduleSession } from './schedule-session-run.mjs';
|
|
17
20
|
import { runWebhookSession } from './webhook-session-run.mjs';
|
|
18
|
-
import { retryRoutineDelivery } from './owned-automation-run.mjs';
|
|
21
|
+
import { beginAutomationRename, retryRoutineDelivery } from './owned-automation-run.mjs';
|
|
19
22
|
|
|
20
23
|
/** Why a "Run now" did not run: its owner bot is missing, or a run is going. */
|
|
21
24
|
function skippedRunMessage(name, outcome) {
|
|
@@ -27,6 +30,36 @@ function skippedRunMessage(name, outcome) {
|
|
|
27
30
|
// directly here and the runtime injects only the closure-owned callbacks
|
|
28
31
|
// (channel worker handle, soft reload).
|
|
29
32
|
export function createChannelConfigApi({ channels, reloadChannelsSoon, ensureAutomationRuntime = () => {} }) {
|
|
33
|
+
// The channels worker owns the scheduler and the runs it fires, so while it
|
|
34
|
+
// is up it performs the run check and the row move in one step
|
|
35
|
+
// (rename_schedule); this process's own runs ("Run now") are reserved around
|
|
36
|
+
// that call. Without a worker, the check and the move happen here.
|
|
37
|
+
async function renameSchedule(oldName, def, opts) {
|
|
38
|
+
if (!channels.status().running) return renameScheduleHere(oldName, def, opts);
|
|
39
|
+
return withScheduleRenameReserved(oldName, async () => {
|
|
40
|
+
try {
|
|
41
|
+
const reply = await channels.execute('rename_schedule', { name: oldName, def, ...opts });
|
|
42
|
+
const text = reply?.content?.[0]?.text ?? '';
|
|
43
|
+
if (reply?.isError === true) {
|
|
44
|
+
// The worker's refusal keeps its structured code and details.
|
|
45
|
+
throw Object.assign(
|
|
46
|
+
new Error(text.replace(/^rename_schedule failed: /, '')),
|
|
47
|
+
typeof reply.code === 'string' ? { code: reply.code } : {},
|
|
48
|
+
reply.details && typeof reply.details === 'object' ? { details: reply.details } : {}
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
return text ? JSON.parse(text) : null;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
// Whatever the worker did, have it re-read the schedules.
|
|
54
|
+
reloadChannelsSoon();
|
|
55
|
+
// execute() already retried a transport failure (call timeout 120 s,
|
|
56
|
+
// same callId so the daemon runs the request once); what is left is
|
|
57
|
+
// an unanswered request.
|
|
58
|
+
if (error?.daemonTransportError) throw scheduleRenameUncertainError(error.message);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
30
63
|
return {
|
|
31
64
|
async getChannelSetup() {
|
|
32
65
|
return channelSetup();
|
|
@@ -40,7 +73,7 @@ export function createChannelConfigApi({ channels, reloadChannelsSoon, ensureAut
|
|
|
40
73
|
return result;
|
|
41
74
|
},
|
|
42
75
|
async saveSchedule(entry) {
|
|
43
|
-
const result = await saveSchedule(entry);
|
|
76
|
+
const result = await saveSchedule(entry, { rename: renameSchedule });
|
|
44
77
|
reloadChannelsSoon();
|
|
45
78
|
// First automation created while the app is already running: the boot-
|
|
46
79
|
// time autostart check has passed, so kick the worker start path now
|
|
@@ -86,22 +119,35 @@ export function createChannelConfigApi({ channels, reloadChannelsSoon, ensureAut
|
|
|
86
119
|
},
|
|
87
120
|
async runScheduleNow(name) {
|
|
88
121
|
const id = String(name || '').trim();
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
122
|
+
// The name is held from the read of the row through the outcome stamps,
|
|
123
|
+
// so a rename can neither move the row this run read nor slip in before
|
|
124
|
+
// its stamps are written (they would land on no row).
|
|
125
|
+
const release = beginAutomationRename('schedule', id);
|
|
126
|
+
// A run or a rename holding it: not run, recorded as an overlap skip.
|
|
127
|
+
if (!release) {
|
|
128
|
+
await markScheduleSkipped(id, new Date()).catch(() => {});
|
|
129
|
+
throw new Error(skippedRunMessage(id, { reason: 'overlap' }));
|
|
130
|
+
}
|
|
94
131
|
try {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
132
|
+
const schedule = await getSchedule(id);
|
|
133
|
+
if (!schedule) throw new Error(`schedule "${id}" does not exist`);
|
|
134
|
+
// Runs in the engine process as a turn in the owner bot's chat, so it
|
|
135
|
+
// works even while the channels worker is off.
|
|
136
|
+
let outcome;
|
|
137
|
+
try {
|
|
138
|
+
// Asked for by a person: no failure backoff.
|
|
139
|
+
outcome = await runScheduleSession(schedule, { attended: true, reserved: true });
|
|
140
|
+
} catch (error) {
|
|
141
|
+
await markScheduleFailure(schedule.name, new Date()).catch(() => {});
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
if (outcome.skipped) throw new Error(skippedRunMessage(schedule.name, outcome));
|
|
145
|
+
// The run's outcome shows as the schedule's last run, like a timed fire.
|
|
146
|
+
await markScheduleSuccess(schedule.name, new Date()).catch(() => {});
|
|
147
|
+
return { name: schedule.name, ok: true, sessionId: outcome.sessionId, result: outcome.result };
|
|
148
|
+
} finally {
|
|
149
|
+
release();
|
|
100
150
|
}
|
|
101
|
-
if (outcome.skipped) throw new Error(skippedRunMessage(schedule.name, outcome));
|
|
102
|
-
// The run's outcome shows as the schedule's last run, like a timed fire.
|
|
103
|
-
await markScheduleSuccess(schedule.name, new Date()).catch(() => {});
|
|
104
|
-
return { name: schedule.name, ok: true, sessionId: outcome.sessionId, result: outcome.result };
|
|
105
151
|
},
|
|
106
152
|
// Re-runs the endpoint on its latest received payload, with its current
|
|
107
153
|
// instructions, behind the same untrusted-data fence as a live delivery.
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
stripStoredRouteDefaults,
|
|
18
18
|
withDefaultPresets,
|
|
19
19
|
} from '../runtime/agent/orchestrator/config-presets.mjs';
|
|
20
|
+
import { syncSessionCompaction } from './session-compaction-sync.mjs';
|
|
20
21
|
import { createConfigWriters } from './config-lifecycle/config-writers.mjs';
|
|
21
22
|
import { createLeadRouteSync } from './config-lifecycle/lead-route-sync.mjs';
|
|
22
23
|
import { createOutputStyleStatusCache } from './config-lifecycle/output-style-cache.mjs';
|
|
@@ -134,6 +135,10 @@ export function createConfigLifecycle({
|
|
|
134
135
|
getConfigHasSecrets,
|
|
135
136
|
setConfigHasSecrets,
|
|
136
137
|
getRoute,
|
|
138
|
+
// The live session follows the reloaded global compaction settings, unless
|
|
139
|
+
// the runtime runs on an injected (headless) config.
|
|
140
|
+
getSession,
|
|
141
|
+
fixedSessionCompaction = false,
|
|
137
142
|
// Main route sync on reload (both optional: a lifecycle without them never syncs)
|
|
138
143
|
setRouteState,
|
|
139
144
|
resolveRoute,
|
|
@@ -222,6 +227,7 @@ export function createConfigLifecycle({
|
|
|
222
227
|
const adopted = adoptConfig(next, { hasSecrets: true });
|
|
223
228
|
configSaveBaseline = structuredClone(adopted);
|
|
224
229
|
leadRoute.syncEmptyMainRoute(adopted);
|
|
230
|
+
if (!fixedSessionCompaction) syncSessionCompaction(getSession?.(), adopted);
|
|
225
231
|
return adopted;
|
|
226
232
|
}
|
|
227
233
|
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
// After the multi-account connector merge (connector-catalog.mjs
|
|
2
|
+
// mergeConnectorAccountServers) `gmail-2`, `google-calendar-2`… are accounts of
|
|
3
|
+
// one server, no longer servers. Every store of ours that keys a setting by
|
|
4
|
+
// MCP server name must name the surviving server instead:
|
|
5
|
+
// agents/<id>/agent.json, bots/<id>/agent.json connectors.off / connectors.tools
|
|
6
|
+
// (a legacy allow list too)
|
|
7
|
+
// <data>/project-connectors.json projects.<root>.off
|
|
8
|
+
// <data>/hooks.json, <data>/hooks/hooks.json mcp_tool `server`, tool matchers
|
|
9
|
+
// (extension scopes are the config's and are dropped by migrateConnectorAccounts;
|
|
10
|
+
// an approval's "always allow" is the agent's connectors.tools; agent routes
|
|
11
|
+
// name models, not servers.) Project and plugin hook files are the user's or
|
|
12
|
+
// the plugin's own and are never rewritten here.
|
|
13
|
+
//
|
|
14
|
+
// Rule: the merged connector is OFF for an agent/project only when EVERY
|
|
15
|
+
// merged server was off (the same rule as the merged server's `enabled`: one
|
|
16
|
+
// working account keeps the connector usable). Per-tool permissions move to
|
|
17
|
+
// the surviving name; where two merged servers disagree on a tool the MORE
|
|
18
|
+
// PERMISSIVE permission wins, as "on beats off" does at server level. Entries
|
|
19
|
+
// of a server that was off are dormant and are dropped when the connector
|
|
20
|
+
// stays on, so they never become live. A setting that names no merged-away
|
|
21
|
+
// server is never touched, which makes every run after the first a no-op.
|
|
22
|
+
//
|
|
23
|
+
// The merge is saved to the config once, so the rename mapping outlives it:
|
|
24
|
+
// `<data>/connector-merge-pending.json` ({ merged: [{ name, from }] }) is
|
|
25
|
+
// written before any store is touched and deleted only when every store
|
|
26
|
+
// migrated. A store that fails (unreadable, malformed, not writable) is
|
|
27
|
+
// reported and the others still go on; the next start retries them all.
|
|
28
|
+
//
|
|
29
|
+
// Hooks: only tool identifiers are rewritten — an `mcp_tool` handler's
|
|
30
|
+
// `server`, and a matcher / tool-name field (or the tool part of an `if`
|
|
31
|
+
// before its `(`) that is an `mcp__<server>__…` identifier or an
|
|
32
|
+
// alternative of a pattern. Argument conditions such as `Bash(mcp__x__*)`
|
|
33
|
+
// and any other data are never touched.
|
|
34
|
+
import { readdirSync, readFileSync, rmSync } from 'node:fs';
|
|
35
|
+
import { join } from 'node:path';
|
|
36
|
+
import { normalizeRules, standardConfigReport } from './services/hook-bus/config.mjs';
|
|
37
|
+
import {
|
|
38
|
+
PERMISSION_RANK,
|
|
39
|
+
PROJECT_CONNECTORS_FILE,
|
|
40
|
+
connectorEnabled,
|
|
41
|
+
parseConnectorPolicy,
|
|
42
|
+
storedConnectorPolicy,
|
|
43
|
+
} from '../runtime/agent/orchestrator/mcp/agent-connectors.mjs';
|
|
44
|
+
import { parseJsonText, withFileLockSync, writeJsonAtomicSync } from '../runtime/shared/atomic-file.mjs';
|
|
45
|
+
|
|
46
|
+
const unique = (list) => [...new Set(list)].sort();
|
|
47
|
+
|
|
48
|
+
/** The policy `{ off, tools }` (or a legacy `{ allow, off, tools }`) with every
|
|
49
|
+
* merged-away server of `merged` mapped onto its surviving one; null when it
|
|
50
|
+
* names none. `merged` is mergeConnectorAccountServers' `merged`. */
|
|
51
|
+
function mapMergedConnectorPolicy(policy, merged) {
|
|
52
|
+
let current = policy;
|
|
53
|
+
for (const { name, from } of merged) {
|
|
54
|
+
const gone = from.filter((server) => server !== name);
|
|
55
|
+
const named = (server) =>
|
|
56
|
+
current.off.includes(server) || current.allow?.includes(server) || Object.hasOwn(current.tools, server);
|
|
57
|
+
if (!gone.some(named)) continue;
|
|
58
|
+
const live = from.filter((server) => connectorEnabled(current, server));
|
|
59
|
+
const on = live.length > 0;
|
|
60
|
+
const off = current.off.filter((server) => !from.includes(server));
|
|
61
|
+
const allow = current.allow?.filter((server) => !from.includes(server));
|
|
62
|
+
if (allow && on) allow.push(name);
|
|
63
|
+
if (!allow && !on) off.push(name);
|
|
64
|
+
const tools = { ...current.tools };
|
|
65
|
+
for (const server of from) delete tools[server];
|
|
66
|
+
const moved = {};
|
|
67
|
+
for (const server of on ? live : from) {
|
|
68
|
+
for (const [tool, permission] of Object.entries(current.tools[server] || {})) {
|
|
69
|
+
if (!(tool in moved) || PERMISSION_RANK[permission] > PERMISSION_RANK[moved[tool]]) moved[tool] = permission;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (Object.keys(moved).length) tools[name] = moved;
|
|
73
|
+
current = { ...(allow ? { allow: unique(allow) } : {}), off: unique(off), tools };
|
|
74
|
+
}
|
|
75
|
+
return current === policy ? null : current;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** A mapped policy as the value the agent.json `connectors` field stores
|
|
79
|
+
* (undefined: the field goes). */
|
|
80
|
+
function storedValue(policy) {
|
|
81
|
+
if (!policy.allow) return storedConnectorPolicy(policy) ?? undefined;
|
|
82
|
+
const ids = unique([...policy.allow, ...Object.keys(policy.tools)]);
|
|
83
|
+
return ids.map((id) => ({
|
|
84
|
+
id,
|
|
85
|
+
enabled: policy.allow.includes(id),
|
|
86
|
+
...(policy.tools[id] ? { tools: policy.tools[id] } : {}),
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const PENDING_MERGE_FILE = 'connector-merge-pending.json';
|
|
91
|
+
|
|
92
|
+
const warn = (file, error) => process.stderr.write(`[connectors] ${file} not migrated (${error?.message || error})\n`);
|
|
93
|
+
|
|
94
|
+
/** The JSON at `file`; null when it does not exist. Any other failure throws. */
|
|
95
|
+
function readJsonFile(file) {
|
|
96
|
+
try {
|
|
97
|
+
return parseJsonText(readFileSync(file, 'utf8'));
|
|
98
|
+
} catch (error) {
|
|
99
|
+
if (error?.code === 'ENOENT' || error?.code === 'ENOTDIR') return null;
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const isRecord = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
105
|
+
|
|
106
|
+
/** Runs `step` for one store; a failure is reported and returned, never thrown. */
|
|
107
|
+
function attempt(file, step, outcome) {
|
|
108
|
+
try {
|
|
109
|
+
step();
|
|
110
|
+
} catch (error) {
|
|
111
|
+
warn(file, error);
|
|
112
|
+
outcome.failed.push(file);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function migrateAgentFiles(dataDir, merged, outcome, readdir) {
|
|
117
|
+
for (const store of ['agents', 'bots']) {
|
|
118
|
+
const dir = join(dataDir, store);
|
|
119
|
+
let entries;
|
|
120
|
+
try {
|
|
121
|
+
entries = readdir(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory());
|
|
122
|
+
} catch (error) {
|
|
123
|
+
// A store that does not exist has nothing to migrate; any other failure
|
|
124
|
+
// leaves its agents unprocessed, so the mapping must stay pending.
|
|
125
|
+
if (error?.code !== 'ENOENT') {
|
|
126
|
+
warn(dir, error);
|
|
127
|
+
outcome.failed.push(dir);
|
|
128
|
+
}
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
for (const entry of entries) {
|
|
132
|
+
const file = join(dataDir, store, entry.name, 'agent.json');
|
|
133
|
+
attempt(
|
|
134
|
+
file,
|
|
135
|
+
() => {
|
|
136
|
+
const manifest = readJsonFile(file);
|
|
137
|
+
if (!isRecord(manifest) || manifest.connectors == null) return;
|
|
138
|
+
const next = mapMergedConnectorPolicy(parseConnectorPolicy(manifest.connectors), merged);
|
|
139
|
+
if (!next) return;
|
|
140
|
+
const value = storedValue(next);
|
|
141
|
+
if (value) manifest.connectors = value;
|
|
142
|
+
else delete manifest.connectors;
|
|
143
|
+
writeJsonAtomicSync(file, manifest, { backup: true });
|
|
144
|
+
outcome.agents.push(`${store}/${entry.name}`);
|
|
145
|
+
},
|
|
146
|
+
outcome
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function migrateProjectFile(dataDir, merged, outcome) {
|
|
153
|
+
const file = join(dataDir, PROJECT_CONNECTORS_FILE);
|
|
154
|
+
attempt(
|
|
155
|
+
file,
|
|
156
|
+
() => {
|
|
157
|
+
withFileLockSync(`${file}.lock`, () => {
|
|
158
|
+
const document = readJsonFile(file);
|
|
159
|
+
const projects = document?.projects;
|
|
160
|
+
if (!isRecord(projects)) return;
|
|
161
|
+
const changed = [];
|
|
162
|
+
for (const [root, entry] of Object.entries(projects)) {
|
|
163
|
+
if (!isRecord(entry) || !Array.isArray(entry.off)) continue;
|
|
164
|
+
const next = mapMergedConnectorPolicy({ off: entry.off.map(String), tools: {} }, merged);
|
|
165
|
+
if (!next) continue;
|
|
166
|
+
if (next.off.length) projects[root] = { ...entry, off: next.off };
|
|
167
|
+
else delete projects[root];
|
|
168
|
+
changed.push(root);
|
|
169
|
+
}
|
|
170
|
+
if (!changed.length) return;
|
|
171
|
+
writeJsonAtomicSync(file, document, { lock: false, backup: true });
|
|
172
|
+
outcome.projects.push(...changed);
|
|
173
|
+
});
|
|
174
|
+
},
|
|
175
|
+
outcome
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
180
|
+
|
|
181
|
+
/** A tool identifier or pattern (`mcp__a__x`, `^mcp__a__.*$`, `Bash|mcp__a__x`)
|
|
182
|
+
* with each `mcp__<merged-away>` alternative renamed. */
|
|
183
|
+
function renameToolPattern(value, renames) {
|
|
184
|
+
let next = value;
|
|
185
|
+
for (const [gone, name] of renames) {
|
|
186
|
+
const identifier = new RegExp(`(^|\\|)(\\^?)mcp__${escapeRegExp(gone)}(?=__|(?![A-Za-z0-9_-]))`, 'g');
|
|
187
|
+
next = next.replace(identifier, (_all, lead, anchor) => `${lead}${anchor}mcp__${name}`);
|
|
188
|
+
}
|
|
189
|
+
return next;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** A condition `Tool(arguments)`: only the tool part is an identifier. */
|
|
193
|
+
function renameCondition(value, renames) {
|
|
194
|
+
const open = value.indexOf('(');
|
|
195
|
+
return open < 0
|
|
196
|
+
? renameToolPattern(value, renames)
|
|
197
|
+
: renameToolPattern(value.slice(0, open), renames) + value.slice(open);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Renames in the hook structures of `document` (in place); true when any changed. */
|
|
201
|
+
function renameInHooks(document, renames) {
|
|
202
|
+
let changed = false;
|
|
203
|
+
const set = (owner, key, rename) => {
|
|
204
|
+
if (typeof owner[key] !== 'string') return;
|
|
205
|
+
const next = rename(owner[key], renames);
|
|
206
|
+
if (next === owner[key]) return;
|
|
207
|
+
owner[key] = next;
|
|
208
|
+
changed = true;
|
|
209
|
+
};
|
|
210
|
+
const handler = (hook) => {
|
|
211
|
+
if (!isRecord(hook)) return;
|
|
212
|
+
if (hook.type === 'mcp_tool') {
|
|
213
|
+
if (typeof hook.server === 'string' && renames.has(hook.server.trim())) {
|
|
214
|
+
hook.server = renames.get(hook.server.trim());
|
|
215
|
+
changed = true;
|
|
216
|
+
}
|
|
217
|
+
set(hook, 'tool', renameToolPattern);
|
|
218
|
+
}
|
|
219
|
+
set(hook, 'if', renameCondition);
|
|
220
|
+
};
|
|
221
|
+
if (standardConfigReport(document).standard) {
|
|
222
|
+
for (const groups of Object.values(document.hooks)) {
|
|
223
|
+
for (const group of Array.isArray(groups) ? groups : []) {
|
|
224
|
+
if (!isRecord(group)) continue;
|
|
225
|
+
set(group, 'matcher', renameToolPattern);
|
|
226
|
+
set(group, 'if', renameCondition);
|
|
227
|
+
for (const hook of Array.isArray(group.hooks) ? group.hooks : []) handler(hook);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
} else {
|
|
231
|
+
for (const rule of normalizeRules(document)) {
|
|
232
|
+
if (!isRecord(rule)) continue;
|
|
233
|
+
set(rule, 'tool', renameToolPattern);
|
|
234
|
+
set(rule, 'name', renameToolPattern);
|
|
235
|
+
set(rule, 'if', renameCondition);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return changed;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function migrateHookFiles(dataDir, merged, outcome) {
|
|
242
|
+
const renames = new Map(
|
|
243
|
+
merged.flatMap(({ name, from }) => from.filter((server) => server !== name).map((gone) => [gone, name]))
|
|
244
|
+
);
|
|
245
|
+
for (const file of [join(dataDir, 'hooks.json'), join(dataDir, 'hooks', 'hooks.json')]) {
|
|
246
|
+
attempt(
|
|
247
|
+
file,
|
|
248
|
+
() => {
|
|
249
|
+
const document = readJsonFile(file);
|
|
250
|
+
if (!isRecord(document) && !Array.isArray(document)) return;
|
|
251
|
+
if (!renameInHooks(document, renames)) return;
|
|
252
|
+
writeJsonAtomicSync(file, document, { backup: true });
|
|
253
|
+
outcome.hooks.push(file);
|
|
254
|
+
},
|
|
255
|
+
outcome
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const validGroup = (group) =>
|
|
261
|
+
isRecord(group) &&
|
|
262
|
+
typeof group.name === 'string' &&
|
|
263
|
+
Array.isArray(group.from) &&
|
|
264
|
+
group.from.every((n) => typeof n === 'string');
|
|
265
|
+
|
|
266
|
+
/** Maps every per-server setting of `dataDir` onto the surviving servers of
|
|
267
|
+
* `merged` (this start's merge, [] to only retry) plus any still pending from
|
|
268
|
+
* an earlier start. Returns what it rewrote and the files that failed:
|
|
269
|
+
* `{ agents, projects, hooks, failed, unrecorded? }`. The pending record is
|
|
270
|
+
* removed only when `failed` is empty; `unrecorded` says it could not be
|
|
271
|
+
* written, so the caller must not save the merge. `readdir` lists the agent
|
|
272
|
+
* and bot directories. */
|
|
273
|
+
export function migrateMergedConnectorServers(dataDir, merged, { readdir = readdirSync } = {}) {
|
|
274
|
+
const outcome = { agents: [], projects: [], hooks: [], failed: [] };
|
|
275
|
+
if (!dataDir) return outcome;
|
|
276
|
+
const pendingFile = join(dataDir, PENDING_MERGE_FILE);
|
|
277
|
+
let pending = [];
|
|
278
|
+
try {
|
|
279
|
+
const stored = readJsonFile(pendingFile)?.merged;
|
|
280
|
+
pending = Array.isArray(stored) ? stored.filter(validGroup).map(({ name, from }) => ({ name, from })) : [];
|
|
281
|
+
} catch (error) {
|
|
282
|
+
warn(pendingFile, error);
|
|
283
|
+
}
|
|
284
|
+
const groups = [...pending];
|
|
285
|
+
for (const { name, from } of merged) {
|
|
286
|
+
if (!groups.some((group) => group.name === name && JSON.stringify(group.from) === JSON.stringify(from))) {
|
|
287
|
+
groups.push({ name, from });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (!groups.length) return outcome;
|
|
291
|
+
if (groups.length !== pending.length) {
|
|
292
|
+
try {
|
|
293
|
+
writeJsonAtomicSync(pendingFile, { merged: groups }, { backup: false });
|
|
294
|
+
} catch (error) {
|
|
295
|
+
warn(pendingFile, error);
|
|
296
|
+
// Nothing records the mapping: a failed store must keep the merge unsaved.
|
|
297
|
+
outcome.unrecorded = true;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
migrateAgentFiles(dataDir, groups, outcome, readdir);
|
|
301
|
+
migrateProjectFile(dataDir, groups, outcome);
|
|
302
|
+
migrateHookFiles(dataDir, groups, outcome);
|
|
303
|
+
if (!outcome.failed.length) rmSync(pendingFile, { force: true });
|
|
304
|
+
return outcome;
|
|
305
|
+
}
|