import test from "node:test"; import assert from "node:assert/strict"; import { mkdtemp, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { resolve } from "node:path"; import { FileSystemProjectContextStore } from "../src/agents/project-context.js"; test("project context store reads defaults and applies domain patches", async () => { const root = await mkdtemp(resolve(tmpdir(), "ai-ops-project-context-")); const store = new FileSystemProjectContextStore({ filePath: resolve(root, "project-context.json"), }); const initial = await store.readState(); assert.deepEqual(initial, { schemaVersion: 1, globalFlags: {}, artifactPointers: {}, taskQueue: [], }); await store.patchState({ globalFlags: { requirements_defined: true, }, artifactPointers: { prd: "docs/PRD.md", }, enqueueTasks: [ { taskId: "task-1", id: "task-1", title: "Build parser", status: "pending", }, ], }); const updated = await store.patchState({ upsertTasks: [ { taskId: "task-1", id: "task-1", title: "Build parser", status: "in_progress", }, { taskId: "task-2", id: "task-2", title: "Add tests", status: "pending", }, ], }); assert.equal(updated.globalFlags.requirements_defined, true); assert.equal(updated.artifactPointers.prd, "docs/PRD.md"); assert.deepEqual( updated.taskQueue.map((task) => `${task.id}:${task.status}`), ["task-1:in_progress", "task-2:pending"], ); assert.equal(updated.schemaVersion, 1); }); test("project context accepts conflict-aware task statuses", async () => { const root = await mkdtemp(resolve(tmpdir(), "ai-ops-project-context-conflict-")); const store = new FileSystemProjectContextStore({ filePath: resolve(root, "project-context.json"), }); const updated = await store.patchState({ upsertTasks: [ { taskId: "task-conflict", id: "task-conflict", title: "Resolve merge conflict", status: "conflict", }, { taskId: "task-resolving", id: "task-resolving", title: "Retry merge", status: "resolving_conflict", }, ], }); assert.deepEqual( updated.taskQueue.map((task) => `${task.taskId}:${task.status}`), ["task-conflict:conflict", "task-resolving:resolving_conflict"], ); }); test("project context parser merges missing root keys with defaults", async () => { const root = await mkdtemp(resolve(tmpdir(), "ai-ops-project-context-")); const filePath = resolve(root, "project-context.json"); const store = new FileSystemProjectContextStore({ filePath }); await writeFile( filePath, `${JSON.stringify( { taskQueue: [ { taskId: "task-1", id: "task-1", title: "Migrate", status: "pending", }, ], }, null, 2, )}\n`, "utf8", ); const state = await store.readState(); assert.equal(state.schemaVersion, 1); assert.deepEqual(state.globalFlags, {}); assert.deepEqual(state.artifactPointers, {}); assert.equal(state.taskQueue[0]?.id, "task-1"); });