"use strict";
// Nervous System — Main controller.
//
// Orchestrates the full nervous system pipeline:
// 1. Sensory inspection → signals
// 2. Signal bus → distribution
// 3. Reflex evaluation → run state modifications
// 4. Attention biases → for Mycelium router
// 5. Motor permissions → before tool calls
// 6. Pain extraction → after execution
// 7. Recovery planning → when things go wrong
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.NervousSystemController = void 0;
const signals_1 = require("./signals");
const sensory_1 = require("./sensory");
const reflexes_1 = require("./reflexes");
const attention_1 = require("./attention");
const motor_1 = require("./motor");
const pain_1 = require("./pain");
const recovery_1 = require("./recovery");
const logger_1 = require("../core/logger");
const atomicFile_1 = require("../persistence/atomicFile");
const silentFailureSink_1 = require("../observability/silentFailureSink");
const fs = __importStar(require("fs/promises"));
const path = __importStar(require("path"));
class NervousSystemController {
    bus;
    runState = null;
    allSignals = [];
    constructor() {
        this.bus = new signals_1.SignalBus(500);
        this.bus.onAny((signal) => {
            this.allSignals.push(signal);
            if (signal.severity === 'critical' || signal.severity === 'high') {
                logger_1.logger.warn('NervousSystem', `${signal.type}: ${signal.message}`, { severity: signal.severity, source: signal.source });
            }
        });
    }
    /** Phase 1: Inspect user query and create run state. */
    inspectQuery(query, taskType) {
        const runId = `run-${Date.now().toString(36)}`;
        this.runState = (0, reflexes_1.createRunState)(runId, taskType);
        this.allSignals = [];
        // Sensory inspection
        const signals = (0, sensory_1.inspectUserQuery)(query, taskType);
        this.bus.publishMany(signals);
        // Reflex evaluation
        const { triggered } = (0, reflexes_1.evaluateReflexes)(signals, this.runState);
        // Attention biases
        const attentionBiases = (0, attention_1.calculateAttentionBiases)(signals, this.runState);
        // Recovery plan if needed
        let recoveryPlan;
        if (this.runState.recoveryMode) {
            recoveryPlan = (0, recovery_1.buildRecoveryPlan)(this.runState, signals);
        }
        logger_1.logger.info('NervousSystem', 'Query inspected', {
            taskType,
            riskLevel: this.runState.riskLevel,
            reflexes: triggered.length,
            signals: signals.length,
        });
        return {
            runState: this.runState,
            signals,
            attentionBiases,
            reflexesTriggered: triggered.map((r) => r.reflexName),
            recoveryPlan,
        };
    }
    /** Phase 2: Check motor permission before a tool call. */
    checkToolPermission(toolName, toolInput) {
        if (!this.runState) {
            return { decision: 'ALLOW', reason: 'No nervous system run state.', actionType: toolName, target: '' };
        }
        return (0, motor_1.checkMotorPermission)(toolName, '', this.runState, toolInput);
    }
    /** Phase 3: Inspect a tool result during execution. */
    onToolResult(toolName, success, output) {
        if (!this.runState)
            return [];
        // Track tool errors
        if (!success) {
            const count = (this.runState.toolErrors.get(toolName) ?? 0) + 1;
            this.runState.toolErrors.set(toolName, count);
        }
        const signals = (0, sensory_1.inspectToolResult)(toolName, success, output, this.runState.toolErrors.get(toolName) ?? 0);
        this.bus.publishMany(signals);
        // Re-evaluate reflexes with new signals
        if (signals.some((s) => s.severity === 'high' || s.severity === 'critical')) {
            (0, reflexes_1.evaluateReflexes)(signals, this.runState);
        }
        return signals;
    }
    /** Phase 4: Inspect loop behavior during execution. */
    onToolCallSequence(toolCallSequence) {
        const signals = (0, sensory_1.inspectLoopBehavior)(toolCallSequence);
        this.bus.publishMany(signals);
        if (this.runState && signals.length > 0) {
            (0, reflexes_1.evaluateReflexes)(signals, this.runState);
        }
        return signals;
    }
    /** Phase 5: Inspect context pressure. */
    onContextPressure(tokenCount, maxTokens) {
        const signals = (0, sensory_1.inspectContextPressure)(tokenCount, maxTokens);
        this.bus.publishMany(signals);
        if (this.runState && signals.length > 0) {
            (0, reflexes_1.evaluateReflexes)(signals, this.runState);
        }
        return signals;
    }
    /** Phase 6: Inspect verifier result after execution. */
    onVerifierResult(status, score, notes) {
        const signals = (0, sensory_1.inspectVerifierResult)(status, score, notes);
        this.bus.publishMany(signals);
        // Re-evaluate reflexes (may trigger recovery mode on verifier failure)
        if (this.runState && signals.some((s) => s.severity === 'high' || s.severity === 'critical' || s.type === 'RECOVERY_REQUIRED')) {
            (0, reflexes_1.evaluateReflexes)(signals, this.runState);
        }
        // Extract pain
        const routeNodeIds = this.runState?.requiredNodes ?? [];
        const painSignals = (0, pain_1.extractPainSignals)([...this.allSignals, ...signals], routeNodeIds);
        const painMultiplier = (0, pain_1.aggregatePainMultiplier)(painSignals);
        // Check for safety reward signals
        const safetyRewards = this.allSignals.filter(pain_1.isSafetyRewardSignal);
        if (safetyRewards.length > 0) {
            logger_1.logger.info('NervousSystem', 'Safety signals correctly fired', { count: safetyRewards.length });
        }
        return { signals, painSignals, painMultiplier };
    }
    /** Get recovery plan if in recovery mode. */
    getRecoveryPlan() {
        if (!this.runState?.recoveryMode)
            return undefined;
        return (0, recovery_1.buildRecoveryPlan)(this.runState, this.allSignals);
    }
    /** Format recovery plan as text. */
    getRecoveryText() {
        const plan = this.getRecoveryPlan();
        return plan ? (0, recovery_1.formatRecoveryPlan)(plan) : '';
    }
    /** Get current run state. */
    getRunState() {
        return this.runState;
    }
    /** Get all signals from current run. */
    getSignals() {
        return [...this.allSignals];
    }
    /** Get signal bus for external subscribers. */
    getBus() {
        return this.bus;
    }
    /** Get a summary for route explanations. */
    getSummary() {
        if (!this.runState)
            return {};
        return {
            taskType: this.runState.taskType,
            riskLevel: this.runState.riskLevel,
            explorationRate: this.runState.explorationRate,
            dryRunRequired: this.runState.dryRunRequired,
            confirmationRequired: this.runState.confirmationRequired,
            verifierRequired: this.runState.verifierRequired,
            recoveryMode: this.runState.recoveryMode,
            activeReflexes: this.runState.activeReflexes,
            safetyNotes: this.runState.safetyNotes,
            signalCount: this.allSignals.length,
            painSignals: this.allSignals.filter((s) => s.severity === 'high' || s.severity === 'critical').length,
        };
    }
    /** Persist signals to disk for historical analysis. Returns false on failure. */
    async persistSignals(projectDir) {
        if (this.allSignals.length === 0)
            return true;
        const dir = path.join(projectDir, '.harness', 'nervous');
        const filePath = path.join(dir, 'signals.jsonl');
        try {
            await fs.mkdir(dir, { recursive: true });
            const lines = this.allSignals.map((s) => JSON.stringify({
                id: s.id,
                type: s.type,
                severity: s.severity,
                source: s.source,
                message: s.message,
                runId: this.runState?.runId,
                taskType: this.runState?.taskType,
                createdAt: s.createdAt,
            })).join('\n') + '\n';
            await (0, atomicFile_1.withFileLock)(filePath, () => fs.appendFile(filePath, lines, 'utf-8'));
            return true;
        }
        catch (error) {
            (0, silentFailureSink_1.recordSwallowed)('NervousSystemController.persistSignals', error);
            return false;
        }
    }
    /** Read recent persisted signals. */
    static async readPersistedSignals(projectDir, limit = 50) {
        try {
            const raw = await fs.readFile(path.join(projectDir, '.harness', 'nervous', 'signals.jsonl'), 'utf-8');
            return raw.trim().split(/\r?\n/)
                .filter(Boolean)
                .map((line) => { try {
                return JSON.parse(line);
            }
            catch {
                return null;
            } })
                .filter((e) => e !== null)
                .slice(-limit)
                .reverse();
        }
        catch {
            return [];
        }
    }
    /** Reset for next run. */
    reset() {
        this.runState = null;
        this.allSignals = [];
    }
}
exports.NervousSystemController = NervousSystemController;
//# sourceMappingURL=controller.js.map