/**
 * Adversary Agent - Main Orchestrator
 *
 * The Adversary agent is a mythos-class ethical hacker that uses real
 * Claude API reasoning to find vulnerabilities that pattern-based scanners
 * miss. It coordinates four analysis phases:
 *
 * 1. Reconnaissance - Technology stack detection, framework identification
 * 2. Attack Surface - Entry points, trust boundaries, data flows
 * 3. Exploitation - LLM-powered vulnerability discovery with PoCs
 * 4. Chaining - Multi-vulnerability attack path discovery
 *
 * @module agents/adversary
 */
import { randomUUID } from "crypto";
import { glob } from "glob";
import { readFile, stat } from "fs/promises";
import * as path from "path";
import Anthropic from "@anthropic-ai/sdk";
import { DEFAULT_INCLUDE_PATTERNS, DEFAULT_EXCLUDE_PATTERNS, SECURITY_RELEVANT_PATTERNS, MODEL_PRICING, } from "./config.js";
// Import tactics modules
import { getTacticsForFocusAreas, runTacticAnalysis, buildCombinedPromptEnhancement, createFileContext, } from "./tactics/index.js";
// Import tactics (auto-registers on import)
import "./tactics/injection.js";
import "./tactics/auth.js";
import "./tactics/llm.js";
import "./tactics/api.js";
import "./tactics/web-app.js";
import "./tactics/infra.js";
// Import reporting modules
import { generatePoC } from "./reporting/poc-generator.js";
import { mapFindingToCompliance } from "./reporting/compliance-mapper.js";
// Re-export types and config
export * from "./types.js";
export * from "./config.js";
// Re-export reporting
export * from "./reporting/index.js";
// ============================================================================
// Claude API Integration
// ============================================================================
let anthropicClient = null;
/**
 * Initialize Anthropic client
 */
function getAnthropicClient() {
    if (!anthropicClient) {
        const apiKey = process.env.ANTHROPIC_API_KEY;
        if (!apiKey) {
            throw new Error("ANTHROPIC_API_KEY environment variable is required for adversary analysis. " +
                "Set it to your Claude API key to enable LLM-powered vulnerability discovery.");
        }
        anthropicClient = new Anthropic({ apiKey });
    }
    return anthropicClient;
}
/**
 * Send prompt to Claude and get response
 */
async function analyzeWithClaude(prompt, model) {
    const client = getAnthropicClient();
    const response = await client.messages.create({
        model: model,
        max_tokens: 8192,
        system: prompt.systemPrompt,
        messages: [
            {
                role: "user",
                content: `${prompt.instructions}\n\n## Code Context\n\`\`\`\n${prompt.codeContext}\n\`\`\`\n\n${prompt.outputFormat}`,
            },
        ],
    });
    const content = response.content[0];
    if (content.type !== "text") {
        throw new Error("Unexpected response type from Claude");
    }
    return {
        content: content.text,
        tokensUsed: {
            input: response.usage.input_tokens,
            output: response.usage.output_tokens,
        },
        model: response.model,
        stopReason: response.stop_reason,
    };
}
// ============================================================================
// File Discovery
// ============================================================================
/**
 * Discover files for analysis
 */
async function discoverFiles(projectPath, config) {
    const includePatterns = config.includePatterns || DEFAULT_INCLUDE_PATTERNS;
    const excludePatterns = config.excludePatterns || DEFAULT_EXCLUDE_PATTERNS;
    const allFiles = [];
    for (const pattern of includePatterns) {
        const matches = await glob(pattern, {
            cwd: projectPath,
            ignore: excludePatterns,
            nodir: true,
            absolute: true,
        });
        allFiles.push(...matches);
    }
    // Deduplicate
    const uniqueFiles = [...new Set(allFiles)];
    // Prioritize security-relevant files
    const prioritized = uniqueFiles.sort((a, b) => {
        const aSecurityRelevant = SECURITY_RELEVANT_PATTERNS.some((p) => a.includes(p.replace("**/*", "").replace("*", "")));
        const bSecurityRelevant = SECURITY_RELEVANT_PATTERNS.some((p) => b.includes(p.replace("**/*", "").replace("*", "")));
        if (aSecurityRelevant && !bSecurityRelevant)
            return -1;
        if (!aSecurityRelevant && bSecurityRelevant)
            return 1;
        return 0;
    });
    // Limit to max files
    const maxFiles = config.maxFiles || 100;
    return prioritized.slice(0, maxFiles);
}
/**
 * Read file content safely
 */
