- Real-time error monitoring system with WebSocket - Auto-fix agent that triggers on browser errors - Bug tracker dashboard with floating button (🐛) - Live activity stream showing AI thought process - Fixed 4 JavaScript errors (SyntaxError, TypeError) - Fixed SessionPicker API endpoint error - Enhanced chat input with Monaco editor - Session picker component for project management Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
227 lines
6.4 KiB
JavaScript
227 lines
6.4 KiB
JavaScript
#!/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 };
|