UNPKG

vibe-code-build

Version:

Real-time code monitoring with teaching explanations, CLAUDE.md compliance checking, and interactive chat

2,328 lines • 88 kB
import { watch } from 'chokidar';
import chalk from 'chalk';
import { readFile } from 'fs/promises';
import path from 'path';
import { execSync } from 'child_process';
import readline from 'readline';
import { RulesChecker } from './rules-checker.js';
import { SeniorDevAdvisor } from './senior-dev-advisor.js';
import { insightEngine } from './insight-engine-unified.js';
import { TypeWriter } from './type-writer.js';
import { tokenAnalyzer } from './token-analyzer.js';
import { BuildChecker } from './build-checker.js';
import { DependencyChecker } from './dependency-checker.js';
import { ClaudeChecker } from './claude-checker.js';
import { SecurityChecker } from './security-checker.js';
import { PerformanceOptimizer } from './performance-optimizer.js';
import { CheckFormatter } from './check-formatter.js';
import { SEOChecker } from './seo-checker.js';

export class UnifiedMonitor {
  constructor(projectPath, options = {}) {
    this.projectPath = projectPath;
    this.options = options;
    this.modes = ['diff', 'rules', 'stats', 'checks', 'seo', 'security', 'speed', 'god'];
    this.currentModeIndex = 0;
    this.currentMode = this.modes[this.currentModeIndex];
    
    // Shared state
    this.updates = [];
    this.updateCount = 0;
    this.currentContext = null;
    this.isProcessingInput = false;
    this.watcher = null;
    this.lastDisplayedUpdate = null;
    this.updateHistoryPage = 0;
    this.viewingHistory = false;
    this.previousFileContents = {};
    
    // Add mode switching protection
    this.isSwitchingMode = false;
    this.lastModeSwitchTime = 0;
    this.isExiting = false;
    
    // Stats tracking
    this.stats = {
      sessionStart: Date.now(),
      totalFiles: 0,
      linesAdded: 0,
      linesRemoved: 0,
      filesModified: new Set(),
      languageStats: {},
      streak: 0,
      lastActive: Date.now()
    };
    
    
    // Initialize components
    this.rulesChecker = new RulesChecker(projectPath);
    this.seniorDev = new SeniorDevAdvisor();
    this.typeWriter = new TypeWriter();
    
    // Initialize checkers for checks mode with silent option to prevent spinner conflicts
    this.checkers = {
      build: new BuildChecker(projectPath, { silent: true }),
      dependencies: new DependencyChecker(projectPath, { silent: true }),
      claude: new ClaudeChecker(projectPath, { silent: true }),
      security: new SecurityChecker(projectPath, { silent: true }),
      performance: new PerformanceOptimizer(projectPath, { silent: true })
    };
    this.checkFormatter = new CheckFormatter();
    this.checkResults = null;
    this.lastCheckTime = null;
    this.isRunningChecks = false;
    
    // SEO mode specific state
    this.seoResults = null;
    this.seoHistory = [];
    this.lastSEOCheck = null;
    
    // Security mode specific state
    this.securityThreats = [];
    this.securityScore = 0;
    this.isMonitoringSecurity = true;
    
    // Speed mode specific state
    this.performanceMetrics = {};
    this.buildMetrics = [];
    this.lastSpeedCheck = null;
    
    // God mode specific state
    this.godModeData = {
      health: 0,
      criticalIssues: [],
      trends: {},
      autoRefresh: false,
      refreshInterval: null
    };
    
    // Set up readline with keypress events
    this.setupReadline();
  }