async function readFileContent(filePath) {
    try {
        const content = await readFile(filePath, "utf-8");
        // Truncate very large files
        if (content.length > 50000) {
            return content.slice(0, 50000) + "\n\n... [truncated]";
        }
        return content;
    }
    catch {
        return "";
    }
}
// ============================================================================
// Phase 1: Reconnaissance
// ============================================================================
/**
 * Detect technology stack from code
 */
function detectTechStack(files, contents) {
    const stack = {
        language: "unknown",
    };
    // Language detection by file extensions
    const extCounts = {};
    for (const file of files) {
        const ext = path.extname(file).toLowerCase();
        extCounts[ext] = (extCounts[ext] || 0) + 1;
    }
    const topExt = Object.entries(extCounts).sort((a, b) => b[1] - a[1])[0];
    if (topExt) {
        const langMap = {
            ".ts": "TypeScript",
            ".tsx": "TypeScript",
            ".js": "JavaScript",
            ".jsx": "JavaScript",
            ".py": "Python",
            ".go": "Go",
            ".rs": "Rust",
            ".java": "Java",
            ".rb": "Ruby",
            ".php": "PHP",
        };
        stack.language = langMap[topExt[0]] || "unknown";
    }
    // Framework detection from content
    const allContent = [...contents.values()].join("\n");
    // Node.js/JavaScript frameworks
    if (allContent.includes("from 'next'") || allContent.includes("'next/")) {
        stack.framework = "Next.js";
        stack.runtime = "Node.js";
    }
    else if (allContent.includes("from 'express'") || allContent.includes("require('express')")) {
        stack.framework = "Express";
        stack.runtime = "Node.js";
    }
    else if (allContent.includes("from '@hono/")) {
        stack.framework = "Hono";
        stack.runtime = "Node.js/Bun";
    }
    else if (allContent.includes("from 'fastify'")) {
        stack.framework = "Fastify";
        stack.runtime = "Node.js";
    }
    // Python frameworks
    if (allContent.includes("from fastapi") || allContent.includes("import fastapi")) {
        stack.framework = "FastAPI";
        stack.runtime = "Python";
    }
    else if (allContent.includes("from flask") || allContent.includes("import flask")) {
        stack.framework = "Flask";
        stack.runtime = "Python";
    }
    else if (allContent.includes("from django") || allContent.includes("import django")) {
        stack.framework = "Django";
        stack.runtime = "Python";
    }
    // Database detection
    const databases = [];
    if (allContent.includes("postgres") || allContent.includes("pg.Pool") || allContent.includes("psycopg")) {
        databases.push("PostgreSQL");
    }
    if (allContent.includes("mongodb") || allContent.includes("mongoose")) {
        databases.push("MongoDB");
    }
    if (allContent.includes("redis") || allContent.includes("ioredis")) {
        databases.push("Redis");
    }
    if (allContent.includes("mysql")) {
        databases.push("MySQL");
    }
    if (databases.length > 0) {
        stack.database = databases;
    }
    // Auth detection
    const auth = [];
    if (allContent.includes("jwt") || allContent.includes("jsonwebtoken")) {
        auth.push("JWT");
    }
    if (allContent.includes("oauth") || allContent.includes("OAuth")) {
        auth.push("OAuth");
    }
    if (allContent.includes("session") || allContent.includes("express-session")) {
        auth.push("session-based");
    }
    if (allContent.includes("@clerk/") || allContent.includes("clerk")) {
        auth.push("Clerk");
    }
    if (auth.length > 0) {
        stack.auth = auth;
    }
    // API types
    const apis = [];
    if (allContent.includes("graphql") || allContent.includes("GraphQL")) {
        apis.push("graphql");
    }
    if (allContent.includes("grpc") || allContent.includes("proto")) {
        apis.push("grpc");
    }
    if (allContent.includes("WebSocket") || allContent.includes("ws://") || allContent.includes("socket.io")) {
        apis.push("websocket");
    }
    // REST is assumed as default
    apis.push("rest");
    stack.apis = apis;
    // Cloud detection
    if (allContent.includes("vercel") || allContent.includes("@vercel/")) {
        stack.cloud = "Vercel";
    }
    else if (allContent.includes("aws-sdk") || allContent.includes("@aws-sdk/")) {
        stack.cloud = "AWS";
    }
    else if (allContent.includes("@google-cloud/")) {
        stack.cloud = "GCP";
    }
    else if (allContent.includes("@azure/")) {
        stack.cloud = "Azure";
    }
    return stack;
}
/**
 * Run reconnaissance phase
 */
