Files
SuperCharged-Claude-Code-Up…/public/claude-ide/bug-tracker.js
uroma efb3ecfb19 feat: AI auto-fix bug tracker with real-time error monitoring
- 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>
2026-01-21 10:53:11 +00:00

664 lines
22 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 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) {
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();
// Trigger auto-fix notification
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 `
<div class="activity-item activity-${activity.type}">
<span class="activity-icon">${activity.icon}</span>
<span class="activity-message">${this.escapeHtml(activity.message)}</span>
<span class="activity-time">${timeAgo}</span>
</div>
`;
}).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 = `
<div class="stat-item">
<span>Total:</span>
<span class="stat-value">${totalErrors}</span>
</div>
<div class="stat-item" style="color: #ff6b6b;">
<span>🔴 Active:</span>
<span class="stat-value">${activeErrors}</span>
</div>
<div class="stat-item" style="color: #ffa94d;">
<span>🔧 Fixing:</span>
<span class="stat-value">${fixingErrors}</span>
</div>
<div class="stat-item" style="color: #51cf66;">
<span>✅ Fixed:</span>
<span class="stat-value">${fixedErrors}</span>
</div>
`;
}
// 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 `
<div class="bug-tracker-empty">
<div class="empty-icon">✨</div>
<div class="empty-title">No bugs detected!</div>
<div class="empty-subtitle">The code is running smoothly</div>
</div>
`;
}
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 `
<div class="bug-item ${statusClasses[error.status]}" data-error-id="${error.id}">
<div class="bug-header">
<span class="bug-status">${statusIcons[error.status]} ${error.status}</span>
<span class="bug-time">${timeAgo}</span>
${error.count > 1 ? `<span class="bug-count">×${error.count}</span>` : ''}
</div>
<div class="bug-message">${this.escapeHtml(error.message.substring(0, 100))}${error.message.length > 100 ? '...' : ''}</div>
${error.filename ? `<div class="bug-location">📄 ${error.filename.split('/').pop()}:${error.line || ''}</div>` : ''}
${error.fixDetails ? `<div class="bug-fix-details">✨ ${error.fixDetails}</div>` : ''}
${error.status === 'detected' ? `
<button class="bug-fix-btn" onclick="window.bugTracker.triggerManualFix('${error.id}')">
🤖 Fix Now
</button>
` : ''}
</div>
`;
},
triggerManualFix(errorId) {
const error = this.errors.find(e => e.id === errorId);
if (error) {
// Report to server to trigger fix
fetch('/claude/api/log-error', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
...error,
manualTrigger: true
})
});
}
},
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 = `
<span class="toggle-icon">🐛</span>
<span class="toggle-badge" id="bug-count-badge">0</span>
`;
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 = `
<div class="bug-tracker-header">
<div class="bug-tracker-title">
<span class="title-icon">🤖</span>
<span>AI Auto-Fix Tracker</span>
</div>
<button class="bug-tracker-close" onclick="window.bugTracker.toggle()">×</button>
</div>
<div class="activity-stream-header">
<span class="activity-title">🔴 Live Activity Feed</span>
</div>
<div id="activity-stream" class="activity-stream"></div>
<div class="bug-tracker-stats" id="bug-tracker-stats"></div>
<div id="bug-tracker-content" class="bug-tracker-content"></div>
`;
// 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');
})();