/** * Real-Time Bug Tracker Dashboard * Shows all auto-detected errors and fix progress */ (function() { 'use strict'; // Error state storage window.bugTracker = { errors: [], fixesInProgress: new Map(), fixesCompleted: new Map(), activityLog: [], // New: stores AI activity stream addError(error) { // Skip 'info' type errors - they're for learning, not bugs if (error.type === 'info') { console.log('[BugTracker] Skipping info-type error:', error.message); return null; } const errorId = this.generateErrorId(error); const existingError = this.errors.find(e => e.id === errorId); if (!existingError) { const errorWithMeta = { id: errorId, ...error, detectedAt: new Date().toISOString(), status: 'detected', count: 1, activity: [] // Activity for this error }; this.errors.push(errorWithMeta); this.updateDashboard(); // Auto-fix notification disabled - errors logged to dashboard only // if (typeof showErrorNotification === 'function') { // showErrorNotification(errorWithMeta); // } } else { existingError.count++; existingError.lastSeen = new Date().toISOString(); } return errorId; }, startFix(errorId) { const error = this.errors.find(e => e.id === errorId); if (error) { error.status = 'fixing'; error.fixStartedAt = new Date().toISOString(); this.fixesInProgress.set(errorId, true); this.addActivity(errorId, '🤖', 'AI agent started analyzing error...'); this.updateDashboard(); } }, // Add activity to error's activity log addActivity(errorId, icon, message, type = 'info') { // Add to global activity log this.activityLog.unshift({ errorId, icon, message, type, timestamp: new Date().toISOString() }); // Keep only last 50 global activities if (this.activityLog.length > 50) { this.activityLog = this.activityLog.slice(0, 50); } // Add to specific error's activity const error = this.errors.find(e => e.id === errorId); if (error) { if (!error.activity) error.activity = []; error.activity.unshift({ icon, message, type, timestamp: new Date().toISOString() }); if (error.activity.length > 20) { error.activity = error.activity.slice(0, 20); } } this.updateActivityStream(); }, // Update the activity stream display updateActivityStream() { const stream = document.getElementById('activity-stream'); if (!stream) return; // Show last 10 activities globally const recentActivities = this.activityLog.slice(0, 10); stream.innerHTML = recentActivities.map(activity => { const timeAgo = this.getTimeAgo(activity.timestamp); return `
${activity.icon} ${this.escapeHtml(activity.message)} ${timeAgo}
`; }).join(''); }, completeFix(errorId, fixDetails) { const error = this.errors.find(e => e.id === errorId); if (error) { error.status = 'fixed'; error.fixedAt = new Date().toISOString(); error.fixDetails = fixDetails; this.fixesInProgress.delete(errorId); this.fixesCompleted.set(errorId, true); this.updateDashboard(); } }, generateErrorId(error) { const parts = [ error.type, error.message.substring(0, 50), error.filename || 'unknown' ]; return btoa(parts.join('::')).substring(0, 20); }, updateDashboard() { const dashboard = document.getElementById('bug-tracker-dashboard'); if (!dashboard) return; const content = dashboard.querySelector('#bug-tracker-content'); const stats = dashboard.querySelector('#bug-tracker-stats'); if (!content) return; // Update stats if (stats) { const totalErrors = this.errors.length; const activeErrors = this.errors.filter(e => e.status === 'detected').length; const fixingErrors = this.errors.filter(e => e.status === 'fixing').length; const fixedErrors = this.errors.filter(e => e.status === 'fixed').length; stats.innerHTML = `
Total: ${totalErrors}
🔴 Active: ${activeErrors}
🔧 Fixing: ${fixingErrors}
✅ Fixed: ${fixedErrors}
`; } // Sort errors: fixing first, then detected, then fixed const sortedErrors = [...this.errors].sort((a, b) => { const statusOrder = { 'fixing': 0, 'detected': 1, 'fixed': 2 }; return statusOrder[a.status] - statusOrder[b.status]; }); content.innerHTML = this.renderErrors(sortedErrors); }, renderErrors(errors) { if (errors.length === 0) { return `
No bugs detected!
The code is running smoothly
`; } return errors.map(error => this.renderError(error)).join(''); }, renderError(error) { const statusIcons = { 'detected': '🔴', 'fixing': '🔧', 'fixed': '✅' }; const statusClasses = { 'detected': 'status-detected', 'fixing': 'status-fixing', 'fixed': 'status-fixed' }; const timeAgo = this.getTimeAgo(error.detectedAt || error.timestamp); return `
${statusIcons[error.status]} ${error.status} ${timeAgo} ${error.count > 1 ? `×${error.count}` : ''}
${this.escapeHtml(error.message.substring(0, 100))}${error.message.length > 100 ? '...' : ''}
${error.filename ? `
📄 ${error.filename.split('/').pop()}:${error.line || ''}
` : ''} ${error.fixDetails ? `
✨ ${error.fixDetails}
` : ''} ${error.status === 'detected' ? ` ` : ''}
`; }, triggerManualFix(errorId) { const error = this.errors.find(e => e.id === errorId); if (!error) { console.error('[BugTracker] Error not found:', errorId); return; } // Report to server to trigger fix fetch('/claude/api/log-error', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...error, manualTrigger: true }) }) .then(res => { if (!res.ok) { throw new Error(`HTTP ${res.status}: ${res.statusText}`); } return res.json(); }) .then(data => { console.log('[BugTracker] Manual fix triggered:', data); // Update error status to 'fixing' this.startFix(errorId); // Show success feedback if (typeof showToast === 'function') { showToast('Auto-fix agent triggered', 'success'); } }) .catch(err => { console.error('[BugTracker] Failed to trigger fix:', err); if (typeof showToast === 'function') { showToast('Failed to trigger auto-fix', 'error'); } }); }, getTimeAgo(timestamp) { const now = new Date(); const then = new Date(timestamp); const diffMs = now - then; const diffSecs = Math.floor(diffMs / 1000); const diffMins = Math.floor(diffSecs / 60); if (diffSecs < 60) return `${diffSecs}s ago`; if (diffMins < 60) return `${diffMins}m ago`; return `${Math.floor(diffMins / 60)}h ago`; }, escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; }, toggle() { const dashboard = document.getElementById('bug-tracker-dashboard'); if (dashboard) { dashboard.classList.toggle('visible'); dashboard.classList.toggle('hidden'); } } }; // Create dashboard UI function createDashboard() { // Create toggle button const toggleBtn = document.createElement('button'); toggleBtn.id = 'bug-tracker-toggle'; toggleBtn.className = 'bug-tracker-toggle'; toggleBtn.innerHTML = ` 🐛 0 `; toggleBtn.onclick = () => window.bugTracker.toggle(); // Create dashboard const dashboard = document.createElement('div'); dashboard.id = 'bug-tracker-dashboard'; dashboard.className = 'bug-tracker-dashboard hidden'; dashboard.innerHTML = `
🤖 AI Auto-Fix Tracker
🔴 Live Activity Feed
`; // Add styles const style = document.createElement('style'); style.id = 'bug-tracker-styles'; style.textContent = ` .bug-tracker-toggle { position: fixed; bottom: 20px; right: 20px; width: 60px; height: 60px; border-radius: 50%; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border: none; box-shadow: 0 4px 20px rgba(102, 126, 234, 0.4); cursor: pointer; z-index: 9999; display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; } .bug-tracker-toggle:hover { transform: scale(1.1); box-shadow: 0 6px 30px rgba(102, 126, 234, 0.6); } .toggle-icon { font-size: 24px; } .toggle-badge { position: absolute; top: -5px; right: -5px; background: #ff6b6b; color: white; font-size: 12px; font-weight: bold; padding: 2px 8px; border-radius: 10px; min-width: 20px; text-align: center; } .bug-tracker-dashboard { position: fixed; top: 50%; right: 20px; transform: translateY(-50%); width: 400px; max-height: 80vh; background: #1a1a1a; border: 1px solid #333; border-radius: 12px; box-shadow: 0 10px 60px rgba(0, 0, 0, 0.5); z-index: 9998; display: flex; flex-direction: column; transition: all 0.3s ease; } .bug-tracker-dashboard.hidden { display: none; } .bug-tracker-dashboard.visible { display: flex; } .bug-tracker-header { padding: 16px 20px; border-bottom: 1px solid #333; display: flex; justify-content: space-between; align-items: center; } .bug-tracker-title { display: flex; align-items: center; gap: 10px; font-size: 16px; font-weight: 600; color: #e0e0e0; } .bug-tracker-close { background: none; border: none; color: #888; font-size: 24px; cursor: pointer; padding: 0; width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; } .bug-tracker-close:hover { color: #e0e0e0; } .bug-tracker-content { flex: 1; overflow-y: auto; padding: 16px; } .bug-item { background: #252525; border: 1px solid #333; border-radius: 8px; padding: 12px; margin-bottom: 12px; transition: all 0.2s ease; } .bug-item:hover { border-color: #4a9eff; } .bug-item.status-fixing { border-color: #ffa94d; background: #2a2520; } .bug-item.status-fixed { border-color: #51cf66; opacity: 0.7; } .bug-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; } .bug-status { font-size: 12px; font-weight: 600; padding: 4px 8px; border-radius: 4px; } .status-detected { background: rgba(255, 107, 107, 0.2); color: #ff6b6b; } .status-fixing { background: rgba(255, 169, 77, 0.2); color: #ffa94d; } .status-fixed { background: rgba(81, 207, 102, 0.2); color: #51cf66; } .bug-time { font-size: 11px; color: #888; } .bug-count { background: #ff6b6b; color: white; font-size: 10px; font-weight: bold; padding: 2px 6px; border-radius: 10px; } .bug-message { color: #e0e0e0; font-size: 13px; margin-bottom: 8px; } .bug-location { color: #888; font-size: 11px; font-family: monospace; } .bug-fix-details { color: #51cf66; font-size: 12px; margin-top: 8px; padding: 8px; background: rgba(81, 207, 102, 0.1); border-radius: 4px; } .bug-fix-btn { width: 100%; padding: 8px; background: linear-gradient(135deg, #4a9eff 0%, #a78bfa 100%); border: none; border-radius: 6px; color: white; font-size: 13px; font-weight: 600; cursor: pointer; margin-top: 8px; } .bug-fix-btn:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(74, 158, 255, 0.4); } .bug-tracker-empty { text-align: center; padding: 40px 20px; } .empty-icon { font-size: 48px; margin-bottom: 16px; } .empty-title { font-size: 18px; font-weight: 600; color: #e0e0e0; margin-bottom: 8px; } .empty-subtitle { font-size: 14px; color: #888; } .activity-stream-header { padding: 12px 20px; border-bottom: 1px solid #333; background: rgba(255, 107, 107, 0.05); } .activity-title { font-size: 13px; font-weight: 600; color: #ff6b6b; text-transform: uppercase; letter-spacing: 0.5px; } .activity-stream { max-height: 200px; overflow-y: auto; padding: 12px; background: #0d0d0d; border-bottom: 1px solid #333; } .activity-item { display: flex; align-items: center; gap: 10px; padding: 8px 12px; margin-bottom: 6px; background: #1a1a1a; border-radius: 6px; border-left: 3px solid #4a9eff; transition: all 0.2s ease; animation: slideIn 0.3s ease; } @keyframes slideIn { from { opacity: 0; transform: translateX(-10px); } to { opacity: 1; transform: translateX(0); } } .activity-item:hover { background: #252525; border-left-color: #a78bfa; } .activity-item.activity-error { border-left-color: #ff6b6b; background: rgba(255, 107, 107, 0.05); } .activity-item.activity-success { border-left-color: #51cf66; background: rgba(81, 207, 102, 0.05); } .activity-item.activity-warning { border-left-color: #ffa94d; background: rgba(255, 169, 77, 0.05); } .activity-icon { font-size: 16px; flex-shrink: 0; } .activity-message { flex: 1; font-size: 12px; color: #e0e0e0; line-height: 1.4; } .activity-time { font-size: 10px; color: #888; flex-shrink: 0; } .bug-tracker-stats { padding: 12px 20px; border-bottom: 1px solid #333; display: flex; gap: 20px; font-size: 12px; background: #151515; } .stat-item { display: flex; align-items: center; gap: 6px; color: #888; } .stat-value { font-weight: 600; color: #e0e0e0; } `; document.head.appendChild(style); document.body.appendChild(toggleBtn); document.body.appendChild(dashboard); // Auto-update error count badge setInterval(() => { const badge = document.getElementById('bug-count-badge'); if (badge) { const activeErrors = window.bugTracker.errors.filter(e => e.status !== 'fixed').length; badge.textContent = activeErrors; badge.style.display = activeErrors > 0 ? 'block' : 'none'; } }, 1000); } // Initialize on DOM ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', createDashboard); } else { createDashboard(); } console.log('[BugTracker] Real-time bug tracker initialized'); })();