UNPKG

aicf-core

Version:

Universal AI Context Format (AICF) - Enterprise-grade AI memory infrastructure with 95.5% compression and zero semantic loss

374 lines 12.2 kB
import { promises as fs } from "node:fs"; import { join } from "node:path"; import { FileOrganizationAgent } from "./file-organization-agent.js"; /** * Memory Lifecycle Manager - 3-tier system compatible * * Manages memory decay for session dumps and AICF files: * - JSON session dumps: 7/30/90-day lifecycle * - AICF files: Compress old entries, keep critical info * - Archive management: Move old dumps to archive */ export class MemoryLifecycleManager { name; projectRoot; lifecycle; paths; constructor(options = {}) { this.name = "MemoryLifecycleManager"; this.projectRoot = options.projectRoot ?? process.cwd(); this.lifecycle = { recent: 7, medium: 30, old: 90, purge: 365, }; this.paths = { sessionDumps: join(this.projectRoot, ".meta/session-dumps"), archive: join(this.projectRoot, ".meta/session-dumps/archive"), aicf: join(this.projectRoot, ".aicf"), ai: join(this.projectRoot, ".ai"), }; } /** * Process complete memory lifecycle for 3-tier system */ async processLifecycle() { try { console.log(`🔄 ${this.name} processing memory lifecycle...`); const results = { fileOrganization: await this.processFileOrganization(), sessionDumps: await this.processSessionDumpLifecycle(), aicfFiles: await this.processAICFLifecycle(), memoryCompression: await this.processMemoryCompression(), statistics: await this.calculateStatistics(), }; console.log(`✅ ${this.name} completed lifecycle processing`); return results; } catch (error) { const err = error; console.error(`❌ ${this.name} lifecycle error:`, err.message); throw error; } } /** * Process file organization using FileOrganizationAgent */ async processFileOrganization() { try { const agent = new FileOrganizationAgent({ projectRoot: this.projectRoot, }); const result = await agent.organizeFiles(); return { success: result.errors === 0, filesOrganized: result.organized, }; } catch (error) { const err = error; return { success: false, error: err.message, }; } } /** * Process session dump lifecycle */ async processSessionDumpLifecycle() { try { if (!(await this.directoryExists(this.paths.sessionDumps))) { return { processed: 0, archived: 0, deleted: 0 }; } const dumps = await this.getSessionDumps(); let archived = 0; let deleted = 0; for (const dump of dumps) { if (dump.ageInDays >= this.lifecycle.purge) { const shouldDelete = await this.shouldDeleteDump(dump.path); if (shouldDelete) { await fs.unlink(dump.path); deleted++; } } else if (dump.ageInDays >= this.lifecycle.old) { await this.archiveDump(dump.path); archived++; } } return { processed: dumps.length, archived, deleted, }; } catch (error) { const err = error; return { processed: 0, archived: 0, deleted: 0, error: err.message, }; } } /** * Process AICF file lifecycle */ async processAICFLifecycle() { try { if (!(await this.directoryExists(this.paths.aicf))) { return { processed: 0, compressed: 0 }; } const files = await fs.readdir(this.paths.aicf); const aicfFiles = files.filter((f) => f.endsWith(".aicf")); let compressed = 0; for (const file of aicfFiles) { const filePath = join(this.paths.aicf, file); const stats = await fs.stat(filePath); const ageInDays = this.calculateAgeInDays(stats.mtime); if (ageInDays >= this.lifecycle.medium) { await this.compressAICFFile(filePath); compressed++; } } return { processed: aicfFiles.length, compressed, }; } catch (error) { const err = error; return { processed: 0, compressed: 0, error: err.message, }; } } /** * Process memory compression */ async processMemoryCompression() { try { const conversationsFile = join(this.paths.aicf, "conversations.aicf"); if (!(await this.fileExists(conversationsFile))) { return { applied: false }; } const originalContent = await fs.readFile(conversationsFile, "utf-8"); const compressedContent = this.compressConversations(originalContent); if (compressedContent.length < originalContent.length) { await fs.writeFile(conversationsFile, compressedContent); const ratio = ((originalContent.length - compressedContent.length) / originalContent.length) * 100; return { applied: true, compressionRatio: Math.round(ratio * 100) / 100, }; } return { applied: false }; } catch (error) { const err = error; return { applied: false, error: err.message, }; } } /** * Calculate memory statistics */ async calculateStatistics() { try { const stats = { totalFiles: 0, totalSize: 0, ageDistribution: {}, }; if (await this.directoryExists(this.paths.sessionDumps)) { const dumps = await this.getSessionDumps(); stats.totalFiles += dumps.length; dumps.forEach((dump) => { stats.totalSize += dump.size; let category; if (dump.ageInDays <= this.lifecycle.recent) category = "recent"; else if (dump.ageInDays <= this.lifecycle.medium) category = "medium"; else if (dump.ageInDays <= this.lifecycle.old) category = "old"; else category = "archived"; stats.ageDistribution[category] = (stats.ageDistribution[category] ?? 0) + 1; }); } return stats; } catch (error) { const err = error; return { totalFiles: 0, totalSize: 0, ageDistribution: {}, error: err.message, }; } } /** * Get all session dumps with metadata */ async getSessionDumps() { const dumps = []; try { const files = await fs.readdir(this.paths.sessionDumps); for (const file of files) { if (file.endsWith(".json")) { const filePath = join(this.paths.sessionDumps, file); const stats = await fs.stat(filePath); dumps.push({ path: filePath, ageInDays: this.calculateAgeInDays(stats.mtime), size: stats.size, }); } } } catch { // Directory doesn't exist or can't be read } return dumps; } /** * Calculate age in days from date */ calculateAgeInDays(date) { const now = new Date(); const diffTime = Math.abs(now.getTime() - date.getTime()); return Math.ceil(diffTime / (1000 * 60 * 60 * 24)); } /** * Check if dump should be deleted */ async shouldDeleteDump(dumpPath) { try { const content = await fs.readFile(dumpPath, "utf-8"); const data = JSON.parse(content); const hasCriticalDecisions = data.decisions?.some((d) => d.impact === "CRITICAL" || d.impact === "HIGH") ?? false; return !hasCriticalDecisions; } catch { return true; } } /** * Archive a session dump */ async archiveDump(dumpPath) { try { await this.ensureDirectoryExists(this.paths.archive); const fileName = dumpPath.split("/").pop() ?? "unknown.json"; const archivePath = join(this.paths.archive, fileName); await fs.rename(dumpPath, archivePath); } catch (error) { const err = error; console.error(`Failed to archive dump: ${err.message}`); } } /** * Compress AICF file by removing old entries */ async compressAICFFile(filePath) { try { const content = await fs.readFile(filePath, "utf-8"); const lines = content.split("\n"); const compressedLines = []; let inOldSection = false; lines.forEach((line) => { if (line.startsWith("@CONVERSATION:")) { inOldSection = false; } if (line.includes("IMPACT:CRITICAL") || line.includes("IMPACT:HIGH") || line.startsWith("@")) { compressedLines.push(line); inOldSection = false; } else if (!inOldSection) { compressedLines.push(line); } }); await fs.writeFile(filePath, compressedLines.join("\n")); } catch (error) { const err = error; console.error(`Failed to compress AICF file: ${err.message}`); } } /** * Compress conversations content */ compressConversations(content) { const lines = content.split("\n"); const compressed = []; let currentAge = 0; let skipNonCritical = false; lines.forEach((line) => { if (line.includes("age=")) { const match = line.match(/age=(\d+)d/); if (match?.[1]) { currentAge = parseInt(match[1], 10); skipNonCritical = currentAge > this.lifecycle.medium; } } if (!skipNonCritical || line.startsWith("@") || line.includes("CRITICAL") || line.includes("HIGH")) { compressed.push(line); } }); return compressed.join("\n"); } /** * Check if directory exists */ async directoryExists(dirPath) { try { const stats = await fs.stat(dirPath); return stats.isDirectory(); } catch { return false; } } /** * Check if file exists */ async fileExists(filePath) { try { await fs.access(filePath); return true; } catch { return false; } } /** * Ensure directory exists */ async ensureDirectoryExists(dirPath) { try { await fs.mkdir(dirPath, { recursive: true }); } catch { // Directory already exists or can't be created } } } //# sourceMappingURL=memory-lifecycle-manager.js.map