/** * Tests for docgraph persisted-state management and the filesystem fallback: * `getState`, `isInitialized`, and `contentText`. */ import { test } from "node:test"; import assert from "node:assert/strict"; import { getState, isInitialized, contentText } from "../src/utils.ts"; import type { DocgraphState } from "../src/types.ts"; import { makeTempRepo, cleanupTemp, writeFiles, makeCtx, resultStateEntry, } from "./helpers.ts"; function state(overrides: Partial = {}): DocgraphState { return { initialized: true, schemaVersion: 1, ...overrides }; } // ── getState ────────────────────────────────────────────────────────── test("getState returns the default uninitialized state when the branch is empty", () => { const cwd = makeTempRepo(); try { const { ctx } = makeCtx({ cwd, entries: [] }); assert.deepEqual(getState(ctx), { initialized: false, schemaVersion: 1 }); } finally { cleanupTemp(cwd); } }); test("getState returns the raw default when the branch has no docgraph tool results", () => { const cwd = makeTempRepo(); try { const { ctx } = makeCtx({ cwd, entries: [ { type: "custom", id: "c1", parentId: null, timestamp: "2026-01-01T00:00:00.000Z", customType: "whatever", data: { state: state({ initialized: true }) }, } as never, resultStateEntry("pi_read", state(), "read"), resultStateEntry("not_docgraph", state()), ], }); // Non-message and non-docgraph_* entries are all ignored. assert.deepEqual(getState(ctx), { initialized: false, schemaVersion: 1 }); } finally { cleanupTemp(cwd); } }); test("getState returns the first docgraph tool-result state in branch order", () => { const cwd = makeTempRepo(); try { const { ctx } = makeCtx({ cwd, entries: [ resultStateEntry("docgraph_init", state({ initialized: true, schemaVersion: 1 })), resultStateEntry("docgraph_ticket_create", state({ initialized: true, schemaVersion: 7 })), ], }); // First match wins (newest-first branch order in real sessions). assert.deepEqual(getState(ctx), { initialized: true, schemaVersion: 1 }); } finally { cleanupTemp(cwd); } }); test("getState ignores tool results that carry no state in details", () => { const cwd = makeTempRepo(); try { const entry = resultStateEntry("docgraph_init", state()); // Stripping details yields a branch with no usable state. const stripped = { ...entry, message: { ...(entry as never as { message: object }).message, details: undefined }, } as never; const { ctx } = makeCtx({ cwd, entries: [stripped] }); assert.deepEqual(getState(ctx), { initialized: false, schemaVersion: 1 }); } finally { cleanupTemp(cwd); } }); // ── isInitialized ───────────────────────────────────────────────────── test("isInitialized returns true from persisted state without touching the filesystem", () => { const cwd = makeTempRepo(); // deliberately empty repo try { const { ctx } = makeCtx({ cwd, state: state({ initialized: true }) }); assert.equal(isInitialized(ctx), true); } finally { cleanupTemp(cwd); } }); test("isInitialized falls back to filesystem markers when no state exists", () => { const cwd = makeTempRepo(); try { writeFiles(cwd, { "AGENTS.md": "# AGENTS\n\n## Documentation Index\n\n| Document | Purpose |", "README.md": "# Project", }); const { ctx } = makeCtx({ cwd }); assert.equal(isInitialized(ctx), true); } finally { cleanupTemp(cwd); } }); test("isInitialized accepts the '## Source of Truth' marker as evidence of scaffolding", () => { const cwd = makeTempRepo(); try { writeFiles(cwd, { "AGENTS.md": "# AGENTS\n\n## Source of Truth\n\nThe code wins.", "README.md": "# Project", }); const { ctx } = makeCtx({ cwd }); assert.equal(isInitialized(ctx), true); } finally { cleanupTemp(cwd); } }); test("isInitialized is false when AGENTS.md lacks the scaffolding markers", () => { const cwd = makeTempRepo(); try { writeFiles(cwd, { "AGENTS.md": "# AGENTS\n\nJust some notes.", "README.md": "# Project", }); const { ctx } = makeCtx({ cwd }); assert.equal(isInitialized(ctx), false); } finally { cleanupTemp(cwd); } }); test("isInitialized is false when README.md is missing even with an AGENTS.md marker", () => { const cwd = makeTempRepo(); try { writeFiles(cwd, { "AGENTS.md": "## Documentation Index", }); const { ctx } = makeCtx({ cwd }); assert.equal(isInitialized(ctx), false); } finally { cleanupTemp(cwd); } }); test("isInitialized is false in a completely empty repo", () => { const cwd = makeTempRepo(); try { const { ctx } = makeCtx({ cwd }); assert.equal(isInitialized(ctx), false); } finally { cleanupTemp(cwd); } }); test("isInitialized reads from ctx.cwd, not the process cwd", () => { const cwd = makeTempRepo(); try { const other = makeTempRepo(); try { writeFiles(other, { "AGENTS.md": "## Documentation Index", "README.md": "# Project", }); const { ctx } = makeCtx({ cwd }); assert.equal(isInitialized(ctx), false); } finally { cleanupTemp(other); } } finally { cleanupTemp(cwd); } }); // ── contentText ─────────────────────────────────────────────────────── test("contentText returns '' for non-text or missing items", () => { assert.equal(contentText(undefined), ""); assert.equal( contentText({ type: "image", data: "abc", mimeType: "image/png" } as never), "", ); assert.equal(contentText({ type: "text" }), ""); assert.equal(contentText({ type: "text", text: "" }), ""); }); test("contentText returns the text of a text item", () => { assert.equal(contentText({ type: "text", text: "hello" }), "hello"); });