agentgui 1.0.67 → 1.0.69

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/.prd +92 -0
  2. package/.prd-browser +607 -0
  3. package/CLAUDE.md +1559 -125
  4. package/browser-test-harness.js +371 -0
  5. package/browser-test.js +409 -0
  6. package/execute-tests.js +164 -0
  7. package/lib/claude-runner.js +41 -12
  8. package/lib/database-service.ts +252 -0
  9. package/lib/sync-service.ts +275 -0
  10. package/lib/types.ts +168 -0
  11. package/package.json +1 -1
  12. package/readme.md +586 -0
  13. package/run-e2e-test.sh +88 -0
  14. package/server.js +274 -8
  15. package/static/index.html +487 -180
  16. package/static/js/client.js +558 -0
  17. package/static/js/event-filter.js +311 -0
  18. package/static/js/event-processor.js +454 -0
  19. package/static/js/streaming-renderer.js +813 -0
  20. package/static/js/syntax-highlighter.js +271 -0
  21. package/static/js/ui-components.js +433 -0
  22. package/static/js/websocket-manager.js +482 -0
  23. package/static/templates/INDEX.html +465 -0
  24. package/static/templates/README.md +190 -0
  25. package/static/templates/agent-capabilities.html +56 -0
  26. package/static/templates/agent-metadata-panel.html +44 -0
  27. package/static/templates/agent-status-badge.html +30 -0
  28. package/static/templates/code-annotation-panel.html +155 -0
  29. package/static/templates/code-suggestion-panel.html +184 -0
  30. package/static/templates/command-header.html +77 -0
  31. package/static/templates/command-output-scrollable.html +118 -0
  32. package/static/templates/elapsed-time.html +54 -0
  33. package/static/templates/error-alert.html +106 -0
  34. package/static/templates/error-history-timeline.html +160 -0
  35. package/static/templates/error-recovery-options.html +109 -0
  36. package/static/templates/error-stack-trace.html +95 -0
  37. package/static/templates/error-summary.html +80 -0
  38. package/static/templates/event-counter.html +48 -0
  39. package/static/templates/execution-actions.html +97 -0
  40. package/static/templates/execution-progress-bar.html +80 -0
  41. package/static/templates/execution-stepper.html +120 -0
  42. package/static/templates/file-breadcrumb.html +118 -0
  43. package/static/templates/file-diff-viewer.html +121 -0
  44. package/static/templates/file-metadata.html +133 -0
  45. package/static/templates/file-read-panel.html +66 -0
  46. package/static/templates/file-write-panel.html +120 -0
  47. package/static/templates/git-branch-remote.html +107 -0
  48. package/static/templates/git-diff-list.html +101 -0
  49. package/static/templates/git-log-visualization.html +153 -0
  50. package/static/templates/git-status-panel.html +115 -0
  51. package/static/templates/quality-metrics-display.html +170 -0
  52. package/static/templates/terminal-output-panel.html +87 -0
  53. package/static/templates/test-results-display.html +144 -0
  54. package/test-browser.js +457 -0
  55. package/test-runner.js +182 -0
package/static/index.html CHANGED
@@ -1,211 +1,518 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en">
2
+ <html lang="en" class="light">
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>GMGUI - Chat with CLI Agents</title>
7
- <script src="https://cdn.tailwindcss.com"></script>
8
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/rippleui@1.12.1/dist/css/styles.css" />
9
- <link rel="stylesheet" href="styles.css">
10
- </head>
11
- <body>
12
- <div id="app" class="app">
13
- <!-- Left Sidebar -->
14
- <aside class="sidebar" id="sidebar">
15
- <div class="sidebar-header">
16
- <button class="sidebar-toggle" onclick="toggleSidebar()" title="Toggle sidebar">
17
- <span class="toggle-icon">×</span>
18
- </button>
19
- </div>
6
+ <meta name="description" content="AgentGUI - Real-time Claude Code Execution Visualization">
7
+ <title>AgentGUI - Agent Execution Visualizer</title>
20
8
 
