@agimon-ai/po-config 0.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +170 -0
- package/dist/agentPluginMcp.cjs +322 -0
- package/dist/agentPluginMcp.cjs.map +1 -0
- package/dist/agentPluginMcp.d.mts +38 -0
- package/dist/agentPluginMcp.d.mts.map +1 -0
- package/dist/agentPluginMcp.mjs +318 -0
- package/dist/agentPluginMcp.mjs.map +1 -0
- package/dist/apiContracts.cjs +203 -0
- package/dist/apiContracts.cjs.map +1 -0
- package/dist/apiContracts.d.mts +53 -0
- package/dist/apiContracts.d.mts.map +1 -0
- package/dist/apiContracts.mjs +198 -0
- package/dist/apiContracts.mjs.map +1 -0
- package/dist/atomicJson-1W0WhuFF.mjs +44 -0
- package/dist/atomicJson-1W0WhuFF.mjs.map +1 -0
- package/dist/atomicJson-Dt2z_DXl.cjs +52 -0
- package/dist/atomicJson-Dt2z_DXl.cjs.map +1 -0
- package/dist/atomicJson.cjs +3 -0
- package/dist/atomicJson.d.mts +2 -0
- package/dist/atomicJson.mjs +2 -0
- package/dist/config-BUw5kHsx.cjs +219 -0
- package/dist/config-BUw5kHsx.cjs.map +1 -0
- package/dist/config-CKA07FxG.mjs +162 -0
- package/dist/config-CKA07FxG.mjs.map +1 -0
- package/dist/config-Cm3EV1jp.d.mts +320 -0
- package/dist/config-Cm3EV1jp.d.mts.map +1 -0
- package/dist/config-NSHRd6na.mjs +2 -0
- package/dist/config-zZz80Mh5.cjs +1 -0
- package/dist/config.cjs +24 -0
- package/dist/config.d.mts +3 -0
- package/dist/config.mjs +3 -0
- package/dist/configPolicy--TNX7feH.mjs +718 -0
- package/dist/configPolicy--TNX7feH.mjs.map +1 -0
- package/dist/configPolicy-DmsZEp0t.cjs +795 -0
- package/dist/configPolicy-DmsZEp0t.cjs.map +1 -0
- package/dist/configSchema.cjs +0 -0
- package/dist/configSchema.d.mts +2 -0
- package/dist/configSchema.mjs +1 -0
- package/dist/configWriter-BTuinLjs.cjs +150 -0
- package/dist/configWriter-BTuinLjs.cjs.map +1 -0
- package/dist/configWriter-BgkGaLrf.mjs +130 -0
- package/dist/configWriter-BgkGaLrf.mjs.map +1 -0
- package/dist/configWriter.cjs +5 -0
- package/dist/configWriter.d.mts +2 -0
- package/dist/configWriter.mjs +2 -0
- package/dist/domains-CBYkuxs5.cjs +727 -0
- package/dist/domains-CBYkuxs5.cjs.map +1 -0
- package/dist/domains-DZOu9vYM.mjs +633 -0
- package/dist/domains-DZOu9vYM.mjs.map +1 -0
- package/dist/domains.cjs +19 -0
- package/dist/domains.d.mts +3 -0
- package/dist/domains.mjs +3 -0
- package/dist/extensions/mcp-ui.mjs +101 -0
- package/dist/extensions/mcp-ui.mjs.map +1 -0
- package/dist/extensions/mcp.cjs +171 -0
- package/dist/extensions/mcp.cjs.map +1 -0
- package/dist/extensions/mcp.d.mts +5 -0
- package/dist/extensions/mcp.d.mts.map +1 -0
- package/dist/extensions/mcp.mjs +166 -0
- package/dist/extensions/mcp.mjs.map +1 -0
- package/dist/extensions/server.cjs +504 -0
- package/dist/extensions/server.cjs.map +1 -0
- package/dist/extensions/server.d.mts +5 -0
- package/dist/extensions/server.d.mts.map +1 -0
- package/dist/extensions/server.mjs +499 -0
- package/dist/extensions/server.mjs.map +1 -0
- package/dist/harnessState-CCyBeutB.cjs +188 -0
- package/dist/harnessState-CCyBeutB.cjs.map +1 -0
- package/dist/harnessState-Dn_S7fB9.mjs +163 -0
- package/dist/harnessState-Dn_S7fB9.mjs.map +1 -0
- package/dist/harnessState.cjs +6 -0
- package/dist/harnessState.d.mts +2 -0
- package/dist/harnessState.mjs +2 -0
- package/dist/harnessStore-CJSxdSkV.cjs +343 -0
- package/dist/harnessStore-CJSxdSkV.cjs.map +1 -0
- package/dist/harnessStore-CltwLB7M.mjs +262 -0
- package/dist/harnessStore-CltwLB7M.mjs.map +1 -0
- package/dist/harnessStore.cjs +15 -0
- package/dist/harnessStore.d.mts +2 -0
- package/dist/harnessStore.mjs +2 -0
- package/dist/index-BAaTySaM.d.mts +35 -0
- package/dist/index-BAaTySaM.d.mts.map +1 -0
- package/dist/index-BT29GZx5.d.mts +142 -0
- package/dist/index-BT29GZx5.d.mts.map +1 -0
- package/dist/index-B_lp0W3U.d.mts +114 -0
- package/dist/index-B_lp0W3U.d.mts.map +1 -0
- package/dist/index-C6GaYjq-.d.mts +6 -0
- package/dist/index-C6GaYjq-.d.mts.map +1 -0
- package/dist/index-CIQrKS1A.d.mts +50 -0
- package/dist/index-CIQrKS1A.d.mts.map +1 -0
- package/dist/index-CRcoVYXz.d.mts +39 -0
- package/dist/index-CRcoVYXz.d.mts.map +1 -0
- package/dist/index-CVlciCJF.d.mts +40 -0
- package/dist/index-CVlciCJF.d.mts.map +1 -0
- package/dist/index-CeOk2kqs.d.mts +118 -0
- package/dist/index-CeOk2kqs.d.mts.map +1 -0
- package/dist/index-Ch7ptOkW.d.mts +54 -0
- package/dist/index-Ch7ptOkW.d.mts.map +1 -0
- package/dist/index-Cvdt-Y-i.d.mts +66 -0
- package/dist/index-Cvdt-Y-i.d.mts.map +1 -0
- package/dist/index-DJpG-I9K.d.mts +122 -0
- package/dist/index-DJpG-I9K.d.mts.map +1 -0
- package/dist/index-DNk4q0Qm.d.mts +81 -0
- package/dist/index-DNk4q0Qm.d.mts.map +1 -0
- package/dist/index.cjs +121 -0
- package/dist/index.d.mts +15 -0
- package/dist/index.mjs +15 -0
- package/dist/init-C_9nyp3-.cjs +448 -0
- package/dist/init-C_9nyp3-.cjs.map +1 -0
- package/dist/init-DJ6wm-dr.mjs +415 -0
- package/dist/init-DJ6wm-dr.mjs.map +1 -0
- package/dist/init.cjs +7 -0
- package/dist/init.d.mts +2 -0
- package/dist/init.mjs +2 -0
- package/dist/layeredConfig-B922ibgn.mjs +67 -0
- package/dist/layeredConfig-B922ibgn.mjs.map +1 -0
- package/dist/layeredConfig-DdI5ysUf.cjs +94 -0
- package/dist/layeredConfig-DdI5ysUf.cjs.map +1 -0
- package/dist/layeredConfig.cjs +6 -0
- package/dist/layeredConfig.d.mts +2 -0
- package/dist/layeredConfig.mjs +2 -0
- package/dist/majorModes-CmPLEpMT.mjs +333 -0
- package/dist/majorModes-CmPLEpMT.mjs.map +1 -0
- package/dist/majorModes-DPhVMuhT.cjs +383 -0
- package/dist/majorModes-DPhVMuhT.cjs.map +1 -0
- package/dist/majorModes.cjs +10 -0
- package/dist/majorModes.d.mts +2 -0
- package/dist/majorModes.mjs +2 -0
- package/dist/piConfig-Bx26HMb_.d.mts +33 -0
- package/dist/piConfig-Bx26HMb_.d.mts.map +1 -0
- package/dist/piConfig-CCBdZXQr.cjs +260 -0
- package/dist/piConfig-CCBdZXQr.cjs.map +1 -0
- package/dist/piConfig-qGyCbcVj.mjs +197 -0
- package/dist/piConfig-qGyCbcVj.mjs.map +1 -0
- package/dist/piConfig.cjs +12 -0
- package/dist/piConfig.d.mts +2 -0
- package/dist/piConfig.mjs +2 -0
- package/dist/piContext.cjs +18 -0
- package/dist/piContext.d.mts +3 -0
- package/dist/piContext.mjs +2 -0
- package/dist/profiles-CTrUCmIh.d.mts +27 -0
- package/dist/profiles-CTrUCmIh.d.mts.map +1 -0
- package/dist/profiles-DnF9DBpd.cjs +552 -0
- package/dist/profiles-DnF9DBpd.cjs.map +1 -0
- package/dist/profiles-fujQKrS0.mjs +483 -0
- package/dist/profiles-fujQKrS0.mjs.map +1 -0
- package/dist/profiles.cjs +13 -0
- package/dist/profiles.d.mts +25 -0
- package/dist/profiles.d.mts.map +1 -0
- package/dist/profiles.mjs +2 -0
- package/dist/rolldown-runtime-VH7oDXx4.cjs +28 -0
- package/dist/selectionSwitch.cjs +70 -0
- package/dist/selectionSwitch.cjs.map +1 -0
- package/dist/selectionSwitch.d.mts +30 -0
- package/dist/selectionSwitch.d.mts.map +1 -0
- package/dist/selectionSwitch.mjs +64 -0
- package/dist/selectionSwitch.mjs.map +1 -0
- package/dist/sessionConfig-Boh4Fdje.cjs +342 -0
- package/dist/sessionConfig-Boh4Fdje.cjs.map +1 -0
- package/dist/sessionConfig-CtLoc-lO.mjs +240 -0
- package/dist/sessionConfig-CtLoc-lO.mjs.map +1 -0
- package/dist/types.cjs +9 -0
- package/dist/types.d.mts +2 -0
- package/dist/types.mjs +2 -0
- package/llms.txt +12 -0
- package/package.json +206 -0
- package/src/prompts/po-author-config/SKILL.md +26 -0
- package/src/prompts/po-author-config/agents/openai.yaml +4 -0
- package/src/prompts/po-author-config/references/config-contract.md +201 -0
|
@@ -0,0 +1,318 @@
|
|
|
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
|
+
import path from "node:path";
|
|
6
|
+
import { AGENT_PLUGIN_MCP_SCHEMA_URL } from "@agimon-ai/po-core/mcpProjection";
|
|
7
|
+
//#region src/services/agentPluginMcp/index.ts
|
|
8
|
+
const PRIVATE_FILE_MODE = 384;
|
|
9
|
+
const PRIVATE_DIRECTORY_MODE = 448;
|
|
10
|
+
const RESERVED_ENVIRONMENT_KEYS = /* @__PURE__ */ new Set(["PLUGIN_ROOT", "PLUGIN_DATA"]);
|
|
11
|
+
const PROXY_SERVER_ALIASES = /* @__PURE__ */ new Set(["mcp-proxy", "agiflow-proxy"]);
|
|
12
|
+
function isObject(value) {
|
|
13
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14
|
+
}
|
|
15
|
+
function onlyKeys(value, allowed, label) {
|
|
16
|
+
const unexpected = Object.keys(value).find((key) => !allowed.includes(key));
|
|
17
|
+
if (unexpected) throw new Error(`${label} contains unsupported field "${unexpected}"`);
|
|
18
|
+
}
|
|
19
|
+
function nonEmptyString(value, label) {
|
|
20
|
+
if (typeof value !== "string" || value.length === 0) throw new Error(`${label} must be a non-empty string`);
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
function optionalStringArray(value, label) {
|
|
24
|
+
if (value === void 0) return void 0;
|
|
25
|
+
if (!Array.isArray(value)) throw new Error(`${label} must be an array of strings`);
|
|
26
|
+
return value.map((item, index) => {
|
|
27
|
+
if (typeof item !== "string") throw new Error(`${label}[${index}] must be a string`);
|
|
28
|
+
return item;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function optionalStringRecord(value, label) {
|
|
32
|
+
if (value === void 0) return void 0;
|
|
33
|
+
if (!isObject(value)) throw new Error(`${label} must be an object of string values`);
|
|
34
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => {
|
|
35
|
+
if (typeof item !== "string") throw new Error(`${label}.${key} must be a string`);
|
|
36
|
+
return [key, item];
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
function expandPluginPlaceholders(value, pluginRoot, pluginDataDirectory) {
|
|
40
|
+
return value.replace(/\$\{PLUGIN_(ROOT|DATA)\}/gu, (placeholder) => placeholder === "${PLUGIN_ROOT}" ? pluginRoot : pluginDataDirectory);
|
|
41
|
+
}
|
|
42
|
+
function isInside(root, candidate) {
|
|
43
|
+
const relative = path.relative(root, candidate);
|
|
44
|
+
return relative === "" || !relative.startsWith(`..${path.sep}`) && relative !== ".." && !path.isAbsolute(relative);
|
|
45
|
+
}
|
|
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
|
+
function normalizeEnvironment(value, pluginRoot, pluginDataDirectory) {
|
|
90
|
+
const declared = optionalStringRecord(value, "env") ?? {};
|
|
91
|
+
for (const key of Object.keys(declared)) {
|
|
92
|
+
const reservedKey = process.platform === "win32" ? key.toUpperCase() : key;
|
|
93
|
+
if (RESERVED_ENVIRONMENT_KEYS.has(reservedKey)) throw new Error(`env key "${key}" is reserved by Agent Plugins`);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
...Object.fromEntries(Object.entries(declared).map(([key, item]) => [key, expandPluginPlaceholders(item, pluginRoot, pluginDataDirectory)])),
|
|
97
|
+
PLUGIN_ROOT: pluginRoot,
|
|
98
|
+
PLUGIN_DATA: pluginDataDirectory
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function isLoopbackHost(hostname) {
|
|
102
|
+
const bareHostname = hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname;
|
|
103
|
+
if (bareHostname.toLowerCase() === "localhost") return true;
|
|
104
|
+
const family = isIP(bareHostname);
|
|
105
|
+
if (family === 4) return bareHostname.split(".")[0] === "127";
|
|
106
|
+
return family === 6 && bareHostname === "::1";
|
|
107
|
+
}
|
|
108
|
+
function normalizeUrl(value) {
|
|
109
|
+
const raw = nonEmptyString(value, "url");
|
|
110
|
+
let parsed;
|
|
111
|
+
try {
|
|
112
|
+
parsed = new URL(raw);
|
|
113
|
+
} catch {
|
|
114
|
+
throw new Error("url must be an absolute HTTP(S) URL");
|
|
115
|
+
}
|
|
116
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new Error("url must use http or https");
|
|
117
|
+
if (parsed.username || parsed.password) throw new Error("url must not contain user information");
|
|
118
|
+
if (parsed.hash) throw new Error("url must not contain a fragment");
|
|
119
|
+
if (parsed.protocol === "http:" && !isLoopbackHost(parsed.hostname)) throw new Error("non-loopback MCP URLs must use https");
|
|
120
|
+
return raw;
|
|
121
|
+
}
|
|
122
|
+
function normalizeHeaders(value) {
|
|
123
|
+
const headers = optionalStringRecord(value, "headers");
|
|
124
|
+
if (!headers) return void 0;
|
|
125
|
+
const seen = /* @__PURE__ */ new Set();
|
|
126
|
+
for (const [name, item] of Object.entries(headers)) {
|
|
127
|
+
const canonical = name.toLowerCase();
|
|
128
|
+
if (seen.has(canonical)) throw new Error(`headers contain duplicate name "${name}"`);
|
|
129
|
+
seen.add(canonical);
|
|
130
|
+
try {
|
|
131
|
+
validateHeaderName(name);
|
|
132
|
+
validateHeaderValue(name, item);
|
|
133
|
+
} catch {
|
|
134
|
+
throw new Error(`header "${name}" is invalid`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return headers;
|
|
138
|
+
}
|
|
139
|
+
function normalizeServer(raw, pluginRoot, pluginDataDirectory, name) {
|
|
140
|
+
if (!isObject(raw)) throw new Error("definition must be an object");
|
|
141
|
+
const type = nonEmptyString(raw.type, "type");
|
|
142
|
+
if (type === "stdio") {
|
|
143
|
+
onlyKeys(raw, [
|
|
144
|
+
"type",
|
|
145
|
+
"command",
|
|
146
|
+
"args",
|
|
147
|
+
"env",
|
|
148
|
+
"cwd"
|
|
149
|
+
], `server "${name}"`);
|
|
150
|
+
const command = normalizeCommand(nonEmptyString(raw.command, "command"), pluginRoot);
|
|
151
|
+
const args = optionalStringArray(raw.args, "args")?.map((item) => expandPluginPlaceholders(item, pluginRoot, pluginDataDirectory));
|
|
152
|
+
const env = normalizeEnvironment(raw.env, pluginRoot, pluginDataDirectory);
|
|
153
|
+
const cwd = normalizeWorkingDirectory(raw.cwd, pluginRoot, pluginDataDirectory);
|
|
154
|
+
const config = {
|
|
155
|
+
command,
|
|
156
|
+
...args ? { args } : {},
|
|
157
|
+
env,
|
|
158
|
+
cwd
|
|
159
|
+
};
|
|
160
|
+
return {
|
|
161
|
+
internal: {
|
|
162
|
+
name,
|
|
163
|
+
transport: "stdio",
|
|
164
|
+
config
|
|
165
|
+
},
|
|
166
|
+
claude: {
|
|
167
|
+
type: "stdio",
|
|
168
|
+
...config
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
if (type === "streamable-http" || type === "sse") {
|
|
173
|
+
onlyKeys(raw, [
|
|
174
|
+
"type",
|
|
175
|
+
"url",
|
|
176
|
+
"headers"
|
|
177
|
+
], `server "${name}"`);
|
|
178
|
+
const url = normalizeUrl(raw.url);
|
|
179
|
+
const headers = normalizeHeaders(raw.headers);
|
|
180
|
+
const transport = type === "streamable-http" ? "http" : "sse";
|
|
181
|
+
const config = {
|
|
182
|
+
url,
|
|
183
|
+
...headers ? { headers } : {}
|
|
184
|
+
};
|
|
185
|
+
return {
|
|
186
|
+
internal: {
|
|
187
|
+
name,
|
|
188
|
+
transport,
|
|
189
|
+
config
|
|
190
|
+
},
|
|
191
|
+
claude: {
|
|
192
|
+
type: transport,
|
|
193
|
+
...config
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
throw new Error(`unsupported transport type "${type}"`);
|
|
198
|
+
}
|
|
199
|
+
function stagedInternalPath(source, contents, stagingDirectory) {
|
|
200
|
+
const digest = createHash("sha256").update(source.sourceId).update("\0").update(source.contentDigest).update("\0").update(contents).digest("hex").slice(0, 20);
|
|
201
|
+
return path.join(stagingDirectory, `agent-plugin-mcp-${digest}.internal.json`);
|
|
202
|
+
}
|
|
203
|
+
function writeStagedInternalConfig(target, contents, stagingDirectory) {
|
|
204
|
+
fs.mkdirSync(stagingDirectory, {
|
|
205
|
+
mode: PRIVATE_DIRECTORY_MODE,
|
|
206
|
+
recursive: true
|
|
207
|
+
});
|
|
208
|
+
fs.chmodSync(stagingDirectory, PRIVATE_DIRECTORY_MODE);
|
|
209
|
+
const temporaryPath = `${target}.${process.pid}-${randomUUID()}.tmp`;
|
|
210
|
+
try {
|
|
211
|
+
fs.writeFileSync(temporaryPath, contents, {
|
|
212
|
+
flag: "wx",
|
|
213
|
+
mode: PRIVATE_FILE_MODE
|
|
214
|
+
});
|
|
215
|
+
try {
|
|
216
|
+
fs.renameSync(temporaryPath, target);
|
|
217
|
+
} catch (error) {
|
|
218
|
+
const code = error.code;
|
|
219
|
+
if (code !== "EEXIST" && code !== "EPERM") throw error;
|
|
220
|
+
const stat = fs.lstatSync(target);
|
|
221
|
+
if (stat.isSymbolicLink() || !stat.isFile() || fs.readFileSync(target, "utf8") !== contents) throw new Error("content-addressed staging path is occupied by different content");
|
|
222
|
+
}
|
|
223
|
+
fs.chmodSync(target, PRIVATE_FILE_MODE);
|
|
224
|
+
} finally {
|
|
225
|
+
fs.rmSync(temporaryPath, { force: true });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function emptyResult(diagnostic) {
|
|
229
|
+
return {
|
|
230
|
+
claudeConfig: { mcpServers: {} },
|
|
231
|
+
serverNames: [],
|
|
232
|
+
droppedServers: [],
|
|
233
|
+
diagnostics: [diagnostic]
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Validates one Agent Plugins v1 `mcp.json` and stages a native mcp-proxy layer.
|
|
238
|
+
*
|
|
239
|
+
* Server validation is isolated: one malformed server is diagnosed and skipped.
|
|
240
|
+
* Document/schema, source identity, or plugin-boundary failures reject the whole
|
|
241
|
+
* source. Only the two portable plugin placeholders are expanded; the staged
|
|
242
|
+
* layer is tagged `internal`, so legacy `${ENV}` interpolation cannot run again.
|
|
243
|
+
*/
|
|
244
|
+
function normalizeAgentPluginMcpSource(source, options) {
|
|
245
|
+
const label = `Agent Plugin MCP source "${source.sourceId}"`;
|
|
246
|
+
try {
|
|
247
|
+
if (source.mcpSchemaUrl !== AGENT_PLUGIN_MCP_SCHEMA_URL) throw new Error(`unsupported schema "${String(source.mcpSchemaUrl)}"`);
|
|
248
|
+
if (!path.isAbsolute(source.pluginRoot) || !path.isAbsolute(source.pluginDataDirectory)) throw new Error("pluginRoot and pluginDataDirectory must be absolute");
|
|
249
|
+
const pluginRoot = fs.realpathSync(source.pluginRoot);
|
|
250
|
+
try {
|
|
251
|
+
const dataStat = fs.lstatSync(source.pluginDataDirectory);
|
|
252
|
+
if (dataStat.isSymbolicLink() || !dataStat.isDirectory()) throw new Error("pluginDataDirectory must be a real directory");
|
|
253
|
+
} catch (error) {
|
|
254
|
+
if (error.code !== "ENOENT") throw error;
|
|
255
|
+
fs.mkdirSync(source.pluginDataDirectory, {
|
|
256
|
+
mode: PRIVATE_DIRECTORY_MODE,
|
|
257
|
+
recursive: true
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
fs.chmodSync(source.pluginDataDirectory, PRIVATE_DIRECTORY_MODE);
|
|
261
|
+
fs.accessSync(source.pluginDataDirectory, fs.constants.W_OK);
|
|
262
|
+
const pluginDataDirectory = fs.realpathSync(source.pluginDataDirectory);
|
|
263
|
+
const configPath = realContainedPath(pluginRoot, source.configPath, "mcp.json");
|
|
264
|
+
if (path.dirname(configPath) !== pluginRoot || path.basename(configPath) !== "mcp.json") throw new Error("portable plugin config must be root mcp.json");
|
|
265
|
+
const bytes = fs.readFileSync(configPath);
|
|
266
|
+
if (createHash("sha256").update(bytes).digest("hex") !== source.contentDigest) throw new Error("content digest does not match the projection");
|
|
267
|
+
const parsed = JSON.parse(bytes.toString("utf8"));
|
|
268
|
+
if (!isObject(parsed)) throw new Error("document must be an object");
|
|
269
|
+
onlyKeys(parsed, ["$schema", "mcpServers"], label);
|
|
270
|
+
if (parsed.$schema !== source.mcpSchemaUrl) throw new Error("$schema does not match the projected schema");
|
|
271
|
+
if (!isObject(parsed.mcpServers)) throw new Error("mcpServers must be an object");
|
|
272
|
+
const allowed = options.allowedServers;
|
|
273
|
+
const keepAll = !allowed || allowed.length === 0;
|
|
274
|
+
const stripProxyWrappers = options.stripProxyWrappers ?? true;
|
|
275
|
+
const internalServers = Object.create(null);
|
|
276
|
+
const claudeServers = Object.create(null);
|
|
277
|
+
const droppedServers = [];
|
|
278
|
+
const diagnostics = [];
|
|
279
|
+
for (const [name, rawServer] of Object.entries(parsed.mcpServers)) {
|
|
280
|
+
if (!name) {
|
|
281
|
+
diagnostics.push(`${label} contains an empty server name; that entry was skipped.`);
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
if (!keepAll && !allowed.includes(name) || stripProxyWrappers && PROXY_SERVER_ALIASES.has(name)) {
|
|
285
|
+
droppedServers.push(name);
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
try {
|
|
289
|
+
const normalized = normalizeServer(rawServer, pluginRoot, pluginDataDirectory, name);
|
|
290
|
+
internalServers[name] = normalized.internal;
|
|
291
|
+
claudeServers[name] = normalized.claude;
|
|
292
|
+
} catch (error) {
|
|
293
|
+
droppedServers.push(name);
|
|
294
|
+
diagnostics.push(`${label} skipped server "${name}": ${error instanceof Error ? error.message : String(error)}`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const contents = `${JSON.stringify({ mcpServers: internalServers }, null, 2)}\n`;
|
|
298
|
+
const target = stagedInternalPath(source, contents, options.stagingDirectory);
|
|
299
|
+
writeStagedInternalConfig(target, contents, options.stagingDirectory);
|
|
300
|
+
return {
|
|
301
|
+
configSource: {
|
|
302
|
+
path: target,
|
|
303
|
+
format: "internal",
|
|
304
|
+
cacheKey: 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")
|
|
305
|
+
},
|
|
306
|
+
claudeConfig: { mcpServers: claudeServers },
|
|
307
|
+
serverNames: Object.keys(internalServers),
|
|
308
|
+
droppedServers,
|
|
309
|
+
diagnostics
|
|
310
|
+
};
|
|
311
|
+
} catch (error) {
|
|
312
|
+
return emptyResult(`${label} was disabled: ${error instanceof Error ? error.message : String(error)}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
//#endregion
|
|
316
|
+
export { normalizeAgentPluginMcpSource };
|
|
317
|
+
|
|
318
|
+
//# sourceMappingURL=agentPluginMcp.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentPluginMcp.mjs","names":[],"sources":["../src/services/agentPluginMcp/index.ts"],"sourcesContent":["import { createHash, randomUUID } from 'node:crypto';\nimport fs from 'node:fs';\nimport { validateHeaderName, validateHeaderValue } from 'node:http';\nimport { isIP } from 'node:net';\nimport path from 'node:path';\n\nimport { AGENT_PLUGIN_MCP_SCHEMA_URL, type DoomMcpAgentPluginProjectionSource } from '@agimon-ai/po-core/mcpProjection';\n\nconst PRIVATE_FILE_MODE = 0o600;\nconst PRIVATE_DIRECTORY_MODE = 0o700;\nconst RESERVED_ENVIRONMENT_KEYS = new Set(['PLUGIN_ROOT', 'PLUGIN_DATA']);\nconst PROXY_SERVER_ALIASES = new Set(['mcp-proxy', 'agiflow-proxy']);\n\ntype JsonObject = Record<string, unknown>;\n\nexport interface AgentPluginMcpConfigSource {\n path: string;\n format: 'internal';\n cacheKey: string;\n}\n\nexport interface NormalizedAgentPluginMcpSource {\n /** Owner-only, content-addressed layer that bypasses Claude env interpolation. */\n configSource?: AgentPluginMcpConfigSource;\n /** Claude-compatible definitions for an external merged config. */\n claudeConfig: { mcpServers: Record<string, JsonObject> };\n serverNames: string[];\n droppedServers: string[];\n diagnostics: string[];\n}\n\nexport interface NormalizeAgentPluginMcpOptions {\n stagingDirectory: string;\n /** Empty and absent lists both mean keep every server. */\n allowedServers?: readonly string[];\n /** Doom strips nested wrappers; external-only callers may opt out. */\n stripProxyWrappers?: boolean;\n}\n\ninterface NormalizedServer {\n internal: JsonObject;\n claude: JsonObject;\n}\n\nfunction isObject(value: unknown): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction onlyKeys(value: JsonObject, allowed: readonly string[], label: string): void {\n const unexpected = Object.keys(value).find((key) => !allowed.includes(key));\n if (unexpected) throw new Error(`${label} contains unsupported field \"${unexpected}\"`);\n}\n\nfunction nonEmptyString(value: unknown, label: string): string {\n if (typeof value !== 'string' || value.length === 0) throw new Error(`${label} must be a non-empty string`);\n return value;\n}\n\nfunction optionalStringArray(value: unknown, label: string): string[] | undefined {\n if (value === undefined) return undefined;\n if (!Array.isArray(value)) throw new Error(`${label} must be an array of strings`);\n return value.map((item, index) => {\n if (typeof item !== 'string') throw new Error(`${label}[${index}] must be a string`);\n return item;\n });\n}\n\nfunction optionalStringRecord(value: unknown, label: string): Record<string, string> | undefined {\n if (value === undefined) return undefined;\n if (!isObject(value)) throw new Error(`${label} must be an object of string values`);\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => {\n if (typeof item !== 'string') throw new Error(`${label}.${key} must be a string`);\n return [key, item];\n }),\n );\n}\n\nfunction expandPluginPlaceholders(value: string, pluginRoot: string, pluginDataDirectory: string): string {\n // The portable contract is a single, non-recursive replacement pass. An\n // unrecognised placeholder remains literal and mcp-proxy must not reinterpret it.\n return value.replace(/\\$\\{PLUGIN_(ROOT|DATA)\\}/gu, (placeholder) =>\n placeholder === '${PLUGIN_ROOT}' ? pluginRoot : pluginDataDirectory,\n );\n}\n\nfunction isInside(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return relative === '' || (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative));\n}\n\nfunction realContainedPath(root: string, candidate: string, label: string): string {\n let realCandidate: string;\n try {\n realCandidate = fs.realpathSync(candidate);\n } catch {\n throw new Error(`${label} does not exist`);\n }\n if (!isInside(root, realCandidate)) throw new Error(`${label} escapes its allowed plugin directory`);\n return realCandidate;\n}\n\nfunction normalizeCommand(command: string, pluginRoot: string): string {\n if (command.startsWith('./')) {\n const resolved = realContainedPath(pluginRoot, path.resolve(pluginRoot, command), 'command');\n if (!fs.statSync(resolved).isFile()) throw new Error('command must resolve to a regular file');\n try {\n fs.accessSync(resolved, fs.constants.X_OK);\n } catch {\n throw new Error('command must resolve to an executable file');\n }\n return resolved;\n }\n if (command === '.' || command === '..' || /[\\s/\\\\]/u.test(command)) {\n throw new Error('command must be a bare executable name or a ./ path inside the plugin');\n }\n return command;\n}\n\nfunction normalizeWorkingDirectory(declared: unknown, pluginRoot: string, pluginDataDirectory: string): string {\n if (declared === undefined) return pluginRoot;\n const cwd = nonEmptyString(declared, 'cwd');\n let base: string;\n let expanded: string;\n if (cwd.startsWith('./')) {\n base = pluginRoot;\n expanded = path.resolve(pluginRoot, cwd);\n } else if (cwd === '${PLUGIN_ROOT}' || cwd.startsWith('${PLUGIN_ROOT}/')) {\n base = pluginRoot;\n expanded = expandPluginPlaceholders(cwd, pluginRoot, pluginDataDirectory);\n } else if (cwd === '${PLUGIN_DATA}' || cwd.startsWith('${PLUGIN_DATA}/')) {\n base = pluginDataDirectory;\n expanded = expandPluginPlaceholders(cwd, pluginRoot, pluginDataDirectory);\n } else {\n throw new Error('cwd must start with ./, ${PLUGIN_ROOT}, or ${PLUGIN_DATA}');\n }\n const resolved = realContainedPath(base, path.resolve(expanded), 'cwd');\n if (!fs.statSync(resolved).isDirectory()) throw new Error('cwd must resolve to a directory');\n return resolved;\n}\n\nfunction normalizeEnvironment(value: unknown, pluginRoot: string, pluginDataDirectory: string): Record<string, string> {\n const declared = optionalStringRecord(value, 'env') ?? {};\n for (const key of Object.keys(declared)) {\n const reservedKey = process.platform === 'win32' ? key.toUpperCase() : key;\n if (RESERVED_ENVIRONMENT_KEYS.has(reservedKey)) {\n throw new Error(`env key \"${key}\" is reserved by Agent Plugins`);\n }\n }\n return {\n ...Object.fromEntries(\n Object.entries(declared).map(([key, item]) => [\n key,\n expandPluginPlaceholders(item, pluginRoot, pluginDataDirectory),\n ]),\n ),\n PLUGIN_ROOT: pluginRoot,\n PLUGIN_DATA: pluginDataDirectory,\n };\n}\n\nfunction isLoopbackHost(hostname: string): boolean {\n const bareHostname = hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;\n if (bareHostname.toLowerCase() === 'localhost') return true;\n const family = isIP(bareHostname);\n if (family === 4) return bareHostname.split('.')[0] === '127';\n return family === 6 && bareHostname === '::1';\n}\n\nfunction normalizeUrl(value: unknown): string {\n const raw = nonEmptyString(value, 'url');\n let parsed: URL;\n try {\n parsed = new URL(raw);\n } catch {\n throw new Error('url must be an absolute HTTP(S) URL');\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new Error('url must use http or https');\n }\n if (parsed.username || parsed.password) throw new Error('url must not contain user information');\n if (parsed.hash) throw new Error('url must not contain a fragment');\n if (parsed.protocol === 'http:' && !isLoopbackHost(parsed.hostname)) {\n throw new Error('non-loopback MCP URLs must use https');\n }\n return raw;\n}\n\nfunction normalizeHeaders(value: unknown): Record<string, string> | undefined {\n const headers = optionalStringRecord(value, 'headers');\n if (!headers) return undefined;\n const seen = new Set<string>();\n for (const [name, item] of Object.entries(headers)) {\n const canonical = name.toLowerCase();\n if (seen.has(canonical)) throw new Error(`headers contain duplicate name \"${name}\"`);\n seen.add(canonical);\n try {\n validateHeaderName(name);\n validateHeaderValue(name, item);\n } catch {\n throw new Error(`header \"${name}\" is invalid`);\n }\n }\n return headers;\n}\n\nfunction normalizeServer(\n raw: unknown,\n pluginRoot: string,\n pluginDataDirectory: string,\n name: string,\n): NormalizedServer {\n if (!isObject(raw)) throw new Error('definition must be an object');\n const type = nonEmptyString(raw.type, 'type');\n if (type === 'stdio') {\n onlyKeys(raw, ['type', 'command', 'args', 'env', 'cwd'], `server \"${name}\"`);\n const command = normalizeCommand(nonEmptyString(raw.command, 'command'), pluginRoot);\n const args = optionalStringArray(raw.args, 'args')?.map((item) =>\n expandPluginPlaceholders(item, pluginRoot, pluginDataDirectory),\n );\n const env = normalizeEnvironment(raw.env, pluginRoot, pluginDataDirectory);\n const cwd = normalizeWorkingDirectory(raw.cwd, pluginRoot, pluginDataDirectory);\n const config = { command, ...(args ? { args } : {}), env, cwd };\n return {\n internal: { name, transport: 'stdio', config },\n claude: { type: 'stdio', ...config },\n };\n }\n\n if (type === 'streamable-http' || type === 'sse') {\n onlyKeys(raw, ['type', 'url', 'headers'], `server \"${name}\"`);\n const url = normalizeUrl(raw.url);\n const headers = normalizeHeaders(raw.headers);\n const transport = type === 'streamable-http' ? 'http' : 'sse';\n const config = { url, ...(headers ? { headers } : {}) };\n return {\n internal: { name, transport, config },\n claude: { type: transport, ...config },\n };\n }\n\n throw new Error(`unsupported transport type \"${type}\"`);\n}\n\nfunction stagedInternalPath(\n source: DoomMcpAgentPluginProjectionSource,\n contents: string,\n stagingDirectory: string,\n): string {\n const digest = createHash('sha256')\n .update(source.sourceId)\n .update('\\0')\n .update(source.contentDigest)\n .update('\\0')\n .update(contents)\n .digest('hex')\n .slice(0, 20);\n return path.join(stagingDirectory, `agent-plugin-mcp-${digest}.internal.json`);\n}\n\nfunction writeStagedInternalConfig(target: string, contents: string, stagingDirectory: string): void {\n fs.mkdirSync(stagingDirectory, { mode: PRIVATE_DIRECTORY_MODE, recursive: true });\n fs.chmodSync(stagingDirectory, PRIVATE_DIRECTORY_MODE);\n const temporaryPath = `${target}.${process.pid}-${randomUUID()}.tmp`;\n try {\n fs.writeFileSync(temporaryPath, contents, { flag: 'wx', mode: PRIVATE_FILE_MODE });\n try {\n fs.renameSync(temporaryPath, target);\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== 'EEXIST' && code !== 'EPERM') throw error;\n const stat = fs.lstatSync(target);\n if (stat.isSymbolicLink() || !stat.isFile() || fs.readFileSync(target, 'utf8') !== contents) {\n throw new Error('content-addressed staging path is occupied by different content');\n }\n }\n fs.chmodSync(target, PRIVATE_FILE_MODE);\n } finally {\n fs.rmSync(temporaryPath, { force: true });\n }\n}\n\nfunction emptyResult(diagnostic: string): NormalizedAgentPluginMcpSource {\n return {\n claudeConfig: { mcpServers: {} },\n serverNames: [],\n droppedServers: [],\n diagnostics: [diagnostic],\n };\n}\n\n/**\n * Validates one Agent Plugins v1 `mcp.json` and stages a native mcp-proxy layer.\n *\n * Server validation is isolated: one malformed server is diagnosed and skipped.\n * Document/schema, source identity, or plugin-boundary failures reject the whole\n * source. Only the two portable plugin placeholders are expanded; the staged\n * layer is tagged `internal`, so legacy `${ENV}` interpolation cannot run again.\n */\nexport function normalizeAgentPluginMcpSource(\n source: DoomMcpAgentPluginProjectionSource,\n options: NormalizeAgentPluginMcpOptions,\n): NormalizedAgentPluginMcpSource {\n const label = `Agent Plugin MCP source \"${source.sourceId}\"`;\n try {\n if (source.mcpSchemaUrl !== AGENT_PLUGIN_MCP_SCHEMA_URL) {\n throw new Error(`unsupported schema \"${String(source.mcpSchemaUrl)}\"`);\n }\n if (!path.isAbsolute(source.pluginRoot) || !path.isAbsolute(source.pluginDataDirectory)) {\n throw new Error('pluginRoot and pluginDataDirectory must be absolute');\n }\n const pluginRoot = fs.realpathSync(source.pluginRoot);\n try {\n const dataStat = fs.lstatSync(source.pluginDataDirectory);\n if (dataStat.isSymbolicLink() || !dataStat.isDirectory()) {\n throw new Error('pluginDataDirectory must be a real directory');\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n fs.mkdirSync(source.pluginDataDirectory, { mode: PRIVATE_DIRECTORY_MODE, recursive: true });\n }\n fs.chmodSync(source.pluginDataDirectory, PRIVATE_DIRECTORY_MODE);\n fs.accessSync(source.pluginDataDirectory, fs.constants.W_OK);\n const pluginDataDirectory = fs.realpathSync(source.pluginDataDirectory);\n const configPath = realContainedPath(pluginRoot, source.configPath, 'mcp.json');\n if (path.dirname(configPath) !== pluginRoot || path.basename(configPath) !== 'mcp.json') {\n throw new Error('portable plugin config must be root mcp.json');\n }\n\n const bytes = fs.readFileSync(configPath);\n const digest = createHash('sha256').update(bytes).digest('hex');\n if (digest !== source.contentDigest) throw new Error('content digest does not match the projection');\n const parsed: unknown = JSON.parse(bytes.toString('utf8'));\n if (!isObject(parsed)) throw new Error('document must be an object');\n onlyKeys(parsed, ['$schema', 'mcpServers'], label);\n if (parsed.$schema !== source.mcpSchemaUrl) throw new Error('$schema does not match the projected schema');\n if (!isObject(parsed.mcpServers)) throw new Error('mcpServers must be an object');\n\n const allowed = options.allowedServers;\n const keepAll = !allowed || allowed.length === 0;\n const stripProxyWrappers = options.stripProxyWrappers ?? true;\n const internalServers = Object.create(null) as Record<string, JsonObject>;\n const claudeServers = Object.create(null) as Record<string, JsonObject>;\n const droppedServers: string[] = [];\n const diagnostics: string[] = [];\n\n for (const [name, rawServer] of Object.entries(parsed.mcpServers)) {\n if (!name) {\n diagnostics.push(`${label} contains an empty server name; that entry was skipped.`);\n continue;\n }\n if ((!keepAll && !allowed.includes(name)) || (stripProxyWrappers && PROXY_SERVER_ALIASES.has(name))) {\n droppedServers.push(name);\n continue;\n }\n try {\n const normalized = normalizeServer(rawServer, pluginRoot, pluginDataDirectory, name);\n internalServers[name] = normalized.internal;\n claudeServers[name] = normalized.claude;\n } catch (error) {\n droppedServers.push(name);\n diagnostics.push(\n `${label} skipped server \"${name}\": ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n const internalConfig = { mcpServers: internalServers };\n const contents = `${JSON.stringify(internalConfig, null, 2)}\\n`;\n const target = stagedInternalPath(source, contents, options.stagingDirectory);\n writeStagedInternalConfig(target, contents, options.stagingDirectory);\n const cacheKey = createHash('sha256')\n .update('agent-plugin-v1\\0')\n .update(source.sourceId)\n .update('\\0')\n .update(source.contentDigest)\n .update('\\0')\n .update(configPath)\n .update('\\0')\n .update(contents)\n .digest('hex');\n\n return {\n configSource: { path: target, format: 'internal', cacheKey },\n claudeConfig: { mcpServers: claudeServers },\n serverNames: Object.keys(internalServers),\n droppedServers,\n diagnostics,\n };\n } catch (error) {\n return emptyResult(`${label} was disabled: ${error instanceof Error ? error.message : String(error)}`);\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
Object.defineProperties(exports, {
|
|
2
|
+
__esModule: { value: true },
|
|
3
|
+
[Symbol.toStringTag]: { value: "Module" }
|
|
4
|
+
});
|
|
5
|
+
let _agimon_ai_po_core_apiContracts = require("@agimon-ai/po-core/apiContracts");
|
|
6
|
+
let typebox = require("typebox");
|
|
7
|
+
//#region src/schemas/apiContracts.ts
|
|
8
|
+
const Text = typebox.Type.String();
|
|
9
|
+
const Optional = typebox.Type.Optional;
|
|
10
|
+
const Strings = typebox.Type.Array(Text);
|
|
11
|
+
const NullableText = typebox.Type.Union([Text, typebox.Type.Null()]);
|
|
12
|
+
const Scope = typebox.Type.Union([typebox.Type.Literal("global"), typebox.Type.Literal("repository")]);
|
|
13
|
+
const Origin = typebox.Type.Union([
|
|
14
|
+
typebox.Type.Literal("global"),
|
|
15
|
+
typebox.Type.Literal("repository"),
|
|
16
|
+
typebox.Type.Literal("default")
|
|
17
|
+
]);
|
|
18
|
+
const SettingsConfigSchema = typebox.Type.Object({
|
|
19
|
+
repoRoot: Text,
|
|
20
|
+
hashes: typebox.Type.Object({
|
|
21
|
+
global: Text,
|
|
22
|
+
repository: Text
|
|
23
|
+
}),
|
|
24
|
+
values: typebox.Type.Record(Text, typebox.Type.Object({
|
|
25
|
+
value: Optional(Text),
|
|
26
|
+
origin: Origin,
|
|
27
|
+
scope: typebox.Type.Union([Scope, typebox.Type.Literal("both")])
|
|
28
|
+
}))
|
|
29
|
+
});
|
|
30
|
+
const SettingsEditSchema = typebox.Type.Object({
|
|
31
|
+
keyPath: Strings,
|
|
32
|
+
value: typebox.Type.Union([
|
|
33
|
+
Text,
|
|
34
|
+
typebox.Type.Number(),
|
|
35
|
+
typebox.Type.Null()
|
|
36
|
+
])
|
|
37
|
+
});
|
|
38
|
+
const SettingsWriteSchema = typebox.Type.Union([typebox.Type.Object({
|
|
39
|
+
repoRoot: Text,
|
|
40
|
+
scope: Scope,
|
|
41
|
+
...SettingsEditSchema.properties,
|
|
42
|
+
expectedHash: Text
|
|
43
|
+
}), typebox.Type.Object({
|
|
44
|
+
repoRoot: Text,
|
|
45
|
+
scope: Scope,
|
|
46
|
+
edits: typebox.Type.Array(SettingsEditSchema, {
|
|
47
|
+
minItems: 1,
|
|
48
|
+
maxItems: 100
|
|
49
|
+
}),
|
|
50
|
+
expectedHash: Text
|
|
51
|
+
})]);
|
|
52
|
+
const Repository = typebox.Type.Object({
|
|
53
|
+
id: Text,
|
|
54
|
+
name: Text,
|
|
55
|
+
path: Text,
|
|
56
|
+
active: typebox.Type.Boolean()
|
|
57
|
+
});
|
|
58
|
+
const Catalog = typebox.Type.Array(typebox.Type.Object({
|
|
59
|
+
name: Text,
|
|
60
|
+
description: Optional(Text),
|
|
61
|
+
expandsTo: Optional(Strings),
|
|
62
|
+
layers: Optional(Strings)
|
|
63
|
+
}));
|
|
64
|
+
const SelectionText = typebox.Type.Object({
|
|
65
|
+
effective: Optional(Text),
|
|
66
|
+
repository: Optional(Text),
|
|
67
|
+
origin: Origin
|
|
68
|
+
});
|
|
69
|
+
const SelectionStrings = typebox.Type.Object({
|
|
70
|
+
effective: Optional(Strings),
|
|
71
|
+
repository: Optional(Strings),
|
|
72
|
+
origin: Origin
|
|
73
|
+
});
|
|
74
|
+
const RepositorySettingsSchema = typebox.Type.Object({
|
|
75
|
+
repository: Repository,
|
|
76
|
+
hash: Text,
|
|
77
|
+
catalogs: typebox.Type.Object({
|
|
78
|
+
majorModes: Catalog,
|
|
79
|
+
domains: Catalog,
|
|
80
|
+
profiles: Catalog
|
|
81
|
+
}),
|
|
82
|
+
selection: typebox.Type.Object({
|
|
83
|
+
majorMode: SelectionText,
|
|
84
|
+
domains: SelectionStrings,
|
|
85
|
+
profile: SelectionText
|
|
86
|
+
})
|
|
87
|
+
});
|
|
88
|
+
const RepositorySelectionWriteSchema = typebox.Type.Object({
|
|
89
|
+
repositoryId: Text,
|
|
90
|
+
expectedHash: Text,
|
|
91
|
+
changes: typebox.Type.Object({
|
|
92
|
+
majorMode: Optional(NullableText),
|
|
93
|
+
domains: Optional(typebox.Type.Union([Strings, typebox.Type.Null()])),
|
|
94
|
+
profile: Optional(NullableText)
|
|
95
|
+
})
|
|
96
|
+
});
|
|
97
|
+
const Images = typebox.Type.Object({
|
|
98
|
+
autoResize: typebox.Type.Boolean(),
|
|
99
|
+
maxDimension: typebox.Type.Number(),
|
|
100
|
+
minDimension: typebox.Type.Number(),
|
|
101
|
+
maxAllowedDimension: typebox.Type.Number()
|
|
102
|
+
});
|
|
103
|
+
const http = ["global", "workspace"].flatMap((scope) => {
|
|
104
|
+
const common = {
|
|
105
|
+
scope,
|
|
106
|
+
basePath: "settings",
|
|
107
|
+
authentication: "owner"
|
|
108
|
+
};
|
|
109
|
+
return [
|
|
110
|
+
{
|
|
111
|
+
...common,
|
|
112
|
+
id: "config",
|
|
113
|
+
path: "/",
|
|
114
|
+
method: "GET",
|
|
115
|
+
description: "Read selected settings keys and file hashes.",
|
|
116
|
+
parameters: [{
|
|
117
|
+
name: "key",
|
|
118
|
+
in: "query",
|
|
119
|
+
required: false,
|
|
120
|
+
schema: Strings
|
|
121
|
+
}],
|
|
122
|
+
responses: (0, _agimon_ai_po_core_apiContracts.jsonApiResponses)(SettingsConfigSchema)
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
...common,
|
|
126
|
+
id: "value",
|
|
127
|
+
path: "/value",
|
|
128
|
+
method: "PUT",
|
|
129
|
+
description: "Write a setting with an optimistic file hash.",
|
|
130
|
+
body: {
|
|
131
|
+
contentType: "application/json",
|
|
132
|
+
required: true,
|
|
133
|
+
schema: SettingsWriteSchema
|
|
134
|
+
},
|
|
135
|
+
responses: (0, _agimon_ai_po_core_apiContracts.jsonApiResponses)(SettingsConfigSchema)
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
...common,
|
|
139
|
+
id: "repositories",
|
|
140
|
+
path: "/repositories",
|
|
141
|
+
method: "GET",
|
|
142
|
+
description: "List admitted repositories.",
|
|
143
|
+
responses: (0, _agimon_ai_po_core_apiContracts.jsonApiResponses)(typebox.Type.Object({ repositories: typebox.Type.Array(Repository) }))
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
...common,
|
|
147
|
+
id: "repository",
|
|
148
|
+
path: "/repository",
|
|
149
|
+
method: "GET",
|
|
150
|
+
description: "Read the mounted workspace catalog and selection.",
|
|
151
|
+
availability: "Requires a workspace mount; global returns 404.",
|
|
152
|
+
responses: (0, _agimon_ai_po_core_apiContracts.jsonApiResponses)(RepositorySettingsSchema)
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
...common,
|
|
156
|
+
id: "selection",
|
|
157
|
+
path: "/repository/selection",
|
|
158
|
+
method: "PUT",
|
|
159
|
+
description: "Update the mounted workspace selection.",
|
|
160
|
+
availability: "Requires a workspace mount; global returns 404.",
|
|
161
|
+
body: {
|
|
162
|
+
contentType: "application/json",
|
|
163
|
+
required: true,
|
|
164
|
+
schema: RepositorySelectionWriteSchema
|
|
165
|
+
},
|
|
166
|
+
responses: (0, _agimon_ai_po_core_apiContracts.jsonApiResponses)(RepositorySettingsSchema)
|
|
167
|
+
},
|
|
168
|
+
...scope === "global" ? [{
|
|
169
|
+
...common,
|
|
170
|
+
id: "images.get",
|
|
171
|
+
path: "/images",
|
|
172
|
+
method: "GET",
|
|
173
|
+
description: "Read image resizing limits.",
|
|
174
|
+
responses: (0, _agimon_ai_po_core_apiContracts.jsonApiResponses)(Images)
|
|
175
|
+
}, {
|
|
176
|
+
...common,
|
|
177
|
+
id: "images.put",
|
|
178
|
+
path: "/images",
|
|
179
|
+
method: "PUT",
|
|
180
|
+
description: "Update image resizing settings; dimensions are clamped.",
|
|
181
|
+
body: {
|
|
182
|
+
contentType: "application/json",
|
|
183
|
+
required: true,
|
|
184
|
+
schema: typebox.Type.Object({
|
|
185
|
+
autoResize: Optional(typebox.Type.Boolean()),
|
|
186
|
+
maxDimension: Optional(typebox.Type.Number())
|
|
187
|
+
})
|
|
188
|
+
},
|
|
189
|
+
responses: (0, _agimon_ai_po_core_apiContracts.jsonApiResponses)(Images)
|
|
190
|
+
}] : []
|
|
191
|
+
];
|
|
192
|
+
});
|
|
193
|
+
const apiContracts = (0, _agimon_ai_po_core_apiContracts.defineApiContract)({
|
|
194
|
+
version: 1,
|
|
195
|
+
http,
|
|
196
|
+
sockets: [],
|
|
197
|
+
dynamic: []
|
|
198
|
+
});
|
|
199
|
+
//#endregion
|
|
200
|
+
exports.apiContracts = apiContracts;
|
|
201
|
+
exports.default = apiContracts;
|
|
202
|
+
|
|
203
|
+
//# sourceMappingURL=apiContracts.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiContracts.cjs","names":["Type","jsonApiResponses","defineApiContract"],"sources":["../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract, jsonApiResponses, type DoomHttpContract } from '@agimon-ai/po-core/apiContracts';\nimport { Type } from 'typebox';\n\nconst Text = Type.String();\nconst Optional = Type.Optional;\nconst Strings = Type.Array(Text);\nconst NullableText = Type.Union([Text, Type.Null()]);\nconst Scope = Type.Union([Type.Literal('global'), Type.Literal('repository')]);\nconst Origin = Type.Union([Type.Literal('global'), Type.Literal('repository'), Type.Literal('default')]);\nexport const SettingsConfigSchema = Type.Object({\n repoRoot: Text,\n hashes: Type.Object({ global: Text, repository: Text }),\n values: Type.Record(\n Text,\n Type.Object({\n value: Optional(Text),\n origin: Origin,\n scope: Type.Union([Scope, Type.Literal('both')]),\n }),\n ),\n});\nconst SettingsEditSchema = Type.Object({ keyPath: Strings, value: Type.Union([Text, Type.Number(), Type.Null()]) });\nexport const SettingsWriteSchema = Type.Union([\n Type.Object({ repoRoot: Text, scope: Scope, ...SettingsEditSchema.properties, expectedHash: Text }),\n Type.Object({\n repoRoot: Text,\n scope: Scope,\n edits: Type.Array(SettingsEditSchema, { minItems: 1, maxItems: 100 }),\n expectedHash: Text,\n }),\n]);\n\nconst Repository = Type.Object({ id: Text, name: Text, path: Text, active: Type.Boolean() });\nconst Catalog = Type.Array(\n Type.Object({ name: Text, description: Optional(Text), expandsTo: Optional(Strings), layers: Optional(Strings) }),\n);\nconst SelectionText = Type.Object({ effective: Optional(Text), repository: Optional(Text), origin: Origin });\nconst SelectionStrings = Type.Object({ effective: Optional(Strings), repository: Optional(Strings), origin: Origin });\nexport const RepositorySettingsSchema = Type.Object({\n repository: Repository,\n hash: Text,\n catalogs: Type.Object({ majorModes: Catalog, domains: Catalog, profiles: Catalog }),\n selection: Type.Object({ majorMode: SelectionText, domains: SelectionStrings, profile: SelectionText }),\n});\nexport const RepositorySelectionWriteSchema = Type.Object({\n repositoryId: Text,\n expectedHash: Text,\n changes: Type.Object({\n majorMode: Optional(NullableText),\n domains: Optional(Type.Union([Strings, Type.Null()])),\n profile: Optional(NullableText),\n }),\n});\nconst Images = Type.Object({\n autoResize: Type.Boolean(),\n maxDimension: Type.Number(),\n minDimension: Type.Number(),\n maxAllowedDimension: Type.Number(),\n});\nconst http: DoomHttpContract[] = (['global', 'workspace'] as const).flatMap((scope) => {\n const common = { scope, basePath: 'settings', authentication: 'owner' as const };\n return [\n {\n ...common,\n id: 'config',\n path: '/',\n method: 'GET',\n description: 'Read selected settings keys and file hashes.',\n parameters: [{ name: 'key', in: 'query', required: false, schema: Strings }],\n responses: jsonApiResponses(SettingsConfigSchema),\n },\n {\n ...common,\n id: 'value',\n path: '/value',\n method: 'PUT',\n description: 'Write a setting with an optimistic file hash.',\n body: { contentType: 'application/json', required: true, schema: SettingsWriteSchema },\n responses: jsonApiResponses(SettingsConfigSchema),\n },\n {\n ...common,\n id: 'repositories',\n path: '/repositories',\n method: 'GET',\n description: 'List admitted repositories.',\n responses: jsonApiResponses(Type.Object({ repositories: Type.Array(Repository) })),\n },\n {\n ...common,\n id: 'repository',\n path: '/repository',\n method: 'GET',\n description: 'Read the mounted workspace catalog and selection.',\n availability: 'Requires a workspace mount; global returns 404.',\n responses: jsonApiResponses(RepositorySettingsSchema),\n },\n {\n ...common,\n id: 'selection',\n path: '/repository/selection',\n method: 'PUT',\n description: 'Update the mounted workspace selection.',\n availability: 'Requires a workspace mount; global returns 404.',\n body: { contentType: 'application/json', required: true, schema: RepositorySelectionWriteSchema },\n responses: jsonApiResponses(RepositorySettingsSchema),\n },\n ...(scope === 'global'\n ? [\n {\n ...common,\n id: 'images.get',\n path: '/images',\n method: 'GET' as const,\n description: 'Read image resizing limits.',\n responses: jsonApiResponses(Images),\n },\n {\n ...common,\n id: 'images.put',\n path: '/images',\n method: 'PUT' as const,\n description: 'Update image resizing settings; dimensions are clamped.',\n body: {\n contentType: 'application/json',\n required: true,\n schema: Type.Object({ autoResize: Optional(Type.Boolean()), maxDimension: Optional(Type.Number()) }),\n },\n responses: jsonApiResponses(Images),\n },\n ]\n : []),\n ] satisfies DoomHttpContract[];\n});\nexport const apiContracts = defineApiContract({ version: 1, http, sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
//#region src/schemas/apiContracts.d.ts
|
|
3
|
+
export declare const apiContracts: {
|
|
4
|
+
version: 1;
|
|
5
|
+
protocols?: Record<string, string> | undefined;
|
|
6
|
+
schemas?: Record<string, boolean | object> | undefined;
|
|
7
|
+
http: {
|
|
8
|
+
id: string;
|
|
9
|
+
scope: "global" | "session" | "workspace";
|
|
10
|
+
basePath?: string | undefined;
|
|
11
|
+
path: string;
|
|
12
|
+
method: "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT";
|
|
13
|
+
description: string;
|
|
14
|
+
availability?: string | undefined;
|
|
15
|
+
authentication: "device" | "none" | "owner";
|
|
16
|
+
parameters?: {
|
|
17
|
+
name: string;
|
|
18
|
+
in: "header" | "path" | "query";
|
|
19
|
+
required: boolean;
|
|
20
|
+
schema: boolean | object;
|
|
21
|
+
}[] | undefined;
|
|
22
|
+
body?: {
|
|
23
|
+
contentType: string;
|
|
24
|
+
contentTypes?: string[] | undefined;
|
|
25
|
+
required: boolean;
|
|
26
|
+
schema: boolean | object;
|
|
27
|
+
} | undefined;
|
|
28
|
+
responses: Record<string, {
|
|
29
|
+
description: string;
|
|
30
|
+
contentType?: string | undefined;
|
|
31
|
+
schema?: boolean | object | undefined;
|
|
32
|
+
events?: Record<string, boolean | object> | undefined;
|
|
33
|
+
}>;
|
|
34
|
+
}[];
|
|
35
|
+
sockets: {
|
|
36
|
+
id: string;
|
|
37
|
+
scope: "global" | "session" | "workspace";
|
|
38
|
+
description: string;
|
|
39
|
+
availability?: string | undefined;
|
|
40
|
+
service: string;
|
|
41
|
+
member: string;
|
|
42
|
+
direction: "client-to-server" | "server-to-client";
|
|
43
|
+
kind: "channel" | "method" | "state";
|
|
44
|
+
input: boolean | object;
|
|
45
|
+
output?: boolean | object | undefined;
|
|
46
|
+
errors?: boolean | object | undefined;
|
|
47
|
+
}[];
|
|
48
|
+
dynamic: string[];
|
|
49
|
+
gaps?: string[] | undefined;
|
|
50
|
+
};
|
|
51
|
+
//#endregion
|
|
52
|
+
export { apiContracts as default };
|
|
53
|
+
//# sourceMappingURL=apiContracts.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiContracts.d.mts","names":[],"sources":["../src/schemas/apiContracts.ts"],"mappings":";;qBAsIa"}
|