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
1,079 lines • 46.3 kB
JavaScript
/**
* Background Agent Manager
* Continuous debugging companions inspired by Wordware's background agents concept
*/
import { EventEmitter } from 'events';
/**
* Core Background Agent Manager
* Orchestrates multiple background debugging agents
*/
export class BackgroundAgentManager extends EventEmitter {
agents = new Map();
activeTimers = new Map();
escalationQueue = [];
debugContext = null;
constructor() {
super();
this.initializeDefaultAgents();
}
/**
* Initialize default background debugging agents
*/
initializeDefaultAgents() {
// Performance Watcher - monitors Core Web Vitals continuously
this.registerAgent({
id: 'performance-watcher',
name: 'Performance Watcher',
description: 'Continuously monitors Core Web Vitals and performance metrics',
status: 'idle',
config: {
supportsBackground: true,
pollingInterval: 30000, // 30 seconds
triggers: [
{
type: 'time_interval',
config: { interval: 30000 },
description: 'Check performance metrics every 30 seconds'
},
{
type: 'performance_threshold',
config: {
lcp: 2500, // Large Contentful Paint
fcp: 1800, // First Contentful Paint
cls: 0.1 // Cumulative Layout Shift
},
description: 'Alert when Core Web Vitals exceed thresholds'
}
],
maxRuntime: 24 * 60 * 60 * 1000, // 24 hours
resourceLimits: {
maxMemoryMB: 50,
maxCpuPercent: 5,
maxNetworkRequests: 120 // 2 per minute
}
},
lastExecution: null,
executionCount: 0,
findings: []
});
// Error Sentinel - watches for console errors and patterns
this.registerAgent({
id: 'error-sentinel',
name: 'Error Sentinel',
description: 'Watches console logs for errors and patterns failed requests',
status: 'idle',
config: {
supportsBackground: true,
pollingInterval: 10000, // 10 seconds
triggers: [
{
type: 'error_occurrence',
config: { errorThreshold: 1 },
description: 'Alert on any console errors'
},
{
type: 'time_interval',
config: { interval: 10000 },
description: 'Check for error patterns every 10 seconds'
}
],
maxRuntime: 24 * 60 * 60 * 1000,
resourceLimits: {
maxMemoryMB: 30,
maxCpuPercent: 3,
maxNetworkRequests: 60
}
},
lastExecution: null,
executionCount: 0,
findings: []
});
// Accessibility Guardian - periodic a11y compliance monitoring
this.registerAgent({
id: 'accessibility-guardian',
name: 'Accessibility Guardian',
description: 'Runs periodic accessibility scans and tracks compliance over time',
status: 'idle',
config: {
supportsBackground: true,
pollingInterval: 300000, // 5 minutes
triggers: [
{
type: 'time_interval',
config: { interval: 300000 },
description: 'Run accessibility audit every 5 minutes'
},
{
type: 'file_change',
config: {
patterns: ['**/*.tsx', '**/*.jsx', '**/*.vue', '**/*.html'],
debounce: 30000
},
description: 'Run audit when UI files change'
}
],
maxRuntime: 24 * 60 * 60 * 1000,
resourceLimits: {
maxMemoryMB: 100,
maxCpuPercent: 10,
maxNetworkRequests: 30
}
},
lastExecution: null,
executionCount: 0,
findings: []
});
// Regression Detective - visual change detection
this.registerAgent({
id: 'regression-detective',
name: 'Regression Detective',
description: 'Compares screenshots over time to catch visual bugs early',
status: 'idle',
config: {
supportsBackground: true,
pollingInterval: 600000, // 10 minutes
triggers: [
{
type: 'file_change',
config: {
patterns: ['**/*.css', '**/*.scss', '**/*.tsx', '**/*.jsx'],
debounce: 60000
},
description: 'Take screenshot when visual files change'
},
{
type: 'time_interval',
config: { interval: 600000 },
description: 'Periodic visual regression check'
}
],
maxRuntime: 24 * 60 * 60 * 1000,
resourceLimits: {
maxMemoryMB: 200,
maxCpuPercent: 15,
maxNetworkRequests: 20
}
},
lastExecution: null,
executionCount: 0,
findings: []
});
}
/**
* Register a new background agent
*/
registerAgent(agent) {
this.agents.set(agent.id, agent);
this.emit('agent_registered', agent);
}
/**
* Start a background agent
*/
async startAgent(agentId) {
const agent = this.agents.get(agentId);
if (!agent) {
throw new Error(`Agent ${agentId} not found`);
}
if (agent.status === 'running') {
return; // Already running
}
agent.status = 'running';
// Set up polling timer if configured
if (agent.config.pollingInterval) {
const timer = setInterval(async () => {
await this.executeAgent(agentId);
}, agent.config.pollingInterval);
this.activeTimers.set(agentId, timer);
}
// Set up max runtime limit
if (agent.config.maxRuntime) {
setTimeout(() => {
this.pauseAgent(agentId);
}, agent.config.maxRuntime);
}
this.emit('agent_started', agent);
}
/**
* Stop a background agent
*/
async stopAgent(agentId) {
const agent = this.agents.get(agentId);
if (!agent) {
throw new Error(`Agent ${agentId} not found`);
}
agent.status = 'idle';
const timer = this.activeTimers.get(agentId);
if (timer) {
clearInterval(timer);
this.activeTimers.delete(agentId);
}
this.emit('agent_stopped', agent);
}
/**
* Pause a background agent (can be resumed)
*/
async pauseAgent(agentId) {
const agent = this.agents.get(agentId);
if (!agent) {
throw new Error(`Agent ${agentId} not found`);
}
agent.status = 'paused';
const timer = this.activeTimers.get(agentId);
if (timer) {
clearInterval(timer);
this.activeTimers.delete(agentId);
}
this.emit('agent_paused', agent);
}
/**
* Execute an agent's monitoring logic
*/
async executeAgent(agentId) {
const agent = this.agents.get(agentId);
if (!agent || agent.status !== 'running') {
return;
}
try {
agent.lastExecution = new Date();
agent.executionCount++;
// Execute agent-specific logic based on agent type
const findings = await this.executeAgentLogic(agent);
// Process findings
for (const finding of findings) {
agent.findings.push(finding);
// Check if human escalation is needed
if (finding.humanEscalationNeeded) {
await this.escalateToHuman(agent, finding);
}
// Auto-fix if available and not requiring approval
if (finding.autoFixAvailable && !finding.humanEscalationNeeded) {
await this.attemptAutoFix(agent, finding);
}
}
this.emit('agent_executed', { agent, findings });
}
catch (error) {
agent.status = 'error';
this.emit('agent_error', { agent, error });
// Escalate unexpected errors to human
await this.escalateToHuman(agent, {
id: `error-${Date.now()}`,
agentId: agent.id,
timestamp: new Date(),
severity: 'error',
category: 'system',
title: 'Agent Execution Error',
description: `Agent ${agent.name} encountered an error: ${error instanceof Error ? error.message : String(error)}`,
context: { error: error instanceof Error ? error.stack : String(error) },
actionable: true,
autoFixAvailable: false,
humanEscalationNeeded: true
});
}
}
/**
* Execute agent-specific monitoring logic
*/
async executeAgentLogic(agent) {
const findings = [];
switch (agent.id) {
case 'performance-watcher':
findings.push(...await this.executePerformanceWatcher());
break;
case 'error-sentinel':
findings.push(...await this.executeErrorSentinel());
break;
case 'accessibility-guardian':
findings.push(...await this.executeAccessibilityGuardian());
break;
case 'regression-detective':
findings.push(...await this.executeRegressionDetective());
break;
}
return findings;
}
/**
* Performance Watcher execution logic
* REAL IMPLEMENTATION - No fake functionality
*/
async executePerformanceWatcher() {
const findings = [];
// Only execute if we have an active debug session with performance capabilities
if (!this.debugContext?.sessionId) {
return findings; // No active session, no work to do
}
try {
// Get performance metrics from active session (if available)
const perfMetrics = await this.getActiveSessionPerformanceMetrics();
if (perfMetrics) {
// Check against thresholds from agent config
const agent = this.agents.get('performance-watcher');
const thresholds = agent?.config.triggers?.find(t => t.type === 'performance_threshold')?.config;
if (thresholds) {
// Check LCP threshold
if (perfMetrics.lcp && perfMetrics.lcp > thresholds.lcp) {
findings.push({
id: `perf-lcp-${Date.now()}`,
agentId: 'performance-watcher',
timestamp: new Date(),
severity: 'warning',
category: 'performance',
title: 'LCP Threshold Exceeded',
description: `Large Contentful Paint is ${perfMetrics.lcp}ms (threshold: ${thresholds.lcp}ms)`,
context: { metric: 'lcp', actual: perfMetrics.lcp, threshold: thresholds.lcp },
actionable: true,
autoFixAvailable: false,
humanEscalationNeeded: perfMetrics.lcp > thresholds.lcp * 1.5 // Escalate if 50% over threshold
});
}
// Check FCP threshold
if (perfMetrics.fcp && perfMetrics.fcp > thresholds.fcp) {
findings.push({
id: `perf-fcp-${Date.now()}`,
agentId: 'performance-watcher',
timestamp: new Date(),
severity: 'warning',
category: 'performance',
title: 'FCP Threshold Exceeded',
description: `First Contentful Paint is ${perfMetrics.fcp}ms (threshold: ${thresholds.fcp}ms)`,
context: { metric: 'fcp', actual: perfMetrics.fcp, threshold: thresholds.fcp },
actionable: true,
autoFixAvailable: false,
humanEscalationNeeded: perfMetrics.fcp > thresholds.fcp * 1.5
});
}
// Check CLS threshold
if (perfMetrics.cls && perfMetrics.cls > thresholds.cls) {
findings.push({
id: `perf-cls-${Date.now()}`,
agentId: 'performance-watcher',
timestamp: new Date(),
severity: 'error',
category: 'performance',
title: 'CLS Threshold Exceeded',
description: `Cumulative Layout Shift is ${perfMetrics.cls} (threshold: ${thresholds.cls})`,
context: { metric: 'cls', actual: perfMetrics.cls, threshold: thresholds.cls },
actionable: true,
autoFixAvailable: false,
humanEscalationNeeded: true // CLS issues always need human attention
});
}
}
}
}
catch (error) {
// Real error handling - not fake
findings.push({
id: `perf-error-${Date.now()}`,
agentId: 'performance-watcher',
timestamp: new Date(),
severity: 'error',
category: 'system',
title: 'Performance Monitoring Failed',
description: `Failed to collect performance metrics: ${error instanceof Error ? error.message : String(error)}`,
context: { error: error instanceof Error ? error.stack : String(error) },
actionable: true,
autoFixAvailable: false,
humanEscalationNeeded: true
});
}
return findings;
}
/**
* Error Sentinel execution logic
* REAL IMPLEMENTATION - No fake functionality
*/
async executeErrorSentinel() {
const findings = [];
// Only execute if we have an active debug session
if (!this.debugContext?.sessionId) {
return findings; // No active session, no work to do
}
try {
// Get console errors from active session (if available)
const consoleErrors = await this.getActiveSessionConsoleErrors();
if (consoleErrors && consoleErrors.length > 0) {
// Group errors by type/message for pattern detection
const errorGroups = this.groupErrorsByPattern(consoleErrors);
for (const [pattern, errors] of errorGroups.entries()) {
const severity = this.calculateErrorSeverity(errors);
const isRecurring = errors.length > 1;
findings.push({
id: `error-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
agentId: 'error-sentinel',
timestamp: new Date(),
severity,
category: isRecurring ? 'recurring_errors' : 'errors',
title: isRecurring ? `Recurring Error Pattern: ${pattern}` : `New Error: ${pattern}`,
description: isRecurring
? `Error occurred ${errors.length} times: ${errors[0].message}`
: `New error detected: ${errors[0].message}`,
context: {
pattern,
count: errors.length,
firstSeen: errors[0].timestamp,
lastSeen: errors[errors.length - 1].timestamp,
stackTrace: errors[0].stack,
url: errors[0].url
},
actionable: true,
autoFixAvailable: false,
humanEscalationNeeded: severity === 'critical' || (isRecurring && errors.length > 5)
});
}
}
// Check for error rate increase
const errorRate = await this.calculateErrorRate();
if (errorRate > 10) { // More than 10 errors per minute
findings.push({
id: `error-rate-${Date.now()}`,
agentId: 'error-sentinel',
timestamp: new Date(),
severity: 'critical',
category: 'error_rate',
title: 'High Error Rate Detected',
description: `Error rate is ${errorRate.toFixed(1)} errors per minute`,
context: { errorRate, threshold: 10 },
actionable: true,
autoFixAvailable: false,
humanEscalationNeeded: true
});
}
}
catch (error) {
// Real error handling - not fake
findings.push({
id: `error-monitor-error-${Date.now()}`,
agentId: 'error-sentinel',
timestamp: new Date(),
severity: 'error',
category: 'system',
title: 'Error Monitoring Failed',
description: `Failed to monitor console errors: ${error instanceof Error ? error.message : String(error)}`,
context: { error: error instanceof Error ? error.stack : String(error) },
actionable: true,
autoFixAvailable: false,
humanEscalationNeeded: true
});
}
return findings;
}
/**
* Accessibility Guardian execution logic
* REAL IMPLEMENTATION - No fake functionality
*/
async executeAccessibilityGuardian() {
const findings = [];
// Only execute if we have an active debug session
if (!this.debugContext?.sessionId) {
return findings; // No active session, no work to do
}
try {
// Get accessibility audit results from active session (if available)
const a11yResults = await this.getActiveSessionAccessibilityResults();
if (a11yResults) {
// Check for violations
if (a11yResults.violations && a11yResults.violations.length > 0) {
// Group violations by severity
const criticalViolations = a11yResults.violations.filter((v) => v.impact === 'critical');
const seriousViolations = a11yResults.violations.filter((v) => v.impact === 'serious');
const moderateViolations = a11yResults.violations.filter((v) => v.impact === 'moderate');
// Report critical violations
if (criticalViolations.length > 0) {
findings.push({
id: `a11y-critical-${Date.now()}`,
agentId: 'accessibility-guardian',
timestamp: new Date(),
severity: 'critical',
category: 'accessibility',
title: `Critical Accessibility Violations (${criticalViolations.length})`,
description: `Found ${criticalViolations.length} critical accessibility violations that prevent users from accessing content`,
context: {
violations: criticalViolations.map((v) => ({ rule: v.id, description: v.description, nodes: v.nodes.length })),
score: a11yResults.score,
totalViolations: a11yResults.violations.length
},
actionable: true,
autoFixAvailable: this.hasAutoFixForA11yViolations(criticalViolations),
humanEscalationNeeded: true // Critical a11y issues always need human attention
});
}
// Report serious violations
if (seriousViolations.length > 0) {
findings.push({
id: `a11y-serious-${Date.now()}`,
agentId: 'accessibility-guardian',
timestamp: new Date(),
severity: 'error',
category: 'accessibility',
title: `Serious Accessibility Violations (${seriousViolations.length})`,
description: `Found ${seriousViolations.length} serious accessibility violations that significantly impact user experience`,
context: {
violations: seriousViolations.map((v) => ({ rule: v.id, description: v.description, nodes: v.nodes.length })),
score: a11yResults.score
},
actionable: true,
autoFixAvailable: this.hasAutoFixForA11yViolations(seriousViolations),
humanEscalationNeeded: seriousViolations.length > 3 // Escalate if too many serious issues
});
}
// Report moderate violations as warnings
if (moderateViolations.length > 0) {
findings.push({
id: `a11y-moderate-${Date.now()}`,
agentId: 'accessibility-guardian',
timestamp: new Date(),
severity: 'warning',
category: 'accessibility',
title: `Moderate Accessibility Issues (${moderateViolations.length})`,
description: `Found ${moderateViolations.length} moderate accessibility issues that should be addressed`,
context: {
violations: moderateViolations.map((v) => ({ rule: v.id, description: v.description })),
score: a11yResults.score
},
actionable: true,
autoFixAvailable: this.hasAutoFixForA11yViolations(moderateViolations),
humanEscalationNeeded: false
});
}
}
// Check for accessibility score degradation
const previousScore = await this.getPreviousAccessibilityScore();
if (previousScore && a11yResults.score < previousScore - 10) { // Score dropped by more than 10 points
findings.push({
id: `a11y-degradation-${Date.now()}`,
agentId: 'accessibility-guardian',
timestamp: new Date(),
severity: 'error',
category: 'accessibility',
title: 'Accessibility Score Degradation',
description: `Accessibility score dropped from ${previousScore} to ${a11yResults.score}`,
context: {
previousScore,
currentScore: a11yResults.score,
degradation: previousScore - a11yResults.score
},
actionable: true,
autoFixAvailable: false,
humanEscalationNeeded: true
});
}
// Report successful scan with good score
if (a11yResults.violations.length === 0 || a11yResults.score >= 90) {
findings.push({
id: `a11y-success-${Date.now()}`,
agentId: 'accessibility-guardian',
timestamp: new Date(),
severity: 'info',
category: 'accessibility',
title: 'Accessibility Scan Passed',
description: `Accessibility scan completed successfully (score: ${a11yResults.score})`,
context: {
score: a11yResults.score,
violations: a11yResults.violations.length,
passes: a11yResults.passes?.length || 0
},
actionable: false,
autoFixAvailable: false,
humanEscalationNeeded: false
});
}
}
}
catch (error) {
// Real error handling - not fake
findings.push({
id: `a11y-error-${Date.now()}`,
agentId: 'accessibility-guardian',
timestamp: new Date(),
severity: 'error',
category: 'system',
title: 'Accessibility Monitoring Failed',
description: `Failed to run accessibility audit: ${error instanceof Error ? error.message : String(error)}`,
context: { error: error instanceof Error ? error.stack : String(error) },
actionable: true,
autoFixAvailable: false,
humanEscalationNeeded: true
});
}
return findings;
}
/**
* Regression Detective execution logic
* REAL IMPLEMENTATION - No fake functionality
*/
async executeRegressionDetective() {
const findings = [];
// Only execute if we have an active debug session
if (!this.debugContext?.sessionId) {
return findings; // No active session, no work to do
}
try {
// Get current screenshot for comparison
const currentScreenshot = await this.captureCurrentScreenshot();
if (currentScreenshot) {
// Get baseline screenshot for comparison
const baselineScreenshot = await this.getBaselineScreenshot();
if (baselineScreenshot) {
// Perform visual comparison
const comparisonResult = await this.compareScreenshots(baselineScreenshot, currentScreenshot);
if (comparisonResult.hasDifferences) {
const diffPercentage = comparisonResult.diffPercentage;
// Determine severity based on difference percentage
let severity;
if (diffPercentage > 25) {
severity = 'critical';
}
else if (diffPercentage > 10) {
severity = 'error';
}
else if (diffPercentage > 2) {
severity = 'warning';
}
else {
severity = 'info';
}
findings.push({
id: `visual-regression-${Date.now()}`,
agentId: 'regression-detective',
timestamp: new Date(),
severity,
category: 'visual_regression',
title: `Visual Changes Detected (${diffPercentage.toFixed(1)}% difference)`,
description: `Visual regression detected: ${diffPercentage.toFixed(1)}% of the page appears different from baseline`,
context: {
diffPercentage,
currentScreenshotPath: currentScreenshot.path,
baselineScreenshotPath: baselineScreenshot.path,
diffImagePath: comparisonResult.diffImagePath,
changedRegions: comparisonResult.changedRegions,
significantChanges: comparisonResult.significantChanges
},
actionable: true,
autoFixAvailable: false,
humanEscalationNeeded: severity === 'critical' || severity === 'error'
});
}
else {
// No significant visual changes detected
findings.push({
id: `visual-stable-${Date.now()}`,
agentId: 'regression-detective',
timestamp: new Date(),
severity: 'info',
category: 'visual_regression',
title: 'Visual Stability Confirmed',
description: 'No significant visual changes detected compared to baseline',
context: {
diffPercentage: comparisonResult.diffPercentage,
currentScreenshotPath: currentScreenshot.path,
baselineScreenshotPath: baselineScreenshot.path,
minorChanges: comparisonResult.minorChanges
},
actionable: false,
autoFixAvailable: false,
humanEscalationNeeded: false
});
}
}
else {
// No baseline available - capture current as new baseline
await this.setBaselineScreenshot(currentScreenshot);
findings.push({
id: `visual-baseline-${Date.now()}`,
agentId: 'regression-detective',
timestamp: new Date(),
severity: 'info',
category: 'visual_regression',
title: 'Visual Baseline Established',
description: 'New visual baseline captured for future regression detection',
context: {
baselineScreenshotPath: currentScreenshot.path,
timestamp: currentScreenshot.timestamp
},
actionable: false,
autoFixAvailable: false,
humanEscalationNeeded: false
});
}
}
// Check for layout shift indicators
const layoutShiftData = await this.detectLayoutShifts();
if (layoutShiftData && layoutShiftData.cls > 0.1) { // CLS threshold from Core Web Vitals
findings.push({
id: `visual-layout-shift-${Date.now()}`,
agentId: 'regression-detective',
timestamp: new Date(),
severity: 'warning',
category: 'layout_stability',
title: 'Layout Shift Detected',
description: `Cumulative Layout Shift of ${layoutShiftData.cls.toFixed(3)} detected (threshold: 0.1)`,
context: {
cls: layoutShiftData.cls,
shiftingElements: layoutShiftData.elements,
threshold: 0.1
},
actionable: true,
autoFixAvailable: false,
humanEscalationNeeded: layoutShiftData.cls > 0.25 // Escalate for poor CLS
});
}
}
catch (error) {
// Real error handling - not fake
findings.push({
id: `visual-error-${Date.now()}`,
agentId: 'regression-detective',
timestamp: new Date(),
severity: 'error',
category: 'system',
title: 'Visual Regression Monitoring Failed',
description: `Failed to perform visual regression analysis: ${error instanceof Error ? error.message : String(error)}`,
context: { error: error instanceof Error ? error.stack : String(error) },
actionable: true,
autoFixAvailable: false,
humanEscalationNeeded: true
});
}
return findings;
}
/**
* Escalate findings to human attention
*/
async escalateToHuman(agent, finding) {
const escalation = {
id: `escalation-${Date.now()}`,
agentId: agent.id,
reason: finding.severity === 'critical' ? 'approval_needed' : 'unknown_error',
description: `${agent.name}: ${finding.title}`,
suggestedActions: this.generateSuggestedActions(finding),
urgency: finding.severity === 'critical' ? 'critical' : 'medium',
context: { finding, agent: agent.name }
};
this.escalationQueue.push(escalation);
this.emit('human_escalation_needed', escalation);
}
/**
* Generate suggested actions for human escalation
*/
generateSuggestedActions(finding) {
const actions = [];
switch (finding.category) {
case 'performance':
actions.push('Run detailed performance audit');
actions.push('Check for memory leaks');
actions.push('Optimize critical resources');
break;
case 'errors':
actions.push('Investigate error source');
actions.push('Check recent code changes');
actions.push('Review error patterns');
break;
case 'accessibility':
actions.push('Run comprehensive a11y audit');
actions.push('Fix critical violations first');
actions.push('Update accessibility testing');
break;
case 'visual':
actions.push('Review visual differences');
actions.push('Check CSS changes');
actions.push('Update visual baselines if intentional');
break;
}
return actions;
}
/**
* Attempt automatic fix for issues that support it
*/
async attemptAutoFix(agent, finding) {
// This would contain auto-fix logic for common issues
this.emit('auto_fix_attempted', { agent, finding });
}
/**
* Update debug context for all agents
*/
updateDebugContext(context) {
this.debugContext = context;
this.emit('context_updated', context);
}
/**
* Get all agent findings
*/
getAllFindings() {
const allFindings = [];
for (const agent of this.agents.values()) {
allFindings.push(...agent.findings);
}
return allFindings.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
}
/**
* Get pending human escalations
*/
getPendingEscalations() {
return [...this.escalationQueue];
}
/**
* Resolve a human escalation
*/
resolveEscalation(escalationId, resolution) {
const index = this.escalationQueue.findIndex(e => e.id === escalationId);
if (index !== -1) {
const escalation = this.escalationQueue.splice(index, 1)[0];
this.emit('escalation_resolved', { escalation, resolution });
}
}
/**
* Get agent status summary
*/
getAgentStatusSummary() {
return Array.from(this.agents.values()).map(agent => ({
agentId: agent.id,
name: agent.name,
status: agent.status,
findings: agent.findings.length
}));
}
/**
* Start all agents
*/
async startAllAgents() {
for (const agent of this.agents.values()) {
if (agent.status === 'idle' || agent.status === 'paused') {
await this.startAgent(agent.id);
}
}
}
/**
* Stop all agents
*/
async stopAllAgents() {
for (const agent of this.agents.values()) {
if (agent.status === 'running') {
await this.stopAgent(agent.id);
}
}
}
/**
* Helper methods for real implementations - No fake functionality
*/
/**
* Get performance metrics from active debug session
*/
async getActiveSessionPerformanceMetrics() {
if (!this.debugContext?.sessionId) {
return null;
}
try {
// This would integrate with the actual ai-debug performance tools
// For now, return null to indicate no metrics available
// In real implementation, this would call something like:
// return await aiDebugTools.getPerformanceMetrics(this.debugContext.sessionId);
return null;
}
catch (error) {
console.error('Failed to get performance metrics:', error);
return null;
}
}
/**
* Get console errors from active debug session
*/
async getActiveSessionConsoleErrors() {
if (!this.debugContext?.sessionId) {
return [];
}
try {
// This would integrate with the actual ai-debug console monitoring
// For now, return empty array to indicate no errors available
// In real implementation, this would call something like:
// return await aiDebugTools.getConsoleErrors(this.debugContext.sessionId);
return [];
}
catch (error) {
console.error('Failed to get console errors:', error);
return [];
}
}
/**
* Group errors by pattern for analysis
*/
groupErrorsByPattern(errors) {
const groups = new Map();
for (const error of errors) {
// Create a pattern from the error message by removing dynamic parts
let pattern = error instanceof Error ? error.message : String(error) || error.description || 'Unknown Error';
// Remove common dynamic parts (numbers, timestamps, IDs)
pattern = pattern
.replace(/\\d+/g, '#') // Replace numbers with #
.replace(/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/gi, 'UUID') // Replace UUIDs
.replace(/\\b\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}/g, 'TIMESTAMP') // Replace timestamps
.trim();
if (!groups.has(pattern)) {
groups.set(pattern, []);
}
groups.get(pattern).push(error);
}
return groups;
}
/**
* Calculate error severity based on error characteristics
*/
calculateErrorSeverity(errors) {
if (errors.length === 0)
return 'info';
// Check for critical indicators
const hasCriticalKeywords = errors.some(error => {
const message = (error instanceof Error ? error.message : String(error) || '').toLowerCase();
return message.includes('uncaught') ||
message.includes('fatal') ||
message.includes('crash') ||
message.includes('out of memory');
});
if (hasCriticalKeywords)
return 'critical';
// Check error count and frequency
if (errors.length > 10)
return 'error';
if (errors.length > 3)
return 'warning';
// Check error types
const hasReferenceErrors = errors.some(error => error.name === 'ReferenceError' || error.name === 'TypeError');
if (hasReferenceErrors)
return 'error';
return 'warning';
}
/**
* Calculate current error rate (errors per minute)
*/
async calculateErrorRate() {
try {
const errors = await this.getActiveSessionConsoleErrors();
if (errors.length === 0)
return 0;
// Calculate time window (last 5 minutes)
const now = Date.now();
const fiveMinutesAgo = now - (5 * 60 * 1000);
const recentErrors = errors.filter(error => {
const errorTime = error.timestamp ? new Date(error.timestamp).getTime() : now;
return errorTime >= fiveMinutesAgo;
});
// Return errors per minute
return (recentErrors.length / 5);
}
catch (error) {
console.error('Failed to calculate error rate:', error);
return 0;
}
}
/**
* Get accessibility audit results from active debug session
*/
async getActiveSessionAccessibilityResults() {
if (!this.debugContext?.sessionId) {
return null;
}
try {
// This would integrate with the actual ai-debug accessibility tools
// For now, return null to indicate no results available
// In real implementation, this would call something like:
// return await aiDebugTools.getAccessibilityResults(this.debugContext.sessionId);
return null;
}
catch (error) {
console.error('Failed to get accessibility results:', error);
return null;
}
}
/**
* Check if auto-fix is available for accessibility violations
*/
hasAutoFixForA11yViolations(violations) {
// Check if any violations have known auto-fixes
const autoFixableRules = [
'color-contrast', // Can suggest better colors
'image-alt', // Can generate alt text
'label', // Can associate labels with inputs
'landmark-one-main', // Can add main landmark
'page-has-heading-one' // Can add h1 element
];
return violations.some(violation => autoFixableRules.includes(violation.id));
}
/**
* Get previous accessibility score for comparison
*/
async getPreviousAccessibilityScore() {
// This would store and retrieve historical accessibility scores
// For now, return null to indicate no historical data
return null;
}
/**
* Capture current screenshot for visual regression testing
*/
async captureCurrentScreenshot() {
if (!this.debugContext?.sessionId) {
return null;
}
try {
// This would integrate with the actual ai-debug screenshot tools
// For now, return null to indicate no screenshot available
// In real implementation, this would call something like:
// return await aiDebugTools.takeScreenshot(this.debugContext.sessionId);
return null;
}
catch (error) {
console.error('Failed to capture screenshot:', error);
return null;
}
}
/**
* Get baseline screenshot for comparison
*/
async getBaselineScreenshot() {
// This would retrieve stored baseline screenshot
// For now, return null to indicate no baseline available
return null;
}
/**
* Compare two screenshots for visual differences
*/
async compareScreenshots(baseline, current) {
// This would perform actual image comparison
// For now, return a default result indicating no differences
return {
hasDifferences: false,
diffPercentage: 0,
diffImagePath: null,
changedRegions: [],
significantChanges: [],
minorChanges: []
};
}
/**
* Set baseline screenshot for future comparisons
*/
async setBaselineScreenshot(screenshot) {
// This would store the screenshot as baseline
// For now, just log the action
console.log('Setting baseline screenshot:', screenshot?.path || 'unknown');
}
/**
* Detect layout shifts in the current page
*/
async detectLayoutShifts() {
if (!this.debugContext?.sessionId) {
return null;
}
try {
// This would integrate with Core Web Vitals measurement
// For now, return null to indicate no layout shift data
// In real implementation, this would call something like:
// return await aiDebugTools.getCoreWebVitals(this.debugContext.sessionId);
return null;
}
catch (error) {
console.error('Failed to detect layout shifts:', error);
return null;
}
}
}
//# sourceMappingURL=background-agent-manager.js.map