21
- <button class="new-chat-btn" onclick="showNewChatModal()">
22
- <span class="icon">+</span> New Chat
23
- </button>
9
+ <!-- RippleUI CSS -->
10
+ <link href="https://unpkg.com/rippleui@0.14.0/dist/ripple.css" rel="stylesheet">
24
11
 
25
- <div class="chat-history-section">
26
- <h3 class="history-title">Today</h3>
27
- <div class="chat-list" id="chatList"></div>
28
- </div>
12
+ <!-- Syntax Highlighting -->
13
+ <link href="https://unpkg.com/prism@1.29.0/themes/prism-dark.css" rel="stylesheet">
29
14
 
30
- <div class="sidebar-footer">
31
- <button class="settings-btn" onclick="switchTab('settings')">
32
- <span class="icon">⚙️</span> Settings
33
- </button>
34
- </div>
35
- </aside>
15
+ <!-- Custom Styles -->
16
+ <style>
17
+ * {
18
+ box-sizing: border-box;
19
+ }
36
20
 
37
- <!-- Main Content -->
38
- <main class="main-content">
39
- <!-- Connection Status Indicator -->
40
- <div class="connection-status connected" id="connectionStatus">
41
- <span class="status-dot"></span>
42
- <span class="status-text">Connected</span>
43
- </div>
21
+ :root {
22
+ --color-primary: #3b82f6;
23
+ --color-primary-dark: #1e40af;
24
+ --color-bg-primary: #ffffff;
25
+ --color-bg-secondary: #f9fafb;
26
+ --color-bg-code: #1f2937;
27
+ --color-text-primary: #111827;
28
+ --color-text-secondary: #6b7280;
29
+ --color-border: #e5e7eb;
30
+ --color-success: #10b981;
31
+ --color-error: #ef4444;
32
+ --color-warning: #f59e0b;
33
+ }
44
34
 
45
- <div class="chat-container">
46
- <!-- Chat messages area -->
47
- <div class="chat-messages" id="chatMessages">
48
- <div class="welcome-section">
49
- <h2>Hi, what's your plan for today?</h2>
50
- <div class="agent-selection">
51
- <div id="agentCards" class="agent-cards"></div>
52
- </div>
53
- </div>
54
- </div>
35
+ html.dark {
36
+ --color-bg-primary: #111827;
37
+ --color-bg-secondary: #1f2937;
38
+ --color-text-primary: #f9fafb;
39
+ --color-text-secondary: #d1d5db;
40
+ --color-border: #374151;
41
+ }
55
42
 
56
- <!-- Chat input area -->
57
- <div class="chat-input-section">
58
- <div class="input-wrapper">
59
- <textarea
60
- id="messageInput"
61
- class="chat-input"
62
- placeholder="Send message, upload files (📎)..."
63
- rows="1"
64
- ></textarea>
65
- <div class="input-actions">
66
- <button class="action-btn" onclick="triggerFileUpload()" title="Upload files">
67
- <span class="icon">📎</span>
68
- </button>
69
- <button class="action-btn send-btn" id="sendBtn" onclick="sendMessage()" title="Send message">
70
- <span class="icon">→</span>
71
- </button>
72
- <input type="file" id="fileInput" style="display: none;" onchange="handleFileUpload()" multiple />
73
- </div>
74
- </div>
75
- </div>
76
- </div>
43
+ body {
44
+ margin: 0;
45
+ padding: 0;
46
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
47
+ background-color: var(--color-bg-primary);
48
+ color: var(--color-text-primary);
49
+ transition: background-color 0.3s, color 0.3s;
50
+ }
77
51
 
78
- </main>
52
+ /* Layout */
53
+ .app-container {
54
+ display: grid;
55
+ grid-template-columns: 1fr;
56
+ grid-template-rows: auto 1fr;
57
+ min-height: 100vh;
58
+ gap: 0;
59
+ }
79
60
 
