- 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>
170 lines
6.1 KiB
JavaScript
170 lines
6.1 KiB
JavaScript
/**
|
||
* Real-Time Error Monitoring
|
||
* Captures browser errors and forwards them to the server for Claude to see
|
||
*/
|
||
|
||
(function() {
|
||
'use strict';
|
||
|
||
// Error endpoint
|
||
const ERROR_ENDPOINT = '/claude/api/log-error';
|
||
|
||
// Send error to server
|
||
function reportError(errorData) {
|
||
// Add to bug tracker
|
||
if (window.bugTracker) {
|
||
const errorId = window.bugTracker.addError(errorData);
|
||
errorData._id = errorId;
|
||
}
|
||
|
||
fetch(ERROR_ENDPOINT, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(errorData)
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.autoFixTriggered && window.bugTracker) {
|
||
window.bugTracker.startFix(errorData._id);
|
||
showErrorNotification(errorData);
|
||
}
|
||
})
|
||
.catch(err => console.error('[ErrorMonitor] Failed to report error:', err));
|
||
}
|
||
|
||
// Show notification that error is being fixed
|
||
function showErrorNotification(errorData) {
|
||
// Create notification element
|
||
const notification = document.createElement('div');
|
||
notification.style.cssText = `
|
||
position: fixed;
|
||
top: 20px;
|
||
right: 20px;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
padding: 16px 20px;
|
||
border-radius: 12px;
|
||
box-shadow: 0 10px 40px rgba(0,0,0,0.3);
|
||
z-index: 10000;
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||
max-width: 400px;
|
||
animation: slideIn 0.3s ease-out;
|
||
`;
|
||
|
||
notification.innerHTML = `
|
||
<div style="display: flex; align-items: flex-start; gap: 12px;">
|
||
<div style="font-size: 24px;">🤖</div>
|
||
<div style="flex: 1;">
|
||
<div style="font-weight: 600; margin-bottom: 4px;">Auto-Fix Agent Triggered</div>
|
||
<div style="font-size: 13px; opacity: 0.9;">
|
||
Error detected: ${errorData.message.substring(0, 60)}${errorData.message.length > 60 ? '...' : ''}
|
||
</div>
|
||
<div style="font-size: 11px; opacity: 0.7; margin-top: 4px;">
|
||
Claude is analyzing and preparing a fix...
|
||
</div>
|
||
</div>
|
||
<button onclick="this.parentElement.parentElement.remove()" style="background: none; border: none; color: white; cursor: pointer; font-size: 18px; opacity: 0.7;">×</button>
|
||
</div>
|
||
`;
|
||
|
||
// Add animation styles
|
||
if (!document.getElementById('error-notification-styles')) {
|
||
const style = document.createElement('style');
|
||
style.id = 'error-notification-styles';
|
||
style.textContent = `
|
||
@keyframes slideIn {
|
||
from { transform: translateX(400px); opacity: 0; }
|
||
to { transform: translateX(0); opacity: 1; }
|
||
}
|
||
`;
|
||
document.head.appendChild(style);
|
||
}
|
||
|
||
document.body.appendChild(notification);
|
||
|
||
// Auto-remove after 10 seconds
|
||
setTimeout(() => {
|
||
if (notification.parentElement) {
|
||
notification.style.animation = 'slideIn 0.3s ease-out reverse';
|
||
setTimeout(() => notification.remove(), 300);
|
||
}
|
||
}, 10000);
|
||
}
|
||
|
||
// Global error handler
|
||
window.addEventListener('error', (event) => {
|
||
reportError({
|
||
type: 'javascript',
|
||
message: event.message,
|
||
filename: event.filename,
|
||
line: event.lineno,
|
||
column: event.colno,
|
||
stack: event.error?.stack,
|
||
timestamp: new Date().toISOString(),
|
||
url: window.location.href,
|
||
userAgent: navigator.userAgent
|
||
});
|
||
});
|
||
|
||
// Unhandled promise rejection handler
|
||
window.addEventListener('unhandledrejection', (event) => {
|
||
reportError({
|
||
type: 'promise',
|
||
message: event.reason?.message || String(event.reason),
|
||
stack: event.reason?.stack,
|
||
timestamp: new Date().toISOString(),
|
||
url: window.location.href,
|
||
userAgent: navigator.userAgent
|
||
});
|
||
});
|
||
|
||
// Console error interception
|
||
const originalError = console.error;
|
||
console.error = function(...args) {
|
||
originalError.apply(console, args);
|
||
reportError({
|
||
type: 'console',
|
||
message: args.map(arg => {
|
||
if (typeof arg === 'object') {
|
||
try { return JSON.stringify(arg); }
|
||
catch(e) { return String(arg); }
|
||
}
|
||
return String(arg);
|
||
}).join(' '),
|
||
timestamp: new Date().toISOString(),
|
||
url: window.location.href
|
||
});
|
||
};
|
||
|
||
// Resource loading errors
|
||
window.addEventListener('error', (event) => {
|
||
if (event.target !== window) {
|
||
const src = event.target.src || event.target.href || 'unknown';
|
||
reportError({
|
||
type: 'resource',
|
||
message: 'Failed to load: ' + src,
|
||
tagName: event.target.tagName,
|
||
timestamp: new Date().toISOString(),
|
||
url: window.location.href
|
||
});
|
||
}
|
||
}, true);
|
||
|
||
// Network error monitoring for fetch
|
||
const originalFetch = window.fetch;
|
||
window.fetch = function(...args) {
|
||
return originalFetch.apply(this, args).catch(error => {
|
||
reportError({
|
||
type: 'network',
|
||
message: 'Fetch failed: ' + args[0],
|
||
error: error.message,
|
||
timestamp: new Date().toISOString(),
|
||
url: window.location.href
|
||
});
|
||
throw error;
|
||
});
|
||
};
|
||
|
||
console.log('[ErrorMonitor] Real-time error monitoring initialized');
|
||
})();
|