// The notes shapes, with NO server imports (the lib/note-types.ts rule): a // client component may take a value from here without dragging node:fs into // the browser bundle. The store that reads and writes them is ./store.mjs, // shared by the app and `umtool notes`; docs/notes.md is the prose. // The values are ./shape.mjs's (pure, shared with the store and the CLI); // this file adds the types. export { ANCHOR_KINDS, NOTE_AUTHORS, NOTE_STATUSES, NOTE_TEXT_LIMIT, NOTES_FORMAT, NOTES_VERSION, REPORT_BLOCKS, } from "./shape.mjs"; export { CONTEXT as ANCHOR_CONTEXT } from "./anchor.mjs"; export type NoteStatus = "open" | "resolved" | "wontfix"; export type NoteAuthor = "operator" | "agent"; /** What a moment resolved to when it was written, for the agent reading it back. */ export type MomentResolved = { entry?: string; title?: string; quote?: string; channel?: string; video?: string; sourceT?: number; url?: string; /** The schedule did not match this file exactly (a preview, not out/). */ approx?: boolean; }; export type Anchor = | { kind: "text"; section: string; quote: string; prefix: string; suffix: string } | { kind: "cite"; cite: string } | { kind: "section"; section: string } | { kind: "whole" } | { kind: "moment"; file: string; t: number; take?: string; entry?: string; resolved?: MomentResolved } | { kind: "entry"; entry: string } | { kind: "take"; take: string } | { kind: "edit"; entry?: string; field: string; from: unknown; to: unknown }; export type AnchorKind = Anchor["kind"]; export type NoteReply = { author: NoteAuthor; text: string; at: string }; export type Note = { id: string; status: NoteStatus; author: NoteAuthor; text: string; at: string; updatedAt: string; anchor: Anchor; replies: NoteReply[]; resolvedAt?: string; resolvedBy?: NoteAuthor; }; export type NotesSubject = | { kind: "article"; site: string; report: string } | { kind: "video-project"; project: string }; /** Which file an agent should edit to act on a note. Filled by umtool, correctable. */ export type NotesSource = { draft?: string; generator?: string; manifest?: string; how?: string }; export type NotesDoc = { format: "umtool-notes"; version: 1; subject: NotesSubject; source?: NotesSource; notes: Note[]; }; /** What GET /api/notes returns. `token` goes back on every write (409 when stale). */ export type NotesRead = { subject: NotesSubject; file: string; token: string; doc: NotesDoc | null; source: NotesSource | null; error?: string; }; /** One write. The server stamps author "operator" on everything the UI sends. */ export type NoteOp = | { op: "add"; text: string; anchor: Anchor } | { op: "edit"; id: string; text?: string; anchor?: Anchor } | { op: "status"; id: string; status: NoteStatus } | { op: "reply"; id: string; text: string; resolve?: boolean } | { op: "delete"; id: string } | { op: "delete-reply"; id: string; index: number } | { op: "source"; source: NotesSource }; export const openCount = (doc: NotesDoc | null | undefined): number => doc ? doc.notes.filter((n) => n.status === "open").length : 0;