import { join } from "node:path"; import { config } from "../config.js"; import { atomicWriteJson, ensureDirectory, readJsonFile, } from "../utils/fileStore.js"; export type LearningSessionState = { lastGatedTurn: number; lastReviewedTurn: number; pendingReview: boolean; sessionId: string; updatedAt: string; }; export class LearningStateStore { constructor(private readonly baseDir = config.LEARNING_STATE_STORAGE_DIR) {} async initialize() { await ensureDirectory(this.baseDir); } async read(sessionId: string): Promise { const existing = await readJsonFile(this.filePath(sessionId)); if (existing) { return existing; } return { lastGatedTurn: 0, lastReviewedTurn: 0, pendingReview: false, sessionId, updatedAt: new Date(0).toISOString(), }; } async write(state: LearningSessionState) { await atomicWriteJson(this.filePath(state.sessionId), { ...state, updatedAt: new Date().toISOString(), }); } async markPending(sessionId: string, pendingReview: boolean) { const current = await this.read(sessionId); await this.write({ ...current, pendingReview, }); } async completeReview(sessionId: string, reviewedTurnCount: number) { const current = await this.read(sessionId); await this.write({ ...current, lastGatedTurn: Math.max(current.lastGatedTurn, reviewedTurnCount), lastReviewedTurn: reviewedTurnCount, pendingReview: false, }); } async completeGate(sessionId: string, gatedTurnCount: number) { const current = await this.read(sessionId); await this.write({ ...current, lastGatedTurn: gatedTurnCount, pendingReview: false, }); } private filePath(sessionId: string) { return join(this.baseDir, `${sessionId}.json`); } }