Files
truthmark/tests/cli/index-impact-context.test.ts
e3edcc8afa feat: v2.3.0 add interactive platform selection to init (#38)
* feat: add interactive platform selection to init

* chore: remove completed OpenSpec artifacts

* chore: remove implemented design note

* fix: protect init lifecycle from unsafe config paths

* fix: support clearing init platforms from CLI

* docs: retire config command from repository rules

* docs: align init lifecycle and clear-platform contracts

* docs: keep repository guidance current-state focused

* docs: limit cleanup to repository-native documents

* docs: preserve historical version notes

---------

Co-authored-by: MerlinH <merlinh221@gmail.com>
2026-07-31 18:54:10 +10:00

325 lines
11 KiB
TypeScript

import { describe, it } from "node:test";
import { expect } from "expect";
import { writeTruthmarkConfig } from "../helpers/truthmark-config.js";
import { runInit } from "../../src/init/init.js";
import { runCli } from "../helpers/run-cli.js";
import { createTempRepo } from "../helpers/temp-repo.js";
describe("repository intelligence CLI commands", () => {
it("renders RepoIndex and RouteMap data from truthmark index --json", async () => {
const repo = await createTempRepo();
try {
await repo.writeFile("src/index.ts", "export const value = 1;\n");
await writeTruthmarkConfig(repo.rootDir);
await runInit(repo.rootDir);
const result = await runCli(["index", "--json"], { cwd: repo.rootDir });
const output = JSON.parse(result.stdout) as {
command: string;
diagnostics: unknown[];
data: {
repoIndex: { schemaVersion: string };
routeMap: { schemaVersion: string };
};
};
expect(output.command).toBe("index");
expect(output.data.repoIndex.schemaVersion).toBe("repo-index/v0");
expect(output.data.routeMap.schemaVersion).toBe("route-map/v0");
expect(output.diagnostics).toEqual([]);
} finally {
await repo.cleanup();
}
});
it("renders ImpactSet from truthmark impact --base main --json", async () => {
const repo = await createTempRepo();
try {
await repo.writeFile("src/index.ts", "export const value = 1;\n");
await writeTruthmarkConfig(repo.rootDir);
await runInit(repo.rootDir);
await repo.runGit(["add", "."]);
await repo.runGit(["commit", "-m", "initial"]);
await repo.writeFile("src/index.ts", "export const value = 2;\n");
const result = await runCli(["impact", "--base", "main", "--json"], {
cwd: repo.rootDir,
});
const output = JSON.parse(result.stdout) as {
command: string;
data: {
impactSet: {
schemaVersion: string;
changedFiles: Array<{ path: string }>;
};
};
};
expect(output.command).toBe("impact");
expect(output.data.impactSet.schemaVersion).toBe("impact-set/v0");
expect(
output.data.impactSet.changedFiles.map((file) => file.path),
).toContain("src/index.ts");
} finally {
await repo.cleanup();
}
});
it("exposes compact ContextPack replacement data from workflow status", async () => {
const repo = await createTempRepo();
try {
await repo.writeFile(
"package.json",
JSON.stringify(
{ name: "sample", scripts: { test: "vitest" } },
null,
2,
),
);
await repo.writeFile(
"src/math.ts",
"export function add(left: number, right: number) { return left + right; }\n",
);
await repo.writeFile(
"tests/math.test.ts",
"import { add } from '../src/math.js';\nvoid add;\n",
);
await writeTruthmarkConfig(repo.rootDir);
await runInit(repo.rootDir);
await repo.runGit(["add", "."]);
await repo.runGit(["commit", "-m", "initial"]);
await repo.writeFile(
"src/math.ts",
"export function add(left: number, right: number) { return left + right + 0; }\n",
);
const result = await runCli(
[
"workflow",
"status",
"--workflow",
"truthmark-sync",
"--base",
"main",
"--json",
],
{ cwd: repo.rootDir },
);
const output = JSON.parse(result.stdout) as {
command: string;
data: {
workflowState: {
applicability: { state: string; reasons: string[] };
actionContext: {
allowedWritePaths: string[];
primaryTruthDocs: string[];
evidencePrompts: string[];
requiredEvidence?: unknown;
};
targetTruthDocs: string[];
changedFiles: Array<{ path: string }>;
affectedRoutes: unknown[];
workflowCard: {
affectedFiles: string[];
likelyRouteOwners: string[];
suggestedTruthDocs: string[];
openQuestions: string[];
skippedHelperStatus: Array<{
helper: string;
status: string;
reason: string;
}>;
};
checks: {
reviewChecklist: string[];
reviewQuestions?: unknown;
required?: unknown;
recommended: string[];
helpers: unknown[];
affectedTests?: string[];
testCommands?: string[];
};
nextSteps: string[];
diagnostics: unknown[];
};
};
};
const state = output.data.workflowState;
const compactTestGuidance = [
...(state.checks.affectedTests ?? []),
...(state.checks.testCommands ?? []),
];
expect(result.exitCode).toBe(0);
expect(output.command).toBe("workflow status");
expect(state.applicability.state).toBe("ready");
expect(state.applicability.reasons).toEqual([]);
expect(state.actionContext.allowedWritePaths).toEqual(
expect.arrayContaining(state.targetTruthDocs),
);
expect(state.actionContext.primaryTruthDocs).toEqual(
state.targetTruthDocs,
);
expect(state.actionContext.allowedWritePaths).toContain(
"docs/truthmark/routes/areas.md",
);
expect(state.targetTruthDocs.length).toBeGreaterThan(0);
expect(state.changedFiles.map((file) => file.path)).toContain(
"src/math.ts",
);
expect(state.affectedRoutes.length).toBeGreaterThan(0);
expect(state.actionContext.evidencePrompts.length).toBeGreaterThan(0);
expect(state.actionContext.requiredEvidence).toBeUndefined();
expect(state.checks.reviewChecklist.length).toBeGreaterThan(0);
expect(state.checks.reviewQuestions).toBeUndefined();
expect(state.checks.required).toBeUndefined();
expect(state.checks.helpers.length).toBeGreaterThan(0);
expect(state.workflowCard.affectedFiles).toContain("src/math.ts");
expect(state.workflowCard.likelyRouteOwners.length).toBeGreaterThan(0);
expect(state.workflowCard.suggestedTruthDocs).toEqual(
state.targetTruthDocs,
);
expect(state.workflowCard.openQuestions).toEqual([]);
expect(state.workflowCard.skippedHelperStatus).toEqual(
expect.arrayContaining([
expect.objectContaining({
helper: "validate-sync-report",
status: "skipped",
}),
]),
);
expect(Array.isArray(state.nextSteps)).toBe(true);
expect(Array.isArray(state.diagnostics)).toBe(true);
expect(compactTestGuidance.join("\n")).toContain("tests/math.test.ts");
const humanResult = await runCli(
[
"workflow",
"status",
"--workflow",
"truthmark-sync",
"--base",
"main",
],
{ cwd: repo.rootDir },
);
expect(humanResult.stdout).toContain("Applicability: ready.");
expect(humanResult.stdout).toContain("Affected files: src/math.ts");
expect(humanResult.stdout).toContain("Likely route owners:");
expect(humanResult.stdout).toContain("Suggested truth docs:");
} finally {
await repo.cleanup();
}
});
it("keeps workflow status and impact JSON free of ContextPack content", async () => {
const repo = await createTempRepo();
try {
await repo.writeFile("src/index.ts", "export const value = 1;\n");
await writeTruthmarkConfig(repo.rootDir);
await runInit(repo.rootDir);
await repo.runGit(["add", "."]);
await repo.runGit(["commit", "-m", "initial"]);
await repo.writeFile("src/index.ts", "export const value = 2;\n");
const statusResult = await runCli(
[
"workflow",
"status",
"--workflow",
"truthmark-sync",
"--base",
"main",
"--json",
],
{ cwd: repo.rootDir },
);
const statusOutput = JSON.parse(statusResult.stdout) as {
command: string;
data: {
workflowState: {
schemaVersion: string;
workflow: string;
contextPack?: unknown;
sourceFiles?: unknown;
truthDocs?: Array<{ content?: string }>;
actionContext: { helperValidationCommands: unknown[] };
checks: { helpers: unknown[] };
};
};
};
const statusJson = JSON.stringify(statusOutput.data.workflowState);
expect(statusResult.exitCode).toBe(0);
expect(statusOutput.command).toBe("workflow status");
expect(statusOutput.data.workflowState.schemaVersion).toBe(
"truthmark-workflow/v0",
);
expect(statusOutput.data.workflowState.workflow).toBe("truthmark-sync");
expect(statusOutput.data.workflowState.contextPack).toBeUndefined();
expect(
statusOutput.data.workflowState.actionContext.helperValidationCommands
.length,
).toBeGreaterThan(0);
expect(
statusOutput.data.workflowState.checks.helpers.length,
).toBeGreaterThan(0);
expect(statusJson).not.toContain('"contextPack"');
expect(statusJson).not.toContain('"sourceFiles"');
expect(statusJson).not.toContain('"truthDocs":[{');
expect(statusJson).not.toContain('"routeMap"');
expect(statusJson).not.toContain('"content":');
const impactResult = await runCli(
["impact", "--base", "main", "--json"],
{ cwd: repo.rootDir },
);
const impactOutput = JSON.parse(impactResult.stdout) as {
data: {
impactSet: {
contextPack?: unknown;
sourceFiles?: unknown;
truthDocs?: unknown;
};
};
};
const impactJson = JSON.stringify(impactOutput.data.impactSet);
expect(impactResult.exitCode).toBe(0);
expect(impactOutput.data.impactSet.contextPack).toBeUndefined();
expect(impactOutput.data.impactSet.truthDocs).toBeUndefined();
expect(impactOutput.data.impactSet.sourceFiles).toBeUndefined();
expect(impactJson).not.toContain('"contextPack"');
expect(impactJson).not.toContain('"sourceFiles"');
expect(impactJson).not.toContain('"truthDocs":[{');
expect(impactJson).not.toContain('"content":');
} finally {
await repo.cleanup();
}
});
it("retires truthmark context as a hard-removed command", async () => {
const repo = await createTempRepo();
try {
await repo.writeFile("src/index.ts", "export const value = 1;\n");
await writeTruthmarkConfig(repo.rootDir);
await runInit(repo.rootDir);
const result = await runCli(
["context", "--workflow", "truth-sync", "--base", "main", "--json"],
{
cwd: repo.rootDir,
},
);
expect(result.exitCode).toBe(1);
expect(`${result.stdout}\n${result.stderr}`).toContain("unknown command");
expect(result.stdout).not.toContain("contextPack");
expect(result.stdout).not.toContain("ContextPack");
} finally {
await repo.cleanup();
}
});
});