import assert from "node:assert/strict"; import { spawnSync } from "node:child_process"; import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync, 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"; const roots: string[] = []; const temporaryRoot = () => { const root = mkdtempSync(path.join(tmpdir(), "the-system-doctor-")); roots.push(root); return root; }; const write = (root: string, relative: string, content = "") => { const target = path.join(root, relative); mkdirSync(path.dirname(target), { recursive: true }); writeFileSync(target, content, "utf8"); }; const markdown = (id: string, type = "spec", extra = "") => `---\nid: ${id}\ntype: ${type}\ntitle: Contract${extra}\n---\n\n# Contract\n`; const validSystem = (root: string) => { for (const file of ["SYSTEM.md", "MISSION.md", "RULES.md"]) write(root, `.system/${file}`, `# ${file}\n`); write(root, ".system/config.json", '{"prefix":"PX","schemaVersion":0}'); write(root, ".system/board.json", '{"schemaVersion":0,"items":{}}'); }; const snapshot = (root: string) => { const entries: { path: string; content?: string; mode: number; mtimeMs: number; }[] = []; const visit = (directory: string) => { for (const entry of readdirSync(directory, { withFileTypes: true }).sort( (a, b) => a.name.localeCompare(b.name), )) { const target = path.join(directory, entry.name); const stats = statSync(target); const record = { path: path.relative(root, target).split(path.sep).join("/"), mode: stats.mode, mtimeMs: stats.mtimeMs, }; entries.push( entry.isFile() ? { ...record, content: readFileSync(target, "utf8") } : record, ); if (entry.isDirectory()) visit(target); } }; visit(root); return entries; }; afterEach(() => { for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); }); describe("system doctor", () => { it("requires the system root, config, and cores but not empty collections", () => { const root = temporaryRoot(); mkdirSync(path.join(root, ".system")); const result = runDoctor(root); assert.deepEqual( result.diagnostics.map(({ code, path }) => `${path} ${code}`), [ ".system/MISSION.md filesystem.missing", ".system/RULES.md filesystem.missing", ".system/SYSTEM.md filesystem.missing", ".system/board.json filesystem.missing", ".system/config.json filesystem.missing", ], ); }); it("rejects collection paths that are not regular directories", () => { const root = temporaryRoot(); const outside = temporaryRoot(); validSystem(root); write(root, ".system/issues", "not a directory"); assert.deepEqual( runDoctor(root).diagnostics.map(({ code, path }) => `${path} ${code}`), [".system/issues bundle.expected-directory"], ); rmSync(path.join(root, ".system/issues")); symlinkSync(outside, path.join(root, ".system/issues"), "dir"); assert.deepEqual( runDoctor(root).diagnostics.map(({ code, path }) => `${path} ${code}`), [".system/issues bundle.symbolic-link"], ); }); it("combines shared bundle, graph, and test diagnostics", () => { const root = temporaryRoot(); validSystem(root); write( root, ".system/specs/PX-SPEC-SPEC0001-contract/index.md", markdown("PX-SPEC-SPEC0001"), ); write( root, ".system/plans/PX-PLAN-PLAN0001-work/index.md", markdown( "PX-PLAN-PLAN0001", "plan", "\nspec: PX-SPEC-MISSING1\nstatus: draft", ), ); write(root, ".system/specs/PX-SPEC-SPEC0002-empty/readme.txt", "asset"); write(root, "tests/contract.test.ts", "// SYSTEM-SPEC: PX-SPEC-MISSING1\n"); const result = runDoctor(root); assert.deepEqual( result.diagnostics.map(({ code, path }) => `${path} ${code}`), [ ".system/plans/PX-PLAN-PLAN0001-work/index.md graph.dangling-reference", ".system/specs/PX-SPEC-SPEC0002-empty bundle.missing-index", "tests/contract.test.ts test.dangling-reference", ], ); }); it("reports invalid and dangling board state", () => { const root = temporaryRoot(); validSystem(root); write( root, ".system/board.json", '{"schemaVersion":0,"items":{"PX-SPEC-MISSING1":{"state":"done","updatedAt":"2026-03-20T12:00:00.000Z","source":"manual"}}}', ); assert.deepEqual( runDoctor(root).diagnostics.map(({ code }) => code), ["board.dangling-item"], ); write(root, ".system/board.json", '{"schemaVersion":4,"items":{}}'); assert.deepEqual( runDoctor(root).diagnostics.map(({ code }) => code), ["board.version"], ); }); it("does not follow bundle symlinks and is green for a complete bundled system", () => { const root = temporaryRoot(); const outside = temporaryRoot(); validSystem(root); write( root, ".system/specs/PX-SPEC-SPEC0001-contract/index.md", markdown("PX-SPEC-SPEC0001"), ); assert.deepEqual(runDoctor(root).diagnostics, []); write( root, ".system/config.json", '{"prefix":"PX","schemaVersion":0,"currentPhase":"PX-PHASE-PHASE001"}', ); assert.deepEqual( runDoctor(root).diagnostics.map(({ code, path }) => `${path} ${code}`), [".system/config.json config.current-phase"], ); write( root, ".system/phases/PX-PHASE-PHASE001-pre-v1/index.md", markdown("PX-PHASE-PHASE001", "phase", "\nlabel: pre-v1"), ); assert.deepEqual(runDoctor(root).diagnostics, []); symlinkSync( outside, path.join(root, ".system/specs/PX-SPEC-SPEC0002-link"), "dir", ); assert.deepEqual( runDoctor(root).diagnostics.map(({ code }) => code), ["bundle.symbolic-link"], ); }); it("renders stable CLI output without mutation", () => { const root = temporaryRoot(); validSystem(root); write( root, ".system/specs/PX-SPEC-SPEC0001-contract/index.md", markdown("PX-SPEC-SPEC0001"), ); write(root, "tests/contract.test.ts", "// SYSTEM-SPEC: PX-SPEC-SPEC0001\n"); const before = snapshot(root); const script = path.resolve(import.meta.dirname, "../scripts/doctor.mjs"); const child = spawnSync( process.execPath, ["--experimental-strip-types", script, root], { encoding: "utf8", env: { ...process.env, NODE_NO_WARNINGS: "1" }, }, ); assert.equal(child.status, 0); assert.equal( child.stdout, `ROOT ${root}\nREF tests/contract.test.ts PX-SPEC-SPEC0001\nOK The System is valid\n`, ); assert.equal(child.stderr, ""); assert.deepEqual(snapshot(root), before); }); });