zai-mcp-server
Version:
🚀 REVOLUTIONARY AI-to-AI Collaboration Platform v6.1! NEW: Advanced Debugging Tools with Screenshot Analysis, Console Error Parsing, Automated Fix Generation, 5 Specialized Debugging Agents, Visual UI Analysis, JavaScript Error Intelligence, CSS/HTML Fix
583 lines (503 loc) • 19 kB
JavaScript
/**
* Console Error Analyzer - Parses and analyzes JavaScript console errors
* Provides intelligent error classification, root cause analysis, and fix suggestions
*/
export class ConsoleErrorAnalyzer {
constructor(multiProviderAI) {
this.multiProviderAI = multiProviderAI;
this.errorPatterns = new Map();
this.knownSolutions = new Map();
this.initializeErrorPatterns();
this.initializeKnownSolutions();
console.log('🐛 Console Error Analyzer initialized with intelligent error parsing');
}
/**
* Initialize common error patterns
*/
initializeErrorPatterns() {
this.errorPatterns.set('syntax', {
patterns: [
/SyntaxError/i,
/Unexpected token/i,
/Unexpected end of input/i,
/Invalid or unexpected token/i
],
severity: 'critical',
category: 'syntax'
});
this.errorPatterns.set('reference', {
patterns: [
/ReferenceError/i,
/is not defined/i,
/Cannot access.*before initialization/i
],
severity: 'high',
category: 'reference'
});
this.errorPatterns.set('type', {
patterns: [
/TypeError/i,
/Cannot read propert(y|ies) of/i,
/Cannot set propert(y|ies) of/i,
/is not a function/i,
/Cannot destructure/i
],
severity: 'high',
category: 'type'
});
this.errorPatterns.set('network', {
patterns: [
/NetworkError/i,
/Failed to fetch/i,
/ERR_NETWORK/i,
/ERR_INTERNET_DISCONNECTED/i,
/CORS/i
],
severity: 'medium',
category: 'network'
});
this.errorPatterns.set('react', {
patterns: [
/Warning: React/i,
/Warning: Each child in a list should have a unique "key" prop/i,
/Warning: Failed prop type/i,
/Cannot update a component while rendering/i
],
severity: 'medium',
category: 'react'
});
this.errorPatterns.set('vue', {
patterns: [
/\[Vue warn\]/i,
/Property or method .* is not defined/i,
/Invalid prop/i,
/Unknown custom element/i
],
severity: 'medium',
category: 'vue'
});
this.errorPatterns.set('angular', {
patterns: [
/ERROR Error/i,
/NullInjectorError/i,
/ExpressionChangedAfterItHasBeenCheckedError/i,
/Cannot find module/i
],
severity: 'medium',
category: 'angular'
});
}
/**
* Initialize known solutions for common errors
*/
initializeKnownSolutions() {
this.knownSolutions.set('is not defined', {
solution: 'Variable or function is not declared. Check spelling and ensure proper import/declaration.',
fixes: [
'Check variable spelling',
'Add proper import statement',
'Declare variable before use',
'Check scope and closure issues'
]
});
this.knownSolutions.set('Cannot read properties of undefined', {
solution: 'Trying to access property of undefined/null object. Add null checks or optional chaining.',
fixes: [
'Add null/undefined checks: if (obj && obj.property)',
'Use optional chaining: obj?.property',
'Initialize object with default values',
'Check async data loading timing'
]
});
this.knownSolutions.set('is not a function', {
solution: 'Variable is not a function or method does not exist. Check function name and object type.',
fixes: [
'Verify function name spelling',
'Check if object has the method',
'Ensure proper function binding',
'Check async loading of functions'
]
});
this.knownSolutions.set('Failed to fetch', {
solution: 'Network request failed. Check URL, CORS settings, and network connectivity.',
fixes: [
'Verify API endpoint URL',
'Check CORS configuration',
'Add error handling for network requests',
'Implement retry logic for failed requests'
]
});
}
/**
* Analyze console errors
*/
async analyzeErrors(consoleErrors, options = {}) {
console.log(`🔍 Analyzing ${consoleErrors.length} console errors...`);
const errors = [];
const issues = [];
const patterns = new Map();
// Process each error
for (let i = 0; i < consoleErrors.length; i++) {
const rawError = consoleErrors[i];
const processedError = await this.processError(rawError, i, options);
errors.push(processedError);
// Convert to issue format
const issue = this.errorToIssue(processedError);
issues.push(issue);
// Track patterns
const pattern = processedError.pattern || 'unknown';
patterns.set(pattern, (patterns.get(pattern) || 0) + 1);
}
// Analyze error relationships
const relationships = this.analyzeErrorRelationships(errors);
// Generate summary
const summary = this.generateErrorSummary(errors, patterns, relationships);
console.log(`✅ Error analysis completed: ${issues.length} issues identified`);
return {
errors,
issues,
patterns: Object.fromEntries(patterns),
relationships,
summary
};
}
/**
* Process individual error
*/
async processError(rawError, index, options) {
const error = {
id: `error_${index}_${Date.now()}`,
raw: rawError,
timestamp: this.extractTimestamp(rawError),
message: this.extractMessage(rawError),
stack: this.extractStackTrace(rawError),
file: this.extractFile(rawError),
line: this.extractLine(rawError),
column: this.extractColumn(rawError),
type: 'unknown',
category: 'unknown',
severity: 'medium',
pattern: null,
rootCause: null,
suggestions: []
};
// Classify error
this.classifyError(error);
// Extract root cause
if (options.findRootCause !== false) {
error.rootCause = await this.findRootCause(error);
}
// Generate suggestions
error.suggestions = this.generateSuggestions(error);
return error;
}
/**
* Extract timestamp from error
*/
extractTimestamp(rawError) {
if (typeof rawError === 'object' && rawError.timestamp) {
return rawError.timestamp;
}
// Try to extract from error string
const timestampMatch = rawError.toString().match(/(\d{2}:\d{2}:\d{2})/);
return timestampMatch ? timestampMatch[1] : new Date().toISOString();
}
/**
* Extract error message
*/
extractMessage(rawError) {
if (typeof rawError === 'string') {
return rawError.split('\n')[0].trim();
}
if (typeof rawError === 'object') {
return rawError.message || rawError.error || rawError.toString();
}
return rawError.toString();
}
/**
* Extract stack trace
*/
extractStackTrace(rawError) {
if (typeof rawError === 'object' && rawError.stack) {
return rawError.stack.split('\n').slice(1); // Remove first line (message)
}
if (typeof rawError === 'string') {
const lines = rawError.split('\n');
return lines.slice(1).filter(line => line.trim().startsWith('at '));
}
return [];
}
/**
* Extract file name from error
*/
extractFile(rawError) {
const stack = this.extractStackTrace(rawError);
if (stack.length > 0) {
const match = stack[0].match(/\(([^:]+):/);
return match ? match[1] : 'unknown';
}
const message = this.extractMessage(rawError);
const fileMatch = message.match(/at ([^:]+):/);
return fileMatch ? fileMatch[1] : 'unknown';
}
/**
* Extract line number from error
*/
extractLine(rawError) {
const stack = this.extractStackTrace(rawError);
if (stack.length > 0) {
const match = stack[0].match(/:(\d+):/);
return match ? parseInt(match[1]) : null;
}
const message = this.extractMessage(rawError);
const lineMatch = message.match(/:(\d+):/);
return lineMatch ? parseInt(lineMatch[1]) : null;
}
/**
* Extract column number from error
*/
extractColumn(rawError) {
const stack = this.extractStackTrace(rawError);
if (stack.length > 0) {
const match = stack[0].match(/:(\d+):(\d+)/);
return match ? parseInt(match[2]) : null;
}
return null;
}
/**
* Classify error type and category
*/
classifyError(error) {
const message = error.message.toLowerCase();
for (const [type, config] of this.errorPatterns) {
for (const pattern of config.patterns) {
if (pattern.test(error.message)) {
error.type = type;
error.category = config.category;
error.severity = config.severity;
error.pattern = type;
return;
}
}
}
// Fallback classification
if (message.includes('error')) {
error.type = 'runtime';
error.category = 'runtime';
error.severity = 'medium';
}
}
/**
* Find root cause of error
*/
async findRootCause(error) {
try {
const prompt = this.buildRootCausePrompt(error);
const response = await this.multiProviderAI.generateResponse(prompt, {
maxTokens: 300,
temperature: 0.1
});
return this.parseRootCause(response);
} catch (aiError) {
console.error('Failed to generate AI root cause analysis:', aiError.message);
return this.generateBasicRootCause(error);
}
}
/**
* Build prompt for root cause analysis
*/
buildRootCausePrompt(error) {
let prompt = `Analyze this JavaScript error and identify the root cause:\n\n`;
prompt += `Error: ${error.message}\n`;
prompt += `Type: ${error.type}\n`;
prompt += `File: ${error.file}:${error.line}\n`;
if (error.stack.length > 0) {
prompt += `Stack trace:\n${error.stack.slice(0, 3).join('\n')}\n`;
}
prompt += `\nProvide a concise root cause analysis focusing on:\n`;
prompt += `1. What specifically caused this error\n`;
prompt += `2. Why it occurred (timing, logic, data issues)\n`;
prompt += `3. The most likely fix approach\n\n`;
prompt += `Keep response under 100 words.`;
return prompt;
}
/**
* Parse root cause from AI response
*/
parseRootCause(response) {
return response.trim().split('\n')[0]; // Take first line as primary cause
}
/**
* Generate basic root cause without AI
*/
generateBasicRootCause(error) {
const knownCauses = {
'syntax': 'Invalid JavaScript syntax in the code',
'reference': 'Variable or function not properly declared or imported',
'type': 'Incorrect data type or null/undefined value access',
'network': 'Network connectivity or API endpoint issue',
'react': 'React component or prop configuration issue',
'vue': 'Vue component or directive configuration issue',
'angular': 'Angular dependency injection or component issue'
};
return knownCauses[error.type] || 'Unknown error cause - requires manual investigation';
}
/**
* Generate fix suggestions
*/
generateSuggestions(error) {
const suggestions = [];
// Check known solutions
for (const [pattern, solution] of this.knownSolutions) {
if (error.message.toLowerCase().includes(pattern.toLowerCase())) {
suggestions.push(...solution.fixes);
break;
}
}
// Add category-specific suggestions
const categorySuggestions = this.getCategorySuggestions(error.category);
suggestions.push(...categorySuggestions);
// Remove duplicates and limit to 5
return [...new Set(suggestions)].slice(0, 5);
}
/**
* Get category-specific suggestions
*/
getCategorySuggestions(category) {
const suggestions = {
'syntax': ['Check for missing brackets, semicolons, or quotes', 'Validate JavaScript syntax'],
'reference': ['Check variable declarations and imports', 'Verify function and variable names'],
'type': ['Add null/undefined checks', 'Validate data types before operations'],
'network': ['Check API endpoints and CORS settings', 'Add network error handling'],
'react': ['Check component props and state', 'Verify React hooks usage'],
'vue': ['Check Vue component configuration', 'Verify directive usage'],
'angular': ['Check dependency injection', 'Verify component lifecycle']
};
return suggestions[category] || ['Review error details and check documentation'];
}
/**
* Analyze relationships between errors
*/
analyzeErrorRelationships(errors) {
const relationships = [];
// Group by file
const fileGroups = new Map();
errors.forEach(error => {
const file = error.file;
if (!fileGroups.has(file)) {
fileGroups.set(file, []);
}
fileGroups.get(file).push(error);
});
// Find cascading errors
for (const [file, fileErrors] of fileGroups) {
if (fileErrors.length > 1) {
relationships.push({
type: 'cascading',
file,
errors: fileErrors.map(e => e.id),
description: `Multiple errors in ${file} may be related`
});
}
}
// Find timing-related errors
const timeGroups = this.groupErrorsByTime(errors);
for (const group of timeGroups) {
if (group.length > 1) {
relationships.push({
type: 'timing',
errors: group.map(e => e.id),
description: 'Errors occurred within short time window'
});
}
}
return relationships;
}
/**
* Group errors by time proximity
*/
groupErrorsByTime(errors) {
const groups = [];
const timeWindow = 1000; // 1 second
for (const error of errors) {
const errorTime = new Date(error.timestamp).getTime();
let addedToGroup = false;
for (const group of groups) {
const groupTime = new Date(group[0].timestamp).getTime();
if (Math.abs(errorTime - groupTime) <= timeWindow) {
group.push(error);
addedToGroup = true;
break;
}
}
if (!addedToGroup) {
groups.push([error]);
}
}
return groups.filter(group => group.length > 1);
}
/**
* Generate error summary
*/
generateErrorSummary(errors, patterns, relationships) {
const totalErrors = errors.length;
const criticalErrors = errors.filter(e => e.severity === 'critical').length;
const highErrors = errors.filter(e => e.severity === 'high').length;
const topPatterns = Array.from(patterns.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, 3);
return {
total: totalErrors,
critical: criticalErrors,
high: highErrors,
medium: errors.filter(e => e.severity === 'medium').length,
low: errors.filter(e => e.severity === 'low').length,
topPatterns: topPatterns.map(([pattern, count]) => ({ pattern, count })),
relationships: relationships.length,
recommendation: this.generateOverallRecommendation(errors, patterns)
};
}
/**
* Generate overall recommendation
*/
generateOverallRecommendation(errors, patterns) {
const criticalCount = errors.filter(e => e.severity === 'critical').length;
const highCount = errors.filter(e => e.severity === 'high').length;
if (criticalCount > 0) {
return 'Fix critical syntax and reference errors immediately';
}
if (highCount > 3) {
return 'Address high-priority type and reference errors first';
}
const topPattern = Array.from(patterns.entries()).sort((a, b) => b[1] - a[1])[0];
if (topPattern && topPattern[1] > 2) {
return `Focus on resolving ${topPattern[0]} errors (${topPattern[1]} occurrences)`;
}
return 'Review and fix errors in order of severity';
}
/**
* Convert error to issue format
*/
errorToIssue(error) {
return {
id: error.id,
type: `console_error_${error.type}`,
category: 'javascript',
severity: error.severity,
title: `${error.type.charAt(0).toUpperCase() + error.type.slice(1)} Error`,
description: error.message,
location: {
file: error.file,
line: error.line,
column: error.column
},
rootCause: error.rootCause,
suggestions: error.suggestions,
metadata: {
pattern: error.pattern,
stack: error.stack,
timestamp: error.timestamp
}
};
}
}