/**
 * Nexus Prime — Operative Journal
 *
 * Per-operative persistent memory journal.  Each Synapse operative gets its
 * own append-only log stored at ~/.nexus-prime/operative-journals/<id>.json.
 *
 * Inspired by MemPalace's specialist-agent diaries.  Entries are lightweight
 * records that capture what the operative learned or decided during a sortie,
 * complementing the shared hierarchical memory with operative-scoped history.
 */
import * as path from 'path';
import * as fs from 'fs';
import { randomUUID } from 'crypto';
import { resolveNexusStateDir } from './runtime-registry.js';
// ─────────────────────────────────────────────────────────────────────────────
// Operative Journal Manager
// ─────────────────────────────────────────────────────────────────────────────
export class OperativeJournal {
    journalsDir;
    constructor() {
        const nexusDir = resolveNexusStateDir();
        this.journalsDir = path.join(nexusDir, 'operative-journals');
        if (!fs.existsSync(this.journalsDir)) {
            fs.mkdirSync(this.journalsDir, { recursive: true });
        }
    }
    journalPath(operativeId) {
        // Sanitize: only allow alphanumeric, hyphens, underscores
        const safe = operativeId.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 64);
        return path.join(this.journalsDir, `${safe}.json`);
    }
    /** Read all entries for an operative */
    read(operativeId) {
        const filePath = this.journalPath(operativeId);
        try {
            const raw = fs.readFileSync(filePath, 'utf-8');
            return JSON.parse(raw);
        }
        catch {
            return [];
        }
    }
    /** Append a new entry to an operative's journal */
    append(operativeId, content, tags = [], sessionId) {
        const entry = {
            id: randomUUID(),
            operativeId,
            sessionId,
            timestamp: Date.now(),
            content,
            tags,
        };
        const entries = this.read(operativeId);
        entries.push(entry);
        fs.writeFileSync(this.journalPath(operativeId), JSON.stringify(entries, null, 2), 'utf-8');
        return entry;
    }
    /** List all operatives that have journal files */
    listOperatives() {
        try {
            return fs.readdirSync(this.journalsDir)
                .filter(f => f.endsWith('.json'))
                .map(f => f.replace(/\.json$/, ''));
        }
        catch {
            return [];
        }
    }
    /** Get the most recent N entries across all operatives, newest first */
    recent(limit = 20) {
        const all = [];
        for (const operative of this.listOperatives()) {
            all.push(...this.read(operative));
        }
        return all.sort((a, b) => b.timestamp - a.timestamp).slice(0, limit);
    }
}
// Singleton used by the MCP adapter
let _instance;
export function getOperativeJournal() {
    if (!_instance)
        _instance = new OperativeJournal();
    return _instance;
}
