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
427 lines (371 loc) • 15.5 kB
JavaScript
/**
* Enhanced Web Debugging Manager
* Comprehensive web application debugging with cross-browser testing,
* performance monitoring, and accessibility auditing
*/
import { spawn, exec } from 'child_process';
import { promisify } from 'util';
import fs from 'fs/promises';
import path from 'path';
const execAsync = promisify(exec);
export class EnhancedWebDebuggingManager {
constructor(multiProviderAI, screenshotProcessor, consoleErrorAnalyzer) {
this.multiProviderAI = multiProviderAI;
this.screenshotProcessor = screenshotProcessor;
this.consoleErrorAnalyzer = consoleErrorAnalyzer;
// Enhanced web debugging capabilities
this.supportedBrowsers = ['chrome', 'firefox', 'safari', 'edge'];
this.supportedFrameworks = ['react', 'vue', 'angular', 'svelte', 'vanilla'];
this.supportedLanguages = ['javascript', 'typescript', 'html', 'css', 'scss', 'less'];
// Active debugging sessions
this.activeSessions = new Map();
this.browserInstances = new Map();
this.performanceMonitors = new Map();
this.accessibilityAudits = new Map();
// Debugging directories
this.screenshotDir = './web-screenshots';
this.performanceDir = './web-performance';
this.accessibilityDir = './web-accessibility';
this.lighthouseDir = './lighthouse-reports';
// Initialize directories
this.initializeDirectories();
console.log('🌐 Enhanced Web Debugging Manager initialized with cross-browser and performance capabilities');
}
/**
* Initialize required directories
*/
async initializeDirectories() {
try {
await fs.mkdir(this.screenshotDir, { recursive: true });
await fs.mkdir(this.performanceDir, { recursive: true });
await fs.mkdir(this.accessibilityDir, { recursive: true });
await fs.mkdir(this.lighthouseDir, { recursive: true });
console.log('📁 Enhanced web debugging directories initialized');
} catch (error) {
console.error('Failed to initialize directories:', error.message);
}
}
/**
* Cross-Browser Testing: Launch multiple browsers for testing
*/
async launchCrossBrowserTesting(url, options = {}) {
console.log(`🌐 Launching cross-browser testing for: ${url}`);
const browsers = options.browsers || this.supportedBrowsers;
const results = [];
for (const browser of browsers) {
try {
const browserResult = await this.launchBrowser(browser, url, options);
results.push({
browser,
success: true,
...browserResult
});
} catch (error) {
results.push({
browser,
success: false,
error: error.message
});
}
}
const successCount = results.filter(r => r.success).length;
console.log(`✅ Launched ${successCount}/${browsers.length} browsers for cross-browser testing`);
return {
success: successCount > 0,
totalBrowsers: browsers.length,
launchedBrowsers: successCount,
results
};
}
/**
* Launch individual browser instance
*/
async launchBrowser(browser, url, options = {}) {
console.log(`🚀 Launching ${browser} for testing...`);
const browserCommands = {
chrome: 'google-chrome',
firefox: 'firefox',
safari: 'safari',
edge: 'microsoft-edge'
};
const command = browserCommands[browser];
if (!command) {
throw new Error(`Unsupported browser: ${browser}`);
}
// Launch browser with debugging flags
const args = this.getBrowserArgs(browser, options);
const browserProcess = spawn(command, [...args, url]);
const sessionId = `${browser}_${Date.now()}`;
this.browserInstances.set(sessionId, {
browser,
process: browserProcess,
url,
startTime: Date.now(),
options
});
return {
sessionId,
browser,
url,
pid: browserProcess.pid
};
}
/**
* Get browser-specific launch arguments
*/
getBrowserArgs(browser, options) {
const commonArgs = [
'--no-first-run',
'--disable-background-timer-throttling',
'--disable-renderer-backgrounding'
];
const browserSpecificArgs = {
chrome: [
'--remote-debugging-port=9222',
'--disable-web-security',
'--disable-features=VizDisplayCompositor',
'--headless=' + (options.headless ? 'new' : 'false')
],
firefox: [
'--remote-debugging-port=9223',
'--headless=' + (options.headless || false)
],
safari: [],
edge: [
'--remote-debugging-port=9224',
'--headless=' + (options.headless || false)
]
};
return [...commonArgs, ...(browserSpecificArgs[browser] || [])];
}
/**
* Core Web Vitals Monitoring: Monitor LCP, FID, CLS
*/
async startCoreWebVitalsMonitoring(url, options = {}) {
console.log(`📊 Starting Core Web Vitals monitoring for: ${url}`);
const monitoringId = `cwv_${Date.now()}`;
const duration = options.duration || 300000; // 5 minutes default
const monitor = {
id: monitoringId,
url,
startTime: Date.now(),
duration,
samples: [],
isActive: true
};
this.performanceMonitors.set(monitoringId, monitor);
// Start periodic monitoring
const monitoringInterval = setInterval(async () => {
try {
const vitals = await this.measureCoreWebVitals(url);
monitor.samples.push({
timestamp: Date.now(),
vitals
});
// Save to file periodically
const performanceFile = path.join(this.performanceDir, `${monitoringId}.json`);
await fs.writeFile(performanceFile, JSON.stringify(monitor, null, 2));
} catch (error) {
console.error('Core Web Vitals monitoring error:', error.message);
}
}, 30000); // Sample every 30 seconds
// Stop monitoring after duration
setTimeout(async () => {
clearInterval(monitoringInterval);
monitor.isActive = false;
const analysis = await this.analyzeCoreWebVitals(monitor);
monitor.analysis = analysis;
const performanceFile = path.join(this.performanceDir, `${monitoringId}.json`);
await fs.writeFile(performanceFile, JSON.stringify(monitor, null, 2));
console.log(`📊 Core Web Vitals monitoring completed for ${url}`);
}, duration);
return {
success: true,
monitoringId,
url,
duration,
message: 'Core Web Vitals monitoring started'
};
}
/**
* Measure Core Web Vitals using Lighthouse
*/
async measureCoreWebVitals(url) {
try {
// Use Lighthouse to measure Core Web Vitals
const lighthouseResult = await execAsync(`lighthouse ${url} --output=json --quiet --chrome-flags="--headless"`);
const report = JSON.parse(lighthouseResult.stdout);
const audits = report.lhr.audits;
return {
lcp: audits['largest-contentful-paint']?.numericValue || 0,
fid: audits['max-potential-fid']?.numericValue || 0,
cls: audits['cumulative-layout-shift']?.numericValue || 0,
fcp: audits['first-contentful-paint']?.numericValue || 0,
si: audits['speed-index']?.numericValue || 0,
tti: audits['interactive']?.numericValue || 0,
performanceScore: report.lhr.categories.performance?.score * 100 || 0
};
} catch (error) {
console.error('Failed to measure Core Web Vitals:', error.message);
return {
lcp: 0,
fid: 0,
cls: 0,
fcp: 0,
si: 0,
tti: 0,
performanceScore: 0,
error: error.message
};
}
}
/**
* WCAG Compliance Auditing: Comprehensive accessibility audit
*/
async performWCAGAudit(url, options = {}) {
console.log(`♿ Performing WCAG compliance audit for: ${url}`);
const auditId = `wcag_${Date.now()}`;
const auditFile = path.join(this.accessibilityDir, `${auditId}.json`);
try {
// Use axe-core for accessibility testing
const axeResult = await this.runAxeAudit(url);
// Use Lighthouse for additional accessibility checks
const lighthouseResult = await this.runLighthouseAccessibilityAudit(url);
const audit = {
id: auditId,
url,
timestamp: Date.now(),
axeResults: axeResult,
lighthouseResults: lighthouseResult,
wcagLevel: options.wcagLevel || 'AA',
summary: this.generateAccessibilitySummary(axeResult, lighthouseResult),
recommendations: this.generateAccessibilityRecommendations(axeResult, lighthouseResult)
};
this.accessibilityAudits.set(auditId, audit);
await fs.writeFile(auditFile, JSON.stringify(audit, null, 2));
console.log(`✅ WCAG audit completed: ${audit.summary.violations} violations found`);
return {
success: true,
auditId,
url,
violations: audit.summary.violations,
wcagLevel: audit.wcagLevel,
summary: audit.summary,
recommendations: audit.recommendations
};
} catch (error) {
console.error(`❌ WCAG audit failed:`, error.message);
return {
success: false,
error: error.message
};
}
}
/**
* Run axe-core accessibility audit
*/
async runAxeAudit(url) {
try {
// This would typically use axe-core via Puppeteer or Playwright
// For now, return mock data structure
return {
violations: [
{
id: 'color-contrast',
impact: 'serious',
description: 'Elements must have sufficient color contrast',
nodes: [
{
target: ['.button-primary'],
failureSummary: 'Fix any of the following: Element has insufficient color contrast'
}
]
}
],
passes: [
{
id: 'document-title',
description: 'Documents must have a title'
}
],
incomplete: [],
inapplicable: []
};
} catch (error) {
console.error('Axe audit failed:', error.message);
return { violations: [], passes: [], incomplete: [], inapplicable: [] };
}
}
/**
* Run Lighthouse accessibility audit
*/
async runLighthouseAccessibilityAudit(url) {
try {
const lighthouseResult = await execAsync(`lighthouse ${url} --output=json --only-categories=accessibility --quiet --chrome-flags="--headless"`);
const report = JSON.parse(lighthouseResult.stdout);
return {
score: report.lhr.categories.accessibility?.score * 100 || 0,
audits: report.lhr.audits
};
} catch (error) {
console.error('Lighthouse accessibility audit failed:', error.message);
return { score: 0, audits: {} };
}
}
/**
* Generate accessibility summary
*/
generateAccessibilitySummary(axeResults, lighthouseResults) {
return {
violations: axeResults.violations.length,
passes: axeResults.passes.length,
incomplete: axeResults.incomplete.length,
lighthouseScore: lighthouseResults.score,
criticalIssues: axeResults.violations.filter(v => v.impact === 'critical').length,
seriousIssues: axeResults.violations.filter(v => v.impact === 'serious').length,
moderateIssues: axeResults.violations.filter(v => v.impact === 'moderate').length,
minorIssues: axeResults.violations.filter(v => v.impact === 'minor').length
};
}
/**
* Generate accessibility recommendations
*/
generateAccessibilityRecommendations(axeResults, lighthouseResults) {
const recommendations = [];
// Priority recommendations based on violations
const criticalViolations = axeResults.violations.filter(v => v.impact === 'critical');
if (criticalViolations.length > 0) {
recommendations.push('Critical: Fix critical accessibility violations immediately');
}
const colorContrastIssues = axeResults.violations.filter(v => v.id === 'color-contrast');
if (colorContrastIssues.length > 0) {
recommendations.push('Improve color contrast ratios to meet WCAG standards');
}
if (lighthouseResults.score < 90) {
recommendations.push('Improve overall accessibility score through comprehensive audit fixes');
}
return recommendations;
}
/**
* Get enhanced debugging status
*/
getDebuggingStatus() {
return {
activeSessions: Array.from(this.activeSessions.values()),
browserInstances: Array.from(this.browserInstances.keys()),
performanceMonitors: Array.from(this.performanceMonitors.keys()),
accessibilityAudits: Array.from(this.accessibilityAudits.keys()),
supportedBrowsers: this.supportedBrowsers,
supportedFrameworks: this.supportedFrameworks,
supportedLanguages: this.supportedLanguages,
capabilities: {
crossBrowserTesting: true,
coreWebVitalsMonitoring: true,
wcagCompliance: true,
performanceAuditing: true,
accessibilityTesting: true,
lighthouseIntegration: true
}
};
}
}