vibe-code-build
Version:
Real-time code monitoring with teaching explanations, CLAUDE.md compliance checking, and interactive chat
294 lines (248 loc) ⢠12.3 kB
JavaScript
import chalk from 'chalk';
import { themeManager } from './theme-manager.js';
import { aiCodeAnalyzer } from './ai-code-analyzer.js';
/**
* Unified Insight Engine with three modes:
* - basic: Original simple insights
* - detailed: Enhanced educational analysis
* - optimized: Token-efficient insights
*/
export class InsightEngine {
constructor() {
this.mode = 'optimized'; // default mode
// Shared patterns for all modes
this.patterns = {
stateManagement: /setState|useState|state\s*=/,
apiIntegration: /fetch|axios|api|http/i,
authentication: /auth|login|token|session/i,
database: /query|select|insert|update|delete|mongoose|sequelize/i,
errorHandling: /try|catch|error|throw/i,
validation: /validate|check|verify|sanitize/i,
performance: /memo|cache|Cache|optimize|debounce|throttle|performance/i,
security: /password|secret|key|encrypt|hash/i,
async: /async|await|promise|then/i,
hooks: /use[A-Z]\w+/,
testing: /test|spec|expect|jest|mocha/i
};
}
setMode(mode) {
return this.mode = mode;
}
getMode() {
return this.mode;
}
analyzeChange(context) {
// Check if this looks like AI-generated code
const { diff } = context;
if (diff && this.looksLikeAICode(diff)) {
return aiCodeAnalyzer.analyzeAICode(context);
}
// Otherwise use optimized mode
return this.optimizedAnalysis(context);
}
looksLikeAICode(diff) {
// Quick heuristics to detect AI-generated code
const addedLines = diff.split('\n')
.filter(line => line.startsWith('+') && !line.startsWith('+++'))
.join('\n');
// AI code often has these patterns
const aiIndicators = [
/try\s*{[\s\S]*?}\s*catch/, // Error handling
/if\s*\([^)]*\)\s*{[\s\S]*?return/, // Validation checks
/async[\s\S]*?await/, // Modern async
/\/\/ [A-Z]/, // Proper comments
/console\.(log|error)/, // Logging
/\?\./, // Optional chaining
/const\s+{.*?}\s*=/ // Destructuring
];
const matches = aiIndicators.filter(pattern => pattern.test(addedLines)).length;
return matches >= 2;
}
// Optimized mode - only explain the diff
optimizedAnalysis(context) {
const { diff, filename, type } = context;
const colors = themeManager.getColors();
const added = (diff.match(/^\+[^+]/gm) || []).length;
const removed = (diff.match(/^-[^-]/gm) || []).length;
let output = '';
// File and change count
output += colors.primary(`\nš ${filename}: ${added} additions, ${removed} deletions\n`);
// Simple explanation of what changed
if (diff) {
const explanation = this.explainDiffChanges(context);
if (explanation) {
output += colors.muted(`\n ${explanation}\n`);
}
}
return output;
}
explainDiffChanges(context) {
const { diff, filename } = context;
const lines = diff.split('\n');
const addedLines = lines.filter(l => l.startsWith('+') && !l.startsWith('+++'));
const removedLines = lines.filter(l => l.startsWith('-') && !l.startsWith('---'));
const addedCode = addedLines.map(l => l.substring(1).trim()).join(' ');
const removedCode = removedLines.map(l => l.substring(1).trim()).join(' ');
// More detailed explanations
let explanation = '';
// Check for specific patterns and provide detailed explanations
if (addedCode.includes('BuildChecker') || addedCode.includes('DependencyChecker') ||
addedCode.includes('SecurityChecker') || addedCode.includes('PerformanceOptimizer')) {
explanation = 'Added comprehensive code quality checking modules:\n';
if (addedCode.includes('BuildChecker')) {
explanation += ' ⢠BuildChecker: Verifies if project builds, runs TypeScript checks, and linting\n';
}
if (addedCode.includes('DependencyChecker')) {
explanation += ' ⢠DependencyChecker: Scans for vulnerabilities and outdated packages\n';
}
if (addedCode.includes('SecurityChecker')) {
explanation += ' ⢠SecurityChecker: Detects dangerous patterns and exposed secrets\n';
}
if (addedCode.includes('PerformanceOptimizer')) {
explanation += ' ⢠PerformanceOptimizer: Analyzes bundle sizes and SEO issues\n';
}
return explanation.trim();
}
if (addedCode.includes('checkGodMode') || addedCode.includes('god mode')) {
return 'Added AI god mode detection to identify dangerous code patterns like:\n' +
' ⢠System deletion commands (rm -rf /)\n' +
' ⢠Dynamic code execution (eval, Function)\n' +
' ⢠Process termination and infinite loops';
}
if (addedCode.includes('checkSecrets') || addedCode.includes('exposed secrets')) {
return 'Added secret detection to find exposed credentials:\n' +
' ⢠API keys and tokens\n' +
' ⢠Passwords and authentication data\n' +
' ⢠Database connection strings';
}
if (addedCode.includes('formatResults') || addedCode.includes('CheckFormatter')) {
return 'Added beautiful output formatting for check results with:\n' +
' ⢠Color-coded severity levels\n' +
' ⢠Progress indicators and health scores\n' +
' ⢠Actionable recommendations';
}
if (addedCode.includes('todo') || addedCode.includes('Todo')) {
return 'Added todo list functionality with:\n' +
' ⢠Task creation and deletion\n' +
' ⢠Priority levels (high/medium/low)\n' +
' ⢠Progress tracking and completion status';
}
if (addedCode.includes('async') && addedCode.includes('await')) {
const asyncMatch = addedCode.match(/async\s+(\w+)/);
const funcName = asyncMatch ? asyncMatch[1] : 'function';
return `Added asynchronous ${funcName} for non-blocking operations:\n` +
' ⢠Prevents UI freezing during long operations\n' +
' ⢠Enables parallel execution of tasks\n' +
' ⢠Better error handling with try/catch';
}
if (addedCode.includes('try') && addedCode.includes('catch')) {
return 'Added error handling to prevent crashes:\n' +
' ⢠Gracefully handles failures\n' +
' ⢠Provides user-friendly error messages\n' +
' ⢠Enables debugging with error logging';
}
// Enhanced function detection
if (addedCode.match(/function|const.*=.*\(|=>|class/)) {
const functionMatch = addedCode.match(/(function\s+(\w+)|const\s+(\w+)|\s+(\w+)\s*(?:=|:))/);
if (functionMatch) {
const funcName = functionMatch[2] || functionMatch[3] || functionMatch[4] || 'function';
// Try to understand what the function does
if (funcName.includes('check') || funcName.includes('Check')) {
return `Added ${funcName} to validate and analyze code quality`;
}
if (funcName.includes('format') || funcName.includes('Format')) {
return `Added ${funcName} to format output for better readability`;
}
if (funcName.includes('handle') || funcName.includes('Handle')) {
return `Added ${funcName} to handle user interactions and events`;
}
if (funcName.includes('display') || funcName.includes('Display')) {
return `Added ${funcName} to render UI elements and information`;
}
return `Added ${funcName} function to extend functionality`;
}
}
// Import analysis
if (addedCode.includes('import') || addedCode.includes('require')) {
const importMatch = addedCode.match(/import.*from\s+['"]([^'"]+)['"]|require\(['"]([^'"]+)['"]\)/);
if (importMatch) {
const module = importMatch[1] || importMatch[2];
if (module.includes('chalk')) return 'Added chalk for colorful terminal output';
if (module.includes('ora')) return 'Added ora for elegant loading spinners';
if (module.includes('boxen')) return 'Added boxen for beautiful boxed terminal output';
return `Added ${module} module to enhance functionality`;
}
}
// Default to category-based explanation
const category = this.detectChangeCategory(context);
return this.getCategoryExplanation(category, addedLines.length, removedLines.length);
}
getCategoryExplanation(category, addedCount, removedCount) {
const explanations = {
'feature': `Added new feature (${addedCount} lines):\n ⢠Extends application capabilities\n ⢠Provides new functionality for users`,
'fix': `Fixed a bug or issue:\n ⢠Resolves existing problems\n ⢠Improves stability and reliability`,
'refactor': `Refactored code for better structure:\n ⢠Improves code readability\n ⢠Makes future changes easier`,
'performance': `Optimized performance:\n ⢠Reduces execution time\n ⢠Improves resource usage`,
'security': `Enhanced security:\n ⢠Prevents vulnerabilities\n ⢠Protects user data`,
'docs': `Updated documentation:\n ⢠Improves code understanding\n ⢠Helps future developers`,
'test': `Updated test coverage:\n ⢠Ensures code reliability\n ⢠Prevents regressions`
};
return explanations[category] || `Modified code (${addedCount} additions, ${removedCount} deletions)`;
}
detectChangeCategory(context) {
const { diff, type, filename } = context;
if (type === 'added') return 'feature';
if (type === 'deleted') return 'cleanup';
if (filename.includes('test') || filename.includes('spec')) return 'test';
if (filename.includes('.md')) return 'docs';
// Analyze the diff content for more accurate categorization
if (diff) {
const addedLines = diff.split('\n').filter(l => l.startsWith('+') && !l.startsWith('+++')).join('\n');
const removedLines = diff.split('\n').filter(l => l.startsWith('-') && !l.startsWith('---')).join('\n');
// Feature detection
if (addedLines.includes('new ') || addedLines.includes('constructor') ||
addedLines.match(/\w+Mode/) || addedLines.match(/display\w+/) ||
addedLines.match(/handle\w+/) || addedLines.includes('// Todo') ||
addedLines.includes('todos') || addedLines.includes('selectedTodoIndex')) {
return 'feature';
}
// Specific keywords
if (diff.includes('fix')) return 'fix';
if (diff.includes('perf')) return 'performance';
if (diff.includes('security')) return 'security';
// Bug fixes usually have small targeted changes
const addedCount = (diff.match(/^\+[^+]/gm) || []).length;
const removedCount = (diff.match(/^-[^-]/gm) || []).length;
if (addedCount > 5 || (addedCount > removedCount * 2)) {
return 'feature';
}
}
return 'refactor';
}
getCategoryInfo(category) {
const categories = {
feature: { icon: 'āØ', label: 'New Feature', color: 'green' },
fix: { icon: 'š', label: 'Bug Fix', color: 'red' },
refactor: { icon: 'ā»ļø', label: 'Refactoring', color: 'blue' },
performance: { icon: 'ā”', label: 'Performance', color: 'yellow' },
security: { icon: 'š', label: 'Security', color: 'red' },
docs: { icon: 'š', label: 'Documentation', color: 'gray' },
test: { icon: 'š§Ŗ', label: 'Testing', color: 'cyan' },
cleanup: { icon: 'š§¹', label: 'Cleanup', color: 'gray' }
};
return categories[category] || { icon: 'š¦', label: 'Change', color: 'white' };
}
detectPatterns(context) {
const { diff, content } = context;
const detected = [];
const searchText = diff || content || '';
for (const [name, pattern] of Object.entries(this.patterns)) {
if (pattern.test(searchText)) {
detected.push(name);
}
}
return detected;
}
}
// Export singleton instance
export const insightEngine = new InsightEngine();