Files
Ekklesia/core/src/cli/doctor.ts
T
ekklesia 02ee3ccd80
CI / verify (pull_request) Successful in 20s
CI / infrastructure-smoke (pull_request) Successful in 20s
CI / migration-smoke (pull_request) Successful in 25s
feat: add Ekklesia doctor command
2026-07-21 10:42:21 -05:00

74 lines
2.3 KiB
TypeScript

import { readFile } from "node:fs/promises";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { diagnoseEkklesia, doctorExitCode, formatDoctorReport } from "../diagnostics/index.js";
interface ModuleSdkPackageDocument {
readonly version?: unknown;
}
interface RootPackageDocument extends ModuleSdkPackageDocument {
readonly engines?: {
readonly node?: unknown;
};
}
async function readJson(pathname: string): Promise<unknown> {
return JSON.parse(await readFile(pathname, "utf8")) as unknown;
}
function rootPackageDocument(value: unknown): RootPackageDocument {
if (typeof value !== "object" || value === null || Array.isArray(value)) {
throw new TypeError("Invalid workspace package metadata.");
}
return value as RootPackageDocument;
}
function requiredString(value: unknown): string {
if (typeof value !== "string" || value.length === 0) {
throw new TypeError("Missing workspace package metadata.");
}
return value;
}
export async function runDoctorCommand(repositoryRoot = process.cwd()): Promise<number> {
const [rootValue, moduleSdkValue] = await Promise.all([
readJson(path.join(repositoryRoot, "package.json")),
readJson(path.join(repositoryRoot, "packages", "module-sdk", "package.json")),
]);
const rootPackage = rootPackageDocument(rootValue);
const moduleSdkPackage = rootPackageDocument(moduleSdkValue);
const report = await diagnoseEkklesia({
databaseUrl: process.env.DATABASE_URL,
moduleDiscovery: {
moduleSdkVersion: requiredString(moduleSdkPackage.version),
modulesDirectory: path.join(repositoryRoot, "modules"),
platformVersion: requiredString(rootPackage.version),
},
runtimeRange: requiredString(rootPackage.engines?.node),
runtimeVersion: process.versions.node,
});
console.log(formatDoctorReport(report).join("\n"));
return doctorExitCode(report);
}
function isDirectExecution(): boolean {
const entrypoint = process.argv[1];
return (
entrypoint !== undefined && import.meta.url === pathToFileURL(path.resolve(entrypoint)).href
);
}
if (isDirectExecution()) {
runDoctorCommand()
.then((exitCode) => {
process.exitCode = exitCode;
})
.catch(() => {
console.error("Ekklesia Doctor failed before diagnostics could be composed.");
process.exitCode = 1;
});
}