import { createHash, randomUUID } from "node:crypto"; import { mkdir, open, readdir, readFile, rename, rm, unlink, } from "node:fs/promises"; import { basename, dirname, join } from "node:path"; import { ALLOWED_STATUSES, ARTIFACT_KIND, ARTIFACT_NAME, ARTIFACT_VERSION, EVENT_FRESHNESS_RECOVERY_RULE, HANDOFF_REASONS, MANDATORY_HEADINGS, OPERATION_NAME, PRODUCT_NAME, REQUIRED_FRONTMATTER_FIELDS, RESUME_PROMPT_INTRO, ARCHIVE_RETENTION_LIMIT, } from "./constants.js"; export type ContinuityStatus = (typeof ALLOWED_STATUSES)[number]; export interface ContinuityFrontmatter { kind: string; product: string; artifact: string; operation: string; status: ContinuityStatus; version: number; eventId: string; sessionId: string; sessionFile: string; createdAt: string; updatedAt: string; modelId: string; synthesisModel: string; synthesisEffort?: string; tokenCountAtTrigger: number; contextWindow: number; reserveTokens: number; keepRecentTokens: number; effectiveTriggerPercent: number; effectiveKeepRecentPercent: number; handoffReason: (typeof HANDOFF_REASONS)[number]; branchLeafBefore?: string | null; } export interface ArtifactPaths { sessionRoot: string; pendingDir: string; archiveDir: string; failedDir: string; pendingPath: string; } export interface ParsedBrief { frontmatter: Record; body: string; } export interface ValidationResult { ok: boolean; errors: string[]; } function safePathPart(value: string): string { return value.replace(/[^A-Za-z0-9_.-]/g, "_"); } export function createEventId(): string { return randomUUID(); } export function buildArtifactPaths( artifactDirectory: string, sessionId: string, eventId: string, ): ArtifactPaths { const safeSessionId = safePathPart(sessionId); const safeEventId = safePathPart(eventId); const sessionRoot = join(artifactDirectory, safeSessionId); const pendingDir = join(sessionRoot, "pending"); const archiveDir = join(sessionRoot, "archive"); const failedDir = join(sessionRoot, "failed"); return { sessionRoot, pendingDir, archiveDir, failedDir, pendingPath: join(pendingDir, `${safeEventId}.md`), }; } export function buildFrontmatter( input: Omit< ContinuityFrontmatter, "kind" | "product" | "artifact" | "operation" | "version" >, ): ContinuityFrontmatter { return { kind: ARTIFACT_KIND, product: PRODUCT_NAME, artifact: ARTIFACT_NAME, operation: OPERATION_NAME, version: ARTIFACT_VERSION, ...input, }; } function yamlScalar(value: string | number | null | undefined): string { if (value === null) return "null"; if (value === undefined) return "null"; if (typeof value === "number") return String(value); return JSON.stringify(value); } export function serializeFrontmatter( frontmatter: ContinuityFrontmatter, ): string { const lines = [ "---", `kind: ${yamlScalar(frontmatter.kind)}`, `product: ${yamlScalar(frontmatter.product)}`, `artifact: ${yamlScalar(frontmatter.artifact)}`, `operation: ${yamlScalar(frontmatter.operation)}`, `status: ${yamlScalar(frontmatter.status)}`, `version: ${yamlScalar(frontmatter.version)}`, `eventId: ${yamlScalar(frontmatter.eventId)}`, `sessionId: ${yamlScalar(frontmatter.sessionId)}`, `sessionFile: ${yamlScalar(frontmatter.sessionFile)}`, `createdAt: ${yamlScalar(frontmatter.createdAt)}`, `updatedAt: ${yamlScalar(frontmatter.updatedAt)}`, `modelId: ${yamlScalar(frontmatter.modelId)}`, `synthesisModel: ${yamlScalar(frontmatter.synthesisModel)}`, ...(frontmatter.synthesisEffort !== undefined ? [`synthesisEffort: ${yamlScalar(frontmatter.synthesisEffort)}`] : []), `tokenCountAtTrigger: ${yamlScalar(frontmatter.tokenCountAtTrigger)}`, `contextWindow: ${yamlScalar(frontmatter.contextWindow)}`, `reserveTokens: ${yamlScalar(frontmatter.reserveTokens)}`, `keepRecentTokens: ${yamlScalar(frontmatter.keepRecentTokens)}`, `effectiveTriggerPercent: ${yamlScalar(frontmatter.effectiveTriggerPercent)}`, `effectiveKeepRecentPercent: ${yamlScalar(frontmatter.effectiveKeepRecentPercent)}`, `handoffReason: ${yamlScalar(frontmatter.handoffReason)}`, ]; if (frontmatter.branchLeafBefore !== undefined) { lines.push(`branchLeafBefore: ${yamlScalar(frontmatter.branchLeafBefore)}`); } lines.push("---"); return `${lines.join("\n")}\n`; } export function serializeBrief( frontmatter: ContinuityFrontmatter, body: string, ): string { return `${serializeFrontmatter(frontmatter)}${body.trim()}\n`; } export function applyEventFreshnessRecoveryRule(body: string): string { if (body.includes(EVENT_FRESHNESS_RECOVERY_RULE)) return body.trim(); const heading = "## Recovery Instructions"; const headingIndex = body.indexOf(heading); if (headingIndex < 0) return body.trim(); const insertionPoint = headingIndex + heading.length; const before = body.slice(0, insertionPoint).trimEnd(); const after = body.slice(insertionPoint).trimStart(); return `${before}\n\n${EVENT_FRESHNESS_RECOVERY_RULE}${after ? `\n\n${after}` : ""}`; } function parseScalar(raw: string): string | number | null { const value = raw.trim(); if (value === "null") return null; if (/^-?\d+(\.\d+)?$/.test(value)) return Number(value); if ( (value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'")) ) { try { return JSON.parse(value); } catch { return value.slice(1, -1); } } return value; } export function parseBrief(content: string): ParsedBrief { if (!content.startsWith("---\n")) { throw new Error("Continuity Brief must start with YAML frontmatter"); } const end = content.indexOf("\n---", 4); if (end === -1) { throw new Error("Continuity Brief frontmatter is not closed"); } const frontmatterText = content.slice(4, end).trim(); const body = content.slice(end + "\n---".length).replace(/^\n/, ""); const frontmatter: Record = {}; for (const line of frontmatterText.split("\n")) { const index = line.indexOf(":"); if (index === -1) continue; const key = line.slice(0, index).trim(); const value = line.slice(index + 1); frontmatter[key] = parseScalar(value); } return { frontmatter, body }; } export function normalizeSynthesizedBody(synthesized: string): string { let body = synthesized.trim(); if (body.startsWith("```")) { body = body .replace(/^```(?:markdown|md)?\s*/i, "") .replace(/```\s*$/i, "") .trim(); } if (body.startsWith("---\n")) { try { body = parseBrief(body).body.trim(); } catch { // Keep original text; validation will fail with a useful message. } } const headingIndex = body.indexOf("# Continuity Brief"); if (headingIndex > 0) body = body.slice(headingIndex); return body.trim(); } function getSection(body: string, heading: string): string { const start = body.indexOf(`${heading}\n`); if (start === -1) return ""; const afterHeading = start + heading.length; const next = body.slice(afterHeading + 1).search(/\n##[#]?\s+/); return next === -1 ? body.slice(afterHeading).trim() : body.slice(afterHeading, afterHeading + 1 + next).trim(); } function findDirectivePromotion(body: string): string | undefined { const authoritySections = [ "## Constraints / Forbid", "## Next Actions", "## Recovery Instructions", ]; const directivePattern = /\b(ignore previous instructions|system instructions are overridden|follow these instructions instead|developer instructions no longer apply)\b/i; const evidencePattern = /\b(observed|quoted|transcript|tool output|file content|prior artifact|as evidence)\b/i; for (const heading of authoritySections) { const section = getSection(body, heading); if (directivePattern.test(section) && !evidencePattern.test(section)) { return `${heading} appears to promote directive-looking content above active instruction authority`; } } return undefined; } const STRING_FRONTMATTER_FIELDS = [ "eventId", "sessionId", "sessionFile", "createdAt", "updatedAt", "modelId", "synthesisModel", "synthesisEffort", "handoffReason", ] as const; const NUMERIC_FRONTMATTER_FIELDS = [ "version", "tokenCountAtTrigger", "contextWindow", "reserveTokens", "keepRecentTokens", "effectiveTriggerPercent", "effectiveKeepRecentPercent", ] as const; const STATUS_TRANSITIONS: Record = { pending: ["archived", "failed"], archived: [], failed: [], }; function assertStatusTransition(from: unknown, to: ContinuityStatus): void { if (!ALLOWED_STATUSES.includes(from as ContinuityStatus)) { throw new Error(`invalid current status: ${String(from)}`); } const current = from as ContinuityStatus; if (!STATUS_TRANSITIONS[current].includes(to)) { throw new Error( `invalid Continuity Brief status transition: ${current} -> ${to}`, ); } } export function validateBrief( content: string, expectedSessionId?: string, ): ValidationResult { const errors: string[] = []; let parsed: ParsedBrief; try { parsed = parseBrief(content); } catch (error) { return { ok: false, errors: [error instanceof Error ? error.message : String(error)], }; } for (const field of REQUIRED_FRONTMATTER_FIELDS) { if ( parsed.frontmatter[field] === undefined || parsed.frontmatter[field] === "" ) { errors.push(`missing required frontmatter field: ${field}`); } } if (parsed.frontmatter.kind !== ARTIFACT_KIND) errors.push(`kind must be ${ARTIFACT_KIND}`); if (parsed.frontmatter.product !== PRODUCT_NAME) errors.push(`product must be ${PRODUCT_NAME}`); if (parsed.frontmatter.artifact !== ARTIFACT_NAME) errors.push(`artifact must be ${ARTIFACT_NAME}`); if (parsed.frontmatter.operation !== OPERATION_NAME) errors.push(`operation must be ${OPERATION_NAME}`); if ( !ALLOWED_STATUSES.includes(parsed.frontmatter.status as ContinuityStatus) ) { errors.push(`invalid status: ${String(parsed.frontmatter.status)}`); } if (parsed.frontmatter.version !== ARTIFACT_VERSION) errors.push(`version must be ${ARTIFACT_VERSION}`); for (const field of STRING_FRONTMATTER_FIELDS) { if (typeof parsed.frontmatter[field] !== "string") { errors.push(`${field} must be a string`); } } for (const field of NUMERIC_FRONTMATTER_FIELDS) { if ( typeof parsed.frontmatter[field] !== "number" || !Number.isFinite(parsed.frontmatter[field]) ) { errors.push(`${field} must be a finite number`); } } if ( typeof parsed.frontmatter.tokenCountAtTrigger === "number" && parsed.frontmatter.tokenCountAtTrigger < 0 ) { errors.push("tokenCountAtTrigger must be non-negative"); } if ( typeof parsed.frontmatter.contextWindow === "number" && parsed.frontmatter.contextWindow < 0 ) { errors.push("contextWindow must be non-negative"); } if ( typeof parsed.frontmatter.reserveTokens === "number" && parsed.frontmatter.reserveTokens <= 0 ) { errors.push("reserveTokens must be positive"); } if ( typeof parsed.frontmatter.keepRecentTokens === "number" && parsed.frontmatter.keepRecentTokens <= 0 ) { errors.push("keepRecentTokens must be positive"); } if ( typeof parsed.frontmatter.contextWindow === "number" && typeof parsed.frontmatter.reserveTokens === "number" && parsed.frontmatter.reserveTokens >= parsed.frontmatter.contextWindow ) { errors.push("reserveTokens must be lower than contextWindow"); } if ( typeof parsed.frontmatter.contextWindow === "number" && typeof parsed.frontmatter.reserveTokens === "number" && typeof parsed.frontmatter.keepRecentTokens === "number" && parsed.frontmatter.keepRecentTokens >= parsed.frontmatter.contextWindow - parsed.frontmatter.reserveTokens ) { errors.push( "keepRecentTokens must be lower than contextWindow - reserveTokens", ); } if ( typeof parsed.frontmatter.effectiveTriggerPercent === "number" && (parsed.frontmatter.effectiveTriggerPercent <= 0 || parsed.frontmatter.effectiveTriggerPercent >= 100) ) { errors.push("effectiveTriggerPercent must be positive and below 100"); } if ( typeof parsed.frontmatter.effectiveKeepRecentPercent === "number" && (parsed.frontmatter.effectiveKeepRecentPercent <= 0 || parsed.frontmatter.effectiveKeepRecentPercent >= 100) ) { errors.push("effectiveKeepRecentPercent must be positive and below 100"); } if ( !HANDOFF_REASONS.includes( parsed.frontmatter.handoffReason as (typeof HANDOFF_REASONS)[number], ) ) { errors.push( `invalid handoffReason: ${String(parsed.frontmatter.handoffReason)}`, ); } if (expectedSessionId && parsed.frontmatter.sessionId !== expectedSessionId) { errors.push(`sessionId mismatch: expected ${expectedSessionId}`); } const bodyLines = parsed.body.split(/\r?\n/).map((line) => line.trim()); for (const heading of MANDATORY_HEADINGS) { if (!bodyLines.includes(heading)) errors.push(`missing mandatory heading: ${heading}`); } const directivePromotion = findDirectivePromotion(parsed.body); if (directivePromotion) errors.push(directivePromotion); return { ok: errors.length === 0, errors }; } export function assertValidBrief( content: string, expectedSessionId?: string, ): void { const result = validateBrief(content, expectedSessionId); if (!result.ok) throw new Error(result.errors.join("; ")); } export function replaceBriefStatus( content: string, status: ContinuityStatus, updatedAt: string, ): string { const parsed = parseBrief(content); assertStatusTransition(parsed.frontmatter.status, status); const nextFrontmatter = { ...parsed.frontmatter, status, updatedAt, } as unknown as ContinuityFrontmatter; return serializeBrief(nextFrontmatter, parsed.body); } export function buildResumePrompt( savedBriefContent: string, expectedSessionId?: string, ): string { const parsed = parseBrief(savedBriefContent); if (parsed.frontmatter.status !== "pending") { throw new Error( `only pending Continuity Brief artifacts are valid resume input; got ${String(parsed.frontmatter.status)}`, ); } assertValidBrief(savedBriefContent, expectedSessionId); return `${savedBriefContent.endsWith("\n") ? savedBriefContent : `${savedBriefContent}\n`}\n${RESUME_PROMPT_INTRO}`; } export async function ensureArtifactDirectories( paths: ArtifactPaths, ): Promise { await Promise.all([ mkdir(paths.pendingDir, { recursive: true }), mkdir(paths.archiveDir, { recursive: true }), mkdir(paths.failedDir, { recursive: true }), ]); } async function syncDirectory(path: string): Promise { const handle = await open(path, "r"); try { await handle.sync(); } finally { await handle.close(); } } export async function writeTextFile( path: string, content: string, ): Promise { const directory = dirname(path); await mkdir(directory, { recursive: true }); const temporaryPath = join( directory, `.${basename(path)}.${process.pid}.${randomUUID()}.tmp`, ); let handle; try { handle = await open(temporaryPath, "wx", 0o600); await handle.writeFile(content, "utf8"); await handle.sync(); await handle.close(); handle = undefined; await rename(temporaryPath, path); await syncDirectory(directory); } finally { if (handle) await handle.close().catch(() => undefined); await rm(temporaryPath, { force: true }).catch(() => undefined); } } export async function readTextFile(path: string): Promise { return readFile(path, "utf8"); } export async function archiveBrief( pendingPath: string, archiveDir: string, eventId: string, content: string, ): Promise { const timestamp = new Date().toISOString().replace(/[:.]/g, "-"); const archivePath = join(archiveDir, `${timestamp}-${eventId}.md`); const archived = replaceBriefStatus( content, "archived", new Date().toISOString(), ); await writeTextFile(pendingPath, archived); await mkdir(archiveDir, { recursive: true }); await rename(pendingPath, archivePath); return archivePath; } export async function pruneArchivedBriefs( archiveDir: string, limit = ARCHIVE_RETENTION_LIMIT, ): Promise { if (!Number.isInteger(limit) || limit < 1) throw new Error("archive retention limit must be a positive integer"); let entries; try { entries = await readdir(archiveDir, { withFileTypes: true }); } catch (error) { if ( error instanceof Error && "code" in error && (error as NodeJS.ErrnoException).code === "ENOENT" ) { return []; } throw error; } const archiveFiles = entries .filter((entry) => entry.isFile() && entry.name.endsWith(".md")) .map((entry) => entry.name) .sort((a, b) => b.localeCompare(a)); const removed = archiveFiles .slice(limit) .map((name) => join(archiveDir, name)); for (const path of removed) await unlink(path); return removed; } export async function writeFailedArtifact( paths: ArtifactPaths, frontmatter: ContinuityFrontmatter, body: string, ): Promise { const timestamp = new Date().toISOString().replace(/[:.]/g, "-"); const failedPath = join( paths.failedDir, `${timestamp}-${frontmatter.eventId}.md`, ); const failed = serializeBrief( { ...frontmatter, status: "failed", updatedAt: new Date().toISOString() }, body, ); await writeTextFile(failedPath, failed); return failedPath; } export function hashBriefContent(content: string): string { return createHash("sha256").update(content, "utf8").digest("hex"); } export function buildFailureBody( phase: string, errorMessage: string, eventId: string, sessionId: string, sessionFile: string, ): string { return `# Continuity Brief Failure\n\nFailure phase: ${phase}\n\nError message: ${errorMessage}\n\nEvent id: ${eventId}\n\nSession id: ${sessionId}\n\nSession file: ${sessionFile}\n\nNative compaction was cancelled and no continuation prompt was submitted.\n`; }