"use strict";
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.scanCodebase = scanCodebase;
exports.getDeveloperProfile = getDeveloperProfile;
exports.getCodePatterns = getCodePatterns;
exports.formatScanReport = formatScanReport;
exports.formatScanReportCompact = formatScanReportCompact;
exports.ensureCodePatternTable = ensureCodePatternTable;
exports.prioritizeBlindSpots = prioritizeBlindSpots;
exports.formatPrioritizedBlindSpots = formatPrioritizedBlindSpots;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const ts = __importStar(require("typescript"));
const database_1 = require("../../06-memory/database/database");
const stack_detector_1 = require("../stack/stack-detector");
// ─── Language Detection ──────────────────────────────────────────────────────
const EXT_MAP = {
    '.ts': 'typescript', '.tsx': 'typescript', '.js': 'javascript',
    '.jsx': 'javascript', '.py': 'python', '.rb': 'ruby',
    '.go': 'go', '.rs': 'rust', '.java': 'java',
    '.cs': 'csharp', '.cpp': 'cpp', '.c': 'c',
    '.php': 'php', '.swift': 'swift', '.kt': 'kotlin',
    '.sql': 'sql', '.sh': 'shell', '.bash': 'shell',
    '.yaml': 'yaml', '.yml': 'yaml', '.json': 'json',
    '.md': 'markdown', '.html': 'html', '.css': 'css',
    '.scss': 'scss', '.vue': 'vue', '.svelte': 'svelte',
};
const IGNORE_DIRS = new Set([
    'node_modules', '.git', 'dist', 'build', '.next', '.nuxt',
    'coverage', '.cache', '__pycache__', '.pytest_cache',
    'vendor', '.gradle', 'target', '.tox', 'venv', '.venv',
    'cell-data', '.fivo',
]);
const MAX_FILE_SIZE = 500 * 1024;
// ─── Pattern Extraction ──────────────────────────────────────────────────────
function detectLanguage(filePath) {
    const ext = path.extname(filePath).toLowerCase();
    return EXT_MAP[ext] || 'unknown';
}
function countOccurrences(text, regex) {
    return (text.match(regex) || []).length;
}
function extractImports(content, lang) {
    const patterns = [];
    const lines = content.split('\n');
    let defaultImports = 0;
    let namedImports = 0;
    let sideEffectImports = 0;
    let dynamicImports = 0;
    for (const line of lines) {
        const trimmed = line.trim();
        if (lang === 'typescript' || lang === 'javascript') {
            if (/^import\s+['"]/.test(trimmed))
                sideEffectImports++;
            else if (/^import\s+\{/.test(trimmed))
                namedImports++;
            else if (/^import\s+\w/.test(trimmed))
                defaultImports++;
            if (/import\s*\(/.test(trimmed))
                dynamicImports++;
        }
        else if (lang === 'python') {
            if (/^from\s+\S+\s+import\s+\*/.test(trimmed))
                patterns.push({ type: 'import_wildcard', category: 'imports', value: 'wildcard', count: 1, trustScore: 80 });
            if (/^import\s+/.test(trimmed) || /^from\s+/.test(trimmed))
                namedImports++;
        }
        else if (lang === 'go') {
            if (/^import\s+"/.test(trimmed))
                defaultImports++;
            if (/^import\s+\(/.test(trimmed))
                namedImports++;
        }
    }
    const total = defaultImports + namedImports + sideEffectImports + dynamicImports;
    if (total > 0) {
        if (namedImports > defaultImports)
            patterns.push({ type: 'import_style', category: 'imports', value: 'named', count: namedImports, trustScore: 90 });
        else
            patterns.push({ type: 'import_style', category: 'imports', value: 'default', count: defaultImports, trustScore: 90 });
        if (dynamicImports > 0)
            patterns.push({ type: 'import_dynamic', category: 'imports', value: 'dynamic', count: dynamicImports, trustScore: 85 });
    }
    return patterns;
}
function extractNamingPatterns(content) {
    const patterns = [];
    const camelCase = (content.match(/\b[a-z][a-zA-Z0-9]*[A-Z][a-zA-Z0-9]*/g) || []).length;
    const snakeCase = (content.match(/\b[a-z]+_[a-z]+(_[a-z]+)*/g) || []).length;
    const PascalCase = (content.match(/\b[A-Z][a-zA-Z0-9]+[A-Z][a-zA-Z0-9]*/g) || []).length;
    const SCREAMING = (content.match(/\b[A-Z][A-Z_]+[A-Z]\b/g) || []).length;
    const kebab = (content.match(/\b[a-z]+-[a-z]+(-[a-z]+)*\b/g) || []).length;
    const total = camelCase + snakeCase + PascalCase + SCREAMING + kebab;
    if (total === 0)
        return patterns;
    if (camelCase > total * 0.4)
        patterns.push({ type: 'naming_style', category: 'naming', value: 'camelCase', count: camelCase, trustScore: Math.min(0.95, camelCase / total) });
    if (snakeCase > total * 0.4)
        patterns.push({ type: 'naming_style', category: 'naming', value: 'snake_case', count: snakeCase, trustScore: Math.min(0.95, snakeCase / total) });
    if (PascalCase > total * 0.2)
        patterns.push({ type: 'naming_type', category: 'naming', value: 'PascalCase', count: PascalCase, trustScore: Math.min(0.9, PascalCase / total) });
    if (SCREAMING > 2)
        patterns.push({ type: 'naming_const', category: 'naming', value: 'SCREAMING_SNAKE', count: SCREAMING, trustScore: 85 });
    if (kebab > total * 0.3)
        patterns.push({ type: 'naming_style', category: 'naming', value: 'kebab-case', count: kebab, trustScore: Math.min(0.9, kebab / total) });
    return patterns;
}
function extractErrorHandling(content, lang) {
    const patterns = [];
    if (lang === 'typescript' || lang === 'javascript') {
        const tryCatch = countOccurrences(content, /\btry\s*\{/g);
        const promiseCatch = countOccurrences(content, /\.catch\s*\(/g);
        const optionalChain = countOccurrences(content, /\?\./g);
        const nullCheck = countOccurrences(content, /===?\s*null|!==?\s*null/g);
        const errorType = countOccurrences(content, /instanceof\s+Error/g);
        if (tryCatch > 0)
            patterns.push({ type: 'error_trycatch', category: 'error_handling', value: 'try-catch', count: tryCatch, trustScore: 90 });
        if (promiseCatch > 0)
            patterns.push({ type: 'error_promise', category: 'error_handling', value: 'promise-catch', count: promiseCatch, trustScore: 85 });
        if (optionalChain > 0)
            patterns.push({ type: 'error_optional', category: 'error_handling', value: 'optional-chaining', count: optionalChain, trustScore: 90 });
        if (nullCheck > 0)
            patterns.push({ type: 'error_nullcheck', category: 'error_handling', value: 'null-check', count: nullCheck, trustScore: 85 });
        if (errorType > 0)
            patterns.push({ type: 'error_typed', category: 'error_handling', value: 'typed-errors', count: errorType, trustScore: 80 });
    }
    else if (lang === 'python') {
        const tryExcept = countOccurrences(content, /\btry\s*:/g);
        const raise = countOccurrences(content, /\braise\s+/g);
        const typeCheck = countOccurrences(content, /isinstance\s*\(/g);
        if (tryExcept > 0)
            patterns.push({ type: 'error_tryexcept', category: 'error_handling', value: 'try-except', count: tryExcept, trustScore: 90 });
        if (raise > 0)
            patterns.push({ type: 'error_explicit', category: 'error_handling', value: 'explicit-raise', count: raise, trustScore: 85 });
        if (typeCheck > 0)
            patterns.push({ type: 'error_typecheck', category: 'error_handling', value: 'type-checking', count: typeCheck, trustScore: 80 });
    }
    else if (lang === 'go') {
        const ifErr = countOccurrences(content, /if\s+err\s*!=\s*nil/g);
        if (ifErr > 0)
            patterns.push({ type: 'error_iferr', category: 'error_handling', value: 'if-err-nil', count: ifErr, trustScore: 95 });
    }
    return patterns;
}
function extractFunctionPatterns(content, lang) {
    const patterns = [];
    if (lang === 'typescript' || lang === 'javascript') {
        const arrowFunctions = countOccurrences(content, /(?:const|let|var)\s+\w+\s*=\s*(?:\([^)]*\)|[a-zA-Z_]\w*)\s*=>/g);
        const functionDecls = countOccurrences(content, /\bfunction\s+\w+/g);
        const asyncFunctions = countOccurrences(content, /\basync\s+(?:function|\()/g);
        const generators = countOccurrences(content, /\bfunction\s*\*/g);
        const methods = countOccurrences(content, /^\s*(?:public|private|protected|static)?\s*(?:async\s+)?[a-zA-Z_]\w*\s*\(/gm);
        const constFunctions = countOccurrences(content, /(?:const|let)\s+\w+\s*=\s*(?:async\s+)?(?:\([^)]*\)|[a-zA-Z_]\w*)\s*=>/g);
        if (arrowFunctions > functionDecls)
            patterns.push({ type: 'function_style', category: 'functions', value: 'arrow', count: arrowFunctions, trustScore: 90 });
        else
            patterns.push({ type: 'function_style', category: 'functions', value: 'declaration', count: functionDecls, trustScore: 85 });
        if (asyncFunctions > 0)
            patterns.push({ type: 'function_async', category: 'functions', value: 'async', count: asyncFunctions, trustScore: 90 });
        if (generators > 0)
            patterns.push({ type: 'function_generator', category: 'functions', value: 'generator', count: generators, trustScore: 80 });
    }
    else if (lang === 'python') {
        const defFunctions = countOccurrences(content, /\bdef\s+\w+/g);
        const asyncDefs = countOccurrences(content, /\basync\s+def\s+/g);
        const lambdas = countOccurrences(content, /\blambda\s+/g);
        const decorators = countOccurrences(content, /@\w+/g);
        if (asyncDefs > 0)
            patterns.push({ type: 'function_async', category: 'functions', value: 'async-def', count: asyncDefs, trustScore: 90 });
        if (decorators > 0)
            patterns.push({ type: 'function_decorator', category: 'functions', value: 'decorated', count: decorators, trustScore: 85 });
        if (lambdas > 0)
            patterns.push({ type: 'function_lambda', category: 'functions', value: 'lambda', count: lambdas, trustScore: 80 });
    }
    return patterns;
}
function extractCodeStyle(content) {
    const patterns = [];
    const lines = content.split('\n');
    let singleQuotes = 0;
    let doubleQuotes = 0;
    let backtickStrings = 0;
    let semicolons = 0;
    let noSemicolons = 0;
    let tabs = 0;
    let twoSpaces = 0;
    let fourSpaces = 0;
    let trailingCommas = 0;
    let inlineComments = 0;
    let blockComments = 0;
    let jsdocComments = 0;
    for (const line of lines) {
        if (line.trim().startsWith('//'))
            inlineComments++;
        if (line.trim().startsWith('/*') || line.trim().startsWith('*'))
            blockComments++;
        if (line.trim().startsWith('/**'))
            jsdocComments++;
        const trimmed = line.trimEnd();
        if (trimmed.length > 0 && !trimmed.startsWith('//') && !trimmed.startsWith('*')) {
            const quoteMatches = trimmed.match(/['"]/g) || [];
            for (const q of quoteMatches) {
                if (q === "'" && !trimmed.includes(`\\'`))
                    singleQuotes++;
                else if (q === '"')
                    doubleQuotes++;
            }
            if (trimmed.includes('`') && (trimmed.includes('${') || trimmed.split('`').length > 2))
                backtickStrings++;
            if (/^[}\])]/.test(trimmed) || trimmed.length === 0) {
                // skip — not a statement line
            }
            else if (trimmed.endsWith(';'))
                semicolons++;
            else if (trimmed.length > 0 && /[a-zA-Z0-9"'`]/.test(trimmed))
                noSemicolons++;
        }
        if (/^\t/.test(line))
            tabs++;
        else if (/^  \S/.test(line))
            twoSpaces++;
        else if (/^    \S/.test(line))
            fourSpaces++;
        if (/,\s*\)/.test(line) || /,\s*\}/.test(line) || /,\s*\]/.test(line))
            trailingCommas++;
    }
    const totalQuotes = singleQuotes + doubleQuotes;
    if (totalQuotes > 0) {
        if (singleQuotes > doubleQuotes * 1.5)
            patterns.push({ type: 'style_quotes', category: 'style', value: 'single', count: singleQuotes, trustScore: 90 });
        else if (doubleQuotes > singleQuotes * 1.5)
            patterns.push({ type: 'style_quotes', category: 'style', value: 'double', count: doubleQuotes, trustScore: 90 });
        else
            patterns.push({ type: 'style_quotes', category: 'style', value: 'mixed', count: totalQuotes, trustScore: 60 });
    }
    if (backtickStrings > 2)
        patterns.push({ type: 'style_template', category: 'style', value: 'template-literals', count: backtickStrings, trustScore: 85 });
    const codeLines = semicolons + noSemicolons;
    if (codeLines > 0) {
        if (semicolons > noSemicolons)
            patterns.push({ type: 'style_semicolons', category: 'style', value: 'always', count: semicolons, trustScore: 90 });
        else if (noSemicolons > semicolons)
            patterns.push({ type: 'style_semicolons', category: 'style', value: 'never', count: noSemicolons, trustScore: 90 });
        else
            patterns.push({ type: 'style_semicolons', category: 'style', value: 'mixed', count: semicolons + noSemicolons, trustScore: 70 });
    }
    if (tabs > twoSpaces + fourSpaces)
        patterns.push({ type: 'style_indent', category: 'style', value: 'tabs', count: tabs, trustScore: 90 });
    else if (twoSpaces > fourSpaces)
        patterns.push({ type: 'style_indent', category: 'style', value: '2-spaces', count: twoSpaces, trustScore: 85 });
    else if (fourSpaces > twoSpaces)
        patterns.push({ type: 'style_indent', category: 'style', value: '4-spaces', count: fourSpaces, trustScore: 85 });
    if (trailingCommas > 2)
        patterns.push({ type: 'style_trailing_comma', category: 'style', value: 'always', count: trailingCommas, trustScore: 80 });
    const totalComments = inlineComments + blockComments + jsdocComments;
    if (totalComments > 0) {
        if (jsdocComments > inlineComments)
            patterns.push({ type: 'style_docs', category: 'style', value: 'jsdoc', count: jsdocComments, trustScore: 85 });
        else if (inlineComments > blockComments)
            patterns.push({ type: 'style_docs', category: 'style', value: 'inline', count: inlineComments, trustScore: 80 });
    }
    return patterns;
}
function extractArchitecturePatterns(content, lang) {
    const patterns = [];
    if (lang === 'typescript' || lang === 'javascript') {
        const classes = countOccurrences(content, /\bclass\s+\w+/g);
        const interfaces = countOccurrences(content, /\binterface\s+\w+/g);
        const types = countOccurrences(content, /\btype\s+\w+/g);
        const enums = countOccurrences(content, /\benum\s+\w+/g);
        const exports = countOccurrences(content, /\bexport\s+(?:default\s+)?(?:const|function|class|interface|type|enum)/g);
        const defaultExports = countOccurrences(content, /\bexport\s+default\s+/g);
        const barrelExports = countOccurrences(content, /export\s+\*\s+from/g);
        const reactComponents = countOccurrences(content, /(?:const|function)\s+[A-Z]\w+\s*(?:=\s*)?(?:\([^)]*\)|\([^)]*\)\s*=>)\s*(?:=>\s*)?(?:\{|<)/g);
        const hooks = countOccurrences(content, /\buse[A-Z]\w+\s*\(/g);
        const useEffect = countOccurrences(content, /\buseEffect\s*\(/g);
        const useState = countOccurrences(content, /\buseState\s*\(/g);
        if (classes > 0 && interfaces > 0)
            patterns.push({ type: 'arch_oo', category: 'architecture', value: 'class+interface', count: classes + interfaces, trustScore: 90 });
        else if (classes > 2)
            patterns.push({ type: 'arch_oo', category: 'architecture', value: 'class-based', count: classes, trustScore: 85 });
        if (interfaces > 0)
            patterns.push({ type: 'arch_types', category: 'architecture', value: 'interfaces', count: interfaces, trustScore: 90 });
        if (types > 0)
            patterns.push({ type: 'arch_types', category: 'architecture', value: 'type-aliases', count: types, trustScore: 85 });
        if (enums > 0)
            patterns.push({ type: 'arch_enum', category: 'architecture', value: 'enum', count: enums, trustScore: 80 });
        if (defaultExports > 0)
            patterns.push({ type: 'arch_export', category: 'architecture', value: 'default-export', count: defaultExports, trustScore: 85 });
        if (barrelExports > 0)
            patterns.push({ type: 'arch_barrel', category: 'architecture', value: 'barrel-export', count: barrelExports, trustScore: 80 });
        if (reactComponents > 2)
            patterns.push({ type: 'arch_react', category: 'architecture', value: 'functional-components', count: reactComponents, trustScore: 90 });
        if (hooks > 0)
            patterns.push({ type: 'arch_hooks', category: 'architecture', value: 'hooks', count: hooks, trustScore: 90 });
        if (useEffect > 0)
            patterns.push({ type: 'arch_effects', category: 'architecture', value: 'useEffect', count: useEffect, trustScore: 85 });
    }
    else if (lang === 'python') {
        const classes = countOccurrences(content, /\bclass\s+\w+/g);
        const dataclasses = countOccurrences(content, /@dataclass/g);
        const typeHints = countOccurrences(content, /:\s*(?:str|int|float|bool|list|dict|tuple|None|Optional|Union|List|Dict|Tuple|Set|Any)\b/g);
        const asyncDefs = countOccurrences(content, /\basync\s+def\s+/g);
        const pydantic = countOccurrences(content, /class\s+\w+\(BaseModel\)/g);
        const fastapi = countOccurrences(content, /@(?:app|router)\.(?:get|post|put|delete|patch)\s*\(/g);
        if (dataclasses > 0)
            patterns.push({ type: 'arch_dataclass', category: 'architecture', value: 'dataclass', count: dataclasses, trustScore: 90 });
        if (pydantic > 0)
            patterns.push({ type: 'arch_pydantic', category: 'architecture', value: 'pydantic', count: pydantic, trustScore: 90 });
        if (fastapi > 0)
            patterns.push({ type: 'arch_fastapi', category: 'architecture', value: 'fastapi', count: fastapi, trustScore: 90 });
        if (typeHints > 3)
            patterns.push({ type: 'arch_typehints', category: 'architecture', value: 'type-hints', count: typeHints, trustScore: 85 });
    }
    else if (lang === 'go') {
        const structs = countOccurrences(content, /\btype\s+\w+\s+struct\b/g);
        const interfaces = countOccurrences(content, /\btype\s+\w+\s+interface\b/g);
        const goroutines = countOccurrences(content, /\bgo\s+\w+/g);
        const channels = countOccurrences(content, /\b(?:make|<-)\s*\(\s*chan\b/g);
        if (structs > 0)
            patterns.push({ type: 'arch_struct', category: 'architecture', value: 'struct', count: structs, trustScore: 90 });
        if (goroutines > 0)
            patterns.push({ type: 'arch_goroutine', category: 'architecture', value: 'goroutine', count: goroutines, trustScore: 90 });
        if (channels > 0)
            patterns.push({ type: 'arch_channel', category: 'architecture', value: 'channel', count: channels, trustScore: 85 });
    }
    return patterns;
}
function extractTestPatterns(content, lang) {
    const patterns = [];
    if (lang === 'typescript' || lang === 'javascript') {
        const jestDescribe = countOccurrences(content, /\bdescribe\s*\(/g);
        const jestIt = countOccurrences(content, /\b(?:it|test)\s*\(/g);
        const jestExpect = countOccurrences(content, /\bexpect\s*\(/g);
        const vitest = content.includes('vitest');
        const playwright = content.includes('@playwright');
        const mocha = content.includes('mocha');
        if (jestDescribe > 0 || jestIt > 0)
            patterns.push({ type: 'test_framework', category: 'testing', value: vitest ? 'vitest' : playwright ? 'playwright' : mocha ? 'mocha' : 'jest', count: jestDescribe + jestIt, trustScore: 90 });
        if (jestExpect > 0)
            patterns.push({ type: 'test_assertion', category: 'testing', value: 'expect', count: jestExpect, trustScore: 85 });
    }
    else if (lang === 'python') {
        const pytest = countOccurrences(content, /\bdef\s+test_\w+/g);
        const unittest = countOccurrences(content, /\bself\.assert/g);
        if (pytest > 0)
            patterns.push({ type: 'test_framework', category: 'testing', value: 'pytest', count: pytest, trustScore: 90 });
        if (unittest > 0)
            patterns.push({ type: 'test_framework', category: 'testing', value: 'unittest', count: unittest, trustScore: 85 });
    }
    return patterns;
}
// ─── AST-Based Deep Analysis (TypeScript/JavaScript) ──────────────────────
function extractASTPatterns(content, filePath) {
    const patterns = [];
    try {
        const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
        if (!sourceFile)
            return patterns;
        let asyncNoTryCatch = 0;
        let totalAsync = 0;
        let missingReturnType = 0;
        let functionsWithType = 0;
        let emptyCatch = 0;
        let totalCatch = 0;
        let consoleLogs = 0;
        let rawQueries = 0;
        let anyTypeCount = 0;
        let zodImports = false;
        let nestDepth = 0;
        let maxNestDepth = 0;
        let controlFlowDepth = 0;
        let maxControlFlowDepth = 0;
        let nPlusOne = 0;
        let hardcodedSecrets = 0;
        let missingNullCheck = 0;
        let missingInputValidation = 0;
        const visit = (node, depth) => {
            nestDepth = Math.max(nestDepth, depth);
            maxNestDepth = Math.max(maxNestDepth, depth);
            const isControlFlow = ts.isIfStatement(node) ||
                ts.isForStatement(node) ||
                ts.isForInStatement(node) ||
                ts.isForOfStatement(node) ||
                ts.isWhileStatement(node) ||
                ts.isDoStatement(node) ||
                ts.isSwitchStatement(node) ||
                ts.isTryStatement(node) ||
                ts.isConditionalExpression(node);
            if (isControlFlow) {
                controlFlowDepth = depth;
                maxControlFlowDepth = Math.max(maxControlFlowDepth, depth);
            }
            if (isControlFlow) {
                ts.forEachChild(node, (child) => visit(child, depth + 1));
                return;
            }
            // ── Async without try/catch ──────────────────────────────────────
            if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node)) {
                const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;
                const isAsync = modifiers?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword);
                if (isAsync) {
                    totalAsync++;
                    let hasTryCatch = false;
                    const bodyVisitor = (n) => {
                        if (ts.isTryStatement(n))
                            hasTryCatch = true;
                        ts.forEachChild(n, bodyVisitor);
                    };
                    if (node.body)
                        bodyVisitor(node.body);
                    if (!hasTryCatch)
                        asyncNoTryCatch++;
                    // Return type check
                    if (ts.isFunctionDeclaration(node) ||
                        ts.isMethodDeclaration(node) ||
                        ts.isFunctionExpression(node) ||
                        ts.isArrowFunction(node)) {
                        const hasReturnType = node.type !== undefined;
                        if (hasReturnType)
                            functionsWithType++;
                        else
                            missingReturnType++;
                    }
                }
            }
            // ── Empty catch blocks ──────────────────────────────────────────
            if (ts.isCatchClause(node)) {
                totalCatch++;
                if (!node.block || node.block.statements.length === 0)
                    emptyCatch++;
            }
            // ── Console.log ─────────────────────────────────────────────────
            if (ts.isCallExpression(node)) {
                const expr = node.expression;
                if (ts.isPropertyAccessExpression(expr) && ts.isIdentifier(expr.expression) && expr.expression.text === 'console') {
                    consoleLogs++;
                }
                // Raw SQL queries (tagged templates like sql`...`)
                if (ts.isTaggedTemplateExpression(node)) {
                    const tte = node;
                    if (ts.isIdentifier(tte.tag) && (tte.tag.text === 'sql' || tte.tag.text === 'raw' || tte.tag.text === 'query')) {
                        rawQueries++;
                    }
                }
                // Zod validation
                if (ts.isIdentifier(expr)) {
                    const callName = expr.text;
                    if (callName === 'z' || callName.startsWith('z.'))
                        zodImports = true;
                }
                if (ts.isPropertyAccessExpression(expr)) {
                    if (expr.expression.getText().startsWith('z.'))
                        zodImports = true;
                }
                // N+1 query detection: await/query inside loop
                if (ts.isCallExpression(node)) {
                    const callText = expr.getText();
                    if (callText.includes('.find') || callText.includes('.query') || callText.includes('.execute') ||
                        callText.includes('fetch') || callText.includes('prisma.') || callText.includes('db.')) {
                        let parent = node.parent;
                        while (parent) {
                            if (ts.isForStatement(parent) ||
                                ts.isForInStatement(parent) ||
                                ts.isForOfStatement(parent) ||
                                ts.isWhileStatement(parent) ||
                                ts.isDoStatement(parent) ||
                                (ts.isCallExpression(parent) &&
                                    ts.isPropertyAccessExpression(parent.expression) &&
                                    (parent.expression.name.text === 'map' || parent.expression.name.text === 'forEach'))) {
                                nPlusOne++;
                                break;
                            }
                            parent = parent.parent;
                        }
                    }
                }
                // Missing null check detection — any property access on awaited API call
                if (ts.isPropertyAccessExpression(expr)) {
                    let base = expr.expression;
                    while (ts.isPropertyAccessExpression(base))
                        base = base.expression;
                    const baseText = base.getText();
                    if (baseText.includes('fetch') ||
                        baseText.includes('axios') ||
                        baseText.includes('request') ||
                        baseText.includes('http.get') ||
                        baseText.includes('prisma.') ||
                        baseText.includes('db.')) {
                        let hasAwait = false;
                        let hasNullCheck = false;
                        let ancestor = expr.parent;
                        while (ancestor && (!hasAwait || !hasNullCheck)) {
                            if (ts.isAwaitExpression(ancestor))
                                hasAwait = true;
                            if (ts.isExpressionStatement(ancestor) || ts.isVariableDeclaration(ancestor))
                                break;
                            if (ts.isIfStatement(ancestor)) {
                                const condText = ancestor.expression.getText();
                                if (condText.includes('!') ||
                                    condText.includes('null') ||
                                    condText.includes('undefined') ||
                                    condText.includes('?.')) {
                                    hasNullCheck = true;
                                }
                            }
                            if (ts.isBinaryExpression(ancestor) &&
                                (ancestor.operatorToken.kind === ts.SyntaxKind.EqualsEqualsToken ||
                                    ancestor.operatorToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken ||
                                    ancestor.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken ||
                                    ancestor.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken)) {
                                const text = ancestor.getText();
                                if (text.includes('null') || text.includes('undefined')) {
                                    hasNullCheck = true;
                                }
                            }
                            ancestor = ancestor.parent;
                        }
                        if (hasAwait && !hasNullCheck)
                            missingNullCheck++;
                    }
                }
            }
            // ── Hardcoded secrets detection ─────────────────────────────────
            if (ts.isVariableDeclaration(node)) {
                const varNode = node;
                const varName = ts.isIdentifier(varNode.name) ? varNode.name.text : '';
                const lower = varName.toLowerCase();
                if ((lower.includes('password') || lower.includes('secret') || lower.includes('api_key') ||
                    lower.includes('apikey') || (lower.includes('token') && lower.includes('auth'))) &&
                    varNode.initializer && ts.isStringLiteral(varNode.initializer)) {
                    const val = varNode.initializer.text;
                    if (val.length > 6 && !val.includes('${') && !val.startsWith('process.env')) {
                        hardcodedSecrets++;
                    }
                }
            }
            // ── Missing input validation in API handlers ────────────────────
            const isHandlerLike = ts.isFunctionDeclaration(node) ||
                ts.isFunctionExpression(node) ||
                ts.isArrowFunction(node);
            if (isHandlerLike) {
                let funcName = '';
                let body;
                if (ts.isFunctionDeclaration(node) && node.name) {
                    funcName = node.name.text;
                    body = node.body;
                }
                else if (ts.isFunctionExpression(node) ||
                    ts.isArrowFunction(node)) {
                    let p = node.parent;
                    while (p) {
                        if (ts.isVariableDeclaration(p) && ts.isIdentifier(p.name)) {
                            funcName = p.name.text;
                            break;
                        }
                        p = p.parent;
                    }
                    body = node.body;
                }
                if (funcName.toLowerCase().includes('handler') || funcName.toLowerCase().includes('route') || funcName.toLowerCase().includes('endpoint') || funcName.toLowerCase().includes('controller')) {
                    let hasValidation = false;
                    const checkBody = (n) => {
                        if (ts.isCallExpression(n)) {
                            const ct = n.expression.getText();
                            if (ct.includes('.parse') || ct.includes('.validate') || ct.includes('.safeParse') ||
                                ct.includes('check(') || ct.includes('body(') || ct.includes('query(')) {
                                hasValidation = true;
                            }
                        }
                        ts.forEachChild(n, checkBody);
                    };
                    if (body)
                        checkBody(body);
                    if (!hasValidation)
                        missingInputValidation++;
                }
            }
            // ── any type usage ──────────────────────────────────────────────
            if (ts.isToken(node) && node.kind === ts.SyntaxKind.AnyKeyword)
                anyTypeCount++;
            ts.forEachChild(node, (child) => visit(child, depth + 1));
        };
        visit(sourceFile, 0);
        // Pattern outputs
        if (totalAsync > 0 && asyncNoTryCatch > 0) {
            patterns.push({
                type: 'blind_spot_async_notry',
                category: 'blind_spots',
                value: `async_without_trycatch:${asyncNoTryCatch}/${totalAsync}`,
                count: asyncNoTryCatch,
                trustScore: 95,
            });
        }
        if (totalCatch > 0 && emptyCatch > 0) {
            patterns.push({
                type: 'blind_spot_empty_catch',
                category: 'blind_spots',
                value: `empty_catch:${emptyCatch}/${totalCatch}`,
                count: emptyCatch,
                trustScore: 90,
            });
        }
        if (functionsWithType + missingReturnType > 0 && missingReturnType > 0) {
            patterns.push({
                type: 'blind_spot_missing_types',
                category: 'blind_spots',
                value: `missing_return_types:${missingReturnType}`,
                count: missingReturnType,
                trustScore: 90,
            });
        }
        if (consoleLogs > 0) {
            patterns.push({
                type: 'blind_spot_console_log',
                category: 'blind_spots',
                value: `console.log:${consoleLogs}`,
                count: consoleLogs,
                trustScore: 85,
            });
        }
        if (anyTypeCount > 0) {
            patterns.push({
                type: 'blind_spot_any_type',
                category: 'blind_spots',
                value: `any_type:${anyTypeCount}`,
                count: anyTypeCount,
                trustScore: 85,
            });
        }
        if (maxControlFlowDepth > 4) {
            patterns.push({
                type: 'blind_spot_deep_nesting',
                category: 'blind_spots',
                value: `max_nesting:${maxControlFlowDepth}`,
                count: maxControlFlowDepth,
                trustScore: 80,
            });
        }
        if (rawQueries > 0) {
            patterns.push({
                type: 'blind_spot_raw_sql',
                category: 'blind_spots',
                value: `raw_sql:${rawQueries}`,
                count: rawQueries,
                trustScore: 85,
            });
        }
        if (zodImports) {
            patterns.push({
                type: 'pattern_validation',
                category: 'security',
                value: 'zod-validation',
                count: 1,
                trustScore: 90,
            });
        }
        if (nPlusOne > 0) {
            patterns.push({
                type: 'blind_spot_n_plus_one',
                category: 'blind_spots',
                value: `n_plus_one_queries:${nPlusOne}`,
                count: nPlusOne,
                trustScore: 85,
            });
        }
        if (hardcodedSecrets > 0) {
            patterns.push({
                type: 'blind_spot_hardcoded_secret',
                category: 'blind_spots',
                value: `hardcoded_secrets:${hardcodedSecrets}`,
                count: hardcodedSecrets,
                trustScore: 95,
            });
        }
        if (missingNullCheck > 0) {
            patterns.push({
                type: 'blind_spot_null_check',
                category: 'blind_spots',
                value: `missing_null_checks:${missingNullCheck}`,
                count: missingNullCheck,
                trustScore: 80,
            });
        }
        if (missingInputValidation > 0) {
            patterns.push({
                type: 'blind_spot_no_validation',
                category: 'blind_spots',
                value: `missing_input_validation:${missingInputValidation}`,
                count: missingInputValidation,
                trustScore: 85,
            });
        }
    }
    catch { /* AST parse may fail on broken files */ }
    return patterns;
}
function analyzeFile(filePath, content) {
    const lang = detectLanguage(filePath);
    const lines = content.split('\n');
    const patterns = [
        ...extractImports(content, lang),
        ...extractNamingPatterns(content),
        ...extractErrorHandling(content, lang),
        ...extractFunctionPatterns(content, lang),
        ...extractCodeStyle(content),
        ...extractArchitecturePatterns(content, lang),
        ...extractTestPatterns(content, lang),
        // AST-based deep analysis for TypeScript/JavaScript only
        ...(lang === 'typescript' || lang === 'javascript' ? extractASTPatterns(content, filePath) : []),
    ];
    const functionCount = lang === 'python'
        ? countOccurrences(content, /\bdef\s+\w+/g)
        : countOccurrences(content, /\b(?:function|const|let|var)\s+\w+/g);
    const classCount = countOccurrences(content, /\bclass\s+\w+/g);
    const importCount = countOccurrences(content, /\b(?:import|from|require)\s/g);
    const exportCount = countOccurrences(content, /\b(?:export|module\.exports|def\s|pub\s)/g);
    return {
        filePath,
        language: lang,
        lineCount: lines.length,
        functionCount,
        classCount,
        importCount,
        exportCount,
        patterns,
    };
}
// ─── Codebase Scanner ────────────────────────────────────────────────────────
function walkDir(dir, files = []) {
    if (!fs.existsSync(dir))
        return files;
    const entries = fs.readdirSync(dir, { withFileTypes: true });
    for (const entry of entries) {
        if (IGNORE_DIRS.has(entry.name))
            continue;
        if (entry.name.startsWith('.') && entry.name !== '.env.example')
            continue;
        const fullPath = path.join(dir, entry.name);
        if (entry.isDirectory()) {
            walkDir(fullPath, files);
        }
        else if (entry.isFile()) {
            const ext = path.extname(entry.name).toLowerCase();
            if (EXT_MAP[ext]) {
                try {
                    const stat = fs.statSync(fullPath);
                    if (stat.size <= MAX_FILE_SIZE)
                        files.push(fullPath);
                }
                catch { /* skip */ }
            }
        }
    }
    return files;
}
function aggregatePatterns(analyses) {
    const patternMap = new Map();
    for (const analysis of analyses) {
        for (const pattern of analysis.patterns) {
            const key = `${pattern.type}:${pattern.value}`;
            const existing = patternMap.get(key);
            if (existing) {
                const totalCount = existing.count + pattern.count;
                existing.trustScore = Math.min(95, Math.round((existing.trustScore * existing.count + pattern.trustScore * pattern.count) / totalCount));
                existing.count = totalCount;
            }
            else {
                patternMap.set(key, { ...pattern });
            }
        }
    }
    return Array.from(patternMap.values()).sort((a, b) => b.count - a.count);
}
function buildDeveloperProfile(patterns) {
    const getByType = (type) => patterns.filter(p => p.type === type);
    const getTopValue = (type) => {
        const matches = getByType(type);
        if (matches.length === 0)
            return 'unknown';
        // Sum counts per unique value, then return the value with highest total count
        const sums = new Map();
        for (const m of matches)
            sums.set(m.value, (sums.get(m.value) || 0) + m.count);
        let best = matches[0].value;
        let bestCount = 0;
        for (const [v, c] of sums)
            if (c > bestCount) {
                best = v;
                bestCount = c;
            }
        // For semicolons, normalize: if "always" is at least 35% of (always + never), prefer "always"
        // because the "noSemi" counter is inflated by multi-line statements
        if (type === 'style_semicolons') {
            const always = sums.get('always') || 0;
            const never = sums.get('never') || 0;
            if (always + never > 0 && always / (always + never) >= 0.35)
                return 'always';
            if (never + always > 0 && never / (always + never) >= 0.7)
                return 'never';
            return 'mixed';
        }
        return best;
    };
    const namingPatterns = getByType('naming_style');
    const namingStyle = namingPatterns.length > 0 ? namingPatterns[0].value : 'mixed';
    const errorPatterns = getByType('error_*');
    const errorHandling = errorPatterns.length > 0 ? errorPatterns[0].value : 'none';
    const functionPatterns = getByType('function_style');
    const functionStyle = functionPatterns.length > 0 ? functionPatterns[0].value : 'mixed';
    const asyncPatterns = getByType('function_async');
    const asyncStyle = asyncPatterns.length > 0 ? 'uses-async' : 'sync-only';
    const archPatterns = getByType('arch_*');
    const archStyle = archPatterns.length > 0 ? archPatterns[0].value : 'mixed';
    const testPatterns = getByType('test_framework');
    const testPattern = testPatterns.length > 0 ? testPatterns[0].value : 'none';
    const docPatterns = getByType('style_docs');
    const commentStyle = docPatterns.length > 0 ? docPatterns[0].value : 'none';
    const strengths = [];
    const improvements = [];
    if (errorHandling !== 'none')
        strengths.push('Uses structured error handling');
    else
        improvements.push('Add error handling (try-catch / if-err)');
    if (asyncStyle === 'uses-async')
        strengths.push('Uses async/await patterns');
    if (testPattern !== 'none')
        strengths.push(`Tests with ${testPattern}`);
    else
        improvements.push('Add unit tests');
    const typePatterns = getByType('arch_types');
    if (typePatterns.length > 0)
        strengths.push('Uses type annotations');
    const hookPatterns = getByType('arch_hooks');
    if (hookPatterns.length > 0)
        strengths.push('Uses React hooks');
    if (commentStyle !== 'none')
        strengths.push('Documents code');
    else
        improvements.push('Add code documentation');
    // ─── AST-based blind spot detection ───────────────────────────────────────
    const asyncNoTry = patterns.find(p => p.type === 'blind_spot_async_notry');
    if (asyncNoTry && asyncNoTry.count > 0) {
        improvements.push(`${asyncNoTry.count} async functions missing try/catch`);
    }
    const emptyCatchBlocks = patterns.find(p => p.type === 'blind_spot_empty_catch');
    if (emptyCatchBlocks && emptyCatchBlocks.count > 0) {
        improvements.push(`${emptyCatchBlocks.count} empty catch blocks — errors silently swallowed`);
    }
    const missingTypes = patterns.find(p => p.type === 'blind_spot_missing_types');
    if (missingTypes && missingTypes.count > 0) {
        improvements.push(`${missingTypes.count} functions missing return type annotations`);
    }
    const consoleLogCount = patterns.find(p => p.type === 'blind_spot_console_log');
    if (consoleLogCount && consoleLogCount.count > 0) {
        improvements.push(`${consoleLogCount.count} console.log statements — switch to structured logger`);
    }
    const anyTypeUsage = patterns.find(p => p.type === 'blind_spot_any_type');
    if (anyTypeUsage && anyTypeUsage.count > 0) {
        improvements.push(`${anyTypeUsage.count} 'any' type usages — use specific types`);
    }
    const deepNest = patterns.find(p => p.type === 'blind_spot_deep_nesting');
    if (deepNest && deepNest.count > 4) {
        improvements.push(`Deep nesting detected (max depth: ${deepNest.count}) — refactor to smaller functions`);
    }
    const rawSQL = patterns.find(p => p.type === 'blind_spot_raw_sql');
    if (rawSQL && rawSQL.count > 0) {
        improvements.push(`${rawSQL.count} raw SQL queries — use parameterized queries`);
    }
    const hasZod = patterns.find(p => p.type === 'pattern_validation');
    if (hasZod)
        strengths.push('Uses Zod validation for inputs');
    else
        improvements.push('Add input validation (Zod/Joi/Yup)');
    // Blind spots v2
    const nPlusOne = patterns.find(p => p.type === 'blind_spot_n_plus_one');
    if (nPlusOne && nPlusOne.count > 0) {
        improvements.push(`${nPlusOne.count} N+1 query patterns — DB calls inside loops`);
    }
    const secrets = patterns.find(p => p.type === 'blind_spot_hardcoded_secret');
    if (secrets && secrets.count > 0) {
        improvements.push(`${secrets.count} hardcoded secrets/API keys — move to env vars`);
    }
    const nullChecks = patterns.find(p => p.type === 'blind_spot_null_check');
    if (nullChecks && nullChecks.count > 0) {
        improvements.push(`${nullChecks.count} API responses used without null check`);
    }
    const noValidation = patterns.find(p => p.type === 'blind_spot_no_validation');
    if (noValidation && noValidation.count > 0) {
        improvements.push(`${noValidation.count} API handlers missing input validation`);
    }
    if (asyncNoTry && asyncNoTry.count === 0 && patterns.find(p => p.type === 'error_trycatch')) {
        strengths.push('All async functions have try/catch error handling');
    }
    const topPatterns = patterns.slice(0, 10).map(p => `${p.category}:${p.value}`);
    return {
        namingStyle,
        importStyle: getTopValue('import_style'),
        exportStyle: getTopValue('arch_export'),
        errorHandling,
        functionStyle,
        asyncStyle,
        commentStyle,
        indentStyle: getTopValue('style_indent'),
        quoteStyle: getTopValue('style_quotes'),
        semicolonStyle: getTopValue('style_semicolons'),
        architectureStyle: archStyle,
        testPattern,
        topPatterns,
        strengths,
        improvements,
    };
}
// ─── Database Storage ────────────────────────────────────────────────────────
function ensureCodePatternTable() {
    const db = (0, database_1.getDb)();
    db.exec(`
    CREATE TABLE IF NOT EXISTS code_patterns (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      project TEXT NOT NULL,
      file_path TEXT NOT NULL,
      pattern_type TEXT NOT NULL,
      pattern_value TEXT NOT NULL,
      category TEXT NOT NULL,
      count INTEGER DEFAULT 1,
      trust_score INTEGER DEFAULT 50,
      language TEXT,
      created_at TEXT DEFAULT (datetime('now'))
    );
    CREATE INDEX IF NOT EXISTS idx_code_patterns_project ON code_patterns(project);
    CREATE INDEX IF NOT EXISTS idx_code_patterns_type ON code_patterns(pattern_type);
    CREATE INDEX IF NOT EXISTS idx_code_patterns_category ON code_patterns(category);

    CREATE TABLE IF NOT EXISTS developer_profiles (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      project TEXT NOT NULL UNIQUE,
      naming_style TEXT,
      import_style TEXT,
      export_style TEXT,
      error_handling TEXT,
      function_style TEXT,
      async_style TEXT,
      comment_style TEXT,
      indent_style TEXT,
      quote_style TEXT,
      semicolon_style TEXT,
      architecture_style TEXT,
      test_pattern TEXT,
      top_patterns TEXT,
      strengths TEXT,
      improvements TEXT,
      files_scanned INTEGER DEFAULT 0,
      total_lines INTEGER DEFAULT 0,
      languages TEXT,
      scanned_at TEXT DEFAULT (datetime('now'))
    );
    CREATE INDEX IF NOT EXISTS idx_dev_profile_project ON developer_profiles(project);
  `);
}
function saveToDatabase(project, result, projectPath) {
    const db = (0, database_1.getDb)();
    ensureCodePatternTable();
    try {
        const { ProjectRegistry } = require('../../../core/project-registry');
        const registry = new ProjectRegistry();
        const stack = Object.keys(result.languages || {}).slice(0, 3).join('+') || 'unknown';
        registry.registerProject({
            name: project,
            path: projectPath || project,
            stack,
            fileCount: result.filesScanned,
        });
    }
    catch (e) {
        console.warn('[cell] Project registration failed (non-fatal):', e instanceof Error ? e.message : String(e));
    }
    db.prepare('DELETE FROM code_patterns WHERE project = ?').run(project);
    const insertPattern = db.prepare('INSERT INTO code_patterns (project, file_path, pattern_type, pattern_value, category, count, trust_score, language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
    const insertMany = db.transaction((patterns) => {
        for (const p of patterns) {
            insertPattern.run(project, 'scan', p.type, p.value, p.category, p.count, p.trustScore, '');
        }
    });
    insertMany(result.patterns);
    db.prepare('DELETE FROM developer_profiles WHERE project = ?').run(project);
    db.prepare(`INSERT INTO developer_profiles 
    (project, naming_style, import_style, export_style, error_handling, function_style, 
     async_style, comment_style, indent_style, quote_style, semicolon_style, 
     architecture_style, test_pattern, top_patterns, strengths, improvements,
     files_scanned, total_lines, languages, scanned_at)
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))`)
        .run(project, result.profile.namingStyle, result.profile.importStyle, result.profile.exportStyle, result.profile.errorHandling, result.profile.functionStyle, result.profile.asyncStyle, result.profile.commentStyle, result.profile.indentStyle, result.profile.quoteStyle, result.profile.semicolonStyle, result.profile.architectureStyle, result.profile.testPattern, JSON.stringify(result.profile.topPatterns), JSON.stringify(result.profile.strengths), JSON.stringify(result.profile.improvements), result.filesScanned, result.totalLines, JSON.stringify(result.languages));
    try {
        const stmt = db.prepare(`INSERT OR REPLACE INTO scans (project, scanned_at, file_count, line_count, stack, patterns, hubs, issues)
      VALUES (?, datetime('now'), ?, ?, ?, ?, ?, ?)`);
        if (stmt) {
            stmt.run(project, result.filesScanned, result.totalLines, JSON.stringify(result.languages), JSON.stringify(result.patterns.slice(0, 20)), JSON.stringify({}), JSON.stringify(result.profile.improvements));
        }
    }
    catch (e) {
        console.warn('[cell] scans table insert failed (schema mismatch, non-fatal):', e instanceof Error ? e.message : String(e));
    }
    try {
        db.prepare(`INSERT INTO stack_history (project, stack_json, file_count, line_count, scanned_at)
      VALUES (?, ?, ?, ?, datetime('now'))`).run(project, JSON.stringify(result.languages), result.filesScanned, result.totalLines);
    }
    catch { }
}
// ─── Public API ──────────────────────────────────────────────────────────────
function scanCodebase(dirPath, projectName) {
    const project = projectName || path.basename(dirPath);
    const files = walkDir(dirPath);
    const analyses = [];
    const languages = {};
    let totalLines = 0;
    for (const file of files) {
        try {
            const content = fs.readFileSync(file, 'utf-8');
            const analysis = analyzeFile(file, content);
            analyses.push(analysis);
            totalLines += analysis.lineCount;
            languages[analysis.language] = (languages[analysis.language] || 0) + 1;
        }
        catch { /* skip unreadable files */ }
    }
    const patterns = aggregatePatterns(analyses);
    const profile = buildDeveloperProfile(patterns);
    const result = {
        project,
        scannedAt: new Date().toISOString(),
        filesScanned: files.length,
        totalLines,
        languages,
        patterns,
        profile,
    };
    saveToDatabase(project, result, dirPath);
    // ─── PHASE 3: Build Knowledge Graphs (file deps + pattern entities) ───
    try {
        const { saveFileKnowledgeGraph, saveTechProficiency } = require('../../06-memory/stores/knowledge-graph-store');
        const fileGraph = saveFileKnowledgeGraph(project, dirPath);
        // Tech proficiency: use languages + architecture style
        const archTech = profile.architectureStyle || 'unknown';
        saveTechProficiency(project, {
            technology: archTech,
            category: 'architecture',
            signalsCount: 1,
            proficiencyScore: 70,
            lastSeen: new Date().toISOString(),
            trend: 'stable',
        });
        for (const [lang, count] of Object.entries(languages)) {
            const score = Math.min(100, 40 + Math.log10(count + 1) * 20);
            saveTechProficiency(project, {
                technology: lang,
                category: 'language',
                signalsCount: count,
                proficiencyScore: Math.round(score),
                lastSeen: new Date().toISOString(),
                trend: 'stable',
            });
        }
        // Save pattern entities + relationships
        if (result.patterns && result.patterns.length > 0) {
            const { savePatternEntities, savePatternRelationships } = require('../../06-memory/stores/knowledge-graph-store');
            const entities = result.patterns.slice(0, 200).map((p, i) => ({
                id: `${p.category || 'pattern'}-${i}`,
                type: p.category || 'pattern',
                label: p.value || '',
                weight: p.trustScore || 1,
            }));
            savePatternEntities(project, entities);
            // Co-occurrence: patterns in same category from same file are related
            const filePatterns = new Map();
            for (let i = 0; i < Math.min(200, result.patterns.length); i++) {
                const p = result.patterns[i];
                const f = p.file || 'global';
                const key = `${f}`;
                const arr = filePatterns.get(key) || [];
                arr.push(`${p.category || 'pattern'}-${i}`);
                filePatterns.set(key, arr);
            }
            const edges = [];
            for (const arr of filePatterns.values()) {
                for (let i = 0; i < arr.length; i++) {
                    for (let j = i + 1; j < arr.length; j++) {
                        edges.push({ from: arr[i], to: arr[j], type: 'co_occurs', weight: 1 });
                    }
                }
            }
            if (edges.length > 0)
                savePatternRelationships(project, edges);
        }
    }
    catch (e) {
        console.warn('[cell] Knowledge graph build failed (non-fatal):', e instanceof Error ? e.message : String(e));
    }
    const hookResults = [];
    // ─── CONNECT: Scanner → Behavioral Tracker ───────────────────────────────
    try {
        const { logError, logDecision, logContext } = require('../../03-knowledge/decisions/behavioral-tracker');
        if (profile.improvements.length > 0) {
            for (const imp of profile.improvements) {
                logError({
                    project,
                    file: 'scan-auto',
                    errorType: 'blind_spot',
                    errorMessage: imp,
                    line: 0,
                });
            }
        }
        logDecision({
            project,
            file: 'scan-auto',
            decision: `Architecture: ${profile.architectureStyle}`,
            approach: `Scan detected ${files.length} files, ${result.languages ? Object.keys(result.languages).join(', ') : 'unknown'}`,
            worked: true,
        });
        logContext({
            project,
            task: `Codebase scan completed — ${files.length} files, ${totalLines.toLocaleString()} lines`,
            files: [dirPath],
        });
        hookResults.push({ hook: 'behavioral-tracker', ok: true });
    }
    catch (e) {
        hookResults.push({ hook: 'behavioral-tracker', ok: false, error: String(e) });
        console.warn('[cell] Hook failed: behavioral-tracker:', e instanceof Error ? e.message : String(e));
    }
    // ─── CONNECT: Git Intelligence ──────
    try {
        const { buildDeveloperIntelligence } = require('../profile/developer-intelligence');
        const gitIntel = buildDeveloperIntelligence(dirPath);
        if (gitIntel) {
            console.log(`[cell] Git intelligence: ${gitIntel.topBlindSpots.length} blind spots, ${gitIntel.topMistakes.length} repeat mistakes, score: ${gitIntel.behavioralScore}/100`);
        }
        hookResults.push({ hook: 'developer-intelligence', ok: true });
    }
    catch (e) {
        hookResults.push({ hook: 'developer-intelligence', ok: false, error: String(e) });
        console.warn('[cell] Hook failed: developer-intelligence:', e instanceof Error ? e.message : String(e));
    }
    // ─── CONNECT: Style Pull ────
    try {
        const { writeStyleFiles, buildStyleSummary } = require('../style/style-pull');
        const summary = buildStyleSummary(dirPath);
        const styleResult = writeStyleFiles(dirPath, summary, { force: false });
        if (styleResult.written.length > 0) {
            console.log(`[cell] Generated: ${styleResult.written.join(', ')}`);
        }
        hookResults.push({ hook: 'style-pull', ok: true });
    }
    catch (e) {
        hookResults.push({ hook: 'style-pull', ok: false, error: String(e) });
        console.warn('[cell] Hook failed: style-pull:', e instanceof Error ? e.message : String(e));
    }
    // ─── CONNECT: Stack Detector ──────────
    try {
        const dna = (0, stack_detector_1.detectProjectDNA)(dirPath);
        const projectName = dna.name || project;
        const db = (0, database_1.getDb)();
        db.prepare('INSERT OR REPLACE INTO code_patterns (project, file_path, pattern_type, pattern_value, category, count, trust_score, language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)').run(projectName, 'stack-dna', 'project_dna', JSON.stringify(dna.stack), 'stack_detect', 1, dna.stack.trustScore, dna.stack.languages[0] || '');
        db.prepare('INSERT OR REPLACE INTO code_patterns (project, file_path, pattern_type, pattern_value, category, count, trust_score, language) VALUES (?, ?, ?, ?, ?, ?, ?, ?)').run(projectName, 'arch-dna', 'architecture', JSON.stringify(dna.architecture), 'architecture', 1, dna.architecture.confidence === 'high' ? 90 : 50, '');
        console.log('[cell] Stack: ' + dna.stack.frontend + ' + ' + dna.stack.backend + ', DB: ' + dna.stack.database.join(', ') + ', ORM: ' + dna.stack.orm + ', Test: ' + dna.stack.testing.join(', '));
        console.log('[cell] Arch: ' + dna.architecture.type + ' (' + dna.architecture.confidence + '), Entry: ' + dna.architecture.entryPoints.join(', '));
        hookResults.push({ hook: 'stack-detector', ok: true });
    }
    catch (e) {
        hookResults.push({ hook: 'stack-detector', ok: false, error: String(e) });
        console.warn('[cell] Hook failed: stack-detector:', e instanceof Error ? e.message : String(e));
    }
    // ─── CONNECT: Knowledge Graph ────────────────────────────────────
    try {
        const { buildKnowledgeGraph } = require('../../03-knowledge/graph/knowledge-graph-builder');
        const graph = buildKnowledgeGraph(dirPath);
        console.log(`[cell] Graph: ${graph.nodes.length} nodes, ${graph.mostCoupled.length} most-coupled, Entry: ${graph.entryPoints.join(', ')}`);
        hookResults.push({ hook: 'knowledge-graph', ok: true });
    }
    catch (e) {
        hookResults.push({ hook: 'knowledge-graph', ok: false, error: String(e) });
        console.warn('[cell] Hook failed: knowledge-graph:', e instanceof Error ? e.message : String(e));
    }
    // ─── CONNECT: Blind Spot Engine ──────────────────────────────
    try {
        const { BlindSpotEngine } = require('../../../core/blind-spot-engine');
        const engine = new BlindSpotEngine(path.join(os.homedir(), '.fivo', 'cell'));
        let totalBlindSpots = 0;
        let totalHit = 0;
        let totalMissed = 0;
        let analyzed = 0;
        for (const analysis of analyses) {
            try {
                if (!analysis.filePath || typeof analysis.filePath !== 'string')
                    continue;
                const content = fs.readFileSync(analysis.filePath, 'utf-8');
                const spots = engine.analyze(content, analysis.language);
                analyzed++;
                // Count unique rule IDs only (not per-detection), cap at 5 per file
                const seenRuleIds = new Set();
                let perFileCount = 0;
                for (const s of spots) {
                    if (seenRuleIds.has(s.id))
                        continue;
                    if (perFileCount >= 5)
                        break;
                    seenRuleIds.add(s.id);
                    perFileCount++;
                    totalBlindSpots++;
                    totalHit += Math.min(100, Math.round(s.hitRate * 100));
                    totalMissed += Math.min(5, Math.round(s.missedRate));
                }
            }
            catch { }
        }
        console.log(`[cell] Blind spots: ${totalBlindSpots} issues across ${analyzed}/${analyses.length} files, ${totalMissed} weighted severity`);
        result.blindSpotStats = { totalBlindSpots, totalHit, totalMissed, files: analyzed };
        hookResults.push({ hook: 'blind-spot-engine', ok: true });
    }
    catch (e) {
        hookResults.push({ hook: 'blind-spot-engine', ok: false, error: String(e) });
        console.warn('[cell] Hook failed: blind-spot-engine:', e instanceof Error ? e.message : String(e));
    }
    const failed = hookResults.filter(h => !h.ok);
    if (failed.length > 0) {
        console.warn(`[cell] Scan completed with ${failed.length} hook failures: ${failed.map(f => f.hook).join(', ')}`);
    }
    result.hookResults = hookResults;
    return result;
}
function getDeveloperProfile(project) {
    const db = (0, database_1.getDb)();
    ensureCodePatternTable();
    const row = db.prepare('SELECT * FROM developer_profiles WHERE project = ?').get(project);
    if (!row)
        return null;
    return {
        namingStyle: String(row.naming_style || 'unknown'),
        importStyle: String(row.import_style || 'unknown'),
        exportStyle: String(row.export_style || 'unknown'),
        errorHandling: String(row.error_handling || 'unknown'),
        functionStyle: String(row.function_style || 'unknown'),
        asyncStyle: String(row.async_style || 'unknown'),
        commentStyle: String(row.comment_style || 'unknown'),
        indentStyle: String(row.indent_style || 'unknown'),
        quoteStyle: String(row.quote_style || 'unknown'),
        semicolonStyle: String(row.semicolon_style || 'unknown'),
        architectureStyle: String(row.architecture_style || 'unknown'),
        testPattern: String(row.test_pattern || 'unknown'),
        topPatterns: JSON.parse(String(row.top_patterns || '[]')),
        strengths: JSON.parse(String(row.strengths || '[]')),
        improvements: JSON.parse(String(row.improvements || '[]')),
    };
}
function getCodePatterns(project, category) {
    const db = (0, database_1.getDb)();
    ensureCodePatternTable();
    let rows;
    if (category) {
        rows = db.prepare('SELECT * FROM code_patterns WHERE project = ? AND category = ? ORDER BY count DESC').all(project, category);
    }
    else {
        rows = db.prepare('SELECT * FROM code_patterns WHERE project = ? ORDER BY count DESC').all(project);
    }
    return rows.map(r => ({
        type: String(r.pattern_type),
        category: String(r.category),
        value: String(r.pattern_value),
        count: Number(r.count),
        trustScore: Number(r.trust_score),
    }));
}
function formatScanReport(result) {
    const lines = [];
    lines.push(`Codebase Scan — ${result.project}`);
    lines.push(`Scanned: ${result.scannedAt}`);
    lines.push(`Files: ${result.filesScanned} | Lines: ${result.totalLines.toLocaleString()}`);
    lines.push('');
    const langEntries = Object.entries(result.languages).sort((a, b) => b[1] - a[1]);
    lines.push('Languages:');
    for (const [lang, count] of langEntries) {
        lines.push(`  ${lang}: ${count} files`);
    }
    lines.push('');
    lines.push('Developer Profile:');
    lines.push(`  Naming: ${result.profile.namingStyle}`);
    lines.push(`  Style: ${result.profile.quoteStyle} quotes, ${result.profile.semicolonStyle} semicolons, ${result.profile.indentStyle}`);
    lines.push(`  Functions: ${result.profile.functionStyle}, async: ${result.profile.asyncStyle}`);
    lines.push(`  Errors: ${result.profile.errorHandling}`);
    lines.push(`  Architecture: ${result.profile.architectureStyle}`);
    lines.push(`  Testing: ${result.profile.testPattern}`);
    lines.push(`  Docs: ${result.profile.commentStyle}`);
    lines.push('');
    if (result.profile.strengths.length > 0) {
        lines.push('Strengths:');
        for (const s of result.profile.strengths)
            lines.push(`  + ${s}`);
    }
    if (result.profile.improvements.length > 0) {
        lines.push('Improvements:');
        for (const i of result.profile.improvements)
            lines.push(`  ! ${i}`);
    }
    lines.push('');
    const topCategories = new Map();
    for (const p of result.patterns) {
        const existing = topCategories.get(p.category) || [];
        existing.push(p);
        topCategories.set(p.category, existing);
    }
    lines.push('Patterns by Category:');
    for (const [cat, catPatterns] of topCategories) {
        lines.push(`  ${cat}:`);
        for (const p of catPatterns.slice(0, 5)) {
            lines.push(`    ${p.value} (${p.count}x, ${p.trustScore}%)`);
        }
    }
    return lines.join('\n');
}
function formatScanReportCompact(result) {
    const lines = [];
    lines.push(`${result.project}: ${result.filesScanned} files, ${result.totalLines.toLocaleString()} lines`);
    const langEntries = Object.entries(result.languages).sort((a, b) => b[1] - a[1]).slice(0, 5);
    lines.push(`Stack: ${langEntries.map(([l, c]) => `${l}(${c})`).join(', ')}`);
    const p = result.profile;
    lines.push(`Style: ${p.quoteStyle} quotes, ${p.semicolonStyle} semis, ${p.indentStyle}, ${p.functionStyle} functions`);
    lines.push(`Errors: ${p.errorHandling} | Arch: ${p.architectureStyle} | Tests: ${p.testPattern}`);
    if (p.strengths.length > 0)
        lines.push(`Strengths: ${p.strengths.join(', ')}`);
    if (p.improvements.length > 0)
        lines.push(`Improve: ${p.improvements.join(', ')}`);
    return lines.join('\n');
}
const BLIND_SPOT_SEVERITY = {
    'blind_spot_async_notry': { severity: 95, reason: 'Unhandled async errors can crash production' },
    'blind_spot_hardcoded_secret': { severity: 90, reason: 'Secrets in code are a security vulnerability' },
    'blind_spot_n_plus_one': { severity: 85, reason: 'N+1 queries cause performance degradation' },
    'blind_spot_raw_sql': { severity: 80, reason: 'Raw SQL is vulnerable to injection attacks' },
    'blind_spot_empty_catch': { severity: 75, reason: 'Swallowed errors hide bugs' },
    'blind_spot_null_check': { severity: 70, reason: 'Missing null checks cause runtime crashes' },
    'blind_spot_no_validation': { severity: 65, reason: 'Missing input validation is a security risk' },
    'blind_spot_deep_nesting': { severity: 60, reason: 'Deep nesting reduces readability and maintainability' },
    'blind_spot_any_type': { severity: 55, reason: 'TypeScript any type defeats type safety' },
    'blind_spot_missing_types': { severity: 50, reason: 'Missing return types reduce code clarity' },
    'blind_spot_console_log': { severity: 30, reason: 'Console logs in production clutter output' },
};
function prioritizeBlindSpots(patterns, maxResults = 5) {
    const blindSpots = patterns.filter(p => p.category === 'blind_spots' || p.type.startsWith('blind_spot_'));
    const prioritized = blindSpots.map(p => {
        const severity = BLIND_SPOT_SEVERITY[p.type] || { severity: 50, reason: 'Unknown blind spot type' };
        // Score = severity * count * trustScore
        const score = severity.severity * (p.count / 100) * (p.trustScore / 100);
        let priority;
        if (score >= 70)
            priority = 'critical';
        else if (score >= 50)
            priority = 'high';
        else if (score >= 30)
            priority = 'medium';
        else
            priority = 'low';
        return {
            type: p.type,
            category: p.category,
            value: p.value,
            count: p.count,
            trustScore: p.trustScore,
            priority,
            reason: severity.reason,
        };
    });
    // Sort by score descending
    prioritized.sort((a, b) => {
        const scoreA = (BLIND_SPOT_SEVERITY[a.type]?.severity || 50) * a.count * a.trustScore;
        const scoreB = (BLIND_SPOT_SEVERITY[b.type]?.severity || 50) * b.count * b.trustScore;
        return scoreB - scoreA;
    });
    return prioritized.slice(0, maxResults);
}
function formatPrioritizedBlindSpots(spots) {
    if (spots.length === 0)
        return 'No blind spots detected.';
    const lines = [];
    lines.push('Top Blind Spots (prioritized by severity):');
    lines.push('');
    for (const [i, spot] of spots.entries()) {
        const priorityIcon = spot.priority === 'critical' ? '🔴' : spot.priority === 'high' ? '🟠' : spot.priority === 'medium' ? '🟡' : '🟢';
        lines.push(`${i + 1}. ${priorityIcon} [${spot.priority.toUpperCase()}] ${spot.value}`);
        lines.push(`   Count: ${spot.count}x | Trust: ${spot.trustScore}%`);
        lines.push(`   Why: ${spot.reason}`);
        lines.push('');
    }
    return lines.join('\n');
}
//# sourceMappingURL=code-scanner.js.map