Files
vscode-cowriting-plugin/src/threadModel.ts
T
2026-06-10 06:53:13 -07:00

49 lines
1.6 KiB
TypeScript

/**
* vscode-free mutations on the Artifact (spec §6.5). Keeping thread logic here
* (not in the vscode controller) keeps it unit-testable; ThreadController is a
* thin adapter that calls these and persists via CoauthorStore.
*/
import {
newId,
type Artifact,
type Fingerprint,
type Provenance,
type ThreadStatus,
} from "./model";
export interface NewMessage {
author: Provenance;
body: string;
}
function message(m: NewMessage) {
return { id: newId("m"), author: m.author, body: m.body, createdAt: new Date().toISOString() };
}
/** Lazily-created anchor + thread for a new region discussion (PUC-1). */
export function addThread(
artifact: Artifact,
fingerprint: Fingerprint,
first: NewMessage,
): { threadId: string; anchorId: string } {
const anchorId = newId("a");
const threadId = newId("t");
artifact.anchors[anchorId] = { fingerprint };
artifact.threads.push({ id: threadId, anchorId, status: "open", messages: [message(first)] });
return { threadId, anchorId };
}
/** Append a reply (PUC-2). Throws if the thread is unknown. */
export function appendMessage(artifact: Artifact, threadId: string, m: NewMessage): void {
const t = artifact.threads.find((x) => x.id === threadId);
if (!t) throw new Error(`unknown thread id: ${threadId}`);
t.messages.push(message(m));
}
/** Resolve/reopen a thread (PUC-2). Throws if the thread is unknown. */
export function setStatus(artifact: Artifact, threadId: string, status: ThreadStatus): void {
const t = artifact.threads.find((x) => x.id === threadId);
if (!t) throw new Error(`unknown thread id: ${threadId}`);
t.status = status;
}