Files
SuperCharged-Claude-Code-Up…/public/claude-ide/bug-tracker.js
uroma 55aafbae9a Fix project isolation: Make loadChatHistory respect active project sessions
- Modified loadChatHistory() to check for active project before fetching all sessions
- When active project exists, use project.sessions instead of fetching from API
- Added detailed console logging to debug session filtering
- This prevents ALL sessions from appearing in every project's sidebar

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 14:43:05 +00:00

696 lines
23 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) {
// 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 `
<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) {
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 = `
<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');
})();