async function runReconnaissance(projectPath, files, config) {
    const startTime = Date.now();
    // Read file contents
    const contents = new Map();
    for (const file of files.slice(0, 50)) { // Limit for recon
        const content = await readFileContent(file);
        if (content) {
            contents.set(file, content);
        }
    }
    // Detect tech stack
    const techStack = detectTechStack(files, contents);
    // Find entry points (basic pattern matching)
    const entryPoints = [];
    for (const [file, content] of contents) {
        // Express-style routes
        const routePatterns = [
            /app\.(get|post|put|delete|patch)\s*\(\s*['"]([^'"]+)['"]/g,
            /router\.(get|post|put|delete|patch)\s*\(\s*['"]([^'"]+)['"]/g,
        ];
        for (const pattern of routePatterns) {
            let match;
            while ((match = pattern.exec(content)) !== null) {
                const lineNumber = content.slice(0, match.index).split("\n").length;
                entryPoints.push({
                    type: "route",
                    path: match[2],
                    methods: [match[1].toUpperCase()],
                    file: file,
                    line: lineNumber,
                    authRequired: false, // Would need deeper analysis
                    inputs: [],
                    riskScore: 50,
                });
            }
        }
        // Next.js API routes
        if (file.includes("/api/") && (file.endsWith(".ts") || file.endsWith(".js"))) {
            const methodMatch = content.match(/export\s+(async\s+)?function\s+(GET|POST|PUT|DELETE|PATCH)/g);
            if (methodMatch) {
                const methods = methodMatch.map((m) => m.replace(/export\s+(async\s+)?function\s+/, ""));
                const relativePath = file.replace(projectPath, "").replace(/\.(ts|js)$/, "");
                entryPoints.push({
                    type: "endpoint",
                    path: relativePath.replace("/src/app", "").replace("/pages", ""),
                    methods,
                    file,
                    line: 1,
                    authRequired: false,
                    inputs: [],
                    riskScore: 50,
                });
            }
        }
    }
    return {
        techStack,
        filesAnalyzed: [...contents.keys()],
        entryPoints,
        trustBoundaries: [], // Would need deeper analysis
        thirdParty: [], // Would need dependency analysis
        duration: Date.now() - startTime,
    };
}
// ============================================================================
// Phase 2: Attack Surface
// ============================================================================
/**
 * Run attack surface analysis phase
 */
async function runAttackSurfaceAnalysis(projectPath, files, recon, config) {
    const startTime = Date.now();
    // For now, use the entry points from recon
    // In full implementation, this would use Claude to analyze data flows
    // Identify high-risk areas
    const highRiskAreas = [];
    // Check for auth-related files
    const authFiles = files.filter((f) => f.includes("auth") || f.includes("login") || f.includes("session"));
    if (authFiles.length > 0) {
        highRiskAreas.push({
            area: "Authentication",
            reason: "Authentication logic is a prime target for bypass attacks",
            files: authFiles,
        });
    }
    // Check for database-related files
    const dbFiles = files.filter((f) => f.includes("db") || f.includes("database") || f.includes("query") || f.includes("sql"));
    if (dbFiles.length > 0) {
        highRiskAreas.push({
            area: "Database Access",
            reason: "Database queries may be vulnerable to injection attacks",
            files: dbFiles,
        });
    }
    // Check for file handling
    const fileHandlingFiles = files.filter((f) => f.includes("upload") || f.includes("download") || f.includes("file"));
    if (fileHandlingFiles.length > 0) {
        highRiskAreas.push({
            area: "File Handling",
            reason: "File operations may lead to path traversal or arbitrary file access",
            files: fileHandlingFiles,
        });
    }
    return {
        entryPoints: recon.entryPoints,
        highRiskAreas,
        dataFlows: [], // Would need Claude analysis
        permissionBoundaries: [], // Would need deeper analysis
        duration: Date.now() - startTime,
    };
}
// ============================================================================
// Phase 3: Exploitation
// ============================================================================
/**
 * Build system prompt for adversarial analysis
 */
function buildAdversarySystemPrompt(config) {
    return `You are an expert ethical hacker and security researcher performing authorized vulnerability assessment.

## Your Mission
Analyze code with an attacker's mindset. Your goal is to find vulnerabilities that pattern-based scanners miss - logic flaws, subtle injection vectors, authentication bypasses, and novel attack paths.

## Analysis Approach
1. **Think like an attacker**: Ask "How would I exploit this?"
2. **Consider context**: Understand the application flow and trust boundaries
3. **Look for subtle issues**: Not just obvious bugs, but design flaws and edge cases
4. **Chain vulnerabilities**: Consider how multiple issues could be combined

## Focus Areas
${config.focusAreas.map((area) => `- ${area}: ${getAreaDescription(area)}`).join("\n")}

## Output Requirements
- Be specific with file paths and line numbers
- Provide clear attack scenarios that demonstrate exploitability
- Assign realistic severity and confidence scores
- Suggest concrete remediations

## Aggressiveness Level: ${config.aggressiveness}
${config.aggressiveness === "passive" ? "Focus on finding issues, do not generate exploits." :
        config.aggressiveness === "active" ? "Generate proof-of-concept exploits where possible." :
            "Deep analysis - generate full exploits and attack chains."}

Remember: This is authorized security testing. Be thorough and think creatively.`;
}
/**
 * Get description for focus area
 */
function getAreaDescription(area) {
    const descriptions = {
        "web-app": "XSS, CSRF, clickjacking, CORS misconfigurations",
        "api": "GraphQL/REST abuse, rate limiting bypasses, BOLA/IDOR",
        "auth": "Authentication bypass, session fixation, OAuth flaws",
        "injection": "SQL, NoSQL, XXE, SSTI, command injection",
        "llm": "Prompt injection, jailbreaks, data extraction",
        "infra": "Container escapes, privilege escalation, cloud misconfig",
        "crypto": "Weak algorithms, key management, timing attacks",
        "data-flow": "Data exposure, exfiltration paths, logging issues",
        "supply-chain": "Dependency vulnerabilities, build pipeline attacks",
    };
    return descriptions[area] || "General security issues";
}
/**
 * Parse findings from Claude response
 */
function parseFindingsFromResponse(response, file, config) {
    const findings = [];
    try {
        // Try to parse JSON if response is structured
        const jsonMatch = response.match(/\[[\s\S]*\]/);
        if (jsonMatch) {
            const parsed = JSON.parse(jsonMatch[0]);
            if (Array.isArray(parsed)) {
                for (const item of parsed) {
                    if (item.title && item.severity) {
                        findings.push({
                            id: `adv-${randomUUID().slice(0, 8)}`,
                            title: item.title,
                            description: item.description || item.title,
                            severity: item.severity,
                            confidence: item.confidence || 70,
                            category: item.category || "code-quality",
                            focusArea: item.focusArea || config.focusAreas[0] || "web-app",
                            file: item.file || file,
                            line: item.line || 1,
                            codeSnippet: item.codeSnippet || "",
                            attackScenario: item.attackScenario || "",
                            exploitability: item.exploitability || "moderate",
                            chainPotential: item.chainPotential || [],
                            mitreAttackTechniques: item.mitreAttackTechniques || [],
                            cweIds: item.cweIds || [],
                            recommendation: item.recommendation || "Review and fix the identified issue",
                            aiReasoning: item.aiReasoning || "",
                            modelUsed: config.model,
                        });
                    }
                }
            }
        }
    }
    catch {
        // If JSON parsing fails, try to extract findings from text
        // This is a fallback for unstructured responses
    }
    return findings;
}
/**
 * Run exploitation phase with Claude analysis
 */
async function runExploitation(projectPath, files, recon, attackSurface, config) {
    const startTime = Date.now();
    const findings = [];
    let totalTokens = 0;
    // Get tactics for configured focus areas
    const tactics = getTacticsForFocusAreas(config.focusAreas);
    const tacticPromptEnhancement = buildCombinedPromptEnhancement(tactics);
    // Prioritize high-risk files
    const prioritizedFiles = [
        ...attackSurface.highRiskAreas.flatMap((area) => area.files),
        ...files.filter((f) => !attackSurface.highRiskAreas.some((area) => area.files.includes(f))),
    ].slice(0, config.maxFiles || 50);
    // Analyze each file with Claude
    for (const file of prioritizedFiles) {
        const content = await readFileContent(file);
        if (!content || content.length < 100)
            continue;
        // Run tactic-based pattern detection first
        const fileContext = createFileContext(projectPath, file, content);
        let tacticFindings = [];
        try {
            tacticFindings = await runTacticAnalysis(fileContext, tactics, config);
        }
        catch {
            // Continue even if tactic analysis fails
        }
        // Convert tactic findings to adversary findings and add to results
        for (const tf of tacticFindings) {
            const adversaryFinding = {
                id: tf.id,
                title: tf.message.split(":")[0] || tf.message,
                description: tf.message,
                severity: tf.severity,
                confidence: tf.confidence,
                category: tf.patternId,
                focusArea: tf.focusArea,
                file: tf.file,
                line: tf.line,
                codeSnippet: tf.evidence,
                attackScenario: "",
                exploitability: tf.severity === "critical" ? "easy" : tf.severity === "high" ? "moderate" : "hard",
                chainPotential: [],
                mitreAttackTechniques: tf.mitreIds,
                cweIds: tf.cweIds,
                recommendation: tf.suggestedFix || "Review and fix the identified issue",
                aiReasoning: "Pattern-based detection",
                modelUsed: "deterministic",
            };
            findings.push(adversaryFinding);
        }
        // Build enhanced prompt with tactic findings context
        const tacticContext = tacticFindings.length > 0
            ? `\n\n## Pre-identified Issues (validate and expand)\n${tacticFindings.map((tf) => `- Line ${tf.line}: ${tf.message}`).join("\n")}`
            : "";
        try {
            const prompt = {
                systemPrompt: buildAdversarySystemPrompt(config) + "\n\n" + tacticPromptEnhancement,
                codeContext: content,
                instructions: `Analyze this file for security vulnerabilities. Focus on ${config.focusAreas.join(", ")}.

File: ${path.relative(projectPath, file)}
Technology Stack: ${JSON.stringify(recon.techStack)}
${tacticContext}

Look for:
- Input validation issues
- Authentication/authorization flaws
- Injection vulnerabilities
- Logic errors
- Cryptographic weaknesses
- Race conditions
- Information disclosure`,
                outputFormat: `Return findings as a JSON array:
[{
  "title": "Vulnerability Title",
  "description": "Detailed description",
  "severity": "critical|high|medium|low",
  "confidence": 0-100,
  "category": "category-name",
  "focusArea": "focus-area",
  "line": line_number,
  "codeSnippet": "relevant code",
  "attackScenario": "Step-by-step attack",
  "exploitability": "trivial|easy|moderate|hard|expert",
  "cweIds": ["CWE-XX"],
  "recommendation": "How to fix"
}]

If no vulnerabilities found, return empty array [].`,
            };
            const response = await analyzeWithClaude(prompt, config.model);
            totalTokens += response.tokensUsed.input + response.tokensUsed.output;
            const fileFindings = parseFindingsFromResponse(response.content, file, config);
            findings.push(...fileFindings);
            // Check time limit
            if (Date.now() - startTime > config.maxAnalysisTime) {
                break;
            }
        }
        catch (error) {
            // Log error but continue with other files
            console.error(`Error analyzing ${file}:`, error);
        }
    }
    // Generate PoCs if enabled
    if (config.generatePoC) {
        const pocConfig = {
            includePayloads: true,
            safeMode: true,
            maxSteps: 6,
            includeRemediation: true,
        };
        for (const finding of findings) {
            if (finding.severity === "critical" || finding.severity === "high") {
                try {
                    const poc = await generatePoC(finding, pocConfig);
                    if (poc) {
                        finding.proofOfConcept = poc;
                    }
                }
                catch {
                    // Continue if PoC generation fails
                }
            }
        }
    }
    // Add compliance mapping to all findings
    for (const finding of findings) {
        const mapping = mapFindingToCompliance(finding, finding.focusArea);
        finding.complianceMapping = mapping.frameworks;
    }
    return {
        findings,
        filesAnalyzed: prioritizedFiles.length,
        tokensUsed: totalTokens,
        duration: Date.now() - startTime,
    };
}
// ============================================================================
// Phase 4: Chaining
// ============================================================================
/**
 * Analyze findings for exploit chains
 */
async function runChainingAnalysis(findings, config) {
    const startTime = Date.now();
    const chains = [];
    const chainedFindingIds = new Set();
    // Simple chaining logic - look for related findings
    // In full implementation, this would use Claude for deeper analysis
    // Group findings by category
    const byCategory = new Map();
    for (const finding of findings) {
        const category = finding.category;
        if (!byCategory.has(category)) {
            byCategory.set(category, []);
        }
        byCategory.get(category).push(finding);
    }
    // Look for common chains
    // XSS + Session = Session Hijacking
    const xssFindings = findings.filter((f) => f.category === "xss");
    const sessionFindings = findings.filter((f) => f.category === "session-management" || f.category === "authentication");
    if (xssFindings.length > 0 && sessionFindings.length > 0) {
        const chain = {
            id: `chain-${randomUUID().slice(0, 8)}`,
            name: "XSS to Session Hijacking",
            description: "Cross-site scripting can be chained with session vulnerabilities to hijack user sessions",
            findingIds: [...xssFindings.map((f) => f.id), ...sessionFindings.map((f) => f.id)],
            combinedSeverity: "critical",
            impact: "Full account takeover through stolen session credentials",
            mitreChain: ["T1189", "T1539"],
            likelihood: "high",
        };
        chains.push(chain);
        xssFindings.forEach((f) => chainedFindingIds.add(f.id));
        sessionFindings.forEach((f) => chainedFindingIds.add(f.id));
    }
    // SQL Injection + Auth Bypass = Full DB Access
    const sqlFindings = findings.filter((f) => f.category === "sql-injection");
    const authFindings = findings.filter((f) => f.category === "auth-bypass");
    if (sqlFindings.length > 0 && authFindings.length > 0) {
        const chain = {
            id: `chain-${randomUUID().slice(0, 8)}`,
            name: "SQL Injection to Database Compromise",
            description: "SQL injection combined with authentication bypass enables complete database access",
            findingIds: [...sqlFindings.map((f) => f.id), ...authFindings.map((f) => f.id)],
            combinedSeverity: "critical",
            impact: "Complete database compromise including sensitive data exfiltration",
            mitreChain: ["T1190", "T1078", "T1005"],
            likelihood: "high",
        };
        chains.push(chain);
        sqlFindings.forEach((f) => chainedFindingIds.add(f.id));
        authFindings.forEach((f) => chainedFindingIds.add(f.id));
    }
    // SSRF + Internal API = Internal Service Access
    const ssrfFindings = findings.filter((f) => f.category === "ssrf");
    const apiFindings = findings.filter((f) => f.category === "api-security");
    if (ssrfFindings.length > 0 && apiFindings.length > 0) {
        const chain = {
            id: `chain-${randomUUID().slice(0, 8)}`,
            name: "SSRF to Internal Service Compromise",
            description: "Server-side request forgery can access internal APIs and services",
            findingIds: [...ssrfFindings.map((f) => f.id), ...apiFindings.map((f) => f.id)],
            combinedSeverity: "critical",
            impact: "Access to internal services, potential cloud metadata exposure",
            mitreChain: ["T1190", "T1552"],
            likelihood: "medium",
        };
        chains.push(chain);
        ssrfFindings.forEach((f) => chainedFindingIds.add(f.id));
        apiFindings.forEach((f) => chainedFindingIds.add(f.id));
    }
    // Isolated findings (not part of any chain)
    const isolatedFindings = findings
        .filter((f) => !chainedFindingIds.has(f.id))
        .map((f) => f.id);
    return {
        chains,
        isolatedFindings,
        duration: Date.now() - startTime,
    };
}
// ============================================================================
// Main Entry Point
// ============================================================================
/**
 * Run full adversary analysis
 */
export async function runAdversaryAnalysis(projectPath, config) {
    const analysisId = `adv-${randomUUID().slice(0, 12)}`;
    const startTime = Date.now();
    try {
        // Validate project path
        const stats = await stat(projectPath);
        if (!stats.isDirectory()) {
            throw new Error(`Project path is not a directory: ${projectPath}`);
        }
        // Discover files
        const files = await discoverFiles(projectPath, config);
        if (files.length === 0) {
            return {
                success: false,
                analysisId,
                projectPath,
                config,
                findings: [],
                chains: [],
                totalTokensUsed: 0,
                totalDuration: Date.now() - startTime,
                error: "No analyzable files found in project",
                recommendations: [],
            };
        }
        // Phase 1: Reconnaissance
        const recon = await runReconnaissance(projectPath, files, config);
        // Phase 2: Attack Surface
        const attackSurface = await runAttackSurfaceAnalysis(projectPath, files, recon, config);
        // Phase 3: Exploitation
        const exploitation = await runExploitation(projectPath, files, recon, attackSurface, config);
        // Phase 4: Chaining (if enabled)
        let chaining;
        if (config.enableChaining && exploitation.findings.length > 1) {
            chaining = await runChainingAnalysis(exploitation.findings, config);
        }
        // Generate recommendations
        const recommendations = [];
        const criticalCount = exploitation.findings.filter((f) => f.severity === "critical").length;
        const highCount = exploitation.findings.filter((f) => f.severity === "high").length;
        if (criticalCount > 0) {
            recommendations.push(`CRITICAL: ${criticalCount} critical vulnerabilities require immediate remediation.`);
        }
        if (highCount > 0) {
            recommendations.push(`HIGH: ${highCount} high-severity issues should be fixed before deployment.`);
        }
        if (chaining && chaining.chains.length > 0) {
            recommendations.push(`WARNING: ${chaining.chains.length} exploit chains discovered that could amplify impact.`);
        }
        // Focus area specific recommendations
        for (const area of config.focusAreas) {
            const areaFindings = exploitation.findings.filter((f) => f.focusArea === area);
            if (areaFindings.length > 0) {
                recommendations.push(`${area.toUpperCase()}: ${areaFindings.length} issues found. Review ${getAreaDescription(area)}.`);
            }
        }
        return {
            success: true,
            analysisId,
            projectPath,
            config,
            recon,
            attackSurface,
            exploitation,
            chaining,
            findings: exploitation.findings,
            chains: chaining?.chains || [],
            totalTokensUsed: exploitation.tokensUsed,
            totalDuration: Date.now() - startTime,
            recommendations,
        };
    }
    catch (error) {
        return {
            success: false,
            analysisId,
            projectPath,
            config,
            findings: [],
            chains: [],
            totalTokensUsed: 0,
            totalDuration: Date.now() - startTime,
            error: error instanceof Error ? error.message : String(error),
            recommendations: [],
        };
    }
}
/**
 * Convert adversary findings to certification findings
 */
export function adversaryToFindings(result) {
    return result.findings.map((f) => ({
        id: f.id,
        severity: f.severity,
        category: f.category,
        description: `${f.title}: ${f.description}`,
        evidence: `File: ${f.file}:${f.line}\nCode: ${f.codeSnippet.slice(0, 200)}\nAttack: ${f.attackScenario}`,
        confidence: f.confidence,
        verifications: [],
        created_at: new Date().toISOString(),
        scanner_source: "adversary",
        metadata: {
            focusArea: f.focusArea,
            exploitability: f.exploitability,
            cweIds: f.cweIds,
            mitreAttackTechniques: f.mitreAttackTechniques,
            recommendation: f.recommendation,
            aiReasoning: f.aiReasoning,
            modelUsed: f.modelUsed,
            hasPoC: !!f.proofOfConcept,
        },
    }));
}
/**
 * Estimate cost for adversary analysis
 */
export function estimateAdversaryCost(filesCount, config) {
    // Rough estimates based on typical analysis patterns
    const tokensPerFile = config.aggressiveness === "aggressive" ? 8000 :
        config.aggressiveness === "active" ? 5000 : 3000;
    const estimatedTokens = filesCount * tokensPerFile;
    const pricing = MODEL_PRICING[config.model];
    // Assume 70% input, 30% output
    const inputTokens = estimatedTokens * 0.7;
    const outputTokens = estimatedTokens * 0.3;
    const inputCost = (inputTokens / 1_000_000) * pricing.input;
    const outputCost = (outputTokens / 1_000_000) * pricing.output;
    return {
        estimatedCost: Math.round((inputCost + outputCost) * 100) / 100,
        estimatedTokens: Math.round(estimatedTokens),
    };
}
//# sourceMappingURL=index.js.map