import { mkdir, readFile, writeFile } from "node:fs/promises"; import { existsSync } from "node:fs"; import { dirname, join, resolve } from "node:path"; import { ContractRegistry, checkContractCompatibility, type ContractSnapshot, } from "@wrnexus/validation"; const CURRENT_FILE = "wrnexus.contracts.json"; const BASELINE_FILE = join(".wrnexus", "contracts.json"); function validateSnapshot(value: unknown, source: string): ContractSnapshot { const snapshot = value as Partial; if (snapshot?.format !== 1 || !Array.isArray(snapshot.contracts)) { throw new Error(`WRN-CONTRACT-FORMAT: ${source} is not a version 1 contract snapshot.`); } return snapshot as ContractSnapshot; } async function currentSnapshot(appRoot: string): Promise { const modulePath = join(appRoot, "app", "contracts.ts"); if (existsSync(modulePath)) { const imported = (await import(`${modulePath}?t=${Date.now()}`)) as { default?: ContractRegistry | ContractSnapshot; contracts?: ContractRegistry | ContractSnapshot; }; const value = imported.contracts ?? imported.default; if (value instanceof ContractRegistry) return value.snapshot(); return validateSnapshot(value, modulePath); } const jsonPath = join(appRoot, CURRENT_FILE); if (!existsSync(jsonPath)) { throw new Error( `WRN-CONTRACT-SOURCE: create app/contracts.ts exporting a ContractRegistry, or ${CURRENT_FILE}.`, ); } return validateSnapshot(JSON.parse(await readFile(jsonPath, "utf8")), jsonPath); } export interface ContractCommandResult { ok: boolean; issueCount: number; baseline: string; } export async function runContractsCommand( root: string, command = "check", args: string[] = [], ): Promise { const appRoot = resolve(root); const baseline = join(appRoot, BASELINE_FILE); const current = await currentSnapshot(appRoot); if (command === "snapshot") { await mkdir(dirname(baseline), { recursive: true }); await writeFile(baseline, `${JSON.stringify(current, null, 2)}\n`, "utf8"); if (args.includes("--json")) console.log(JSON.stringify({ ok: true, baseline })); else console.log(`✓ Contract baseline written: ${baseline}`); return { ok: true, issueCount: 0, baseline }; } if (command !== "check") throw new Error(`WRN-CONTRACT-COMMAND: unknown command '${command}'.`); if (!existsSync(baseline)) { throw new Error(`WRN-CONTRACT-BASELINE: no baseline found; run 'wrnexus contracts snapshot'.`); } const previous = validateSnapshot(JSON.parse(await readFile(baseline, "utf8")), baseline); const issues = checkContractCompatibility(previous, current); if (args.includes("--json")) { console.log(JSON.stringify({ ok: issues.length === 0, issues, baseline }, null, 2)); } else if (issues.length === 0) { console.log(`✓ ${current.contracts.length} contracts are backward compatible.`); } else { console.error(`Breaking contract changes detected (${issues.length}):`); for (const issue of issues) { console.error(` ${issue.code} ${issue.contract}: ${issue.message}`); if (issue.consumers.length) console.error(` Consumers: ${issue.consumers.join(", ")}`); } } return { ok: issues.length === 0, issueCount: issues.length, baseline }; }