Darkwing's round 2 candidate, approved by Filbert (#1518 comment 26730). build-r2.patch a27890d5, manifest 869168c7, 34 files, applied on HEAD and checked 34/34. Integration gate on an export of HEAD plus the patch: business 60/60 on Node 24 and 26, every package test and every scripts/test-*.sh green, test-task 98/98 with the live-provider cases. Conductor, queue, conversation and discord confirmed in git worktrees of HEAD with and without the patch, identical results. Lead decision 63 accepts the vocabulary location, the example path and the business branch. Co-Authored-By: Claude Opus 5.5 <[email protected]>
99 lines
3.6 KiB
JavaScript
99 lines
3.6 KiB
JavaScript
// Shared fixtures. Every test works in its own temporary directory and
|
|
// points MOSAIC_CONFIG there; nothing reads the real ~/.config.
|
|
|
|
import { chmodSync, cpSync, mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { dirname, join, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
export const REPO = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
|
|
export const REPO_ROLES = join(REPO, "roles");
|
|
export const FAR_DATE = "2099-01-01";
|
|
|
|
export function tmp() {
|
|
return mkdtempSync(join(tmpdir(), "mosaic-business-"));
|
|
}
|
|
|
|
export function writeJson(file, value, mode = 0o600) {
|
|
mkdirSync(dirname(file), { recursive: true });
|
|
writeFileSync(file, typeof value === "string" ? value : `${JSON.stringify(value, null, 2)}\n`);
|
|
chmodSync(file, mode);
|
|
return file;
|
|
}
|
|
|
|
// A token file with a placeholder value; the package never reads it.
|
|
export function tokenFile(dir, name) {
|
|
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
const file = join(dir, name);
|
|
writeFileSync(file, "placeholder-not-a-token");
|
|
chmodSync(file, 0o600);
|
|
return file;
|
|
}
|
|
|
|
// A copy of the shipped role files in a scratch roles directory.
|
|
export function rolesCopy(root) {
|
|
const dir = join(root, "roles");
|
|
cpSync(REPO_ROLES, dir, { recursive: true });
|
|
return dir;
|
|
}
|
|
|
|
// A complete valid business document for the shipped four roles, with
|
|
// token files under `<root>/secrets`, and a project root under `<root>`.
|
|
export function businessDoc(root, id = "acme") {
|
|
const secrets = join(root, "secrets");
|
|
const ref = (role, service) => service === "gitea"
|
|
? { file: tokenFile(secrets, `${role}-gitea.token`), rotateBy: FAR_DATE }
|
|
: { file: tokenFile(secrets, `${role}-vikunja.token`), expires: FAR_DATE };
|
|
const role = (definition, botId, extra = {}) => ({
|
|
definition,
|
|
tracker: { bot: `bot-${id}-${definition}`, botId },
|
|
credentials: { gitea: ref(definition, "gitea"), vikunja: ref(definition, "vikunja") },
|
|
...extra,
|
|
});
|
|
const projectRoot = join(root, "project");
|
|
mkdirSync(projectRoot, { recursive: true });
|
|
return {
|
|
businessVersion: 1,
|
|
id,
|
|
human: "jason",
|
|
arbiters: { delivery: "pm", technical: "cto" },
|
|
projects: { stack: { root: projectRoot } },
|
|
vars: { "tracker.baseUrl": "http://127.0.0.1:3456", "gitea.baseUrl": "https://git.example", "tracker.pollSeconds": 60 },
|
|
tracker: {
|
|
sync: { bot: `bot-${id}-sync`, botId: 9, credentials: { vikunja: ref("sync", "vikunja") } },
|
|
labels: {},
|
|
},
|
|
roles: {
|
|
pm: role("pm", 3, { holder: "sage", vars: { harness: "pi", model: "claude-opus-5-5" } }),
|
|
cto: role("cto", 4, { holder: "darkwing", vars: { harness: "claude-code" } }),
|
|
coder: role("coder", 5, { vars: { harness: "pi", "limits.network": "none" } }),
|
|
reviewer: role("reviewer", 6),
|
|
},
|
|
launch: { by: "pm", instances: ["coder", "reviewer"], max: { opus: 2, sonnet: 4 } },
|
|
};
|
|
}
|
|
|
|
// The system config file mosaic-config.mjs validates, under `root`.
|
|
export function systemConfig(root) {
|
|
const file = join(root, "config", "config.json");
|
|
writeJson(file, {
|
|
configVersion: 1,
|
|
environment: "development",
|
|
dataRoot: join(root, "data"),
|
|
execution: { backend: "docker", provider: "zai", model: "glm-5.3-flash", adapter: "mock" },
|
|
});
|
|
return file;
|
|
}
|
|
|
|
// The checked system layer, as systemVars() returns it, without spawning.
|
|
export function systemFor(root) {
|
|
return {
|
|
environment: "development",
|
|
dataRoot: join(root, "data"),
|
|
"execution.backend": "docker",
|
|
"execution.provider": "zai",
|
|
"execution.model": "glm-5.3-flash",
|
|
"execution.adapter": "mock",
|
|
};
|
|
}
|