/**
 * Tactics Module Registry and Dispatcher
 *
 * Provides specialized vulnerability detection for each focus area.
 * Each tactic module contains domain-specific patterns, LLM prompt
 * enhancements, and PoC generation logic.
 *
 * @module agents/adversary/tactics
 */
// ============================================================================
// Registry
// ============================================================================
const tacticRegistry = new Map();
/**
 * Register a tactic module
 */
export function registerTactic(tactic) {
    tacticRegistry.set(tactic.focusArea, tactic);
}
/**
 * Get tactic module for a focus area
 */
export function getTactic(focusArea) {
    return tacticRegistry.get(focusArea);
}
/**
 * Get all registered tactics
 */
export function getAllTactics() {
    return Array.from(tacticRegistry.values());
}
/**
 * Get tactics for specified focus areas
 */
export function getTacticsForFocusAreas(areas) {
    return areas
        .map((area) => tacticRegistry.get(area))
        .filter((t) => t !== undefined);
}
// ============================================================================
// Dispatcher
// ============================================================================
/**
 * Run tactic analysis on a file
 */
export async function runTacticAnalysis(file, tactics, config) {
    const findings = [];
    for (const tactic of tactics) {
        // Check if tactic is relevant to this file
        const patterns = tactic.getRelevantFilePatterns();
        const isRelevant = patterns.length === 0 || patterns.some((p) => {
            const regex = new RegExp(p.replace(/\*/g, ".*"));
            return regex.test(file.relativePath);
        });
        if (!isRelevant) {
            continue;
        }
        try {
            const tacticFindings = await tactic.analyzeFile(file, config);
            findings.push(...tacticFindings);
        }
        catch (error) {
            // Log but don't fail on individual tactic errors
            console.error(`Tactic ${tactic.name} failed on ${file.path}:`, error);
        }
    }
    return findings;
}
/**
 * Build combined LLM prompt enhancement from tactics
 */
export function buildCombinedPromptEnhancement(tactics) {
    const enhancements = tactics.map((t) => {
        const enhancement = t.getPromptEnhancement();
        return `## ${t.name} (${t.focusArea})\n${enhancement}`;
    });
    return enhancements.join("\n\n");
}
/**
 * Convert tactic findings to adversary findings
 */
export function tacticFindingsToAdversaryFindings(tacticFindings) {
    return tacticFindings.map((tf) => ({
        id: tf.id,
        file: tf.file,
        line: tf.line,
        column: tf.column,
        message: tf.message,
        severity: tf.severity,
        confidence: tf.confidence,
        evidence: tf.evidence,
        cweIds: tf.cweIds,
        mitreAttackTechniques: tf.mitreIds,
        focusArea: tf.focusArea,
        category: mapTacticToCategory(tf.focusArea, tf.patternId),
    }));
}
/**
 * Map tactic focus area to finding category
 */
function mapTacticToCategory(focusArea, patternId) {
    const categoryMap = {
        // Injection
        "sql-injection": "sql-injection",
        "command-injection": "command-injection",
        "xxe": "xxe",
        "ssti": "code-injection",
        "code-injection": "code-injection",
        // Auth
        "jwt-weak": "authentication",
        "session-fixation": "session-management",
        "oauth-bypass": "auth-bypass",
        "hardcoded-creds": "hardcoded-secret",
        "missing-rate-limit": "authentication",
        // API
        "idor": "broken-access-control",
        "bola": "broken-access-control",
        "graphql-complexity": "api-security",
        "mass-assignment": "api-security",
        // Web
        "xss-stored": "xss",
        "xss-reflected": "xss",
        "xss-dom": "xss",
        "csrf": "csrf",
        "clickjacking": "insecure-design",
        "open-redirect": "open-redirect",
        // LLM
        "prompt-injection-direct": "prompt-injection",
        "prompt-injection-indirect": "prompt-injection",
        "prompt-leakage": "sensitive-disclosure",
        "jailbreak": "prompt-injection",
        "plugin-abuse": "insecure-plugin",
        "excessive-agency": "excessive-agency",
        // Infra
        "privileged-container": "insecure-design",
        "container-escape": "insecure-design",
        "k8s-rbac": "broken-access-control",
        "secret-in-image": "hardcoded-secret",
    };
    return categoryMap[patternId] || focusArea;
}
// ============================================================================
// Utilities
// ============================================================================
/**
 * Detect language from file extension
 */
export function detectLanguage(filePath) {
    const ext = filePath.split(".").pop()?.toLowerCase() || "";
    const langMap = {
        ts: "typescript",
        tsx: "typescript",
        js: "javascript",
        jsx: "javascript",
        py: "python",
        go: "go",
        rs: "rust",
        java: "java",
        rb: "ruby",
        php: "php",
        cs: "csharp",
        yaml: "yaml",
        yml: "yaml",
        json: "json",
        dockerfile: "dockerfile",
    };
    return langMap[ext] || "unknown";
}
/**
 * Create file context from path and content
 */
export function createFileContext(projectPath, filePath, content) {
    const relativePath = filePath.replace(projectPath, "").replace(/^\//, "");
    return {
        path: filePath,
        relativePath,
        content,
        language: detectLanguage(filePath),
        lines: content.split("\n"),
    };
}
/**
 * Extract context around a match
 */
export function extractContext(lines, lineNum, contextLines = 2) {
    const start = Math.max(0, lineNum - contextLines);
    const end = Math.min(lines.length, lineNum + contextLines + 1);
    return lines.slice(start, end).join("\n");
}
/**
 * Generate unique finding ID
 */
export function generateFindingId(tacticName, file, line, patternId) {
    const hash = Buffer.from(`${tacticName}:${file}:${line}:${patternId}`)
        .toString("base64")
        .slice(0, 8);
    return `adv-${tacticName.slice(0, 3)}-${hash}`;
}
//# sourceMappingURL=index.js.map