@ponythewhite/base-context 1.0.0 → 1.0.1
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 +33 -0
- package/NOTICE +0 -5
- package/README.md +44 -27
- package/dist/NOTICE +0 -5
- package/dist/base-context-runtime/pyproject.toml +1 -1
- package/dist/base-context-runtime/src/rlm/__init__.py +7 -5
- package/dist/base-context-runtime/test/test_subagent_registry.py +28 -1
- package/dist/base-context-runtime/uv.lock +1 -1
- package/dist/build-info.json +1 -1
- package/dist/bundle/amazon-bedrock.js +21 -0
- package/dist/bundle/{anthropic-YY4S534V.js → anthropic-UV5GZDGU.js} +5 -5
- package/dist/bundle/{azure-openai-responses-JRP6MIM3.js → azure-openai-responses-WSNPXLYC.js} +6 -6
- package/dist/bundle/{bundled-modules-P5HARVZA.js → bundled-modules-TXUMJ2XQ.js} +71 -16
- package/dist/bundle/chunk-27QCJ2AZ.js +2578 -0
- package/dist/bundle/{chunk-MZHTNNVA.js → chunk-4GXPNXOJ.js} +8 -0
- package/dist/bundle/{chunk-SC5KG5R4.js → chunk-DGNX7HQ3.js} +1 -7
- package/dist/bundle/{chunk-A53O363M.js → chunk-GRJFXLBM.js} +0 -1
- package/dist/bundle/chunk-HKINIBP4.js +29 -0
- package/dist/bundle/{chunk-UDSW6FNG.js → chunk-KTNETTHI.js} +1 -1
- package/dist/bundle/{chunk-BYVP7LWV.js → chunk-S3INFPZZ.js} +1861 -4662
- package/dist/bundle/{chunk-73DCPU3D.js → chunk-V3L54UD6.js} +1019 -3427
- package/dist/bundle/{chunk-U7AUVG3B.js → chunk-VSIYFWYI.js} +24 -6
- package/dist/bundle/{chunk-IW77OXFS.js → chunk-W46VZFI6.js} +0 -2099
- package/dist/bundle/{cli-main-O4X7GFGY.js → cli-main-BYMSRPH6.js} +8 -6
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/{google-AUTVGDGZ.js → google-T32FMD4G.js} +6 -6
- package/dist/bundle/{google-vertex-Q75D7RKS.js → google-vertex-56KP6I3B.js} +3 -3
- package/dist/bundle/{main-XKOW2BV6.js → main-ODOYCEQC.js} +7 -5
- package/dist/bundle/{mistral-7ESB7QUD.js → mistral-WGBMYIVU.js} +5 -5
- package/dist/bundle/{openai-codex-responses-LV3QRPN4.js → openai-codex-responses-PIV2RQ3G.js} +6 -6
- package/dist/bundle/{openai-completions-OJECLPXJ.js → openai-completions-64C3JPR4.js} +11 -22
- package/dist/bundle/{openai-responses-FN6HZMBC.js → openai-responses-UI7RSTDV.js} +6 -6
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +108 -59
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/daemon-ps.d.ts +4 -3
- package/dist/cli/daemon-ps.d.ts.map +1 -1
- package/dist/cli/daemon-ps.js +6 -1
- package/dist/cli/daemon-ps.js.map +1 -1
- package/dist/cli/product-doctor.d.ts +0 -1
- package/dist/cli/product-doctor.d.ts.map +1 -1
- package/dist/cli/product-doctor.js +6 -3
- package/dist/cli/product-doctor.js.map +1 -1
- package/dist/config.d.ts +0 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -8
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-config.d.ts +1 -2
- package/dist/core/agent-session-config.d.ts.map +1 -1
- package/dist/core/agent-session-config.js +0 -3
- package/dist/core/agent-session-config.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +5 -4
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +5 -3
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +2 -27
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +10 -6
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +107 -107
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +8 -35
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +33 -243
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/cron-jobs.d.ts.map +1 -1
- package/dist/core/cron-jobs.js +7 -1
- package/dist/core/cron-jobs.js.map +1 -1
- package/dist/core/inference-coordinator.d.ts +6 -1
- package/dist/core/inference-coordinator.d.ts.map +1 -1
- package/dist/core/inference-coordinator.js +18 -2
- package/dist/core/inference-coordinator.js.map +1 -1
- package/dist/core/kernel/bootstrap.d.ts.map +1 -1
- package/dist/core/kernel/bootstrap.js +2 -2
- package/dist/core/kernel/bootstrap.js.map +1 -1
- package/dist/core/kernel/repl-manager.d.ts +2 -0
- package/dist/core/kernel/repl-manager.d.ts.map +1 -1
- package/dist/core/kernel/repl-manager.js +44 -1
- package/dist/core/kernel/repl-manager.js.map +1 -1
- package/dist/core/logging.d.ts +4 -3
- package/dist/core/logging.d.ts.map +1 -1
- package/dist/core/logging.js +6 -6
- package/dist/core/logging.js.map +1 -1
- package/dist/core/mcp/mcp-manager.d.ts.map +1 -1
- package/dist/core/mcp/mcp-manager.js +3 -3
- package/dist/core/mcp/mcp-manager.js.map +1 -1
- package/dist/core/model-registry.d.ts +1 -16
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +88 -196
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +2 -19
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +36 -266
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/provider-contracts.d.ts +5 -6
- package/dist/core/provider-contracts.d.ts.map +1 -1
- package/dist/core/provider-contracts.js +25 -36
- package/dist/core/provider-contracts.js.map +1 -1
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/provider-display-names.js +0 -2
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/rlm-max-subagents.d.ts +32 -0
- package/dist/core/rlm-max-subagents.d.ts.map +1 -0
- package/dist/core/rlm-max-subagents.js +50 -0
- package/dist/core/rlm-max-subagents.js.map +1 -0
- package/dist/core/rlm-runtime.d.ts +3 -3
- package/dist/core/rlm-runtime.d.ts.map +1 -1
- package/dist/core/rlm-runtime.js.map +1 -1
- package/dist/core/sdk.d.ts +4 -3
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +27 -14
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -16
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +12 -44
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +6 -6
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/installer.mjs +2 -3
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +39 -34
- package/dist/main.js.map +1 -1
- package/dist/modes/acp/acp-mode.d.ts.map +1 -1
- package/dist/modes/acp/acp-mode.js +1 -1
- package/dist/modes/acp/acp-mode.js.map +1 -1
- package/dist/modes/agent-connection/daemon-agent-connection.d.ts +6 -2
- package/dist/modes/agent-connection/daemon-agent-connection.d.ts.map +1 -1
- package/dist/modes/agent-connection/daemon-agent-connection.js +13 -2
- package/dist/modes/agent-connection/daemon-agent-connection.js.map +1 -1
- package/dist/modes/agent-connection/in-process-agent-connection.d.ts +2 -0
- package/dist/modes/agent-connection/in-process-agent-connection.d.ts.map +1 -1
- package/dist/modes/agent-connection/in-process-agent-connection.js +6 -0
- package/dist/modes/agent-connection/in-process-agent-connection.js.map +1 -1
- package/dist/modes/agent-connection/types.d.ts +3 -0
- package/dist/modes/agent-connection/types.d.ts.map +1 -1
- package/dist/modes/agent-connection/types.js.map +1 -1
- package/dist/modes/agents-view/agents-view-mode.d.ts.map +1 -1
- package/dist/modes/agents-view/agents-view-mode.js +2 -19
- package/dist/modes/agents-view/agents-view-mode.js.map +1 -1
- package/dist/modes/daemon/daemon-mode.d.ts +5 -0
- package/dist/modes/daemon/daemon-mode.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-mode.js +107 -12
- package/dist/modes/daemon/daemon-mode.js.map +1 -1
- package/dist/modes/daemon/daemon-protocol.d.ts +194 -165
- package/dist/modes/daemon/daemon-protocol.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-protocol.js +16 -11
- package/dist/modes/daemon/daemon-protocol.js.map +1 -1
- package/dist/modes/daemon/daemon-rlm-capacity-coordinator.d.ts +19 -0
- package/dist/modes/daemon/daemon-rlm-capacity-coordinator.d.ts.map +1 -0
- package/dist/modes/daemon/daemon-rlm-capacity-coordinator.js +74 -0
- package/dist/modes/daemon/daemon-rlm-capacity-coordinator.js.map +1 -0
- package/dist/modes/daemon/daemon-rlm-capacity.d.ts +19 -0
- package/dist/modes/daemon/daemon-rlm-capacity.d.ts.map +1 -0
- package/dist/modes/daemon/daemon-rlm-capacity.js +85 -0
- package/dist/modes/daemon/daemon-rlm-capacity.js.map +1 -0
- package/dist/modes/daemon/daemon-session-summarizer.d.ts +2 -3
- package/dist/modes/daemon/daemon-session-summarizer.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-session-summarizer.js +32 -23
- package/dist/modes/daemon/daemon-session-summarizer.js.map +1 -1
- package/dist/modes/daemon/daemon-state-root.d.ts +15 -0
- package/dist/modes/daemon/daemon-state-root.d.ts.map +1 -0
- package/dist/modes/daemon/daemon-state-root.js +40 -0
- package/dist/modes/daemon/daemon-state-root.js.map +1 -0
- package/dist/modes/daemon/daemon-supervisor-ownership.d.ts +2 -0
- package/dist/modes/daemon/daemon-supervisor-ownership.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-supervisor-ownership.js +27 -0
- package/dist/modes/daemon/daemon-supervisor-ownership.js.map +1 -1
- package/dist/modes/daemon/daemon-supervisor.d.ts +10 -1
- package/dist/modes/daemon/daemon-supervisor.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-supervisor.js +213 -20
- package/dist/modes/daemon/daemon-supervisor.js.map +1 -1
- package/dist/modes/daemon/daemon-worker-protocol.d.ts +28 -1
- package/dist/modes/daemon/daemon-worker-protocol.d.ts.map +1 -1
- package/dist/modes/daemon/daemon-worker-protocol.js +16 -2
- package/dist/modes/daemon/daemon-worker-protocol.js.map +1 -1
- package/dist/modes/daemon/saved-session-catalog.d.ts.map +1 -1
- package/dist/modes/daemon/saved-session-catalog.js +2 -0
- package/dist/modes/daemon/saved-session-catalog.js.map +1 -1
- package/dist/modes/interactive/auth-flows.d.ts +0 -6
- package/dist/modes/interactive/auth-flows.d.ts.map +1 -1
- package/dist/modes/interactive/auth-flows.js +6 -126
- package/dist/modes/interactive/auth-flows.js.map +1 -1
- package/dist/modes/interactive/components/configuration-menu.d.ts +3 -0
- package/dist/modes/interactive/components/configuration-menu.d.ts.map +1 -1
- package/dist/modes/interactive/components/configuration-menu.js +13 -2
- package/dist/modes/interactive/components/configuration-menu.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +2 -2
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +0 -1
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +0 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +0 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +3 -40
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +2 -0
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +13 -2
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +2 -11
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/feature-hints.d.ts.map +1 -1
- package/dist/modes/interactive/feature-hints.js +0 -4
- package/dist/modes/interactive/feature-hints.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +3 -12
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +81 -507
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/onboarding.d.ts +0 -3
- package/dist/modes/interactive/onboarding.d.ts.map +1 -1
- package/dist/modes/interactive/onboarding.js +0 -17
- package/dist/modes/interactive/onboarding.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +2 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +24 -11
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/node/amazon-bedrock.d.ts +2 -0
- package/dist/node/amazon-bedrock.d.ts.map +1 -0
- package/dist/node/amazon-bedrock.js +6 -0
- package/dist/node/amazon-bedrock.js.map +1 -0
- package/dist/product-identity.d.ts +0 -1
- package/dist/product-identity.d.ts.map +1 -1
- package/dist/product-identity.js +0 -1
- package/dist/product-identity.js.map +1 -1
- package/docs/development.md +1 -1
- package/docs/fork-philosophy.md +4 -8
- package/docs/installation.md +83 -62
- package/docs/providers.md +23 -25
- package/docs/quickstart.md +19 -10
- package/docs/rlm-runtime.md +13 -5
- package/docs/rpc.md +4 -4
- package/docs/sdk.md +20 -11
- package/docs/sessions.md +0 -1
- package/docs/settings.md +9 -42
- package/docs/skills.md +0 -1
- package/docs/upstream-0.9.5.md +171 -0
- package/docs/usage.md +14 -10
- package/package.json +4 -4
- package/dist/core/agent-traces.d.ts +0 -149
- package/dist/core/agent-traces.d.ts.map +0 -1
- package/dist/core/agent-traces.js +0 -904
- package/dist/core/agent-traces.js.map +0 -1
- package/dist/core/prime-inference-auth.d.ts +0 -70
- package/dist/core/prime-inference-auth.d.ts.map +0 -1
- package/dist/core/prime-inference-auth.js +0 -352
- package/dist/core/prime-inference-auth.js.map +0 -1
- package/dist/core/prime-inference-model-selection.d.ts +0 -16
- package/dist/core/prime-inference-model-selection.d.ts.map +0 -1
- package/dist/core/prime-inference-model-selection.js +0 -16
- package/dist/core/prime-inference-model-selection.js.map +0 -1
- package/dist/core/prime-inference-models.d.ts +0 -6
- package/dist/core/prime-inference-models.d.ts.map +0 -1
- package/dist/core/prime-inference-models.js +0 -62
- package/dist/core/prime-inference-models.js.map +0 -1
- package/dist/core/telemetry.d.ts +0 -95
- package/dist/core/telemetry.d.ts.map +0 -1
- package/dist/core/telemetry.js +0 -637
- package/dist/core/telemetry.js.map +0 -1
- package/dist/modes/interactive/components/prime-onboarding-splash.d.ts +0 -39
- package/dist/modes/interactive/components/prime-onboarding-splash.d.ts.map +0 -1
- package/dist/modes/interactive/components/prime-onboarding-splash.js +0 -286
- package/dist/modes/interactive/components/prime-onboarding-splash.js.map +0 -1
- package/dist/modes/interactive/components/prime-team-selector.d.ts +0 -30
- package/dist/modes/interactive/components/prime-team-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/prime-team-selector.js +0 -166
- package/dist/modes/interactive/components/prime-team-selector.js.map +0 -1
- package/dist/skills/prime-intellect/SKILL.md +0 -87
- package/dist/skills/prime-intellect/references/compute.md +0 -45
- package/dist/skills/prime-intellect/references/environments.md +0 -73
- package/dist/skills/prime-intellect/references/inference.md +0 -47
- package/dist/skills/prime-intellect/references/sandboxes.md +0 -75
- package/skills/prime-intellect/SKILL.md +0 -87
- package/skills/prime-intellect/references/compute.md +0 -45
- package/skills/prime-intellect/references/environments.md +0 -73
- package/skills/prime-intellect/references/inference.md +0 -47
- package/skills/prime-intellect/references/sandboxes.md +0 -75
package/dist/core/logging.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { type LogEntry } from "@ponythewhite/base-context-ai";
|
|
1
2
|
/** Merge late-bound fields (e.g. mode, sessionId) into every subsequent log entry. */
|
|
2
3
|
export declare function setLogContext(fields: Record<string, unknown>): void;
|
|
4
|
+
export declare function writeFileLogEntry(entry: LogEntry): void;
|
|
3
5
|
/**
|
|
4
|
-
* Route
|
|
5
|
-
*
|
|
6
|
-
* pid/context fields; writes are best-effort and size-bounded.
|
|
6
|
+
* Route coding-agent and AI logs to the owned local agent log.
|
|
7
|
+
* Writes include the current pid/session context and remain size-bounded.
|
|
7
8
|
*/
|
|
8
9
|
export declare function installFileLogSink(fields?: Record<string, unknown>): void;
|
|
9
10
|
//# sourceMappingURL=logging.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../src/core/logging.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logging.d.ts","sourceRoot":"","sources":["../../src/core/logging.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAiC,MAAM,+BAA+B,CAAC;AAO7F,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAEnE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAEvD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAGzE","sourcesContent":["import { type LogEntry, setLogSink, stringifyLogEntry } from \"@ponythewhite/base-context-ai\";\nimport { appendRotatingLog, getAgentLogPath } from \"../config.js\";\n\nconst AGENT_LOG_MAX_BYTES = 20 * 1024 * 1024;\n\nlet context: Record<string, unknown> = {};\n\n/** Merge late-bound fields (e.g. mode, sessionId) into every subsequent log entry. */\nexport function setLogContext(fields: Record<string, unknown>): void {\n\tObject.assign(context, fields);\n}\n\nexport function writeFileLogEntry(entry: LogEntry): void {\n\tappendRotatingLog(getAgentLogPath(), stringifyLogEntry({ ...entry, ...context }), AGENT_LOG_MAX_BYTES);\n}\n\n/**\n * Route coding-agent and AI logs to the owned local agent log.\n * Writes include the current pid/session context and remain size-bounded.\n */\nexport function installFileLogSink(fields?: Record<string, unknown>): void {\n\tcontext = { pid: process.pid, ...fields };\n\tsetLogSink(writeFileLogEntry);\n}\n"]}
|
package/dist/core/logging.js
CHANGED
|
@@ -6,15 +6,15 @@ let context = {};
|
|
|
6
6
|
export function setLogContext(fields) {
|
|
7
7
|
Object.assign(context, fields);
|
|
8
8
|
}
|
|
9
|
+
export function writeFileLogEntry(entry) {
|
|
10
|
+
appendRotatingLog(getAgentLogPath(), stringifyLogEntry({ ...entry, ...context }), AGENT_LOG_MAX_BYTES);
|
|
11
|
+
}
|
|
9
12
|
/**
|
|
10
|
-
* Route
|
|
11
|
-
*
|
|
12
|
-
* pid/context fields; writes are best-effort and size-bounded.
|
|
13
|
+
* Route coding-agent and AI logs to the owned local agent log.
|
|
14
|
+
* Writes include the current pid/session context and remain size-bounded.
|
|
13
15
|
*/
|
|
14
16
|
export function installFileLogSink(fields) {
|
|
15
17
|
context = { pid: process.pid, ...fields };
|
|
16
|
-
setLogSink(
|
|
17
|
-
appendRotatingLog(getAgentLogPath(), stringifyLogEntry({ ...entry, ...context }), AGENT_LOG_MAX_BYTES);
|
|
18
|
-
});
|
|
18
|
+
setLogSink(writeFileLogEntry);
|
|
19
19
|
}
|
|
20
20
|
//# sourceMappingURL=logging.js.map
|
package/dist/core/logging.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logging.js","sourceRoot":"","sources":["../../src/core/logging.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,UAAU,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAElE,MAAM,mBAAmB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAE7C,IAAI,OAAO,GAA4B,EAAE,CAAC;AAE1C,sFAAsF;AACtF,MAAM,UAAU,aAAa,CAAC,MAA+B,EAAQ;IACpE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAAA,CAC/B;AAED
|
|
1
|
+
{"version":3,"file":"logging.js","sourceRoot":"","sources":["../../src/core/logging.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,UAAU,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAElE,MAAM,mBAAmB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAE7C,IAAI,OAAO,GAA4B,EAAE,CAAC;AAE1C,sFAAsF;AACtF,MAAM,UAAU,aAAa,CAAC,MAA+B,EAAQ;IACpE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAAA,CAC/B;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAe,EAAQ;IACxD,iBAAiB,CAAC,eAAe,EAAE,EAAE,iBAAiB,CAAC,EAAE,GAAG,KAAK,EAAE,GAAG,OAAO,EAAE,CAAC,EAAE,mBAAmB,CAAC,CAAC;AAAA,CACvG;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAgC,EAAQ;IAC1E,OAAO,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;IAC1C,UAAU,CAAC,iBAAiB,CAAC,CAAC;AAAA,CAC9B","sourcesContent":["import { type LogEntry, setLogSink, stringifyLogEntry } from \"@ponythewhite/base-context-ai\";\nimport { appendRotatingLog, getAgentLogPath } from \"../config.js\";\n\nconst AGENT_LOG_MAX_BYTES = 20 * 1024 * 1024;\n\nlet context: Record<string, unknown> = {};\n\n/** Merge late-bound fields (e.g. mode, sessionId) into every subsequent log entry. */\nexport function setLogContext(fields: Record<string, unknown>): void {\n\tObject.assign(context, fields);\n}\n\nexport function writeFileLogEntry(entry: LogEntry): void {\n\tappendRotatingLog(getAgentLogPath(), stringifyLogEntry({ ...entry, ...context }), AGENT_LOG_MAX_BYTES);\n}\n\n/**\n * Route coding-agent and AI logs to the owned local agent log.\n * Writes include the current pid/session context and remain size-bounded.\n */\nexport function installFileLogSink(fields?: Record<string, unknown>): void {\n\tcontext = { pid: process.pid, ...fields };\n\tsetLogSink(writeFileLogEntry);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-manager.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/mcp-manager.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,MAAM,WAAW,iBAAiB;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,qFAAmF;IACnF,cAAc,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;IACnE,kFAAkF;IAClF,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAcD,qBAAa,UAAU;IACtB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoD;IACnF,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAoC;IAChE,OAAO,CAAC,YAAY,CAA0C;IAC9D,OAAO,CAAC,UAAU,CAAyC;IAC3D,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,qFAAqF;IACrF,OAAO,CAAC,yBAAyB,CAAqB;IAEtD,YAAY,OAAO,EAAE,iBAAiB,EAMrC;IAED,+EAA+E;IAC/E,OAAO,IAAI,IAAI,CAGd;IAED,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE7C;IAED,iBAAiB,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAqBlF;IAED,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,mBAAmB;IAsB3B,OAAO,CAAC,iBAAiB;IAKzB;;;;OAIG;IACH,qBAAqB,IAAI,IAAI,CAuB5B;IAED,iFAAiF;IACjF,OAAO,CAAC,QAAQ;IAoBhB,gGAAgG;IAChG,gCAAgC,IAAI,MAAM,EAAE,CAS3C;IAED,mDAAmD;IACnD,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAgDrG;IAED,gEAAgE;IAChE,aAAa,IAAI,kBAAkB,EAAE,CAEpC;IAED,8EAA8E;IAC9E,kCAAkC,IAAI,MAAM,EAAE,CAW7C;IAED,wCAAwC;IACxC,UAAU,IAAI,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAO3F;CACD","sourcesContent":["// Host side of MCP integrations. The protocol itself runs Python-side in the kernel; the host\n// only registers OAuth providers, gates integration skills by auth, and serves mcp.* host-requests.\n\nimport {\n\tBUILTIN_MCP_CATALOG,\n\tcreateMcpOAuthProvider,\n\tgetCatalogEntry,\n\tregisterBuiltinMcpOAuthProviders,\n} from \"@ponythewhite/base-context-ai/mcp\";\nimport { registerOAuthProvider, unregisterOAuthProvider } from \"@ponythewhite/base-context-ai/oauth\";\nimport type { AuthStorage } from \"../auth-storage.js\";\nimport { getProviderAuthContract } from \"../provider-contracts.js\";\nimport type { McpServerConfig } from \"../settings-manager.js\";\nimport type { AcpMcpServerConfig } from \"./acp-mcp-types.js\";\n\nexport interface McpManagerOptions {\n\tauthStorage: AuthStorage;\n\t/** Reads the current Settings.mcpServers (name → config). Re-read on refresh(). */\n\tgetUserServers?: () => Record<string, McpServerConfig> | undefined;\n\t/** Start an interactive host-side login for a server. Provided by the UI mode. */\n\tbeginLogin?: (server: string) => Promise<void>;\n}\n\n/** A resolved integration: a catalog/user entry plus its provider id. */\nconst GENERIC_SERVER_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;\n\ninterface ResolvedIntegration {\n\tserver: string;\n\tlabel: string;\n\tconfig: McpServerConfig;\n\tusesOAuth: boolean;\n\t/** True when this came from Settings.mcpServers (may override a catalog name). */\n\tuserDeclared?: boolean;\n}\n\nexport class McpManager {\n\tprivate readonly authStorage: AuthStorage;\n\tprivate readonly getUserServers: () => Record<string, McpServerConfig> | undefined;\n\tprivate readonly beginLogin?: (server: string) => Promise<void>;\n\tprivate integrations = new Map<string, ResolvedIntegration>();\n\tprivate acpServers = new Map<string, AcpMcpServerConfig>();\n\tprivate acpOwnerId?: string;\n\t/** Provider ids we registered for user servers, so refresh can drop removed ones. */\n\tprivate registeredUserProviderIds = new Set<string>();\n\n\tconstructor(options: McpManagerOptions) {\n\t\tthis.authStorage = options.authStorage;\n\t\tthis.getUserServers = options.getUserServers ?? (() => undefined);\n\t\tthis.beginLogin = options.beginLogin;\n\t\tthis.resolveIntegrations();\n\t\tthis.registerProviders();\n\t}\n\n\t/** Re-read settings and re-register providers; call after a session reload. */\n\trefresh(): void {\n\t\tthis.resolveIntegrations();\n\t\tthis.registerProviders();\n\t}\n\n\tcanReleaseAcpServers(ownerId: string): boolean {\n\t\treturn this.acpOwnerId === undefined || this.acpOwnerId === ownerId;\n\t}\n\n\treplaceAcpServers(servers: readonly AcpMcpServerConfig[], ownerId: string): boolean {\n\t\tif (!ownerId) throw new Error(\"ACP MCP owner id is required\");\n\t\tif (servers.length === 0 && this.acpOwnerId !== ownerId) return false;\n\t\tif (servers.length > 0 && this.acpOwnerId && this.acpOwnerId !== ownerId) {\n\t\t\tthrow new Error(\"ACP MCP configuration is owned by another client\");\n\t\t}\n\n\t\tconst next = new Map<string, AcpMcpServerConfig>();\n\t\tfor (const server of servers) {\n\t\t\tif (next.has(server.name)) throw new Error(`Duplicate ACP MCP server: ${server.name}`);\n\t\t\tnext.set(server.name, server);\n\t\t}\n\t\tconst unchanged =\n\t\t\tnext.size === this.acpServers.size &&\n\t\t\tArray.from(next).every(\n\t\t\t\t([name, config]) => JSON.stringify(this.acpServers.get(name)) === JSON.stringify(config),\n\t\t\t);\n\t\tif (unchanged) return false;\n\t\tthis.acpServers = next;\n\t\tthis.acpOwnerId = next.size > 0 ? ownerId : undefined;\n\t\treturn true;\n\t}\n\n\tprivate providerId(server: string): string {\n\t\treturn `mcp:${server}`;\n\t}\n\n\tprivate resolveIntegrations(): void {\n\t\tconst integrations = new Map<string, ResolvedIntegration>();\n\t\tfor (const entry of BUILTIN_MCP_CATALOG) {\n\t\t\tintegrations.set(entry.server, {\n\t\t\t\tserver: entry.server,\n\t\t\t\tlabel: entry.label,\n\t\t\t\tconfig: { type: \"http\", url: entry.url, oauth: true },\n\t\t\t\tusesOAuth: entry.oauth?.kind === \"oauth\",\n\t\t\t});\n\t\t}\n\t\tfor (const [server, config] of Object.entries(this.getUserServers() ?? {})) {\n\t\t\tintegrations.set(server, {\n\t\t\t\tserver,\n\t\t\t\tlabel: server,\n\t\t\t\tconfig,\n\t\t\t\tusesOAuth: config.type === \"http\" && config.oauth === true,\n\t\t\t\tuserDeclared: true,\n\t\t\t});\n\t\t}\n\t\tthis.integrations = integrations;\n\t}\n\n\tprivate registerProviders(): void {\n\t\tregisterBuiltinMcpOAuthProviders();\n\t\tthis.registerUserProviders();\n\t}\n\n\t/**\n\t * Register OAuth providers for user-declared (non-catalog) servers. Public so it\n\t * can run after ModelRegistry.refresh() resets the registry — otherwise custom\n\t * `mcp:<server>` providers vanish on every refresh (e.g. post-login).\n\t */\n\tregisterUserProviders(): void {\n\t\tconst current = new Set<string>();\n\t\tfor (const integration of this.integrations.values()) {\n\t\t\tif (!integration.userDeclared || integration.config.type !== \"http\" || getCatalogEntry(integration.server)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst id = this.providerId(integration.server);\n\t\t\tif (integration.usesOAuth) {\n\t\t\t\tcurrent.add(id);\n\t\t\t\tregisterOAuthProvider(\n\t\t\t\t\tcreateMcpOAuthProvider({\n\t\t\t\t\t\tserver: integration.server,\n\t\t\t\t\t\tlabel: integration.label,\n\t\t\t\t\t\turl: integration.config.url,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\t// Drop providers for user servers removed since the last registration.\n\t\tfor (const id of this.registeredUserProviderIds) {\n\t\t\tif (!current.has(id)) unregisterOAuthProvider(id);\n\t\t}\n\t\tthis.registeredUserProviderIds = current;\n\t}\n\n\t/** True when valid credentials exist for the integration (drives enablement). */\n\tprivate isAuthed(integration: ResolvedIntegration): boolean {\n\t\tif (integration.config.enabled === false) return false;\n\t\tif (integration.userDeclared && getCatalogEntry(integration.server)) return false;\n\t\tif (integration.config.type === \"stdio\") return true;\n\t\tconst { bearerTokenEnvVar } = integration.config;\n\t\tif (!integration.usesOAuth && !bearerTokenEnvVar) return true;\n\t\tif (bearerTokenEnvVar && process.env[bearerTokenEnvVar]?.trim()) {\n\t\t\treturn true;\n\t\t}\n\t\tconst providerId = this.providerId(integration.server);\n\t\tconst cred = this.authStorage.get(providerId);\n\t\tif (cred === undefined) return false;\n\t\tif (cred.type === \"oauth\" && getProviderAuthContract(providerId).oauth !== \"validated\") return false;\n\t\t// Builtin URLs are code-constant; only user-declared endpoints can be retargeted, so only their\n\t\t// tokens must prove where they belong. Mismatched or unbound tokens require re-login.\n\t\tif (!integration.userDeclared) return true;\n\t\tconst endpoint = (cred as { endpoint?: string }).endpoint;\n\t\treturn typeof endpoint === \"string\" && endpoint === integration.config.url;\n\t}\n\n\t/** `-<server>/SKILL.md` overrides for every built-in integration the user isn't logged into. */\n\tgetDisabledBuiltinSkillOverrides(): string[] {\n\t\tconst overrides: string[] = [];\n\t\tfor (const entry of BUILTIN_MCP_CATALOG) {\n\t\t\tconst integration = this.integrations.get(entry.server);\n\t\t\tif (integration && !this.isAuthed(integration)) {\n\t\t\t\toverrides.push(`-${entry.server}/SKILL.md`);\n\t\t\t}\n\t\t}\n\t\treturn overrides;\n\t}\n\n\t/** Host-request handlers exposed to the kernel. */\n\thostHandlers(): Record<string, (payload: Record<string, unknown>) => Promise<Record<string, unknown>>> {\n\t\tconst handlers: Record<string, (payload: Record<string, unknown>) => Promise<Record<string, unknown>>> = {\n\t\t\t\"mcp.refresh\": async (payload) => {\n\t\t\t\tconst server = String(payload.server ?? \"\");\n\t\t\t\tif (!server) throw new Error(\"mcp.refresh requires a server\");\n\t\t\t\tif (this.acpServers.has(server)) throw new Error(`ACP MCP server ${server} does not use host OAuth`);\n\t\t\t\t// getApiKey refreshes + rewrites auth.json under lock; Python re-reads.\n\t\t\t\t// Surface failure (throw) instead of a false success so the kernel can\n\t\t\t\t// report a refresh error rather than a misleading \"not enabled\".\n\t\t\t\tconst providerId = this.providerId(server);\n\t\t\t\tconst key = await this.authStorage.getApiKey(providerId);\n\t\t\t\tif (!key) {\n\t\t\t\t\tconst contract = getProviderAuthContract(providerId);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tcontract.oauth === \"validated\" ? `Could not refresh credentials for ${server}` : contract.guidance,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn {};\n\t\t\t},\n\t\t\t// Resolved config so the kernel skill connects to the same URL the host\n\t\t\t// registered/authenticated (honors a user's mcpServers `url` override).\n\t\t\t\"mcp.config\": async (payload) => {\n\t\t\t\tconst server = String(payload.server ?? \"\");\n\t\t\t\tif (!server) throw new Error(\"mcp.config requires a server\");\n\t\t\t\tconst acpServer = this.acpServers.get(server);\n\t\t\t\tif (acpServer) {\n\t\t\t\t\tconst { name: _name, ...config } = acpServer;\n\t\t\t\t\treturn { ...config, credentialSource: \"acp\" };\n\t\t\t\t}\n\t\t\t\tconst integration = this.integrations.get(server);\n\t\t\t\tif (!integration?.userDeclared || getCatalogEntry(server)) return {};\n\t\t\t\treturn { ...integration.config };\n\t\t\t},\n\t\t};\n\t\t// Only expose begin_login when an interactive login is actually wired, so the\n\t\t// kernel doesn't get a handler whose only behavior is to throw.\n\t\tconst beginLogin = this.beginLogin;\n\t\tif (beginLogin) {\n\t\t\thandlers[\"mcp.begin_login\"] = async (payload) => {\n\t\t\t\tconst server = String(payload.server ?? \"\");\n\t\t\t\tif (!server) throw new Error(\"mcp.begin_login requires a server\");\n\t\t\t\tconst contract = getProviderAuthContract(this.providerId(server));\n\t\t\t\tif (contract.oauth !== \"validated\") throw new Error(contract.guidance);\n\t\t\t\tawait beginLogin(server);\n\t\t\t\treturn {};\n\t\t\t};\n\t\t}\n\t\treturn handlers;\n\t}\n\n\t/** Session-scoped servers supplied by the active ACP client. */\n\tgetAcpServers(): AcpMcpServerConfig[] {\n\t\treturn [...this.acpServers.values()];\n\t}\n\n\t/** Enabled user-declared servers available through the generic kernel API. */\n\tgetEnabledPersistentGenericServers(): string[] {\n\t\treturn Array.from(this.integrations.values())\n\t\t\t.filter(\n\t\t\t\t(integration) =>\n\t\t\t\t\tintegration.userDeclared &&\n\t\t\t\t\tGENERIC_SERVER_NAME_PATTERN.test(integration.server) &&\n\t\t\t\t\t!getCatalogEntry(integration.server) &&\n\t\t\t\t\tthis.isAuthed(integration),\n\t\t\t)\n\t\t\t.map((integration) => integration.server)\n\t\t\t.sort((left, right) => left.localeCompare(right));\n\t}\n\n\t/** Status for the /mcp list command. */\n\tlistStatus(): Array<{ server: string; label: string; enabled: boolean; usesOAuth: boolean }> {\n\t\treturn Array.from(this.integrations.values()).map((integration) => ({\n\t\t\tserver: integration.server,\n\t\t\tlabel: integration.label,\n\t\t\tenabled: this.isAuthed(integration),\n\t\t\tusesOAuth: integration.usesOAuth,\n\t\t}));\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mcp-manager.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/mcp-manager.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,MAAM,WAAW,iBAAiB;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,qFAAmF;IACnF,cAAc,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;IACnE,kFAAkF;IAClF,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAcD,qBAAa,UAAU;IACtB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoD;IACnF,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAoC;IAChE,OAAO,CAAC,YAAY,CAA0C;IAC9D,OAAO,CAAC,UAAU,CAAyC;IAC3D,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,qFAAqF;IACrF,OAAO,CAAC,yBAAyB,CAAqB;IAEtD,YAAY,OAAO,EAAE,iBAAiB,EAMrC;IAED,+EAA+E;IAC/E,OAAO,IAAI,IAAI,CAGd;IAED,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE7C;IAED,iBAAiB,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAqBlF;IAED,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,mBAAmB;IAsB3B,OAAO,CAAC,iBAAiB;IAKzB;;;;OAIG;IACH,qBAAqB,IAAI,IAAI,CAuB5B;IAED,iFAAiF;IACjF,OAAO,CAAC,QAAQ;IAoBhB,gGAAgG;IAChG,gCAAgC,IAAI,MAAM,EAAE,CAS3C;IAED,mDAAmD;IACnD,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAgDrG;IAED,gEAAgE;IAChE,aAAa,IAAI,kBAAkB,EAAE,CAEpC;IAED,8EAA8E;IAC9E,kCAAkC,IAAI,MAAM,EAAE,CAW7C;IAED,wCAAwC;IACxC,UAAU,IAAI,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAO3F;CACD","sourcesContent":["// Host side of MCP integrations. The protocol itself runs Python-side in the kernel; the host\n// only registers OAuth providers, gates integration skills by auth, and serves mcp.* host-requests.\n\nimport {\n\tBUILTIN_MCP_CATALOG,\n\tcreateMcpOAuthProvider,\n\tgetCatalogEntry,\n\tregisterBuiltinMcpOAuthProviders,\n} from \"@ponythewhite/base-context-ai/mcp\";\nimport { registerOAuthProvider, unregisterOAuthProvider } from \"@ponythewhite/base-context-ai/oauth\";\nimport type { AuthStorage } from \"../auth-storage.js\";\nimport { getProviderAuthContract } from \"../provider-contracts.js\";\nimport type { McpServerConfig } from \"../settings-manager.js\";\nimport type { AcpMcpServerConfig } from \"./acp-mcp-types.js\";\n\nexport interface McpManagerOptions {\n\tauthStorage: AuthStorage;\n\t/** Reads the current Settings.mcpServers (name → config). Re-read on refresh(). */\n\tgetUserServers?: () => Record<string, McpServerConfig> | undefined;\n\t/** Start an interactive host-side login for a server. Provided by the UI mode. */\n\tbeginLogin?: (server: string) => Promise<void>;\n}\n\n/** A resolved integration: a catalog/user entry plus its provider id. */\nconst GENERIC_SERVER_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;\n\ninterface ResolvedIntegration {\n\tserver: string;\n\tlabel: string;\n\tconfig: McpServerConfig;\n\tusesOAuth: boolean;\n\t/** True when this came from Settings.mcpServers (may override a catalog name). */\n\tuserDeclared?: boolean;\n}\n\nexport class McpManager {\n\tprivate readonly authStorage: AuthStorage;\n\tprivate readonly getUserServers: () => Record<string, McpServerConfig> | undefined;\n\tprivate readonly beginLogin?: (server: string) => Promise<void>;\n\tprivate integrations = new Map<string, ResolvedIntegration>();\n\tprivate acpServers = new Map<string, AcpMcpServerConfig>();\n\tprivate acpOwnerId?: string;\n\t/** Provider ids we registered for user servers, so refresh can drop removed ones. */\n\tprivate registeredUserProviderIds = new Set<string>();\n\n\tconstructor(options: McpManagerOptions) {\n\t\tthis.authStorage = options.authStorage;\n\t\tthis.getUserServers = options.getUserServers ?? (() => undefined);\n\t\tthis.beginLogin = options.beginLogin;\n\t\tthis.resolveIntegrations();\n\t\tthis.registerProviders();\n\t}\n\n\t/** Re-read settings and re-register providers; call after a session reload. */\n\trefresh(): void {\n\t\tthis.resolveIntegrations();\n\t\tthis.registerProviders();\n\t}\n\n\tcanReleaseAcpServers(ownerId: string): boolean {\n\t\treturn this.acpOwnerId === undefined || this.acpOwnerId === ownerId;\n\t}\n\n\treplaceAcpServers(servers: readonly AcpMcpServerConfig[], ownerId: string): boolean {\n\t\tif (!ownerId) throw new Error(\"ACP MCP owner id is required\");\n\t\tif (servers.length === 0 && this.acpOwnerId !== ownerId) return false;\n\t\tif (servers.length > 0 && this.acpOwnerId && this.acpOwnerId !== ownerId) {\n\t\t\tthrow new Error(\"ACP MCP configuration is owned by another client\");\n\t\t}\n\n\t\tconst next = new Map<string, AcpMcpServerConfig>();\n\t\tfor (const server of servers) {\n\t\t\tif (next.has(server.name)) throw new Error(`Duplicate ACP MCP server: ${server.name}`);\n\t\t\tnext.set(server.name, server);\n\t\t}\n\t\tconst unchanged =\n\t\t\tnext.size === this.acpServers.size &&\n\t\t\tArray.from(next).every(\n\t\t\t\t([name, config]) => JSON.stringify(this.acpServers.get(name)) === JSON.stringify(config),\n\t\t\t);\n\t\tif (unchanged) return false;\n\t\tthis.acpServers = next;\n\t\tthis.acpOwnerId = next.size > 0 ? ownerId : undefined;\n\t\treturn true;\n\t}\n\n\tprivate providerId(server: string): string {\n\t\treturn `mcp:${server}`;\n\t}\n\n\tprivate resolveIntegrations(): void {\n\t\tconst integrations = new Map<string, ResolvedIntegration>();\n\t\tfor (const entry of BUILTIN_MCP_CATALOG) {\n\t\t\tintegrations.set(entry.server, {\n\t\t\t\tserver: entry.server,\n\t\t\t\tlabel: entry.label,\n\t\t\t\tconfig: { type: \"http\", url: entry.url, oauth: true },\n\t\t\t\tusesOAuth: entry.oauth?.kind === \"oauth\",\n\t\t\t});\n\t\t}\n\t\tfor (const [server, config] of Object.entries(this.getUserServers() ?? {})) {\n\t\t\tintegrations.set(server, {\n\t\t\t\tserver,\n\t\t\t\tlabel: server,\n\t\t\t\tconfig,\n\t\t\t\tusesOAuth: config.type === \"http\" && config.oauth === true,\n\t\t\t\tuserDeclared: true,\n\t\t\t});\n\t\t}\n\t\tthis.integrations = integrations;\n\t}\n\n\tprivate registerProviders(): void {\n\t\tregisterBuiltinMcpOAuthProviders();\n\t\tthis.registerUserProviders();\n\t}\n\n\t/**\n\t * Register OAuth providers for user-declared (non-catalog) servers. Public so it\n\t * can run after ModelRegistry.refresh() resets the registry — otherwise custom\n\t * `mcp:<server>` providers vanish on every refresh (e.g. post-login).\n\t */\n\tregisterUserProviders(): void {\n\t\tconst current = new Set<string>();\n\t\tfor (const integration of this.integrations.values()) {\n\t\t\tif (!integration.userDeclared || integration.config.type !== \"http\" || getCatalogEntry(integration.server)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst id = this.providerId(integration.server);\n\t\t\tif (integration.usesOAuth) {\n\t\t\t\tcurrent.add(id);\n\t\t\t\tregisterOAuthProvider(\n\t\t\t\t\tcreateMcpOAuthProvider({\n\t\t\t\t\t\tserver: integration.server,\n\t\t\t\t\t\tlabel: integration.label,\n\t\t\t\t\t\turl: integration.config.url,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\t// Drop providers for user servers removed since the last registration.\n\t\tfor (const id of this.registeredUserProviderIds) {\n\t\t\tif (!current.has(id)) unregisterOAuthProvider(id);\n\t\t}\n\t\tthis.registeredUserProviderIds = current;\n\t}\n\n\t/** True when valid credentials exist for the integration (drives enablement). */\n\tprivate isAuthed(integration: ResolvedIntegration): boolean {\n\t\tif (integration.config.enabled === false) return false;\n\t\tif (integration.userDeclared && getCatalogEntry(integration.server)) return false;\n\t\tif (integration.config.type === \"stdio\") return true;\n\t\tconst { bearerTokenEnvVar } = integration.config;\n\t\tif (!integration.usesOAuth && !bearerTokenEnvVar) return true;\n\t\tif (bearerTokenEnvVar && process.env[bearerTokenEnvVar]?.trim()) {\n\t\t\treturn true;\n\t\t}\n\t\tconst providerId = this.providerId(integration.server);\n\t\tconst cred = this.authStorage.get(providerId);\n\t\tif (cred === undefined) return false;\n\t\tif (cred.type === \"oauth\" && getProviderAuthContract(providerId).oauth !== \"supported\") return false;\n\t\t// Builtin URLs are code-constant; only user-declared endpoints can be retargeted, so only their\n\t\t// tokens must prove where they belong. Mismatched or unbound tokens require re-login.\n\t\tif (!integration.userDeclared) return true;\n\t\tconst endpoint = (cred as { endpoint?: string }).endpoint;\n\t\treturn typeof endpoint === \"string\" && endpoint === integration.config.url;\n\t}\n\n\t/** `-<server>/SKILL.md` overrides for every built-in integration the user isn't logged into. */\n\tgetDisabledBuiltinSkillOverrides(): string[] {\n\t\tconst overrides: string[] = [];\n\t\tfor (const entry of BUILTIN_MCP_CATALOG) {\n\t\t\tconst integration = this.integrations.get(entry.server);\n\t\t\tif (integration && !this.isAuthed(integration)) {\n\t\t\t\toverrides.push(`-${entry.server}/SKILL.md`);\n\t\t\t}\n\t\t}\n\t\treturn overrides;\n\t}\n\n\t/** Host-request handlers exposed to the kernel. */\n\thostHandlers(): Record<string, (payload: Record<string, unknown>) => Promise<Record<string, unknown>>> {\n\t\tconst handlers: Record<string, (payload: Record<string, unknown>) => Promise<Record<string, unknown>>> = {\n\t\t\t\"mcp.refresh\": async (payload) => {\n\t\t\t\tconst server = String(payload.server ?? \"\");\n\t\t\t\tif (!server) throw new Error(\"mcp.refresh requires a server\");\n\t\t\t\tif (this.acpServers.has(server)) throw new Error(`ACP MCP server ${server} does not use host OAuth`);\n\t\t\t\t// getApiKey refreshes + rewrites auth.json under lock; Python re-reads.\n\t\t\t\t// Surface failure (throw) instead of a false success so the kernel can\n\t\t\t\t// report a refresh error rather than a misleading \"not enabled\".\n\t\t\t\tconst providerId = this.providerId(server);\n\t\t\t\tconst key = await this.authStorage.getApiKey(providerId);\n\t\t\t\tif (!key) {\n\t\t\t\t\tconst contract = getProviderAuthContract(providerId);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tcontract.oauth === \"supported\" ? `Could not refresh credentials for ${server}` : contract.guidance,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn {};\n\t\t\t},\n\t\t\t// Resolved config so the kernel skill connects to the same URL the host\n\t\t\t// registered/authenticated (honors a user's mcpServers `url` override).\n\t\t\t\"mcp.config\": async (payload) => {\n\t\t\t\tconst server = String(payload.server ?? \"\");\n\t\t\t\tif (!server) throw new Error(\"mcp.config requires a server\");\n\t\t\t\tconst acpServer = this.acpServers.get(server);\n\t\t\t\tif (acpServer) {\n\t\t\t\t\tconst { name: _name, ...config } = acpServer;\n\t\t\t\t\treturn { ...config, credentialSource: \"acp\" };\n\t\t\t\t}\n\t\t\t\tconst integration = this.integrations.get(server);\n\t\t\t\tif (!integration?.userDeclared || getCatalogEntry(server)) return {};\n\t\t\t\treturn { ...integration.config };\n\t\t\t},\n\t\t};\n\t\t// Only expose begin_login when an interactive login is actually wired, so the\n\t\t// kernel doesn't get a handler whose only behavior is to throw.\n\t\tconst beginLogin = this.beginLogin;\n\t\tif (beginLogin) {\n\t\t\thandlers[\"mcp.begin_login\"] = async (payload) => {\n\t\t\t\tconst server = String(payload.server ?? \"\");\n\t\t\t\tif (!server) throw new Error(\"mcp.begin_login requires a server\");\n\t\t\t\tconst contract = getProviderAuthContract(this.providerId(server));\n\t\t\t\tif (contract.oauth !== \"supported\") throw new Error(contract.guidance);\n\t\t\t\tawait beginLogin(server);\n\t\t\t\treturn {};\n\t\t\t};\n\t\t}\n\t\treturn handlers;\n\t}\n\n\t/** Session-scoped servers supplied by the active ACP client. */\n\tgetAcpServers(): AcpMcpServerConfig[] {\n\t\treturn [...this.acpServers.values()];\n\t}\n\n\t/** Enabled user-declared servers available through the generic kernel API. */\n\tgetEnabledPersistentGenericServers(): string[] {\n\t\treturn Array.from(this.integrations.values())\n\t\t\t.filter(\n\t\t\t\t(integration) =>\n\t\t\t\t\tintegration.userDeclared &&\n\t\t\t\t\tGENERIC_SERVER_NAME_PATTERN.test(integration.server) &&\n\t\t\t\t\t!getCatalogEntry(integration.server) &&\n\t\t\t\t\tthis.isAuthed(integration),\n\t\t\t)\n\t\t\t.map((integration) => integration.server)\n\t\t\t.sort((left, right) => left.localeCompare(right));\n\t}\n\n\t/** Status for the /mcp list command. */\n\tlistStatus(): Array<{ server: string; label: string; enabled: boolean; usesOAuth: boolean }> {\n\t\treturn Array.from(this.integrations.values()).map((integration) => ({\n\t\t\tserver: integration.server,\n\t\t\tlabel: integration.label,\n\t\t\tenabled: this.isAuthed(integration),\n\t\t\tusesOAuth: integration.usesOAuth,\n\t\t}));\n\t}\n}\n"]}
|
|
@@ -125,7 +125,7 @@ export class McpManager {
|
|
|
125
125
|
const cred = this.authStorage.get(providerId);
|
|
126
126
|
if (cred === undefined)
|
|
127
127
|
return false;
|
|
128
|
-
if (cred.type === "oauth" && getProviderAuthContract(providerId).oauth !== "
|
|
128
|
+
if (cred.type === "oauth" && getProviderAuthContract(providerId).oauth !== "supported")
|
|
129
129
|
return false;
|
|
130
130
|
// Builtin URLs are code-constant; only user-declared endpoints can be retargeted, so only their
|
|
131
131
|
// tokens must prove where they belong. Mismatched or unbound tokens require re-login.
|
|
@@ -161,7 +161,7 @@ export class McpManager {
|
|
|
161
161
|
const key = await this.authStorage.getApiKey(providerId);
|
|
162
162
|
if (!key) {
|
|
163
163
|
const contract = getProviderAuthContract(providerId);
|
|
164
|
-
throw new Error(contract.oauth === "
|
|
164
|
+
throw new Error(contract.oauth === "supported" ? `Could not refresh credentials for ${server}` : contract.guidance);
|
|
165
165
|
}
|
|
166
166
|
return {};
|
|
167
167
|
},
|
|
@@ -191,7 +191,7 @@ export class McpManager {
|
|
|
191
191
|
if (!server)
|
|
192
192
|
throw new Error("mcp.begin_login requires a server");
|
|
193
193
|
const contract = getProviderAuthContract(this.providerId(server));
|
|
194
|
-
if (contract.oauth !== "
|
|
194
|
+
if (contract.oauth !== "supported")
|
|
195
195
|
throw new Error(contract.guidance);
|
|
196
196
|
await beginLogin(server);
|
|
197
197
|
return {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-manager.js","sourceRoot":"","sources":["../../../src/core/mcp/mcp-manager.ts"],"names":[],"mappings":"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","sourcesContent":["// Host side of MCP integrations. The protocol itself runs Python-side in the kernel; the host\n// only registers OAuth providers, gates integration skills by auth, and serves mcp.* host-requests.\n\nimport {\n\tBUILTIN_MCP_CATALOG,\n\tcreateMcpOAuthProvider,\n\tgetCatalogEntry,\n\tregisterBuiltinMcpOAuthProviders,\n} from \"@ponythewhite/base-context-ai/mcp\";\nimport { registerOAuthProvider, unregisterOAuthProvider } from \"@ponythewhite/base-context-ai/oauth\";\nimport type { AuthStorage } from \"../auth-storage.js\";\nimport { getProviderAuthContract } from \"../provider-contracts.js\";\nimport type { McpServerConfig } from \"../settings-manager.js\";\nimport type { AcpMcpServerConfig } from \"./acp-mcp-types.js\";\n\nexport interface McpManagerOptions {\n\tauthStorage: AuthStorage;\n\t/** Reads the current Settings.mcpServers (name → config). Re-read on refresh(). */\n\tgetUserServers?: () => Record<string, McpServerConfig> | undefined;\n\t/** Start an interactive host-side login for a server. Provided by the UI mode. */\n\tbeginLogin?: (server: string) => Promise<void>;\n}\n\n/** A resolved integration: a catalog/user entry plus its provider id. */\nconst GENERIC_SERVER_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;\n\ninterface ResolvedIntegration {\n\tserver: string;\n\tlabel: string;\n\tconfig: McpServerConfig;\n\tusesOAuth: boolean;\n\t/** True when this came from Settings.mcpServers (may override a catalog name). */\n\tuserDeclared?: boolean;\n}\n\nexport class McpManager {\n\tprivate readonly authStorage: AuthStorage;\n\tprivate readonly getUserServers: () => Record<string, McpServerConfig> | undefined;\n\tprivate readonly beginLogin?: (server: string) => Promise<void>;\n\tprivate integrations = new Map<string, ResolvedIntegration>();\n\tprivate acpServers = new Map<string, AcpMcpServerConfig>();\n\tprivate acpOwnerId?: string;\n\t/** Provider ids we registered for user servers, so refresh can drop removed ones. */\n\tprivate registeredUserProviderIds = new Set<string>();\n\n\tconstructor(options: McpManagerOptions) {\n\t\tthis.authStorage = options.authStorage;\n\t\tthis.getUserServers = options.getUserServers ?? (() => undefined);\n\t\tthis.beginLogin = options.beginLogin;\n\t\tthis.resolveIntegrations();\n\t\tthis.registerProviders();\n\t}\n\n\t/** Re-read settings and re-register providers; call after a session reload. */\n\trefresh(): void {\n\t\tthis.resolveIntegrations();\n\t\tthis.registerProviders();\n\t}\n\n\tcanReleaseAcpServers(ownerId: string): boolean {\n\t\treturn this.acpOwnerId === undefined || this.acpOwnerId === ownerId;\n\t}\n\n\treplaceAcpServers(servers: readonly AcpMcpServerConfig[], ownerId: string): boolean {\n\t\tif (!ownerId) throw new Error(\"ACP MCP owner id is required\");\n\t\tif (servers.length === 0 && this.acpOwnerId !== ownerId) return false;\n\t\tif (servers.length > 0 && this.acpOwnerId && this.acpOwnerId !== ownerId) {\n\t\t\tthrow new Error(\"ACP MCP configuration is owned by another client\");\n\t\t}\n\n\t\tconst next = new Map<string, AcpMcpServerConfig>();\n\t\tfor (const server of servers) {\n\t\t\tif (next.has(server.name)) throw new Error(`Duplicate ACP MCP server: ${server.name}`);\n\t\t\tnext.set(server.name, server);\n\t\t}\n\t\tconst unchanged =\n\t\t\tnext.size === this.acpServers.size &&\n\t\t\tArray.from(next).every(\n\t\t\t\t([name, config]) => JSON.stringify(this.acpServers.get(name)) === JSON.stringify(config),\n\t\t\t);\n\t\tif (unchanged) return false;\n\t\tthis.acpServers = next;\n\t\tthis.acpOwnerId = next.size > 0 ? ownerId : undefined;\n\t\treturn true;\n\t}\n\n\tprivate providerId(server: string): string {\n\t\treturn `mcp:${server}`;\n\t}\n\n\tprivate resolveIntegrations(): void {\n\t\tconst integrations = new Map<string, ResolvedIntegration>();\n\t\tfor (const entry of BUILTIN_MCP_CATALOG) {\n\t\t\tintegrations.set(entry.server, {\n\t\t\t\tserver: entry.server,\n\t\t\t\tlabel: entry.label,\n\t\t\t\tconfig: { type: \"http\", url: entry.url, oauth: true },\n\t\t\t\tusesOAuth: entry.oauth?.kind === \"oauth\",\n\t\t\t});\n\t\t}\n\t\tfor (const [server, config] of Object.entries(this.getUserServers() ?? {})) {\n\t\t\tintegrations.set(server, {\n\t\t\t\tserver,\n\t\t\t\tlabel: server,\n\t\t\t\tconfig,\n\t\t\t\tusesOAuth: config.type === \"http\" && config.oauth === true,\n\t\t\t\tuserDeclared: true,\n\t\t\t});\n\t\t}\n\t\tthis.integrations = integrations;\n\t}\n\n\tprivate registerProviders(): void {\n\t\tregisterBuiltinMcpOAuthProviders();\n\t\tthis.registerUserProviders();\n\t}\n\n\t/**\n\t * Register OAuth providers for user-declared (non-catalog) servers. Public so it\n\t * can run after ModelRegistry.refresh() resets the registry — otherwise custom\n\t * `mcp:<server>` providers vanish on every refresh (e.g. post-login).\n\t */\n\tregisterUserProviders(): void {\n\t\tconst current = new Set<string>();\n\t\tfor (const integration of this.integrations.values()) {\n\t\t\tif (!integration.userDeclared || integration.config.type !== \"http\" || getCatalogEntry(integration.server)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst id = this.providerId(integration.server);\n\t\t\tif (integration.usesOAuth) {\n\t\t\t\tcurrent.add(id);\n\t\t\t\tregisterOAuthProvider(\n\t\t\t\t\tcreateMcpOAuthProvider({\n\t\t\t\t\t\tserver: integration.server,\n\t\t\t\t\t\tlabel: integration.label,\n\t\t\t\t\t\turl: integration.config.url,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\t// Drop providers for user servers removed since the last registration.\n\t\tfor (const id of this.registeredUserProviderIds) {\n\t\t\tif (!current.has(id)) unregisterOAuthProvider(id);\n\t\t}\n\t\tthis.registeredUserProviderIds = current;\n\t}\n\n\t/** True when valid credentials exist for the integration (drives enablement). */\n\tprivate isAuthed(integration: ResolvedIntegration): boolean {\n\t\tif (integration.config.enabled === false) return false;\n\t\tif (integration.userDeclared && getCatalogEntry(integration.server)) return false;\n\t\tif (integration.config.type === \"stdio\") return true;\n\t\tconst { bearerTokenEnvVar } = integration.config;\n\t\tif (!integration.usesOAuth && !bearerTokenEnvVar) return true;\n\t\tif (bearerTokenEnvVar && process.env[bearerTokenEnvVar]?.trim()) {\n\t\t\treturn true;\n\t\t}\n\t\tconst providerId = this.providerId(integration.server);\n\t\tconst cred = this.authStorage.get(providerId);\n\t\tif (cred === undefined) return false;\n\t\tif (cred.type === \"oauth\" && getProviderAuthContract(providerId).oauth !== \"validated\") return false;\n\t\t// Builtin URLs are code-constant; only user-declared endpoints can be retargeted, so only their\n\t\t// tokens must prove where they belong. Mismatched or unbound tokens require re-login.\n\t\tif (!integration.userDeclared) return true;\n\t\tconst endpoint = (cred as { endpoint?: string }).endpoint;\n\t\treturn typeof endpoint === \"string\" && endpoint === integration.config.url;\n\t}\n\n\t/** `-<server>/SKILL.md` overrides for every built-in integration the user isn't logged into. */\n\tgetDisabledBuiltinSkillOverrides(): string[] {\n\t\tconst overrides: string[] = [];\n\t\tfor (const entry of BUILTIN_MCP_CATALOG) {\n\t\t\tconst integration = this.integrations.get(entry.server);\n\t\t\tif (integration && !this.isAuthed(integration)) {\n\t\t\t\toverrides.push(`-${entry.server}/SKILL.md`);\n\t\t\t}\n\t\t}\n\t\treturn overrides;\n\t}\n\n\t/** Host-request handlers exposed to the kernel. */\n\thostHandlers(): Record<string, (payload: Record<string, unknown>) => Promise<Record<string, unknown>>> {\n\t\tconst handlers: Record<string, (payload: Record<string, unknown>) => Promise<Record<string, unknown>>> = {\n\t\t\t\"mcp.refresh\": async (payload) => {\n\t\t\t\tconst server = String(payload.server ?? \"\");\n\t\t\t\tif (!server) throw new Error(\"mcp.refresh requires a server\");\n\t\t\t\tif (this.acpServers.has(server)) throw new Error(`ACP MCP server ${server} does not use host OAuth`);\n\t\t\t\t// getApiKey refreshes + rewrites auth.json under lock; Python re-reads.\n\t\t\t\t// Surface failure (throw) instead of a false success so the kernel can\n\t\t\t\t// report a refresh error rather than a misleading \"not enabled\".\n\t\t\t\tconst providerId = this.providerId(server);\n\t\t\t\tconst key = await this.authStorage.getApiKey(providerId);\n\t\t\t\tif (!key) {\n\t\t\t\t\tconst contract = getProviderAuthContract(providerId);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tcontract.oauth === \"validated\" ? `Could not refresh credentials for ${server}` : contract.guidance,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn {};\n\t\t\t},\n\t\t\t// Resolved config so the kernel skill connects to the same URL the host\n\t\t\t// registered/authenticated (honors a user's mcpServers `url` override).\n\t\t\t\"mcp.config\": async (payload) => {\n\t\t\t\tconst server = String(payload.server ?? \"\");\n\t\t\t\tif (!server) throw new Error(\"mcp.config requires a server\");\n\t\t\t\tconst acpServer = this.acpServers.get(server);\n\t\t\t\tif (acpServer) {\n\t\t\t\t\tconst { name: _name, ...config } = acpServer;\n\t\t\t\t\treturn { ...config, credentialSource: \"acp\" };\n\t\t\t\t}\n\t\t\t\tconst integration = this.integrations.get(server);\n\t\t\t\tif (!integration?.userDeclared || getCatalogEntry(server)) return {};\n\t\t\t\treturn { ...integration.config };\n\t\t\t},\n\t\t};\n\t\t// Only expose begin_login when an interactive login is actually wired, so the\n\t\t// kernel doesn't get a handler whose only behavior is to throw.\n\t\tconst beginLogin = this.beginLogin;\n\t\tif (beginLogin) {\n\t\t\thandlers[\"mcp.begin_login\"] = async (payload) => {\n\t\t\t\tconst server = String(payload.server ?? \"\");\n\t\t\t\tif (!server) throw new Error(\"mcp.begin_login requires a server\");\n\t\t\t\tconst contract = getProviderAuthContract(this.providerId(server));\n\t\t\t\tif (contract.oauth !== \"validated\") throw new Error(contract.guidance);\n\t\t\t\tawait beginLogin(server);\n\t\t\t\treturn {};\n\t\t\t};\n\t\t}\n\t\treturn handlers;\n\t}\n\n\t/** Session-scoped servers supplied by the active ACP client. */\n\tgetAcpServers(): AcpMcpServerConfig[] {\n\t\treturn [...this.acpServers.values()];\n\t}\n\n\t/** Enabled user-declared servers available through the generic kernel API. */\n\tgetEnabledPersistentGenericServers(): string[] {\n\t\treturn Array.from(this.integrations.values())\n\t\t\t.filter(\n\t\t\t\t(integration) =>\n\t\t\t\t\tintegration.userDeclared &&\n\t\t\t\t\tGENERIC_SERVER_NAME_PATTERN.test(integration.server) &&\n\t\t\t\t\t!getCatalogEntry(integration.server) &&\n\t\t\t\t\tthis.isAuthed(integration),\n\t\t\t)\n\t\t\t.map((integration) => integration.server)\n\t\t\t.sort((left, right) => left.localeCompare(right));\n\t}\n\n\t/** Status for the /mcp list command. */\n\tlistStatus(): Array<{ server: string; label: string; enabled: boolean; usesOAuth: boolean }> {\n\t\treturn Array.from(this.integrations.values()).map((integration) => ({\n\t\t\tserver: integration.server,\n\t\t\tlabel: integration.label,\n\t\t\tenabled: this.isAuthed(integration),\n\t\t\tusesOAuth: integration.usesOAuth,\n\t\t}));\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mcp-manager.js","sourceRoot":"","sources":["../../../src/core/mcp/mcp-manager.ts"],"names":[],"mappings":"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","sourcesContent":["// Host side of MCP integrations. The protocol itself runs Python-side in the kernel; the host\n// only registers OAuth providers, gates integration skills by auth, and serves mcp.* host-requests.\n\nimport {\n\tBUILTIN_MCP_CATALOG,\n\tcreateMcpOAuthProvider,\n\tgetCatalogEntry,\n\tregisterBuiltinMcpOAuthProviders,\n} from \"@ponythewhite/base-context-ai/mcp\";\nimport { registerOAuthProvider, unregisterOAuthProvider } from \"@ponythewhite/base-context-ai/oauth\";\nimport type { AuthStorage } from \"../auth-storage.js\";\nimport { getProviderAuthContract } from \"../provider-contracts.js\";\nimport type { McpServerConfig } from \"../settings-manager.js\";\nimport type { AcpMcpServerConfig } from \"./acp-mcp-types.js\";\n\nexport interface McpManagerOptions {\n\tauthStorage: AuthStorage;\n\t/** Reads the current Settings.mcpServers (name → config). Re-read on refresh(). */\n\tgetUserServers?: () => Record<string, McpServerConfig> | undefined;\n\t/** Start an interactive host-side login for a server. Provided by the UI mode. */\n\tbeginLogin?: (server: string) => Promise<void>;\n}\n\n/** A resolved integration: a catalog/user entry plus its provider id. */\nconst GENERIC_SERVER_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;\n\ninterface ResolvedIntegration {\n\tserver: string;\n\tlabel: string;\n\tconfig: McpServerConfig;\n\tusesOAuth: boolean;\n\t/** True when this came from Settings.mcpServers (may override a catalog name). */\n\tuserDeclared?: boolean;\n}\n\nexport class McpManager {\n\tprivate readonly authStorage: AuthStorage;\n\tprivate readonly getUserServers: () => Record<string, McpServerConfig> | undefined;\n\tprivate readonly beginLogin?: (server: string) => Promise<void>;\n\tprivate integrations = new Map<string, ResolvedIntegration>();\n\tprivate acpServers = new Map<string, AcpMcpServerConfig>();\n\tprivate acpOwnerId?: string;\n\t/** Provider ids we registered for user servers, so refresh can drop removed ones. */\n\tprivate registeredUserProviderIds = new Set<string>();\n\n\tconstructor(options: McpManagerOptions) {\n\t\tthis.authStorage = options.authStorage;\n\t\tthis.getUserServers = options.getUserServers ?? (() => undefined);\n\t\tthis.beginLogin = options.beginLogin;\n\t\tthis.resolveIntegrations();\n\t\tthis.registerProviders();\n\t}\n\n\t/** Re-read settings and re-register providers; call after a session reload. */\n\trefresh(): void {\n\t\tthis.resolveIntegrations();\n\t\tthis.registerProviders();\n\t}\n\n\tcanReleaseAcpServers(ownerId: string): boolean {\n\t\treturn this.acpOwnerId === undefined || this.acpOwnerId === ownerId;\n\t}\n\n\treplaceAcpServers(servers: readonly AcpMcpServerConfig[], ownerId: string): boolean {\n\t\tif (!ownerId) throw new Error(\"ACP MCP owner id is required\");\n\t\tif (servers.length === 0 && this.acpOwnerId !== ownerId) return false;\n\t\tif (servers.length > 0 && this.acpOwnerId && this.acpOwnerId !== ownerId) {\n\t\t\tthrow new Error(\"ACP MCP configuration is owned by another client\");\n\t\t}\n\n\t\tconst next = new Map<string, AcpMcpServerConfig>();\n\t\tfor (const server of servers) {\n\t\t\tif (next.has(server.name)) throw new Error(`Duplicate ACP MCP server: ${server.name}`);\n\t\t\tnext.set(server.name, server);\n\t\t}\n\t\tconst unchanged =\n\t\t\tnext.size === this.acpServers.size &&\n\t\t\tArray.from(next).every(\n\t\t\t\t([name, config]) => JSON.stringify(this.acpServers.get(name)) === JSON.stringify(config),\n\t\t\t);\n\t\tif (unchanged) return false;\n\t\tthis.acpServers = next;\n\t\tthis.acpOwnerId = next.size > 0 ? ownerId : undefined;\n\t\treturn true;\n\t}\n\n\tprivate providerId(server: string): string {\n\t\treturn `mcp:${server}`;\n\t}\n\n\tprivate resolveIntegrations(): void {\n\t\tconst integrations = new Map<string, ResolvedIntegration>();\n\t\tfor (const entry of BUILTIN_MCP_CATALOG) {\n\t\t\tintegrations.set(entry.server, {\n\t\t\t\tserver: entry.server,\n\t\t\t\tlabel: entry.label,\n\t\t\t\tconfig: { type: \"http\", url: entry.url, oauth: true },\n\t\t\t\tusesOAuth: entry.oauth?.kind === \"oauth\",\n\t\t\t});\n\t\t}\n\t\tfor (const [server, config] of Object.entries(this.getUserServers() ?? {})) {\n\t\t\tintegrations.set(server, {\n\t\t\t\tserver,\n\t\t\t\tlabel: server,\n\t\t\t\tconfig,\n\t\t\t\tusesOAuth: config.type === \"http\" && config.oauth === true,\n\t\t\t\tuserDeclared: true,\n\t\t\t});\n\t\t}\n\t\tthis.integrations = integrations;\n\t}\n\n\tprivate registerProviders(): void {\n\t\tregisterBuiltinMcpOAuthProviders();\n\t\tthis.registerUserProviders();\n\t}\n\n\t/**\n\t * Register OAuth providers for user-declared (non-catalog) servers. Public so it\n\t * can run after ModelRegistry.refresh() resets the registry — otherwise custom\n\t * `mcp:<server>` providers vanish on every refresh (e.g. post-login).\n\t */\n\tregisterUserProviders(): void {\n\t\tconst current = new Set<string>();\n\t\tfor (const integration of this.integrations.values()) {\n\t\t\tif (!integration.userDeclared || integration.config.type !== \"http\" || getCatalogEntry(integration.server)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst id = this.providerId(integration.server);\n\t\t\tif (integration.usesOAuth) {\n\t\t\t\tcurrent.add(id);\n\t\t\t\tregisterOAuthProvider(\n\t\t\t\t\tcreateMcpOAuthProvider({\n\t\t\t\t\t\tserver: integration.server,\n\t\t\t\t\t\tlabel: integration.label,\n\t\t\t\t\t\turl: integration.config.url,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\t// Drop providers for user servers removed since the last registration.\n\t\tfor (const id of this.registeredUserProviderIds) {\n\t\t\tif (!current.has(id)) unregisterOAuthProvider(id);\n\t\t}\n\t\tthis.registeredUserProviderIds = current;\n\t}\n\n\t/** True when valid credentials exist for the integration (drives enablement). */\n\tprivate isAuthed(integration: ResolvedIntegration): boolean {\n\t\tif (integration.config.enabled === false) return false;\n\t\tif (integration.userDeclared && getCatalogEntry(integration.server)) return false;\n\t\tif (integration.config.type === \"stdio\") return true;\n\t\tconst { bearerTokenEnvVar } = integration.config;\n\t\tif (!integration.usesOAuth && !bearerTokenEnvVar) return true;\n\t\tif (bearerTokenEnvVar && process.env[bearerTokenEnvVar]?.trim()) {\n\t\t\treturn true;\n\t\t}\n\t\tconst providerId = this.providerId(integration.server);\n\t\tconst cred = this.authStorage.get(providerId);\n\t\tif (cred === undefined) return false;\n\t\tif (cred.type === \"oauth\" && getProviderAuthContract(providerId).oauth !== \"supported\") return false;\n\t\t// Builtin URLs are code-constant; only user-declared endpoints can be retargeted, so only their\n\t\t// tokens must prove where they belong. Mismatched or unbound tokens require re-login.\n\t\tif (!integration.userDeclared) return true;\n\t\tconst endpoint = (cred as { endpoint?: string }).endpoint;\n\t\treturn typeof endpoint === \"string\" && endpoint === integration.config.url;\n\t}\n\n\t/** `-<server>/SKILL.md` overrides for every built-in integration the user isn't logged into. */\n\tgetDisabledBuiltinSkillOverrides(): string[] {\n\t\tconst overrides: string[] = [];\n\t\tfor (const entry of BUILTIN_MCP_CATALOG) {\n\t\t\tconst integration = this.integrations.get(entry.server);\n\t\t\tif (integration && !this.isAuthed(integration)) {\n\t\t\t\toverrides.push(`-${entry.server}/SKILL.md`);\n\t\t\t}\n\t\t}\n\t\treturn overrides;\n\t}\n\n\t/** Host-request handlers exposed to the kernel. */\n\thostHandlers(): Record<string, (payload: Record<string, unknown>) => Promise<Record<string, unknown>>> {\n\t\tconst handlers: Record<string, (payload: Record<string, unknown>) => Promise<Record<string, unknown>>> = {\n\t\t\t\"mcp.refresh\": async (payload) => {\n\t\t\t\tconst server = String(payload.server ?? \"\");\n\t\t\t\tif (!server) throw new Error(\"mcp.refresh requires a server\");\n\t\t\t\tif (this.acpServers.has(server)) throw new Error(`ACP MCP server ${server} does not use host OAuth`);\n\t\t\t\t// getApiKey refreshes + rewrites auth.json under lock; Python re-reads.\n\t\t\t\t// Surface failure (throw) instead of a false success so the kernel can\n\t\t\t\t// report a refresh error rather than a misleading \"not enabled\".\n\t\t\t\tconst providerId = this.providerId(server);\n\t\t\t\tconst key = await this.authStorage.getApiKey(providerId);\n\t\t\t\tif (!key) {\n\t\t\t\t\tconst contract = getProviderAuthContract(providerId);\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\tcontract.oauth === \"supported\" ? `Could not refresh credentials for ${server}` : contract.guidance,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn {};\n\t\t\t},\n\t\t\t// Resolved config so the kernel skill connects to the same URL the host\n\t\t\t// registered/authenticated (honors a user's mcpServers `url` override).\n\t\t\t\"mcp.config\": async (payload) => {\n\t\t\t\tconst server = String(payload.server ?? \"\");\n\t\t\t\tif (!server) throw new Error(\"mcp.config requires a server\");\n\t\t\t\tconst acpServer = this.acpServers.get(server);\n\t\t\t\tif (acpServer) {\n\t\t\t\t\tconst { name: _name, ...config } = acpServer;\n\t\t\t\t\treturn { ...config, credentialSource: \"acp\" };\n\t\t\t\t}\n\t\t\t\tconst integration = this.integrations.get(server);\n\t\t\t\tif (!integration?.userDeclared || getCatalogEntry(server)) return {};\n\t\t\t\treturn { ...integration.config };\n\t\t\t},\n\t\t};\n\t\t// Only expose begin_login when an interactive login is actually wired, so the\n\t\t// kernel doesn't get a handler whose only behavior is to throw.\n\t\tconst beginLogin = this.beginLogin;\n\t\tif (beginLogin) {\n\t\t\thandlers[\"mcp.begin_login\"] = async (payload) => {\n\t\t\t\tconst server = String(payload.server ?? \"\");\n\t\t\t\tif (!server) throw new Error(\"mcp.begin_login requires a server\");\n\t\t\t\tconst contract = getProviderAuthContract(this.providerId(server));\n\t\t\t\tif (contract.oauth !== \"supported\") throw new Error(contract.guidance);\n\t\t\t\tawait beginLogin(server);\n\t\t\t\treturn {};\n\t\t\t};\n\t\t}\n\t\treturn handlers;\n\t}\n\n\t/** Session-scoped servers supplied by the active ACP client. */\n\tgetAcpServers(): AcpMcpServerConfig[] {\n\t\treturn [...this.acpServers.values()];\n\t}\n\n\t/** Enabled user-declared servers available through the generic kernel API. */\n\tgetEnabledPersistentGenericServers(): string[] {\n\t\treturn Array.from(this.integrations.values())\n\t\t\t.filter(\n\t\t\t\t(integration) =>\n\t\t\t\t\tintegration.userDeclared &&\n\t\t\t\t\tGENERIC_SERVER_NAME_PATTERN.test(integration.server) &&\n\t\t\t\t\t!getCatalogEntry(integration.server) &&\n\t\t\t\t\tthis.isAuthed(integration),\n\t\t\t)\n\t\t\t.map((integration) => integration.server)\n\t\t\t.sort((left, right) => left.localeCompare(right));\n\t}\n\n\t/** Status for the /mcp list command. */\n\tlistStatus(): Array<{ server: string; label: string; enabled: boolean; usesOAuth: boolean }> {\n\t\treturn Array.from(this.integrations.values()).map((integration) => ({\n\t\t\tserver: integration.server,\n\t\t\tlabel: integration.label,\n\t\t\tenabled: this.isAuthed(integration),\n\t\t\tusesOAuth: integration.usesOAuth,\n\t\t}));\n\t}\n}\n"]}
|
|
@@ -7,6 +7,7 @@ export type ResolvedRequestAuth = {
|
|
|
7
7
|
ok: true;
|
|
8
8
|
apiKey?: string;
|
|
9
9
|
headers?: Record<string, string>;
|
|
10
|
+
sourceToken?: AuthSourceToken;
|
|
10
11
|
} | {
|
|
11
12
|
ok: false;
|
|
12
13
|
error: string;
|
|
@@ -27,11 +28,7 @@ export declare class ModelRegistry {
|
|
|
27
28
|
private lastProviderAuthSourceTokens;
|
|
28
29
|
private modelRequestHeaders;
|
|
29
30
|
private registeredProviders;
|
|
30
|
-
private authorizedPrivatePrimeInferenceModelIds;
|
|
31
|
-
private authorizedPrivatePrimeInferenceTeamId;
|
|
32
|
-
private explicitPrivatePrimeInferenceModelIds;
|
|
33
31
|
private openAICodexModelsCache;
|
|
34
|
-
private backgroundPrivatePrimeAuthorization;
|
|
35
32
|
private loadError;
|
|
36
33
|
/** Re-register dynamic OAuth providers (e.g. user MCP servers) after refresh() resets the registry. */
|
|
37
34
|
private onOAuthProvidersReset?;
|
|
@@ -66,18 +63,6 @@ export declare class ModelRegistry {
|
|
|
66
63
|
*/
|
|
67
64
|
getAvailable(): Model<Api>[];
|
|
68
65
|
refreshAvailableModels(): Promise<Model<Api>[]>;
|
|
69
|
-
private refreshPrivatePrimeInferenceAuthorization;
|
|
70
|
-
/**
|
|
71
|
-
* Stale cache hits refresh in the background; failures keep the cached ids.
|
|
72
|
-
* Refreshes for the same credentials are deduped, a changed-credentials
|
|
73
|
-
* refresh is queued after the in-flight one, and a result is only applied
|
|
74
|
-
* if the credentials it was fetched with are still current.
|
|
75
|
-
*/
|
|
76
|
-
private startBackgroundPrivatePrimeAuthorizationRefresh;
|
|
77
|
-
private currentPrivatePrimeAuthorizationFingerprint;
|
|
78
|
-
private privatePrimeAuthorizationCachePath;
|
|
79
|
-
private readPrivatePrimeAuthorizationCache;
|
|
80
|
-
private writePrivatePrimeAuthorizationCache;
|
|
81
66
|
refreshModelCatalog(): Promise<ModelCatalogSnapshot>;
|
|
82
67
|
canUseModel(model: Model<Api>): Promise<boolean>;
|
|
83
68
|
getExecutableModels(): Promise<Model<Api>[]>;
|