@agimon-ai/po-config 0.0.0-alpha.2 → 0.0.0-alpha.21
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/LICENSE +149 -21
- package/README.md +11 -11
- package/dist/agentPluginMcp.cjs +313 -134
- package/dist/agentPluginMcp.cjs.map +1 -1
- package/dist/agentPluginMcp.d.mts +22 -4
- package/dist/agentPluginMcp.d.mts.map +1 -1
- package/dist/agentPluginMcp.mjs +312 -134
- package/dist/agentPluginMcp.mjs.map +1 -1
- package/dist/apiContracts.cjs.map +1 -1
- package/dist/apiContracts.mjs.map +1 -1
- package/dist/atomicJson-D3MHqnLW.cjs +59 -0
- package/dist/atomicJson-D3MHqnLW.cjs.map +1 -0
- package/dist/atomicJson-Dj3rlZbD.mjs +40 -0
- package/dist/atomicJson-Dj3rlZbD.mjs.map +1 -0
- package/dist/atomicJson.cjs +4 -2
- package/dist/atomicJson.d.mts +2 -2
- package/dist/atomicJson.mjs +3 -2
- package/dist/{index-BT29GZx5.d.mts → completion-Ba0TiBHa.d.mts} +58 -27
- package/dist/completion-Ba0TiBHa.d.mts.map +1 -0
- package/dist/config-BBvn_ZLP.mjs +1 -0
- package/dist/config-Cdybp9rT.cjs +155 -0
- package/dist/config-Cdybp9rT.cjs.map +1 -0
- package/dist/config-Cxc2xw54.mjs +112 -0
- package/dist/config-Cxc2xw54.mjs.map +1 -0
- package/dist/{config-D2HbBLzo.d.mts → config-pxC7FyUJ.d.mts} +33 -33
- package/dist/config-pxC7FyUJ.d.mts.map +1 -0
- package/dist/config.cjs +21 -17
- package/dist/config.d.mts +3 -3
- package/dist/config.mjs +4 -3
- package/dist/{configPolicy-Ce1QKDxa.cjs → configPolicy-CowlLhK1.cjs} +99 -99
- package/dist/configPolicy-CowlLhK1.cjs.map +1 -0
- package/dist/{configPolicy-DCQgF5-f.mjs → configPolicy-DueX0k6i.mjs} +84 -84
- package/dist/configPolicy-DueX0k6i.mjs.map +1 -0
- package/dist/configSchema.d.mts +2 -2
- package/dist/configWriter-DCASRzr-.mjs +180 -0
- package/dist/configWriter-DCASRzr-.mjs.map +1 -0
- package/dist/configWriter-DGO0gmXo.cjs +218 -0
- package/dist/configWriter-DGO0gmXo.cjs.map +1 -0
- package/dist/configWriter.cjs +7 -4
- package/dist/configWriter.d.mts +2 -2
- package/dist/configWriter.mjs +1 -2
- package/dist/core-B0Qg0Qq2.cjs +224 -0
- package/dist/core-B0Qg0Qq2.cjs.map +1 -0
- package/dist/core-DKWW9gkh.mjs +139 -0
- package/dist/core-DKWW9gkh.mjs.map +1 -0
- package/dist/{domains-DGCb7uMC.cjs → domains-CiDUsRiX.cjs} +473 -171
- package/dist/domains-CiDUsRiX.cjs.map +1 -0
- package/dist/{domains-BroCVHrS.mjs → domains-IlieGHaY.mjs} +437 -170
- package/dist/domains-IlieGHaY.mjs.map +1 -0
- package/dist/domains.cjs +9 -3
- package/dist/domains.d.mts +3 -3
- package/dist/domains.mjs +3 -3
- package/dist/extensions/mcp-ui.mjs +1 -1
- package/dist/extensions/mcp-ui.mjs.map +1 -1
- package/dist/extensions/mcp.cjs +3 -3
- package/dist/extensions/mcp.cjs.map +1 -1
- package/dist/extensions/mcp.d.mts +1 -1
- package/dist/extensions/mcp.mjs +2 -2
- package/dist/extensions/mcp.mjs.map +1 -1
- package/dist/extensions/server.cjs +55 -47
- package/dist/extensions/server.cjs.map +1 -1
- package/dist/extensions/server.d.mts +2 -2
- package/dist/extensions/server.d.mts.map +1 -1
- package/dist/extensions/server.mjs +56 -48
- package/dist/extensions/server.mjs.map +1 -1
- package/dist/{harnessState-Dn_S7fB9.mjs → harnessState-8lZda_8r.mjs} +2 -2
- package/dist/{harnessState-Dn_S7fB9.mjs.map → harnessState-8lZda_8r.mjs.map} +1 -1
- package/dist/{harnessState-CCyBeutB.cjs → harnessState-BrmH0lG5.cjs} +2 -2
- package/dist/{harnessState-CCyBeutB.cjs.map → harnessState-BrmH0lG5.cjs.map} +1 -1
- package/dist/harnessState.cjs +1 -1
- package/dist/harnessState.d.mts +1 -1
- package/dist/harnessState.mjs +1 -2
- package/dist/{harnessStore-CJSxdSkV.cjs → harnessStore-BinxGITh.cjs} +189 -81
- package/dist/harnessStore-BinxGITh.cjs.map +1 -0
- package/dist/{harnessStore-CltwLB7M.mjs → harnessStore-w8zHmJ_H.mjs} +160 -82
- package/dist/harnessStore-w8zHmJ_H.mjs.map +1 -0
- package/dist/harnessStore.cjs +6 -1
- package/dist/harnessStore.d.mts +2 -2
- package/dist/harnessStore.mjs +1 -2
- package/dist/index-7RuIAWX1.d.mts +63 -0
- package/dist/index-7RuIAWX1.d.mts.map +1 -0
- package/dist/{index-CkDDvVQt.d.mts → index-BNcG0voG.d.mts} +61 -16
- package/dist/index-BNcG0voG.d.mts.map +1 -0
- package/dist/{index-Dy_-m7gx.d.mts → index-BTOU4XiI.d.mts} +3 -3
- package/dist/{index-Dy_-m7gx.d.mts.map → index-BTOU4XiI.d.mts.map} +1 -1
- package/dist/index-COokUToB.d.mts +83 -0
- package/dist/index-COokUToB.d.mts.map +1 -0
- package/dist/index-D3vGEYup.d.mts +135 -0
- package/dist/index-D3vGEYup.d.mts.map +1 -0
- package/dist/{index-Ch7ptOkW.d.mts → index-DNEK9W6n.d.mts} +26 -16
- package/dist/index-DNEK9W6n.d.mts.map +1 -0
- package/dist/index-D_OtYtsl.d.mts +37 -0
- package/dist/index-D_OtYtsl.d.mts.map +1 -0
- package/dist/{index-DNk4q0Qm.d.mts → index-Nbj2iQWw.d.mts} +19 -25
- package/dist/index-Nbj2iQWw.d.mts.map +1 -0
- package/dist/{index-CEUc7m16.d.mts → index-dYgF03lE.d.mts} +82 -32
- package/dist/index-dYgF03lE.d.mts.map +1 -0
- package/dist/index-fTuf8tVH.d.mts +34 -0
- package/dist/index-fTuf8tVH.d.mts.map +1 -0
- package/dist/index-nVcEC1jO.d.mts +62 -0
- package/dist/index-nVcEC1jO.d.mts.map +1 -0
- package/dist/index.cjs +81 -59
- package/dist/index.d.mts +16 -15
- package/dist/index.mjs +17 -15
- package/dist/{init-Cd3Ki6Ub.cjs → init-BdZ-gqqk.cjs} +209 -59
- package/dist/init-BdZ-gqqk.cjs.map +1 -0
- package/dist/{init-DVzhiCUE.mjs → init-DG7MxGxC.mjs} +187 -48
- package/dist/init-DG7MxGxC.mjs.map +1 -0
- package/dist/init.cjs +8 -6
- package/dist/init.d.mts +2 -2
- package/dist/init.mjs +1 -2
- package/dist/layeredConfig-BbkoIEfM.mjs +95 -0
- package/dist/layeredConfig-BbkoIEfM.mjs.map +1 -0
- package/dist/layeredConfig-Bs18dXQG.cjs +127 -0
- package/dist/layeredConfig-Bs18dXQG.cjs.map +1 -0
- package/dist/layeredConfig.cjs +5 -4
- package/dist/layeredConfig.d.mts +7 -2
- package/dist/layeredConfig.d.mts.map +1 -0
- package/dist/layeredConfig.mjs +1 -2
- package/dist/{majorModes-D1Itd8SN.mjs → majorModes-B8Km83e1.mjs} +130 -23
- package/dist/majorModes-B8Km83e1.mjs.map +1 -0
- package/dist/{majorModes-DnNSH9ZK.cjs → majorModes-CLccNMZt.cjs} +147 -22
- package/dist/majorModes-CLccNMZt.cjs.map +1 -0
- package/dist/majorModes.cjs +4 -1
- package/dist/majorModes.d.mts +2 -2
- package/dist/majorModes.mjs +1 -2
- package/dist/{piConfig-qGyCbcVj.mjs → piConfig-Bq36PQFF.mjs} +104 -69
- package/dist/piConfig-Bq36PQFF.mjs.map +1 -0
- package/dist/{piConfig-Bx26HMb_.d.mts → piConfig-C9rGUqPe.d.mts} +3 -3
- package/dist/{piConfig-Bx26HMb_.d.mts.map → piConfig-C9rGUqPe.d.mts.map} +1 -1
- package/dist/{piConfig-CCBdZXQr.cjs → piConfig-cluCie5i.cjs} +122 -70
- package/dist/piConfig-cluCie5i.cjs.map +1 -0
- package/dist/piConfig.cjs +4 -1
- package/dist/piConfig.d.mts +2 -2
- package/dist/piConfig.mjs +1 -2
- package/dist/piContext.cjs +27 -16
- package/dist/piContext.d.mts +3 -3
- package/dist/piContext.mjs +1 -2
- package/dist/{profiles-DBcYg5nA.mjs → profiles-CHict0x-.mjs} +322 -101
- package/dist/profiles-CHict0x-.mjs.map +1 -0
- package/dist/{profiles-tpplXY4r.cjs → profiles-t2EUj0aB.cjs} +359 -102
- package/dist/profiles-t2EUj0aB.cjs.map +1 -0
- package/dist/profiles.cjs +7 -1
- package/dist/profiles.d.mts +27 -3
- package/dist/profiles.d.mts.map +1 -1
- package/dist/profiles.mjs +1 -2
- package/dist/selectionSwitch.cjs +88 -22
- package/dist/selectionSwitch.cjs.map +1 -1
- package/dist/selectionSwitch.d.mts +40 -18
- package/dist/selectionSwitch.d.mts.map +1 -1
- package/dist/selectionSwitch.mjs +85 -22
- package/dist/selectionSwitch.mjs.map +1 -1
- package/dist/{sessionConfig-DV5xTRRw.mjs → sessionConfig-DFQF618G.mjs} +48 -47
- package/dist/sessionConfig-DFQF618G.mjs.map +1 -0
- package/dist/{sessionConfig-Bf6xHWLd.cjs → sessionConfig-DeP6pplT.cjs} +74 -85
- package/dist/sessionConfig-DeP6pplT.cjs.map +1 -0
- package/dist/sync-BJ8gCP9s.mjs +29 -0
- package/dist/sync-BJ8gCP9s.mjs.map +1 -0
- package/dist/sync-CC_15kkB.d.mts +46 -0
- package/dist/sync-CC_15kkB.d.mts.map +1 -0
- package/dist/sync-Dlxz2msM.cjs +37 -0
- package/dist/sync-Dlxz2msM.cjs.map +1 -0
- package/dist/types.cjs +2 -2
- package/dist/types.d.mts +2 -2
- package/dist/types.mjs +1 -2
- package/llms.txt +1 -1
- package/package.json +16 -16
- package/src/prompts/po-author-config/SKILL.md +4 -4
- package/src/prompts/po-author-config/agents/openai.yaml +1 -1
- package/src/prompts/po-author-config/references/config-contract.md +5 -5
- package/dist/atomicJson-1W0WhuFF.mjs +0 -44
- package/dist/atomicJson-1W0WhuFF.mjs.map +0 -1
- package/dist/atomicJson-Dt2z_DXl.cjs +0 -52
- package/dist/atomicJson-Dt2z_DXl.cjs.map +0 -1
- package/dist/config-CfTb0_9G.cjs +0 -219
- package/dist/config-CfTb0_9G.cjs.map +0 -1
- package/dist/config-D2HbBLzo.d.mts.map +0 -1
- package/dist/config-DoQWSt1V.mjs +0 -162
- package/dist/config-DoQWSt1V.mjs.map +0 -1
- package/dist/config-NSHRd6na.mjs +0 -2
- package/dist/configPolicy-Ce1QKDxa.cjs.map +0 -1
- package/dist/configPolicy-DCQgF5-f.mjs.map +0 -1
- package/dist/configWriter-B7uO8MuN.cjs +0 -150
- package/dist/configWriter-B7uO8MuN.cjs.map +0 -1
- package/dist/configWriter-DUtLgOlD.mjs +0 -130
- package/dist/configWriter-DUtLgOlD.mjs.map +0 -1
- package/dist/domains-BroCVHrS.mjs.map +0 -1
- package/dist/domains-DGCb7uMC.cjs.map +0 -1
- package/dist/harnessStore-CJSxdSkV.cjs.map +0 -1
- package/dist/harnessStore-CltwLB7M.mjs.map +0 -1
- package/dist/index-78zvoS9s.d.mts +0 -35
- package/dist/index-78zvoS9s.d.mts.map +0 -1
- package/dist/index-BT29GZx5.d.mts.map +0 -1
- package/dist/index-C6GaYjq-.d.mts +0 -6
- package/dist/index-C6GaYjq-.d.mts.map +0 -1
- package/dist/index-CEUc7m16.d.mts.map +0 -1
- package/dist/index-CRcoVYXz.d.mts +0 -39
- package/dist/index-CRcoVYXz.d.mts.map +0 -1
- package/dist/index-CVlciCJF.d.mts +0 -40
- package/dist/index-CVlciCJF.d.mts.map +0 -1
- package/dist/index-Ch7ptOkW.d.mts.map +0 -1
- package/dist/index-CkDDvVQt.d.mts.map +0 -1
- package/dist/index-Cvdt-Y-i.d.mts +0 -66
- package/dist/index-Cvdt-Y-i.d.mts.map +0 -1
- package/dist/index-DNk4q0Qm.d.mts.map +0 -1
- package/dist/index-DdH0w56b.d.mts +0 -116
- package/dist/index-DdH0w56b.d.mts.map +0 -1
- package/dist/init-Cd3Ki6Ub.cjs.map +0 -1
- package/dist/init-DVzhiCUE.mjs.map +0 -1
- package/dist/layeredConfig-fukqN2EA.mjs +0 -67
- package/dist/layeredConfig-fukqN2EA.mjs.map +0 -1
- package/dist/layeredConfig-ol0274TN.cjs +0 -94
- package/dist/layeredConfig-ol0274TN.cjs.map +0 -1
- package/dist/majorModes-D1Itd8SN.mjs.map +0 -1
- package/dist/majorModes-DnNSH9ZK.cjs.map +0 -1
- package/dist/piConfig-CCBdZXQr.cjs.map +0 -1
- package/dist/piConfig-qGyCbcVj.mjs.map +0 -1
- package/dist/profiles-DBcYg5nA.mjs.map +0 -1
- package/dist/profiles-tpplXY4r.cjs.map +0 -1
- package/dist/sessionConfig-Bf6xHWLd.cjs.map +0 -1
- package/dist/sessionConfig-DV5xTRRw.mjs.map +0 -1
package/dist/agentPluginMcp.mjs
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import { validateHeaderName, validateHeaderValue } from "node:http";
|
|
4
|
-
import { isIP } from "node:net";
|
|
5
1
|
import path from "node:path";
|
|
2
|
+
import { getOrThrow, nodeHost, writeFileAtomic } from "@agimon-ai/po-core/platform";
|
|
3
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
6
4
|
import { AGENT_PLUGIN_MCP_SCHEMA_URL } from "@agimon-ai/po-core/mcpProjection";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
//#region src/services/agentPluginMcp/normalize.ts
|
|
7
|
+
/** Pure Agent Plugin MCP normalisation shared by the async API and the deprecated Node-only sync shim. */
|
|
8
|
+
/** Same token grammar as node:http `validateHeaderName` (RFC 9110 tchar). */
|
|
9
|
+
const HTTP_TOKEN = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/u;
|
|
10
|
+
/** Same rejected characters as node:http `validateHeaderValue`. */
|
|
11
|
+
const INVALID_HEADER_VALUE_CHARACTER = /[^\t\x20-\x7e\x80-\xff]/u;
|
|
12
|
+
const IPV4_OCTET = "(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)";
|
|
13
|
+
const IPV4_ADDRESS = new RegExp(`^${IPV4_OCTET}(?:\\.${IPV4_OCTET}){3}$`, "u");
|
|
14
|
+
function isIPv4(value) {
|
|
15
|
+
return IPV4_ADDRESS.test(value);
|
|
16
|
+
}
|
|
10
17
|
const RESERVED_ENVIRONMENT_KEYS = /* @__PURE__ */ new Set(["PLUGIN_ROOT", "PLUGIN_DATA"]);
|
|
11
18
|
const PROXY_SERVER_ALIASES = /* @__PURE__ */ new Set(["mcp-proxy", "agiflow-proxy"]);
|
|
12
19
|
function isObject(value) {
|
|
@@ -43,49 +50,6 @@ function isInside(root, candidate) {
|
|
|
43
50
|
const relative = path.relative(root, candidate);
|
|
44
51
|
return relative === "" || !relative.startsWith(`..${path.sep}`) && relative !== ".." && !path.isAbsolute(relative);
|
|
45
52
|
}
|
|
46
|
-
function realContainedPath(root, candidate, label) {
|
|
47
|
-
let realCandidate;
|
|
48
|
-
try {
|
|
49
|
-
realCandidate = fs.realpathSync(candidate);
|
|
50
|
-
} catch {
|
|
51
|
-
throw new Error(`${label} does not exist`);
|
|
52
|
-
}
|
|
53
|
-
if (!isInside(root, realCandidate)) throw new Error(`${label} escapes its allowed plugin directory`);
|
|
54
|
-
return realCandidate;
|
|
55
|
-
}
|
|
56
|
-
function normalizeCommand(command, pluginRoot) {
|
|
57
|
-
if (command.startsWith("./")) {
|
|
58
|
-
const resolved = realContainedPath(pluginRoot, path.resolve(pluginRoot, command), "command");
|
|
59
|
-
if (!fs.statSync(resolved).isFile()) throw new Error("command must resolve to a regular file");
|
|
60
|
-
try {
|
|
61
|
-
fs.accessSync(resolved, fs.constants.X_OK);
|
|
62
|
-
} catch {
|
|
63
|
-
throw new Error("command must resolve to an executable file");
|
|
64
|
-
}
|
|
65
|
-
return resolved;
|
|
66
|
-
}
|
|
67
|
-
if (command === "." || command === ".." || /[\s/\\]/u.test(command)) throw new Error("command must be a bare executable name or a ./ path inside the plugin");
|
|
68
|
-
return command;
|
|
69
|
-
}
|
|
70
|
-
function normalizeWorkingDirectory(declared, pluginRoot, pluginDataDirectory) {
|
|
71
|
-
if (declared === void 0) return pluginRoot;
|
|
72
|
-
const cwd = nonEmptyString(declared, "cwd");
|
|
73
|
-
let base;
|
|
74
|
-
let expanded;
|
|
75
|
-
if (cwd.startsWith("./")) {
|
|
76
|
-
base = pluginRoot;
|
|
77
|
-
expanded = path.resolve(pluginRoot, cwd);
|
|
78
|
-
} else if (cwd === "${PLUGIN_ROOT}" || cwd.startsWith("${PLUGIN_ROOT}/")) {
|
|
79
|
-
base = pluginRoot;
|
|
80
|
-
expanded = expandPluginPlaceholders(cwd, pluginRoot, pluginDataDirectory);
|
|
81
|
-
} else if (cwd === "${PLUGIN_DATA}" || cwd.startsWith("${PLUGIN_DATA}/")) {
|
|
82
|
-
base = pluginDataDirectory;
|
|
83
|
-
expanded = expandPluginPlaceholders(cwd, pluginRoot, pluginDataDirectory);
|
|
84
|
-
} else throw new Error("cwd must start with ./, ${PLUGIN_ROOT}, or ${PLUGIN_DATA}");
|
|
85
|
-
const resolved = realContainedPath(base, path.resolve(expanded), "cwd");
|
|
86
|
-
if (!fs.statSync(resolved).isDirectory()) throw new Error("cwd must resolve to a directory");
|
|
87
|
-
return resolved;
|
|
88
|
-
}
|
|
89
53
|
function normalizeEnvironment(value, pluginRoot, pluginDataDirectory) {
|
|
90
54
|
const declared = optionalStringRecord(value, "env") ?? {};
|
|
91
55
|
for (const key of Object.keys(declared)) {
|
|
@@ -101,9 +65,8 @@ function normalizeEnvironment(value, pluginRoot, pluginDataDirectory) {
|
|
|
101
65
|
function isLoopbackHost(hostname) {
|
|
102
66
|
const bareHostname = hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname;
|
|
103
67
|
if (bareHostname.toLowerCase() === "localhost") return true;
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return family === 6 && bareHostname === "::1";
|
|
68
|
+
if (isIPv4(bareHostname)) return bareHostname.split(".")[0] === "127";
|
|
69
|
+
return bareHostname === "::1";
|
|
107
70
|
}
|
|
108
71
|
function normalizeUrl(value) {
|
|
109
72
|
const raw = nonEmptyString(value, "url");
|
|
@@ -127,48 +90,89 @@ function normalizeHeaders(value) {
|
|
|
127
90
|
const canonical = name.toLowerCase();
|
|
128
91
|
if (seen.has(canonical)) throw new Error(`headers contain duplicate name "${name}"`);
|
|
129
92
|
seen.add(canonical);
|
|
130
|
-
|
|
131
|
-
validateHeaderName(name);
|
|
132
|
-
validateHeaderValue(name, item);
|
|
133
|
-
} catch {
|
|
134
|
-
throw new Error(`header "${name}" is invalid`);
|
|
135
|
-
}
|
|
93
|
+
if (!HTTP_TOKEN.test(name) || INVALID_HEADER_VALUE_CHARACTER.test(item)) throw new Error(`header "${name}" is invalid`);
|
|
136
94
|
}
|
|
137
95
|
return headers;
|
|
138
96
|
}
|
|
139
|
-
function
|
|
97
|
+
function stagedInternalPath(source, contents, stagingDirectory) {
|
|
98
|
+
const digest = createHash("sha256").update(source.sourceId).update("\0").update(source.contentDigest).update("\0").update(contents).digest("hex").slice(0, 20);
|
|
99
|
+
return path.join(stagingDirectory, `agent-plugin-mcp-${digest}.internal.json`);
|
|
100
|
+
}
|
|
101
|
+
function emptyResult(diagnostic) {
|
|
102
|
+
return {
|
|
103
|
+
claudeConfig: { mcpServers: {} },
|
|
104
|
+
serverNames: [],
|
|
105
|
+
droppedServers: [],
|
|
106
|
+
diagnostics: [diagnostic]
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function sourceLabel(source) {
|
|
110
|
+
return `Agent Plugin MCP source "${source.sourceId}"`;
|
|
111
|
+
}
|
|
112
|
+
/** Checks the projection identity before any file is touched. */
|
|
113
|
+
function assertProjectionSource(source) {
|
|
114
|
+
if (source.mcpSchemaUrl !== AGENT_PLUGIN_MCP_SCHEMA_URL) throw new Error(`unsupported schema "${String(source.mcpSchemaUrl)}"`);
|
|
115
|
+
if (!path.isAbsolute(source.pluginRoot) || !path.isAbsolute(source.pluginDataDirectory)) throw new Error("pluginRoot and pluginDataDirectory must be absolute");
|
|
116
|
+
}
|
|
117
|
+
function assertRootConfigPath(configPath, pluginRoot) {
|
|
118
|
+
if (path.dirname(configPath) !== pluginRoot || path.basename(configPath) !== "mcp.json") throw new Error("portable plugin config must be root mcp.json");
|
|
119
|
+
}
|
|
120
|
+
/** Verifies the digest and document shape of the raw mcp.json bytes; returns its server map. */
|
|
121
|
+
function parseMcpDocument(source, bytes, label) {
|
|
122
|
+
if (createHash("sha256").update(bytes).digest("hex") !== source.contentDigest) throw new Error("content digest does not match the projection");
|
|
123
|
+
const parsed = JSON.parse(new TextDecoder("utf-8", { ignoreBOM: true }).decode(bytes));
|
|
124
|
+
if (!isObject(parsed)) throw new Error("document must be an object");
|
|
125
|
+
onlyKeys(parsed, ["$schema", "mcpServers"], label);
|
|
126
|
+
if (parsed.$schema !== source.mcpSchemaUrl) throw new Error("$schema does not match the projected schema");
|
|
127
|
+
if (!isObject(parsed.mcpServers)) throw new Error("mcpServers must be an object");
|
|
128
|
+
return parsed.mcpServers;
|
|
129
|
+
}
|
|
130
|
+
/** Whether a declared server is skipped (empty name), dropped by the allowlist or wrapper rule, or normalised. */
|
|
131
|
+
function serverDisposition(name, options) {
|
|
132
|
+
if (!name) return "empty";
|
|
133
|
+
const allowed = options.allowedServers;
|
|
134
|
+
const keepAll = !allowed || allowed.length === 0;
|
|
135
|
+
const stripProxyWrappers = options.stripProxyWrappers ?? true;
|
|
136
|
+
if (!keepAll && !allowed.includes(name) || stripProxyWrappers && PROXY_SERVER_ALIASES.has(name)) return "dropped";
|
|
137
|
+
return "keep";
|
|
138
|
+
}
|
|
139
|
+
function emptyServerDiagnostic(label) {
|
|
140
|
+
return `${label} contains an empty server name; that entry was skipped.`;
|
|
141
|
+
}
|
|
142
|
+
function skippedServerDiagnostic(label, name, error) {
|
|
143
|
+
return `${label} skipped server "${name}": ${error instanceof Error ? error.message : String(error)}`;
|
|
144
|
+
}
|
|
145
|
+
function disabledResult(label, error) {
|
|
146
|
+
return emptyResult(`${label} was disabled: ${error instanceof Error ? error.message : String(error)}`);
|
|
147
|
+
}
|
|
148
|
+
/** The declared transport of one server; stdio declarations are also checked for unsupported fields. */
|
|
149
|
+
function serverType(raw, name) {
|
|
140
150
|
if (!isObject(raw)) throw new Error("definition must be an object");
|
|
141
151
|
const type = nonEmptyString(raw.type, "type");
|
|
142
|
-
if (type === "stdio")
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
claude: {
|
|
167
|
-
type: "stdio",
|
|
168
|
-
...config
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
}
|
|
152
|
+
if (type === "stdio") onlyKeys(raw, [
|
|
153
|
+
"type",
|
|
154
|
+
"command",
|
|
155
|
+
"args",
|
|
156
|
+
"env",
|
|
157
|
+
"cwd"
|
|
158
|
+
], `server "${name}"`);
|
|
159
|
+
return type;
|
|
160
|
+
}
|
|
161
|
+
function stdioServer(name, config) {
|
|
162
|
+
return {
|
|
163
|
+
internal: {
|
|
164
|
+
name,
|
|
165
|
+
transport: "stdio",
|
|
166
|
+
config
|
|
167
|
+
},
|
|
168
|
+
claude: {
|
|
169
|
+
type: "stdio",
|
|
170
|
+
...config
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/** A streamable-http or sse server; any other type is unsupported. */
|
|
175
|
+
function remoteServer(raw, name, type) {
|
|
172
176
|
if (type === "streamable-http" || type === "sse") {
|
|
173
177
|
onlyKeys(raw, [
|
|
174
178
|
"type",
|
|
@@ -196,21 +200,93 @@ function normalizeServer(raw, pluginRoot, pluginDataDirectory, name) {
|
|
|
196
200
|
}
|
|
197
201
|
throw new Error(`unsupported transport type "${type}"`);
|
|
198
202
|
}
|
|
199
|
-
function
|
|
200
|
-
|
|
201
|
-
|
|
203
|
+
function stagedContents(internalServers) {
|
|
204
|
+
return `${JSON.stringify({ mcpServers: internalServers }, null, 2)}\n`;
|
|
205
|
+
}
|
|
206
|
+
function stagedCacheKey(source, configPath, contents) {
|
|
207
|
+
return createHash("sha256").update("agent-plugin-v1\0").update(source.sourceId).update("\0").update(source.contentDigest).update("\0").update(configPath).update("\0").update(contents).digest("hex");
|
|
202
208
|
}
|
|
203
|
-
|
|
209
|
+
/** The containment base and expanded path of a declared cwd, or undefined when the plugin root is the default. */
|
|
210
|
+
function workingDirectoryCandidate(declared, pluginRoot, pluginDataDirectory) {
|
|
211
|
+
if (declared === void 0) return void 0;
|
|
212
|
+
const cwd = nonEmptyString(declared, "cwd");
|
|
213
|
+
if (cwd.startsWith("./")) return {
|
|
214
|
+
base: pluginRoot,
|
|
215
|
+
candidate: path.resolve(pluginRoot, cwd)
|
|
216
|
+
};
|
|
217
|
+
const expanded = expandPluginPlaceholders(cwd, pluginRoot, pluginDataDirectory);
|
|
218
|
+
if (cwd === "${PLUGIN_ROOT}" || cwd.startsWith("${PLUGIN_ROOT}/")) return {
|
|
219
|
+
base: pluginRoot,
|
|
220
|
+
candidate: path.resolve(expanded)
|
|
221
|
+
};
|
|
222
|
+
if (cwd === "${PLUGIN_DATA}" || cwd.startsWith("${PLUGIN_DATA}/")) return {
|
|
223
|
+
base: pluginDataDirectory,
|
|
224
|
+
candidate: path.resolve(expanded)
|
|
225
|
+
};
|
|
226
|
+
throw new Error("cwd must start with ./, ${PLUGIN_ROOT}, or ${PLUGIN_DATA}");
|
|
227
|
+
}
|
|
228
|
+
/** Rejects a command that is neither a bare executable name nor a ./ path; true when it must be resolved. */
|
|
229
|
+
function isPluginRelativeCommand(command) {
|
|
230
|
+
if (command.startsWith("./")) return true;
|
|
231
|
+
if (command === "." || command === ".." || /[\s/\\]/u.test(command)) throw new Error("command must be a bare executable name or a ./ path inside the plugin");
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
//#endregion
|
|
235
|
+
//#region src/services/agentPluginMcp/sync.ts
|
|
236
|
+
function realContainedPath$1(root, candidate, label) {
|
|
237
|
+
let realCandidate;
|
|
238
|
+
try {
|
|
239
|
+
realCandidate = fs.realpathSync(candidate);
|
|
240
|
+
} catch {
|
|
241
|
+
throw new Error(`${label} does not exist`);
|
|
242
|
+
}
|
|
243
|
+
if (!isInside(root, realCandidate)) throw new Error(`${label} escapes its allowed plugin directory`);
|
|
244
|
+
return realCandidate;
|
|
245
|
+
}
|
|
246
|
+
function normalizeCommand$1(command, pluginRoot) {
|
|
247
|
+
if (!isPluginRelativeCommand(command)) return command;
|
|
248
|
+
const resolved = realContainedPath$1(pluginRoot, path.resolve(pluginRoot, command), "command");
|
|
249
|
+
if (!fs.statSync(resolved).isFile()) throw new Error("command must resolve to a regular file");
|
|
250
|
+
try {
|
|
251
|
+
fs.accessSync(resolved, fs.constants.X_OK);
|
|
252
|
+
} catch {
|
|
253
|
+
throw new Error("command must resolve to an executable file");
|
|
254
|
+
}
|
|
255
|
+
return resolved;
|
|
256
|
+
}
|
|
257
|
+
function normalizeWorkingDirectory$1(declared, pluginRoot, pluginDataDirectory) {
|
|
258
|
+
const declaredCwd = workingDirectoryCandidate(declared, pluginRoot, pluginDataDirectory);
|
|
259
|
+
if (!declaredCwd) return pluginRoot;
|
|
260
|
+
const resolved = realContainedPath$1(declaredCwd.base, declaredCwd.candidate, "cwd");
|
|
261
|
+
if (!fs.statSync(resolved).isDirectory()) throw new Error("cwd must resolve to a directory");
|
|
262
|
+
return resolved;
|
|
263
|
+
}
|
|
264
|
+
function normalizeServer$1(raw, pluginRoot, pluginDataDirectory, name) {
|
|
265
|
+
const type = serverType(raw, name);
|
|
266
|
+
const declaration = raw;
|
|
267
|
+
if (type !== "stdio") return remoteServer(declaration, name, type);
|
|
268
|
+
const command = normalizeCommand$1(nonEmptyString(declaration.command, "command"), pluginRoot);
|
|
269
|
+
const args = optionalStringArray(declaration.args, "args")?.map((item) => expandPluginPlaceholders(item, pluginRoot, pluginDataDirectory));
|
|
270
|
+
const env = normalizeEnvironment(declaration.env, pluginRoot, pluginDataDirectory);
|
|
271
|
+
const cwd = normalizeWorkingDirectory$1(declaration.cwd, pluginRoot, pluginDataDirectory);
|
|
272
|
+
return stdioServer(name, {
|
|
273
|
+
command,
|
|
274
|
+
...args ? { args } : {},
|
|
275
|
+
env,
|
|
276
|
+
cwd
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
function writeStagedInternalConfig$1(target, contents, stagingDirectory) {
|
|
204
280
|
fs.mkdirSync(stagingDirectory, {
|
|
205
|
-
mode:
|
|
281
|
+
mode: 448,
|
|
206
282
|
recursive: true
|
|
207
283
|
});
|
|
208
|
-
fs.chmodSync(stagingDirectory,
|
|
284
|
+
fs.chmodSync(stagingDirectory, 448);
|
|
209
285
|
const temporaryPath = `${target}.${process.pid}-${randomUUID()}.tmp`;
|
|
210
286
|
try {
|
|
211
287
|
fs.writeFileSync(temporaryPath, contents, {
|
|
212
288
|
flag: "wx",
|
|
213
|
-
mode:
|
|
289
|
+
mode: 384
|
|
214
290
|
});
|
|
215
291
|
try {
|
|
216
292
|
fs.renameSync(temporaryPath, target);
|
|
@@ -220,19 +296,11 @@ function writeStagedInternalConfig(target, contents, stagingDirectory) {
|
|
|
220
296
|
const stat = fs.lstatSync(target);
|
|
221
297
|
if (stat.isSymbolicLink() || !stat.isFile() || fs.readFileSync(target, "utf8") !== contents) throw new Error("content-addressed staging path is occupied by different content");
|
|
222
298
|
}
|
|
223
|
-
fs.chmodSync(target,
|
|
299
|
+
fs.chmodSync(target, 384);
|
|
224
300
|
} finally {
|
|
225
301
|
fs.rmSync(temporaryPath, { force: true });
|
|
226
302
|
}
|
|
227
303
|
}
|
|
228
|
-
function emptyResult(diagnostic) {
|
|
229
|
-
return {
|
|
230
|
-
claudeConfig: { mcpServers: {} },
|
|
231
|
-
serverNames: [],
|
|
232
|
-
droppedServers: [],
|
|
233
|
-
diagnostics: [diagnostic]
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
304
|
/**
|
|
237
305
|
* Validates one Agent Plugins v1 `mcp.json` and stages a native mcp-proxy layer.
|
|
238
306
|
*
|
|
@@ -240,12 +308,13 @@ function emptyResult(diagnostic) {
|
|
|
240
308
|
* Document/schema, source identity, or plugin-boundary failures reject the whole
|
|
241
309
|
* source. Only the two portable plugin placeholders are expanded; the staged
|
|
242
310
|
* layer is tagged `internal`, so legacy `${ENV}` interpolation cannot run again.
|
|
311
|
+
*
|
|
312
|
+
* @deprecated Node-only sync shim; use normalizeAgentPluginMcpSourceAsync. Removed in M2.
|
|
243
313
|
*/
|
|
244
314
|
function normalizeAgentPluginMcpSource(source, options) {
|
|
245
|
-
const label =
|
|
315
|
+
const label = sourceLabel(source);
|
|
246
316
|
try {
|
|
247
|
-
|
|
248
|
-
if (!path.isAbsolute(source.pluginRoot) || !path.isAbsolute(source.pluginDataDirectory)) throw new Error("pluginRoot and pluginDataDirectory must be absolute");
|
|
317
|
+
assertProjectionSource(source);
|
|
249
318
|
const pluginRoot = fs.realpathSync(source.pluginRoot);
|
|
250
319
|
try {
|
|
251
320
|
const dataStat = fs.lstatSync(source.pluginDataDirectory);
|
|
@@ -253,55 +322,164 @@ function normalizeAgentPluginMcpSource(source, options) {
|
|
|
253
322
|
} catch (error) {
|
|
254
323
|
if (error.code !== "ENOENT") throw error;
|
|
255
324
|
fs.mkdirSync(source.pluginDataDirectory, {
|
|
256
|
-
mode:
|
|
325
|
+
mode: 448,
|
|
257
326
|
recursive: true
|
|
258
327
|
});
|
|
259
328
|
}
|
|
260
|
-
fs.chmodSync(source.pluginDataDirectory,
|
|
329
|
+
fs.chmodSync(source.pluginDataDirectory, 448);
|
|
261
330
|
fs.accessSync(source.pluginDataDirectory, fs.constants.W_OK);
|
|
262
331
|
const pluginDataDirectory = fs.realpathSync(source.pluginDataDirectory);
|
|
263
|
-
const configPath = realContainedPath(pluginRoot, source.configPath, "mcp.json");
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
332
|
+
const configPath = realContainedPath$1(pluginRoot, source.configPath, "mcp.json");
|
|
333
|
+
assertRootConfigPath(configPath, pluginRoot);
|
|
334
|
+
const servers = parseMcpDocument(source, fs.readFileSync(configPath), label);
|
|
335
|
+
const internalServers = Object.create(null);
|
|
336
|
+
const claudeServers = Object.create(null);
|
|
337
|
+
const droppedServers = [];
|
|
338
|
+
const diagnostics = [];
|
|
339
|
+
for (const [name, rawServer] of Object.entries(servers)) {
|
|
340
|
+
const disposition = serverDisposition(name, options);
|
|
341
|
+
if (disposition === "empty") {
|
|
342
|
+
diagnostics.push(emptyServerDiagnostic(label));
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
if (disposition === "dropped") {
|
|
346
|
+
droppedServers.push(name);
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
try {
|
|
350
|
+
const normalized = normalizeServer$1(rawServer, pluginRoot, pluginDataDirectory, name);
|
|
351
|
+
internalServers[name] = normalized.internal;
|
|
352
|
+
claudeServers[name] = normalized.claude;
|
|
353
|
+
} catch (error) {
|
|
354
|
+
droppedServers.push(name);
|
|
355
|
+
diagnostics.push(skippedServerDiagnostic(label, name, error));
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
const contents = stagedContents(internalServers);
|
|
359
|
+
const target = stagedInternalPath(source, contents, options.stagingDirectory);
|
|
360
|
+
writeStagedInternalConfig$1(target, contents, options.stagingDirectory);
|
|
361
|
+
return {
|
|
362
|
+
configSource: {
|
|
363
|
+
path: target,
|
|
364
|
+
format: "internal",
|
|
365
|
+
cacheKey: stagedCacheKey(source, configPath, contents)
|
|
366
|
+
},
|
|
367
|
+
claudeConfig: { mcpServers: claudeServers },
|
|
368
|
+
serverNames: Object.keys(internalServers),
|
|
369
|
+
droppedServers,
|
|
370
|
+
diagnostics
|
|
371
|
+
};
|
|
372
|
+
} catch (error) {
|
|
373
|
+
return disabledResult(label, error);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
//#endregion
|
|
377
|
+
//#region src/services/agentPluginMcp/index.ts
|
|
378
|
+
async function realContainedPath(fs, root, candidate, label, context) {
|
|
379
|
+
const real = await fs.canonicalPath(candidate, context);
|
|
380
|
+
if (!real.ok) throw new Error(`${label} does not exist`);
|
|
381
|
+
if (!isInside(root, real.value)) throw new Error(`${label} escapes its allowed plugin directory`);
|
|
382
|
+
return real.value;
|
|
383
|
+
}
|
|
384
|
+
async function normalizeCommand(fs, command, pluginRoot, context) {
|
|
385
|
+
if (!isPluginRelativeCommand(command)) return command;
|
|
386
|
+
const resolved = await realContainedPath(fs, pluginRoot, path.resolve(pluginRoot, command), "command", context);
|
|
387
|
+
if (getOrThrow(await fs.fileInfo(resolved, context)).kind !== "file") throw new Error("command must resolve to a regular file");
|
|
388
|
+
const mode = await nodeHost.fileMode(resolved);
|
|
389
|
+
if (mode !== void 0 && (mode & 73) === 0) throw new Error("command must resolve to an executable file");
|
|
390
|
+
return resolved;
|
|
391
|
+
}
|
|
392
|
+
async function normalizeWorkingDirectory(fs, declared, pluginRoot, pluginDataDirectory, context) {
|
|
393
|
+
const declaredCwd = workingDirectoryCandidate(declared, pluginRoot, pluginDataDirectory);
|
|
394
|
+
if (!declaredCwd) return pluginRoot;
|
|
395
|
+
const resolved = await realContainedPath(fs, declaredCwd.base, declaredCwd.candidate, "cwd", context);
|
|
396
|
+
if (getOrThrow(await fs.fileInfo(resolved, context)).kind !== "directory") throw new Error("cwd must resolve to a directory");
|
|
397
|
+
return resolved;
|
|
398
|
+
}
|
|
399
|
+
async function normalizeServer(fs, raw, pluginRoot, pluginDataDirectory, name, context) {
|
|
400
|
+
const type = serverType(raw, name);
|
|
401
|
+
const declaration = raw;
|
|
402
|
+
if (type !== "stdio") return remoteServer(declaration, name, type);
|
|
403
|
+
const command = await normalizeCommand(fs, nonEmptyString(declaration.command, "command"), pluginRoot, context);
|
|
404
|
+
const args = optionalStringArray(declaration.args, "args")?.map((item) => expandPluginPlaceholders(item, pluginRoot, pluginDataDirectory));
|
|
405
|
+
const env = normalizeEnvironment(declaration.env, pluginRoot, pluginDataDirectory);
|
|
406
|
+
const cwd = await normalizeWorkingDirectory(fs, declaration.cwd, pluginRoot, pluginDataDirectory, context);
|
|
407
|
+
return stdioServer(name, {
|
|
408
|
+
command,
|
|
409
|
+
...args ? { args } : {},
|
|
410
|
+
env,
|
|
411
|
+
cwd
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
/** Owner-only plugin data directory; a symbolic link or non-directory rejects the source. */
|
|
415
|
+
async function preparePluginDataDirectory(fs, directory, context) {
|
|
416
|
+
const info = await fs.fileInfo(directory, context);
|
|
417
|
+
if (info.ok) {
|
|
418
|
+
if (info.value.kind !== "directory") throw new Error("pluginDataDirectory must be a real directory");
|
|
419
|
+
} else if (info.error.code === "not_found") getOrThrow(await fs.createDir(directory, { recursive: true }, context));
|
|
420
|
+
else throw info.error;
|
|
421
|
+
await nodeHost.setMode(directory, 448);
|
|
422
|
+
return getOrThrow(await fs.canonicalPath(directory, context));
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Content-addressed and owner-only. The name hashes the contents, so replacing an
|
|
426
|
+
* existing staged file through a uniquely named temporary file never changes what it holds.
|
|
427
|
+
*/
|
|
428
|
+
async function writeStagedInternalConfig(fs, target, contents, stagingDirectory, context) {
|
|
429
|
+
getOrThrow(await fs.createDir(stagingDirectory, { recursive: true }, context));
|
|
430
|
+
await nodeHost.setMode(stagingDirectory, 448);
|
|
431
|
+
await writeFileAtomic(fs, target, contents, context);
|
|
432
|
+
await nodeHost.setMode(target, 384);
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Validates one Agent Plugins v1 `mcp.json` and stages a native mcp-proxy layer,
|
|
436
|
+
* reading and writing through the injected file system.
|
|
437
|
+
*
|
|
438
|
+
* Server validation is isolated: one malformed server is diagnosed and skipped.
|
|
439
|
+
* Document/schema, source identity, or plugin-boundary failures reject the whole
|
|
440
|
+
* source. Only the two portable plugin placeholders are expanded; the staged
|
|
441
|
+
* layer is tagged `internal`, so legacy `${ENV}` interpolation cannot run again.
|
|
442
|
+
*/
|
|
443
|
+
async function normalizeAgentPluginMcpSourceAsync(fs, source, options, context) {
|
|
444
|
+
const label = sourceLabel(source);
|
|
445
|
+
try {
|
|
446
|
+
assertProjectionSource(source);
|
|
447
|
+
const pluginRoot = getOrThrow(await fs.canonicalPath(source.pluginRoot, context));
|
|
448
|
+
const pluginDataDirectory = await preparePluginDataDirectory(fs, source.pluginDataDirectory, context);
|
|
449
|
+
const configPath = await realContainedPath(fs, pluginRoot, source.configPath, "mcp.json", context);
|
|
450
|
+
assertRootConfigPath(configPath, pluginRoot);
|
|
451
|
+
const servers = parseMcpDocument(source, getOrThrow(await fs.readBinaryFile(configPath, context)), label);
|
|
275
452
|
const internalServers = Object.create(null);
|
|
276
453
|
const claudeServers = Object.create(null);
|
|
277
454
|
const droppedServers = [];
|
|
278
455
|
const diagnostics = [];
|
|
279
|
-
for (const [name, rawServer] of Object.entries(
|
|
280
|
-
|
|
281
|
-
|
|
456
|
+
for (const [name, rawServer] of Object.entries(servers)) {
|
|
457
|
+
const disposition = serverDisposition(name, options);
|
|
458
|
+
if (disposition === "empty") {
|
|
459
|
+
diagnostics.push(emptyServerDiagnostic(label));
|
|
282
460
|
continue;
|
|
283
461
|
}
|
|
284
|
-
if (
|
|
462
|
+
if (disposition === "dropped") {
|
|
285
463
|
droppedServers.push(name);
|
|
286
464
|
continue;
|
|
287
465
|
}
|
|
288
466
|
try {
|
|
289
|
-
const normalized = normalizeServer(rawServer, pluginRoot, pluginDataDirectory, name);
|
|
467
|
+
const normalized = await normalizeServer(fs, rawServer, pluginRoot, pluginDataDirectory, name, context);
|
|
290
468
|
internalServers[name] = normalized.internal;
|
|
291
469
|
claudeServers[name] = normalized.claude;
|
|
292
470
|
} catch (error) {
|
|
293
471
|
droppedServers.push(name);
|
|
294
|
-
diagnostics.push(
|
|
472
|
+
diagnostics.push(skippedServerDiagnostic(label, name, error));
|
|
295
473
|
}
|
|
296
474
|
}
|
|
297
|
-
const contents =
|
|
475
|
+
const contents = stagedContents(internalServers);
|
|
298
476
|
const target = stagedInternalPath(source, contents, options.stagingDirectory);
|
|
299
|
-
writeStagedInternalConfig(target, contents, options.stagingDirectory);
|
|
477
|
+
await writeStagedInternalConfig(fs, target, contents, options.stagingDirectory, context);
|
|
300
478
|
return {
|
|
301
479
|
configSource: {
|
|
302
480
|
path: target,
|
|
303
481
|
format: "internal",
|
|
304
|
-
cacheKey:
|
|
482
|
+
cacheKey: stagedCacheKey(source, configPath, contents)
|
|
305
483
|
},
|
|
306
484
|
claudeConfig: { mcpServers: claudeServers },
|
|
307
485
|
serverNames: Object.keys(internalServers),
|
|
@@ -309,10 +487,10 @@ function normalizeAgentPluginMcpSource(source, options) {
|
|
|
309
487
|
diagnostics
|
|
310
488
|
};
|
|
311
489
|
} catch (error) {
|
|
312
|
-
return
|
|
490
|
+
return disabledResult(label, error);
|
|
313
491
|
}
|
|
314
492
|
}
|
|
315
493
|
//#endregion
|
|
316
|
-
export { normalizeAgentPluginMcpSource };
|
|
494
|
+
export { normalizeAgentPluginMcpSource, normalizeAgentPluginMcpSourceAsync };
|
|
317
495
|
|
|
318
496
|
//# sourceMappingURL=agentPluginMcp.mjs.map
|