dream-cycles.ts
1 import fs from 'fs' 2 import path from 'path' 3 import { DATA_DIR } from '@/lib/server/data-dir' 4 import { hmrSingleton, safeJsonParse } from '@/lib/shared-utils' 5 import type { DreamCycle } from '@/types' 6 7 const DREAM_CYCLES_PATH = path.join(DATA_DIR, 'dream-cycles.json') 8 9 const state = hmrSingleton('__dream_cycles__', () => ({ 10 cycles: null as DreamCycle[] | null, 11 })) 12 13 function ensureLoaded(): DreamCycle[] { 14 if (state.cycles !== null) return state.cycles 15 try { 16 const raw = fs.readFileSync(DREAM_CYCLES_PATH, { encoding: 'utf-8' }) 17 state.cycles = safeJsonParse<DreamCycle[]>(raw, []) 18 } catch { 19 state.cycles = [] 20 } 21 return state.cycles 22 } 23 24 function persist(): void { 25 fs.mkdirSync(path.dirname(DREAM_CYCLES_PATH), { recursive: true }) 26 fs.writeFileSync(DREAM_CYCLES_PATH, JSON.stringify(ensureLoaded(), null, 2), { encoding: 'utf-8' }) 27 } 28 29 export function saveDreamCycle(cycle: DreamCycle): void { 30 const cycles = ensureLoaded() 31 const idx = cycles.findIndex((c) => c.id === cycle.id) 32 if (idx >= 0) { 33 cycles[idx] = cycle 34 } else { 35 cycles.push(cycle) 36 } 37 persist() 38 } 39 40 export function listDreamCycles(agentId?: string, limit = 50): DreamCycle[] { 41 const cycles = ensureLoaded() 42 const filtered = agentId ? cycles.filter((c) => c.agentId === agentId) : [...cycles] 43 filtered.sort((a, b) => b.startedAt - a.startedAt) 44 return filtered.slice(0, limit) 45 } 46 47 export function getDreamCycle(id: string): DreamCycle | null { 48 return ensureLoaded().find((c) => c.id === id) ?? null 49 }