personal memory agent
1// SPDX-License-Identifier: AGPL-3.0-only
2// Copyright (c) 2026 sol pbc
3
4/**
5 * Error Handler for App System
6 * Captures JavaScript errors and provides visual feedback
7 *
8 * Features:
9 * - Catches window errors and unhandled promise rejections
10 * - Adds error glow to status icon via .error class
11 * - Displays error log at bottom of viewport
12 * - Provides modal for manual error display via window.showError()
13 */
14
15(function(){
16 const statusIcon = document.querySelector('.facet-bar .status-icon');
17 const errorLog = document.getElementById('error-log');
18 const errorModal = document.getElementById('errorModal');
19 const errorMessage = document.getElementById('errorMessage');
20 const closeButton = errorModal ? errorModal.querySelector('.close') : null;
21
22 // Escape HTML to prevent XSS
23 function escapeHtml(text) {
24 return String(text).replace(/</g, '<').replace(/>/g, '>');
25 }
26
27 // Log error to bottom panel
28 function logError(text) {
29 if (errorLog) {
30 if (!document.getElementById('error-log-dismiss')) {
31 var btn = document.createElement('button');
32 btn.id = 'error-log-dismiss';
33 btn.textContent = 'clear';
34 btn.setAttribute('aria-label', 'dismiss error log');
35 btn.onclick = function() {
36 errorLog.innerHTML = '';
37 errorLog.style.display = 'none';
38 };
39 errorLog.insertAdjacentElement('afterbegin', btn);
40 }
41 errorLog.insertAdjacentHTML(
42 'beforeend',
43 escapeHtml(text) + '<br>'
44 );
45 errorLog.style.display = 'block';
46 }
47 }
48
49 // Mark status icon as error state (red with glow)
50 function markError() {
51 if (statusIcon) {
52 statusIcon.classList.add('error');
53 }
54 }
55
56 // Global error handler
57 window.addEventListener('error', (e) => {
58 markError();
59 logError(`❌ ${e.message} @ ${e.filename}:${e.lineno}`);
60 });
61
62 // Unhandled promise rejection handler
63 window.addEventListener('unhandledrejection', (e) => {
64 markError();
65 logError(`⚠️ Promise: ${e.reason}`);
66 });
67
68 // Modal controls
69 if (errorModal && closeButton && errorMessage) {
70 // Provide global function for manual error display
71 window.showError = (text) => {
72 errorMessage.textContent = text;
73 errorModal.style.display = 'block';
74 };
75
76 // Close button
77 closeButton.onclick = () => {
78 errorModal.style.display = 'none';
79 };
80
81 // Click outside to close
82 window.addEventListener('click', (e) => {
83 if (e.target === errorModal) {
84 errorModal.style.display = 'none';
85 }
86 });
87 }
88})();