80
- <!-- Settings Panel (hidden by default) -->
81
- <div id="settingsPanel" class="settings-panel" style="display: none;">
82
- <div class="settings-content">
83
- <div class="settings-header">
84
- <h2>Settings</h2>
85
- <button class="close-btn" onclick="switchTab('chat')">&times;</button>
86
- </div>
61
+ header {
62
+ background-color: var(--color-bg-secondary);
63
+ border-bottom: 1px solid var(--color-border);
64
+ padding: 1rem;
65
+ display: flex;
66
+ justify-content: space-between;
67
+ align-items: center;
68
+ gap: 1rem;
69
+ }
87
70
 
88
- <div class="setting-group">
89
- <label>
90
- <input type="checkbox" id="autoScroll" checked />
91
- Auto-scroll Chat
92
- </label>
93
- </div>
71
+ .header-title {
72
+ font-size: 1.5rem;
73
+ font-weight: bold;
74
+ margin: 0;
75
+ flex: 1;
76
+ }
94
77
 
95
- <div class="setting-group">
96
- <label for="connectTimeout">Connection Timeout (seconds)</label>
97
- <input type="number" id="connectTimeout" value="30" class="gm-input" />
98
- </div>
78
+ .header-controls {
79
+ display: flex;
80
+ gap: 1rem;
81
+ align-items: center;
82
+ }
99
83
 
