Every bundle is now a child speaking MCP over stdio, so stdout is the channel: the module logs on stderr. The managed CLAUDE.md teaches mesh_search, mesh_describe, mesh_call, mesh_overview and mesh_machine with addresses (<seat>.<verb>, <node>/<module>.<tool>) instead of flat tool names. A hand-over is applied whatever the trailing render says; a failed render is reported beside it. Proven over stdio as the runtime drives it: five tools listed, a key made on first use, a sealed switch writing an access-token-only 0600 credentials file that keeps unknown keys.
41 lines
2.1 KiB
TypeScript
41 lines
2.1 KiB
TypeScript
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { render } from "../dist/render.js";
|
|
|
|
const facts = { node: "workstation", console: "http://127.0.0.1:4270/mcp" };
|
|
|
|
test("the console is the `mesh` server, and an operator's servers are listed beside it", () => {
|
|
const out = render(facts, { mcp_servers: { search: { type: "http", url: "https://s.example/mcp" } } }, null, "/h");
|
|
const mcp = JSON.parse(out["managed-mcp.json"]);
|
|
assert.deepEqual(Object.keys(mcp.mcpServers), ["mesh", "search"]);
|
|
assert.deepEqual(mcp.mcpServers.mesh, { type: "http", url: facts.console });
|
|
});
|
|
|
|
test("a setting cannot replace the mesh's own entry, and a name the vendor refuses is left out", () => {
|
|
const out = render(facts, { mcp_servers: { mesh: { type: "http", url: "http://evil" }, "bad name": {} } }, null, "/h");
|
|
const mcp = JSON.parse(out["managed-mcp.json"]);
|
|
assert.equal(mcp.mcpServers.mesh.url, facts.console);
|
|
assert.ok(!("bad name" in mcp.mcpServers));
|
|
});
|
|
|
|
test("managed settings carry the mesh's keys only, and the key-helper only for an API-key licence", () => {
|
|
const sub = JSON.parse(render(facts, {}, { licence: "personal", kind: "subscription" }, "/h")["managed-settings.json"]);
|
|
assert.deepEqual(sub, { attribution: { commit: "", pr: "" }, allowAllClaudeAiMcps: true });
|
|
const key = JSON.parse(render(facts, {}, { licence: "api", kind: "api-key" }, "/state/api-key-helper")["managed-settings.json"]);
|
|
assert.equal(key.apiKeyHelper, "/state/api-key-helper");
|
|
assert.ok(!("model" in key), "a preference is the person's");
|
|
});
|
|
|
|
test("the instruction file names the node and its role, and no other node", () => {
|
|
const md = render(facts, { role: "the laptop" }, null, "/h")["CLAUDE.md"];
|
|
assert.match(md, /\*\*Node:\*\* `workstation`/);
|
|
assert.match(md, /\*\*Role:\*\* the laptop/);
|
|
assert.match(md, /mesh_call/);
|
|
assert.match(md, /records_search/);
|
|
});
|
|
|
|
test("rendering is deterministic, so an unchanged input writes nothing", () => {
|
|
const s = { mcp_servers: { b: { type: "http", url: "https://b" }, a: { type: "http", url: "https://a" } } };
|
|
assert.deepEqual(render(facts, s, null, "/h"), render(facts, s, null, "/h"));
|
|
});
|