import * as fs from 'fs';
import * as path from 'path';
/**
 * Service for cross-layer memory consolidation.
 *
 * Reads all agent memories (learnings, failures, successes), identifies
 * recurring patterns, and generates a consolidation report. Can be run
 * periodically (e.g., weekly) to keep insights fresh.
 *
 * Storage: ~/.crewly/agents/{sessionName}/consolidation.json
 */
export class MemoryConsolidationService {
    memoryProvider;
    /**
     * Create a new MemoryConsolidationService.
     *
     * @param memoryProvider - Function that retrieves agent memories
     */
    constructor(memoryProvider) {
        this.memoryProvider = memoryProvider;
    }
    /**
     * Get the file path for an agent's consolidation report.
     *
     * @param sessionName - Agent session name
     * @returns Absolute path to consolidation.json
     */
    getFilePath(sessionName) {
        const homeDir = process.env.HOME || process.env.USERPROFILE || '/tmp';
        return path.join(homeDir, '.crewly', 'agents', sessionName, 'consolidation.json');
    }
    /**
     * Read the most recent consolidation report from disk.
     *
     * @param sessionName - Agent session name
     * @returns Consolidation report, or empty default if none exists
     */
    async getReport(sessionName) {
        try {
            const filePath = this.getFilePath(sessionName);
            const raw = fs.readFileSync(filePath, 'utf-8');
            return JSON.parse(raw);
        }
        catch {
            return {
                patterns: [],
                insights: [],
                consolidatedAt: '',
                memoriesAnalyzed: 0,
            };
        }
    }
    /**
     * Run consolidation analysis on all agent memories.
     *
     * Identifies recurring patterns by counting word/phrase frequency
     * across memories and extracting common themes.
     *
     * @param sessionName - Agent session name
     * @returns The generated consolidation report
     */
    async consolidate(sessionName) {
        const memories = await this.memoryProvider(sessionName);
        if (memories.length === 0) {
            const emptyReport = {
                patterns: [],
                insights: [],
                consolidatedAt: new Date().toISOString(),
                memoriesAnalyzed: 0,
            };
            await this.save(sessionName, emptyReport);
            return emptyReport;
        }
        const patterns = this.extractPatterns(memories);
        const insights = this.deriveInsights(memories, patterns);
        const report = {
            patterns,
            insights,
            consolidatedAt: new Date().toISOString(),
            memoriesAnalyzed: memories.length,
        };
        await this.save(sessionName, report);
        return report;
    }
    /**
     * Extract recurring patterns from memories by analyzing keyword frequency.
     *
     * @param memories - Array of memory text strings
     * @returns Identified patterns sorted by occurrence count
     */
    extractPatterns(memories) {
        const keyPhrases = {};
        const now = new Date().toISOString().split('T')[0];
        // Track keyword groups
        const topicKeywords = {
            'error handling': ['error', 'exception', 'catch', 'throw', 'failure'],
            'testing': ['test', 'coverage', 'jest', 'assert', 'mock'],
            'performance': ['performance', 'slow', 'optimize', 'cache', 'latency'],
            'async patterns': ['async', 'await', 'promise', 'concurrent', 'race'],
            'type safety': ['type', 'typescript', 'interface', 'generic', 'cast'],
            'code quality': ['refactor', 'clean', 'duplicate', 'pattern', 'convention'],
            'deployment': ['deploy', 'docker', 'build', 'release', 'production'],
            'security': ['security', 'auth', 'token', 'credential', 'vulnerability'],
        };
        for (const memory of memories) {
            const lower = memory.toLowerCase();
            for (const [topic, keywords] of Object.entries(topicKeywords)) {
                const hits = keywords.filter((kw) => lower.includes(kw));
                if (hits.length >= 2) {
                    if (!keyPhrases[topic]) {
                        keyPhrases[topic] = { count: 0, sources: new Set() };
                    }
                    keyPhrases[topic].count++;
                    // Categorize source by content hints
                    if (lower.includes('fail') || lower.includes('error') || lower.includes('bug')) {
                        keyPhrases[topic].sources.add('failure');
                    }
                    else if (lower.includes('complet') || lower.includes('success') || lower.includes('fixed')) {
                        keyPhrases[topic].sources.add('success');
                    }
                    else {
                        keyPhrases[topic].sources.add('learning');
                    }
                }
            }
        }
        return Object.entries(keyPhrases)
            .filter(([, v]) => v.count >= 2)
            .sort((a, b) => b[1].count - a[1].count)
            .map(([topic, v]) => ({
            pattern: topic,
            occurrences: v.count,
            sources: Array.from(v.sources),
            identifiedAt: now,
        }));
    }
    /**
     * Derive insights from memories and patterns.
     *
     * @param memories - Array of memory text strings
     * @param patterns - Previously extracted patterns
     * @returns Array of derived insights
     */
    deriveInsights(memories, patterns) {
        const insights = [];
        // Insight: if a pattern appears in both failures and successes, it's a learning area
        for (const pattern of patterns) {
            if (pattern.sources.includes('failure') && pattern.sources.includes('success')) {
                insights.push({
                    insight: `${pattern.pattern}: appears in both failures and successes — active learning area`,
                    confidence: pattern.occurrences >= 4 ? 'high' : 'medium',
                    relatedMemories: memories
                        .filter((m) => m.toLowerCase().includes(pattern.pattern.split(' ')[0]))
                        .slice(0, 3),
                });
            }
        }
        // Insight: high-frequency pattern suggests systematic behavior
        for (const pattern of patterns) {
            if (pattern.occurrences >= 4) {
                insights.push({
                    insight: `${pattern.pattern}: recurring theme across ${pattern.occurrences} memories — may indicate systematic tendency`,
                    confidence: 'high',
                    relatedMemories: [],
                });
            }
        }
        return insights;
    }
    /**
     * Persist consolidation report to disk.
     *
     * @param sessionName - Agent session name
     * @param report - Consolidation report to save
     */
    async save(sessionName, report) {
        const filePath = this.getFilePath(sessionName);
        const dir = path.dirname(filePath);
        fs.mkdirSync(dir, { recursive: true });
        fs.writeFileSync(filePath, JSON.stringify(report, null, 2), 'utf-8');
    }
}
//# sourceMappingURL=memory-consolidation.service.js.map