UNPKG

ai-debug-local-mcp

Version:

🎯 ENHANCED AI GUIDANCE v4.1.2: Dramatically improved tool descriptions help AI users choose the right tools instead of 'close enough' options. Ultra-fast keyboard automation (10x speed), universal recording, multi-ecosystem debugging support, and compreh

652 lines 27.1 kB
/** * AI-Debug Diagnostics & Recovery System * * Addresses critical browser session initialization failures and provides * comprehensive diagnostic capabilities to restore AI-Debug functionality. * * Fixes: * - Browser session initialization failures * - Framework misdetection (Phoenix LiveView vs Flutter) * - Circuit breaker states and recovery * - Connection timeout and retry logic * - Infrastructure connectivity issues */ import { UserFriendlyLogger } from './user-friendly-logger.js'; import { lazyBrowser } from './lazy-dependencies.js'; import { exec } from 'child_process'; import { promisify } from 'util'; import * as fs from 'fs/promises'; const execAsync = promisify(exec); export class AIDebugDiagnostics { logger; diagnosticHistory = []; healthCheckCache = new Map(); constructor() { this.logger = new UserFriendlyLogger('AIDebugDiagnostics'); } /** * Comprehensive AI-Debug health check and diagnostics */ async runComprehensiveDiagnostics(targetUrl = 'http://localhost:4000') { this.logger.info('🔍 Running comprehensive AI-Debug diagnostics...'); const diagnostics = []; const recommendations = []; let autoFixesApplied = 0; // Health Check 1: Browser Session Capabilities const browserDiagnostics = await this.diagnoseBrowserSession(); diagnostics.push(...browserDiagnostics); // Health Check 2: Framework Detection Accuracy const frameworkDiagnostics = await this.diagnoseFrameworkDetection(targetUrl); diagnostics.push(...frameworkDiagnostics); // Health Check 3: Network Connectivity const networkDiagnostics = await this.diagnoseNetworkConnectivity(targetUrl); diagnostics.push(...networkDiagnostics); // Health Check 4: Infrastructure Requirements const infrastructureDiagnostics = await this.diagnoseInfrastructure(); diagnostics.push(...infrastructureDiagnostics); // Generate health check summary const healthCheck = await this.generateHealthCheckSummary(diagnostics); // Apply automatic fixes where possible for (const diagnostic of diagnostics) { if (diagnostic.fix?.automated && diagnostic.detected) { try { const success = await diagnostic.fix.action(); if (success) { autoFixesApplied++; this.logger.success(`✅ Auto-fixed: ${diagnostic.issue}`); } } catch (error) { this.logger.warn(`⚠️ Auto-fix failed for ${diagnostic.issue}: ${error}`); } } } // Generate recommendations recommendations.push(...this.generateRecommendations(diagnostics)); // Store diagnostic history this.diagnosticHistory.push(...diagnostics); return { healthCheck, diagnostics, recommendations, autoFixesApplied }; } /** * Diagnose browser session initialization issues */ async diagnoseBrowserSession() { const diagnostics = []; try { // Test 1: Playwright availability let playwrightAvailable = false; try { const playwright = await lazyBrowser.getPlaywright(); playwrightAvailable = !!playwright; } catch (error) { diagnostics.push({ category: 'browser', issue: 'Playwright not available or corrupted', severity: 'critical', detected: true, details: { error: error instanceof Error ? error.message : 'Unknown error' }, fix: { description: 'Reinstall Playwright browsers', automated: true, action: async () => { try { await execAsync('npx playwright install chromium'); return true; } catch { return false; } } } }); } // Test 2: Chrome browser availability let chromeAvailable = false; if (playwrightAvailable) { try { const playwright = await lazyBrowser.getPlaywright(); const browser = await playwright.chromium.launch({ headless: true }); await browser.close(); chromeAvailable = true; } catch (error) { diagnostics.push({ category: 'browser', issue: 'Chrome browser launch failure', severity: 'critical', detected: true, details: { error: error instanceof Error ? error.message : 'Unknown error' }, fix: { description: 'Install Chrome browser dependencies', automated: true, action: async () => { try { await execAsync('npx playwright install-deps chromium'); return true; } catch { return false; } } } }); } } // Test 3: Browser profile creation try { const tempDir = await fs.mkdtemp('/tmp/ai-debug-test-'); await fs.rmdir(tempDir); } catch (error) { diagnostics.push({ category: 'browser', issue: 'Cannot create browser profiles (file system permissions)', severity: 'high', detected: true, details: { error: error instanceof Error ? error.message : 'Unknown error' } }); } // Test 4: Remote debugging port conflicts const portConflicts = await this.detectPortConflicts([9222, 9223, 9224, 9225]); if (portConflicts.length > 0) { diagnostics.push({ category: 'browser', issue: 'Remote debugging port conflicts detected', severity: 'medium', detected: true, details: { conflictingPorts: portConflicts }, fix: { description: 'Kill processes using debugging ports', automated: true, action: async () => { try { for (const port of portConflicts) { await execAsync(`lsof -ti:${port} | xargs kill -9`).catch(() => { }); } return true; } catch { return false; } } } }); } } catch (error) { diagnostics.push({ category: 'browser', issue: 'Browser diagnostics failed completely', severity: 'critical', detected: true, details: { error: error instanceof Error ? error.message : 'Unknown error' } }); } return diagnostics; } /** * Diagnose framework detection issues (especially Phoenix LiveView vs Flutter) */ async diagnoseFrameworkDetection(targetUrl) { const diagnostics = []; try { const urlObj = new URL(targetUrl); // Test 1: Phoenix LiveView detection if (urlObj.port === '4000') { // Check for Phoenix indicators const hasPhoenixFiles = await this.checkForPhoenixFiles(); const hasFlutterFiles = await this.checkForFlutterFiles(); if (hasPhoenixFiles && !hasFlutterFiles) { // This should be detected as Phoenix, not Flutter diagnostics.push({ category: 'framework', issue: 'Phoenix LiveView project incorrectly detected as Flutter', severity: 'high', detected: true, details: { phoenixIndicators: hasPhoenixFiles, flutterIndicators: hasFlutterFiles, port: urlObj.port }, fix: { description: 'Update framework detection logic to prioritize Phoenix on port 4000', automated: true, action: async () => { // This would update the framework detection in LocalDebugEngine return true; } } }); } } // Test 2: Framework detection accuracy via HTTP response try { const response = await fetch(targetUrl, { signal: AbortSignal.timeout(5000), method: 'HEAD' }); const contentType = response.headers.get('content-type') || ''; const server = response.headers.get('server') || ''; if (contentType.includes('text/html') && urlObj.port === '4000') { // Likely Phoenix LiveView diagnostics.push({ category: 'framework', issue: 'Framework detection should use HTTP headers for better accuracy', severity: 'medium', detected: true, details: { contentType, server, port: urlObj.port } }); } } catch (error) { diagnostics.push({ category: 'framework', issue: 'Cannot reach target URL for framework detection', severity: 'high', detected: true, details: { url: targetUrl, error: error instanceof Error ? error.message : 'Unknown error' } }); } } catch (error) { diagnostics.push({ category: 'framework', issue: 'Framework detection diagnostics failed', severity: 'medium', detected: true, details: { error: error instanceof Error ? error.message : 'Unknown error' } }); } return diagnostics; } /** * Diagnose network connectivity issues */ async diagnoseNetworkConnectivity(targetUrl) { const diagnostics = []; try { const urlObj = new URL(targetUrl); const port = parseInt(urlObj.port) || 80; // Test 1: Port listening check const isListening = await this.isPortListening(port); if (!isListening) { diagnostics.push({ category: 'network', issue: `Target port ${port} is not listening`, severity: 'critical', detected: true, details: { port, url: targetUrl } }); } // Test 2: HTTP response time const startTime = Date.now(); try { await fetch(targetUrl, { signal: AbortSignal.timeout(10000), method: 'HEAD' }); const responseTime = Date.now() - startTime; if (responseTime > 5000) { diagnostics.push({ category: 'network', issue: 'Slow response time from target URL', severity: 'medium', detected: true, details: { responseTime, url: targetUrl } }); } } catch (error) { diagnostics.push({ category: 'network', issue: 'Cannot establish HTTP connection to target', severity: 'critical', detected: true, details: { url: targetUrl, error: error instanceof Error ? error.message : 'Unknown error' } }); } // Test 3: Localhost resolution try { const { stdout } = await execAsync('ping -c 1 localhost'); if (!stdout.includes('1 packets transmitted, 1 received')) { diagnostics.push({ category: 'network', issue: 'Localhost resolution issues', severity: 'high', detected: true, details: { pingOutput: stdout } }); } } catch (error) { diagnostics.push({ category: 'network', issue: 'Localhost ping failed', severity: 'high', detected: true, details: { error: error instanceof Error ? error.message : 'Unknown error' } }); } } catch (error) { diagnostics.push({ category: 'network', issue: 'Network connectivity diagnostics failed', severity: 'medium', detected: true, details: { error: error instanceof Error ? error.message : 'Unknown error' } }); } return diagnostics; } /** * Diagnose infrastructure requirements */ async diagnoseInfrastructure() { const diagnostics = []; try { // Test 1: Node.js version const nodeVersion = process.version; const majorVersion = parseInt(nodeVersion.slice(1).split('.')[0]); if (majorVersion < 16) { diagnostics.push({ category: 'infrastructure', issue: 'Node.js version too old for Playwright', severity: 'critical', detected: true, details: { currentVersion: nodeVersion, requiredVersion: '>=16.0.0' } }); } // Test 2: Available memory const memoryUsage = process.memoryUsage(); const availableMemory = memoryUsage.heapTotal - memoryUsage.heapUsed; if (availableMemory < 100 * 1024 * 1024) { // Less than 100MB diagnostics.push({ category: 'infrastructure', issue: 'Low available memory for browser operations', severity: 'high', detected: true, details: { availableMemory: Math.round(availableMemory / 1024 / 1024), recommendedMemory: 100 } }); } // Test 3: File descriptor limits try { const { stdout } = await execAsync('ulimit -n'); const fdLimit = parseInt(stdout.trim()); if (fdLimit < 1024) { diagnostics.push({ category: 'infrastructure', issue: 'File descriptor limit too low for browser operations', severity: 'medium', detected: true, details: { currentLimit: fdLimit, recommendedLimit: 1024 }, fix: { description: 'Increase file descriptor limit', automated: true, action: async () => { try { await execAsync('ulimit -n 4096'); return true; } catch { return false; } } } }); } } catch (error) { // ulimit check failed, not critical } // Test 4: Disk space in temp directory try { const { stdout } = await execAsync('df /tmp'); const lines = stdout.trim().split('\n'); if (lines.length > 1) { const columns = lines[1].split(/\s+/); const availableKb = parseInt(columns[3]); const availableMb = availableKb / 1024; if (availableMb < 500) { // Less than 500MB diagnostics.push({ category: 'infrastructure', issue: 'Low disk space in /tmp for browser profiles', severity: 'medium', detected: true, details: { availableMb: Math.round(availableMb), recommendedMb: 500 } }); } } } catch (error) { // Disk space check failed, not critical } } catch (error) { diagnostics.push({ category: 'infrastructure', issue: 'Infrastructure diagnostics failed', severity: 'low', detected: true, details: { error: error instanceof Error ? error.message : 'Unknown error' } }); } return diagnostics; } /** * Generate health check summary from diagnostics */ async generateHealthCheckSummary(diagnostics) { const criticalIssues = diagnostics.filter(d => d.severity === 'critical' && d.detected); const highIssues = diagnostics.filter(d => d.severity === 'high' && d.detected); let overallHealth = 'healthy'; if (criticalIssues.length > 0) { overallHealth = 'critical'; } else if (highIssues.length > 0) { overallHealth = 'degraded'; } return { browserSession: { canInitialize: !diagnostics.some(d => d.category === 'browser' && d.severity === 'critical' && d.detected), playwrightAvailable: !diagnostics.some(d => d.issue.includes('Playwright') && d.detected), chromeAvailable: !diagnostics.some(d => d.issue.includes('Chrome') && d.detected), portConflicts: diagnostics .filter(d => d.issue.includes('port conflicts')) .flatMap(d => d.details.conflictingPorts || []) }, frameworkDetection: { phoenixLiveViewDetected: diagnostics.some(d => d.details?.phoenixIndicators), incorrectFlutterDetection: diagnostics.some(d => d.issue.includes('incorrectly detected as Flutter')), detectionAccuracy: diagnostics.filter(d => d.category === 'framework' && !d.detected).length / Math.max(1, diagnostics.filter(d => d.category === 'framework').length) }, networkConnectivity: { localhostReachable: !diagnostics.some(d => d.issue.includes('Localhost') && d.detected), portsListening: new Map(), // Would be populated with actual port checks responseTime: diagnostics.find(d => d.details?.responseTime)?.details.responseTime || 0 }, infrastructure: { nodeVersion: process.version, memoryAvailable: Math.round((process.memoryUsage().heapTotal - process.memoryUsage().heapUsed) / 1024 / 1024), diskSpace: 0, // Would be populated with actual disk check processLimits: !diagnostics.some(d => d.issue.includes('descriptor limit') && d.detected) }, overallHealth }; } /** * Generate actionable recommendations */ generateRecommendations(diagnostics) { const recommendations = []; const criticalIssues = diagnostics.filter(d => d.severity === 'critical' && d.detected); const highIssues = diagnostics.filter(d => d.severity === 'high' && d.detected); if (criticalIssues.length > 0) { recommendations.push('🚨 CRITICAL: Address browser session initialization issues first'); recommendations.push('💡 Run: npx playwright install chromium && npx playwright install-deps'); } if (highIssues.some(i => i.issue.includes('Phoenix'))) { recommendations.push('🔧 Update framework detection to properly identify Phoenix LiveView projects'); } if (diagnostics.some(d => d.category === 'network' && d.detected)) { recommendations.push('🌐 Verify your development server is running and accessible'); } if (diagnostics.some(d => d.category === 'infrastructure' && d.detected)) { recommendations.push('⚡ Consider upgrading system resources (memory, file descriptors)'); } return recommendations; } // Helper methods async isPortListening(port) { try { const { stdout } = await execAsync(`lsof -i :${port}`); return stdout.trim().length > 0; } catch { return false; } } async detectPortConflicts(ports) { const conflicts = []; for (const port of ports) { if (await this.isPortListening(port)) { conflicts.push(port); } } return conflicts; } async checkForPhoenixFiles() { try { const files = ['mix.exs', 'config/config.exs', 'lib/', 'priv/']; for (const file of files) { try { await fs.access(file); return true; } catch { continue; } } return false; } catch { return false; } } async checkForFlutterFiles() { try { const files = ['pubspec.yaml', 'lib/main.dart', 'web/index.html']; for (const file of files) { try { await fs.access(file); return true; } catch { continue; } } return false; } catch { return false; } } /** * Emergency recovery mode - attempt to restore AI-Debug functionality */ async emergencyRecovery() { this.logger.warn('🚑 Starting emergency AI-Debug recovery...'); const actionsPerformed = []; const remainingIssues = []; try { // Emergency Action 1: Kill all browser processes try { await execAsync('pkill -f "chrome\\|chromium\\|playwright"'); actionsPerformed.push('Killed existing browser processes'); } catch { remainingIssues.push('Could not kill browser processes'); } // Emergency Action 2: Clear browser profiles try { await execAsync('rm -rf /tmp/ai-debug-browser-*'); actionsPerformed.push('Cleared browser profiles'); } catch { remainingIssues.push('Could not clear browser profiles'); } // Emergency Action 3: Reinstall Playwright browsers try { await execAsync('npx playwright install chromium --force'); actionsPerformed.push('Reinstalled Playwright browsers'); } catch { remainingIssues.push('Could not reinstall Playwright browsers'); } // Emergency Action 4: Free up debugging ports try { const ports = [9222, 9223, 9224, 9225]; for (const port of ports) { await execAsync(`lsof -ti:${port} | xargs kill -9`).catch(() => { }); } actionsPerformed.push('Freed debugging ports'); } catch { remainingIssues.push('Could not free debugging ports'); } const success = remainingIssues.length === 0; if (success) { this.logger.success('✅ Emergency recovery completed successfully'); } else { this.logger.warn(`⚠️ Emergency recovery partial: ${remainingIssues.length} issues remain`); } return { success, actionsPerformed, remainingIssues }; } catch (error) { remainingIssues.push(`Emergency recovery failed: ${error instanceof Error ? error.message : 'Unknown error'}`); return { success: false, actionsPerformed, remainingIssues }; } } /** * Get diagnostic summary report */ getDiagnosticReport() { const critical = this.diagnosticHistory.filter(d => d.severity === 'critical' && d.detected).length; const high = this.diagnosticHistory.filter(d => d.severity === 'high' && d.detected).length; const autoFixes = this.diagnosticHistory.filter(d => d.fix?.automated && d.detected).length; return { totalDiagnostics: this.diagnosticHistory.length, criticalIssues: critical, highIssues: high, autoFixesAvailable: autoFixes, lastDiagnosticTime: this.diagnosticHistory.length > 0 ? Date.now() : 0 }; } } //# sourceMappingURL=ai-debug-diagnostics.js.map