Files

99 lines
3.3 KiB
JavaScript

#!/usr/bin/env node
import fs from "node:fs";
import path from "node:path";
import process from "node:process";
import { spawnSync } from "node:child_process";
import { capture, commandExists, run } from "./lib/exec.mjs";
const root = process.cwd();
const requiredRootFiles = [
"CLAUDE.md",
"product/milestones.json",
"ItWorx.KnowledgeHub.slnx",
"src/frontend/package.json"
];
const missingRoot = requiredRootFiles.filter((entry) => !fs.existsSync(path.join(root, entry)));
if (missingRoot.length > 0) {
console.error("Run this command from the repository root. Missing:", missingRoot.join(", "));
process.exit(1);
}
const checks = [];
async function check(name, command, args, predicate, required = true) {
if (!commandExists(command)) {
checks.push({ name, value: "missing", ok: false, required });
return;
}
try {
const value = await capture(command, args);
checks.push({ name, value: value.split(/\r?\n/)[0], ok: predicate(value), required });
} catch (error) {
checks.push({ name, value: `error: ${error.message}`, ok: false, required });
}
}
await check("Git", "git", ["--version"], (value) => /git version/i.test(value));
await check("Node.js", "node", ["--version"], (value) => {
const major = Number(value.match(/v?(\d+)/)?.[1] ?? 0);
return major >= 24;
});
await check("Corepack", "corepack", ["--version"], (value) => value.length > 0);
await check("pnpm", "corepack", ["pnpm", "--version"], (value) => {
const major = Number(value.match(/(\d+)/)?.[1] ?? 0);
return major >= 11;
});
await check(".NET SDK", "dotnet", ["--version"], (value) => value.trim().startsWith("10."));
function findWorkingPython() {
for (const candidate of ["python3", "python"]) {
if (!commandExists(candidate)) {
continue;
}
const probe = spawnSync(candidate, ["--version"], { stdio: "ignore", shell: false });
if (probe.status === 0) {
return candidate;
}
}
return null;
}
const python = findWorkingPython();
if (python) {
await check("Python", python, ["--version"], (value) => {
const match = value.match(/Python\s+(\d+)\.(\d+)/i);
return Boolean(match && Number(match[1]) >= 3 && Number(match[2]) >= 11);
});
} else {
checks.push({ name: "Python", value: "missing or non-working", ok: false, required: true });
}
await check("Docker", "docker", ["--version"], (value) => /Docker version/i.test(value));
if (commandExists("docker")) {
try {
const compose = await capture("docker", ["compose", "version"]);
checks.push({ name: "Docker Compose", value: compose, ok: /Compose version\s+v?\d+\./i.test(compose), required: true });
} catch (error) {
checks.push({ name: "Docker Compose", value: `error: ${error.message}`, ok: false, required: true });
}
}
const width = Math.max(...checks.map((entry) => entry.name.length), 10);
for (const entry of checks) {
const marker = entry.ok ? "OK " : entry.required ? "ERR" : "WARN";
console.log(`${marker} ${entry.name.padEnd(width)} ${entry.value}`);
}
const failures = checks.filter((entry) => entry.required && !entry.ok);
if (failures.length > 0) {
console.error("\nRequired toolchain checks failed.");
process.exit(1);
}
if (!fs.existsSync(path.join(root, "pnpm-lock.yaml"))) {
console.warn("\nWARN pnpm-lock.yaml is not present yet. M0 must generate and commit it.");
}
console.log("\nToolchain baseline is available.");