/**
 * Module-level helpers for the MCP adapter (Phase 3 split).
 *
 * Extracted from mcp.ts to keep each file under 1500 LOC.
 * These are pure functions and lazy-singleton getters shared by the
 * handler files and by MCPAdapter itself.
 */
import { statSync, readdirSync } from 'fs';
import * as path from 'path';
import { GuardrailEngine } from '../../../engines/guardrails-bridge.js';
import { ContinuousAttentionStream, createKVBridge, OrchestratorEngine, } from '../../../engines/index.js';
import { FederationEngine } from '../../../engines/federation.js';
import { GraphMemoryEngine } from '../../../engines/graph-memory.js';
import { GraphTraversalEngine } from '../../../engines/graph-traversal.js';
import { HybridRetriever } from '../../../engines/hybrid-retriever.js';
import { createSubAgentRuntime } from '../../../phantom/index.js';
// ─── Lazy-init engine singletons ─────────────────────────────────────────────
let _guardrailEngine;
let _casEngine;
let _kvBridge;
let _federation;
let _graphEngine = null;
let _traversalEngine = null;
let _hybridRetriever = null;
export function getGuardrailEngine() {
    if (!_guardrailEngine)
        _guardrailEngine = new GuardrailEngine();
    return _guardrailEngine;
}
export function getCasEngine() {
    if (!_casEngine)
        _casEngine = new ContinuousAttentionStream();
    return _casEngine;
}
export function getKvBridge() {
    if (!_kvBridge)
        _kvBridge = createKVBridge({ agents: 3 });
    return _kvBridge;
}
export function getFederation() {
    if (!_federation)
        _federation = new FederationEngine();
    return _federation;
}
export function getGraphEngine() {
    if (!_graphEngine)
        _graphEngine = new GraphMemoryEngine();
    return _graphEngine;
}
export function getTraversalEngine() {
    if (!_traversalEngine)
        _traversalEngine = new GraphTraversalEngine(getGraphEngine().getDb());
    return _traversalEngine;
}
export function getHybridRetriever() {
    if (!_hybridRetriever)
        _hybridRetriever = new HybridRetriever(getGraphEngine());
    return _hybridRetriever;
}
// Fallback runtime/orchestrator maps (keyed by workspace stateKey)
const _fallbackRuntimes = new Map();
const _fallbackOrchestrators = new Map();
export function getFallbackRuntime(workspace) {
    let runtime = _fallbackRuntimes.get(workspace.stateKey);
    if (!runtime) {
        runtime = createSubAgentRuntime({
            repoRoot: workspace.repoRoot,
            artifactsRoot: path.join(workspace.stateRoot, 'runs'),
        });
        _fallbackRuntimes.set(workspace.stateKey, runtime);
    }
    return runtime;
}
export function getFallbackOrchestrator(workspace) {
    let instance = _fallbackOrchestrators.get(workspace.stateKey);
    if (!instance) {
        instance = new OrchestratorEngine({
            repoRoot: workspace.repoRoot,
            runtime: getFallbackRuntime(workspace),
        });
        _fallbackOrchestrators.set(workspace.stateKey, instance);
    }
    return instance;
}
export function formatBullets(lines) {
    return lines.filter(Boolean).map((line) => `- ${line}`).join('\n');
}
export function formatJsonDetails(label, value) {
    return `\n\n${label}\n\`\`\`json\n${JSON.stringify(value, null, 2)}\n\`\`\``;
}
export function normalizeDetailLevel(value) {
    const normalized = String(value ?? 'compact').toLowerCase();
    if (normalized === 'standard' || normalized === 'debug')
        return normalized;
    return 'compact';
}
export function normalizeBootstrapDepth(value, detailLevel) {
    const normalized = String(value ?? '').toLowerCase();
    if (normalized === 'deep')
        return 'deep';
    if (normalized === 'fast')
        return 'fast';
    return detailLevel === 'debug' ? 'deep' : 'fast';
}
export function normalizeResponseIntent(value) {
    const normalized = String(value ?? 'inspect').toLowerCase();
    if (normalized === 'plan' || normalized === 'mutate')
        return normalized;
    return 'inspect';
}
export function normalizeResponseTopology(value) {
    const normalized = String(value ?? 'auto').toLowerCase();
    if (normalized === 'manager-tools' || normalized === 'handoff' || normalized === 'dag-pool' || normalized === 'worktree-swarm') {
        return normalized;
    }
    return 'auto';
}
export function buildWorkspaceEnvelope(workspace) {
    return {
        workspaceRoot: workspace.workspaceRoot,
        repoRoot: workspace.repoRoot,
        repoName: workspace.repoName,
        remoteUrl: workspace.remoteUrl,
        workspaceSource: workspace.workspaceSource,
        stateKey: workspace.stateKey,
        notes: workspace.notes,
    };
}
export function truncateText(value, limit = 600) {
    const normalized = String(value ?? '');
    if (normalized.length <= limit)
        return normalized;
    return `${normalized.slice(0, Math.max(0, limit - 1))}…`;
}
export function buildResultPreview(result) {
    const text = result?.content?.map((chunk) => chunk.text).join('\n\n') ?? '';
    return {
        contentType: result?.content?.[0]?.type ?? 'text',
        contentCount: result?.content?.length ?? 0,
        textPreview: truncateText(text, 900),
    };
}
/**
 * Recursively collect files under `folderAbs`, optionally filtered by extension.
 * Only descends into directories within the same workspace root (caller must pre-validate root).
 * Skips hidden directories and node_modules to stay bounded.
 */
