@gajae-code/coding-agent 0.17.1 → 0.17.4
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/CHANGELOG.md +266 -0
- package/dist/types/async/job-manager.d.ts +7 -6
- package/dist/types/cli/daemon-cli.d.ts +3 -1
- package/dist/types/cli/github-release.d.ts +17 -0
- package/dist/types/cli/public-command-entry.d.ts +56 -0
- package/dist/types/cli/public-command-errors.d.ts +126 -0
- package/dist/types/cli/public-command-evidence.d.ts +99 -0
- package/dist/types/cli/public-command-help.d.ts +65 -0
- package/dist/types/cli/public-command-registry.d.ts +69 -0
- package/dist/types/cli/session-picker.d.ts +1 -1
- package/dist/types/cli/setup-cli.d.ts +1 -0
- package/dist/types/cli/skills-cli.d.ts +5 -0
- package/dist/types/cli.d.ts +3 -0
- package/dist/types/commands/daemon.d.ts +4 -50
- package/dist/types/commands/sdk.d.ts +20 -37
- package/dist/types/commands/setup.d.ts +3 -0
- package/dist/types/commands/skills.d.ts +9 -0
- package/dist/types/config/autorouting-tier-map.d.ts +24 -0
- package/dist/types/config/file-lock.d.ts +10 -1
- package/dist/types/config/model-profile-activation.d.ts +63 -4
- package/dist/types/config/model-registry.d.ts +20 -2
- package/dist/types/config/settings-schema.d.ts +11 -0
- package/dist/types/coordinator-mcp/question-state.d.ts +6 -1
- package/dist/types/coordinator-mcp/server.d.ts +3 -0
- package/dist/types/daemon/operator-contract.d.ts +5 -1
- package/dist/types/eval/js/worker-protocol.d.ts +2 -0
- package/dist/types/extensibility/extensions/types.d.ts +12 -0
- package/dist/types/extensibility/gjc-plugins/registry.d.ts +4 -0
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +18 -0
- package/dist/types/extensibility/shared-events.d.ts +3 -1
- package/dist/types/gjc-runtime/session-state-lock.d.ts +61 -0
- package/dist/types/internal-urls/embedded-protocol.d.ts +9 -0
- package/dist/types/internal-urls/index.d.ts +1 -0
- package/dist/types/internal-urls/parse.d.ts +9 -1
- package/dist/types/main.d.ts +22 -0
- package/dist/types/modes/acp/acp-agent.d.ts +94 -1
- package/dist/types/modes/acp/startup-provenance.d.ts +16 -0
- package/dist/types/modes/components/custom-provider-wizard.d.ts +19 -1
- package/dist/types/modes/components/session-selector.d.ts +5 -2
- package/dist/types/modes/components/thinking-selector.d.ts +2 -1
- package/dist/types/modes/components/user-message-selector.d.ts +5 -2
- package/dist/types/modes/controllers/command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +11 -1
- package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +14 -1
- package/dist/types/modes/types.d.ts +2 -2
- package/dist/types/runtime/process-lifecycle.d.ts +2 -0
- package/dist/types/runtime-mcp/manager.d.ts +56 -0
- package/dist/types/runtime-mcp/pool.d.ts +17 -0
- package/dist/types/runtime-mcp/redaction.d.ts +20 -0
- package/dist/types/runtime-mcp/startup-policy.d.ts +6 -0
- package/dist/types/runtime-mcp/tool-bridge.d.ts +9 -0
- package/dist/types/runtime-mcp/transports/http.d.ts +11 -0
- package/dist/types/sdk/acp/adapter.d.ts +27 -0
- package/dist/types/sdk/acp/final-text.d.ts +8 -0
- package/dist/types/sdk/broker/broker.d.ts +13 -2
- package/dist/types/sdk/broker/ensure.d.ts +46 -1
- package/dist/types/sdk/broker/identity.d.ts +3 -1
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +23 -3
- package/dist/types/sdk/broker/lifecycle.d.ts +15 -8
- package/dist/types/sdk/broker/runtime.d.ts +1 -1
- package/dist/types/sdk/broker/session-index.d.ts +22 -3
- package/dist/types/sdk/broker/spawn-authority.d.ts +4 -0
- package/dist/types/sdk/broker/stderr-drainer.d.ts +13 -0
- package/dist/types/sdk/bus/index.d.ts +19 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +3 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +5 -0
- package/dist/types/sdk/cli/master-cli.d.ts +6 -10
- package/dist/types/sdk/cli/rows.d.ts +19 -1
- package/dist/types/sdk/cli/session-cli.d.ts +22 -5
- package/dist/types/sdk/client/client.d.ts +2 -0
- package/dist/types/sdk/guides/cli.d.ts +3 -4
- package/dist/types/sdk/guides/verify.d.ts +2 -0
- package/dist/types/sdk/host/host.d.ts +9 -0
- package/dist/types/sdk/host/session-runtime.d.ts +31 -0
- package/dist/types/sdk/host/types.d.ts +10 -0
- package/dist/types/sdk/index.d.ts +1 -0
- package/dist/types/sdk/prompt-deadline-flush.d.ts +83 -0
- package/dist/types/sdk/prompt-deadline-manager.d.ts +38 -1
- package/dist/types/sdk/prompt-failure.d.ts +30 -1
- package/dist/types/sdk/prompt-status.d.ts +8 -0
- package/dist/types/sdk/prompt-tool-boundary.d.ts +73 -0
- package/dist/types/sdk/router/replay-retention-gap-cache.d.ts +13 -0
- package/dist/types/sdk/router/session-router.d.ts +2 -0
- package/dist/types/sdk/startup-capability.d.ts +2 -0
- package/dist/types/sdk/transport/relay.d.ts +1 -0
- package/dist/types/sdk/transport/serve-cli.d.ts +73 -2
- package/dist/types/sdk/transport/stdio.d.ts +5 -1
- package/dist/types/session/agent-session.d.ts +168 -21
- package/dist/types/session/fallback-chain-controller.d.ts +6 -6
- package/dist/types/session/fold-coordinator.d.ts +17 -3
- package/dist/types/session/internal/managed-session-storage.d.ts +7 -1
- package/dist/types/session/session-manager.d.ts +64 -1
- package/dist/types/session/session-work-lease.d.ts +14 -0
- package/dist/types/setup/model-onboarding-guidance.d.ts +1 -1
- package/dist/types/setup/provider-onboarding.d.ts +81 -1
- package/dist/types/thinking.d.ts +3 -1
- package/dist/types/tools/bash.d.ts +37 -11
- package/dist/types/tools/job.d.ts +1 -1
- package/dist/types/tools/steer-fold.d.ts +31 -0
- package/dist/types/utils/git.d.ts +28 -2
- package/dist/types/utils/mupdf-embedded.d.ts +2 -0
- package/dist/types/utils/mupdf-wasm-embedded.d.ts +2 -0
- package/dist/types/utils/mupdf.d.ts +4 -0
- package/dist/types/utils/session-title-generation.d.ts +6 -0
- package/dist/types/utils/title-generator.d.ts +11 -2
- package/dist/types/web/scrapers/types.d.ts +3 -0
- package/package.json +18 -10
- package/scripts/build-binary.ts +9 -3
- package/scripts/compile-args.ts +0 -9
- package/scripts/embed-mupdf.ts +52 -0
- package/scripts/generate-sdk-operation-inventory.ts +31 -1
- package/scripts/vendor-markit.ts +196 -0
- package/src/async/job-manager.ts +60 -9
- package/src/cli/daemon-cli.ts +53 -18
- package/src/cli/github-release.ts +87 -5
- package/src/cli/mcp-cli.ts +38 -4
- package/src/cli/public-command-entry.ts +450 -0
- package/src/cli/public-command-errors.ts +581 -0
- package/src/cli/public-command-evidence.ts +717 -0
- package/src/cli/public-command-help.ts +360 -0
- package/src/cli/public-command-registry.ts +535 -0
- package/src/cli/session-picker.ts +2 -1
- package/src/cli/setup-cli.ts +9 -1
- package/src/cli/skills-cli.ts +46 -2
- package/src/cli.ts +61 -1
- package/src/commands/daemon.ts +65 -69
- package/src/commands/sdk.ts +232 -100
- package/src/commands/setup.ts +2 -0
- package/src/commands/skills.ts +11 -0
- package/src/config/autorouting-tier-map.ts +16 -0
- package/src/config/file-lock.ts +199 -68
- package/src/config/model-profile-activation.ts +406 -53
- package/src/config/model-registry.ts +204 -25
- package/src/config/settings-schema.ts +26 -2
- package/src/coordinator-mcp/policy.ts +10 -5
- package/src/coordinator-mcp/question-gate-codec.ts +17 -0
- package/src/coordinator-mcp/question-state.ts +175 -8
- package/src/coordinator-mcp/server.ts +528 -87
- package/src/coordinator-mcp/session-reaper.ts +6 -4
- package/src/crash/record-loader.ts +6 -2
- package/src/daemon/operator-contract.ts +26 -12
- package/src/debug/report-bundle.ts +114 -24
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +1 -1
- package/src/eval/js/context-manager.ts +8 -8
- package/src/eval/js/worker-core.ts +9 -4
- package/src/eval/js/worker-protocol.ts +2 -0
- package/src/extensibility/extensions/runner.ts +52 -4
- package/src/extensibility/extensions/types.ts +10 -0
- package/src/extensibility/gjc-plugins/registry.ts +196 -37
- package/src/extensibility/runtime-skill-discovery.ts +61 -3
- package/src/extensibility/shared-events.ts +3 -1
- package/src/gjc-runtime/managed-owner-admission.ts +67 -50
- package/src/gjc-runtime/session-state-lock.ts +165 -24
- package/src/gjc-runtime/ultragoal-succession.ts +31 -3
- package/src/internal-urls/docs-index.generated.ts +21 -19
- package/src/internal-urls/embedded-protocol.ts +83 -0
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/parse.ts +21 -1
- package/src/internal-urls/router.ts +4 -2
- package/src/main.ts +123 -55
- package/src/modes/acp/acp-agent.ts +593 -47
- package/src/modes/acp/acp-event-mapper.ts +9 -0
- package/src/modes/acp/startup-provenance.ts +59 -0
- package/src/modes/components/custom-provider-wizard.ts +308 -7
- package/src/modes/components/model-selector.ts +31 -15
- package/src/modes/components/oauth-selector.ts +9 -0
- package/src/modes/components/session-selector.ts +47 -4
- package/src/modes/components/status-line/segments.ts +6 -1
- package/src/modes/components/thinking-selector.ts +7 -3
- package/src/modes/components/user-message-selector.ts +57 -15
- package/src/modes/controllers/command-controller.ts +58 -32
- package/src/modes/controllers/extension-ui-controller.ts +33 -7
- package/src/modes/controllers/input-controller.ts +4 -0
- package/src/modes/controllers/selector-controller.ts +177 -18
- package/src/modes/interactive-mode.ts +21 -7
- package/src/modes/runtime-init.ts +1 -0
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +124 -7
- package/src/modes/shared/agent-wire/workflow-gate-types.ts +16 -2
- package/src/modes/types.ts +2 -2
- package/src/prompts/agent-fragments/browser-aside.md +1 -0
- package/src/prompts/system/title-system.md +1 -1
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/job.md +1 -1
- package/src/prompts/tools/read.md +2 -0
- package/src/runtime/network-prewarm-service.test.ts +36 -1
- package/src/runtime/network-prewarm-service.ts +28 -3
- package/src/runtime/process-lifecycle.ts +22 -11
- package/src/runtime-mcp/config.ts +16 -1
- package/src/runtime-mcp/manager.ts +689 -55
- package/src/runtime-mcp/pool.test.ts +31 -0
- package/src/runtime-mcp/pool.ts +304 -28
- package/src/runtime-mcp/redaction.ts +42 -0
- package/src/runtime-mcp/startup-policy.ts +7 -0
- package/src/runtime-mcp/tool-bridge.ts +71 -0
- package/src/runtime-mcp/transports/http.ts +108 -25
- package/src/sdk/acp/adapter.ts +90 -9
- package/src/sdk/acp/final-text.ts +19 -2
- package/src/sdk/broker/broker.ts +378 -52
- package/src/sdk/broker/ensure.ts +97 -19
- package/src/sdk/broker/identity.ts +9 -1
- package/src/sdk/broker/lifecycle-ledger.ts +95 -31
- package/src/sdk/broker/lifecycle.ts +690 -141
- package/src/sdk/broker/runtime.ts +1 -1
- package/src/sdk/broker/session-index.ts +97 -4
- package/src/sdk/broker/spawn-authority.ts +35 -7
- package/src/sdk/broker/stderr-drainer.ts +59 -0
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/chat-daemon-runtime.ts +1 -0
- package/src/sdk/bus/index.ts +721 -84
- package/src/sdk/bus/telegram-daemon-cli.ts +31 -2
- package/src/sdk/bus/telegram-daemon-contract.ts +3 -1
- package/src/sdk/bus/telegram-daemon.ts +10 -3
- package/src/sdk/cli/master-cli.ts +47 -36
- package/src/sdk/cli/rows.ts +30 -7
- package/src/sdk/cli/session-cli.ts +687 -184
- package/src/sdk/client/client.ts +18 -0
- package/src/sdk/guides/catalog.ts +2 -2
- package/src/sdk/guides/cli.ts +20 -62
- package/src/sdk/guides/verify.ts +14 -0
- package/src/sdk/host/host.ts +49 -5
- package/src/sdk/host/session-runtime.test.ts +636 -9
- package/src/sdk/host/session-runtime.ts +499 -118
- package/src/sdk/host/types.ts +12 -1
- package/src/sdk/host/websocket-transport.lifecycle.test.ts +84 -0
- package/src/sdk/host/websocket-transport.ts +40 -6
- package/src/sdk/index.ts +11 -0
- package/src/sdk/prompt-deadline-flush.ts +334 -0
- package/src/sdk/prompt-deadline-manager.ts +136 -4
- package/src/sdk/prompt-failure.ts +43 -1
- package/src/sdk/prompt-status.ts +8 -0
- package/src/sdk/prompt-tool-boundary.ts +121 -0
- package/src/sdk/protocol/operation-inventory.generated.json +106 -0
- package/src/sdk/router/replay-retention-gap-cache.ts +27 -0
- package/src/sdk/router/session-router.ts +31 -4
- package/src/sdk/session.ts +194 -16
- package/src/sdk/startup-capability.ts +1 -1
- package/src/sdk/transport/relay.ts +71 -6
- package/src/sdk/transport/serve-cli.ts +494 -49
- package/src/sdk/transport/socket.ts +12 -11
- package/src/sdk/transport/stdio.ts +7 -3
- package/src/session/agent-session.ts +2437 -400
- package/src/session/fallback-chain-controller.ts +6 -7
- package/src/session/fold-coordinator.ts +24 -5
- package/src/session/internal/managed-session-scope.ts +58 -18
- package/src/session/internal/managed-session-storage.ts +304 -11
- package/src/session/session-manager.ts +382 -44
- package/src/session/session-work-lease.ts +34 -0
- package/src/session-import/codex.ts +12 -3
- package/src/setup/model-onboarding-guidance.ts +1 -1
- package/src/setup/provider-onboarding.ts +397 -24
- package/src/slash-commands/builtin-registry.ts +258 -14
- package/src/task/index.ts +14 -2
- package/src/thinking.ts +21 -2
- package/src/tools/bash.ts +98 -78
- package/src/tools/fetch.ts +119 -20
- package/src/tools/job.ts +151 -25
- package/src/tools/output-meta.ts +15 -2
- package/src/tools/path-utils.ts +27 -3
- package/src/tools/read.ts +3 -3
- package/src/tools/steer-fold.ts +107 -0
- package/src/tools/tool-catalog.generated.ts +29 -2
- package/src/tools/tool-errors.ts +4 -0
- package/src/utils/git.ts +53 -3
- package/src/utils/markit.ts +55 -41
- package/src/utils/mupdf-assets.d.ts +4 -0
- package/src/utils/mupdf-embedded.ts +4 -0
- package/src/utils/mupdf-wasm-embedded.ts +3 -0
- package/src/utils/mupdf-wasm.ts +24 -2
- package/src/utils/mupdf.ts +129 -0
- package/src/utils/session-title-generation.ts +29 -0
- package/src/utils/title-generator.ts +46 -2
- package/src/web/scrapers/types.ts +24 -3
- package/vendor/markit-ai/LICENSE +21 -0
- package/vendor/markit-ai/MANIFEST.json +412 -0
- package/vendor/markit-ai/dist/commands/config.d.ts +4 -0
- package/vendor/markit-ai/dist/commands/config.js +139 -0
- package/vendor/markit-ai/dist/commands/convert.d.ts +6 -0
- package/vendor/markit-ai/dist/commands/convert.js +113 -0
- package/vendor/markit-ai/dist/commands/formats.d.ts +2 -0
- package/vendor/markit-ai/dist/commands/formats.js +92 -0
- package/vendor/markit-ai/dist/commands/init.d.ts +2 -0
- package/vendor/markit-ai/dist/commands/init.js +29 -0
- package/vendor/markit-ai/dist/commands/onboard.d.ts +2 -0
- package/vendor/markit-ai/dist/commands/onboard.js +61 -0
- package/vendor/markit-ai/dist/commands/plugin.d.ts +4 -0
- package/vendor/markit-ai/dist/commands/plugin.js +58 -0
- package/vendor/markit-ai/dist/config.d.ts +26 -0
- package/vendor/markit-ai/dist/config.js +42 -0
- package/vendor/markit-ai/dist/converters/audio.d.ts +7 -0
- package/vendor/markit-ai/dist/converters/audio.js +104 -0
- package/vendor/markit-ai/dist/converters/csv.d.ts +7 -0
- package/vendor/markit-ai/dist/converters/csv.js +83 -0
- package/vendor/markit-ai/dist/converters/docx.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/docx.js +57 -0
- package/vendor/markit-ai/dist/converters/epub.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/epub.js +128 -0
- package/vendor/markit-ai/dist/converters/github.d.ts +18 -0
- package/vendor/markit-ai/dist/converters/github.js +148 -0
- package/vendor/markit-ai/dist/converters/html.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/html.js +30 -0
- package/vendor/markit-ai/dist/converters/image.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/image.js +124 -0
- package/vendor/markit-ai/dist/converters/ipynb.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/ipynb.js +75 -0
- package/vendor/markit-ai/dist/converters/iwork.d.ts +20 -0
- package/vendor/markit-ai/dist/converters/iwork.js +391 -0
- package/vendor/markit-ai/dist/converters/json.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/json.js +21 -0
- package/vendor/markit-ai/dist/converters/pdf/columns.d.ts +35 -0
- package/vendor/markit-ai/dist/converters/pdf/columns.js +93 -0
- package/vendor/markit-ai/dist/converters/pdf/extract.d.ts +19 -0
- package/vendor/markit-ai/dist/converters/pdf/extract.js +514 -0
- package/vendor/markit-ai/dist/converters/pdf/grid.d.ts +25 -0
- package/vendor/markit-ai/dist/converters/pdf/grid.js +795 -0
- package/vendor/markit-ai/dist/converters/pdf/headers.d.ts +24 -0
- package/vendor/markit-ai/dist/converters/pdf/headers.js +108 -0
- package/vendor/markit-ai/dist/converters/pdf/index.d.ts +19 -0
- package/vendor/markit-ai/dist/converters/pdf/index.js +136 -0
- package/vendor/markit-ai/dist/converters/pdf/mupdf-loader.js +9 -0
- package/vendor/markit-ai/dist/converters/pdf/render.d.ts +24 -0
- package/vendor/markit-ai/dist/converters/pdf/render.js +513 -0
- package/vendor/markit-ai/dist/converters/pdf/types.d.ts +75 -0
- package/vendor/markit-ai/dist/converters/pdf/types.js +1 -0
- package/vendor/markit-ai/dist/converters/plain-text.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/plain-text.js +87 -0
- package/vendor/markit-ai/dist/converters/pptx.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/pptx.js +289 -0
- package/vendor/markit-ai/dist/converters/rss.d.ts +11 -0
- package/vendor/markit-ai/dist/converters/rss.js +138 -0
- package/vendor/markit-ai/dist/converters/wikipedia.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/wikipedia.js +33 -0
- package/vendor/markit-ai/dist/converters/xlsx.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/xlsx.js +147 -0
- package/vendor/markit-ai/dist/converters/xml.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/xml.js +18 -0
- package/vendor/markit-ai/dist/converters/yaml.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/yaml.js +17 -0
- package/vendor/markit-ai/dist/converters/zip.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/zip.js +57 -0
- package/vendor/markit-ai/dist/index.d.ts +30 -0
- package/vendor/markit-ai/dist/index.js +26 -0
- package/vendor/markit-ai/dist/main.d.ts +2 -0
- package/vendor/markit-ai/dist/main.js +191 -0
- package/vendor/markit-ai/dist/markit.d.ts +45 -0
- package/vendor/markit-ai/dist/markit.js +267 -0
- package/vendor/markit-ai/dist/plugins/api.d.ts +7 -0
- package/vendor/markit-ai/dist/plugins/api.js +42 -0
- package/vendor/markit-ai/dist/plugins/index.d.ts +4 -0
- package/vendor/markit-ai/dist/plugins/index.js +3 -0
- package/vendor/markit-ai/dist/plugins/installer.d.ts +25 -0
- package/vendor/markit-ai/dist/plugins/installer.js +176 -0
- package/vendor/markit-ai/dist/plugins/loader.d.ts +6 -0
- package/vendor/markit-ai/dist/plugins/loader.js +61 -0
- package/vendor/markit-ai/dist/plugins/types.d.ts +25 -0
- package/vendor/markit-ai/dist/plugins/types.js +1 -0
- package/vendor/markit-ai/dist/providers/anthropic.d.ts +2 -0
- package/vendor/markit-ai/dist/providers/anthropic.js +47 -0
- package/vendor/markit-ai/dist/providers/index.d.ts +21 -0
- package/vendor/markit-ai/dist/providers/index.js +56 -0
- package/vendor/markit-ai/dist/providers/openai.d.ts +2 -0
- package/vendor/markit-ai/dist/providers/openai.js +76 -0
- package/vendor/markit-ai/dist/providers/types.d.ts +26 -0
- package/vendor/markit-ai/dist/providers/types.js +1 -0
- package/vendor/markit-ai/dist/types.d.ts +36 -0
- package/vendor/markit-ai/dist/types.js +1 -0
- package/vendor/markit-ai/dist/utils/exit-codes.d.ts +4 -0
- package/vendor/markit-ai/dist/utils/exit-codes.js +4 -0
- package/vendor/markit-ai/dist/utils/output.d.ts +22 -0
- package/vendor/markit-ai/dist/utils/output.js +31 -0
- package/vendor/markit-ai/dist/utils/turndown.d.ts +8 -0
- package/vendor/markit-ai/dist/utils/turndown.js +70 -0
- package/vendor/markit-ai/package.json +74 -0
- package/vendor/markit-ai.patch +49 -0
|
@@ -758,6 +758,37 @@ describe("MCPConnectionPool", () => {
|
|
|
758
758
|
await pool.shutdown();
|
|
759
759
|
});
|
|
760
760
|
|
|
761
|
+
test("fences a pending acquisition when a prepared replacement publishes first", async () => {
|
|
762
|
+
const openStarted = Promise.withResolvers<void>();
|
|
763
|
+
const allowOpen = Promise.withResolvers<MCPServerConnection>();
|
|
764
|
+
let opens = 0;
|
|
765
|
+
const replacementTransport = new FakeTransport();
|
|
766
|
+
const pool = new MCPConnectionPool({
|
|
767
|
+
connect: async (name, config) => {
|
|
768
|
+
opens += 1;
|
|
769
|
+
if (opens === 1) {
|
|
770
|
+
openStarted.resolve();
|
|
771
|
+
return allowOpen.promise;
|
|
772
|
+
}
|
|
773
|
+
return connection(name, config, replacementTransport);
|
|
774
|
+
},
|
|
775
|
+
});
|
|
776
|
+
const configValue = config();
|
|
777
|
+
const pending = pool.acquire("server", configValue, { sessionId: "replacement-fence" });
|
|
778
|
+
await openStarted.promise;
|
|
779
|
+
|
|
780
|
+
const replacement = await pool.prepareReplacement("server", configValue, {
|
|
781
|
+
sessionId: "replacement-fence",
|
|
782
|
+
});
|
|
783
|
+
replacement.commit();
|
|
784
|
+
allowOpen.resolve(connection("server", configValue, new FakeTransport()));
|
|
785
|
+
|
|
786
|
+
await expect(pending).rejects.toBeInstanceOf(MCPPoolAcquireAbortError);
|
|
787
|
+
expect(pool.isCurrentLease(replacement.lease)).toBe(true);
|
|
788
|
+
await replacement.lease.release();
|
|
789
|
+
await pool.shutdown();
|
|
790
|
+
});
|
|
791
|
+
|
|
761
792
|
test("onEvent rejects after pool shutdown invalidates the lease", async () => {
|
|
762
793
|
const transport = new FakeTransport();
|
|
763
794
|
const pool = new MCPConnectionPool({ connect: async (name, cfg) => connection(name, cfg, transport) });
|
package/src/runtime-mcp/pool.ts
CHANGED
|
@@ -208,6 +208,7 @@ type RetiredAcquisitionCleanup = {
|
|
|
208
208
|
error: MCPPoolAcquireAbortError;
|
|
209
209
|
failure?: MCPConnectionCleanupFailure;
|
|
210
210
|
retry?: Promise<void>;
|
|
211
|
+
entry?: PoolEntry;
|
|
211
212
|
};
|
|
212
213
|
|
|
213
214
|
function errorMessage(error: unknown): string {
|
|
@@ -245,6 +246,14 @@ export interface MCPPoolLease {
|
|
|
245
246
|
release(): Promise<void>;
|
|
246
247
|
}
|
|
247
248
|
|
|
249
|
+
export interface MCPPreparedReplacement {
|
|
250
|
+
readonly lease: MCPPoolLease;
|
|
251
|
+
canCommit(): boolean;
|
|
252
|
+
publish(): void;
|
|
253
|
+
commit(): void;
|
|
254
|
+
abort(): Promise<void>;
|
|
255
|
+
}
|
|
256
|
+
|
|
248
257
|
class MCPPoolLeaseImpl implements MCPPoolLease {
|
|
249
258
|
readonly generation: number;
|
|
250
259
|
readonly key: string;
|
|
@@ -407,6 +416,8 @@ export class MCPConnectionPool {
|
|
|
407
416
|
readonly #pending = new Map<string, PendingEntry>();
|
|
408
417
|
readonly #allLeases = new Set<MCPPoolLeaseImpl>();
|
|
409
418
|
readonly #retiredEntries = new Set<PoolEntry>();
|
|
419
|
+
readonly #preparedEntries = new Set<PoolEntry>();
|
|
420
|
+
readonly #pendingPreparedReplacements = new Set<Promise<void>>();
|
|
410
421
|
readonly #retiredAcquisitionCleanups = new Map<string, RetiredAcquisitionCleanup>();
|
|
411
422
|
readonly #restartOwners = new Set<string>();
|
|
412
423
|
readonly #restartWaiters = new Map<string, { promise: Promise<boolean>; resolve: (value: boolean) => void }>();
|
|
@@ -480,26 +491,42 @@ export class MCPConnectionPool {
|
|
|
480
491
|
this.#restartWaiters.delete(key);
|
|
481
492
|
}
|
|
482
493
|
|
|
494
|
+
private retiredCleanupId(key: string, generation: number): string {
|
|
495
|
+
return JSON.stringify([key, generation]);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
private getRetiredAcquisitionCleanup(key: string, generation: number): RetiredAcquisitionCleanup | undefined {
|
|
499
|
+
return this.#retiredAcquisitionCleanups.get(this.retiredCleanupId(key, generation));
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
private getRetiredAcquisitionCleanupForKey(key: string): RetiredAcquisitionCleanup | undefined {
|
|
503
|
+
for (const cleanup of this.#retiredAcquisitionCleanups.values()) {
|
|
504
|
+
if (cleanup.key === key) return cleanup;
|
|
505
|
+
}
|
|
506
|
+
return undefined;
|
|
507
|
+
}
|
|
508
|
+
|
|
483
509
|
private retainCancelledAcquireCleanup(
|
|
484
510
|
key: string,
|
|
485
511
|
name: string,
|
|
486
512
|
pending: PendingEntry,
|
|
487
513
|
cause: unknown,
|
|
488
514
|
): RetiredAcquisitionCleanup {
|
|
489
|
-
const current = this.#retiredAcquisitionCleanups.get(key);
|
|
490
|
-
if (current) return current;
|
|
491
515
|
const completion = pending.settlement;
|
|
492
516
|
const generation = pending.entry?.generation;
|
|
493
517
|
if (!completion || generation === undefined) {
|
|
494
518
|
throw new Error(`MCP cancelled acquisition cleanup is missing its flight identity: ${key}`);
|
|
495
519
|
}
|
|
520
|
+
const current = this.getRetiredAcquisitionCleanup(key, generation);
|
|
521
|
+
if (current) return current;
|
|
496
522
|
const error = new MCPPoolAcquireAbortError(name, key, cause, completion, generation);
|
|
497
523
|
const owner: RetiredAcquisitionCleanup = { key, serverName: name, generation, completion, error };
|
|
498
|
-
this
|
|
524
|
+
const ownerId = this.retiredCleanupId(key, generation);
|
|
525
|
+
this.#retiredAcquisitionCleanups.set(ownerId, owner);
|
|
499
526
|
void completion.then(
|
|
500
527
|
() => {
|
|
501
|
-
if (this.#retiredAcquisitionCleanups.get(
|
|
502
|
-
this.#retiredAcquisitionCleanups.delete(
|
|
528
|
+
if (this.#retiredAcquisitionCleanups.get(ownerId) === owner && !owner.retry) {
|
|
529
|
+
this.#retiredAcquisitionCleanups.delete(ownerId);
|
|
503
530
|
}
|
|
504
531
|
},
|
|
505
532
|
error => {
|
|
@@ -507,14 +534,42 @@ export class MCPConnectionPool {
|
|
|
507
534
|
owner.failure = error;
|
|
508
535
|
return;
|
|
509
536
|
}
|
|
510
|
-
if (this.#retiredAcquisitionCleanups.get(
|
|
511
|
-
this.#retiredAcquisitionCleanups.delete(
|
|
537
|
+
if (this.#retiredAcquisitionCleanups.get(ownerId) === owner && !owner.retry) {
|
|
538
|
+
this.#retiredAcquisitionCleanups.delete(ownerId);
|
|
512
539
|
}
|
|
513
540
|
},
|
|
514
541
|
);
|
|
515
542
|
return owner;
|
|
516
543
|
}
|
|
517
544
|
|
|
545
|
+
private retainPreparedCleanup(
|
|
546
|
+
key: string,
|
|
547
|
+
name: string,
|
|
548
|
+
generation: number,
|
|
549
|
+
cause: unknown,
|
|
550
|
+
transport: MCPTransport,
|
|
551
|
+
entry?: PoolEntry,
|
|
552
|
+
): RetiredAcquisitionCleanup {
|
|
553
|
+
const current = this.getRetiredAcquisitionCleanup(key, generation);
|
|
554
|
+
if (current) return current;
|
|
555
|
+
const failure =
|
|
556
|
+
cause instanceof MCPConnectionCleanupFailure ? cause : new MCPConnectionCleanupFailure(cause, transport);
|
|
557
|
+
const completion = Promise.reject<void>(failure);
|
|
558
|
+
void completion.catch(() => {});
|
|
559
|
+
const error = new MCPPoolAcquireAbortError(name, key, failure, completion, generation);
|
|
560
|
+
const owner: RetiredAcquisitionCleanup = {
|
|
561
|
+
key,
|
|
562
|
+
serverName: name,
|
|
563
|
+
generation,
|
|
564
|
+
completion,
|
|
565
|
+
error,
|
|
566
|
+
failure,
|
|
567
|
+
entry,
|
|
568
|
+
};
|
|
569
|
+
this.#retiredAcquisitionCleanups.set(this.retiredCleanupId(key, generation), owner);
|
|
570
|
+
return owner;
|
|
571
|
+
}
|
|
572
|
+
|
|
518
573
|
private notifyPendingAcquireCleanup(
|
|
519
574
|
listener: MCPPoolAcquireOptions["onCleanupPending"],
|
|
520
575
|
owner: RetiredAcquisitionCleanup,
|
|
@@ -532,14 +587,17 @@ export class MCPConnectionPool {
|
|
|
532
587
|
|
|
533
588
|
/** @internal Whether this pool still owns the notified abandoned-acquire flight. */
|
|
534
589
|
hasPendingAcquireCleanup(error: MCPPoolAcquireAbortError): boolean {
|
|
535
|
-
|
|
536
|
-
|
|
590
|
+
return (
|
|
591
|
+
error.cleanupGeneration !== undefined &&
|
|
592
|
+
this.getRetiredAcquisitionCleanup(error.poolKey, error.cleanupGeneration) !== undefined
|
|
593
|
+
);
|
|
537
594
|
}
|
|
538
595
|
|
|
539
596
|
/** @internal Current retained failure for one notified abandoned-acquire generation. */
|
|
540
597
|
getPendingAcquireCleanupFailure(error: MCPPoolAcquireAbortError): MCPConnectionCleanupFailure | undefined {
|
|
541
|
-
|
|
542
|
-
|
|
598
|
+
return error.cleanupGeneration === undefined
|
|
599
|
+
? undefined
|
|
600
|
+
: this.getRetiredAcquisitionCleanup(error.poolKey, error.cleanupGeneration)?.failure;
|
|
543
601
|
}
|
|
544
602
|
|
|
545
603
|
/** @internal Prevent manager-level duplication of the pool's retained cleanup owner. */
|
|
@@ -566,9 +624,10 @@ export class MCPConnectionPool {
|
|
|
566
624
|
|
|
567
625
|
/** @internal Join and retry one generation of abandoned acquisition cleanup. */
|
|
568
626
|
async closePendingAcquireCleanup(key: string, generation: number): Promise<void> {
|
|
569
|
-
const owner = this
|
|
570
|
-
if (!owner
|
|
627
|
+
const owner = this.getRetiredAcquisitionCleanup(key, generation);
|
|
628
|
+
if (!owner) return;
|
|
571
629
|
if (owner.retry) return owner.retry;
|
|
630
|
+
const ownerId = this.retiredCleanupId(key, generation);
|
|
572
631
|
let tracked!: Promise<void>;
|
|
573
632
|
tracked = (async () => {
|
|
574
633
|
let failure = owner.failure;
|
|
@@ -584,15 +643,21 @@ export class MCPConnectionPool {
|
|
|
584
643
|
try {
|
|
585
644
|
await failure.close();
|
|
586
645
|
} catch (error) {
|
|
587
|
-
if (this.#retiredAcquisitionCleanups.get(
|
|
646
|
+
if (this.#retiredAcquisitionCleanups.get(ownerId) === owner) {
|
|
588
647
|
owner.failure = error instanceof MCPConnectionCleanupFailure ? error : failure;
|
|
589
648
|
}
|
|
590
649
|
throw error;
|
|
591
650
|
}
|
|
592
651
|
}
|
|
593
|
-
if (
|
|
652
|
+
if (owner.entry) {
|
|
653
|
+
owner.entry.closePromise = undefined;
|
|
654
|
+
await this.closeEntry(owner.entry);
|
|
655
|
+
this.#preparedEntries.delete(owner.entry);
|
|
656
|
+
}
|
|
657
|
+
if (this.#retiredAcquisitionCleanups.get(ownerId) === owner) this.#retiredAcquisitionCleanups.delete(ownerId);
|
|
594
658
|
})().finally(() => {
|
|
595
|
-
if (this.#retiredAcquisitionCleanups.get(
|
|
659
|
+
if (this.#retiredAcquisitionCleanups.get(ownerId) === owner && owner.retry === tracked)
|
|
660
|
+
owner.retry = undefined;
|
|
596
661
|
});
|
|
597
662
|
owner.retry = tracked;
|
|
598
663
|
return tracked;
|
|
@@ -610,7 +675,7 @@ export class MCPConnectionPool {
|
|
|
610
675
|
);
|
|
611
676
|
}
|
|
612
677
|
for (;;) {
|
|
613
|
-
const cleanup = this
|
|
678
|
+
const cleanup = this.getRetiredAcquisitionCleanupForKey(key);
|
|
614
679
|
if (!cleanup) break;
|
|
615
680
|
this.notifyPendingAcquireCleanup(options.onCleanupPending, cleanup);
|
|
616
681
|
await this.closePendingAcquireCleanup(cleanup.key, cleanup.generation);
|
|
@@ -658,6 +723,175 @@ export class MCPConnectionPool {
|
|
|
658
723
|
return lease;
|
|
659
724
|
}
|
|
660
725
|
|
|
726
|
+
/**
|
|
727
|
+
* Prepared MCP replacements fence and retain acquisition cleanup ownership
|
|
728
|
+
* The caller validates its catalog first, then commits the key swap
|
|
729
|
+
* synchronously or aborts and closes only the candidate.
|
|
730
|
+
*/
|
|
731
|
+
async prepareReplacement(
|
|
732
|
+
name: string,
|
|
733
|
+
config: MCPServerConfig,
|
|
734
|
+
options: MCPPoolAcquireOptions = {},
|
|
735
|
+
): Promise<MCPPreparedReplacement> {
|
|
736
|
+
if (this.#shuttingDown) throw new Error("MCP connection pool is shut down");
|
|
737
|
+
const key = computeMCPPoolKey(name, config, options);
|
|
738
|
+
if (options.signal?.aborted) {
|
|
739
|
+
throw new MCPPoolAcquireAbortError(
|
|
740
|
+
name,
|
|
741
|
+
key,
|
|
742
|
+
options.signal.reason ?? new Error(`MCP replacement preparation aborted: ${name}`),
|
|
743
|
+
);
|
|
744
|
+
}
|
|
745
|
+
for (;;) {
|
|
746
|
+
const cleanup = this.getRetiredAcquisitionCleanupForKey(key);
|
|
747
|
+
if (!cleanup) break;
|
|
748
|
+
this.notifyPendingAcquireCleanup(options.onCleanupPending, cleanup);
|
|
749
|
+
await this.closePendingAcquireCleanup(cleanup.key, cleanup.generation);
|
|
750
|
+
}
|
|
751
|
+
if (options.signal?.aborted) {
|
|
752
|
+
throw new MCPPoolAcquireAbortError(
|
|
753
|
+
name,
|
|
754
|
+
key,
|
|
755
|
+
options.signal.reason ?? new Error(`MCP replacement preparation aborted: ${name}`),
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
const pending = this.#pending.get(key);
|
|
759
|
+
if (pending && !pending.cancelled && !pending.settled) {
|
|
760
|
+
this.cancelPendingEntry(
|
|
761
|
+
key,
|
|
762
|
+
pending,
|
|
763
|
+
new MCPPoolAcquireAbortError(
|
|
764
|
+
name,
|
|
765
|
+
key,
|
|
766
|
+
new Error(`MCP connection acquisition superseded by replacement: ${name}`),
|
|
767
|
+
),
|
|
768
|
+
);
|
|
769
|
+
}
|
|
770
|
+
const identity = buildMCPPoolKeyIdentity(name, config, options);
|
|
771
|
+
const generation = (this.#entryGenerations.get(key) ?? 0) + 1;
|
|
772
|
+
this.#entryGenerations.set(key, generation);
|
|
773
|
+
const openSignal = options.signal
|
|
774
|
+
? AbortSignal.any([options.signal, this.#shutdownController.signal])
|
|
775
|
+
: this.#shutdownController.signal;
|
|
776
|
+
const preparedFlight = Promise.withResolvers<void>();
|
|
777
|
+
this.#pendingPreparedReplacements.add(preparedFlight.promise);
|
|
778
|
+
let connection: MCPServerConnection;
|
|
779
|
+
try {
|
|
780
|
+
connection = await this.#connect(name, config, {
|
|
781
|
+
signal: openSignal,
|
|
782
|
+
advertiseRoots: options.advertiseRoots,
|
|
783
|
+
onNotification: options.onNotification,
|
|
784
|
+
onRequest: options.onRequest,
|
|
785
|
+
});
|
|
786
|
+
if (this.#shuttingDown) {
|
|
787
|
+
try {
|
|
788
|
+
await connection.transport.close();
|
|
789
|
+
} catch (closeError) {
|
|
790
|
+
const cleanup = this.retainPreparedCleanup(
|
|
791
|
+
key,
|
|
792
|
+
name,
|
|
793
|
+
generation,
|
|
794
|
+
new AggregateError(
|
|
795
|
+
[new Error(`MCP replacement connected after pool shutdown: ${name}`), closeError],
|
|
796
|
+
`MCP late replacement cleanup failed: ${name}`,
|
|
797
|
+
),
|
|
798
|
+
connection.transport,
|
|
799
|
+
);
|
|
800
|
+
this.notifyPendingAcquireCleanup(options.onCleanupPending, cleanup);
|
|
801
|
+
logger.error("MCP late replacement transport close failed", {
|
|
802
|
+
path: `mcp:${name}`,
|
|
803
|
+
poolKey: key,
|
|
804
|
+
error: closeError,
|
|
805
|
+
});
|
|
806
|
+
throw cleanup.failure!;
|
|
807
|
+
}
|
|
808
|
+
throw new Error(`MCP connection pool is shut down`);
|
|
809
|
+
}
|
|
810
|
+
} catch (error) {
|
|
811
|
+
preparedFlight.resolve();
|
|
812
|
+
this.#pendingPreparedReplacements.delete(preparedFlight.promise);
|
|
813
|
+
throw error;
|
|
814
|
+
}
|
|
815
|
+
const entry: PoolEntry = {
|
|
816
|
+
generation,
|
|
817
|
+
key,
|
|
818
|
+
name,
|
|
819
|
+
config,
|
|
820
|
+
identity,
|
|
821
|
+
connection,
|
|
822
|
+
refCount: 1,
|
|
823
|
+
leases: new Set(),
|
|
824
|
+
rootsByLease: new Map(),
|
|
825
|
+
resourceSubscriptionCounts: new Map(),
|
|
826
|
+
resourceSubscriptionUpdate: Promise.resolve(),
|
|
827
|
+
state: "connected",
|
|
828
|
+
events: [],
|
|
829
|
+
};
|
|
830
|
+
try {
|
|
831
|
+
this.installTransportHandlers(entry, options);
|
|
832
|
+
this.#preparedEntries.add(entry);
|
|
833
|
+
} finally {
|
|
834
|
+
preparedFlight.resolve();
|
|
835
|
+
this.#pendingPreparedReplacements.delete(preparedFlight.promise);
|
|
836
|
+
}
|
|
837
|
+
const lease = new MCPPoolLeaseImpl(this, entry);
|
|
838
|
+
entry.leases.add(lease);
|
|
839
|
+
entry.rootsByLease.set(lease, []);
|
|
840
|
+
this.#allLeases.add(lease);
|
|
841
|
+
let settled = false;
|
|
842
|
+
const canCommit = (): boolean => entry.state === "connected" && entry.connection.transport.connected;
|
|
843
|
+
const publish = (): void => {
|
|
844
|
+
if (settled) throw new Error(`MCP prepared replacement already settled: ${name}`);
|
|
845
|
+
if (this.#shuttingDown || !canCommit()) {
|
|
846
|
+
throw new Error(`MCP prepared replacement closed before publish: ${name}`);
|
|
847
|
+
}
|
|
848
|
+
settled = true;
|
|
849
|
+
this.#preparedEntries.delete(entry);
|
|
850
|
+
const predecessor = this.#entries.get(key);
|
|
851
|
+
if (predecessor) this.retireEntry(predecessor);
|
|
852
|
+
this.#entries.set(key, entry);
|
|
853
|
+
this.record(entry, "connected");
|
|
854
|
+
};
|
|
855
|
+
return {
|
|
856
|
+
lease,
|
|
857
|
+
canCommit,
|
|
858
|
+
publish,
|
|
859
|
+
commit: () => {
|
|
860
|
+
if (!canCommit()) {
|
|
861
|
+
throw new Error(`MCP prepared replacement closed before commit: ${name}`);
|
|
862
|
+
}
|
|
863
|
+
publish();
|
|
864
|
+
},
|
|
865
|
+
abort: async () => {
|
|
866
|
+
if (settled) return;
|
|
867
|
+
lease.invalidate(new Error(`MCP prepared replacement aborted: ${name}`));
|
|
868
|
+
entry.leases.delete(lease);
|
|
869
|
+
entry.rootsByLease.delete(lease);
|
|
870
|
+
this.#allLeases.delete(lease);
|
|
871
|
+
entry.refCount = 0;
|
|
872
|
+
try {
|
|
873
|
+
await this.closeEntry(entry);
|
|
874
|
+
} catch (closeError) {
|
|
875
|
+
const cleanup = this.retainPreparedCleanup(
|
|
876
|
+
key,
|
|
877
|
+
name,
|
|
878
|
+
generation,
|
|
879
|
+
new AggregateError(
|
|
880
|
+
[new Error(`MCP prepared replacement aborted: ${name}`), closeError],
|
|
881
|
+
`MCP prepared replacement cleanup failed: ${name}`,
|
|
882
|
+
),
|
|
883
|
+
entry.connection.transport,
|
|
884
|
+
entry,
|
|
885
|
+
);
|
|
886
|
+
this.notifyPendingAcquireCleanup(options.onCleanupPending, cleanup);
|
|
887
|
+
throw cleanup.failure!;
|
|
888
|
+
}
|
|
889
|
+
settled = true;
|
|
890
|
+
this.#preparedEntries.delete(entry);
|
|
891
|
+
},
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
|
|
661
895
|
private waitForPendingEntry(
|
|
662
896
|
key: string,
|
|
663
897
|
name: string,
|
|
@@ -858,7 +1092,13 @@ export class MCPConnectionPool {
|
|
|
858
1092
|
onRequest: options.onRequest,
|
|
859
1093
|
});
|
|
860
1094
|
entry.connection = connection;
|
|
861
|
-
|
|
1095
|
+
const superseded = this.#entryGenerations.get(key) !== generation;
|
|
1096
|
+
if (pending.cancelled || this.#pending.get(key) !== pending || this.#shuttingDown || superseded) {
|
|
1097
|
+
if (superseded && !pending.cancelled) {
|
|
1098
|
+
pending.cancelled = true;
|
|
1099
|
+
pending.cancellationReason = new Error(`MCP connection acquisition superseded: ${name}`);
|
|
1100
|
+
pending.openAbortController.abort(pending.cancellationReason);
|
|
1101
|
+
}
|
|
862
1102
|
try {
|
|
863
1103
|
await connection.transport.close();
|
|
864
1104
|
} catch (closeError) {
|
|
@@ -1141,29 +1381,51 @@ export class MCPConnectionPool {
|
|
|
1141
1381
|
pending.waiters.clear();
|
|
1142
1382
|
if (this.#pending.get(key) === pending) this.#pending.delete(key);
|
|
1143
1383
|
}
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1384
|
+
await Promise.allSettled([...this.#pendingPreparedReplacements]);
|
|
1385
|
+
const retainedCleanups = [...this.#retiredAcquisitionCleanups.values()].filter(cleanup =>
|
|
1386
|
+
this.getPendingAcquireCleanupFailure(cleanup.error),
|
|
1387
|
+
);
|
|
1388
|
+
const retainedCleanupResults = await Promise.allSettled(
|
|
1389
|
+
retainedCleanups.map(cleanup => this.closePendingAcquireCleanup(cleanup.key, cleanup.generation)),
|
|
1390
|
+
);
|
|
1391
|
+
for (const [index, result] of retainedCleanupResults.entries()) {
|
|
1392
|
+
if (result.status === "rejected") {
|
|
1393
|
+
const cleanup = retainedCleanups[index];
|
|
1148
1394
|
logger.error("MCP pool shutdown pending acquire cleanup failed", {
|
|
1149
|
-
serverName: cleanup
|
|
1150
|
-
poolKey: cleanup
|
|
1151
|
-
error,
|
|
1152
|
-
})
|
|
1153
|
-
|
|
1395
|
+
serverName: cleanup?.serverName,
|
|
1396
|
+
poolKey: cleanup?.key,
|
|
1397
|
+
error: result.reason,
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1154
1400
|
}
|
|
1155
1401
|
for (const lease of this.#allLeases) lease.invalidate(reason);
|
|
1156
1402
|
this.#allLeases.clear();
|
|
1157
|
-
const entries = [...new Set([...this.#entries.values(), ...this.#retiredEntries])];
|
|
1403
|
+
const entries = [...new Set([...this.#entries.values(), ...this.#retiredEntries, ...this.#preparedEntries])];
|
|
1158
1404
|
for (const entry of entries) {
|
|
1159
1405
|
for (const lease of entry.leases) lease.invalidate(reason);
|
|
1160
1406
|
entry.leases.clear();
|
|
1161
1407
|
entry.rootsByLease.clear();
|
|
1162
1408
|
}
|
|
1163
1409
|
const closeResults = await Promise.allSettled(entries.map(entry => this.closeEntry(entry)));
|
|
1410
|
+
const failedEntryCleanups: RetiredAcquisitionCleanup[] = [];
|
|
1164
1411
|
for (const [index, result] of closeResults.entries()) {
|
|
1165
1412
|
if (result.status === "rejected") {
|
|
1166
1413
|
const entry = entries[index];
|
|
1414
|
+
if (entry) {
|
|
1415
|
+
failedEntryCleanups.push(
|
|
1416
|
+
this.retainPreparedCleanup(
|
|
1417
|
+
entry.key,
|
|
1418
|
+
entry.name,
|
|
1419
|
+
entry.generation,
|
|
1420
|
+
new AggregateError(
|
|
1421
|
+
[new Error(`MCP pool shutdown closing entry: ${entry.name}`), result.reason],
|
|
1422
|
+
`MCP pool shutdown cleanup failed: ${entry.name}`,
|
|
1423
|
+
),
|
|
1424
|
+
entry.connection.transport,
|
|
1425
|
+
entry,
|
|
1426
|
+
),
|
|
1427
|
+
);
|
|
1428
|
+
}
|
|
1167
1429
|
logger.error("MCP pool shutdown close failed", {
|
|
1168
1430
|
serverName: entry?.name,
|
|
1169
1431
|
poolKey: entry?.key,
|
|
@@ -1171,8 +1433,22 @@ export class MCPConnectionPool {
|
|
|
1171
1433
|
});
|
|
1172
1434
|
}
|
|
1173
1435
|
}
|
|
1436
|
+
const failedEntryCleanupResults = await Promise.allSettled(
|
|
1437
|
+
failedEntryCleanups.map(cleanup => this.closePendingAcquireCleanup(cleanup.key, cleanup.generation)),
|
|
1438
|
+
);
|
|
1439
|
+
for (const [index, result] of failedEntryCleanupResults.entries()) {
|
|
1440
|
+
if (result.status === "rejected") {
|
|
1441
|
+
const cleanup = failedEntryCleanups[index];
|
|
1442
|
+
logger.error("MCP pool shutdown retry cleanup failed", {
|
|
1443
|
+
serverName: cleanup?.serverName,
|
|
1444
|
+
poolKey: cleanup?.key,
|
|
1445
|
+
error: result.reason,
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1174
1449
|
this.#entries.clear();
|
|
1175
1450
|
this.#retiredEntries.clear();
|
|
1451
|
+
this.#preparedEntries.clear();
|
|
1176
1452
|
this.#restartOwners.clear();
|
|
1177
1453
|
for (const waiter of this.#restartWaiters.values()) waiter.resolve(false);
|
|
1178
1454
|
this.#restartWaiters.clear();
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { AgentSession } from "../session/agent-session";
|
|
2
|
+
|
|
1
3
|
const REDACTED = "<redacted>";
|
|
2
4
|
const SENSITIVE_KEY_PATTERN = /(?:token|secret|key|credential|password|authorization|auth|bearer|cookie|session)/i;
|
|
3
5
|
|
|
@@ -28,3 +30,43 @@ export function redactMCPDiagnosticValue(value: unknown): unknown {
|
|
|
28
30
|
]),
|
|
29
31
|
);
|
|
30
32
|
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Capability granted to a session that the root interactive entry point created
|
|
36
|
+
* with an explicit `--mcp-config` path. Holding it is the only way to read exact
|
|
37
|
+
* MCP status; it carries no manager, transport, or configuration reference.
|
|
38
|
+
*/
|
|
39
|
+
export interface ExactMcpControls {
|
|
40
|
+
readonly grantSource: "root-interactive-exact-config";
|
|
41
|
+
/**
|
|
42
|
+
* The exact config this session was started with. Status needs it because a
|
|
43
|
+
* tools-only manager deletes a server from its own bookkeeping when the
|
|
44
|
+
* connection fails, so the manager alone can never report a server that did
|
|
45
|
+
* not come up — the very case an operator runs `/mcp` to see.
|
|
46
|
+
*/
|
|
47
|
+
readonly configPath: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Exact MCP capability lives in a revocable export-blocked leaf WeakMap.
|
|
52
|
+
*
|
|
53
|
+
* The registry lives in this module because the file is a dependency-free leaf
|
|
54
|
+
* whose package subpath is blocked (`./runtime-mcp/*` is null in package.json
|
|
55
|
+
* exports) and which no barrel re-exports, so nothing outside this package can
|
|
56
|
+
* reach the map or mint a capability. Keep it that way: runtime imports here
|
|
57
|
+
* must stay at zero and the session type is referenced with `import type` only.
|
|
58
|
+
*/
|
|
59
|
+
const exactMcpControlsBySession = new WeakMap<AgentSession, ExactMcpControls>();
|
|
60
|
+
|
|
61
|
+
export function attachExactMcpControls(session: AgentSession, controls: ExactMcpControls): void {
|
|
62
|
+
exactMcpControlsBySession.set(session, controls);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function getExactMcpControls(session: AgentSession): ExactMcpControls | undefined {
|
|
66
|
+
return exactMcpControlsBySession.get(session);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Revoke controls when the AgentSession object adopts a new logical identity. */
|
|
70
|
+
export function revokeExactMcpControls(session: AgentSession): void {
|
|
71
|
+
exactMcpControlsBySession.delete(session);
|
|
72
|
+
}
|
|
@@ -2,6 +2,13 @@ import type { MCPServerConfig } from "./types";
|
|
|
2
2
|
|
|
3
3
|
export type AutoloadStatus = "autoload" | "autoload-off" | "disabled";
|
|
4
4
|
|
|
5
|
+
/** Ordinary standalone sessions stop blocking on MCP startup after this wait. */
|
|
6
|
+
export const DEFAULT_MCP_STARTUP_WAIT_MS = 250;
|
|
7
|
+
/** Grace added to the largest declared per-server startup window. */
|
|
8
|
+
export const MCP_STARTUP_WAIT_GRACE_MS = 500;
|
|
9
|
+
/** Ordinary startup never blocks longer than this batch ceiling. */
|
|
10
|
+
export const MAX_MCP_STARTUP_WAIT_MS = 1_750;
|
|
11
|
+
|
|
5
12
|
/** Pure startup policy shared by runtime-facing CLI inspection and doctor. */
|
|
6
13
|
export function computeAutoloadStatus(
|
|
7
14
|
name: string,
|