/**
 * Subagent Persistent Memory
 *
 * Scoped memory system for subagents with user/project/local scopes,
 * topic files, and context injection support.
 */
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import { logger } from '../utils/logger.js';
// ============================================================================
// Defaults
// ============================================================================
const DEFAULT_MAX_LINES = 200;
// ============================================================================
// Subagent Memory
// ============================================================================
export class SubagentMemory {
    config;
    memoryPath;
    constructor(config) {
        this.config = {
            ...config,
            maxLines: config.maxLines || DEFAULT_MAX_LINES,
        };
        if (config.memoryDir) {
            this.memoryPath = config.memoryDir;
        }
        else {
            this.memoryPath = SubagentMemory.getMemoryDir(config.agentName, config.scope);
        }
    }
    /**
     * Get memory directory path based on scope
     */
    static getMemoryDir(agentName, scope) {
        const safeName = agentName.replace(/[^a-zA-Z0-9_-]/g, '_');
        switch (scope) {
            case 'user':
                return path.join(os.homedir(), '.codebuddy', 'agents', safeName, 'memory');
            case 'project':
                return path.join(process.cwd(), '.codebuddy', 'agents', safeName, 'memory');
            case 'local':
                return path.join(os.tmpdir(), 'codebuddy-agents', safeName, 'memory');
        }
    }
    /**
     * Ensure the memory directory exists
     */
    ensureDir() {
        if (!fs.existsSync(this.memoryPath)) {
            fs.mkdirSync(this.memoryPath, { recursive: true });
        }
    }
    /**
     * Get the MEMORY.md file path
     */
    getMemoryFilePath() {
        return path.join(this.memoryPath, 'MEMORY.md');
    }
    /**
     * Read MEMORY.md (first maxLines lines)
     */
    readMemory() {
        const filePath = this.getMemoryFilePath();
        if (!fs.existsSync(filePath)) {
            return '';
        }
        const content = fs.readFileSync(filePath, 'utf-8');
        const lines = content.split('\n');
        const limited = lines.slice(0, this.config.maxLines);
        return limited.join('\n');
    }
    /**
     * Write to MEMORY.md (replace all content)
     */
    writeMemory(content) {
        this.ensureDir();
        const filePath = this.getMemoryFilePath();
        fs.writeFileSync(filePath, content, 'utf-8');
        logger.debug(`Memory written for agent: ${this.config.agentName}`);
    }
    /**
     * Append to MEMORY.md
     */
    appendMemory(entry) {
        this.ensureDir();
        const filePath = this.getMemoryFilePath();
        const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf-8') : '';
        const separator = existing.endsWith('\n') || existing === '' ? '' : '\n';
        fs.writeFileSync(filePath, existing + separator + entry + '\n', 'utf-8');
        logger.debug(`Memory appended for agent: ${this.config.agentName}`);
    }
    /**
     * Read a specific topic file
     */
    readTopic(topicName) {
        const safeTopic = topicName.replace(/[^a-zA-Z0-9_-]/g, '_');
        const filePath = path.join(this.memoryPath, `${safeTopic}.md`);
        if (!fs.existsSync(filePath)) {
            return null;
        }
        return fs.readFileSync(filePath, 'utf-8');
    }
    /**
     * Write a topic file
     */
    writeTopic(topicName, content) {
        this.ensureDir();
        const safeTopic = topicName.replace(/[^a-zA-Z0-9_-]/g, '_');
        const filePath = path.join(this.memoryPath, `${safeTopic}.md`);
        fs.writeFileSync(filePath, content, 'utf-8');
        logger.debug(`Topic written: ${topicName} for agent: ${this.config.agentName}`);
    }
    /**
     * List all memory files
     */
    listMemoryFiles() {
        if (!fs.existsSync(this.memoryPath)) {
            return [];
        }
        return fs.readdirSync(this.memoryPath).filter(f => f.endsWith('.md'));
    }
    /**
     * Check if memory exists (MEMORY.md file)
     */
    hasMemory() {
        return fs.existsSync(this.getMemoryFilePath());
    }
    /**
     * Get memory size in bytes
     */
    getMemorySize() {
        const filePath = this.getMemoryFilePath();
        if (!fs.existsSync(filePath)) {
            return 0;
        }
        return fs.statSync(filePath).size;
    }
    /**
     * Clear all memory
     */
    clearMemory() {
        if (!fs.existsSync(this.memoryPath))
            return;
        const files = fs.readdirSync(this.memoryPath);
        for (const file of files) {
            fs.unlinkSync(path.join(this.memoryPath, file));
        }
        logger.info(`Memory cleared for agent: ${this.config.agentName}`);
    }
    /**
     * Generate context injection (first maxLines lines of MEMORY.md)
     */
    getContextInjection() {
        const content = this.readMemory();
        if (!content) {
            return '';
        }
        return `\n--- SUBAGENT MEMORY (${this.config.agentName}) ---\n${content}\n--- END SUBAGENT MEMORY ---\n`;
    }
    getAgentName() {
        return this.config.agentName;
    }
    getScope() {
        return this.config.scope;
    }
    getMemoryPath() {
        return this.memoryPath;
    }
}
//# sourceMappingURL=subagent-memory.js.map