"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getFileCategory = exports.shouldSkipLLM = exports.filterFilesForLLM = exports.logTokenSavings = exports.generateConsolidatedRecommendations = exports.generateRecommendation = exports.classifyFiles = exports.classifyFile = exports.LOCKFILES = exports.IGNORED_PATTERNS = void 0; exports.IGNORED_PATTERNS = [ /node_modules\//, /dist\//, /build\//, /\.next\//, /coverage\//, /\.min\.js$/, /\.bundle\.js$/, /\.generated\./, /vendor\//, /\.map$/, /\.snap$/, /\.lock$/, /\.md$/, // Skip markdown files unless explicitly requested /__pycache__\//, /\.pyc$/, /\.egg-info\//, /target\//, // Rust/Java build output /out\//, // TypeScript/JavaScript build output /\.cache\//, /\.vscode\//, /\.idea\//, /\.DS_Store$/, /Thumbs\.db$/ ]; exports.LOCKFILES = [ 'package-lock.json', 'pnpm-lock.yaml', 'yarn.lock', 'Cargo.lock', 'poetry.lock', 'requirements.txt', 'Pipfile.lock', 'go.sum', 'composer.lock' ]; const TOKENS_PER_LINE = 4; const TOKENS_PER_KB = 150; const classifyFile = (filename) => { const lowerFilename = filename.toLowerCase(); if (lowerFilename.includes('node_modules/')) { return { filename, category: 'node_modules', skipLLM: true, reason: 'node_modules directory should not be committed to Git' }; } const isLockfile = exports.LOCKFILES.some(lockfile => { const lockfileLower = lockfile.toLowerCase(); return (lowerFilename.endsWith(lockfileLower) || lowerFilename.includes(lockfileLower)); }); if (isLockfile) { return { filename, category: 'lockfile', skipLLM: true, reason: 'Dependency lockfile - skipping deep AI analysis' }; } for (const pattern of exports.IGNORED_PATTERNS) { if (pattern.test(filename)) { return { filename, category: 'generated', skipLLM: true, reason: 'Generated or build artifact' }; } } return { filename, category: 'source', skipLLM: false }; }; exports.classifyFile = classifyFile; const classifyFiles = (filenames) => { const classifications = []; const metrics = { skippedFiles: 0, skippedTokensEstimate: 0, categories: {} }; for (const filename of filenames) { const classification = (0, exports.classifyFile)(filename); classifications.push(classification); if (classification.skipLLM) { metrics.skippedFiles++; // Track by category metrics.categories[classification.category] = (metrics.categories[classification.category] || 0) + 1; // Estimate tokens saved (rough estimate based on file path length) // In a real implementation, this would use actual file size const estimatedTokens = Math.max(1000, filename.length * TOKENS_PER_LINE); metrics.skippedTokensEstimate += estimatedTokens; } } return { classifications, metrics }; }; exports.classifyFiles = classifyFiles; const generateRecommendation = (classification) => { if (!classification.skipLLM) { return null; } switch (classification.category) { case 'node_modules': return `## 💡 Recommendation \`node_modules/\` was detected in this pull request. This directory should usually not be committed to Git. ### Suggested Fix Add this to \`.gitignore\`: \`\`\`gitignore node_modules/ \`\`\` ### AI Agent Prompt Remove committed node_modules files and update .gitignore to exclude them permanently.`; case 'lockfile': return `## ℹ️ Optimization Suggestion Large dependency lockfile changes detected. Consider separating dependency updates into dedicated PRs to reduce review noise and improve review clarity.`; case 'generated': return `## 💡 Recommendation Generated/build artifacts were detected and skipped from AI review to improve review performance and reduce unnecessary noise.`; default: return `## ℹ️ Information File \`${classification.filename}\` was skipped from AI review: ${classification.reason || 'No specific reason provided'}`; } }; exports.generateRecommendation = generateRecommendation; const generateConsolidatedRecommendations = (classifications) => { const recommendations = []; const seenCategories = new Set(); // Group by category to avoid duplicate recommendations const byCategory = new Map(); for (const classification of classifications) { if (classification.skipLLM) { if (!byCategory.has(classification.category)) { byCategory.set(classification.category, []); } byCategory.get(classification.category).push(classification); } } // Generate one recommendation per category for (const [category, files] of byCategory.entries()) { if (seenCategories.has(category)) continue; seenCategories.add(category); const representative = files[0]; const recommendation = (0, exports.generateRecommendation)(representative); if (recommendation) { // Add file count if multiple files in this category let finalRecommendation = recommendation; if (files.length > 1) { finalRecommendation = recommendation.replace(/was detected/, `(${files.length} files) were detected`); } recommendations.push(finalRecommendation); } } return recommendations; }; exports.generateConsolidatedRecommendations = generateConsolidatedRecommendations; const logTokenSavings = (metrics) => { console.log('REVIEW_OPTIMIZATION', { skippedFiles: metrics.skippedFiles, skippedTokensEstimate: metrics.skippedTokensEstimate, reason: 'File classification filtering', categories: metrics.categories }); // Human-readable summary if (metrics.skippedFiles > 0) { const tokenK = (metrics.skippedTokensEstimate / 1000).toFixed(0); console.log(`Skipped ${metrics.skippedFiles} generated/irrelevant files`); console.log(`Estimated token savings: ${tokenK}k`); } }; exports.logTokenSavings = logTokenSavings; const filterFilesForLLM = (filenames) => { return filenames.filter(filename => !(0, exports.classifyFile)(filename).skipLLM); }; exports.filterFilesForLLM = filterFilesForLLM; const shouldSkipLLM = (filename) => { return (0, exports.classifyFile)(filename).skipLLM; }; exports.shouldSkipLLM = shouldSkipLLM; const getFileCategory = (filename) => { return (0, exports.classifyFile)(filename).category; }; exports.getFileCategory = getFileCategory; //# sourceMappingURL=file-filter.js.map