import type { CheckpointId, CheckpointRef, CheckpointScopeId, MessageId, OrchestrationV2ThreadProjection, RunId, } from "@t3tools/contracts"; import * as DateTime from "effect/DateTime"; export interface ThreadCheckpointSummary { readonly checkpointId?: CheckpointId; readonly scopeId?: CheckpointScopeId; readonly runId: RunId; readonly checkpointTurnCount: number; readonly checkpointRef: CheckpointRef; readonly status: "ready" | "missing" | "error" | "stale"; readonly files: ReadonlyArray<{ readonly path: string; readonly kind: string; readonly additions: number; readonly deletions: number; }>; readonly assistantMessageId: MessageId | null; readonly completedAt: string; } /** Derives the checkpoint/diff rows needed by review UIs from native V2 entities. */ export function deriveThreadCheckpointSummaries( projection: OrchestrationV2ThreadProjection, ): ReadonlyArray { return projection.checkpoints.flatMap((checkpoint) => { if (checkpoint.appRunOrdinal === null || checkpoint.runId === null) return []; const assistantMessageId = projection.messages.findLast( (message) => message.runId === checkpoint.runId && message.role === "assistant", )?.id ?? null; return [ { checkpointId: checkpoint.id, scopeId: checkpoint.scopeId, runId: checkpoint.runId, checkpointTurnCount: checkpoint.appRunOrdinal, checkpointRef: checkpoint.ref, status: checkpoint.status, files: checkpoint.files, assistantMessageId, completedAt: DateTime.formatIso(checkpoint.capturedAt), }, ]; }); }