198 lines
5.5 KiB
TypeScript
198 lines
5.5 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import {
|
|
auditPostCompactionReads,
|
|
extractReadPaths,
|
|
formatAuditWarning,
|
|
} from "./post-compaction-audit.js";
|
|
|
|
describe("extractReadPaths", () => {
|
|
it("extracts file paths from Read tool calls", () => {
|
|
const messages = [
|
|
{
|
|
role: "assistant",
|
|
content: [
|
|
{
|
|
type: "tool_use",
|
|
name: "read",
|
|
input: { file_path: "WORKFLOW_AUTO.md" },
|
|
},
|
|
],
|
|
},
|
|
{
|
|
role: "assistant",
|
|
content: [
|
|
{
|
|
type: "tool_use",
|
|
name: "read",
|
|
input: { file_path: "memory/2026-02-16.md" },
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
const paths = extractReadPaths(messages);
|
|
expect(paths).toEqual(["WORKFLOW_AUTO.md", "memory/2026-02-16.md"]);
|
|
});
|
|
|
|
it("handles path parameter (alternative to file_path)", () => {
|
|
const messages = [
|
|
{
|
|
role: "assistant",
|
|
content: [
|
|
{
|
|
type: "tool_use",
|
|
name: "read",
|
|
input: { path: "AGENTS.md" },
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
const paths = extractReadPaths(messages);
|
|
expect(paths).toEqual(["AGENTS.md"]);
|
|
});
|
|
|
|
it("ignores non-assistant messages", () => {
|
|
const messages = [
|
|
{
|
|
role: "user",
|
|
content: [
|
|
{
|
|
type: "tool_use",
|
|
name: "read",
|
|
input: { file_path: "should_be_ignored.md" },
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
const paths = extractReadPaths(messages);
|
|
expect(paths).toEqual([]);
|
|
});
|
|
|
|
it("ignores non-read tool calls", () => {
|
|
const messages = [
|
|
{
|
|
role: "assistant",
|
|
content: [
|
|
{
|
|
type: "tool_use",
|
|
name: "exec",
|
|
input: { command: "cat WORKFLOW_AUTO.md" },
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
const paths = extractReadPaths(messages);
|
|
expect(paths).toEqual([]);
|
|
});
|
|
|
|
it("handles empty messages array", () => {
|
|
const paths = extractReadPaths([]);
|
|
expect(paths).toEqual([]);
|
|
});
|
|
|
|
it("handles messages with non-array content", () => {
|
|
const messages = [
|
|
{
|
|
role: "assistant",
|
|
content: "text only",
|
|
},
|
|
];
|
|
|
|
const paths = extractReadPaths(messages);
|
|
expect(paths).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe("auditPostCompactionReads", () => {
|
|
const workspaceDir = "/Users/test/workspace";
|
|
|
|
it("passes when all required files are read", () => {
|
|
const readPaths = ["WORKFLOW_AUTO.md", "memory/2026-02-16.md"];
|
|
const result = auditPostCompactionReads(readPaths, workspaceDir);
|
|
|
|
expect(result.passed).toBe(true);
|
|
expect(result.missingPatterns).toEqual([]);
|
|
});
|
|
|
|
it("fails when no files are read", () => {
|
|
const result = auditPostCompactionReads([], workspaceDir);
|
|
|
|
expect(result.passed).toBe(false);
|
|
expect(result.missingPatterns).toContain("WORKFLOW_AUTO.md");
|
|
expect(result.missingPatterns.some((p) => p.includes("memory"))).toBe(true);
|
|
});
|
|
|
|
it("reports only missing files", () => {
|
|
const readPaths = ["WORKFLOW_AUTO.md"];
|
|
const result = auditPostCompactionReads(readPaths, workspaceDir);
|
|
|
|
expect(result.passed).toBe(false);
|
|
expect(result.missingPatterns).not.toContain("WORKFLOW_AUTO.md");
|
|
expect(result.missingPatterns.some((p) => p.includes("memory"))).toBe(true);
|
|
});
|
|
|
|
it("matches RegExp patterns against relative paths", () => {
|
|
const readPaths = ["memory/2026-02-16.md"];
|
|
const result = auditPostCompactionReads(readPaths, workspaceDir);
|
|
|
|
expect(result.passed).toBe(false);
|
|
expect(result.missingPatterns).toContain("WORKFLOW_AUTO.md");
|
|
expect(result.missingPatterns.length).toBe(1);
|
|
});
|
|
|
|
it("normalizes relative paths when matching", () => {
|
|
const readPaths = ["./WORKFLOW_AUTO.md", "memory/2026-02-16.md"];
|
|
const result = auditPostCompactionReads(readPaths, workspaceDir);
|
|
|
|
expect(result.passed).toBe(true);
|
|
expect(result.missingPatterns).toEqual([]);
|
|
});
|
|
|
|
it("normalizes absolute paths when matching", () => {
|
|
const readPaths = [
|
|
"/Users/test/workspace/WORKFLOW_AUTO.md",
|
|
"/Users/test/workspace/memory/2026-02-16.md",
|
|
];
|
|
const result = auditPostCompactionReads(readPaths, workspaceDir);
|
|
|
|
expect(result.passed).toBe(true);
|
|
expect(result.missingPatterns).toEqual([]);
|
|
});
|
|
|
|
it("accepts custom required reads list", () => {
|
|
const readPaths = ["custom.md"];
|
|
const customRequired = ["custom.md"];
|
|
const result = auditPostCompactionReads(readPaths, workspaceDir, customRequired);
|
|
|
|
expect(result.passed).toBe(true);
|
|
expect(result.missingPatterns).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe("formatAuditWarning", () => {
|
|
it("formats warning message with missing patterns", () => {
|
|
const missingPatterns = ["WORKFLOW_AUTO.md", "memory\\/\\d{4}-\\d{2}-\\d{2}\\.md"];
|
|
const message = formatAuditWarning(missingPatterns);
|
|
|
|
expect(message).toContain("⚠️ Post-Compaction Audit");
|
|
expect(message).toContain("WORKFLOW_AUTO.md");
|
|
expect(message).toContain("memory");
|
|
expect(message).toContain("Please read them now");
|
|
});
|
|
|
|
it("formats single missing pattern", () => {
|
|
const missingPatterns = ["WORKFLOW_AUTO.md"];
|
|
const message = formatAuditWarning(missingPatterns);
|
|
|
|
expect(message).toContain("WORKFLOW_AUTO.md");
|
|
// Check that the missing patterns list only contains WORKFLOW_AUTO.md
|
|
const lines = message.split("\n");
|
|
const patternLines = lines.filter((l) => l.trim().startsWith("- "));
|
|
expect(patternLines).toHaveLength(1);
|
|
expect(patternLines[0]).toContain("WORKFLOW_AUTO.md");
|
|
});
|
|
});
|