feat(foundry): add managed data consumers and agent settings
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { execFile } from "node:child_process";
|
||||
import { createServer } from "node:http";
|
||||
import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
import test from "node:test";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
const installer = new URL("../server/assets/foundry-agent-npm/bin/nodedc-foundry-codex-agent.mjs", import.meta.url);
|
||||
|
||||
async function listen(server) {
|
||||
await new Promise((resolve, reject) => {
|
||||
server.once("error", reject);
|
||||
server.listen(0, "127.0.0.1", resolve);
|
||||
});
|
||||
return `http://127.0.0.1:${server.address().port}`;
|
||||
}
|
||||
|
||||
test("Foundry installer preserves unrelated MCP entries and installs two independent servers", async () => {
|
||||
let baseUrl = "";
|
||||
const server = createServer(async (request, response) => {
|
||||
if (request.url === "/api/foundry-agent/v1/setup/redeem") {
|
||||
response.writeHead(200, { "content-type": "application/json" });
|
||||
response.end(JSON.stringify({
|
||||
ok: true,
|
||||
foundry: { serverName: "nodedc_module_foundry", mcpUrl: `${baseUrl}/foundry-mcp`, token: "foundry-device-token" },
|
||||
ontology: { serverName: "nodedc_ontology", mcpUrl: `${baseUrl}/ontology-mcp`, token: "ontology-device-token", readOnly: true },
|
||||
}));
|
||||
return;
|
||||
}
|
||||
if (request.url === "/foundry-mcp" || request.url === "/ontology-mcp") {
|
||||
const chunks = [];
|
||||
for await (const chunk of request) chunks.push(chunk);
|
||||
const message = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
||||
const tools = request.url === "/foundry-mcp"
|
||||
? [{ name: "foundry_status" }, { name: "foundry_create_application" }]
|
||||
: [{ name: "ontology_status" }, { name: "ontology_search" }];
|
||||
response.writeHead(200, { "content-type": "application/json" });
|
||||
response.end(JSON.stringify({
|
||||
jsonrpc: "2.0",
|
||||
id: message.id,
|
||||
result: message.method === "tools/list"
|
||||
? { tools }
|
||||
: { protocolVersion: "2025-06-18", capabilities: { tools: {} }, serverInfo: { name: "test", version: "1" } },
|
||||
}));
|
||||
return;
|
||||
}
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
});
|
||||
baseUrl = await listen(server);
|
||||
const codexHome = await mkdtemp(path.join(os.tmpdir(), "nodedc-foundry-installer-"));
|
||||
await mkdir(codexHome, { recursive: true });
|
||||
const original = [
|
||||
"model = \"gpt-5\"",
|
||||
"",
|
||||
"[mcp_servers.nodedc_engine_agent]",
|
||||
"url = \"https://engine.example/mcp\"",
|
||||
"",
|
||||
"[mcp_servers.nodedc_module_foundry]",
|
||||
"url = \"https://stale.example/foundry\"",
|
||||
"",
|
||||
"[mcp_servers.nodedc_ontology]",
|
||||
"url = \"https://stale.example/ontology\"",
|
||||
"",
|
||||
].join("\n");
|
||||
await writeFile(path.join(codexHome, "config.toml"), original, "utf8");
|
||||
try {
|
||||
const result = await execFileAsync(process.execPath, [installer.pathname, "--server", baseUrl, "--code", "test-code", "--codex-home", codexHome]);
|
||||
assert.match(result.stdout, /Foundry MCP smoke tools: 2/);
|
||||
assert.match(result.stdout, /Ontology MCP smoke tools: 2/);
|
||||
|
||||
const config = await readFile(path.join(codexHome, "config.toml"), "utf8");
|
||||
assert.match(config, /\[mcp_servers\.nodedc_engine_agent\]/);
|
||||
assert.equal((config.match(/\[mcp_servers\.nodedc_module_foundry\]/g) || []).length, 1);
|
||||
assert.equal((config.match(/\[mcp_servers\.nodedc_ontology\]/g) || []).length, 1);
|
||||
assert.match(config, new RegExp(`${baseUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\/foundry-mcp`));
|
||||
assert.match(config, /Bearer foundry-device-token/);
|
||||
assert.match(config, /Bearer ontology-device-token/);
|
||||
assert.equal(config.includes("stale.example"), false);
|
||||
|
||||
const backup = await readFile(path.join(codexHome, "config.toml.nodedc-foundry-agent.bak"), "utf8");
|
||||
assert.equal(backup, original);
|
||||
const skill = await readFile(path.join(codexHome, "skills", "foundry-context", "SKILL.md"), "utf8");
|
||||
assert.match(skill, /nodedc_module_foundry/);
|
||||
assert.match(skill, /nodedc_ontology/);
|
||||
|
||||
const doctor = await execFileAsync(process.execPath, [installer.pathname, "doctor", "--codex-home", codexHome]);
|
||||
assert.match(doctor.stdout, /install is present/);
|
||||
} finally {
|
||||
await new Promise((resolve) => server.close(resolve));
|
||||
await rm(codexHome, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user