export function collectFolderFiles(folderAbs, folderGlob) {
    const extFilter = folderGlob ? folderGlob.replace(/^\*/, '') : null; // "*.ts" → ".ts"
    const results = [];
    const walk = (dir, depth) => {
        if (depth > 12)
            return; // hard depth cap
        let entries;
        try {
            entries = readdirSync(dir);
        }
        catch {
            return;
        }
        for (const entry of entries) {
            if (entry.startsWith('.') || entry === 'node_modules' || entry === 'dist')
                continue;
            const full = path.join(dir, entry);
            let st;
            try {
                st = statSync(full);
            }
            catch {
                continue;
            }
            if (st.isDirectory()) {
                walk(full, depth + 1);
            }
            else if (!extFilter || full.endsWith(extFilter)) {
                results.push(full);
            }
        }
    };
    walk(folderAbs, 0);
    return results;
}
// ─── Auto-memory helpers (server-side Commit 15) ─────────────────────────────
/**
 * Returns true for tools that are read-only or discovery-only and therefore
 * produce no meaningful state change worth storing in memory.
 */
export function isReadOnlyMcpTool(toolName) {
    const skipPrefixes = [
        'nexus_list_', 'nexus_describe_', 'nexus_runtime_health',
        'nexus_doctor', 'nexus_token_report', 'nexus_recall_memory',
        'nexus_temporal_query', 'nexus_memory_stats', 'nexus_federation_status',
        'nexus_license_usage', 'nexus_run_status', 'nexus_user_workflow_trace', 'nexus_selection_ledger',
        'nexus_operative_journal',
    ];
    return skipPrefixes.some(p => toolName.startsWith(p));
}
/**
 * Builds a compact, content-free summary of a tool call for auto-memory storage.
 * Strips large fields (content, new_string, old_string, result, command_result)
 * so the memory record stays small.
 */
export function buildAutoMemorySummary(toolName, args) {
    const skipKeys = new Set(['content', 'new_string', 'old_string', 'result', 'command_result', 'text', 'output']);
    const parts = Object.entries(args)
        .filter(([k]) => !skipKeys.has(k))
        .map(([k, v]) => `${k}=${String(v ?? '').slice(0, 80)}`)
        .join(', ')
        .slice(0, 200);
    return parts ? `${toolName}: ${parts}` : toolName;
}