100
- <div class="setting-group">
101
- <label for="screenshotFormat">Screenshot Format</label>
102
- <select id="screenshotFormat" class="gm-input">
103
- <option value="png">PNG</option>
104
- <option value="jpg">JPEG</option>
105
- </select>
106
- </div>
84
+ .status-badge {
85
+ display: inline-flex;
86
+ align-items: center;
87
+ gap: 0.5rem;
88
+ padding: 0.5rem 1rem;
89
+ border-radius: 0.25rem;
90
+ font-size: 0.875rem;
91
+ font-weight: 500;
92
+ background-color: var(--color-bg-primary);
93
+ border: 1px solid var(--color-border);
94
+ }
95
+
96
+ .status-indicator {
97
+ width: 0.75rem;
98
+ height: 0.75rem;
99
+ border-radius: 50%;
100
+ background-color: var(--color-error);
101
+ animation: pulse 2s infinite;
102
+ }
103
+
104
+ .status-indicator[data-status="connected"] {
105
+ background-color: var(--color-success);
106
+ }
107
+
108
+ .status-indicator[data-status="reconnecting"],
109
+ .status-indicator[data-status="connecting"] {
110
+ background-color: var(--color-warning);
111
+ animation: pulse 1s infinite;
112
+ }
113
+
114
+ @keyframes pulse {
115
+ 0%, 100% {
116
+ opacity: 1;
117
+ }
118
+ 50% {
119
+ opacity: 0.5;
120
+ }
121
+ }
122
+
123
+ /* Main content */
124
+ main {
125
+ display: grid;
126
+ grid-template-columns: 1fr;
127
+ grid-template-rows: auto 1fr;
128
+ gap: 0;
129
+ min-height: 0;
130
+ overflow: hidden;
131
+ }
132
+
133
+ .execution-panel {
134
+ background-color: var(--color-bg-secondary);
135
+ border-bottom: 1px solid var(--color-border);
136
+ padding: 1.5rem;
137
+ display: grid;
138
+ grid-template-columns: 1fr auto;
139
+ gap: 1rem;
140
+ align-items: end;
141
+ }
142
+
143
+ .execution-input-group {
144
+ display: grid;
145
+ grid-template-columns: 1fr auto;
146
+ gap: 0.5rem;
147
+ align-items: end;
148
+ }
149
+
150
+ .execution-input-group > * {
151
+ min-width: 0;
152
+ }
153
+
154
+ .execution-textarea {
155
+ width: 100%;
156
+ padding: 0.75rem;
157
+ border: 1px solid var(--color-border);
158
+ border-radius: 0.375rem;
159
+ background-color: var(--color-bg-primary);
160
+ color: var(--color-text-primary);
161
+ font-family: inherit;
162
+ resize: none;
163
+ min-height: 3rem;
164
+ max-height: 8rem;
165
+ }
166
+
167
+ .btn {
168
+ padding: 0.75rem 1.5rem;
169
+ border: none;
170
+ border-radius: 0.375rem;
171
+ font-weight: 500;
172
+ cursor: pointer;
173
+ transition: all 0.2s;
174
+ font-size: 0.875rem;
175
+ }
176
+
177
+ .btn-primary {
178
+ background-color: var(--color-primary);
179
+ color: white;
180
+ }
181
+
182
+ .btn-primary:hover:not(:disabled) {
183
+ background-color: var(--color-primary-dark);
184
+ }
185
+
186
+ .btn:disabled {
187
+ opacity: 0.5;
188
+ cursor: not-allowed;
189
+ }
190
+
191
+ .agent-selector {
192
+ padding: 0.5rem;
193
+ border: 1px solid var(--color-border);
194
+ border-radius: 0.375rem;
195
+ background-color: var(--color-bg-primary);
196
+ color: var(--color-text-primary);
197
+ font-size: 0.875rem;
198
+ cursor: pointer;
199
+ }
200
+
201
+ /* Output area */
202
+ #output-scroll {
203
+ overflow-y: auto;
204
+ overflow-x: hidden;
205
+ display: flex;
206
+ flex-direction: column;
207
+ min-height: 0;
208
+ }
209
+
210
+ #output {
211
+ flex: 1;
212
+ padding: 1rem;
213
+ display: flex;
214
+ flex-direction: column;
215
+ gap: 0.5rem;
216
+ }
217
+
218
+ /* Event cards */
219
+ .card {
220
+ background-color: var(--color-bg-primary);
221
+ border: 1px solid var(--color-border);
222
+ border-radius: 0.375rem;
223
+ padding: 1rem;
224
+ margin-bottom: 0.5rem;
225
+ }
226
+
227
+ .card-header {
228
+ font-weight: 600;
229
+ margin-bottom: 0.5rem;
230
+ }
231
+
232
+ .badge {
233
+ display: inline-block;
234
+ padding: 0.25rem 0.75rem;
235
+ border-radius: 0.25rem;
236
+ font-size: 0.75rem;
237
+ font-weight: 600;
238
+ background-color: var(--color-bg-secondary);
239
+ color: var(--color-text-secondary);
240
+ }
241
+
242
+ .badge-sm {
243
+ padding: 0.125rem 0.5rem;
244
+ font-size: 0.7rem;
245
+ }
246
+
247
+ /* Responsive */
248
+ @media (max-width: 768px) {
249
+ .execution-panel {
250
+ grid-template-columns: 1fr;
251
+ }
252
+
253
+ .header-controls {
254
+ flex-wrap: wrap;
255
+ }
256
+
257
+ .execution-input-group {
258
+ grid-template-columns: 1fr;
259
+ }
260
+ }
261
+
262
+ /* Utilities */
263
+ .flex {
264
+ display: flex;
265
+ }
266
+
267
+ .items-center {
268
+ align-items: center;
269
+ }
270
+
271
+ .justify-between {
272
+ justify-content: space-between;
273
+ }
274
+
275
+ .gap-2 {
276
+ gap: 0.5rem;
277
+ }
278
+
279
+ .gap-3 {
280
+ gap: 0.75rem;
281
+ }
282
+
283
+ .text-xs {
284
+ font-size: 0.75rem;
285
+ }
286
+
287
+ .text-sm {
288
+ font-size: 0.875rem;
289
+ }
290
+
291
+ .text-secondary {
292
+ color: var(--color-text-secondary);
293
+ }
294
+
295
+ .font-mono {
296
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
297
+ }
298
+
299
+ .truncate {
300
+ overflow: hidden;
301
+ text-overflow: ellipsis;
302
+ white-space: nowrap;
303
+ }
304
+
305
+ .mb-2 {
306
+ margin-bottom: 0.5rem;
307
+ }
308
+
309
+ .mb-3 {
310
+ margin-bottom: 0.75rem;
311
+ }
312
+
313
+ .mt-2 {
314
+ margin-top: 0.5rem;
315
+ }
107
316
 
