repositories / pi-ext
pi-ext
bugabingas pi extensions
owned by admin
extensions/the-system/__tests__/init.test.ts
Rawimport assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import {
lstatSync,
mkdirSync,
mkdtempSync,
readFileSync,
rmSync,
symlinkSync,
writeFileSync,
} from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { afterEach, describe, it } from "vitest";
import { runDoctor } from "../doctor.ts";
import { SystemDocumentError } from "../documents.ts";
import { applyInitialization, inspectInitialization } from "../init.ts";
const roots: string[] = [];
const root = () => {
const value = mkdtempSync(path.join(tmpdir(), "the-system-init-"));
roots.push(value);
return value;
};
const write = (project: string, relative: string, content: string) => {
const target = path.join(project, relative);
mkdirSync(path.dirname(target), { recursive: true });
writeFileSync(target, content, "utf8");
};
const cores = (project: string) => {
for (const name of ["SYSTEM.md", "MISSION.md", "RULES.md"])
write(project, `.system/${name}`, `# ${name}\n\nApproved.\n`);
};
afterEach(() => {
for (const value of roots.splice(0))
rmSync(value, { recursive: true, force: true });
});
describe("guided initialization machine state", () => {
it("creates schema-0 config and core files, then preserves cores on rerun", () => {
const project = root();
const cwd = path.join(project, "packages", "app");
mkdirSync(cwd, { recursive: true });
const script = path.resolve(import.meta.dirname, "../scripts/init.mjs");
const child = spawnSync(
process.execPath,
["--experimental-strip-types", script, "apply", cwd, "PX"],
{ encoding: "utf8", env: { ...process.env, NODE_NO_WARNINGS: "1" } },
);
assert.equal(child.status, 0);
assert.match(child.stdout, /WROTE \.system\/config\.json/);
assert.match(child.stdout, /WROTE \.system\/board\.json/);
assert.match(child.stdout, /WROTE \.system\/SYSTEM\.md/);
assert.deepEqual(
JSON.parse(readFileSync(path.join(cwd, ".system/config.json"), "utf8")),
{ prefix: "PX", schemaVersion: 0, title: path.basename(cwd) },
);
assert.deepEqual(
JSON.parse(readFileSync(path.join(cwd, ".system/board.json"), "utf8")),
{ schemaVersion: 0, items: {} },
);
assert.match(
readFileSync(path.join(cwd, ".system/SYSTEM.md"), "utf8"),
/Stable project identity/,
);
assert.match(
readFileSync(path.join(cwd, ".system/MISSION.md"), "utf8"),
/Enduring high-level project objective/,
);
assert.match(
readFileSync(path.join(cwd, ".system/RULES.md"), "utf8"),
/Concrete operating constraints/,
);
for (const directory of ["specs", "phases", "plans", "issues", "research"])
assert.equal(
lstatSync(path.join(cwd, ".system", directory), {
throwIfNoEntry: false,
}),
undefined,
);
const before = ["SYSTEM.md", "MISSION.md", "RULES.md"].map((name) => {
const target = path.join(cwd, ".system", name);
return [name, readFileSync(target, "utf8"), lstatSync(target).mtimeMs];
});
assert.deepEqual(applyInitialization(cwd, "PX"), {
root: cwd,
prefix: "PX",
changed: [],
pending: [],
});
for (const [name, source, mtime] of before) {
const target = path.join(cwd, ".system", name);
assert.deepEqual(
[readFileSync(target, "utf8"), lstatSync(target).mtimeMs],
[source, mtime],
);
}
assert.equal(runDoctor(cwd).exitCode, 0);
});
it("holds a mismatched config pending, then rewrites it when approved", () => {
const project = root();
const mismatched =
'{"prefix":"PX","schemaVersion":4,"title":"Project","obsolete":true}\n';
write(project, ".system/config.json", mismatched);
cores(project);
const rewrites = [".system/config.json schemaVersion 4 -> 0"];
assert.deepEqual(inspectInitialization(project).rewrites, rewrites);
assert.deepEqual(applyInitialization(project).pending, rewrites);
assert.equal(
readFileSync(path.join(project, ".system/config.json"), "utf8"),
mismatched,
);
const result = applyInitialization(project, undefined, true);
assert.deepEqual(result.changed, [".system/config.json"]);
assert.deepEqual(
JSON.parse(
readFileSync(path.join(project, ".system/config.json"), "utf8"),
),
{ prefix: "PX", schemaVersion: 0, title: "Project" },
);
});
it("rewrites a mismatched board directly to schema 0", () => {
const project = root();
applyInitialization(project, "PX");
write(
project,
".system/board.json",
JSON.stringify({
schemaVersion: 7,
items: {
"PX-SPEC-SPEC0001": {
state: "done",
updatedAt: "2026-03-20T12:00:00.000Z",
source: "manual",
},
},
}),
);
assert.deepEqual(inspectInitialization(project).rewrites, [
".system/board.json schemaVersion 7 -> 0",
]);
const configBefore = readFileSync(
path.join(project, ".system/config.json"),
"utf8",
);
const result = applyInitialization(project, undefined, true);
assert.deepEqual(result.changed, [".system/board.json"]);
assert.equal(
readFileSync(path.join(project, ".system/config.json"), "utf8"),
configBefore,
);
assert.equal(
JSON.parse(readFileSync(path.join(project, ".system/board.json"), "utf8"))
.schemaVersion,
0,
);
});
it("preserves selected phase and title while resetting the schema", () => {
const project = root();
applyInitialization(project, "PX");
write(
project,
".system/config.json",
JSON.stringify({
prefix: "PX",
schemaVersion: 4,
title: "Custom title",
currentPhase: "PX-PHASE-PHASE001",
}),
);
applyInitialization(project, undefined, true);
assert.deepEqual(
JSON.parse(
readFileSync(path.join(project, ".system/config.json"), "utf8"),
),
{
prefix: "PX",
schemaVersion: 0,
title: "Custom title",
currentPhase: "PX-PHASE-PHASE001",
},
);
});
it("rejects invalid prefixes, prefix conflicts, and unsafe config paths", () => {
const project = root();
assert.throws(() => applyInitialization(project), /prefix is required/i);
assert.throws(() => applyInitialization(project, "x"), SystemDocumentError);
applyInitialization(project, "PX");
assert.throws(
() => inspectInitialization(project, "AB"),
/prefix.*does not match/i,
);
const linked = root();
mkdirSync(path.join(linked, ".system"));
symlinkSync("elsewhere.json", path.join(linked, ".system/config.json"));
assert.throws(
() => inspectInitialization(linked),
(error: unknown) =>
error instanceof SystemDocumentError &&
error.code === "init.unsafe-path",
);
});
});