import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { test, expect } from "vitest";
import {
discoverSiteWorkspaces,
executeKernelPipeline,
findWorkspaceRoot,
parseKernelArgv,
} from "../index.ts";
/*
Verify foundational kernel runtime behaviors such as argv parsing, app discovery, and workspace root resolution.
- Do not cover app-specific command behavior here.
- Fixtures stay inline and minimal so each case states its own setup.
- RFC-1311: carried legacy entry — Backfill reduced Compass scaffolding on the kernel runtime tests file.
- RFC-0246: Pin targetless workspace pipeline execution from root kernel config.
*/
// @ai-invariant fixtures must not couple to internals beyond the public surface under test
test("parseKernelArgv separates args and flags", () => {
const parsed = parseKernelArgv([
"--root",
"src",
"--dry-run",
"alpha",
"--tag=beta",
"--",
"tail",
]);
expect(parsed.diagnostics.length).toBe(2);
expect(parsed.diagnostics[0]?.ruleId).toBe("KERNEL-ARG-01");
expect(parsed.diagnostics[1]?.ruleId).toBe("KERNEL-ARG-01");
expect(parsed.flags.root).toBe("src");
expect(parsed.flags["dry-run"]).toBe(true);
expect(parsed.flags.tag).toBe("beta");
});
test("discoverSiteWorkspaces finds configured apps", async () => {
const workspaceRoot = await fs.mkdtemp(path.join(os.tmpdir(), "werkstatt-workspace-"));
const appRoot = path.join(workspaceRoot, "apps", "demo");
const toolsRoot = path.join(appRoot, "tools");
await fs.mkdir(toolsRoot, { recursive: true });
await fs.writeFile(path.join(workspaceRoot, "package.json"), "{}\n", "utf8");
await fs.writeFile(
path.join(workspaceRoot, "pnpm-workspace.yaml"),
"packages:\n - apps/*\n",
"utf8",
);
await fs.writeFile(
path.join(appRoot, "package.json"),
JSON.stringify({ name: "@demo/site" }, null, 2),
"utf8",
);
await fs.writeFile(
path.join(toolsRoot, "kernel.config.js"),
"export default { modules: [] };\n",
"utf8",
);
const sites = await discoverSiteWorkspaces(workspaceRoot);
expect(sites.length).toBe(1);
expect(sites[0]?.name).toBe("demo");
expect(sites[0]?.packageName).toBe("@demo/site");
expect(sites[0]?.configPath?.endsWith("kernel.config.js")).toBeTruthy();
});
test("findWorkspaceRoot walks upward to the pnpm workspace", async () => {
const workspaceRoot = await fs.mkdtemp(path.join(os.tmpdir(), "werkstatt-root-"));
const nestedDirectory = path.join(workspaceRoot, "apps", "demo", "src");
await fs.mkdir(nestedDirectory, { recursive: true });
await fs.writeFile(path.join(workspaceRoot, "package.json"), "{}\n", "utf8");
await fs.writeFile(
path.join(workspaceRoot, "pnpm-workspace.yaml"),
"packages:\n - apps/*\n",
"utf8",
);
const resolved = await findWorkspaceRoot(nestedDirectory);
expect(resolved).toBe(workspaceRoot);
});
test(
"executeKernelPipeline runs workspace pipelines without an app target",
{ timeout: 60_000 },
async () => {
const workspaceRoot = await fs.mkdtemp(path.join(os.tmpdir(), "werkstatt-pipeline-"));
const toolsRoot = path.join(workspaceRoot, "tools");
await fs.mkdir(toolsRoot, { recursive: true });
await fs.writeFile(path.join(workspaceRoot, "package.json"), "{}\n", "utf8");
await fs.writeFile(
path.join(workspaceRoot, "pnpm-workspace.yaml"),
"packages:\n - apps/*\n",
"utf8",
);
await fs.writeFile(
path.join(toolsRoot, "kernel.config.mjs"),
`
export default {
modules: [{
name: "workspace-fixture",
version: "0.0.0",
declarations: [],
commands: [
{
name: "workspace.ok",
modulePath: "test",
description: "fixture",
scope: "workspace",
expectedDurationMs: 1,
timeoutMs: 1000,
execute() {
return { exitCode: 0, summary: "workspace.ok" };
},
},
{
name: "workspace.fail",
modulePath: "test",
description: "fixture",
scope: "workspace",
execute() {
return { exitCode: 1, summary: "workspace.fail" };
},
},
{
name: "workspace.timeout",
modulePath: "test",
description: "fixture",
scope: "workspace",
timeoutMs: 10,
execute() {
return new Promise(() => {});
},
},
{
name: "app.only",
modulePath: "test",
description: "fixture",
scope: "app",
execute() {
return { exitCode: 0, summary: "app.only" };
},
},
],
pipelines: [
{ name: "workspace.good", steps: [{ command: "workspace.ok" }] },
{ name: "workspace.fail", steps: [{ command: "workspace.fail" }] },
{ name: "workspace.timeout", steps: [{ command: "workspace.timeout" }] },
{ name: "workspace.skipped", steps: [{ command: "workspace.ok", skip: true, skipReason: "fixture skip" }] },
{ name: "workspace.bad", steps: [{ command: "app.only" }] },
],
}],
};
`,
"utf8",
);
const report = await executeKernelPipeline({
workspaceRoot,
pipelineName: "workspace.good",
outputFormat: "json",
});
expect(Array.isArray(report)).toBe(false);
expect(Array.isArray(report) ? undefined : report.ok).toBe(true);
expect(Array.isArray(report) ? undefined : report.siteName).toBe(undefined);
expect(Array.isArray(report) ? undefined : report.steps[0]?.commandName).toBe("workspace.ok");
expect(Array.isArray(report) ? undefined : report.steps[0]?.timing.exceededTimeout).toBe(false);
expect(Array.isArray(report) ? undefined : typeof report.timing.totalDurationMs).toBe("number");
expect(Array.isArray(report) ? undefined : report.timing.slowestSteps[0]?.command).toBe(
"workspace.ok",
);
const failedReport = await executeKernelPipeline({
workspaceRoot,
pipelineName: "workspace.fail",
outputFormat: "json",
});
expect(Array.isArray(failedReport) ? undefined : failedReport.ok).toBe(false);
expect(Array.isArray(failedReport) ? undefined : failedReport.timing.failedStep).toBe(
"workspace.fail",
);
expect(
Array.isArray(failedReport) ? undefined : failedReport.timing.slowestSteps[0]?.status,
).toBe("fail");
const skippedReport = await executeKernelPipeline({
workspaceRoot,
pipelineName: "workspace.skipped",
outputFormat: "json",
});
expect(Array.isArray(skippedReport) ? undefined : skippedReport.ok).toBe(true);
expect(
Array.isArray(skippedReport) ? undefined : skippedReport.timing.slowestSteps[0]?.status,
).toBe("skipped");
const timeoutReport = await executeKernelPipeline({
workspaceRoot,
pipelineName: "workspace.timeout",
outputFormat: "json",
});
expect(Array.isArray(timeoutReport) ? undefined : timeoutReport.ok).toBe(false);
expect(Array.isArray(timeoutReport) ? undefined : timeoutReport.timing.timeoutCount).toBe(1);
expect(
Array.isArray(timeoutReport) ? undefined : timeoutReport.timing.slowestSteps[0]?.status,
).toBe("timeout");
await expect(() =>
executeKernelPipeline({
workspaceRoot,
pipelineName: "workspace.bad",
outputFormat: "json",
}),
).rejects.toThrow(/cannot execute app-scoped step/);
},
);