UNPKG

aicf-core

Version:

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

235 lines 8.06 kB
#!/usr/bin/env node /* * SPDX-License-Identifier: AGPL-3.0-or-later * Copyright (c) 2025 Dennis van Leeuwen * * AICF Writer - Atomic, thread-safe writing to AI Context Format files */ import { join } from "node:path"; import { randomUUID } from "node:crypto"; import { ok, err, toError } from "./types/result.js"; import { SafeFileSystem } from "./utils/file-system.js"; import { ConsoleLogger } from "./utils/logger.js"; import { validatePath } from "./security/path-validator.js"; import { validateConfig, SECURE_DEFAULTS, } from "./security/config-validator.js"; import { sanitizePipeData } from "./security/data-sanitizer.js"; import { atomicFileOperation } from "./security/file-operations.js"; /** * AICF Writer - Write and update AICF files safely */ export class AICFWriter { aicfDir; fs; logger; config; locks = new Map(); constructor(aicfDir = ".aicf", fs, logger, config) { const pathResult = validatePath(aicfDir); if (!pathResult.ok) { throw pathResult.error; } this.aicfDir = pathResult.value; this.fs = new SafeFileSystem(fs); this.logger = logger ?? new ConsoleLogger(); validateConfig({ maxFileSize: config?.maxFileSize ?? SECURE_DEFAULTS.maxFileSize, ...config, }); this.config = { maxFileSize: config?.maxFileSize ?? SECURE_DEFAULTS.maxFileSize, lockTimeout: config?.lockTimeout ?? 5000, enablePIIRedaction: config?.enablePIIRedaction ?? false, }; this.ensureDirectory(); } /** * Ensure directory exists */ async ensureDirectory() { const existsResult = await this.fs.exists(this.aicfDir); if (!existsResult.ok || !existsResult.value) { const mkdirResult = await this.fs.mkdir(this.aicfDir, { recursive: true, }); if (!mkdirResult.ok) { this.logger.error("Failed to create directory", mkdirResult.error); } } } /** * Acquire lock for file */ async acquireLock(fileName) { try { const lockKey = `${this.aicfDir}/${fileName}`; const startTime = Date.now(); while (this.locks.has(lockKey)) { if (Date.now() - startTime > this.config.lockTimeout) { return err(new Error(`Lock acquisition timeout for ${fileName}`)); } const lockInfo = this.locks.get(lockKey); if (lockInfo && Date.now() - lockInfo.timestamp > 30000) { this.logger.warn(`Removing stale lock for ${fileName}`); this.locks.delete(lockKey); break; } await new Promise((resolve) => setTimeout(resolve, 10)); } this.locks.set(lockKey, { timestamp: Date.now(), pid: process.pid, lockId: randomUUID(), }); return ok(lockKey); } catch (error) { return err(toError(error)); } } /** * Release lock for file */ releaseLock(lockKey) { if (this.locks.has(lockKey)) { const lockInfo = this.locks.get(lockKey); if (lockInfo && lockInfo.pid === process.pid) { this.locks.delete(lockKey); } else { this.logger.warn(`Attempted to release lock owned by different process: ${lockKey}`); } } } /** * Get next line number for file */ async getNextLineNumber(filePath) { try { const existsResult = await this.fs.exists(filePath); if (!existsResult.ok) { return err(existsResult.error); } if (!existsResult.value) { return ok(1); } const contentResult = await this.fs.readFile(filePath); if (!contentResult.ok) { return err(contentResult.error); } const lines = contentResult.value.split("\n").filter(Boolean); if (lines.length === 0) { return ok(1); } const lastLine = lines[lines.length - 1]; if (!lastLine) { return ok(1); } const parts = lastLine.split("|", 1); const lineNum = parseInt(parts[0] ?? "0", 10); return ok(lineNum + 1); } catch (error) { return err(toError(error)); } } /** * Append line to file */ async appendLine(fileName, data) { const lockResult = await this.acquireLock(fileName); if (!lockResult.ok) { return err(lockResult.error); } const lockKey = lockResult.value; try { const filePath = join(this.aicfDir, fileName); const lineNumResult = await this.getNextLineNumber(filePath); if (!lineNumResult.ok) { return err(lineNumResult.error); } const lineNum = lineNumResult.value; const sanitized = sanitizePipeData(data); const line = `${lineNum}|${sanitized}\n`; const writeResult = await atomicFileOperation(filePath, async (tempPath) => { const existsResult = await this.fs.exists(filePath); if (existsResult.ok && existsResult.value) { const contentResult = await this.fs.readFile(filePath); if (contentResult.ok) { await this.fs.writeFile(tempPath, contentResult.value + line); } else { await this.fs.writeFile(tempPath, line); } } else { await this.fs.writeFile(tempPath, line); } return lineNum; }); if (!writeResult.ok) { return err(writeResult.error); } return ok(writeResult.value); } catch (error) { return err(toError(error)); } finally { this.releaseLock(lockKey); } } /** * Write conversation */ async writeConversation(conversation) { try { const data = [ `@CONVERSATION:`, `id=${sanitizePipeData(conversation.id)}`, `timestamp=${sanitizePipeData(conversation.timestamp)}`, `role=${sanitizePipeData(conversation.role)}`, `content=${sanitizePipeData(conversation.content)}`, ].join("\n"); return await this.appendLine("conversations.aicf", data); } catch (error) { return err(toError(error)); } } /** * Write memory */ async writeMemory(memory) { try { const data = [ `@MEMORY:`, `id=${sanitizePipeData(memory.id)}`, `type=${sanitizePipeData(memory.type)}`, `content=${sanitizePipeData(memory.content)}`, `timestamp=${sanitizePipeData(memory.timestamp)}`, ].join("\n"); return await this.appendLine("memories.aicf", data); } catch (error) { return err(toError(error)); } } /** * Write decision */ async writeDecision(decision) { try { const data = [ `@DECISION:`, `decision=${sanitizePipeData(decision.decision)}`, `rationale=${sanitizePipeData(decision.rationale)}`, `timestamp=${sanitizePipeData(decision.timestamp)}`, ].join("\n"); return await this.appendLine("decisions.aicf", data); } catch (error) { return err(toError(error)); } } } //# sourceMappingURL=aicf-writer.js.map