108
- <div class="setting-group">
109
- <label>
110
- <button id="themeToggle" style="background: var(--color-primary); color: white; padding: 0.5rem 1rem; border: none; border-radius: 0.5rem; cursor: pointer; font-size: 1rem; font-family: inherit; display: flex; align-items: center; gap: 0.5rem;">
111
- <span class="theme-icon">🌙</span>
112
- <span>Toggle Theme</span>
113
- </button>
114
- </label>
317
+ .mt-3 {
318
+ margin-top: 0.75rem;
319
+ }
320
+
321
+ .p-2 {
322
+ padding: 0.5rem;
323
+ }
324
+
325
+ .p-3 {
326
+ padding: 0.75rem;
327
+ }
328
+
329
+ .p-4 {
330
+ padding: 1rem;
331
+ }
332
+
333
+ .rounded {
334
+ border-radius: 0.375rem;
335
+ }
336
+
337
+ .bg-gray-50 {
338
+ background-color: #f9fafb;
339
+ }
340
+
341
+ .bg-gray-900 {
342
+ background-color: #111827;
343
+ }
344
+
345
+ .dark .bg-gray-50 {
346
+ background-color: #1f2937;
347
+ }
348
+
349
+ .dark .bg-gray-900 {
350
+ background-color: #111827;
351
+ }
352
+
353
+ .text-green-400 {
354
+ color: #4ade80;
355
+ }
356
+
357
+ /* Loading animation */
358
+ .animate-spin {
359
+ animation: spin 1s linear infinite;
360
+ }
361
+
362
+ @keyframes spin {
363
+ from {
364
+ transform: rotate(0deg);
365
+ }
366
+ to {
367
+ transform: rotate(360deg);
368
+ }
369
+ }
370
+
371
+ /* Syntax highlighting adjustments */
372
+ pre {
373
+ margin: 0;
374
+ overflow-x: auto;
375
+ }
376
+
377
+ code {
378
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
379
+ font-size: 0.875rem;
380
+ }
381
+
382
+ /* Details/summary styling */
383
+ details {
384
+ margin: 0.5rem 0;
385
+ }
386
+
387
+ summary {
388
+ cursor: pointer;
389
+ user-select: none;
390
+ padding: 0.5rem;
391
+ border-radius: 0.25rem;
392
+ transition: background-color 0.2s;
393
+ }
394
+
395
+ summary:hover {
396
+ background-color: var(--color-bg-secondary);
397
+ }
398
+
399
+ /* Grid helpers */
400
+ .grid {
401
+ display: grid;
402
+ }
403
+
404
+ .grid-cols-2 {
405
+ grid-template-columns: repeat(2, minmax(0, 1fr));
406
+ }
407
+
408
+ .gap-1 {
409
+ gap: 0.25rem;
410
+ }
411
+
412
+ .min-w-0 {
413
+ min-width: 0;
414
+ }
415
+
416
+ .flex-1 {
417
+ flex: 1;
418
+ }
419
+
420
+ .flex-shrink-0 {
421
+ flex-shrink: 0;
422
+ }
423
+ </style>
424
+ </head>
425
+ <body>
426
+ <div class="app-container">
427
+ <!-- Header -->
428
+ <header>
429
+ <h1 class="header-title">AgentGUI</h1>
430
+
431
+ <div class="header-controls">
432
+ <div class="status-badge">
433
+ <div class="status-indicator" data-status="disconnected"></div>
434
+ <span data-status-indicator>Disconnected</span>
115
435
  </div>
116
- </div>
117
- </div>
118
- </div>
119
436
 
