/*
RFC-0221: `handoff.validate` — pre-flight integrity check of a bundle without absorbing.
- Do not migrate, regenerate, or write anything.
- RFC-0221: initial bundle validator.
- RFC-1249: wire werkstatt.commands.validate into packages.check + retire CMD-OUTPUT debt
*/
import path from "node:path";
import type {
KernelCommandInput,
KernelCommandResult,
KernelRuntimeContext,
} from "@warpgogol/werkstatt-engine/kernel";
import { hashFile, readLock, readManifest } from "./bundle-io.ts";
export interface HandoffValidateData {
bundleDir: string;
app: string;
entriesChecked: number;
problems: string[];
}
function resolveBundleDir(input: KernelCommandInput, workspaceRoot: string): string {
const flag = input.flags["bundle"];
const raw = typeof flag === "string" ? flag : undefined;
if (!raw) {
throw new Error("[handoff.validate] requires --bundle ");
}
return path.resolve(workspaceRoot, raw);
}
export async function runHandoffValidate(
input: KernelCommandInput,
context: KernelRuntimeContext,
): Promise> {
const { workspaceRoot, logger } = context;
const bundleDir = resolveBundleDir(input, workspaceRoot);
const lock = await readLock(bundleDir);
const manifest = await readManifest(bundleDir);
const problems: string[] = [];
if (lock.app !== manifest.app) {
problems.push(`lock.app (${lock.app}) != manifest.app (${manifest.app})`);
}
for (const entry of manifest.entries) {
const abs = path.join(bundleDir, entry.path);
try {
const actual = await hashFile(abs);
if (actual !== entry.hash) {
problems.push(`hash mismatch: ${entry.path} (${entry.kind})`);
}
} catch {
problems.push(`missing file: ${entry.path}`);
}
}
logger.section("[handoff.validate]");
logger.info(`Bundle: ${bundleDir}`);
logger.info(
`App: ${lock.app} | ecosystem ${lock.ecosystem.version} | ${manifest.entries.length} entries`,
);
const data: HandoffValidateData = {
bundleDir,
app: lock.app,
entriesChecked: manifest.entries.length,
problems,
};
if (problems.length > 0) {
for (const p of problems) logger.error(`[handoff.validate] ${p}`);
return {
data,
exitCode: 1,
summary: `[handoff.validate] ${problems.length} integrity problem(s)`,
nextSteps: [
{
action: `Fix the ${problems.length} integrity problem(s) above, then re-run: pnpm exec werkstatt run handoff.validate --bundle `,
kind: "required",
},
],
};
}
logger.success("[handoff.validate] bundle integrity OK");
return {
data,
exitCode: 0,
summary: `[handoff.validate] OK — ${manifest.entries.length} entries verified`,
};
}