Luigit
repositories / pi-ext

pi-ext

bugabingas pi extensions

owned by admin

extensions/the-system/__tests__/init.test.ts

Raw
import 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",
		);
	});
});