apex-code 0.0.1-alpha.1 → 0.0.1-alpha.11
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 +482 -0
- package/README.md +75 -680
- package/dist/cli/args.d.ts +21 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +119 -15
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/auth-command.d.ts.map +1 -1
- package/dist/cli/auth-command.js +3 -3
- package/dist/cli/auth-command.js.map +1 -1
- package/dist/cli/concurrent-session.d.ts +3 -0
- package/dist/cli/concurrent-session.d.ts.map +1 -0
- package/dist/cli/concurrent-session.js +13 -0
- package/dist/cli/concurrent-session.js.map +1 -0
- package/dist/cli/cost-command.d.ts +19 -0
- package/dist/cli/cost-command.d.ts.map +1 -0
- package/dist/cli/cost-command.js +107 -0
- package/dist/cli/cost-command.js.map +1 -0
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +2 -1
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/cli/startup-ui.d.ts +1 -1
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +1 -2
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +99 -16
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +5 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +58 -24
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +2 -0
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +28 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +140 -4
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +147 -9
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +440 -123
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +4 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +17 -14
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +18 -10
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/checkpoints/git-checkpoints.d.ts +33 -0
- package/dist/core/checkpoints/git-checkpoints.d.ts.map +1 -0
- package/dist/core/checkpoints/git-checkpoints.js +230 -0
- package/dist/core/checkpoints/git-checkpoints.js.map +1 -0
- package/dist/core/checkpoints/session-checkpoints.d.ts +23 -0
- package/dist/core/checkpoints/session-checkpoints.d.ts.map +1 -0
- package/dist/core/checkpoints/session-checkpoints.js +29 -0
- package/dist/core/checkpoints/session-checkpoints.js.map +1 -0
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +3 -0
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +4 -3
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +41 -32
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/context/deferred-schemas.d.ts +92 -0
- package/dist/core/context/deferred-schemas.d.ts.map +1 -0
- package/dist/core/context/deferred-schemas.js +74 -0
- package/dist/core/context/deferred-schemas.js.map +1 -0
- package/dist/core/context/eviction.d.ts +47 -0
- package/dist/core/context/eviction.d.ts.map +1 -0
- package/dist/core/context/eviction.js +83 -0
- package/dist/core/context/eviction.js.map +1 -0
- package/dist/core/context/pipeline.d.ts +90 -0
- package/dist/core/context/pipeline.d.ts.map +1 -0
- package/dist/core/context/pipeline.js +109 -0
- package/dist/core/context/pipeline.js.map +1 -0
- package/dist/core/credential-failover.d.ts +30 -0
- package/dist/core/credential-failover.d.ts.map +1 -0
- package/dist/core/credential-failover.js +46 -0
- package/dist/core/credential-failover.js.map +1 -0
- package/dist/core/credential-pool.d.ts +60 -0
- package/dist/core/credential-pool.d.ts.map +1 -0
- package/dist/core/credential-pool.js +84 -0
- package/dist/core/credential-pool.js.map +1 -0
- package/dist/core/defaults.d.ts +1 -0
- package/dist/core/defaults.d.ts.map +1 -1
- package/dist/core/defaults.js +9 -0
- package/dist/core/defaults.js.map +1 -1
- package/dist/core/delegation/agents.d.ts +15 -0
- package/dist/core/delegation/agents.d.ts.map +1 -0
- package/dist/core/delegation/agents.js +55 -0
- package/dist/core/delegation/agents.js.map +1 -0
- package/dist/core/delegation/ceiling.d.ts +29 -0
- package/dist/core/delegation/ceiling.d.ts.map +1 -0
- package/dist/core/delegation/ceiling.js +34 -0
- package/dist/core/delegation/ceiling.js.map +1 -0
- package/dist/core/delegation/runtime.d.ts +94 -0
- package/dist/core/delegation/runtime.d.ts.map +1 -0
- package/dist/core/delegation/runtime.js +117 -0
- package/dist/core/delegation/runtime.js.map +1 -0
- package/dist/core/durable-state/daemon.d.ts +37 -0
- package/dist/core/durable-state/daemon.d.ts.map +1 -0
- package/dist/core/durable-state/daemon.js +62 -0
- package/dist/core/durable-state/daemon.js.map +1 -0
- package/dist/core/durable-state/provenance.d.ts +7 -0
- package/dist/core/durable-state/provenance.d.ts.map +1 -0
- package/dist/core/durable-state/provenance.js +24 -0
- package/dist/core/durable-state/provenance.js.map +1 -0
- package/dist/core/durable-state/sqlite.d.ts +84 -0
- package/dist/core/durable-state/sqlite.d.ts.map +1 -0
- package/dist/core/durable-state/sqlite.js +355 -0
- package/dist/core/durable-state/sqlite.js.map +1 -0
- package/dist/core/environment.d.ts +12 -0
- package/dist/core/environment.d.ts.map +1 -0
- package/dist/core/environment.js +69 -0
- package/dist/core/environment.js.map +1 -0
- package/dist/core/evidence-policy.d.ts +17 -0
- package/dist/core/evidence-policy.d.ts.map +1 -0
- package/dist/core/evidence-policy.js +25 -0
- package/dist/core/evidence-policy.js.map +1 -0
- package/dist/core/evidence.d.ts +16 -0
- package/dist/core/evidence.d.ts.map +1 -0
- package/dist/core/evidence.js +51 -0
- package/dist/core/evidence.js.map +1 -0
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +5 -2
- package/dist/core/exec.js.map +1 -1
- package/dist/core/experimental.d.ts +4 -0
- package/dist/core/experimental.d.ts.map +1 -1
- package/dist/core/experimental.js +6 -1
- package/dist/core/experimental.js.map +1 -1
- package/dist/core/extensions/index.d.ts +2 -2
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +122 -49
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +44 -9
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +3 -0
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +1 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +1 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts +1 -2
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +2 -17
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/http-idle-timeout.d.ts +12 -0
- package/dist/core/http-idle-timeout.d.ts.map +1 -0
- package/dist/core/http-idle-timeout.js +27 -0
- package/dist/core/http-idle-timeout.js.map +1 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/keybindings.d.ts +38 -13
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +26 -5
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/lsp/client.d.ts +78 -0
- package/dist/core/lsp/client.d.ts.map +1 -0
- package/dist/core/lsp/client.js +494 -0
- package/dist/core/lsp/client.js.map +1 -0
- package/dist/core/lsp/diagnostics.d.ts +47 -0
- package/dist/core/lsp/diagnostics.d.ts.map +1 -0
- package/dist/core/lsp/diagnostics.js +224 -0
- package/dist/core/lsp/diagnostics.js.map +1 -0
- package/dist/core/lsp/pool.d.ts +48 -0
- package/dist/core/lsp/pool.d.ts.map +1 -0
- package/dist/core/lsp/pool.js +150 -0
- package/dist/core/lsp/pool.js.map +1 -0
- package/dist/core/lsp/registry.d.ts +49 -0
- package/dist/core/lsp/registry.d.ts.map +1 -0
- package/dist/core/lsp/registry.js +215 -0
- package/dist/core/lsp/registry.js.map +1 -0
- package/dist/core/lsp/status.d.ts +23 -0
- package/dist/core/lsp/status.d.ts.map +1 -0
- package/dist/core/lsp/status.js +35 -0
- package/dist/core/lsp/status.js.map +1 -0
- package/dist/core/lsp/sync.d.ts +13 -0
- package/dist/core/lsp/sync.d.ts.map +1 -0
- package/dist/core/lsp/sync.js +71 -0
- package/dist/core/lsp/sync.js.map +1 -0
- package/dist/core/mcp/config.d.ts +16 -0
- package/dist/core/mcp/config.d.ts.map +1 -0
- package/dist/core/mcp/config.js +152 -0
- package/dist/core/mcp/config.js.map +1 -0
- package/dist/core/mcp/connector.d.ts +10 -0
- package/dist/core/mcp/connector.d.ts.map +1 -0
- package/dist/core/mcp/connector.js +70 -0
- package/dist/core/mcp/connector.js.map +1 -0
- package/dist/core/mcp/contract.d.ts +19 -0
- package/dist/core/mcp/contract.d.ts.map +1 -0
- package/dist/core/mcp/contract.js +89 -0
- package/dist/core/mcp/contract.js.map +1 -0
- package/dist/core/mcp/mcp-tool.d.ts +32 -0
- package/dist/core/mcp/mcp-tool.d.ts.map +1 -0
- package/dist/core/mcp/mcp-tool.js +165 -0
- package/dist/core/mcp/mcp-tool.js.map +1 -0
- package/dist/core/mcp/metadata-cache.d.ts +29 -0
- package/dist/core/mcp/metadata-cache.d.ts.map +1 -0
- package/dist/core/mcp/metadata-cache.js +99 -0
- package/dist/core/mcp/metadata-cache.js.map +1 -0
- package/dist/core/mcp/runtime.d.ts +18 -0
- package/dist/core/mcp/runtime.d.ts.map +1 -0
- package/dist/core/mcp/runtime.js +35 -0
- package/dist/core/mcp/runtime.js.map +1 -0
- package/dist/core/mcp/schema.d.ts +22 -0
- package/dist/core/mcp/schema.d.ts.map +1 -0
- package/dist/core/mcp/schema.js +20 -0
- package/dist/core/mcp/schema.js.map +1 -0
- package/dist/core/mcp/server-manager.d.ts +43 -0
- package/dist/core/mcp/server-manager.d.ts.map +1 -0
- package/dist/core/mcp/server-manager.js +142 -0
- package/dist/core/mcp/server-manager.js.map +1 -0
- package/dist/core/mcp/types.d.ts +98 -0
- package/dist/core/mcp/types.d.ts.map +1 -0
- package/dist/core/mcp/types.js +8 -0
- package/dist/core/mcp/types.js.map +1 -0
- package/dist/core/model-config.d.ts +18 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +25 -6
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-resolver.d.ts +21 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +73 -8
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +73 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +225 -8
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/models-store.d.ts.map +1 -1
- package/dist/core/models-store.js +2 -1
- package/dist/core/models-store.js.map +1 -1
- package/dist/core/observability/aggregate.d.ts +21 -0
- package/dist/core/observability/aggregate.d.ts.map +1 -0
- package/dist/core/observability/aggregate.js +36 -0
- package/dist/core/observability/aggregate.js.map +1 -0
- package/dist/core/observability/otlp.d.ts +66 -0
- package/dist/core/observability/otlp.d.ts.map +1 -0
- package/dist/core/observability/otlp.js +95 -0
- package/dist/core/observability/otlp.js.map +1 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +40 -16
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/permissions/gate.d.ts +42 -0
- package/dist/core/permissions/gate.d.ts.map +1 -0
- package/dist/core/permissions/gate.js +72 -0
- package/dist/core/permissions/gate.js.map +1 -0
- package/dist/core/permissions/modes.d.ts +18 -0
- package/dist/core/permissions/modes.d.ts.map +1 -0
- package/dist/core/permissions/modes.js +57 -0
- package/dist/core/permissions/modes.js.map +1 -0
- package/dist/core/permissions/responder.d.ts +30 -0
- package/dist/core/permissions/responder.d.ts.map +1 -0
- package/dist/core/permissions/responder.js +32 -0
- package/dist/core/permissions/responder.js.map +1 -0
- package/dist/core/permissions/rules.d.ts +34 -0
- package/dist/core/permissions/rules.d.ts.map +1 -0
- package/dist/core/permissions/rules.js +74 -0
- package/dist/core/permissions/rules.js.map +1 -0
- package/dist/core/permissions/startup.d.ts +45 -0
- package/dist/core/permissions/startup.d.ts.map +1 -0
- package/dist/core/permissions/startup.js +63 -0
- package/dist/core/permissions/startup.js.map +1 -0
- package/dist/core/permissions/store.d.ts +114 -0
- package/dist/core/permissions/store.d.ts.map +1 -0
- package/dist/core/permissions/store.js +229 -0
- package/dist/core/permissions/store.js.map +1 -0
- package/dist/core/pi-manifest.d.ts.map +1 -1
- package/dist/core/pi-manifest.js +2 -1
- package/dist/core/pi-manifest.js.map +1 -1
- package/dist/core/project-trust.d.ts.map +1 -1
- package/dist/core/project-trust.js +1 -1
- package/dist/core/project-trust.js.map +1 -1
- package/dist/core/provider-attribution.d.ts.map +1 -1
- package/dist/core/provider-attribution.js +6 -7
- package/dist/core/provider-attribution.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts +2 -2
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +22 -17
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +3 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sandbox/bwrap-arguments.d.ts +52 -0
- package/dist/core/sandbox/bwrap-arguments.d.ts.map +1 -0
- package/dist/core/sandbox/bwrap-arguments.js +86 -0
- package/dist/core/sandbox/bwrap-arguments.js.map +1 -0
- package/dist/core/sandbox/child-entry.d.ts +2 -0
- package/dist/core/sandbox/child-entry.d.ts.map +1 -0
- package/dist/core/sandbox/child-entry.js +22 -0
- package/dist/core/sandbox/child-entry.js.map +1 -0
- package/dist/core/sandbox/cli-launch.d.ts +88 -0
- package/dist/core/sandbox/cli-launch.d.ts.map +1 -0
- package/dist/core/sandbox/cli-launch.js +272 -0
- package/dist/core/sandbox/cli-launch.js.map +1 -0
- package/dist/core/sandbox/cli-supervisor.d.ts +30 -0
- package/dist/core/sandbox/cli-supervisor.d.ts.map +1 -0
- package/dist/core/sandbox/cli-supervisor.js +123 -0
- package/dist/core/sandbox/cli-supervisor.js.map +1 -0
- package/dist/core/sandbox/default-hosts.d.ts +28 -0
- package/dist/core/sandbox/default-hosts.d.ts.map +1 -0
- package/dist/core/sandbox/default-hosts.js +69 -0
- package/dist/core/sandbox/default-hosts.js.map +1 -0
- package/dist/core/sandbox/full-access.d.ts +28 -0
- package/dist/core/sandbox/full-access.d.ts.map +1 -0
- package/dist/core/sandbox/full-access.js +63 -0
- package/dist/core/sandbox/full-access.js.map +1 -0
- package/dist/core/sandbox/git-identity.d.ts +57 -0
- package/dist/core/sandbox/git-identity.d.ts.map +1 -0
- package/dist/core/sandbox/git-identity.js +78 -0
- package/dist/core/sandbox/git-identity.js.map +1 -0
- package/dist/core/sandbox/host-approval.d.ts +42 -0
- package/dist/core/sandbox/host-approval.d.ts.map +1 -0
- package/dist/core/sandbox/host-approval.js +99 -0
- package/dist/core/sandbox/host-approval.js.map +1 -0
- package/dist/core/sandbox/linux-backend.d.ts +46 -0
- package/dist/core/sandbox/linux-backend.d.ts.map +1 -0
- package/dist/core/sandbox/linux-backend.js +304 -0
- package/dist/core/sandbox/linux-backend.js.map +1 -0
- package/dist/core/sandbox/macos-backend.d.ts +28 -0
- package/dist/core/sandbox/macos-backend.d.ts.map +1 -0
- package/dist/core/sandbox/macos-backend.js +313 -0
- package/dist/core/sandbox/macos-backend.js.map +1 -0
- package/dist/core/sandbox/network-proxy.d.ts +38 -0
- package/dist/core/sandbox/network-proxy.d.ts.map +1 -0
- package/dist/core/sandbox/network-proxy.js +153 -0
- package/dist/core/sandbox/network-proxy.js.map +1 -0
- package/dist/core/sandbox/network-refusal.d.ts +24 -0
- package/dist/core/sandbox/network-refusal.d.ts.map +1 -0
- package/dist/core/sandbox/network-refusal.js +72 -0
- package/dist/core/sandbox/network-refusal.js.map +1 -0
- package/dist/core/sandbox/policy.d.ts +40 -0
- package/dist/core/sandbox/policy.d.ts.map +1 -0
- package/dist/core/sandbox/policy.js +55 -0
- package/dist/core/sandbox/policy.js.map +1 -0
- package/dist/core/sandbox/profiles.d.ts +25 -0
- package/dist/core/sandbox/profiles.d.ts.map +1 -0
- package/dist/core/sandbox/profiles.js +23 -0
- package/dist/core/sandbox/profiles.js.map +1 -0
- package/dist/core/sandbox/rpc/command-client.d.ts +28 -0
- package/dist/core/sandbox/rpc/command-client.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/command-client.js +86 -0
- package/dist/core/sandbox/rpc/command-client.js.map +1 -0
- package/dist/core/sandbox/rpc/command-proxy.d.ts +48 -0
- package/dist/core/sandbox/rpc/command-proxy.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/command-proxy.js +120 -0
- package/dist/core/sandbox/rpc/command-proxy.js.map +1 -0
- package/dist/core/sandbox/rpc/credential-client.d.ts +20 -0
- package/dist/core/sandbox/rpc/credential-client.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/credential-client.js +170 -0
- package/dist/core/sandbox/rpc/credential-client.js.map +1 -0
- package/dist/core/sandbox/rpc/credential-proxy.d.ts +44 -0
- package/dist/core/sandbox/rpc/credential-proxy.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/credential-proxy.js +287 -0
- package/dist/core/sandbox/rpc/credential-proxy.js.map +1 -0
- package/dist/core/sandbox/rpc/framing.d.ts +35 -0
- package/dist/core/sandbox/rpc/framing.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/framing.js +114 -0
- package/dist/core/sandbox/rpc/framing.js.map +1 -0
- package/dist/core/sandbox/rpc/git-credential-helper.d.ts +40 -0
- package/dist/core/sandbox/rpc/git-credential-helper.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/git-credential-helper.js +152 -0
- package/dist/core/sandbox/rpc/git-credential-helper.js.map +1 -0
- package/dist/core/sandbox/rpc/git-credential-proxy.d.ts +48 -0
- package/dist/core/sandbox/rpc/git-credential-proxy.d.ts.map +1 -0
- package/dist/core/sandbox/rpc/git-credential-proxy.js +142 -0
- package/dist/core/sandbox/rpc/git-credential-proxy.js.map +1 -0
- package/dist/core/sandbox/supervisor-temp.d.ts +18 -0
- package/dist/core/sandbox/supervisor-temp.d.ts.map +1 -0
- package/dist/core/sandbox/supervisor-temp.js +21 -0
- package/dist/core/sandbox/supervisor-temp.js.map +1 -0
- package/dist/core/sandbox/supervisor.d.ts +51 -0
- package/dist/core/sandbox/supervisor.d.ts.map +1 -0
- package/dist/core/sandbox/supervisor.js +18 -0
- package/dist/core/sandbox/supervisor.js.map +1 -0
- package/dist/core/sandbox/terminal-handoff.d.ts +45 -0
- package/dist/core/sandbox/terminal-handoff.d.ts.map +1 -0
- package/dist/core/sandbox/terminal-handoff.js +176 -0
- package/dist/core/sandbox/terminal-handoff.js.map +1 -0
- package/dist/core/sandbox/terminal-size.d.ts +40 -0
- package/dist/core/sandbox/terminal-size.d.ts.map +1 -0
- package/dist/core/sandbox/terminal-size.js +105 -0
- package/dist/core/sandbox/terminal-size.js.map +1 -0
- package/dist/core/sandbox/violations.d.ts +23 -0
- package/dist/core/sandbox/violations.d.ts.map +1 -0
- package/dist/core/sandbox/violations.js +30 -0
- package/dist/core/sandbox/violations.js.map +1 -0
- package/dist/core/sdk.d.ts +32 -41
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +174 -6
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-export.d.ts +4 -0
- package/dist/core/session-export.d.ts.map +1 -0
- package/dist/core/session-export.js +32 -0
- package/dist/core/session-export.js.map +1 -0
- package/dist/core/session-lease.d.ts +31 -0
- package/dist/core/session-lease.d.ts.map +1 -0
- package/dist/core/session-lease.js +138 -0
- package/dist/core/session-lease.js.map +1 -0
- package/dist/core/session-manager.d.ts +58 -2
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +92 -7
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-share.d.ts +31 -0
- package/dist/core/session-share.d.ts.map +1 -0
- package/dist/core/session-share.js +45 -0
- package/dist/core/session-share.js.map +1 -0
- package/dist/core/settings-diagnostics.d.ts +9 -0
- package/dist/core/settings-diagnostics.d.ts.map +1 -0
- package/dist/core/settings-diagnostics.js +21 -0
- package/dist/core/settings-diagnostics.js.map +1 -0
- package/dist/core/settings-manager.d.ts +99 -9
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +141 -36
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +19 -7
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +128 -52
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +6 -2
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts +2 -2
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +59 -68
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/timings.d.ts +1 -1
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js +3 -2
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/ask-user.d.ts +25 -0
- package/dist/core/tools/ask-user.d.ts.map +1 -0
- package/dist/core/tools/ask-user.js +49 -0
- package/dist/core/tools/ask-user.js.map +1 -0
- package/dist/core/tools/bash-command-segments.d.ts +22 -0
- package/dist/core/tools/bash-command-segments.d.ts.map +1 -0
- package/dist/core/tools/bash-command-segments.js +128 -0
- package/dist/core/tools/bash-command-segments.js.map +1 -0
- package/dist/core/tools/bash.d.ts +40 -4
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +183 -32
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/contract-snapshot.d.ts +58 -0
- package/dist/core/tools/contract-snapshot.d.ts.map +1 -0
- package/dist/core/tools/contract-snapshot.js +51 -0
- package/dist/core/tools/contract-snapshot.js.map +1 -0
- package/dist/core/tools/contract.d.ts +185 -0
- package/dist/core/tools/contract.d.ts.map +1 -0
- package/dist/core/tools/contract.js +50 -0
- package/dist/core/tools/contract.js.map +1 -0
- package/dist/core/tools/delegate.d.ts +38 -0
- package/dist/core/tools/delegate.d.ts.map +1 -0
- package/dist/core/tools/delegate.js +90 -0
- package/dist/core/tools/delegate.js.map +1 -0
- package/dist/core/tools/diagnostics.d.ts +39 -0
- package/dist/core/tools/diagnostics.d.ts.map +1 -0
- package/dist/core/tools/diagnostics.js +62 -0
- package/dist/core/tools/diagnostics.js.map +1 -0
- package/dist/core/tools/edit-diff.d.ts +0 -5
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +2 -5
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts +12 -2
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +61 -10
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts +2 -2
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +13 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts +4 -2
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +47 -10
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +60 -6
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +148 -2
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts +4 -2
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +17 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/lsp.d.ts +62 -0
- package/dist/core/tools/lsp.d.ts.map +1 -0
- package/dist/core/tools/lsp.js +216 -0
- package/dist/core/tools/lsp.js.map +1 -0
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +1 -1
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/core/tools/path-permission.d.ts +18 -0
- package/dist/core/tools/path-permission.d.ts.map +1 -0
- package/dist/core/tools/path-permission.js +28 -0
- package/dist/core/tools/path-permission.js.map +1 -0
- package/dist/core/tools/plan-present.d.ts +27 -0
- package/dist/core/tools/plan-present.d.ts.map +1 -0
- package/dist/core/tools/plan-present.js +55 -0
- package/dist/core/tools/plan-present.js.map +1 -0
- package/dist/core/tools/powershell.d.ts +16 -0
- package/dist/core/tools/powershell.d.ts.map +1 -0
- package/dist/core/tools/powershell.js +39 -0
- package/dist/core/tools/powershell.js.map +1 -0
- package/dist/core/tools/read.d.ts +2 -2
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +14 -0
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/skill-search.d.ts +32 -0
- package/dist/core/tools/skill-search.d.ts.map +1 -0
- package/dist/core/tools/skill-search.js +56 -0
- package/dist/core/tools/skill-search.js.map +1 -0
- package/dist/core/tools/test.d.ts +34 -0
- package/dist/core/tools/test.d.ts.map +1 -0
- package/dist/core/tools/test.js +75 -0
- package/dist/core/tools/test.js.map +1 -0
- package/dist/core/tools/todo-write.d.ts +31 -0
- package/dist/core/tools/todo-write.d.ts.map +1 -0
- package/dist/core/tools/todo-write.js +51 -0
- package/dist/core/tools/todo-write.js.map +1 -0
- package/dist/core/tools/tool-definition-wrapper.d.ts +13 -2
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +11 -1
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/tools/tool-schema.d.ts +22 -0
- package/dist/core/tools/tool-schema.d.ts.map +1 -0
- package/dist/core/tools/tool-schema.js +45 -0
- package/dist/core/tools/tool-schema.js.map +1 -0
- package/dist/core/tools/web-fetch.d.ts +26 -0
- package/dist/core/tools/web-fetch.d.ts.map +1 -0
- package/dist/core/tools/web-fetch.js +62 -0
- package/dist/core/tools/web-fetch.js.map +1 -0
- package/dist/core/tools/web-search-exa.d.ts +33 -0
- package/dist/core/tools/web-search-exa.d.ts.map +1 -0
- package/dist/core/tools/web-search-exa.js +128 -0
- package/dist/core/tools/web-search-exa.js.map +1 -0
- package/dist/core/tools/web-search.d.ts +26 -0
- package/dist/core/tools/web-search.d.ts.map +1 -0
- package/dist/core/tools/web-search.js +53 -0
- package/dist/core/tools/web-search.js.map +1 -0
- package/dist/core/tools/write.d.ts +16 -2
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +48 -2
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +2 -1
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/core/usage-performance-store.d.ts +56 -0
- package/dist/core/usage-performance-store.d.ts.map +1 -0
- package/dist/core/usage-performance-store.js +85 -0
- package/dist/core/usage-performance-store.js.map +1 -0
- package/dist/core/web-search-provider.d.ts +64 -0
- package/dist/core/web-search-provider.d.ts.map +1 -0
- package/dist/core/web-search-provider.js +149 -0
- package/dist/core/web-search-provider.js.map +1 -0
- package/dist/extensions/llama/index.d.ts.map +1 -1
- package/dist/extensions/llama/index.js +2 -0
- package/dist/extensions/llama/index.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +6 -2
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/index.d.ts +9 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -4
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +5 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +87 -22
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +6 -5
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +29 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +182 -23
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +7 -0
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +20 -0
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +9 -6
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +72 -1
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +338 -1
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts +7 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js +11 -2
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +4 -0
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +24 -6
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts +1 -4
- package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.js +17 -41
- package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
- package/dist/modes/interactive/components/first-use-hints.d.ts +8 -0
- package/dist/modes/interactive/components/first-use-hints.d.ts.map +1 -0
- package/dist/modes/interactive/components/first-use-hints.js +22 -0
- package/dist/modes/interactive/components/first-use-hints.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts +31 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +205 -24
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +2 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +2 -0
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +31 -9
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +236 -96
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +25 -5
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +226 -58
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-submenu.d.ts +72 -0
- package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -0
- package/dist/modes/interactive/components/settings-submenu.js +165 -0
- package/dist/modes/interactive/components/settings-submenu.js.map +1 -0
- package/dist/modes/interactive/components/splash-header.d.ts +66 -0
- package/dist/modes/interactive/components/splash-header.d.ts.map +1 -0
- package/dist/modes/interactive/components/splash-header.js +180 -0
- package/dist/modes/interactive/components/splash-header.js.map +1 -0
- package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +74 -17
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +28 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +144 -35
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tool-panel.d.ts +30 -0
- package/dist/modes/interactive/components/tool-panel.d.ts.map +1 -0
- package/dist/modes/interactive/components/tool-panel.js +130 -0
- package/dist/modes/interactive/components/tool-panel.js.map +1 -0
- package/dist/modes/interactive/external-editor.d.ts.map +1 -1
- package/dist/modes/interactive/external-editor.js +60 -10
- package/dist/modes/interactive/external-editor.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +90 -5
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +729 -206
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/model-catalog-refresh.d.ts +7 -0
- package/dist/modes/interactive/model-catalog-refresh.d.ts.map +1 -0
- package/dist/modes/interactive/model-catalog-refresh.js +34 -0
- package/dist/modes/interactive/model-catalog-refresh.js.map +1 -0
- package/dist/modes/interactive/theme/apex.json +93 -0
- package/dist/modes/interactive/theme/dark.json +2 -0
- package/dist/modes/interactive/theme/light.json +3 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts +10 -2
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.js +25 -11
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.json +11 -3
- package/dist/modes/interactive/theme/theme.d.ts +14 -3
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +65 -10
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/json-event.d.ts +18 -12
- package/dist/modes/json-event.d.ts.map +1 -1
- package/dist/modes/json-event.js +22 -5
- package/dist/modes/json-event.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +2 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/package-manager-cli.d.ts +1 -0
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +210 -19
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/rpc-entry.d.ts.map +1 -1
- package/dist/rpc-entry.js +2 -1
- package/dist/rpc-entry.js.map +1 -1
- package/dist/testing/replay/metrics.d.ts +24 -0
- package/dist/testing/replay/metrics.d.ts.map +1 -0
- package/dist/testing/replay/metrics.js +35 -0
- package/dist/testing/replay/metrics.js.map +1 -0
- package/dist/testing/replay/recorded-provider.d.ts +10 -0
- package/dist/testing/replay/recorded-provider.d.ts.map +1 -0
- package/dist/testing/replay/recorded-provider.js +108 -0
- package/dist/testing/replay/recorded-provider.js.map +1 -0
- package/dist/testing/replay/runner.d.ts +56 -0
- package/dist/testing/replay/runner.d.ts.map +1 -0
- package/dist/testing/replay/runner.js +406 -0
- package/dist/testing/replay/runner.js.map +1 -0
- package/dist/themes/apex-logo.d.ts +41 -0
- package/dist/themes/apex-logo.d.ts.map +1 -0
- package/dist/themes/apex-logo.js +35 -0
- package/dist/themes/apex-logo.js.map +1 -0
- package/dist/utils/apex-code-user-agent.d.ts +2 -0
- package/dist/utils/apex-code-user-agent.d.ts.map +1 -0
- package/dist/utils/apex-code-user-agent.js +5 -0
- package/dist/utils/apex-code-user-agent.js.map +1 -0
- package/dist/utils/changelog.d.ts +7 -2
- package/dist/utils/changelog.d.ts.map +1 -1
- package/dist/utils/changelog.js +82 -13
- package/dist/utils/changelog.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +1 -1
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/frontmatter.js +2 -1
- package/dist/utils/frontmatter.js.map +1 -1
- package/dist/utils/management-http.d.ts +5 -3
- package/dist/utils/management-http.d.ts.map +1 -1
- package/dist/utils/management-http.js +14 -10
- package/dist/utils/management-http.js.map +1 -1
- package/dist/utils/shell.d.ts +3 -0
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +17 -5
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts +1 -0
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.js +60 -1
- package/dist/utils/syntax-highlight.js.map +1 -1
- package/dist/utils/text.d.ts +8 -0
- package/dist/utils/text.d.ts.map +1 -0
- package/dist/utils/text.js +9 -0
- package/dist/utils/text.js.map +1 -0
- package/dist/utils/tools-manager.d.ts +70 -2
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +280 -124
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/version-check.d.ts +7 -5
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +27 -14
- package/dist/utils/version-check.js.map +1 -1
- package/dist/utils/windows-self-update.d.ts.map +1 -1
- package/dist/utils/windows-self-update.js +1 -1
- package/dist/utils/windows-self-update.js.map +1 -1
- package/docs/compaction.md +41 -24
- package/docs/containerization.md +24 -21
- package/docs/custom-provider.md +15 -12
- package/docs/development.md +11 -11
- package/docs/environment-variables.md +37 -77
- package/docs/extensions.md +68 -54
- package/docs/index.md +12 -24
- package/docs/json.md +18 -11
- package/docs/keybindings.md +18 -12
- package/docs/llama-cpp.md +9 -7
- package/docs/models.md +17 -11
- package/docs/packages.md +47 -43
- package/docs/prompt-templates.md +3 -3
- package/docs/providers.md +10 -10
- package/docs/quickstart.md +49 -32
- package/docs/rpc.md +35 -18
- package/docs/sdk.md +20 -6
- package/docs/security.md +18 -18
- package/docs/session-format.md +9 -9
- package/docs/sessions.md +13 -13
- package/docs/settings.md +83 -16
- package/docs/shell-aliases.md +1 -1
- package/docs/skills.md +66 -15
- package/docs/terminal-setup.md +44 -19
- package/docs/termux.md +4 -4
- package/docs/themes.md +32 -11
- package/docs/tmux.md +4 -4
- package/docs/tui.md +5 -5
- package/docs/usage.md +61 -53
- package/docs/windows.md +24 -2
- package/examples/extensions/border-status-editor.ts +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +2 -2
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/git-checkpoint.ts +24 -36
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/notify.ts +3 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/subagent/README.md +3 -1
- package/examples/extensions/subagent/agents.ts +40 -9
- package/examples/extensions/subagent/index.ts +27 -4
- package/examples/extensions/titlebar-spinner.ts +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/rpc-extension-ui.ts +1 -1
- package/examples/sdk/06-extensions.ts +1 -1
- package/examples/sdk/README.md +1 -1
- package/npm-shrinkwrap.json +435 -452
- package/package.json +17 -18
- package/dist/core/telemetry.d.ts +0 -3
- package/dist/core/telemetry.d.ts.map +0 -1
- package/dist/core/telemetry.js +0 -9
- package/dist/core/telemetry.js.map +0 -1
- package/dist/server/create-harness.d.ts +0 -26
- package/dist/server/create-harness.d.ts.map +0 -1
- package/dist/server/create-harness.js +0 -104
- package/dist/server/create-harness.js.map +0 -1
- package/dist/utils/pi-user-agent.d.ts +0 -2
- package/dist/utils/pi-user-agent.d.ts.map +0 -1
- package/dist/utils/pi-user-agent.js +0 -5
- package/dist/utils/pi-user-agent.js.map +0 -1
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One tool for every MCP server, instead of one tool per server tool.
|
|
3
|
+
*
|
|
4
|
+
* Registering each server tool individually costs 150-300 prompt tokens apiece, and
|
|
5
|
+
* two ordinary servers would exceed the whole static-prefix budget before a
|
|
6
|
+
* conversation starts. The proxy costs one announced name and this description,
|
|
7
|
+
* because its schema defers.
|
|
8
|
+
*
|
|
9
|
+
* `search` and `describe` read the disk cache and reach no server. Only a `tool` call
|
|
10
|
+
* connects, which is what makes discovery free and is why the two have separate
|
|
11
|
+
* permission rules (ADR 0025).
|
|
12
|
+
*/
|
|
13
|
+
import { wrapToolDefinition } from "../tools/tool-definition-wrapper.js";
|
|
14
|
+
import { createMcpToolContract } from "./contract.js";
|
|
15
|
+
import { mcpToolSchema } from "./schema.js";
|
|
16
|
+
export const MCP_TOOL_NAME = "mcp";
|
|
17
|
+
const MAX_RESULTS = 25;
|
|
18
|
+
const DESCRIPTION = "Use tools provided by configured MCP servers. " +
|
|
19
|
+
'Search with {"search":"keyword"}, list one server with {"server":"name"}, ' +
|
|
20
|
+
'see a tool\'s full schema with {"describe":"server:tool"}, ' +
|
|
21
|
+
'and call one with {"tool":"server:tool","args":{...}}. ' +
|
|
22
|
+
"Search and describe read a local cache and never start a server, so discovery is free. " +
|
|
23
|
+
"Always describe a tool before calling it for the first time.";
|
|
24
|
+
function text(body) {
|
|
25
|
+
return [{ type: "text", text: body }];
|
|
26
|
+
}
|
|
27
|
+
function qualified(tool) {
|
|
28
|
+
return `${tool.server}:${tool.name}`;
|
|
29
|
+
}
|
|
30
|
+
/** Substring scoring, weighted to the name, which is what the model searched for. */
|
|
31
|
+
function score(tool, needle) {
|
|
32
|
+
const name = qualified(tool).toLowerCase();
|
|
33
|
+
const description = tool.description.toLowerCase();
|
|
34
|
+
if (name === needle)
|
|
35
|
+
return 100;
|
|
36
|
+
if (name.includes(needle))
|
|
37
|
+
return 50;
|
|
38
|
+
if (description.includes(needle))
|
|
39
|
+
return 10;
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
function renderList(tools) {
|
|
43
|
+
return tools.map((tool) => `${qualified(tool)}: ${tool.description}`).join("\n");
|
|
44
|
+
}
|
|
45
|
+
function nearest(tools, target) {
|
|
46
|
+
const needle = target.toLowerCase();
|
|
47
|
+
const stem = needle.slice(0, Math.max(3, Math.floor(needle.length * 0.6)));
|
|
48
|
+
return tools.filter((tool) => qualified(tool).toLowerCase().includes(stem)).slice(0, 5);
|
|
49
|
+
}
|
|
50
|
+
export function createMcpToolDefinition(options) {
|
|
51
|
+
const { servers, cache, manager } = options;
|
|
52
|
+
return {
|
|
53
|
+
name: MCP_TOOL_NAME,
|
|
54
|
+
label: "mcp",
|
|
55
|
+
description: DESCRIPTION,
|
|
56
|
+
promptSnippet: "Call tools on configured MCP servers",
|
|
57
|
+
parameters: mcpToolSchema,
|
|
58
|
+
contract: createMcpToolContract(servers),
|
|
59
|
+
async execute(_id, params) {
|
|
60
|
+
if (params.tool)
|
|
61
|
+
return callTool(params.tool, params.args);
|
|
62
|
+
if (params.describe)
|
|
63
|
+
return describeTool(params.describe);
|
|
64
|
+
if (params.search !== undefined)
|
|
65
|
+
return searchTools(params.search, params.server);
|
|
66
|
+
if (params.server)
|
|
67
|
+
return listServer(params.server);
|
|
68
|
+
return {
|
|
69
|
+
content: text('Provide one of "search", "server", "describe", or "tool".'),
|
|
70
|
+
details: { action: "search", server: undefined, tool: undefined },
|
|
71
|
+
};
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
function searchTools(needle, serverFilter) {
|
|
75
|
+
const pool = serverFilter ? cache.all().filter((tool) => tool.server === serverFilter) : cache.all();
|
|
76
|
+
const lowered = needle.toLowerCase();
|
|
77
|
+
const ranked = pool
|
|
78
|
+
.map((tool) => ({ tool, rank: score(tool, lowered) }))
|
|
79
|
+
.filter((entry) => entry.rank > 0)
|
|
80
|
+
.sort((a, b) => b.rank - a.rank)
|
|
81
|
+
.slice(0, MAX_RESULTS)
|
|
82
|
+
.map((entry) => entry.tool);
|
|
83
|
+
return {
|
|
84
|
+
content: text(ranked.length > 0
|
|
85
|
+
? renderList(ranked)
|
|
86
|
+
: `No cached MCP tool matches "${needle}". Configured servers: ${[...servers.keys()].join(", ") || "none"}.`),
|
|
87
|
+
details: { action: "search", server: serverFilter, tool: undefined },
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function listServer(name) {
|
|
91
|
+
if (!servers.has(name)) {
|
|
92
|
+
return {
|
|
93
|
+
content: text(`MCP server "${name}" is not configured. Configured servers: ${[...servers.keys()].join(", ") || "none"}.`),
|
|
94
|
+
details: { action: "list", server: name, tool: undefined },
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const tools = cache.all().filter((tool) => tool.server === name);
|
|
98
|
+
return {
|
|
99
|
+
content: text(tools.length > 0
|
|
100
|
+
? renderList(tools)
|
|
101
|
+
: `No cached tools for "${name}" yet. Tools are cached the first time the server is called, so call a known tool on it, or set "lifecycle": "eager" for this server in .mcp.json to have them cached at startup.`),
|
|
102
|
+
details: { action: "list", server: name, tool: undefined },
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function describeTool(target) {
|
|
106
|
+
const found = cache.all().find((tool) => qualified(tool) === target);
|
|
107
|
+
if (!found) {
|
|
108
|
+
const suggestions = nearest(cache.all(), target);
|
|
109
|
+
return {
|
|
110
|
+
content: text(suggestions.length > 0
|
|
111
|
+
? `No cached tool named "${target}". Did you mean:\n${renderList(suggestions)}`
|
|
112
|
+
: `No cached tool named "${target}". Search with {"search":"keyword"}.`),
|
|
113
|
+
details: { action: "describe", server: undefined, tool: target },
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
content: text(`${qualified(found)}\n${found.description}\n\nInput schema:\n${JSON.stringify(found.inputSchema, null, 2)}`),
|
|
118
|
+
details: { action: "describe", server: found.server, tool: target },
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
async function callTool(target, args) {
|
|
122
|
+
const separator = target.indexOf(":");
|
|
123
|
+
const details = { action: "call", server: undefined, tool: target };
|
|
124
|
+
if (separator <= 0) {
|
|
125
|
+
return { content: text(`Tool must be qualified as "server:tool". Received "${target}".`), details };
|
|
126
|
+
}
|
|
127
|
+
const serverName = target.slice(0, separator);
|
|
128
|
+
const toolName = target.slice(separator + 1);
|
|
129
|
+
details.server = serverName;
|
|
130
|
+
if (!servers.has(serverName)) {
|
|
131
|
+
return {
|
|
132
|
+
content: text(`MCP server "${serverName}" is not configured. Configured servers: ${[...servers.keys()].join(", ") || "none"}.`),
|
|
133
|
+
details,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
const result = await manager.withConnection(serverName, async (connection) => {
|
|
138
|
+
// An empty list is a fact about the server, not a failed read. Keeping the
|
|
139
|
+
// previous entry would leave search advertising tools that no longer exist.
|
|
140
|
+
const fresh = await connection.listTools();
|
|
141
|
+
cache.set(servers.get(serverName), fresh);
|
|
142
|
+
cache.save();
|
|
143
|
+
return connection.callTool(toolName, args);
|
|
144
|
+
});
|
|
145
|
+
// `AgentToolResult` has no error flag; a server-reported failure is marked in
|
|
146
|
+
// the text so the model can see it failed without the turn being aborted.
|
|
147
|
+
const content = result.isError
|
|
148
|
+
? text(`Tool reported an error:\n${result.content.map((part) => part.text).join("\n")}`)
|
|
149
|
+
: result.content;
|
|
150
|
+
return { content, details };
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
// A failed server is reported, not retried: the manager holds it in `failed`
|
|
154
|
+
// with a backoff window so one broken server cannot cost every call a spawn.
|
|
155
|
+
return {
|
|
156
|
+
content: text(`MCP server "${serverName}" is unavailable: ${error instanceof Error ? error.message : String(error)}`),
|
|
157
|
+
details,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
export function createMcpTool(options) {
|
|
163
|
+
return wrapToolDefinition(createMcpToolDefinition(options));
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=mcp-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-tool.js","sourceRoot":"","sources":["../../../src/core/mcp/mcp-tool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * One tool for every MCP server, instead of one tool per server tool.\n *\n * Registering each server tool individually costs 150-300 prompt tokens apiece, and\n * two ordinary servers would exceed the whole static-prefix budget before a\n * conversation starts. The proxy costs one announced name and this description,\n * because its schema defers.\n *\n * `search` and `describe` read the disk cache and reach no server. Only a `tool` call\n * connects, which is what makes discovery free and is why the two have separate\n * permission rules (ADR 0025).\n */\n\nimport type { AgentToolResult } from \"apex-code-agent-core\";\nimport type { ApexToolDefinition } from \"../tools/contract.ts\";\nimport { wrapToolDefinition } from \"../tools/tool-definition-wrapper.ts\";\nimport { createMcpToolContract } from \"./contract.ts\";\nimport type { McpMetadataCache } from \"./metadata-cache.ts\";\nimport { type McpToolDetails, type McpToolParams, mcpToolSchema } from \"./schema.ts\";\nimport type { McpServerManager } from \"./server-manager.ts\";\nimport type { CachedTool, McpServerConfig } from \"./types.ts\";\n\nexport const MCP_TOOL_NAME = \"mcp\";\n\nconst MAX_RESULTS = 25;\n\nconst DESCRIPTION =\n\t\"Use tools provided by configured MCP servers. \" +\n\t'Search with {\"search\":\"keyword\"}, list one server with {\"server\":\"name\"}, ' +\n\t'see a tool\\'s full schema with {\"describe\":\"server:tool\"}, ' +\n\t'and call one with {\"tool\":\"server:tool\",\"args\":{...}}. ' +\n\t\"Search and describe read a local cache and never start a server, so discovery is free. \" +\n\t\"Always describe a tool before calling it for the first time.\";\n\nfunction text(body: string): AgentToolResult<McpToolDetails>[\"content\"] {\n\treturn [{ type: \"text\", text: body }];\n}\n\nfunction qualified(tool: CachedTool): string {\n\treturn `${tool.server}:${tool.name}`;\n}\n\n/** Substring scoring, weighted to the name, which is what the model searched for. */\nfunction score(tool: CachedTool, needle: string): number {\n\tconst name = qualified(tool).toLowerCase();\n\tconst description = tool.description.toLowerCase();\n\tif (name === needle) return 100;\n\tif (name.includes(needle)) return 50;\n\tif (description.includes(needle)) return 10;\n\treturn 0;\n}\n\nfunction renderList(tools: readonly CachedTool[]): string {\n\treturn tools.map((tool) => `${qualified(tool)}: ${tool.description}`).join(\"\\n\");\n}\n\nfunction nearest(tools: readonly CachedTool[], target: string): CachedTool[] {\n\tconst needle = target.toLowerCase();\n\tconst stem = needle.slice(0, Math.max(3, Math.floor(needle.length * 0.6)));\n\treturn tools.filter((tool) => qualified(tool).toLowerCase().includes(stem)).slice(0, 5);\n}\n\nexport interface McpToolOptions {\n\tservers: ReadonlyMap<string, McpServerConfig>;\n\tcache: McpMetadataCache;\n\tmanager: McpServerManager;\n}\n\nexport function createMcpToolDefinition(\n\toptions: McpToolOptions,\n): ApexToolDefinition<typeof mcpToolSchema, McpToolDetails> {\n\tconst { servers, cache, manager } = options;\n\n\treturn {\n\t\tname: MCP_TOOL_NAME,\n\t\tlabel: \"mcp\",\n\t\tdescription: DESCRIPTION,\n\t\tpromptSnippet: \"Call tools on configured MCP servers\",\n\t\tparameters: mcpToolSchema,\n\t\tcontract: createMcpToolContract(servers),\n\t\tasync execute(_id, params: McpToolParams): Promise<AgentToolResult<McpToolDetails>> {\n\t\t\tif (params.tool) return callTool(params.tool, params.args);\n\t\t\tif (params.describe) return describeTool(params.describe);\n\t\t\tif (params.search !== undefined) return searchTools(params.search, params.server);\n\t\t\tif (params.server) return listServer(params.server);\n\n\t\t\treturn {\n\t\t\t\tcontent: text('Provide one of \"search\", \"server\", \"describe\", or \"tool\".'),\n\t\t\t\tdetails: { action: \"search\", server: undefined, tool: undefined },\n\t\t\t};\n\t\t},\n\t};\n\n\tfunction searchTools(needle: string, serverFilter?: string): AgentToolResult<McpToolDetails> {\n\t\tconst pool = serverFilter ? cache.all().filter((tool) => tool.server === serverFilter) : cache.all();\n\t\tconst lowered = needle.toLowerCase();\n\t\tconst ranked = pool\n\t\t\t.map((tool) => ({ tool, rank: score(tool, lowered) }))\n\t\t\t.filter((entry) => entry.rank > 0)\n\t\t\t.sort((a, b) => b.rank - a.rank)\n\t\t\t.slice(0, MAX_RESULTS)\n\t\t\t.map((entry) => entry.tool);\n\n\t\treturn {\n\t\t\tcontent: text(\n\t\t\t\tranked.length > 0\n\t\t\t\t\t? renderList(ranked)\n\t\t\t\t\t: `No cached MCP tool matches \"${needle}\". Configured servers: ${[...servers.keys()].join(\", \") || \"none\"}.`,\n\t\t\t),\n\t\t\tdetails: { action: \"search\", server: serverFilter, tool: undefined },\n\t\t};\n\t}\n\n\tfunction listServer(name: string): AgentToolResult<McpToolDetails> {\n\t\tif (!servers.has(name)) {\n\t\t\treturn {\n\t\t\t\tcontent: text(\n\t\t\t\t\t`MCP server \"${name}\" is not configured. Configured servers: ${[...servers.keys()].join(\", \") || \"none\"}.`,\n\t\t\t\t),\n\t\t\t\tdetails: { action: \"list\", server: name, tool: undefined },\n\t\t\t};\n\t\t}\n\n\t\tconst tools = cache.all().filter((tool) => tool.server === name);\n\t\treturn {\n\t\t\tcontent: text(\n\t\t\t\ttools.length > 0\n\t\t\t\t\t? renderList(tools)\n\t\t\t\t\t: `No cached tools for \"${name}\" yet. Tools are cached the first time the server is called, so call a known tool on it, or set \"lifecycle\": \"eager\" for this server in .mcp.json to have them cached at startup.`,\n\t\t\t),\n\t\t\tdetails: { action: \"list\", server: name, tool: undefined },\n\t\t};\n\t}\n\n\tfunction describeTool(target: string): AgentToolResult<McpToolDetails> {\n\t\tconst found = cache.all().find((tool) => qualified(tool) === target);\n\t\tif (!found) {\n\t\t\tconst suggestions = nearest(cache.all(), target);\n\t\t\treturn {\n\t\t\t\tcontent: text(\n\t\t\t\t\tsuggestions.length > 0\n\t\t\t\t\t\t? `No cached tool named \"${target}\". Did you mean:\\n${renderList(suggestions)}`\n\t\t\t\t\t\t: `No cached tool named \"${target}\". Search with {\"search\":\"keyword\"}.`,\n\t\t\t\t),\n\t\t\t\tdetails: { action: \"describe\", server: undefined, tool: target },\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tcontent: text(\n\t\t\t\t`${qualified(found)}\\n${found.description}\\n\\nInput schema:\\n${JSON.stringify(found.inputSchema, null, 2)}`,\n\t\t\t),\n\t\t\tdetails: { action: \"describe\", server: found.server, tool: target },\n\t\t};\n\t}\n\n\tasync function callTool(target: string, args: unknown): Promise<AgentToolResult<McpToolDetails>> {\n\t\tconst separator = target.indexOf(\":\");\n\t\tconst details: McpToolDetails = { action: \"call\", server: undefined, tool: target };\n\t\tif (separator <= 0) {\n\t\t\treturn { content: text(`Tool must be qualified as \"server:tool\". Received \"${target}\".`), details };\n\t\t}\n\n\t\tconst serverName = target.slice(0, separator);\n\t\tconst toolName = target.slice(separator + 1);\n\t\tdetails.server = serverName;\n\n\t\tif (!servers.has(serverName)) {\n\t\t\treturn {\n\t\t\t\tcontent: text(\n\t\t\t\t\t`MCP server \"${serverName}\" is not configured. Configured servers: ${[...servers.keys()].join(\", \") || \"none\"}.`,\n\t\t\t\t),\n\t\t\t\tdetails,\n\t\t\t};\n\t\t}\n\n\t\ttry {\n\t\t\tconst result = await manager.withConnection(serverName, async (connection) => {\n\t\t\t\t// An empty list is a fact about the server, not a failed read. Keeping the\n\t\t\t\t// previous entry would leave search advertising tools that no longer exist.\n\t\t\t\tconst fresh = await connection.listTools();\n\t\t\t\tcache.set(servers.get(serverName) as McpServerConfig, fresh);\n\t\t\t\tcache.save();\n\t\t\t\treturn connection.callTool(toolName, args);\n\t\t\t});\n\n\t\t\t// `AgentToolResult` has no error flag; a server-reported failure is marked in\n\t\t\t// the text so the model can see it failed without the turn being aborted.\n\t\t\tconst content = result.isError\n\t\t\t\t? text(`Tool reported an error:\\n${result.content.map((part) => part.text).join(\"\\n\")}`)\n\t\t\t\t: result.content;\n\t\t\treturn { content, details };\n\t\t} catch (error) {\n\t\t\t// A failed server is reported, not retried: the manager holds it in `failed`\n\t\t\t// with a backoff window so one broken server cannot cost every call a spawn.\n\t\t\treturn {\n\t\t\t\tcontent: text(\n\t\t\t\t\t`MCP server \"${serverName}\" is unavailable: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t),\n\t\t\t\tdetails,\n\t\t\t};\n\t\t}\n\t}\n}\n\nexport function createMcpTool(options: McpToolOptions) {\n\treturn wrapToolDefinition(createMcpToolDefinition(options));\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent MCP tool metadata, so search and describe answer without a running
|
|
3
|
+
* server. Everything the cache holds is producible from a past connection, which is
|
|
4
|
+
* what makes "no server needed to search" a property rather than a convention.
|
|
5
|
+
*
|
|
6
|
+
* One file for every server, not one per server: the whole cache is read once at
|
|
7
|
+
* session start and written whole, and a handful of servers never makes that costly.
|
|
8
|
+
*/
|
|
9
|
+
import type { CachedTool, McpServerConfig } from "./types.ts";
|
|
10
|
+
export declare function mcpCachePath(): string;
|
|
11
|
+
/**
|
|
12
|
+
* The name is part of the key, not only the launch spec. Two servers can share a
|
|
13
|
+
* command (the same binary run twice under different names) and would otherwise
|
|
14
|
+
* collide, the second silently overwriting the first's cached tools.
|
|
15
|
+
*/
|
|
16
|
+
export declare function serverCacheKey(server: McpServerConfig): string;
|
|
17
|
+
export declare class McpMetadataCache {
|
|
18
|
+
private file;
|
|
19
|
+
private readonly path;
|
|
20
|
+
constructor(path?: string);
|
|
21
|
+
private static read;
|
|
22
|
+
get(server: McpServerConfig): CachedTool[];
|
|
23
|
+
all(): CachedTool[];
|
|
24
|
+
set(server: McpServerConfig, tools: readonly CachedTool[]): void;
|
|
25
|
+
/** Forget every server absent from `configured`, so a removed server stops appearing in search. */
|
|
26
|
+
prune(configured: readonly McpServerConfig[]): void;
|
|
27
|
+
save(): void;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=metadata-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata-cache.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/metadata-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAgB,MAAM,YAAY,CAAC;AAW5E,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAwBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAG9D;AAED,qBAAa,gBAAgB;IAC5B,OAAO,CAAC,IAAI,CAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAE9B,YAAY,IAAI,GAAE,MAAuB,EAGxC;IAED,OAAO,CAAC,MAAM,CAAC,IAAI;IAanB,GAAG,CAAC,MAAM,EAAE,eAAe,GAAG,UAAU,EAAE,CAEzC;IAED,GAAG,IAAI,UAAU,EAAE,CAElB;IAED,GAAG,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,IAAI,CAE/D;IAED,mGAAmG;IACnG,KAAK,CAAC,UAAU,EAAE,SAAS,eAAe,EAAE,GAAG,IAAI,CAKlD;IAED,IAAI,IAAI,IAAI,CAUX;CACD","sourcesContent":["/**\n * Persistent MCP tool metadata, so search and describe answer without a running\n * server. Everything the cache holds is producible from a past connection, which is\n * what makes \"no server needed to search\" a property rather than a convention.\n *\n * One file for every server, not one per server: the whole cache is read once at\n * session start and written whole, and a handful of servers never makes that costly.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { getAgentDir } from \"../../config.ts\";\nimport type { CachedTool, McpServerConfig, McpTransport } from \"./types.ts\";\n\ninterface CacheFile {\n\tversion: 1;\n\tservers: Record<string, { name: string; tools: CachedTool[] }>;\n}\n\nconst EMPTY: CacheFile = { version: 1, servers: {} };\n\nconst SEPARATOR = \"|\";\n\nexport function mcpCachePath(): string {\n\treturn join(getAgentDir(), \"mcp\", \"metadata.json\");\n}\n\n/**\n * Everything that can change which tools a server publishes, and nothing that cannot.\n * A version bump in `args` produces a new key and therefore reads no stale entries,\n * while `capabilities` or `idleTimeoutMinutes` leave the key alone.\n */\nfunction transportIdentity(transport: McpTransport): string {\n\tif (transport.kind === \"stdio\") {\n\t\t// Env values, not just keys: a server that switches which token or mode it runs\n\t\t// under can publish a different tool list under the same command line.\n\t\tconst env = Object.entries(transport.env)\n\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t.map(([key, value]) => `${key}=${value}`)\n\t\t\t.join(\",\");\n\t\treturn [\"stdio\", transport.command, transport.args.join(\" \"), env, transport.cwd ?? \"\"].join(SEPARATOR);\n\t}\n\tconst headers = Object.entries(transport.headers)\n\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t.map(([key, value]) => `${key}=${value}`)\n\t\t.join(\",\");\n\treturn [\"http\", transport.url, headers, transport.bearerTokenEnv ?? \"\"].join(SEPARATOR);\n}\n\n/**\n * The name is part of the key, not only the launch spec. Two servers can share a\n * command (the same binary run twice under different names) and would otherwise\n * collide, the second silently overwriting the first's cached tools.\n */\nexport function serverCacheKey(server: McpServerConfig): string {\n\tconst identity = [server.name, transportIdentity(server.transport)].join(SEPARATOR);\n\treturn createHash(\"sha256\").update(identity).digest(\"hex\").slice(0, 32);\n}\n\nexport class McpMetadataCache {\n\tprivate file: CacheFile;\n\tprivate readonly path: string;\n\n\tconstructor(path: string = mcpCachePath()) {\n\t\tthis.path = path;\n\t\tthis.file = McpMetadataCache.read(path);\n\t}\n\n\tprivate static read(path: string): CacheFile {\n\t\tif (!existsSync(path)) return structuredClone(EMPTY);\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(readFileSync(path, \"utf-8\")) as CacheFile;\n\t\t\tif (parsed?.version !== 1 || typeof parsed.servers !== \"object\" || parsed.servers === null) {\n\t\t\t\treturn structuredClone(EMPTY);\n\t\t\t}\n\t\t\treturn parsed;\n\t\t} catch {\n\t\t\treturn structuredClone(EMPTY);\n\t\t}\n\t}\n\n\tget(server: McpServerConfig): CachedTool[] {\n\t\treturn this.file.servers[serverCacheKey(server)]?.tools ?? [];\n\t}\n\n\tall(): CachedTool[] {\n\t\treturn Object.values(this.file.servers).flatMap((entry) => entry.tools);\n\t}\n\n\tset(server: McpServerConfig, tools: readonly CachedTool[]): void {\n\t\tthis.file.servers[serverCacheKey(server)] = { name: server.name, tools: [...tools] };\n\t}\n\n\t/** Forget every server absent from `configured`, so a removed server stops appearing in search. */\n\tprune(configured: readonly McpServerConfig[]): void {\n\t\tconst live = new Set(configured.map(serverCacheKey));\n\t\tfor (const key of Object.keys(this.file.servers)) {\n\t\t\tif (!live.has(key)) delete this.file.servers[key];\n\t\t}\n\t}\n\n\tsave(): void {\n\t\tconst directory = dirname(this.path);\n\t\tmkdirSync(directory, { recursive: true });\n\t\tconst temporary = join(directory, `.metadata.${process.pid}.tmp`);\n\t\ttry {\n\t\t\twriteFileSync(temporary, JSON.stringify(this.file));\n\t\t\trenameSync(temporary, this.path);\n\t\t} catch {\n\t\t\trmSync(temporary, { force: true });\n\t\t}\n\t}\n}\n"]}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent MCP tool metadata, so search and describe answer without a running
|
|
3
|
+
* server. Everything the cache holds is producible from a past connection, which is
|
|
4
|
+
* what makes "no server needed to search" a property rather than a convention.
|
|
5
|
+
*
|
|
6
|
+
* One file for every server, not one per server: the whole cache is read once at
|
|
7
|
+
* session start and written whole, and a handful of servers never makes that costly.
|
|
8
|
+
*/
|
|
9
|
+
import { createHash } from "node:crypto";
|
|
10
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
11
|
+
import { dirname, join } from "node:path";
|
|
12
|
+
import { getAgentDir } from "../../config.js";
|
|
13
|
+
const EMPTY = { version: 1, servers: {} };
|
|
14
|
+
const SEPARATOR = "|";
|
|
15
|
+
export function mcpCachePath() {
|
|
16
|
+
return join(getAgentDir(), "mcp", "metadata.json");
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Everything that can change which tools a server publishes, and nothing that cannot.
|
|
20
|
+
* A version bump in `args` produces a new key and therefore reads no stale entries,
|
|
21
|
+
* while `capabilities` or `idleTimeoutMinutes` leave the key alone.
|
|
22
|
+
*/
|
|
23
|
+
function transportIdentity(transport) {
|
|
24
|
+
if (transport.kind === "stdio") {
|
|
25
|
+
// Env values, not just keys: a server that switches which token or mode it runs
|
|
26
|
+
// under can publish a different tool list under the same command line.
|
|
27
|
+
const env = Object.entries(transport.env)
|
|
28
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
29
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
30
|
+
.join(",");
|
|
31
|
+
return ["stdio", transport.command, transport.args.join(" "), env, transport.cwd ?? ""].join(SEPARATOR);
|
|
32
|
+
}
|
|
33
|
+
const headers = Object.entries(transport.headers)
|
|
34
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
35
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
36
|
+
.join(",");
|
|
37
|
+
return ["http", transport.url, headers, transport.bearerTokenEnv ?? ""].join(SEPARATOR);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The name is part of the key, not only the launch spec. Two servers can share a
|
|
41
|
+
* command (the same binary run twice under different names) and would otherwise
|
|
42
|
+
* collide, the second silently overwriting the first's cached tools.
|
|
43
|
+
*/
|
|
44
|
+
export function serverCacheKey(server) {
|
|
45
|
+
const identity = [server.name, transportIdentity(server.transport)].join(SEPARATOR);
|
|
46
|
+
return createHash("sha256").update(identity).digest("hex").slice(0, 32);
|
|
47
|
+
}
|
|
48
|
+
export class McpMetadataCache {
|
|
49
|
+
file;
|
|
50
|
+
path;
|
|
51
|
+
constructor(path = mcpCachePath()) {
|
|
52
|
+
this.path = path;
|
|
53
|
+
this.file = McpMetadataCache.read(path);
|
|
54
|
+
}
|
|
55
|
+
static read(path) {
|
|
56
|
+
if (!existsSync(path))
|
|
57
|
+
return structuredClone(EMPTY);
|
|
58
|
+
try {
|
|
59
|
+
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
60
|
+
if (parsed?.version !== 1 || typeof parsed.servers !== "object" || parsed.servers === null) {
|
|
61
|
+
return structuredClone(EMPTY);
|
|
62
|
+
}
|
|
63
|
+
return parsed;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return structuredClone(EMPTY);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
get(server) {
|
|
70
|
+
return this.file.servers[serverCacheKey(server)]?.tools ?? [];
|
|
71
|
+
}
|
|
72
|
+
all() {
|
|
73
|
+
return Object.values(this.file.servers).flatMap((entry) => entry.tools);
|
|
74
|
+
}
|
|
75
|
+
set(server, tools) {
|
|
76
|
+
this.file.servers[serverCacheKey(server)] = { name: server.name, tools: [...tools] };
|
|
77
|
+
}
|
|
78
|
+
/** Forget every server absent from `configured`, so a removed server stops appearing in search. */
|
|
79
|
+
prune(configured) {
|
|
80
|
+
const live = new Set(configured.map(serverCacheKey));
|
|
81
|
+
for (const key of Object.keys(this.file.servers)) {
|
|
82
|
+
if (!live.has(key))
|
|
83
|
+
delete this.file.servers[key];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
save() {
|
|
87
|
+
const directory = dirname(this.path);
|
|
88
|
+
mkdirSync(directory, { recursive: true });
|
|
89
|
+
const temporary = join(directory, `.metadata.${process.pid}.tmp`);
|
|
90
|
+
try {
|
|
91
|
+
writeFileSync(temporary, JSON.stringify(this.file));
|
|
92
|
+
renameSync(temporary, this.path);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
rmSync(temporary, { force: true });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=metadata-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata-cache.js","sourceRoot":"","sources":["../../../src/core/mcp/metadata-cache.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Persistent MCP tool metadata, so search and describe answer without a running\n * server. Everything the cache holds is producible from a past connection, which is\n * what makes \"no server needed to search\" a property rather than a convention.\n *\n * One file for every server, not one per server: the whole cache is read once at\n * session start and written whole, and a handful of servers never makes that costly.\n */\n\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { getAgentDir } from \"../../config.ts\";\nimport type { CachedTool, McpServerConfig, McpTransport } from \"./types.ts\";\n\ninterface CacheFile {\n\tversion: 1;\n\tservers: Record<string, { name: string; tools: CachedTool[] }>;\n}\n\nconst EMPTY: CacheFile = { version: 1, servers: {} };\n\nconst SEPARATOR = \"|\";\n\nexport function mcpCachePath(): string {\n\treturn join(getAgentDir(), \"mcp\", \"metadata.json\");\n}\n\n/**\n * Everything that can change which tools a server publishes, and nothing that cannot.\n * A version bump in `args` produces a new key and therefore reads no stale entries,\n * while `capabilities` or `idleTimeoutMinutes` leave the key alone.\n */\nfunction transportIdentity(transport: McpTransport): string {\n\tif (transport.kind === \"stdio\") {\n\t\t// Env values, not just keys: a server that switches which token or mode it runs\n\t\t// under can publish a different tool list under the same command line.\n\t\tconst env = Object.entries(transport.env)\n\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t.map(([key, value]) => `${key}=${value}`)\n\t\t\t.join(\",\");\n\t\treturn [\"stdio\", transport.command, transport.args.join(\" \"), env, transport.cwd ?? \"\"].join(SEPARATOR);\n\t}\n\tconst headers = Object.entries(transport.headers)\n\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t.map(([key, value]) => `${key}=${value}`)\n\t\t.join(\",\");\n\treturn [\"http\", transport.url, headers, transport.bearerTokenEnv ?? \"\"].join(SEPARATOR);\n}\n\n/**\n * The name is part of the key, not only the launch spec. Two servers can share a\n * command (the same binary run twice under different names) and would otherwise\n * collide, the second silently overwriting the first's cached tools.\n */\nexport function serverCacheKey(server: McpServerConfig): string {\n\tconst identity = [server.name, transportIdentity(server.transport)].join(SEPARATOR);\n\treturn createHash(\"sha256\").update(identity).digest(\"hex\").slice(0, 32);\n}\n\nexport class McpMetadataCache {\n\tprivate file: CacheFile;\n\tprivate readonly path: string;\n\n\tconstructor(path: string = mcpCachePath()) {\n\t\tthis.path = path;\n\t\tthis.file = McpMetadataCache.read(path);\n\t}\n\n\tprivate static read(path: string): CacheFile {\n\t\tif (!existsSync(path)) return structuredClone(EMPTY);\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(readFileSync(path, \"utf-8\")) as CacheFile;\n\t\t\tif (parsed?.version !== 1 || typeof parsed.servers !== \"object\" || parsed.servers === null) {\n\t\t\t\treturn structuredClone(EMPTY);\n\t\t\t}\n\t\t\treturn parsed;\n\t\t} catch {\n\t\t\treturn structuredClone(EMPTY);\n\t\t}\n\t}\n\n\tget(server: McpServerConfig): CachedTool[] {\n\t\treturn this.file.servers[serverCacheKey(server)]?.tools ?? [];\n\t}\n\n\tall(): CachedTool[] {\n\t\treturn Object.values(this.file.servers).flatMap((entry) => entry.tools);\n\t}\n\n\tset(server: McpServerConfig, tools: readonly CachedTool[]): void {\n\t\tthis.file.servers[serverCacheKey(server)] = { name: server.name, tools: [...tools] };\n\t}\n\n\t/** Forget every server absent from `configured`, so a removed server stops appearing in search. */\n\tprune(configured: readonly McpServerConfig[]): void {\n\t\tconst live = new Set(configured.map(serverCacheKey));\n\t\tfor (const key of Object.keys(this.file.servers)) {\n\t\t\tif (!live.has(key)) delete this.file.servers[key];\n\t\t}\n\t}\n\n\tsave(): void {\n\t\tconst directory = dirname(this.path);\n\t\tmkdirSync(directory, { recursive: true });\n\t\tconst temporary = join(directory, `.metadata.${process.pid}.tmp`);\n\t\ttry {\n\t\t\twriteFileSync(temporary, JSON.stringify(this.file));\n\t\t\trenameSync(temporary, this.path);\n\t\t} catch {\n\t\t\trmSync(temporary, { force: true });\n\t\t}\n\t}\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assembles the MCP subsystem for one session, or returns undefined when nothing is
|
|
3
|
+
* configured.
|
|
4
|
+
*
|
|
5
|
+
* The undefined case is the point. A session with no `.mcp.json` builds no cache, no
|
|
6
|
+
* manager, and no tool, so its registry and static prompt prefix are identical to a
|
|
7
|
+
* build from before this subsystem existed.
|
|
8
|
+
*/
|
|
9
|
+
import type { McpToolOptions } from "./mcp-tool.ts";
|
|
10
|
+
import type { McpConfigDiagnostic, McpConnector } from "./types.ts";
|
|
11
|
+
export interface McpRuntime extends McpToolOptions {
|
|
12
|
+
diagnostics: readonly McpConfigDiagnostic[];
|
|
13
|
+
/** Connect `eager` servers and cache their tools, so they are discoverable cold. */
|
|
14
|
+
warm(): Promise<void>;
|
|
15
|
+
close(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
export declare function createMcpRuntime(cwd: string, connector?: McpConnector): McpRuntime | undefined;
|
|
18
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEpE,MAAM,WAAW,UAAW,SAAQ,cAAc;IACjD,WAAW,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC5C,oFAAoF;IACpF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,GAAE,YAA+B,GAAG,UAAU,GAAG,SAAS,CAsBhH","sourcesContent":["/**\n * Assembles the MCP subsystem for one session, or returns undefined when nothing is\n * configured.\n *\n * The undefined case is the point. A session with no `.mcp.json` builds no cache, no\n * manager, and no tool, so its registry and static prompt prefix are identical to a\n * build from before this subsystem existed.\n */\n\nimport { join } from \"node:path\";\nimport { loadMcpConfig, PROJECT_CONFIG_FILENAME } from \"./config.ts\";\nimport { connectMcpServer } from \"./connector.ts\";\nimport type { McpToolOptions } from \"./mcp-tool.ts\";\nimport { McpMetadataCache } from \"./metadata-cache.ts\";\nimport { McpServerManager } from \"./server-manager.ts\";\nimport type { McpConfigDiagnostic, McpConnector } from \"./types.ts\";\n\nexport interface McpRuntime extends McpToolOptions {\n\tdiagnostics: readonly McpConfigDiagnostic[];\n\t/** Connect `eager` servers and cache their tools, so they are discoverable cold. */\n\twarm(): Promise<void>;\n\tclose(): Promise<void>;\n}\n\nexport function createMcpRuntime(cwd: string, connector: McpConnector = connectMcpServer): McpRuntime | undefined {\n\tconst { servers, diagnostics } = loadMcpConfig({ projectPath: join(cwd, PROJECT_CONFIG_FILENAME) });\n\tif (servers.size === 0) return undefined;\n\n\tconst cache = new McpMetadataCache();\n\t// A server removed from config stops appearing in search immediately, rather than\n\t// lingering until something happens to overwrite its cache entry.\n\tcache.prune([...servers.values()]);\n\n\tconst manager = new McpServerManager({ servers, connector });\n\n\treturn {\n\t\tservers,\n\t\tcache,\n\t\tmanager,\n\t\tdiagnostics,\n\t\twarm: async () => {\n\t\t\tawait manager.warmEagerServers((server, tools) => cache.set(server, tools));\n\t\t\tcache.save();\n\t\t},\n\t\tclose: () => manager.closeAll(),\n\t};\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assembles the MCP subsystem for one session, or returns undefined when nothing is
|
|
3
|
+
* configured.
|
|
4
|
+
*
|
|
5
|
+
* The undefined case is the point. A session with no `.mcp.json` builds no cache, no
|
|
6
|
+
* manager, and no tool, so its registry and static prompt prefix are identical to a
|
|
7
|
+
* build from before this subsystem existed.
|
|
8
|
+
*/
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { loadMcpConfig, PROJECT_CONFIG_FILENAME } from "./config.js";
|
|
11
|
+
import { connectMcpServer } from "./connector.js";
|
|
12
|
+
import { McpMetadataCache } from "./metadata-cache.js";
|
|
13
|
+
import { McpServerManager } from "./server-manager.js";
|
|
14
|
+
export function createMcpRuntime(cwd, connector = connectMcpServer) {
|
|
15
|
+
const { servers, diagnostics } = loadMcpConfig({ projectPath: join(cwd, PROJECT_CONFIG_FILENAME) });
|
|
16
|
+
if (servers.size === 0)
|
|
17
|
+
return undefined;
|
|
18
|
+
const cache = new McpMetadataCache();
|
|
19
|
+
// A server removed from config stops appearing in search immediately, rather than
|
|
20
|
+
// lingering until something happens to overwrite its cache entry.
|
|
21
|
+
cache.prune([...servers.values()]);
|
|
22
|
+
const manager = new McpServerManager({ servers, connector });
|
|
23
|
+
return {
|
|
24
|
+
servers,
|
|
25
|
+
cache,
|
|
26
|
+
manager,
|
|
27
|
+
diagnostics,
|
|
28
|
+
warm: async () => {
|
|
29
|
+
await manager.warmEagerServers((server, tools) => cache.set(server, tools));
|
|
30
|
+
cache.save();
|
|
31
|
+
},
|
|
32
|
+
close: () => manager.closeAll(),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/core/mcp/runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAUvD,MAAM,UAAU,gBAAgB,CAAC,GAAW,EAAE,SAAS,GAAiB,gBAAgB,EAA0B;IACjH,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,aAAa,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,uBAAuB,CAAC,EAAE,CAAC,CAAC;IACpG,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAEzC,MAAM,KAAK,GAAG,IAAI,gBAAgB,EAAE,CAAC;IACrC,kFAAkF;IAClF,kEAAkE;IAClE,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAEnC,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;IAE7D,OAAO;QACN,OAAO;QACP,KAAK;QACL,OAAO;QACP,WAAW;QACX,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YACjB,MAAM,OAAO,CAAC,gBAAgB,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;YAC5E,KAAK,CAAC,IAAI,EAAE,CAAC;QAAA,CACb;QACD,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE;KAC/B,CAAC;AAAA,CACF","sourcesContent":["/**\n * Assembles the MCP subsystem for one session, or returns undefined when nothing is\n * configured.\n *\n * The undefined case is the point. A session with no `.mcp.json` builds no cache, no\n * manager, and no tool, so its registry and static prompt prefix are identical to a\n * build from before this subsystem existed.\n */\n\nimport { join } from \"node:path\";\nimport { loadMcpConfig, PROJECT_CONFIG_FILENAME } from \"./config.ts\";\nimport { connectMcpServer } from \"./connector.ts\";\nimport type { McpToolOptions } from \"./mcp-tool.ts\";\nimport { McpMetadataCache } from \"./metadata-cache.ts\";\nimport { McpServerManager } from \"./server-manager.ts\";\nimport type { McpConfigDiagnostic, McpConnector } from \"./types.ts\";\n\nexport interface McpRuntime extends McpToolOptions {\n\tdiagnostics: readonly McpConfigDiagnostic[];\n\t/** Connect `eager` servers and cache their tools, so they are discoverable cold. */\n\twarm(): Promise<void>;\n\tclose(): Promise<void>;\n}\n\nexport function createMcpRuntime(cwd: string, connector: McpConnector = connectMcpServer): McpRuntime | undefined {\n\tconst { servers, diagnostics } = loadMcpConfig({ projectPath: join(cwd, PROJECT_CONFIG_FILENAME) });\n\tif (servers.size === 0) return undefined;\n\n\tconst cache = new McpMetadataCache();\n\t// A server removed from config stops appearing in search immediately, rather than\n\t// lingering until something happens to overwrite its cache entry.\n\tcache.prune([...servers.values()]);\n\n\tconst manager = new McpServerManager({ servers, connector });\n\n\treturn {\n\t\tservers,\n\t\tcache,\n\t\tmanager,\n\t\tdiagnostics,\n\t\twarm: async () => {\n\t\t\tawait manager.warmEagerServers((server, tools) => cache.set(server, tools));\n\t\t\tcache.save();\n\t\t},\n\t\tclose: () => manager.closeAll(),\n\t};\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `mcp` tool's parameter schema, and the single source of its param type.
|
|
3
|
+
*
|
|
4
|
+
* It lives apart from the tool itself so the contract (`contract.ts`) can type its
|
|
5
|
+
* permission grammar against the same shape without importing the tool, which would
|
|
6
|
+
* be a cycle: the tool needs the contract.
|
|
7
|
+
*/
|
|
8
|
+
import { type Static, Type } from "typebox";
|
|
9
|
+
export declare const mcpToolSchema: Type.TObject<{
|
|
10
|
+
search: Type.TOptional<Type.TString>;
|
|
11
|
+
server: Type.TOptional<Type.TString>;
|
|
12
|
+
describe: Type.TOptional<Type.TString>;
|
|
13
|
+
tool: Type.TOptional<Type.TString>;
|
|
14
|
+
args: Type.TOptional<Type.TUnknown>;
|
|
15
|
+
}>;
|
|
16
|
+
export type McpToolParams = Static<typeof mcpToolSchema>;
|
|
17
|
+
export interface McpToolDetails {
|
|
18
|
+
action: "search" | "describe" | "list" | "call";
|
|
19
|
+
server: string | undefined;
|
|
20
|
+
tool: string | undefined;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,eAAO,MAAM,aAAa;;;;;;EAmBxB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;IAChD,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;CACzB","sourcesContent":["/**\n * The `mcp` tool's parameter schema, and the single source of its param type.\n *\n * It lives apart from the tool itself so the contract (`contract.ts`) can type its\n * permission grammar against the same shape without importing the tool, which would\n * be a cycle: the tool needs the contract.\n */\n\nimport { type Static, Type } from \"typebox\";\n\nexport const mcpToolSchema = Type.Object({\n\tsearch: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Find tools across configured MCP servers by keyword. Reads a local cache, so it works without starting a server.\",\n\t\t}),\n\t),\n\tserver: Type.Optional(\n\t\tType.String({ description: \"Restrict a search to one server, or list that server's tools when used alone.\" }),\n\t),\n\tdescribe: Type.Optional(\n\t\tType.String({ description: 'Show one tool\\'s full input schema. Qualified as \"<server>:<tool>\".' }),\n\t),\n\ttool: Type.Optional(\n\t\tType.String({\n\t\t\tdescription: 'The tool to call, qualified as \"<server>:<tool>\". Requires the server to be reachable.',\n\t\t}),\n\t),\n\targs: Type.Optional(Type.Unknown({ description: \"Arguments for the called tool, matching its input schema.\" })),\n});\n\nexport type McpToolParams = Static<typeof mcpToolSchema>;\n\nexport interface McpToolDetails {\n\taction: \"search\" | \"describe\" | \"list\" | \"call\";\n\tserver: string | undefined;\n\ttool: string | undefined;\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `mcp` tool's parameter schema, and the single source of its param type.
|
|
3
|
+
*
|
|
4
|
+
* It lives apart from the tool itself so the contract (`contract.ts`) can type its
|
|
5
|
+
* permission grammar against the same shape without importing the tool, which would
|
|
6
|
+
* be a cycle: the tool needs the contract.
|
|
7
|
+
*/
|
|
8
|
+
import { Type } from "typebox";
|
|
9
|
+
export const mcpToolSchema = Type.Object({
|
|
10
|
+
search: Type.Optional(Type.String({
|
|
11
|
+
description: "Find tools across configured MCP servers by keyword. Reads a local cache, so it works without starting a server.",
|
|
12
|
+
})),
|
|
13
|
+
server: Type.Optional(Type.String({ description: "Restrict a search to one server, or list that server's tools when used alone." })),
|
|
14
|
+
describe: Type.Optional(Type.String({ description: 'Show one tool\'s full input schema. Qualified as "<server>:<tool>".' })),
|
|
15
|
+
tool: Type.Optional(Type.String({
|
|
16
|
+
description: 'The tool to call, qualified as "<server>:<tool>". Requires the server to be reachable.',
|
|
17
|
+
})),
|
|
18
|
+
args: Type.Optional(Type.Unknown({ description: "Arguments for the called tool, matching its input schema." })),
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/core/mcp/schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC;IACxC,MAAM,EAAE,IAAI,CAAC,QAAQ,CACpB,IAAI,CAAC,MAAM,CAAC;QACX,WAAW,EACV,kHAAkH;KACnH,CAAC,CACF;IACD,MAAM,EAAE,IAAI,CAAC,QAAQ,CACpB,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,+EAA+E,EAAE,CAAC,CAC7G;IACD,QAAQ,EAAE,IAAI,CAAC,QAAQ,CACtB,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,qEAAqE,EAAE,CAAC,CACnG;IACD,IAAI,EAAE,IAAI,CAAC,QAAQ,CAClB,IAAI,CAAC,MAAM,CAAC;QACX,WAAW,EAAE,wFAAwF;KACrG,CAAC,CACF;IACD,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,2DAA2D,EAAE,CAAC,CAAC;CAC/G,CAAC,CAAC","sourcesContent":["/**\n * The `mcp` tool's parameter schema, and the single source of its param type.\n *\n * It lives apart from the tool itself so the contract (`contract.ts`) can type its\n * permission grammar against the same shape without importing the tool, which would\n * be a cycle: the tool needs the contract.\n */\n\nimport { type Static, Type } from \"typebox\";\n\nexport const mcpToolSchema = Type.Object({\n\tsearch: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Find tools across configured MCP servers by keyword. Reads a local cache, so it works without starting a server.\",\n\t\t}),\n\t),\n\tserver: Type.Optional(\n\t\tType.String({ description: \"Restrict a search to one server, or list that server's tools when used alone.\" }),\n\t),\n\tdescribe: Type.Optional(\n\t\tType.String({ description: 'Show one tool\\'s full input schema. Qualified as \"<server>:<tool>\".' }),\n\t),\n\ttool: Type.Optional(\n\t\tType.String({\n\t\t\tdescription: 'The tool to call, qualified as \"<server>:<tool>\". Requires the server to be reachable.',\n\t\t}),\n\t),\n\targs: Type.Optional(Type.Unknown({ description: \"Arguments for the called tool, matching its input schema.\" })),\n});\n\nexport type McpToolParams = Static<typeof mcpToolSchema>;\n\nexport interface McpToolDetails {\n\taction: \"search\" | \"describe\" | \"list\" | \"call\";\n\tserver: string | undefined;\n\ttool: string | undefined;\n}\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Owns when a server is running and nothing about how it is reached.
|
|
3
|
+
*
|
|
4
|
+
* The `McpConnection` seam is why this module has no MCP SDK import and no child
|
|
5
|
+
* process: lifecycle is the part with the interesting failure modes (a connect that
|
|
6
|
+
* never returns, a broken server retried on every call, two callers racing the same
|
|
7
|
+
* spawn) and all of it is testable against a fake.
|
|
8
|
+
*/
|
|
9
|
+
import type { CachedTool, McpConnection, McpConnector, McpServerConfig, ServerState } from "./types.ts";
|
|
10
|
+
export interface McpServerManagerOptions {
|
|
11
|
+
servers: ReadonlyMap<string, McpServerConfig>;
|
|
12
|
+
connector: McpConnector;
|
|
13
|
+
now?: () => number;
|
|
14
|
+
connectTimeoutMs?: number;
|
|
15
|
+
}
|
|
16
|
+
export declare class McpServerManager {
|
|
17
|
+
private readonly servers;
|
|
18
|
+
private readonly connector;
|
|
19
|
+
private readonly now;
|
|
20
|
+
private readonly connectTimeoutMs;
|
|
21
|
+
private readonly entries;
|
|
22
|
+
constructor(options: McpServerManagerOptions);
|
|
23
|
+
state(name: string): ServerState;
|
|
24
|
+
private entry;
|
|
25
|
+
private connect;
|
|
26
|
+
private acquire;
|
|
27
|
+
withConnection<T>(name: string, use: (connection: McpConnection) => Promise<T>): Promise<T>;
|
|
28
|
+
/**
|
|
29
|
+
* Connect every `eager` server and cache what it publishes.
|
|
30
|
+
*
|
|
31
|
+
* This is the answer to the cold-cache problem. A lazily configured server has no
|
|
32
|
+
* cached tools until something calls one, so it cannot be discovered by search; a
|
|
33
|
+
* user who wants a server discoverable from the first turn declares it `eager`.
|
|
34
|
+
* Failures are swallowed on purpose, because a broken server must not stop a
|
|
35
|
+
* session from starting.
|
|
36
|
+
*/
|
|
37
|
+
warmEagerServers(onTools: (server: McpServerConfig, tools: CachedTool[]) => void): Promise<void>;
|
|
38
|
+
/** Close every `ready` server whose idle window has passed, unless it is kept alive. */
|
|
39
|
+
sweepIdle(): Promise<void>;
|
|
40
|
+
private disconnect;
|
|
41
|
+
closeAll(): Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=server-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-manager.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/server-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAYxG,MAAM,WAAW,uBAAuB;IACvC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC9C,SAAS,EAAE,YAAY,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAMD,qBAAa,gBAAgB;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IAEpD,YAAY,OAAO,EAAE,uBAAuB,EAK3C;IAED,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAE/B;IAED,OAAO,CAAC,KAAK;YASC,OAAO;YAiCP,OAAO;IAkBf,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,aAAa,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAOhG;IAED;;;;;;;;OAQG;IACG,gBAAgB,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAWrG;IAED,wFAAwF;IAClF,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAQ/B;YAEa,UAAU;IAUlB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAI9B;CACD","sourcesContent":["/**\n * Owns when a server is running and nothing about how it is reached.\n *\n * The `McpConnection` seam is why this module has no MCP SDK import and no child\n * process: lifecycle is the part with the interesting failure modes (a connect that\n * never returns, a broken server retried on every call, two callers racing the same\n * spawn) and all of it is testable against a fake.\n */\n\nimport type { CachedTool, McpConnection, McpConnector, McpServerConfig, ServerState } from \"./types.ts\";\n\nconst DEFAULT_CONNECT_TIMEOUT_MS = 30_000;\nconst FAILURE_BACKOFF_MS = 60_000;\n\ninterface Entry {\n\tstate: ServerState;\n\tconnection: McpConnection | undefined;\n\t/** Held so concurrent callers await one spawn instead of racing a second. */\n\tpending: Promise<McpConnection> | undefined;\n}\n\nexport interface McpServerManagerOptions {\n\tservers: ReadonlyMap<string, McpServerConfig>;\n\tconnector: McpConnector;\n\tnow?: () => number;\n\tconnectTimeoutMs?: number;\n}\n\nfunction isKeptAlive(server: McpServerConfig): boolean {\n\treturn server.lifecycle === \"keep-alive\" || server.lifecycle === \"lazy-keep-alive\";\n}\n\nexport class McpServerManager {\n\tprivate readonly servers: ReadonlyMap<string, McpServerConfig>;\n\tprivate readonly connector: McpConnector;\n\tprivate readonly now: () => number;\n\tprivate readonly connectTimeoutMs: number;\n\tprivate readonly entries = new Map<string, Entry>();\n\n\tconstructor(options: McpServerManagerOptions) {\n\t\tthis.servers = options.servers;\n\t\tthis.connector = options.connector;\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.connectTimeoutMs = options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;\n\t}\n\n\tstate(name: string): ServerState {\n\t\treturn this.entries.get(name)?.state ?? { kind: \"disconnected\" };\n\t}\n\n\tprivate entry(name: string): Entry {\n\t\tlet entry = this.entries.get(name);\n\t\tif (!entry) {\n\t\t\tentry = { state: { kind: \"disconnected\" }, connection: undefined, pending: undefined };\n\t\t\tthis.entries.set(name, entry);\n\t\t}\n\t\treturn entry;\n\t}\n\n\tprivate async connect(server: McpServerConfig, entry: Entry): Promise<McpConnection> {\n\t\tentry.state = { kind: \"connecting\", since: this.now() };\n\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\tconst timeout = new Promise<never>((_, reject) => {\n\t\t\ttimer = setTimeout(\n\t\t\t\t() => reject(new Error(`Connecting to MCP server \"${server.name}\" timed out`)),\n\t\t\t\tthis.connectTimeoutMs,\n\t\t\t);\n\t\t});\n\n\t\ttry {\n\t\t\tconst connection = await Promise.race([this.connector(server), timeout]);\n\t\t\tconst at = this.now();\n\t\t\tentry.connection = connection;\n\t\t\tentry.state = { kind: \"ready\", since: at, lastUsed: at };\n\t\t\treturn connection;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tentry.connection = undefined;\n\t\t\tentry.state = {\n\t\t\t\tkind: \"failed\",\n\t\t\t\terror: message,\n\t\t\t\tfailedAt: this.now(),\n\t\t\t\tretryAfter: this.now() + FAILURE_BACKOFF_MS,\n\t\t\t};\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tif (timer) clearTimeout(timer);\n\t\t\tentry.pending = undefined;\n\t\t}\n\t}\n\n\tprivate async acquire(name: string): Promise<McpConnection> {\n\t\tconst server = this.servers.get(name);\n\t\tif (!server) throw new Error(`MCP server \"${name}\" is not configured`);\n\n\t\tconst entry = this.entry(name);\n\t\tif (entry.state.kind === \"ready\" && entry.connection) return entry.connection;\n\t\tif (entry.pending) return entry.pending;\n\n\t\t// A server that just failed is not retried until its window passes, so one\n\t\t// broken server cannot cost every call a spawn attempt.\n\t\tif (entry.state.kind === \"failed\" && this.now() < entry.state.retryAfter) {\n\t\t\tthrow new Error(entry.state.error);\n\t\t}\n\n\t\tentry.pending = this.connect(server, entry);\n\t\treturn entry.pending;\n\t}\n\n\tasync withConnection<T>(name: string, use: (connection: McpConnection) => Promise<T>): Promise<T> {\n\t\tconst connection = await this.acquire(name);\n\t\tconst result = await use(connection);\n\n\t\tconst entry = this.entry(name);\n\t\tif (entry.state.kind === \"ready\") entry.state = { ...entry.state, lastUsed: this.now() };\n\t\treturn result;\n\t}\n\n\t/**\n\t * Connect every `eager` server and cache what it publishes.\n\t *\n\t * This is the answer to the cold-cache problem. A lazily configured server has no\n\t * cached tools until something calls one, so it cannot be discovered by search; a\n\t * user who wants a server discoverable from the first turn declares it `eager`.\n\t * Failures are swallowed on purpose, because a broken server must not stop a\n\t * session from starting.\n\t */\n\tasync warmEagerServers(onTools: (server: McpServerConfig, tools: CachedTool[]) => void): Promise<void> {\n\t\tfor (const server of this.servers.values()) {\n\t\t\tif (server.lifecycle !== \"eager\") continue;\n\t\t\ttry {\n\t\t\t\tawait this.withConnection(server.name, async (connection) => {\n\t\t\t\t\tonTools(server, await connection.listTools());\n\t\t\t\t});\n\t\t\t} catch {\n\t\t\t\t// Recorded as `failed` by `connect`; the next call reports it.\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Close every `ready` server whose idle window has passed, unless it is kept alive. */\n\tasync sweepIdle(): Promise<void> {\n\t\tconst at = this.now();\n\t\tfor (const [name, entry] of this.entries) {\n\t\t\tconst server = this.servers.get(name);\n\t\t\tif (!server || entry.state.kind !== \"ready\" || isKeptAlive(server)) continue;\n\t\t\tif (at - entry.state.lastUsed < server.idleTimeoutMinutes * 60_000) continue;\n\t\t\tawait this.disconnect(name, entry);\n\t\t}\n\t}\n\n\tprivate async disconnect(name: string, entry: Entry): Promise<void> {\n\t\tconst connection = entry.connection;\n\t\tentry.connection = undefined;\n\t\tentry.state = { kind: \"disconnected\" };\n\t\tif (connection) {\n\t\t\tawait connection.close().catch(() => undefined);\n\t\t}\n\t\tthis.entries.set(name, entry);\n\t}\n\n\tasync closeAll(): Promise<void> {\n\t\tfor (const [name, entry] of this.entries) {\n\t\t\tawait this.disconnect(name, entry);\n\t\t}\n\t}\n}\n"]}
|