  setupReadline() {
    this.rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout,
      prompt: this.getPrompt(),
      terminal: true
    });

    // Enable keypress events
    if (process.stdin.isTTY) {
      try {
        process.stdin.setRawMode(true);
      } catch (e) {
        console.error('Warning: Could not set raw mode:', e.message);
      }
    }
    
    readline.emitKeypressEvents(process.stdin, this.rl);
    
    // Handle keypress events with better escape sequence filtering
    // Remove any existing keypress listeners to prevent duplicates
    process.stdin.removeAllListeners('keypress');
    
    process.stdin.on('keypress', async (str, key) => {
      // Ensure we're still active and not exiting
      if (!this.rl || this.rl.closed || this.isExiting) {
        return;
      }
      
      // Filter out raw escape sequences and prevent them from accumulating
      if (str && (str.includes('\x1B[Z') || str === '\x1B[Z')) {
        // This is a raw Shift+Tab escape sequence, process it properly
        if (!this.isSwitchingMode && !key) {
          // Only handle if we didn't get a proper key object
          await this.handleModeSwitch();
        }
        return;
      }
      
      // Also check for sequences that might slip through
      if (str && str.match(/^\x1B\[/)) {
        // This is an escape sequence, ignore it
        return;
      }
      
      // Prevent processing during mode switching
      if (this.isSwitchingMode) {
        return;
      }
      
      // No special handling needed during input - readline.question handles it
      
      // Clear any stray input for non-interactive modes
      if (this.currentMode !== 'diff' && this.currentMode !== 'rules' && str && !key.ctrl) {
        process.stdout.write('\r\x1B[K');
      }
      
      // Normal keypress handling
      if (key && key.name === 'tab' && key.shift) {
        await this.handleModeSwitch();
      } else if (key && key.ctrl && key.name === 'c') {
        this.handleExit();
      } else if (this.currentMode === 'checks') {
        await this.handleChecksKeypress(key, str);
      } else if (this.currentMode === 'seo') {
        await this.handleSEOKeypress(key, str);
      } else if (this.currentMode === 'security') {
        await this.handleSecurityKeypress(key, str);
      } else if (this.currentMode === 'speed') {
        await this.handleSpeedKeypress(key, str);
      } else if (this.currentMode === 'god') {
        await this.handleGodModeKeypress(key, str);
      } else if (this.currentMode === 'diff' && this.viewingHistory) {
        await this.handleHistoryNavigation(key);
      } else if (this.currentMode === 'diff' && key && key.name === 'h' && !this.viewingHistory) {
        // Press 'h' to view history
        this.viewingHistory = true;
        this.updateHistoryPage = 0;
        await this.displayUpdateHistory();
      } else if (this.currentMode === 'diff' && key && key.name === 't') {
        // Press 't' to cycle through insight modes
        const modes = ['basic', 'detailed', 'optimized'];
        const currentMode = insightEngine.getMode();
        const currentIndex = modes.indexOf(currentMode);
        const nextMode = modes[(currentIndex + 1) % modes.length];
        insightEngine.setMode(nextMode);
        const colors = {
          error: chalk.red,
          warning: chalk.yellow,
          success: chalk.green,
          info: chalk.blue,
          muted: chalk.gray,
          primary: chalk.white,
          secondary: chalk.cyan,
          header: chalk.bold.blue,
          highlight: chalk.bgBlue.white
        };
        console.log(colors.info(`\nšŸ”„ Switched to ${nextMode} insights mode\n`));
        await this.updateDisplay();
      }
      // Remove the manual character writing - readline handles this
    });
  }

  async handleModeSwitch() {
    // Prevent rapid mode switching
    const now = Date.now();
    if (this.isSwitchingMode || (now - this.lastModeSwitchTime) < 300) {
      return; // Debounce: ignore if switching or less than 300ms since last switch
    }
    
    // Safety check: prevent infinite switching
    if (!this.switchCount) this.switchCount = 0;
    this.switchCount++;
    
    // Reset counter after 5 seconds of no switching
    if (this.switchResetTimer) clearTimeout(this.switchResetTimer);
    this.switchResetTimer = setTimeout(() => {
      this.switchCount = 0;
    }, 5000);
    
    // Prevent excessive switching that might crash the app
    if (this.switchCount > 20) {
      console.log('\nāš ļø  Too many rapid mode switches detected. Please wait a moment...');
      this.switchCount = 0;
      return;
    }
    
    this.isSwitchingMode = true;
    this.lastModeSwitchTime = now;
    
    try {
      // Clear any pending input from readline with error handling
      if (this.rl && !this.rl.closed) {
        try {
          this.rl.clearLine(process.stdout, 0);
          this.rl.pause();
        } catch (e) {
          // Ignore errors if readline is in bad state
        }
      }
      
      // Clear any lingering text
      process.stdout.write('\r\x1B[K');
      
      // Switch to next mode
      this.currentModeIndex = (this.currentModeIndex + 1) % this.modes.length;
      this.currentMode = this.modes[this.currentModeIndex];
      
      // Clear screen before switching
      this.clearScreen();
      
      // Update display
      await this.updateDisplay();
      
      // Show mode switch notification
      this.showModeNotification();
      
      // Resume readline and update prompt with error handling
      if (this.rl && !this.rl.closed) {
        try {
          this.rl.resume();
          this.rl.setPrompt(this.getPrompt());
          
          // Only show prompt for modes that need it
          if (this.currentMode === 'diff' || this.currentMode === 'rules') {
            this.rl.prompt();
          }
        } catch (e) {
          // If readline is corrupted, recreate it
          console.error('Readline error, recreating interface...');
          this.setupReadline();
        }
      }
    } catch (error) {
      console.error('Error switching modes:', error);
      // Try to recover by recreating readline if needed
      if (this.rl && this.rl.closed) {
        this.setupReadline();
      }
    } finally {
      this.isSwitchingMode = false;
    }
  }

  
  async handleHistoryNavigation(key) {
    if (!key) return;
    
    const pageSize = 5;
    const totalPages = Math.ceil(this.updates.length / pageSize);
    
    if (key.name === 'escape' || key.name === 'q') {
      // Return to live mode
      this.viewingHistory = false;
      await this.updateDisplay();
    } else if ((key.name === 'left' || key.name === 'up') && this.updateHistoryPage < totalPages - 1) {
      // Older updates (page increases)
      this.updateHistoryPage++;
      await this.displayUpdateHistory();
    } else if ((key.name === 'right' || key.name === 'down') && this.updateHistoryPage > 0) {
      // Newer updates (page decreases)
      this.updateHistoryPage--;
      await this.displayUpdateHistory();
    }
  }
  
  showModeNotification() {
    const modeInfo = {
      'diff': 'šŸ” Diff Mode - Real-time file monitoring with AI explanations',
      'rules': 'šŸ“‹ Rules Mode - CLAUDE.md compliance checking and best practices',
      'stats': 'šŸ“Š Stats Mode - Coding session metrics and productivity insights',
      'checks': 'šŸ” Checks Mode - Build, lint, test, and dependency monitoring',
      'seo': 'šŸ” SEO Mode - Search engine optimization scoring and recommendations',
      'security': 'šŸ”’ Security Mode - Vulnerability scanning and threat detection',
      'speed': '⚔ Speed Mode - Performance analysis and optimization tips',
      'god': 'šŸ‘ļø God Mode - All monitoring systems active simultaneously'
    };
    
    const colors = {
          error: chalk.red,
          warning: chalk.yellow,
          success: chalk.green,
          info: chalk.blue,
          muted: chalk.gray,
          primary: chalk.white,
          secondary: chalk.cyan,
          header: chalk.bold.blue,
          highlight: chalk.bgBlue.white,
          accent: chalk.magenta
        };
    console.log('\n' + colors.success(`✨ Mode switched to: ${modeInfo[this.currentMode] || this.currentMode}`));
    console.log(colors.muted('Loading interface...'));
    console.log(colors.muted('Press Shift+Tab to switch modes • Ctrl+C to exit\n'));
  }

  getPrompt() {
    const prompts = {
      'diff': '',      // No prompt needed - just monitoring
      'rules': '',     // No prompt needed - just monitoring  
      'stats': '',     // No prompt needed
      'checks': '',    // No prompt needed - keyboard controlled
      'seo': '',       // No prompt needed - keyboard controlled
      'security': '',  // No prompt needed - keyboard controlled
      'speed': '',     // No prompt needed - keyboard controlled
      'god': ''        // No prompt needed - keyboard controlled
    };
    return prompts[this.currentMode] || '';
  }

  async start() {
    // Add global error handlers to prevent unexpected exits
    process.on('uncaughtException', (error) => {
      console.error('Uncaught Exception:', error);
      // Try to recover instead of exiting
      if (this.rl && this.rl.closed) {
        this.setupReadline();
      }
    });
    
    process.on('unhandledRejection', (reason, promise) => {
      console.error('Unhandled Rejection at:', promise, 'reason:', reason);
      // Don't exit on unhandled promise rejections
    });
    
    // Log unexpected exits for debugging
    process.on('exit', (code) => {
      if (!this.isExiting && code !== 0) {
        console.error('Unexpected exit with code:', code);
      }
    });
    
    // Theme loading removed
    const colors = {
          error: chalk.red,
          warning: chalk.yellow,
          success: chalk.green,
          info: chalk.blue,
          muted: chalk.gray,
          primary: chalk.white,
          secondary: chalk.cyan,
          header: chalk.bold.blue,
          highlight: chalk.bgBlue.white,
          accent: chalk.magenta
        };
    
    // Clear screen and show ASCII logo
    console.clear();
    const logo = colors.primary(`
╦  ╦╦╔╗ ╔═╗  ╔═╗╔═╗╔╦╗╔═╗  ╔╗ ╦ ╦╦╦  ╔╦╗
ā•šā•—ā•”ā•ā•‘ā• ā•©ā•—ā•‘ā•£ā”€ā”€ā”€ā•‘  ā•‘ ā•‘ ║║║╣───╠╩╗║ ā•‘ā•‘ā•‘   ā•‘ā•‘
 ā•šā• ā•©ā•šā•ā•ā•šā•ā•  ā•šā•ā•ā•šā•ā•ā•ā•©ā•ā•šā•ā•  ā•šā•ā•ā•šā•ā•ā•©ā•©ā•ā•ā•ā•©ā•
    `);
    console.log(logo);
    console.log(colors.muted('Real-time code monitoring with AI insights\n'));
    
    // Small pause to let logo display
    await new Promise(resolve => setTimeout(resolve, 500));
    
    // Quick initialization
    await this.rulesChecker.initialize();
    
    // Quick checks
    try {
      execSync('git status', { cwd: this.projectPath, stdio: 'ignore' });
      console.log(colors.success('āœ“ Git repository detected'));
    } catch {
      console.log(colors.muted('ℹ Not a git repository (limited diff support)'));
    }
    
    const fileCount = await this.countProjectFiles();
    console.log(colors.success(`āœ“ Monitoring ${fileCount} files`));
    console.log(colors.success('āœ“ Ready to analyze code changes\n'));
    
    // Show initial mode (interface will be displayed after mode switch)
    console.log(colors.secondary('šŸ” Starting in Diff Mode...'));
    
    // Set up file watcher
    this.setupFileWatcher();
    
    // Set up input handling
    this.setupInputHandling();
    
    // Initial display
    await this.updateDisplay();
  }

  async showWelcome() {
    // No longer needed - startup is now simple and direct
  }

  setupFileWatcher() {
    this.watcher = watch(this.projectPath, {
      ignored: [
        /node_modules/,
        /\.git/,
        /\.DS_Store/,
        /\.next/,
        /dist/,
        /build/,
        /coverage/,
        /\.cache/,
        /tmp/,
        /temp/,
        /\.log$/,
        /\.lock$/,
        /\.bin$/,
        /\.exe$/,
        /\.dll$/,
        /\.so$/,
        /\.dylib$/,
        /\.zip$/,
        /\.tar/,
        /\.gz$/,
        /\.jpg$/,
        /\.png$/,
        /\.gif$/,
        /\.pdf$/,
        /\.mp4$/,
        /\.mov$/,
        /\.avi$/,
        /\.mp3$/,
        /\.wav$/,
        // Skip large data files
        /\.csv$/,
        /\.json$/ // Skip large JSON files for now
      ],
      persistent: true,
      ignoreInitial: true
    });

    this.watcher
      .on('add', path => this.handleFileChange('added', path))
      .on('change', path => this.handleFileChange('modified', path))
      .on('unlink', path => this.handleFileChange('deleted', path));
  }

  setupInputHandling() {
    // No input handling needed for monitoring modes
    this.rl.on('line', async (input) => {
      // Clear any input line and don't show prompt
      process.stdout.write('\r\x1B[K');
    });
  }

  async handleFileChange(type, filePath) {
    this.updateCount++;
    
    const filename = path.basename(filePath);
    const ext = path.extname(filename).slice(1);
    
    // Store context
    this.currentContext = {
      type,
      filename,
      filePath,
      ext,
      timestamp: new Date().toLocaleTimeString()
    };
    
    // Get file content and diff for modified files
    if (type !== 'deleted') {
      try {
        // Check file size first - skip huge files
        const stats = await import('fs/promises').then(fs => fs.stat(filePath));
        if (stats.size > 1024 * 1024) { // Skip files > 1MB
          console.log(`āš ļø  Skipping large file: ${filename} (${Math.round(stats.size/1024)}KB)`);
          return;
        }
        
        this.currentContext.content = await readFile(filePath, 'utf-8');
        
        // Truncate very long content
        if (this.currentContext.content.length > 50000) {
          this.currentContext.content = this.currentContext.content.substring(0, 50000) + '\n... (truncated)';
        }
        
        if (type === 'modified') {
          try {
            // First try unstaged changes (what most developers are working on)
            const diffUnstaged = execSync(`git diff -- "${filePath}"`, {
              encoding: 'utf8',
              maxBuffer: 512 * 1024, // Reduce buffer size
              cwd: this.projectPath
            });
            if (diffUnstaged && diffUnstaged.trim()) {
              // Truncate very long diffs
              this.currentContext.diff = diffUnstaged.length > 10000 
                ? diffUnstaged.substring(0, 10000) + '\n... (diff truncated)'
                : diffUnstaged;
            } else {
              // If no unstaged changes, try staged changes
              const diff = execSync(`git diff --cached -- "${filePath}"`, {
                encoding: 'utf8',
                maxBuffer: 512 * 1024,
                cwd: this.projectPath
              });
              if (diff && diff.trim()) {
                this.currentContext.diff = diff.length > 10000 
                  ? diff.substring(0, 10000) + '\n... (diff truncated)'
                  : diff;
              }
            }
          } catch (e) {
            // Not in git or no changes - create a manual diff
            if (this.previousFileContents && this.previousFileContents[filePath]) {
              const oldContent = this.previousFileContents[filePath];
              const newContent = this.currentContext.content;
              this.currentContext.diff = this.createSimpleDiff(oldContent, newContent, filename);
            } else {
              // First time seeing this file - show limited content
              const lines = this.currentContext.content.split('\n');
              let diff = `diff --git a/${filename} b/${filename}\n`;
              diff += `--- /dev/null\n`;
              diff += `+++ b/${filename}\n`;
              diff += `@@ -0,0 +1,${Math.min(lines.length, 20)} @@\n`;
              lines.slice(0, 20).forEach(line => {
                diff += `+${line.substring(0, 200)}\n`; // Limit line length
              });
              if (lines.length > 20) {
                diff += `... ${lines.length - 20} more lines\n`;
              }
              this.currentContext.diff = diff;
            }
          }
        } else if (type === 'added') {
          // For new files, create a diff showing limited lines
          const lines = this.currentContext.content.split('\n');
          let diff = `diff --git a/${filename} b/${filename}\n`;
          diff += `new file mode 100644\n`;
          diff += `--- /dev/null\n`;
          diff += `+++ b/${filename}\n`;
          diff += `@@ -0,0 +1,${Math.min(lines.length, 20)} @@\n`;
          lines.slice(0, 20).forEach(line => {
            diff += `+${line.substring(0, 200)}\n`; // Limit line length
          });
          if (lines.length > 20) {
            diff += `... ${lines.length - 20} more lines (truncated)\n`;
          }
          this.currentContext.diff = diff;
        }
      } catch (e) {
        console.log(`āš ļø  Error reading file: ${filename}`);
        return;
      }
    }
    
    // Store content for future diffs (store current content for next comparison)
    if (type !== 'deleted' && this.currentContext.content) {
      // Limit memory usage - only store content for recent files
      const maxStoredFiles = 50;
      if (Object.keys(this.previousFileContents).length > maxStoredFiles) {
        // Remove oldest entries
        const keys = Object.keys(this.previousFileContents);
        keys.slice(0, 10).forEach(key => delete this.previousFileContents[key]);
      }
      
      // For first time seeing a file, capture baseline (truncated)
      if (!this.previousFileContents[filePath]) {
        this.previousFileContents[filePath] = this.currentContext.content.substring(0, 10000);
      } else if (type === 'modified') {
        // Update stored content after processing diff (truncated)
        setTimeout(() => {
          this.previousFileContents[filePath] = this.currentContext.content.substring(0, 10000);
        }, 100);
      }
    }
    
    // Update stats tracking
    this.updateStats(type, filename, this.currentContext);
    
    // Create update object with proper timestamp for sorting
    const update = {
      number: this.updateCount,
      timestamp: this.currentContext.timestamp,
      sortTimestamp: Date.now(), // Add numeric timestamp for accurate sorting
      type,
      filename,
      filePath,
      context: { ...this.currentContext }
    };
    
    // Add to updates
    this.updates.push(update);
    const maxUpdates = 10;
    if (this.updates.length > maxUpdates) {
      this.updates.shift();
    }
    
    // Update display if not processing input
    if (!this.isProcessingInput && this.currentMode === 'diff') {
      // For diff mode, show the new update immediately at the top
      await this.showNewUpdate(update);
    } else if (!this.isProcessingInput) {
      await this.updateDisplay();
    }
  }

  async updateDisplay() {
    // All modes now get proper display
    if (this.currentMode === 'diff') {
      this.clearScreen();
      await this.displayDiffMode();
    } else if (this.currentMode === 'rules') {
      this.clearScreen();
      await this.displayRulesMode();
    } else if (this.currentMode === 'stats') {
      this.clearScreen();
      await this.displayStatsMode();
    } else if (this.currentMode === 'checks') {
      this.clearScreen();
      await this.displayChecksMode();
    } else if (this.currentMode === 'seo') {
      this.clearScreen();
      await this.displaySEOMode();
    } else if (this.currentMode === 'security') {
      this.clearScreen();
      await this.displaySecurityMode();
    } else if (this.currentMode === 'speed') {
      this.clearScreen();
      await this.displaySpeedMode();
    } else if (this.currentMode === 'god') {
      this.clearScreen();
      await this.displayGodMode();
    }
    // diff mode doesn't need updateDisplay - it uses natural terminal flow
  }

  async displayDiffMode() {
    const colors = {
      error: chalk.red,
      warning: chalk.yellow,
      success: chalk.green,
      info: chalk.blue,
      muted: chalk.gray,
      primary: chalk.white,
      secondary: chalk.cyan,
      header: chalk.bold.blue,
      highlight: chalk.bgBlue.white,
      accent: chalk.magenta
    };
    
    console.log(colors.header('šŸ” Vibe Code - Real-time Code Changes'));
    console.log(colors.muted('Live monitoring with AI-powered explanations'));
    console.log(colors.muted('─'.repeat(60)));
    
    // Show monitoring status
    const fileCount = await this.countProjectFiles();
    console.log(colors.success(`šŸ‘€ Actively monitoring ${fileCount} files for changes`));
    console.log(colors.muted('Changes appear instantly with teaching explanations\n'));
    
    if (this.updates.length === 0) {
      console.log(colors.info('   Ready to analyze your next code change...'));
      console.log(colors.muted('   Make changes to any file to see AI explanations'));
    } else {
      // Show recent changes (most recent first)
      console.log(colors.secondary('\nšŸ“‹ Recent Changes:'));
      const recentUpdates = this.updates.slice(-3).reverse();
      for (const update of recentUpdates) {
        const timeAgo = this.getTimeAgo(update.timestamp);
        console.log(colors.muted(`  šŸ“ ${update.file} ${timeAgo}`));
      }
    }
    
    this.showControlsFooter(colors, ['h - View change history', 't - Cycle AI insights']);
  }

  async displayRulesMode() {
    const colors = {
          error: chalk.red,
          warning: chalk.yellow,
          success: chalk.green,
          info: chalk.blue,
          muted: chalk.gray,
          primary: chalk.white,
          secondary: chalk.cyan,
          header: chalk.bold.blue,
          highlight: chalk.bgBlue.white,
          accent: chalk.magenta
        };
    console.log(colors.header('šŸ“‹ Vibe Code - CLAUDE.md Compliance'));
    console.log(colors.muted('Real-time monitoring of best practices and rules'));
    console.log(colors.muted('─'.repeat(60)));
    console.log(colors.muted('\nMost recent changes appear at the top\n'));
    
    if (this.updates.length === 0) {
      console.log(colors.info('   šŸ‘€ Actively monitoring for rule violations...'));
      console.log(colors.muted('   Code changes will be analyzed against CLAUDE.md guidelines'));
      return;
    }
    
    // Show updates with focused AI analysis (most recent first)
    const recentUpdates = this.updates.slice(-3);
    recentUpdates.sort((a, b) => b.sortTimestamp - a.sortTimestamp);
    
    for (const update of recentUpdates) {
      console.log('\n' + colors.muted('─'.repeat(50)));
      console.log(`${this.getUpdateIcon(update.type)} ${colors.primary(update.filename)} ${colors.muted(update.timestamp)}`);
      
      if (update.context.diff && update.type !== 'deleted') {
        // Show the diff first
        console.log('\n' + colors.secondary('šŸ“ Code Changes:'));
        console.log(colors.muted('─'.repeat(50)));
        console.log(this.formatDiff(update.context.diff));
        console.log(colors.muted('─'.repeat(50)));
        
        // Then show AI analysis of the changes
        const insights = insightEngine.analyzeChange(update.context);
        if (insights) {
          console.log(insights);
        } else {
          console.log(colors.muted('   No specific insights for this change'));
        }
      }
    }
  }

  async displayStatsMode() {
    const colors = {
          error: chalk.red,
          warning: chalk.yellow,
          success: chalk.green,
          info: chalk.blue,
          muted: chalk.gray,
          primary: chalk.white,
          secondary: chalk.cyan,
          header: chalk.bold.blue,
          highlight: chalk.bgBlue.white,
          accent: chalk.magenta
        };
    console.log(colors.header('šŸ“Š Vibe Code - Developer Stats'));
    console.log(colors.muted('Real-time coding session metrics and progress'));
    console.log(colors.muted('─'.repeat(60)));
    
    // Session duration
    const sessionDuration = Date.now() - this.stats.sessionStart;
    const minutes = Math.floor(sessionDuration / 60000);
    const seconds = Math.floor((sessionDuration % 60000) / 1000);
    
    console.log(colors.secondary('\nā±ļø  Session Overview:'));
    console.log(colors.muted(`   Active for: ${minutes}m ${seconds}s`));
    console.log(colors.muted(`   Files monitored: ${this.stats.totalFiles}`));
    console.log(colors.muted(`   Files modified: ${this.stats.filesModified.size}`));
    
    // Code changes
    console.log(colors.secondary('\nšŸ“ Code Changes:'));
    const progressBar = this.createProgressBar(this.stats.linesAdded, this.stats.linesAdded + this.stats.linesRemoved);
    console.log(colors.success(`   Lines added: ${this.stats.linesAdded} ${progressBar.added}`));
    console.log(colors.error(`   Lines removed: ${this.stats.linesRemoved} ${progressBar.removed}`));
    console.log(colors.primary(`   Net change: ${this.stats.linesAdded - this.stats.linesRemoved}`));
    
    // Language breakdown
    if (Object.keys(this.stats.languageStats).length > 0) {
      console.log(colors.secondary('\nšŸ’» Languages:'));
      Object.entries(this.stats.languageStats)
        .sort(([,a], [,b]) => b - a)
        .slice(0, 5)
        .forEach(([lang, count]) => {
          const bar = this.createMiniProgressBar(count, Math.max(...Object.values(this.stats.languageStats)));
          console.log(colors.muted(`   ${lang}: ${count} files ${bar}`));
        });
    }
    
    // Productivity metrics
    const linesPerMinute = minutes > 0 ? Math.round((this.stats.linesAdded + this.stats.linesRemoved) / minutes) : 0;
    const filesPerHour = minutes > 0 ? Math.round((this.stats.filesModified.size * 60) / minutes) : 0;
    
    console.log(colors.secondary('\n⚔ Productivity:'));
    console.log(colors.accent(`   Lines/min: ${linesPerMinute}`));
    console.log(colors.accent(`   Files/hour: ${filesPerHour}`));
    
    // Quality Check Summary (if available)
    if (this.checkResults && this.lastCheckTime) {
      console.log(colors.secondary('\nšŸ” Quality Checks:'));
      
      let passedChecks = 0;
      let failedChecks = 0;
      let warningChecks = 0;
      
      // Count check statuses
      Object.values(this.checkResults).forEach(category => {
        if (category && typeof category === 'object') {
          Object.values(category).forEach(check => {
            if (check && check.status) {
              switch (check.status) {
                case 'passed': passedChecks++; break;
                case 'failed': failedChecks++; break;
                case 'warning': warningChecks++; break;
              }
            }
          });
        }
      });
      
      const totalChecks = passedChecks + failedChecks + warningChecks;
      const healthScore = totalChecks > 0 ? Math.round((passedChecks / totalChecks) * 100) : 0;
      
      console.log(`   Health Score: ${this.getHealthScoreDisplay(healthScore)}`);
      console.log(`   ${colors.success(`āœ… Passed: ${passedChecks}`)} | ${colors.error(`āŒ Failed: ${failedChecks}`)} | ${colors.warning(`āš ļø Warnings: ${warningChecks}`)}`);
      
      const checkAge = Math.floor((Date.now() - this.lastCheckTime) / 1000);
      console.log(colors.muted(`   Last checked: ${checkAge}s ago`));
    }
    
    // Recent activity
    const lastActiveAgo = Math.floor((Date.now() - this.stats.lastActive) / 1000);
    const status = lastActiveAgo < 10 ? '🟢 Active' : lastActiveAgo < 60 ? '🟔 Idle' : 'šŸ”“ Away';
    console.log(colors.secondary('\nšŸŽÆ Status:'));
    console.log(colors.muted(`   ${status} (${lastActiveAgo}s ago)`));
    
    console.log(colors.muted('\n' + '─'.repeat(60)));
    console.log(colors.muted('Press Shift+Tab to switch modes • Stats update in real-time'));
  }
  
  getHealthScoreDisplay(score) {
    const colors = {
          error: chalk.red,
          warning: chalk.yellow,
          success: chalk.green,
          info: chalk.blue,
          muted: chalk.gray,
          primary: chalk.white,
          secondary: chalk.cyan,
          header: chalk.bold.blue,
          highlight: chalk.bgBlue.white,
          accent: chalk.magenta
        };
    const emoji = score >= 90 ? '🌟' : score >= 70 ? 'šŸ‘' : score >= 50 ? '😐' : 'āš ļø';
    const color = score >= 90 ? colors.success : score >= 70 ? colors.warning : colors.error;
    return `${emoji} ${color(score + '%')}`;
  }

  
  async handleChecksKeypress(key, str) {
    if (!key && !str) return;
    
    // Handle 'r' key to manually run checks
    if (str === 'r' && !key.ctrl && !key.meta) {
      console.log('\nšŸ”„ Running checks...');
      await this.runChecks();
    }
  }

  
  createProgressBar(value, total, length = 20) {
    if (total === 0) return { added: '', removed: '' };
    const addedRatio = value / total;
    const removedRatio = (total - value) / total;
    
    const addedBars = Math.round(addedRatio * length);
    const removedBars = Math.round(removedRatio * length);
    
    return {
      added: 'ā–ˆ'.repeat(addedBars),
      removed: 'ā–ˆ'.repeat(removedBars)
    };
  }
  
  showControlsFooter(colors, customControls = []) {
    console.log(colors.muted('\nšŸŽ® Controls:'));
    console.log(colors.muted('  Shift+Tab - Switch between modes'));
    console.log(colors.muted('  Ctrl+C - Exit application'));
    
    // Add mode-specific controls
    customControls.forEach(control => {
      console.log(colors.muted(`  ${control}`));
    });
  }

  getTimeAgo(timestamp) {
    const now = Date.now();
    const diff = now - timestamp;
    const seconds = Math.floor(diff / 1000);
    const minutes = Math.floor(seconds / 60);
    const hours = Math.floor(minutes / 60);
    
    if (seconds < 60) return 'just now';
    if (minutes < 60) return `${minutes}m ago`;
    if (hours < 24) return `${hours}h ago`;
    return new Date(timestamp).toLocaleDateString();
  }

  createMiniProgressBar(value, max, length = 10) {
    if (max === 0) return '';
    const ratio = value / max;
    const bars = Math.round(ratio * length);
    return 'ā–“'.repeat(bars) + 'ā–‘'.repeat(length - bars);
  }

  async displayChecksMode() {
    const colors = {
          error: chalk.red,
          warning: chalk.yellow,
          success: chalk.green,
          info: chalk.blue,
          muted: chalk.gray,
          primary: chalk.white,
          secondary: chalk.cyan,
          header: chalk.bold.blue,
          highlight: chalk.bgBlue.white,
          accent: chalk.magenta
        };
    console.log(colors.header('šŸ” Vibe Code - Quality Checks'));
    console.log(colors.muted('Real-time code quality monitoring'));
    console.log(colors.muted('─'.repeat(60)));
    
    // Show when checks were last run
    if (this.lastCheckTime) {
      const ago = Math.floor((Date.now() - this.lastCheckTime) / 1000);
      console.log(colors.muted(`Last check: ${ago}s ago`));
    }
    
    // Show what's currently being checked
    if (this.currentCheckStatus) {
      console.log(colors.info(`\n${this.currentCheckStatus}`));
    }
    
    // If no results yet, run initial checks
    if (!this.checkResults) {
      console.log(colors.info('\nā³ Running initial checks...'));
      await this.runChecks();
      return;
    }
    
    // Display results with specific issues
    console.log(colors.secondary('\nšŸ“Š Check Results:'));
    
    // Build checks
    if (this.checkResults.build) {
      const buildResult = this.checkResults.build.build || {};
      const icon = buildResult.status === 'passed' ? 'āœ…' : 
                   buildResult.status === 'failed' ? 'āŒ' : 'ā­ļø';
      console.log(`\n${icon} ${colors.primary('Build')}: ${buildResult.message || 'Not checked'}`);
      if (buildResult.status === 'failed' && buildResult.error) {
        console.log(colors.error(`   āš ļø  ${buildResult.error.split('\n')[0]}`));
      }
    }
    
    // Dependencies
    if (this.checkResults.dependencies) {
      const vulns = this.checkResults.dependencies.vulnerabilities || {};
      const outdated = this.checkResults.dependencies.outdated || {};
      
      const vulnIcon = vulns.status === 'passed' ? 'āœ…' : 
                       vulns.status === 'failed' ? 'āŒ' : 'āš ļø';
      console.log(`\n${vulnIcon} ${colors.primary('Dependencies')}:`);
      if (vulns.message) {
        console.log(`   ${vulns.message}`);
      }
      if (vulns.status === 'failed' && vulns.vulnerabilities) {
        vulns.vulnerabilities.slice(0, 3).forEach(v => {
          console.log(colors.error(`   āš ļø  ${v.name} - ${v.severity}`));
        });
      }
      if (outdated.message) {
        console.log(`   ${outdated.message}`);
      }
      if (outdated.dependencies && outdated.dependencies.length > 0) {
        outdated.dependencies.slice(0, 3).forEach(d => {
          console.log(colors.warning(`   šŸ“¦ ${d.name}: ${d.current} → ${d.latest}`));
        });
      }
    }
    
    // Security
    if (this.checkResults.security) {
      const godMode = this.checkResults.security.godMode || {};
      const secrets = this.checkResults.security.secrets || {};
      
      const secIcon = (godMode.status === 'failed' || secrets.status === 'failed') ? 'āŒ' : 
                      (godMode.status === 'warning' || secrets.status === 'warning') ? 'āš ļø' : 'āœ…';
      console.log(`\n${secIcon} ${colors.primary('Security')}:`);
      if (godMode.message) {
        console.log(`   ${godMode.message}`);
      }
      if (godMode.findings && godMode.findings.length > 0) {
        godMode.findings.slice(0, 3).forEach(f => {
          console.log(colors.error(`   🚨 ${f.file}:${f.line} - ${f.description}`));
        });
        if (godMode.findings.length > 3) {
          console.log(colors.error(`   ... and ${godMode.findings.length - 3} more issues`));
        }
      }
      if (secrets.message && secrets.message !== godMode.message) {
        console.log(`   ${secrets.message}`);
      }
      if (secrets.findings && secrets.findings.length > 0) {
        secrets.findings.slice(0, 2).forEach(f => {
          console.log(colors.error(`   šŸ” ${f.file}:${f.line} - ${f.type}`));
        });
      }
    }
    
    // CLAUDE.md
    if (this.checkResults.claude) {
      const claudeMd = this.checkResults.claude.claudeMdExists || {};
      const icon = claudeMd.status === 'passed' ? 'āœ…' : 
                   claudeMd.status === 'failed' ? 'āŒ' : 'āš ļø';
      console.log(`\n${icon} ${colors.primary('CLAUDE.md')}: ${claudeMd.message || 'Not checked'}`);
    }
    
    // Performance & SEO
    if (this.checkResults.performance) {
      const bundle = this.checkResults.performance.bundleSize || {};
      const seo = this.checkResults.performance.seo || {};
      
      // Show bundle size
      const bundleIcon = bundle.status === 'warning' ? 'āš ļø' : 
                        bundle.status === 'failed' ? 'āŒ' : 'āœ…';
      console.log(`\n${bundleIcon} ${colors.primary('Performance')}:`);
      if (bundle.message) {
        console.log(`   ${bundle.message}`);
      }
      
      // Enhanced SEO display
      if (seo.score !== undefined) {
        // Show SEO score prominently
        const seoIcon = seo.status === 'passed' ? 'āœ…' : 
                       seo.status === 'warning' ? 'āš ļø' : 'āŒ';
        const scoreColor = seo.score >= 80 ? colors.success : 
                          seo.score >= 60 ? colors.warning : colors.error;
        console.log(`\n${seoIcon} ${colors.primary('SEO Analysis')}:`);
        console.log(scoreColor(`   šŸŽÆ Score: ${seo.score}/100 (${seo.grade || 'N/A'})`));
        
        // Show category breakdown if available
        if (seo.categories) {
          console.log(colors.secondary('   šŸ“Š Category Scores:'));
          ['technical', 'content', 'social', 'performance'].forEach(category => {
            const cat = seo.categories[category];
            if (cat && cat.score !== undefined) {
              const catColor = cat.score >= 80 ? colors.success : 
                              cat.score >= 60 ? colors.warning : colors.error;
              console.log(catColor(`      • ${category.charAt(0).toUpperCase() + category.slice(1)}: ${cat.score}/100`));
            }
          });
        }
        
        // Show top issues
        if (seo.issues && seo.issues.length > 0) {
          console.log(colors.secondary('   āš ļø  Top Issues:'));
          seo.issues.slice(0, 3).forEach(issue => {
            const issueColor = issue.severity === 'critical' ? colors.error :
                              issue.severity === 'high' ? colors.error :
                              issue.severity === 'medium' ? colors.warning : colors.muted;
            console.log(issueColor(`      • ${issue.message}`));
            if (issue.recommendation) {
              console.log(colors.info(`        šŸ’” ${issue.recommendation}`));
            }
          });
          
          if (seo.issues.length > 3) {
            console.log(colors.muted(`      ... and ${seo.issues.length - 3} more issues`));
          }
        }
        
        // Show top recommendations
        if (seo.recommendations && seo.recommendations.length > 0) {
          console.log(colors.secondary('   šŸŽÆ Priority Actions:'));
          seo.recommendations.slice(0, 2).forEach((rec, idx) => {
            if (rec.priority) {
              const recColor = rec.priority === 'critical' || rec.priority === 'high' ? colors.error :
                              rec.priority === 'medium' ? colors.warning : colors.info;
              console.log(recColor(`      ${idx + 1}. ${rec.title}`));
              console.log(colors.muted(`         ${rec.description}`));
            } else {
              console.log(colors.info(`      • ${rec}`));
            }
          });
        }
      } else if (seo.message) {
        // Fallback to simple message
        console.log(`   ${seo.message}`);
      }
    }
    
    // Show hint about manual checking
    if (this.updates.length > 0 && !this.lastCheckTime) {
      const lastUpdate = this.updates[this.updates.length - 1];
      const timeSinceUpdate = Date.now() - lastUpdate.sortTimestamp;
      
      if (timeSinceUpdate > 5000) {
        console.log(colors.muted('\nšŸ’” Tip: Press "r" to run checks on recent changes'));
      }
    }
    
    this.showControlsFooter(colors, ['r - Run quality checks']);
  }

  async runChecks() {
    // Prevent recursive calls
    if (this.isRunningChecks) return;
    this.isRunningChecks = true;
    
    const colors = {
          error: chalk.red,
          warning: chalk.yellow,
          success: chalk.green,
          info: chalk.blue,
          muted: chalk.gray,
          primary: chalk.white,
          secondary: chalk.cyan,
          header: chalk.bold.blue,
          highlight: chalk.bgBlue.white,
          accent: chalk.magenta
        };
    
    try {
      this.checkResults = {};
      
      // Run checks sequentially to show progress
      console.log(colors.info('\nšŸ”„ Running quality checks...\n'));
      
      // Build check
      this.currentCheckStatus = 'šŸ”Ø Checking build configuration...';
      await this.updateDisplay();
      this.checkResults.build = await this.checkers.build.checkAll().catch(e => ({ error: e.message }));
      
      // Dependencies check
      this.currentCheckStatus = 'šŸ“¦ Checking dependencies...';
      await this.updateDisplay();
      this.checkResults.dependencies = await this.checkers.dependencies.checkAll().catch(e => ({ error: e.message }));
      
      // Security check
      this.currentCheckStatus = 'šŸ”’ Running security scans...';
      await this.updateDisplay();
      this.checkResults.security = await this.checkers.security.checkAll().catch(e => ({ error: e.message }));
      
      // CLAUDE.md check
      this.currentCheckStatus = 'šŸ¤– Validating CLAUDE.md compliance...';
      await this.updateDisplay();
      this.checkResults.claude = await this.checkers.claude.checkAll().catch(e => ({ error: e.message }));
      
      // Performance check
      this.currentCheckStatus = '⚔ Analyzing performance...';
      await this.updateDisplay();
      this.checkResults.performance = await this.checkers.performance.checkAll().catch(e => ({ error: e.message }));
      
      this.lastCheckTime = Date.now();
      this.currentCheckStatus = null;
      
      // Clear screen and display results
      this.clearScreen();
      await this.displayChecksMode();
    } catch (error) {
      console.error(colors.error('Check failed: ' + error.message));
      this.currentCheckStatus = null;
    } finally {
      this.isRunningChecks = false;
    }
  }
  
  updateStats(type, filename, context) {
    // Update last active time
    this.stats.lastActive = Date.now();
    
    // Track file extensions/languages
    const ext = path.extname(filename).slice(1).toLowerCase() || 'other';
    if (!this.stats.languageStats[ext]) {
      this.stats.languageStats[ext] = 0;
    }
    this.stats.languageStats[ext]++;
    
    // Count files
    if (type === 'added') {
      this.stats.totalFiles++;
    }
    
    // Track modified files
    if (type === 'modified' || type === 'added') {
      this.stats.filesModified.add(context.filePath);
    }
    
    // Count lines added/removed from diff
    if (context.diff) {
      const lines = context.diff.split('\n');
      const addedLines = lines.filter(line => line.startsWith('+') && !line.startsWith('+++')).length;
      const removedLines = lines.filter(line => line.startsWith('-') && !line.startsWith('---')).length;
      
      this.stats.linesAdded += addedLines;
      this.stats.linesRemoved += removedLines;
    }
  }


  getUpdateIcon(type) {
    const icons = {
      'added': chalk.green('āœ…'),
      'modified': chalk.yellow('šŸ“'),
      'deleted': chalk.red('šŸ—‘ļø')
    };
    return icons[type] || 'šŸ“„';
  }

  createSimpleDiff(oldContent, newContent, filename) {
    const oldLines = oldContent.split('\n');
    const newLines = newContent.split('\n');
    
    let diff = `diff --git a/${filename} b/${filename}\n`;
    diff += `--- a/${filename}\n`;
    diff += `+++ b/${filename}\n`;
    diff += `@@ -1,${oldLines.length} +1,${newLines.length} @@\n`;
    
    // Simple line-by-line diff
    const maxLines = Math.max(oldLines.length, newLines.length);
    for (let i = 0; i < maxLines; i++) {
      if (i < oldLines.length && i < newLines.length) {
        if (oldLines[i] !== newLines[i]) {
          diff += `-${oldLines[i]}\n`;
          diff += `+${newLines[i]}\n`;
        } else {
          diff += ` ${oldLines[i]}\n`;
        }
      } else if (i < oldLines.length) {
        diff += `-${oldLines[i]}\n`;
      } else {
        diff += `+${newLines[i]}\n`;
      }
    }
    
    return diff;
  }
  
  formatDiff(diff) {
    const lines = diff.split('\n');
    const formatted = [];
    let showCount = 0;
    let inHunk = false;
    let addedCount = 0;
    let removedCount = 0;
    
    lines.forEach((line, index) => {
      if (showCount > 40) return;
      
      if (line.startsWith('@@')) {
        // Hunk header - shows line numbers
        formatted.push(chalk.cyan.bold(line));
        inHunk = true;
      } else if (line.startsWith('+') && !line.startsWith('+++')) {
        // Added line - highlight with better formatting
        formatted.push(chalk.green.bold('+ ') + chalk.green(line.substring(1)));
        showCount++;
        addedCount++;
      } else if (line.startsWith('-') && !line.startsWith('---')) {
        // Removed line - highlight with better formatting  
        formatted.push(chalk.red.bold('- ') + chalk.red(line.substring(1)));
        showCount++;
        removedCount++;
      } else if (line.startsWith('diff --git')) {
        // File header with better styling
        formatted.push(chalk.yellow.bold('šŸ“„ ' + line));
      } else if (line.startsWith('+++') || line.startsWith('---')) {
        // File paths
        formatted.push(chalk.gray(line));
      } else if (inHunk && line.startsWith(' ')) {
        // Context line in hunk - show some context
        formatted.push(chalk.gray('  ' + line.substring(1)));
        showCount++;
      }
    });
    
    if (showCount > 40) {
      formatted.push(chalk.gray('\n... (diff truncated, showing first 40 changes)'));
    }
    
    // Add summary
    if (addedCount > 0 || removedCount > 0) {
      formatted.unshift(chalk.cyan(`šŸ“Š Changes: ${addedCount} additions, ${removedCount} deletions\n`));
    }
    
    return formatted.join('\n');
  }



  clearScreen() {
    console.clear();
  }
  
  async showNewUpdate(update) {
    const colors = {
          error: chalk.red,
          warning: chalk.yellow,
          success: chalk.green,
          info: chalk.blue,
          muted: chalk.gray,
          primary: chalk.white,
          secondary: chalk.cyan,
          header: chalk.bold.blue,
          highlight: chalk.bgBlue.white,
          accent: chalk.magenta
        };
    
    // Just append the new update naturally - no screen clearing
    console.log('\n' + colors.accent('═'.repeat(60)));
    console.log(colors.success.bold('šŸ†• FILE CHANGED'));
    console.log(colors.accent('═'.repeat(60)));
    
    await this.displaySingleUpdate(update, true);
    console.log(colors.muted('─'.repeat(60)) + '\n');
    
    // Update the last displayed update
    this.lastDisplayedUpdate = update;
  }
  
  async displaySingleUpdate(update, withAnimation = false) {
    const colors = {
          error: chalk.red,
          warning: chalk.yellow,
          success: chalk.green,
          info: chalk.blue,
          muted: chalk.gray,
          primary: chalk.white,
          secondary: chalk.cyan,
          header: chalk.bold.blue,
          highlight: chalk.bgBlue.white,
          accent: chalk.magenta
        };
    
    console.log(colors.header(`šŸ“Œ UPDATE #${update.number} | ${update.timestamp}`));
    console.log(colors.muted('═'.repeat(50)));
    
    const icon = update.type === 'added' ? 'āœ…' : update.type === 'modified' ? 'šŸ“' : 'šŸ—‘ļø';
    console.log(`${icon} ${colors.primary(update.filename)}`);
    
    if (update.context.diff) {
      console.log('\n' + colors.secondary('šŸ“ Code Changes:'));
      console.log(colors.muted('─'.repeat(50)));
      console.log(this.formatDiff(update.context.diff));
      console.log(colors.muted('─'.repeat(50)));
      
      // Get insights with mentoring
      const insights = insightEngine.analyzeChange(update.context);
      
      if (insights) {
        if (withAnimation) {
          await this.typeWriter.typeOut(insights, 'fast');
        } else {
          console.log(insights);
        }
      }
      
      // Show token usage stats
      const stats = tokenAnalyzer.analyzeOutput(insights);
      const tokenStats = tokenAnalyzer.formatStats(stats, 'Insight');
      console.log(tokenStats);
      
      // If in optimized mode, show savings compared to detailed
      if (insightEngine.getMode() === 'optimized') {
        const currentMode = insightEngine.getMode();
        insightEngine.setMode('detailed');
        const detailedAnalysis = insightEngine.analyzeChange(update.context);
        insightEngine.setMode(currentMode);
        
        const comparison = tokenAnalyzer.compareOutputs(detailedAnalysis, insights);
        if (comparison.savings.percentage > 0) {
          console.log(colors.success(`   šŸ’° Token savings: ${comparison.savings.tokens} tokens (${comparison.savings.percentage}% reduction)\n`));
        }
      }
    }
  }
  
  async displayUpdateHistory() {
    const colors = {
          error: chalk.red,
          warning: chalk.yellow,
          success: chalk.green,
          info: chalk.blue,
          muted: chalk.gray,
          primary: chalk.white,
          secondary: chalk.cyan,
          header: chalk.bold.blue,
          highlight: chalk.bgBlue.white,
          accent: chalk.magenta
        };
    this.clearScreen();
    
    console.log(colors.header('šŸ“š Update History'));
    console.log(colors.muted('Navigate with arrow keys • Press ESC or Q to return to live mode'));
    console.log(colors.muted('─'.repeat(60)));
    
    const pageSize = 5;
    const totalPages = Math.ceil(this.updates.length / pageSize);
    const currentPage = totalPages - this.updateHistoryPage - 1;
    
    // Calculate indices for reverse pagination (newest first)
    const startIdx = currentPage * pageSize;
    const endIdx = Math.min(startIdx + pageSize, this.updates.length);
    
    // Get updates for this page and sort newest first
    const pageUpdates = this.updates.slice(startIdx, endIdx);
    pageUpdates.sort((a, b) => b.sortTimestamp - a.sortTimestamp);
    
    console.log(colors.info(`\nPage ${this.updateHistoryPage + 1} of ${totalPages} (Updates ${this.updates.length - endIdx + 1}-${this.updates.length - startIdx})\n`));
    
    for (const update of pageUpdates) {
      await this.displaySingleUpdate(update, false);
      console.log(colors.muted('\n' + '─'.repeat(50) + '\n'));
    }
    
    // Navigation footer
    const hasOlder = this.updateHistoryPage < totalPages - 1;
    const hasNewer = this.updateHistoryPage > 0;
    
    console.log(colors.secondary('\nšŸŽ® Navigation:'));
    if (hasNewer) console.log(colors.muted('  ← or ↓ - Newer updates'));
    if (hasOlder) console.log(colors.muted('  → or ↑ - Older updates'));
    console.log(colors.muted('  ESC or Q - Return to live mode'));
  }
  
  async countProjectFiles() {
    // Simple file count - in real implementation could be more sophisticated
    try {
      const { execSync } = await import('child_process');
      const count = execSync(
        `find ${this.projectPath} -type f -name "*.js" -o -name "*.ts" -o -name "*.jsx" -o -name "*.tsx" -o -name "*.json" -o -name "*.md" | grep -v node_modules | wc -l`,
        { encoding: 'utf8', stdio: 'pipe' }
      ).trim();
      return parseInt(count) || 0;
    } catch {
      // Fallback for Windows or if find command fails
      return 'multiple';
    }
  }

  handleExit() {
    // Prevent multiple exit calls
    if (this.isExiting) return;
    this.isExiting = true;
    
    // Clean up all event listeners
    process.stdin.removeAllListeners('keypress');
    
    // Clean up readline interface
    if (this.rl && !this.rl.closed) {
      this.rl.close();
    }
    
    // Restore terminal state
    if (process.stdin.isTTY) {
      try {
        process.stdin.setRawMode(false);
      } catch (e) {
        // Ignore errors when restoring terminal
      }
    }
    
    // Stop file watcher
    if (this.watcher) {
      this.watcher.close();
    }
    
    console.log(chalk.yellow('\n\nšŸ‘‹ Thanks for using Vibe Code!'));
    process.exit(0);
  }
  
  capitalize(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
  }
  
  async displaySEOMode() {
    const colors = {
          error: chalk.red,
          warning: chalk.yellow,
          success: chalk.green,
          info: chalk.blue,
          muted: chalk.gray,
          primary: chalk.white,
          secondary: chalk.cyan,
          header: chalk.bold.blue,
          highlight: chalk.bgBlue.white,
          accent: chalk.magenta
        };
    console.log(colors.header('šŸ” Vibe Code - SEO Analysis'));
    console.log(colors.muted('Search engine optimization monitoring and insights'));
    console.log(colors.muted('─'.repeat(60)));
    
    // Run SEO analysis if not done yet or if it's been more than 30 seconds
    if (!this.seoResults || !this.lastSEOCheck || (Date.now() - this.lastSEOCheck > 30000)) {
      await this.runSEOAnalysis();
    }
    
    if (this.seoResults && this.seoResults.overall) {
      const { score, grade } = this.seoResults.overall;
      const scoreColor = score >= 80 ? colors.success : score >= 60 ? colors.warning : colors.error;
      
      // Calculate score change from history
      let scoreChange = '';
      if (this.seoHistory.length > 1) {
        const prevScore = this.seoHistory[this.seoHistory.length - 2].score;
        const diff = score - prevScore;
        if (diff > 0) scoreChange = colors.success(` ↑ +${diff} from last check`);
        else if (diff < 0) scoreChange = colors.error(` ↓ ${diff} from last check`);
      }
      
      console.log(scoreColor.bold(`Overall Score: ${score}/100 (${grade})${scoreChange}\n`));
      
      // Live metrics
      console.log(colors.secondary('šŸ“Š Live Metrics:'));
      if (this.seoResults.categories) {
        ['technical', 'content', 'social', 'performance'].forEach(category => {
          const cat = this.seoResults.categories[category];
          if (cat && cat.score !== undefined) {
            const catColor = cat.score >= 80 ? colors.success : cat.score >= 60 ? colors.warning : colors.error;
            const icon = cat.score >= 80 ? 'āœ…' : cat.score >= 60 ? 'āš ļø' : 'āŒ';
            const details = this.getSEOCategoryDetails(category, cat);
            console.log(catColor(`• ${this.capitalize(category)}: ${cat.score}/100 ${icon} ${details}`));
          }
        });
      }
      
      // Critical issues
      if (this.seoResults.issues && this.seoResults.issues.length > 0) {
        const criticalIssues = this.seoResults.issues.filter(i => i.severity === 'critical' || i.severity === 'high');
        if (criticalIssues.length > 0) {
          console.log(colors.error.bold('\nšŸ”“ Critical Issues (Fix immediately):'));
          criticalIssues.slice(0, 3).forEach((issue, idx) => {
            console.log(colors.error(`${idx + 1}. ${issue.message}`));
            if (issue.recommendation) {
              console.log(colors.info(`   → ${issue.recommendation}`));
            }
          });
        }
      }
      
      // Real-time monitoring status
      console.log(colors.secondary('\n⚔ Real-time Monitoring: ') + colors.success('Active'));
      if (this.updates.length > 0) {
        const lastUpdate = this.updates[this.updates.length - 1];
        const timeSince = Math.floor((Date.now() - lastUpdate.sortTimestamp) / 1000);
        console.log(colors.muted(`Last change: ${lastUpdate.filename} (${timeSince}s ago)`));
      }
      
      // SEO History trend
      if (this.seoHistory.length > 1) {
        console.log(colors.secondary('\nšŸ“ˆ Score Trend:'));
        this.displaySEOTrend();
      }
    } else {
      console.log(colors.info('ā³ Running SEO analysis...'));
    }
    
    this.showControlsFooter(colors, ['r - Run SEO analysis', 'e - Export report', 'h - View score history']);
  }
  
  async runSEOAnalysis() {
    try {
      const seoChecker = new SEOChecker(this.projectPath, { silent: true });
      this.seoResults = await seoChecker.checkAll();
      this.lastSEOCheck = Date.now();
      
      // Add to history
      if (this.seoResults.overall) {
        this.seoHistory.push({
          timestamp: Date.now(),
          score: this.seoResults.overall.score,
          grade: this.seoResults.overall.grade
        });
        
        // Keep only last 10 entries
        if (this.seoHistory.length > 10) {
          this.seoHistory.shift();
        }
      }
    } catch (error) {
      console.error('SEO analysis failed:', error);
    }
  }
  
  getSEOCategoryDetails(category, data) {
    const details = {
      technical: (data) => {
        const checks = data.checks || {};
        const found = [];
        if (checks.robots?.found) found.push('robots.txt āœ“');
        if (checks.sitemap?.found) found.push('sitemap.xml āœ“');
        if (checks.https?.enabled) found.push('HTTPS āœ“');
        return found.length > 0 ? `(${found.join(', ')})` : '(missing core files)';
      },
      content: (data) => {
        const stats = data.stats || {};
        if (stats.pagesAnalyzed > 0) {
          const missing = [];
          if (stats.titlesFound < stats.pagesAnalyzed) {
            missing.push(`${stats.pagesAnalyzed - stats.titlesFound} missing titles`);
          }
          if (stats.descriptionsFound < stats.pagesAnalyzed) {
            missing.push(`${stats.pagesAnalyzed - stats.descriptionsFound} missing descriptions`);
          }
          return missing.length > 0 ? `(${missing.join(', ')})` : '(all meta tags present)';
        }
        return '';
      },
      social: (data) => {
        const stats = data.stats || {};
        if (stats.pagesChecked > 0) {
          const missing = stats.pagesChecked - (stats.ogTags?.found || 0);
          return missing > 0 ? `(${missing} pages missing OG tags)` : '(all social tags present)';
        }
        return '';
      },
      performance: (data) => {
        const factors = data.factors || {};
        const issues = [];
        if (factors.largeImages?.length > 0) {
          issues.push(`${factors.largeImages.length} large images`);
        }
        if (factors.renderBlocking?.length > 0) {
          issues.push(`${factors.renderBlocking.length} render-blocking`);
        }
        return issues.length > 0 ? `(${issues.join(', ')})` : '(optimized)';
      }
    };
    
    return details[category] ? details[category](data) : '';
  }
  
  displaySEOTrend() {
    const colors = {
          error: chalk.red,
          warning: chalk.yellow,
          success: chalk.green,
          info: chalk.blue,
          muted: chalk.gray,
          primary: chalk.white,
          secondary: chalk.cyan,
          header: chalk.bold.blue,
          highlight: chalk.bgBlue.white,
          accent: chalk.magenta
        };
    const width = 40;
    const height = 5;
    const scores = this.seoHistory.map(h => h.score);
    const maxScore = 100;
    const minScore = 0;
    
    // Simple ASCII chart
    for (let i = height; i > 0; i--) {
      const threshold = (i / height) * maxScore;
      let line = '';
      
      scores.forEach((score, idx) => {
        if (score >= threshold) {
          line += idx === scores.length - 1 ? colors.success('ā–ˆ') : colors.muted('ā–ˆ');
        } else {
          line += ' ';
        }
      });
      
      console.log(colors.muted(`${String(Math.round(threshold)).padStart(3)} │`) + line);
    }
    console.log(colors.muted('    ā””' + '─'.repeat(scores.length)));
  }
  
  async handleSEOKeypress(key, str) {
    if (!key) return;
    
    if (key.name === 'r') {
      await this.runSEOAnalysis();
      await this.updateDisplay();
    } else if (key.name === 'e') {
      // Export SEO report
      console.log(chalk.blue('\nšŸ“„ Exporting SEO report...'));
      // TODO: Implement export functionality
    } else if (key.name === 'h') {
      // Show history
      console.log(chalk.blue('\nšŸ“Š SEO Score History:'));
      this.seoHistory.forEach(entry => {
        const date = new Date(entry.timestamp).toLocaleString();
        console.log(`${date}: ${entry.score}/100 (${entry.grade})`);
      });
    } else if (str && !key.ctrl && !key.meta) {
      process.stdout.write('\r\x1B[K');
    }
  }
  
  async displaySecurityMode() {
    const colors = {
          error: chalk.red,
          warning: chalk.yellow,
          success: chalk.green,
          info: chalk.blue,
          muted: chalk.gray,
          primary: chalk.white,
          secondary: chalk.cyan,
          header: chalk.bold.blue,
          highlight: chalk.bgBlue.white,
          accent: chalk.magenta
        };
    console.log(colors.header('šŸ”’ Vibe Code - Security Analysis'));
    console.log(colors.muted('Real-time vulnerability and threat detection'));
    console.log(colors.muted('─'.repeat(60)));
    
    // Run security scan if needed
    if (!this.securityThreats || Date.now() - (this.lastSecurityCheck || 0) > 10000) {
      await this.runSecurityScan();
    }
    
    // Security score with color
    const scoreColor = this.securityScore >= 80 ? colors.success : 
                      this.securityScore >= 60 ? colors.warning : colors.error;
    const riskLevel = this.securityScore >= 80 ? 'LOW RISK' :
                     this.securityScore >= 60 ? 'MEDIUM RISK' : 'HIGH RISK';
    
    console.log(scoreColor.bold(`Security Score: ${this.securityScore}/100 (${this.getGrade(this.securityScore)}) - ${riskLevel} āš ļø\n`));
    
    // Separate production and test threats
    const prodThreats = this.securityThreats.filter(t => t.isRealThreat !== false);
    const testThreats = this.securityThreats.filter(t => t.isRealThreat === false);
    
    // Production threats (real issues)
    if (prodThreats.length > 0) {
      console.log(colors.error.bold('🚨 Production Code Threats (Action Required):'));
      prodThreats.slice(0, 5).forEach(threat => {
        const icon = threat.severity === 'critical' ? '• CRITICAL:' : '• HIGH:';
        console.log(colors.error(`${icon} ${threat.message}`));
        if (threat.code) {
          console.log(colors.muted(`  ${threat.code}`));
        }
        if (threat.fix) {
          console.log(colors.success(`  → ${threat.fix}`));
        }
      });
      
      if (prodThreats.length > 5) {
        console.log(colors.error(`\n... and ${prodThreats.length - 5} more production threats`));
      }
    } else {
      console.log(colors.success.bold('āœ… No Production Threats Detected'));
    }
    
    // Test/Local threats (informational)
    if (testThreats.length > 0) {
      console.log(colors.secondary('\nšŸ“‹ Test/Local Code (Informational):'));
      console.log(colors.muted(`Found ${testThreats.length} intentional test patterns - not deployment risks`));
      testThreats.slice(0, 2).forEach(threat => {
        console.log(colors.muted(`  • ${threat.file} (${threat.environment})`));
      });
    }
    
    // Security breakdown
    console.log(colors.secondary('\nšŸ“Š Security Breakdown:'));
    if (this.checkResults?.security) {
      const sec = this.checkResults.security;
      const godMode = sec.godMode || {};
      const secrets = sec.secrets || {};
      const vulns = sec.vulnerabilities || {};
      
      console.log(`• God Mode Patterns: ${godMode.findings?.length || 0} found${godMode.findings?.filter(f => f.severity === 'critical').length ? ` (${godMode.findings.filter(f => f.severity === 'critical').length} critical)` : ''}`);
      console.log(`• Exposed Secrets: ${secrets.findings?.length || 0} found${secrets.findings?.filter(f => f.severity === 'critical').length ? ` (${secrets.findings.filter(f => f.severity === 'critical').length} API keys)` : ''}`);
      console.log(`• Injection Risks: ${vulns.sqlInjection?.length || 0} SQL, ${vulns.xss?.length || 0} XSS vulnerabilities`);
      
      if (this.checkResults?.dependencies?.vulnerabilities) {
        const depVulns = this.checkResults.dependencies.vulnerabilities.vulnerabilities || [];
        const high = depVulns.filter(v => v.severity === 'high').length;
        const critical = depVulns.filter(v => v.severity === 'critical').length;
        console.log(`• Dependencies: ${depVulns.length} vulnerabilities${critical ? ` (${critical} critical)` : ''}`);
      }
    }
    
    // Real-time monitoring
    console.log(colors.secondary('\nšŸ›”ļø Real-time Protection: ') + colors.success('Active'));
    const fileCount = await this.countProjectFiles();
    console.log(colors.muted(`Monitoring: ${fileCount} files | Last scan: ${this.lastSecurityCheck ? Math.floor((Date.now() - this.lastSecurityCheck) / 1000) + 's ago' : 'running...'}`));
    
    this.showControlsFooter(colors, ['r - Run full security scan', 's - Scan specific file', 'd - Check dependencies', 'f - Auto-fix issues']);
  }
  
  async runSecurityScan() {
    this.lastSecurityCheck = Date.now();
    
    try {
      // Run security checker
      const securityChecker = new SecurityChecker(this.projectPath, { silent: true });
      const results = await securityChecker.checkAll();
      
      // Calculate security score
      let score = 100;
      const threats = [];
      
      // Process god mode patterns
      if (results.godMode?.findings) {
        results.godMode.findings.forEach(finding => {
          // Only deduct points for production threats
          if (finding.isRealThreat) {
            if (finding.originalSeverity === 'critical') score -= 15;
            else if (finding.originalSeverity === 'high') score -= 10;
            else score -= 5;
          }
          
          threats.push({
            severity: finding.severity,
            message: `${finding.description} in ${finding.file}:${finding.line}`,
            code: finding.match,
            fix: this.getSecurityFix(finding.type),
            environment: finding.environment,
            isRealThreat: finding.isRealThreat,
            file: finding.file
          });
        });
      }
      
      // Process exposed secrets
      if (results.secrets?.findings) {
        results.secrets.findings.forEach(finding => {
          // Only deduct points for production threats
          if (finding.isRealThreat) {
            if (finding.originalSeverity === 'critical') score -= 20;
            else score -= 10;
          }
          
          threats.push({
            severity: finding.severity,
            message: `${finding.type} exposed in ${finding.file}:${finding.line}`,
            code: finding.match?.substring(0, 50) + '...',
            fix: 'Move to .env file and add to .gitignore',
            environment: finding.environment,
            isRealThreat: finding.isRealThreat,
            file: finding.file
          });
        });
      }
      
      this.securityScore = Math.max(0, score);
      this.securityThreats = threats.sort((a, b) => {
        const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
        return severityOrder[a.severity] - severityOrder[b.severity];
      });
      
      // Store full results for breakdown
      this.checkResults = this.checkResults || {};
      this.checkResults.security = results;
    } catch (error) {
      console.error('Security scan failed:', error);
    }
  }
  
  getSecurityFix(type) {
    const fixes = {
      'eval': 'Never use eval with user input - use JSON.parse or safer alternatives',
      'sql-injection': 'Use parameterized queries or prepared statements',
      'xss': 'Sanitize user input and escape HTML entities',
      'hardcoded-secret': 'Move to environment variables',
      'weak-crypto': 'Use crypto.randomBytes for secure random values'
    };
    return fixes[type] || 'Review security best practices';
  }
  
  async handleSecurityKeypress(key, str) {
    if (!key) return;
    
    if (key.name === 'r') {
      console.log(chalk.blue('\nšŸ”„ Running full security scan...'));
      await this.runSecurityScan();
      await this.updateDisplay();
    } else if (key.name === 's') {
      // TODO: Implement file-specific scanning
      console.log(chalk.blue('\nšŸ“„ File scanning coming soon...'));
    } else if (key.name === 'd') {
      // Check dependencies
      console.log(chalk.blue('\nšŸ“¦ Checking dependencies...'));
      const depChecker = new DependencyChecker(this.projectPath, { silent: true });
      const deps = await depChecker.checkVulnerabilities();
      console.log(deps.message);
    } else if (key.name === 'f') {
      console.log(chalk.yellow('\nšŸ”§ Auto-fix feature coming soon...'));
    } else if (str && !key.ctrl && !key.meta) {
      process.stdout.write('\r\x1B[K');
    }
  }
  
  async displaySpeedMode() {
    const colors = {
          error: chalk.red,
          warning: chalk.yellow,
          success: chalk.green,
          info: chalk.blue,
          muted: chalk.gray,
          primary: chalk.white,
          secondary: chalk.cyan,
          header: chalk.bold.blue,
          highlight: chalk.bgBlue.white,
          accent: chalk.magenta
        };
    console.log(colors.header('⚔ Vibe Code - Performance Analysis'));
    console.log(colors.muted('Real-time speed and optimization monitoring'));
    console.log(colors.muted('─'.repeat(60)));
    
    // Run performance analysis if needed
    if (!this.performanceMetrics || Date.now() - (this.lastSpeedCheck || 0) > 15000) {
      await this.runSpeedAnalysis();
    }
    
    // Performance score
    const perfScore = this.performanceMetrics.score || 0;
    const scoreColor = perfScore >= 80 ? colors.success : perfScore >= 60 ? colors.warning : colors.error;
    const grade = this.getGrade(perfScore);
    
    console.log(scoreColor.bold(`Performance Score: ${perfScore}/100 (${grade})\n`));
    
    // Bundle analysis
    if (this.performanceMetrics.bundleSize) {
      const bundle = this.performanceMetrics.bundleSize;
      console.log(colors.secondary('šŸ“¦ Bundle Analysis:'));
      const sizeColor = bundle.totalSize > 2 * 1024 * 1024 ? colors.error : colors.success;
      console.log(sizeColor(`• Total Size: ${this.formatSize(bundle.totalSize)}${bundle.totalSize > 2 * 1024 * 1024 ? ' (āŒ Target: < 2MB)' : ' āœ…'}`));
      
      if (bundle.breakdown) {
        console.log(`• JS: ${this.formatSize(bundle.breakdown.js.size)} | CSS: ${this.formatSize(bundle.breakdown.css.size)} | Images: ${this.formatSize(bundle.breakdown.other.size)}`);
      }
      
      if (bundle.largeFiles && bundle.largeFiles.length > 0) {
        console.log(colors.warning(`• Largest: ${bundle.largeFiles[0].name} (${bundle.largeFiles[0].size}) - Consider code splitting`));
      }
    }
    
    // Image optimization
    if (this.performanceMetrics.images) {
      const images = this.performanceMetrics.images;
      if (images.unoptimized > 0) {
        console.log(colors.secondary('\nšŸ–¼ļø Image Optimization:'));
        console.log(colors.warning(`• ${images.unoptimized} unoptimized images (Save ${images.potentialSavings || 'significant size'})`));
        if (images.recommendations && images.recommendations.length > 0) {
          images.recommendations.slice(0, 2).forEach(rec => {
            console.log(colors.muted(`  - ${rec.file}: ${rec.size} → ${rec.optimizedSize} (${rec.format})`));
          });
        }
      }
    }
    
    // Core Web Vitals (simulated)
    console.log(colors.secondary('\n⚔ Core Web Vitals (Simulated):'));
    const lcp = this.performanceMetrics.lcp || 3.2;
    const fid = this.performanceMetrics.fid || 95;
    const cls = this.performanceMetrics.cls || 0.15;
    
    console.log(`• LCP: ${lcp}s ${lcp <= 2.5 ? 'āœ…' : 'āš ļø'} (Target: < 2.5s)`);
    console.log(`• FID: ${fid}ms ${fid <= 100 ? 'āœ…' : 'āš ļø'} (Target: < 100ms)`);
    console.log(`• CLS: ${cls} ${cls <= 0.1 ? 'āœ…' : 'āš ļø'} (Target: < 0.1)`);
    
    // Hot spots
    if (this.performanceMetrics.hotSpots && this.performanceMetrics.hotSpots.length > 0) {
      console.log(colors.secondary('\nšŸ”„ Hot Spots:'));
      this.performanceMetrics.hotSpots.slice(0, 3).forEach((spot, idx) => {
        console.log(colors.warning(`${idx + 1}. ${spot.file}: ${spot.issue}`));
      });
    }
    
    // Real-time metrics
    console.log(colors.secondary('\nšŸ“ˆ Real-time Metrics:'));
    const buildTime = this.buildMetrics.length > 0 ? this.buildMetrics[this.buildMetrics.length - 1].time : 'N/A';
    console.log(colors.muted(`Build time: ${buildTime} | Memory: ${process.memoryUsage().heapUsed / 1024 / 1024 | 0}MB`));
    
    this.showControlsFooter(colors, ['r - Run performance analysis', 'b - Bundle details', 'i - Image optimizer', 'c - Core Web Vitals']);
  }
  
  async runSpeedAnalysis() {
    this.lastSpeedCheck = Date.now();
    
    try {
      const perfOptimizer = new PerformanceOptimizer(this.projectPath, { silent: true });
      const results = await perfOptimizer.checkAll();
      
      // Calculate performance score
      let score = 100;
      const hotSpots = [];
      
      // Bundle size scoring
      if (results.bundleSize) {
        const totalSize = results.bundleSize.totalSize || 0;
        if (totalSize > 5 * 1024 * 1024) score -= 30;
        else if (totalSize > 2 * 1024 * 1024) score -= 15;
        else if (totalSize > 1 * 1024 * 1024) score -= 5;
        
        if (results.bundleSize.largeFiles) {
          results.bundleSize.largeFiles.forEach(file => {
            hotSpots.push({
              file: file.name,
              issue: `Large file: ${file.size}`
            });
          });
        }
      }
      
      // Image optimization scoring
      if (results.imageOptimization) {
        const unoptimized = results.imageOptimization.unoptimized || 0;
        score -= Math.min(20, unoptimized * 2);
      }
      
      // Performance issues
      if (results.performance?.issues) {
        results.performance.issues.forEach(issue => {
          if (issue.severity === 'high') score -= 5;
          else score -= 2;
          
          hotSpots.push({
            file: issue.file,
            issue: issue.message
          });
        });
      }
      
      this.performanceMetrics = {
        score: Math.max(0, score),
        bundleSize: results.bundleSize,
        images: results.imageOptimization,
        performance: results.performance,
        hotSpots,
        // Simulated Core Web Vitals
        lcp: 2.5 + (100 - score) * 0.02,
        fid: 50 + (100 - score),
        cls: 0.05 + (100 - score) * 0.002
      };
    } catch (error) {
      console.error('Performance analysis failed:', error);
    }
  }
  
  formatSize(bytes) {
    if (!bytes) return '0 B';
    if (bytes < 1024) return `${bytes} B`;
    if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
    return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
  }
  
  async handleSpeedKeypress(key, str) {
    if (!key) return;
    
    if (key.name === 'r') {
      console.log(chalk.blue('\n⚔ Running performance analysis...'));
      await this.runSpeedAnalysis();
      await this.updateDisplay();
    } else if (key.name === 'b') {
      console.log(chalk.blue('\nšŸ“¦ Detailed bundle analysis coming soon...'));
    } else if (key.name === 'i') {
      console.log(chalk.blue('\nšŸ–¼ļø Image optimization wizard coming soon...'));
    } else if (key.name === 'c') {
      console.log(chalk.blue('\nšŸ“Š Core Web Vitals testing coming soon...'));
    } else if (str && !key.ctrl && !key.meta) {
      process.stdout.write('\r\x1B[K');
    }
  }
  
  async displayGodMode() {
    const colors = {
          error: chalk.red,
          warning: chalk.yellow,
          success: chalk.green,
          info: chalk.blue,
          muted: chalk.gray,
          primary: chalk.white,
          secondary: chalk.cyan,
          header: chalk.bold.blue,
          highlight: chalk.bgBlue.white,
          accent: chalk.magenta
        };
    console.log(colors.header('šŸ‘ļø Vibe Code - God Mode Monitoring'));
    console.log(colors.muted('All-in-one comprehensive code oversight'));
    console.log(colors.muted('─'.repeat(60)));
    
    // Run all checks if needed or auto-refresh is on
    if (!this.godModeData.health || this.godModeData.autoRefresh || Date.now() - (this.lastGodCheck || 0) > 30000) {
      await this.runGodModeAnalysis();
    }
    
    // Overall health with color and trend
    const healthColor = this.godModeData.health >= 80 ? colors.success :
                       this.godModeData.health >= 60 ? colors.warning : colors.error;
    const trend = this.godModeData.trend || 'stable';
    const trendIcon = trend === 'improving' ? '↑' : trend === 'declining' ? '↓' : '═';
    
    console.log(healthColor.bold(`Overall Health: ${this.godModeData.health}/100 (${this.getGrade(this.godModeData.health)}) ${trendIcon} ${this.capitalize(trend)}\n`));
    
    // Critical issues
    if (this.godModeData.criticalIssues.length > 0) {
      console.log(colors.error.bold('šŸŽÆ Critical Issues (Fix First):'));
      this.godModeData.criticalIssues.slice(0, 4).forEach((issue, idx) => {
        const icon = issue.category === 'security' ? 'šŸ”’' : 
                    issue.category === 'performance' ? '⚔' :
                    issue.category === 'seo' ? 'šŸ”' : '🚨';
        console.log(colors.error(`${idx + 1}. ${icon} ${issue.severity.toUpperCase()}: ${issue.message}`));
      });
    }
    
    // Live monitors table
    console.log(colors.secondary('\nšŸ“Š Live Monitors:'));
    console.log(colors.muted('ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”'));
    console.log(colors.muted('│ Category    │ Score  │ Trend          │'));
    console.log(colors.muted('ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤'));
    
    const categories = [
      { name: 'šŸ”Ø Build', key: 'build' },
      { name: 'šŸ“¦ Deps', key: 'dependencies' },
      { name: 'šŸ”’ Security', key: 'security' },
      { name: 'šŸ” SEO', key: 'seo' },
      { name: '⚔ Speed', key: 'speed' }
    ];
    
    categories.forEach(cat => {
      const score = this.godModeData.scores?.[cat.key] || 0;
      const icon = score >= 80 ? 'āœ…' : score >= 60 ? 'āš ļø' : 'āŒ';
      const trend = this.drawSparkline(this.godModeData.trends[cat.key] || []);
      console.log(colors.muted(`│ ${cat.name.padEnd(11)} │ ${icon} ${String(score).padStart(3)} │ ${trend.padEnd(14)} │`));
    });
    
    console.log(colors.muted('ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜'));
    
    // Auto-refresh status
    const refreshStatus = this.godModeData.autoRefresh ? colors.success('ON (30s)') : colors.muted('OFF');
    console.log(colors.secondary(`\nšŸ”„ Auto-refresh: ${refreshStatus} | šŸŽ¬ Recording: `) + colors.success('ON'));
    
    // Session stats
    console.log(colors.secondary('\nšŸ“ˆ Session Stats:'));
    const sessionTime = Math.floor((Date.now() - this.stats.sessionStart) / 60000);
    console.log(colors.muted(`• Session time: ${sessionTime}m | Files changed: ${this.stats.filesModified.size}`));
    console.log(colors.muted(`• Issues fixed: ${this.godModeData.issuesFixed || 0} | Performance gain: ${this.godModeData.performanceGain || 0}%`));
    
    this.showControlsFooter(colors, ['r - Run all checks', 'a - Toggle auto-refresh', '1-5 - Focus category', 'e - Export report', 'n - Notifications']);
  }
  
  async runGodModeAnalysis() {
    this.lastGodCheck = Date.now();
    const criticalIssues = [];
    const scores = {};
    
    try {
      // Run all checks in parallel for speed
      const [buildResult, depsResult, securityResult, seoResult, perfResult] = await Promise.all([
        this.checkers.build.checkAll().catch(e => ({ error: e.message })),
        this.checkers.dependencies.checkAll().catch(e => ({ error: e.message })),
        this.checkers.security.checkAll().catch(e => ({ error: e.message })),
        new SEOChecker(this.projectPath, { silent: true }).checkAll().catch(e => ({ error: e.message })),
        this.checkers.performance.checkAll().catch(e => ({ error: e.message }))
      ]);
      
      // Calculate scores
      scores.build = buildResult.build?.status === 'passed' ? 100 : buildResult.build?.status === 'failed' ? 0 : 75;
      scores.dependencies = 100;
      if (depsResult.vulnerabilities?.vulnerabilities?.length > 0) {
        scores.dependencies -= depsResult.vulnerabilities.vulnerabilities.length * 10;
      }
      scores.security = 100;
      if (securityResult.godMode?.findings?.length > 0) {
        scores.security -= securityResult.godMode.findings.length * 15;
      }
      if (securityResult.secrets?.findings?.length > 0) {
        scores.security -= securityResult.secrets.findings.length * 20;
      }
      scores.seo = seoResult.overall?.score || 0;
      scores.speed = 100;
      if (perfResult.bundleSize?.totalSize > 2 * 1024 * 1024) {
        scores.speed -= 30;
      }
      
      // Collect critical issues
      if (securityResult.secrets?.findings?.length > 0) {
        criticalIssues.push({
          category: 'security',
          severity: 'critical',
          message: `API key exposed in ${securityResult.secrets.findings[0].file}`
        });
      }
      
      if (perfResult.bundleSize?.totalSize > 3 * 1024 * 1024) {
        criticalIssues.push({
          category: 'performance',
          severity: 'high',
          message: `Bundle size ${this.formatSize(perfResult.bundleSize.totalSize)} (target: 2MB)`
        });
      }
      
      if (seoResult.overall?.score < 60) {
        const issues = seoResult.technical?.issues?.filter(i => i.severity === 'high') || [];
        if (issues.length > 0) {
          criticalIssues.push({
            category: 'seo',
            severity: 'high',
            message: issues[0].message
          });
        }
      }
      
      // Calculate overall health
      const weights = { build: 0.2, dependencies: 0.15, security: 0.25, seo: 0.2, speed: 0.2 };
      let health = 0;
      Object.entries(weights).forEach(([key, weight]) => {
        health += (scores[key] || 0) * weight;
      });
      
      // Update trends
      Object.keys(scores).forEach(key => {
        if (!this.godModeData.trends[key]) {
          this.godModeData.trends[key] = [];
        }
        this.godModeData.trends[key].push(scores[key]);
        if (this.godModeData.trends[key].length > 10) {
          this.godModeData.trends[key].shift();
        }
      });
      
      // Determine overall trend
      const oldHealth = this.godModeData.health || health;
      this.godModeData.trend = health > oldHealth ? 'improving' : health < oldHealth ? 'declining' : 'stable';
      
      this.godModeData.health = Math.round(health);
      this.godModeData.scores = scores;
      this.godModeData.criticalIssues = criticalIssues;
    } catch (error) {
      console.error('God mode analysis failed:', error);
    }
  }
  
  drawSparkline(data) {
    if (!data || data.length === 0) return '═══════════';
    
    const chars = ['▁', 'ā–‚', 'ā–ƒ', 'ā–„', 'ā–…', 'ā–†', 'ā–‡', 'ā–ˆ'];
    const max = Math.max(...data);
    const min = Math.min(...data);
    const range = max - min || 1;
    
    return data.map(value => {
      const normalized = (value - min) / range;
      const index = Math.floor(normalized * (chars.length - 1));
      return chars[index];
    }).join('');
  }
  
  getGrade(score) {
    if (score >= 90) return 'A+';
    if (score >= 85) return 'A';
    if (score >= 80) return 'A-';
    if (score >= 75) return 'B+';
    if (score >= 70) return 'B';
    if (score >= 65) return 'B-';
    if (score >= 60) return 'C+';
    if (score >= 55) return 'C';
    if (score >= 50) return 'C-';
    if (score >= 45) return 'D+';
    if (score >= 40) return 'D';
    return 'F';
  }
  
  async handleGodModeKeypress(key, str) {
    if (!key && !str) return;
    
    if (key && key.name === 'r') {
      console.log(chalk.blue('\nšŸ”„ Running all checks...'));
      await this.runGodModeAnalysis();
      await this.updateDisplay();
    } else if (key && key.name === 'a') {
      // Toggle auto-refresh
      this.godModeData.autoRefresh = !this.godModeData.autoRefresh;
      if (this.godModeData.autoRefresh) {
        console.log(chalk.green('\nāœ… Auto-refresh enabled (30s intervals)'));
        this.godModeData.refreshInterval = setInterval(async () => {
          await this.runGodModeAnalysis();
          await this.updateDisplay();
        }, 30000);
      } else {
        console.log(chalk.yellow('\nāŒ Auto-refresh disabled'));
        if (this.godModeData.refreshInterval) {
          clearInterval(this.godModeData.refreshInterval);
        }
      }
    } else if (str >= '1' && str <= '5' && !key.ctrl && !key.meta) {
      // Jump to specific category
      const categoryMap = { '1': 'checks', '2': 'checks', '3': 'security', '4': 'seo', '5': 'speed' };
      this.currentMode = categoryMap[str];
      this.currentModeIndex = this.modes.indexOf(this.currentMode);
      await this.updateDisplay();
      this.showModeNotification();
    } else if (key && key.name === 'e') {
      console.log(chalk.blue('\nšŸ“„ Export feature coming soon...'));
    } else if (key && key.name === 'n') {
      console.log(chalk.blue('\nšŸ”” Notification settings coming soon...'));
    } else if (str && !key.ctrl && !key.meta) {
      process.stdout.write('\r\x1B[K');
    }
  }
}

export async function startUnifiedMonitor(projectPath) {
  const monitor = new UnifiedMonitor(projectPath);
  await monitor.start();
  return monitor;
}