// engine/session-safeguard/learnings-buffer.ts — SPEC-585: Append/flush learnings buffer
import { open, readFile, writeFile, mkdir, unlink } from 'node:fs/promises';
import { join } from 'node:path';
import { hashProjectPath, projectDataDir } from '../../storage/base-store.js';
const BUFFER_VERSION = 1;
const MEMORY_MD_PATH = '/Users/kevin/.claude/projects/-Users-kevin-Documents-desarrollo-sdd-mcp-server/memory/MEMORY.md';
const MAX_RETRIES = 50;
const JITTER_MS = 100;
function bufferPath(projectPath) {
    const hash = hashProjectPath(projectPath);
    return join(projectDataDir(hash), 'learnings-buffer.json');
}
function emptyBuffer() {
    return { version: BUFFER_VERSION, entries: [] };
}
/** Read the learnings buffer for a project (best-effort, returns empty on miss). */
export async function readBuffer(projectPath) {
    try {
        const raw = await readFile(bufferPath(projectPath), 'utf-8');
        return JSON.parse(raw);
    }
    catch {
        return emptyBuffer();
    }
}
/** Write the buffer to disk, creating parent dirs as needed. */
async function writeBuffer(projectPath, buffer) {
    const path = bufferPath(projectPath);
    await mkdir(join(path, '..'), { recursive: true });
    await writeFile(path, JSON.stringify(buffer, null, 2), 'utf-8');
}
/**
 * Append an entry to the learnings buffer with exclusive-lock retry.
 * Uses 'wx' flag on a lock file with jitter-backoff (3 retries, 100ms each).
 */
export async function appendToBuffer(projectPath, entry) {
    const lockFile = `${bufferPath(projectPath)}.lock`;
    await mkdir(join(lockFile, '..'), { recursive: true });
    let lastError;
    for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
        try {
            const fh = await open(lockFile, 'wx');
            try {
                const buffer = await readBuffer(projectPath);
                buffer.entries.push(entry);
                await writeBuffer(projectPath, buffer);
            }
            finally {
                try {
                    await fh.close();
                }
                catch {
                    /* best-effort */
                }
                try {
                    await unlink(lockFile);
                }
                catch {
                    /* best-effort */
                }
            }
            return;
        }
        catch (err) {
            lastError = err;
            const isExist = err instanceof Error && 'code' in err
                ? err.code === 'EEXIST'
                : false;
            if (!isExist) {
                break;
            }
            await new Promise((resolve) => setTimeout(resolve, JITTER_MS + Math.random() * JITTER_MS));
        }
    }
    throw lastError instanceof Error
        ? lastError
        : new Error('Unable to acquire learnings buffer lock');
}
/** Build the markdown bullet for an entry to append to MEMORY.md. */
function entryToMarkdown(entry) {
    const label = `[${entry.category}/${entry.source}]`;
    return `- ${label} ${entry.content} _(${entry.timestamp.slice(0, 10)})_`;
}
/**
 * Flush all entries in the learnings buffer to MEMORY.md.
 * Appends under an existing section or creates a new one.
 * Clears the buffer after successful write.
 * Returns the number of entries flushed.
 */
export async function flushBuffer(projectPath) {
    const buffer = await readBuffer(projectPath);
    if (buffer.entries.length === 0) {
        return 0;
    }
    const memoryPath = MEMORY_MD_PATH;
    let existing = '';
    try {
        existing = await readFile(memoryPath, 'utf-8');
    }
    catch {
        /* file may not exist */
    }
    const bullets = buffer.entries.map(entryToMarkdown).join('\n');
    const section = `\n\n## Session Learnings (auto-flushed ${new Date().toISOString().slice(0, 10)})\n\n${bullets}\n`;
    await writeFile(memoryPath, existing + section, 'utf-8');
    await writeBuffer(projectPath, emptyBuffer());
    return buffer.entries.length;
}
//# sourceMappingURL=learnings-buffer.js.map