"use strict";
/**
 * InstinctSystem -- Continuous learning with confidence-scored behavioral patterns.
 *
 * Agents build up "instincts" -- patterns they've learned work well.
 * Unlike memory (facts), instincts are behavioral with confidence scores.
 *
 * Confidence lifecycle:
 *   New: 0.3 -> Success: +0.1 -> Auto-promote at >= 0.8 across 2+ projects
 *   Failure: -0.15 -> Decay: -0.05 per 7 days idle -> Prune at < 0.2
 *
 * @connexum/ai-governance
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.InstinctSystem = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const crypto = __importStar(require("crypto"));
class InstinctSystem {
    instinctsFile;
    logFile;
    config;
    constructor(config) {
        this.config = {
            initialConfidence: 0.3,
            successBoost: 0.1,
            failurePenalty: 0.15,
            decayAfterDays: 7,
            decayRate: 0.05,
            pruneThreshold: 0.2,
            maxAgeDays: 30,
            promotionThreshold: 0.8,
            promotionMinProjects: 2,
            maxInstincts: 100,
            ...config,
        };
        const agentDir = path.join(config.dataDir, config.agentName);
        if (!fs.existsSync(agentDir)) {
            fs.mkdirSync(agentDir, { recursive: true });
        }
        this.instinctsFile = path.join(agentDir, 'instincts.json');
        this.logFile = path.join(agentDir, 'instinct-log.jsonl');
    }
    /**
     * Learn a new instinct from experience.
     */
    learn(pattern, context, sessionId, tags = []) {
        const instincts = this.loadInstincts();
        // Check for duplicate/similar pattern
        const existing = instincts.find((i) => i.pattern.toLowerCase() === pattern.toLowerCase());
        if (existing) {
            // Reinforce existing instinct
            existing.appliedCount++;
            if (!existing.learnedFrom.includes(sessionId)) {
                existing.learnedFrom.push(sessionId);
            }
            if (!existing.projects.includes(this.config.projectName)) {
                existing.projects.push(this.config.projectName);
            }
            existing.lastApplied = new Date().toISOString();
            this.saveInstincts(instincts);
            this.log('reinforce', existing.id, pattern);
            return existing;
        }
        // Create new instinct
        const instinct = {
            id: `inst_${crypto.randomBytes(8).toString('hex')}`,
            pattern,
            context,
            confidence: this.config.initialConfidence,
            source: 'learned',
            learnedFrom: [sessionId],
            appliedCount: 0,
            successCount: 0,
            failureCount: 0,
            lastApplied: null,
            createdAt: new Date().toISOString(),
            ttlDays: this.config.maxAgeDays,
            projects: [this.config.projectName],
            tags,
        };
        instincts.push(instinct);
        // Enforce max instincts (remove lowest confidence first)
        if (instincts.length > this.config.maxInstincts) {
            instincts.sort((a, b) => a.confidence - b.confidence);
            instincts.splice(0, instincts.length - this.config.maxInstincts);
        }
        this.saveInstincts(instincts);
        this.log('learn', instinct.id, pattern);
        return instinct;
    }
    /**
     * Record successful application of an instinct.
     */
    recordSuccess(instinctId) {
        const instincts = this.loadInstincts();
        const instinct = instincts.find((i) => i.id === instinctId);
        if (!instinct)
            return null;
        instinct.appliedCount++;
        instinct.successCount++;
        instinct.confidence = Math.min(0.9, instinct.confidence + this.config.successBoost);
        instinct.lastApplied = new Date().toISOString();
        if (!instinct.projects.includes(this.config.projectName)) {
            instinct.projects.push(this.config.projectName);
        }
        this.saveInstincts(instincts);
        this.log('success', instinctId, `confidence: ${instinct.confidence.toFixed(2)}`);
        return instinct;
    }
    /**
     * Record failed application of an instinct.
     */
    recordFailure(instinctId, reason) {
        const instincts = this.loadInstincts();
        const instinct = instincts.find((i) => i.id === instinctId);
        if (!instinct)
            return null;
        instinct.appliedCount++;
        instinct.failureCount++;
        instinct.confidence = Math.max(0, instinct.confidence - this.config.failurePenalty);
        instinct.lastApplied = new Date().toISOString();
        this.saveInstincts(instincts);
        this.log('failure', instinctId, reason || `confidence: ${instinct.confidence.toFixed(2)}`);
        return instinct;
    }
    /**
     * Find instincts relevant to a given context.
     * Returns instincts sorted by confidence (highest first).
     */
    findRelevant(contextKeywords, minConfidence = 0.3) {
        const instincts = this.loadInstincts();
        const keywords = contextKeywords.map((k) => k.toLowerCase());
        return instincts
            .filter((i) => {
            if (i.confidence < minConfidence)
                return false;
            const text = `${i.pattern} ${i.context} ${i.tags.join(' ')}`.toLowerCase();
            return keywords.some((k) => text.includes(k));
        })
            .sort((a, b) => b.confidence - a.confidence);
    }
    /**
     * Apply confidence decay to stale instincts.
     * Call this periodically (e.g., on session start).
     */
    applyDecay() {
        const instincts = this.loadInstincts();
        const now = Date.now();
        let decayed = 0;
        let pruned = 0;
        const remaining = instincts.filter((instinct) => {
            const lastActive = instinct.lastApplied
                ? new Date(instinct.lastApplied).getTime()
                : new Date(instinct.createdAt).getTime();
            const daysSinceActive = (now - lastActive) / (1000 * 60 * 60 * 24);
            // Apply decay if stale
            if (daysSinceActive > this.config.decayAfterDays) {
                const decayPeriods = Math.floor((daysSinceActive - this.config.decayAfterDays) / this.config.decayAfterDays);
                const decay = decayPeriods * this.config.decayRate;
                instinct.confidence = Math.max(0, instinct.confidence - decay);
                decayed++;
            }
            // Prune if below threshold or too old
            if (instinct.confidence < this.config.pruneThreshold) {
                pruned++;
                this.log('prune', instinct.id, `confidence ${instinct.confidence.toFixed(2)} below threshold`);
                return false;
            }
            const ageDays = (now - new Date(instinct.createdAt).getTime()) / (1000 * 60 * 60 * 24);
            if (ageDays > instinct.ttlDays && instinct.confidence < this.config.promotionThreshold) {
                pruned++;
                this.log('prune', instinct.id, `expired (${Math.round(ageDays)} days old)`);
                return false;
            }
            return true;
        });
        this.saveInstincts(remaining);
        return { decayed, pruned };
    }
    /**
     * Find instincts eligible for global promotion.
     * Criteria: confidence >= threshold AND used in >= N projects.
     */
    findPromotable() {
        const instincts = this.loadInstincts();
        return instincts.filter((i) => i.confidence >= this.config.promotionThreshold &&
            i.projects.length >= this.config.promotionMinProjects &&
            i.source !== 'promoted');
    }
    /**
     * Promote an instinct to global scope.
     */
    promote(instinctId) {
        const instincts = this.loadInstincts();
        const instinct = instincts.find((i) => i.id === instinctId);
        if (!instinct)
            return null;
        instinct.source = 'promoted';
        instinct.ttlDays = 90; // Extended TTL for promoted instincts
        this.saveInstincts(instincts);
        this.log('promote', instinctId, `global promotion (confidence: ${instinct.confidence.toFixed(2)})`);
        return instinct;
    }
    /**
     * Export instincts for sharing between agents/projects.
     */
    exportInstincts(minConfidence = 0.5) {
        return this.loadInstincts().filter((i) => i.confidence >= minConfidence);
    }
    /**
     * Import instincts from another agent/project.
     */
    importInstincts(instincts) {
        const existing = this.loadInstincts();
        const existingPatterns = new Set(existing.map((i) => i.pattern.toLowerCase()));
        let imported = 0;
        let skipped = 0;
        for (const instinct of instincts) {
            if (existingPatterns.has(instinct.pattern.toLowerCase())) {
                skipped++;
                continue;
            }
            existing.push({
                ...instinct,
                id: `inst_${crypto.randomBytes(8).toString('hex')}`,
                source: 'imported',
                confidence: Math.min(instinct.confidence, 0.6), // Cap imported confidence
            });
            imported++;
        }
        this.saveInstincts(existing);
        this.log('import', 'batch', `imported ${imported}, skipped ${skipped}`);
        return { imported, skipped };
    }
    /**
     * Get comprehensive status of all instincts.
     */
    getStatus() {
        const instincts = this.loadInstincts();
        const now = Date.now();
        const byProject = {};
        const bySource = {};
        let totalConfidence = 0;
        let highConfidence = 0;
        let lowConfidence = 0;
        let stale = 0;
        for (const i of instincts) {
            totalConfidence += i.confidence;
            if (i.confidence >= 0.7)
                highConfidence++;
            if (i.confidence < 0.4)
                lowConfidence++;
            for (const p of i.projects) {
                byProject[p] = (byProject[p] || 0) + 1;
            }
            bySource[i.source] = (bySource[i.source] || 0) + 1;
            const lastActive = i.lastApplied
                ? new Date(i.lastApplied).getTime()
                : new Date(i.createdAt).getTime();
            if ((now - lastActive) / (1000 * 60 * 60 * 24) > this.config.decayAfterDays) {
                stale++;
            }
        }
        return {
            total: instincts.length,
            active: instincts.length - stale,
            highConfidence,
            lowConfidence,
            promotable: this.findPromotable().length,
            stale,
            byProject,
            bySource,
            avgConfidence: instincts.length > 0 ? totalConfidence / instincts.length : 0,
        };
    }
    /**
     * Force re-evaluation of all instincts.
     * Recalculates confidence based on success/failure ratios.
     */
    evolve() {
        const instincts = this.loadInstincts();
        let evolved = 0;
        for (const instinct of instincts) {
            if (instinct.appliedCount === 0)
                continue;
            const successRate = instinct.successCount / instinct.appliedCount;
            const newConfidence = this.config.initialConfidence +
                (successRate * (0.9 - this.config.initialConfidence));
            if (Math.abs(newConfidence - instinct.confidence) > 0.05) {
                instinct.confidence = Math.max(0, Math.min(0.9, newConfidence));
                evolved++;
            }
        }
        this.saveInstincts(instincts);
        this.log('evolve', 'all', `${evolved} instincts re-evaluated`);
        return { evolved };
    }
    /**
     * Get all instincts (read-only).
     */
    getAll() {
        return this.loadInstincts();
    }
    /**
     * Remove a specific instinct.
     */
    remove(instinctId) {
        const instincts = this.loadInstincts();
        const idx = instincts.findIndex((i) => i.id === instinctId);
        if (idx === -1)
            return false;
        instincts.splice(idx, 1);
        this.saveInstincts(instincts);
        this.log('remove', instinctId, 'manually removed');
        return true;
    }
    loadInstincts() {
        if (!fs.existsSync(this.instinctsFile))
            return [];
        try {
            return JSON.parse(fs.readFileSync(this.instinctsFile, 'utf-8'));
        }
        catch {
            return [];
        }
    }
    saveInstincts(instincts) {
        try {
            fs.writeFileSync(this.instinctsFile, JSON.stringify(instincts, null, 2));
        }
        catch (err) {
            // Instinct persistence failure means learned patterns are lost
            process.stderr.write(`[INSTINCT SYSTEM] Failed to save instincts for ${this.config.agentName}: ${err.message}\n`);
        }
    }
    log(action, instinctId, detail) {
        const entry = {
            timestamp: new Date().toISOString(),
            agent: this.config.agentName,
            project: this.config.projectName,
            action,
            instinctId,
            detail,
        };
        try {
            fs.appendFileSync(this.logFile, JSON.stringify(entry) + '\n');
        }
        catch {
            // Fire-and-forget
        }
    }
}
exports.InstinctSystem = InstinctSystem;
//# sourceMappingURL=instinct-system.js.map