#!/usr/bin/env node /** * Auto-Fix Error Agent * Triggered automatically when browser errors are detected * Analyzes error and attempts to fix it */ const fs = require('fs'); const path = require('path'); const { spawn } = require('child_process'); const ERROR_LOG = '/tmp/browser-errors.log'; const SERVER_LOG = '/tmp/obsidian-server.log'; const WORKING_DIR = '/home/uroma/obsidian-web-interface'; const AGENT_LOG = '/tmp/auto-fix-agent.log'; // Log function function log(message) { const timestamp = new Date().toISOString(); const logMessage = `[${timestamp}] ${message}\n`; console.log(logMessage.trim()); fs.appendFileSync(AGENT_LOG, logMessage); } // Error patterns and their fixes const ERROR_FIXES = { // Authentication errors 'Unauthorized': { type: 'auth', description: 'Authentication required', fix: 'Check authentication middleware and session handling' }, // 404 errors '404': { type: 'missing_endpoint', description: 'Endpoint not found', fix: 'Check if route exists in server.js' }, // Failed to fetch 'Failed to load': { type: 'resource_error', description: 'Resource loading failed', fix: 'Check if file exists and path is correct' }, // Network errors 'Failed to fetch': { type: 'network_error', description: 'Network request failed', fix: 'Check CORS, endpoint availability, and network configuration' } }; // Analyze error function analyzeError(error) { log('🔍 Analyzing error...'); log(` Type: ${error.type}`); log(` Message: ${error.message}`); // Determine error category let category = 'unknown'; for (const [pattern, fix] of Object.entries(ERROR_FIXES)) { if (error.message.includes(pattern)) { category = fix.type; log(` Category: ${category}`); log(` Fix Strategy: ${fix.fix}`); break; } } return category; } // Find relevant files based on error function findRelevantFiles(error) { const files = []; if (error.filename) { // Extract file path from error const filePath = error.filename.replace(window.location.origin, ''); files.push(path.join(WORKING_DIR, 'public', filePath)); } if (error.message.includes('projects')) { files.push( path.join(WORKING_DIR, 'server.js'), path.join(WORKING_DIR, 'public/claude-ide/sessions-landing.js'), path.join(WORKING_DIR, 'public/claude-ide/ide.js') ); } if (error.message.includes('session')) { files.push( path.join(WORKING_DIR, 'services/claude-service.js'), path.join(WORKING_DIR, 'public/claude-ide/chat-functions.js') ); } return files; } // Trigger Claude Code to fix the error async function triggerClaudeFix(error, category, relevantFiles) { log('🤖 Triggering Claude Code agent to fix error...'); const prompt = ` ERROR DETECTED - Auto-Fix Request: Type: ${error.type} Message: ${error.message} URL: ${error.url} Line: ${error.line || 'N/A'} Stack: ${error.stack || 'N/A'} Category: ${category} Please analyze this error and provide a fix. Focus on: 1. Root cause identification 2. Specific file and line numbers to modify 3. Code changes needed 4. Testing steps to verify fix The error monitoring system detected this automatically. Please provide a concise fix. `.trim(); // Create a task file for Claude const taskFile = '/tmp/auto-fix-task.txt'; fs.writeFileSync(taskFile, prompt); log(`📝 Task created: ${taskFile}`); log('⏳ Awaiting fix implementation...'); // Return the task file path so it can be processed return taskFile; } // Main auto-fix function async function processError(error) { log('\n' + '='.repeat(60)); log('🚨 AUTO-FIX AGENT TRIGGERED'); log('='.repeat(60)); const category = analyzeError(error); const relevantFiles = findRelevantFiles(error); if (relevantFiles.length > 0) { log(`📁 Relevant files: ${relevantFiles.join(', ')}`); } const taskFile = await triggerClaudeFix(error, category, relevantFiles); log('✅ Error queued for fixing'); log('='.repeat(60) + '\n'); return { success: true, category, taskFile, relevantFiles }; } // Watch for new errors function watchForErrors() { log('👀 Auto-fix agent watching for errors...'); log(`📂 Error log: ${ERROR_LOG}`); log(`📂 Server log: ${SERVER_LOG}`); log(''); let lastSize = 0; if (fs.existsSync(ERROR_LOG)) { lastSize = fs.statSync(ERROR_LOG).size; } setInterval(() => { if (!fs.existsSync(ERROR_LOG)) return; const currentSize = fs.statSync(ERROR_LOG).size; if (currentSize > lastSize) { // New error logged const content = fs.readFileSync(ERROR_LOG, 'utf8'); const newContent = content.substring(lastSize); const lines = newContent.trim().split('\n'); for (const line of lines) { try { const error = JSON.parse(line); processError(error); } catch (e) { log(`⚠️ Failed to parse error: ${e.message}`); } } lastSize = currentSize; } }, 2000); // Check every 2 seconds } // CLI interface if (require.main === module) { const args = process.argv.slice(2); if (args[0] === 'watch') { // Watch mode watchForErrors(); } else if (args[0] === 'process') { // Process single error from stdin const errorData = fs.readFileSync(0, 'utf-8'); try { const error = JSON.parse(errorData); processError(error); } catch (e) { log(`❌ Failed to parse error: ${e.message}`); process.exit(1); } } else { console.log('Usage:'); console.log(' node auto-fix-agent.js watch # Watch for errors continuously'); console.log(' echo \'{"type":"test","message":"error"}\' | node auto-fix-agent.js process'); } } module.exports = { processError, analyzeError };