120
- <!-- Modal for new chat options -->
121
- <div id="newChatModal" class="gm-modal">
122
- <div class="gm-modal-content" style="max-width: 400px;">
123
- <div class="gm-modal-header">
124
- <h3>New Chat</h3>
125
- <button onclick="closeNewChatModal()" class="gm-btn-close">&times;</button>
126
- </div>
127
- <div class="gm-modal-body" style="gap: 1rem; flex-direction: column; padding: 2rem;">
128
- <button class="chat-option-btn" onclick="createChatInWorkspace()">
129
- <span class="chat-option-icon">💬</span>
130
- <div class="chat-option-content">
131
- <div class="chat-option-title">Chat in this workspace</div>
132
- <div class="chat-option-desc">Default chat mode</div>
133
- </div>
134
- </button>
135
- <button class="chat-option-btn" onclick="createChatInFolder()">
136
- <span class="chat-option-icon">📁</span>
137
- <div class="chat-option-content">
138
- <div class="chat-option-title">Chat in folder</div>
139
- <div class="chat-option-desc">Contextualize chat to a specific folder</div>
140
- </div>
437
+ <button class="btn btn-primary" data-theme-toggle title="Toggle dark mode">
438
+ 🌓 Theme
141
439
  </button>
142
440
  </div>
143
- </div>
144
- </div>
441
+ </header>
145
442
 
146
- <!-- Modal for folder browser -->
147
- <div id="folderBrowserModal" class="gm-modal">
148
- <div class="gm-modal-content" style="max-width: 600px; height: 500px;">
149
- <div class="gm-modal-header">
150
- <h3>Select a Folder</h3>
151
- <button class="gm-btn-close" onclick="closeFolderBrowser()">&times;</button>
152
- </div>
153
- <div class="gm-modal-body" style="flex-direction: column; gap: 0; padding: 0;">
154
- <div style="padding: 1rem 1.5rem; border-bottom: 1px solid var(--border-color); display: flex; gap: 0.5rem; align-items: center;">
155
- <input type="text" id="folderPath" class="gm-input" placeholder="/home or ~" style="flex: 1; margin: 0;" />
156
- <button onclick="browseFolders()" class="gm-btn gm-btn-primary" style="margin: 0;">Browse</button>
443
+ <!-- Main Content -->
444
+ <main>
445
+ <!-- Execution Panel -->
446
+ <div class="execution-panel">
447
+ <div class="execution-input-group">
448
+ <select class="agent-selector" data-agent-selector title="Select agent">
449
+ <option value="claude-code">Claude Code</option>
450
+ <option value="opencode">OpenCode</option>
451
+ </select>
452
+
453
+ <textarea
454
+ class="execution-textarea"
455
+ data-message-input
456
+ placeholder="Enter command or prompt... (Ctrl+Enter to submit)"
457
+ aria-label="Execution prompt input"
458
+ ></textarea>
157
459
  </div>
158
- <div id="folderBrowserList" style="flex: 1; overflow-y: auto; padding: 0; border: none;"></div>
159
- </div>
160
- <div class="gm-modal-footer">
161
- <button onclick="confirmFolderSelection()" class="gm-btn gm-btn-primary">Select</button>
162
- <button onclick="closeFolderBrowser()" class="gm-btn gm-btn-secondary">Cancel</button>
163
- </div>
164
- </div>
165
- </div>
166
460
 
167
- <!-- Modal for delete confirmation -->
168
- <div id="deleteConfirmModal" class="gm-modal">
169
- <div class="gm-modal-content" style="max-width: 400px;">
170
- <div class="gm-modal-header">
171
- <h3>Delete Chat</h3>
172
- <button class="gm-btn-close" onclick="app.closeDeleteConfirmDialog()">&times;</button>
173
- </div>
174
- <div class="gm-modal-body" style="flex-direction: column; gap: 1rem; text-align: center;">
175
- <p style="margin: 0; color: var(--text-primary);">Are you sure you want to delete this chat?</p>
176
- <p style="margin: 0; font-size: 0.875rem; color: var(--text-tertiary);">This action cannot be undone.</p>
177
- </div>
178
- <div class="gm-modal-footer">
179
- <button class="gm-btn-confirm gm-btn gm-btn-danger">Delete</button>
180
- <button class="gm-btn-cancel gm-btn gm-btn-secondary">Cancel</button>
461
+ <button class="btn btn-primary" data-send-button title="Start execution (Ctrl+Enter)">
462
+ Execute
463
+ </button>
181
464
  </div>
