import assert from "node:assert/strict"; import { test } from "node:test"; import type { ReviewComment } from "./comments.js"; import { applyAgentResponses, conversationReviewItems, pruneAgentResponses, setConversationAction, type AgentResponseInput, } from "./conversations.js"; function comment(extra: Partial = {}): ReviewComment { return { id: "conversation-1", author: "user", sha: null, file: "src/a.ts", side: "new", line: 8, lineText: "const before = true;", body: "Please fix this.", ...extra, }; } test("selective handoff queues and clears an action without changing conversation identity", () => { let comments = setConversationAction([comment()], "conversation-1", "fix"); assert.equal(comments[0]!.id, "conversation-1"); assert.equal(comments[0]!.requestedAction, "fix"); assert.equal(comments[0]!.status, "open"); comments = setConversationAction(comments, "conversation-1", null); assert.equal(comments[0]!.requestedAction, undefined); }); test("agent response marks a conversation addressed and appends immutable before/after evidence", () => { const input: AgentResponseInput = { commentId: "conversation-1", summary: "Renamed the flag and covered the false branch.", changedLocations: [ { file: "src/a.ts", line: 8, after: "const enabled = false;", }, ], checks: [{ command: "npm test", status: "passed", summary: "42 tests passed" }], }; const result = applyAgentResponses([comment({ requestedAction: "fix" })], [], [input], "2026-07-30T12:00:00.000Z"); assert.equal(result.comments[0]!.status, "agent_addressed"); assert.equal(result.comments[0]!.requestedAction, undefined); assert.deepEqual(result.responses, [ { id: "response-conversation-1-2026-07-30T12:00:00.000Z-1", commentId: "conversation-1", summary: input.summary, changedLocations: [ { file: "src/a.ts", line: 8, before: "const before = true;", after: "const enabled = false;", }, ], checks: input.checks, createdAt: "2026-07-30T12:00:00.000Z", }, ]); }); test("agent responses reject unknown, resolved, and duplicate conversation ids", () => { const response: AgentResponseInput = { commentId: "missing", summary: "Done.", changedLocations: [], checks: [], }; assert.throws(() => applyAgentResponses([comment()], [], [response], "2026-07-30T12:00:00.000Z"), /Unknown/); assert.throws( () => applyAgentResponses( [comment({ status: "resolved" })], [], [{ ...response, commentId: "conversation-1" }], "2026-07-30T12:00:00.000Z", ), /resolved/, ); assert.throws( () => applyAgentResponses( [comment()], [], [ { ...response, commentId: "conversation-1" }, { ...response, commentId: "conversation-1" }, ], "2026-07-30T12:00:00.000Z", ), /Duplicate/, ); }); test("before evidence is not inferred for a different line in the same file", () => { const result = applyAgentResponses( [comment()], [], [ { commentId: "conversation-1", summary: "Changed the related declaration.", changedLocations: [{ file: "src/a.ts", line: 2, after: "const enabled = false;" }], checks: [], }, ], "2026-07-30T12:00:00.000Z", ); assert.equal(result.responses[0]!.changedLocations[0]!.before, undefined); }); test("agent responses are pruned with their owning conversation", () => { const response = applyAgentResponses( [comment()], [], [ { commentId: "conversation-1", summary: "Done.", changedLocations: [], checks: [], }, ], "2026-07-30T12:00:00.000Z", ).responses; assert.deepEqual(pruneAgentResponses(response, []), []); assert.deepEqual(pruneAgentResponses(response, [comment()]), response); }); test("persisted conversations become review items when there is no current diff", () => { assert.deepEqual( conversationReviewItems([ comment(), comment({ id: "conversation-2", line: 9 }), comment({ id: "conversation-3", sha: "abcdef123456", line: 10 }), ]), [ { sha: null, label: "conversation", subject: "Persisted review conversations" }, { sha: "abcdef123456", label: "abcdef1", subject: "Persisted review conversations" }, ], ); });