182
- </div>
183
- </div>
184
465
 
185
- <!-- Modal for screenshot preview -->
186
- <div id="screenshotModal" class="gm-modal">
187
- <div class="gm-modal-content">
188
- <div class="gm-modal-header">
189
- <h3>Screenshot Captured</h3>
190
- <button onclick="closeScreenshotModal()" class="gm-btn-close">&times;</button>
466
+ <!-- Output Container -->
467
+ <div id="output-scroll" role="region" aria-label="Execution output" aria-live="polite" aria-atomic="false">
468
+ <div id="output" class="output"></div>
191
469
  </div>
192
- <div class="gm-modal-body">
193
- <img id="screenshotImage" src="" alt="Screenshot" style="max-width: 100%; max-height: 60vh; border-radius: 0.5rem;" />
194
- </div>
195
- <div class="gm-modal-footer">
196
- <button onclick="sendScreenshot()" class="gm-btn gm-btn-success">Send to Agent</button>
197
- <button onclick="downloadScreenshot()" class="gm-btn gm-btn-secondary">Download</button>
198
- <button onclick="closeScreenshotModal()" class="gm-btn gm-btn-secondary">Close</button>
199
- </div>
200
- </div>
470
+ </main>
201
471
  </div>
202
472
 
203
- <!-- Loading overlay -->
204
- <div id="loadingOverlay" class="loading-overlay">
205
- <div class="gm-spinner"></div>
206
- </div>
473
+ <!-- Scripts - Order matters! -->
474
+ <!-- 1. Event Processor (no dependencies) -->
475
+ <script src="/gm/js/event-processor.js"></script>
476
+
477
+ <!-- 2. Streaming Renderer (no dependencies) -->
478
+ <script src="/gm/js/streaming-renderer.js"></script>
479
+
480
+ <!-- 3. WebSocket Manager (no dependencies) -->
481
+ <script src="/gm/js/websocket-manager.js"></script>
482
+
483
+ <!-- 4. Event Filter (depends on Streaming Renderer) -->
484
+ <script src="/gm/js/event-filter.js"></script>
485
+
486
+ <!-- 5. Syntax Highlighter (no dependencies) -->
487
+ <script src="/gm/js/syntax-highlighter.js"></script>
488
+
489
+ <!-- 6. UI Components (no dependencies) -->
490
+ <script src="/gm/js/ui-components.js"></script>
491
+
492
+ <!-- 7. Main Client (depends on all above) -->
493
+ <script src="/gm/js/client.js"></script>
494
+
495
+ <!-- Inline initialization -->
496
+ <script>
497
+ // Set initial theme based on preference
498
+ const savedTheme = localStorage.getItem('theme') || 'light';
499
+ if (savedTheme === 'dark') {
500
+ document.documentElement.classList.add('dark');
501
+ }
502
+
503
+ // Fallback error handler
504
+ window.addEventListener('error', (event) => {
505
+ console.error('Uncaught error:', event.error);
506
+ });
507
+
508
+ window.addEventListener('unhandledrejection', (event) => {
509
+ console.error('Unhandled rejection:', event.reason);
510
+ });
207
511
 
208
- <script src="theme.js"></script>
209
- <script src="app.js"></script>
512
+ // Log client readiness
513
+ document.addEventListener('DOMContentLoaded', () => {
514
+ console.log('DOM loaded, waiting for client initialization');
515
+ });
516
+ </script>
210
517
  </body>
211
518
  </html>