agentgui 1.0.930 → 1.0.932
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.
- package/AGENTS.md +35 -12
- package/database.js +31 -2
- package/lib/http-handler.js +11 -25
- package/lib/routes-registry.js +4 -48
- package/lib/server-startup.js +3 -11
- package/lib/ws-setup.js +2 -1
- package/package.json +3 -3
- package/server.js +7 -1
- package/site/app/js/app.js +64 -68
- package/site/app/js/backend.js +1 -1
- package/static/lib/xstate.umd.min.js +1 -1
- package/lib/db-queries-chunks.js +0 -195
- package/lib/db-queries-chunks2.js +0 -82
- package/lib/db-queries-cleanup.js +0 -74
- package/lib/db-queries-del.js +0 -141
- package/lib/db-queries-events.js +0 -68
- package/lib/db-queries-import.js +0 -133
- package/lib/db-queries-messages.js +0 -102
- package/lib/db-queries-sessions.js +0 -112
- package/lib/db-queries-streams.js +0 -100
- package/lib/db-queries.js +0 -89
- package/lib/jsonl-parser.js +0 -190
- package/lib/jsonl-watcher.js +0 -64
- package/lib/routes-agent-actions.js +0 -61
- package/lib/routes-auth-config.js +0 -30
- package/lib/routes-conversations.js +0 -96
- package/lib/routes-debug.js +0 -119
- package/lib/routes-messages.js +0 -139
- package/lib/routes-runs.js +0 -156
- package/lib/routes-scripts.js +0 -135
- package/lib/routes-sessions.js +0 -144
- package/lib/routes-threads.js +0 -100
- package/lib/routes-util.js +0 -110
- package/lib/ws-handlers-conv.js +0 -138
- package/lib/ws-handlers-conv2.js +0 -169
- package/lib/ws-handlers-msg.js +0 -121
- package/lib/ws-handlers-queue.js +0 -56
- package/lib/ws-handlers-run.js +0 -182
- package/lib/ws-handlers-scripts.js +0 -66
- package/lib/ws-handlers-session.js +0 -105
- package/lib/ws-handlers-session2.js +0 -85
- package/lib/ws-legacy-handlers.js +0 -51
- package/static/app.js +0 -261
- package/static/css/app-shell.css +0 -419
- package/static/css/brand-bible.css +0 -591
- package/static/css/colors_and_type.css +0 -568
- package/static/css/gmail-skin.css +0 -663
- package/static/css/main.css +0 -4015
- package/static/css/tools-popup.css +0 -472
- package/static/index.html +0 -418
- package/static/js/agent-auth.js +0 -146
- package/static/js/app-shortcuts.js +0 -30
- package/static/js/audio-recorder-processor.js +0 -18
- package/static/js/client-agents.js +0 -155
- package/static/js/client-cache.js +0 -171
- package/static/js/client-conv.js +0 -198
- package/static/js/client-events.js +0 -164
- package/static/js/client-exec.js +0 -160
- package/static/js/client-helpers.js +0 -199
- package/static/js/client-load.js +0 -175
- package/static/js/client-render.js +0 -132
- package/static/js/client-scroll.js +0 -178
- package/static/js/client-status.js +0 -167
- package/static/js/client-streaming.js +0 -117
- package/static/js/client-streaming2.js +0 -116
- package/static/js/client-streaming3.js +0 -153
- package/static/js/client-streaming4.js +0 -194
- package/static/js/client-ui-controls.js +0 -170
- package/static/js/client-ui.js +0 -128
- package/static/js/client-ui2.js +0 -160
- package/static/js/client-url.js +0 -93
- package/static/js/client-utils.js +0 -174
- package/static/js/client-ws-msg.js +0 -88
- package/static/js/client-ws.js +0 -161
- package/static/js/client.js +0 -145
- package/static/js/codec.js +0 -4
- package/static/js/conv-list-machine.js +0 -145
- package/static/js/conv-list-renderer.js +0 -198
- package/static/js/conv-machine.js +0 -110
- package/static/js/conv-sidebar-actions.js +0 -188
- package/static/js/conv-sidebar-clone.js +0 -91
- package/static/js/conversations.js +0 -116
- package/static/js/dialogs-types.js +0 -111
- package/static/js/dialogs.js +0 -53
- package/static/js/event-filter-config.js +0 -36
- package/static/js/event-processor.js +0 -181
- package/static/js/features.js +0 -187
- package/static/js/image-loader-element.js +0 -76
- package/static/js/image-loader.js +0 -146
- package/static/js/prompt-machine.js +0 -108
- package/static/js/recording-machine.js +0 -49
- package/static/js/script-runner.js +0 -192
- package/static/js/state-barrier.js +0 -105
- package/static/js/streaming-renderer-dispatch.js +0 -144
- package/static/js/streaming-renderer-events.js +0 -163
- package/static/js/streaming-renderer-events2.js +0 -125
- package/static/js/streaming-renderer-params.js +0 -38
- package/static/js/streaming-renderer-render-misc.js +0 -107
- package/static/js/streaming-renderer-render.js +0 -181
- package/static/js/streaming-renderer-render2.js +0 -149
- package/static/js/streaming-renderer-render3.js +0 -142
- package/static/js/streaming-renderer-static.js +0 -181
- package/static/js/streaming-renderer-static2.js +0 -140
- package/static/js/streaming-renderer-stream.js +0 -170
- package/static/js/streaming-renderer-text.js +0 -185
- package/static/js/streaming-renderer-tools.js +0 -189
- package/static/js/streaming-renderer-tools2.js +0 -92
- package/static/js/streaming-renderer.js +0 -200
- package/static/js/syntax-highlighter-render.js +0 -72
- package/static/js/syntax-highlighter.js +0 -131
- package/static/js/terminal-machine.js +0 -51
- package/static/js/terminal.js +0 -178
- package/static/js/ui-components-rendering.js +0 -62
- package/static/js/ui-components.js +0 -88
- package/static/js/websocket-manager.js +0 -107
- package/static/js/ws-client.js +0 -87
- package/static/js/ws-core.js +0 -162
- package/static/js/ws-latency.js +0 -88
- package/static/js/ws-machine.js +0 -68
- package/static/lib/msgpackr.min.js +0 -2
- package/static/theme.js +0 -74
- package/static/vendor/highlight-js.css +0 -10
- package/static/vendor/highlight.min.js +0 -1244
- package/static/vendor/prism-dark.css +0 -129
- package/static/vendor/rippleui.css +0 -35
- package/static/vendor/xterm-addon-fit.min.js +0 -8
- package/static/vendor/xterm.css +0 -8
- package/static/vendor/xterm.min.js +0 -8
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
class EventProcessor {
|
|
2
|
-
constructor(config = {}) {
|
|
3
|
-
this.config = {
|
|
4
|
-
enableSyntaxHighlight: config.enableSyntaxHighlight !== false,
|
|
5
|
-
...config
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
this.stats = {
|
|
9
|
-
totalEvents: 0,
|
|
10
|
-
processedEvents: 0,
|
|
11
|
-
validatedEvents: 0,
|
|
12
|
-
transformedEvents: 0,
|
|
13
|
-
errorCount: 0,
|
|
14
|
-
avgProcessTime: 0
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Process and enrich event
|
|
20
|
-
*/
|
|
21
|
-
processEvent(event) {
|
|
22
|
-
if (!event || typeof event !== 'object') {
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Filter isMeta user entries (local command caveats injected by Claude Code CLI)
|
|
27
|
-
if (event.type === 'user' && event.isMeta === true) {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const startTime = performance.now();
|
|
32
|
-
this.stats.totalEvents++;
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
// Validate event structure
|
|
36
|
-
if (!this.validateEvent(event)) {
|
|
37
|
-
this.stats.errorCount++;
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
this.stats.validatedEvents++;
|
|
42
|
-
|
|
43
|
-
// Add processing metadata
|
|
44
|
-
const processed = {
|
|
45
|
-
...event,
|
|
46
|
-
processedAt: Date.now(),
|
|
47
|
-
processTime: 0
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
// Route isCompactSummary entries to special display type
|
|
51
|
-
if (event.isCompactSummary === true) {
|
|
52
|
-
processed.type = 'compact_summary';
|
|
53
|
-
this.stats.transformedEvents++;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Extract and flatten cache usage for cost tracking
|
|
57
|
-
if (event.message?.usage) {
|
|
58
|
-
const u = event.message.usage;
|
|
59
|
-
processed._cacheCreation = u.cache_creation_input_tokens
|
|
60
|
-
|| u['cache_creation.ephemeral_1h_input_tokens']
|
|
61
|
-
|| u['cache_creation.ephemeral_5m_input_tokens']
|
|
62
|
-
|| 0;
|
|
63
|
-
processed._cacheRead = u.cache_read_input_tokens || 0;
|
|
64
|
-
if (processed._cacheCreation || processed._cacheRead) {
|
|
65
|
-
this.stats.transformedEvents++;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (event.type === 'file_read' && event.path && this.isImagePath(event.path)) {
|
|
70
|
-
processed.isImage = true;
|
|
71
|
-
processed.imagePath = event.path;
|
|
72
|
-
this.stats.transformedEvents++;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if ((event.type === 'text_block' || event.type === 'command_execute' || event.type === 'streaming_progress') && (event.content || event.output)) {
|
|
76
|
-
const imagePaths = this.extractImagePaths(event.content || event.output || '');
|
|
77
|
-
if (imagePaths.length > 0) {
|
|
78
|
-
processed.detectedImages = imagePaths;
|
|
79
|
-
this.stats.transformedEvents++;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
processed.processTime = performance.now() - startTime;
|
|
84
|
-
this.stats.processedEvents++;
|
|
85
|
-
|
|
86
|
-
// Update average processing time
|
|
87
|
-
this.stats.avgProcessTime = (this.stats.avgProcessTime * (this.stats.processedEvents - 1) + processed.processTime) / this.stats.processedEvents;
|
|
88
|
-
|
|
89
|
-
return processed;
|
|
90
|
-
} catch (error) {
|
|
91
|
-
console.error('Event processing error:', error);
|
|
92
|
-
this.stats.errorCount++;
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Validate event structure
|
|
99
|
-
*/
|
|
100
|
-
validateEvent(event) {
|
|
101
|
-
if (!event.type) {
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Required fields by type
|
|
106
|
-
const typeRequirements = {
|
|
107
|
-
streaming_start: ['sessionId', 'conversationId'],
|
|
108
|
-
streaming_complete: ['sessionId'],
|
|
109
|
-
file_read: ['path'],
|
|
110
|
-
file_write: ['path'],
|
|
111
|
-
command_execute: ['command'],
|
|
112
|
-
git_status: [],
|
|
113
|
-
error: ['message']
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
const requirements = typeRequirements[event.type];
|
|
117
|
-
if (requirements) {
|
|
118
|
-
for (const field of requirements) {
|
|
119
|
-
if (!event[field]) {
|
|
120
|
-
return false;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return true;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
getFileExtension(filePath) {
|
|
129
|
-
const match = filePath.match(/\.([^.]+)$/);
|
|
130
|
-
return match ? match[1].toLowerCase() : null;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
getStats() {
|
|
134
|
-
return { ...this.stats };
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Reset statistics
|
|
139
|
-
*/
|
|
140
|
-
resetStats() {
|
|
141
|
-
this.stats = {
|
|
142
|
-
totalEvents: 0,
|
|
143
|
-
processedEvents: 0,
|
|
144
|
-
validatedEvents: 0,
|
|
145
|
-
transformedEvents: 0,
|
|
146
|
-
errorCount: 0,
|
|
147
|
-
avgProcessTime: 0
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Check if a path is an image file
|
|
153
|
-
*/
|
|
154
|
-
isImagePath(filePath) {
|
|
155
|
-
if (!filePath || typeof filePath !== 'string') return false;
|
|
156
|
-
const imageExts = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg'];
|
|
157
|
-
const ext = this.getFileExtension(filePath);
|
|
158
|
-
return imageExts.includes(ext);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Extract image file paths from text content
|
|
163
|
-
*/
|
|
164
|
-
extractImagePaths(content) {
|
|
165
|
-
if (typeof content !== 'string') return [];
|
|
166
|
-
const paths = [];
|
|
167
|
-
const pathPattern = /(?:\/[a-zA-Z0-9_.\-]+)+\/[a-zA-Z0-9_.\-]+\.(?:png|jpg|jpeg|gif|webp|svg)/gi;
|
|
168
|
-
let match;
|
|
169
|
-
while ((match = pathPattern.exec(content)) !== null) {
|
|
170
|
-
if (this.isImagePath(match[0])) {
|
|
171
|
-
paths.push(match[0]);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
return [...new Set(paths)];
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Export for use in browser
|
|
179
|
-
if (typeof module !== 'undefined' && module.exports) {
|
|
180
|
-
module.exports = EventProcessor;
|
|
181
|
-
}
|
package/static/js/features.js
DELETED
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
(function() {
|
|
2
|
-
const BASE = window.__BASE_URL || '';
|
|
3
|
-
let currentConversation = null;
|
|
4
|
-
let currentView = 'chat';
|
|
5
|
-
let dragCounter = 0;
|
|
6
|
-
|
|
7
|
-
function init() {
|
|
8
|
-
setupSidebarToggle();
|
|
9
|
-
setupDragAndDrop();
|
|
10
|
-
setupViewToggle();
|
|
11
|
-
setupConversationListener();
|
|
12
|
-
setupModelProgressIndicator();
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function setupSidebarToggle() {
|
|
16
|
-
var toggleBtn = document.querySelector('[data-sidebar-toggle]');
|
|
17
|
-
var sidebar = document.querySelector('[data-sidebar]');
|
|
18
|
-
var overlay = document.querySelector('[data-sidebar-overlay]');
|
|
19
|
-
if (!sidebar) return;
|
|
20
|
-
if (window.innerWidth <= 768) {
|
|
21
|
-
sidebar.classList.add('collapsed');
|
|
22
|
-
} else {
|
|
23
|
-
var savedState = localStorage.getItem('sidebar-collapsed');
|
|
24
|
-
if (savedState === 'true') sidebar.classList.add('collapsed');
|
|
25
|
-
}
|
|
26
|
-
function isMobile() { return window.innerWidth <= 768; }
|
|
27
|
-
function toggleSidebar() {
|
|
28
|
-
if (isMobile()) {
|
|
29
|
-
sidebar.classList.contains('mobile-visible') ? closeSidebar() : openSidebar();
|
|
30
|
-
} else {
|
|
31
|
-
sidebar.classList.toggle('collapsed');
|
|
32
|
-
localStorage.setItem('sidebar-collapsed', sidebar.classList.contains('collapsed'));
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
function openSidebar() {
|
|
36
|
-
sidebar.classList.add('mobile-visible');
|
|
37
|
-
sidebar.classList.remove('collapsed');
|
|
38
|
-
if (overlay) overlay.classList.add('visible');
|
|
39
|
-
}
|
|
40
|
-
function closeSidebar() {
|
|
41
|
-
sidebar.classList.remove('mobile-visible');
|
|
42
|
-
sidebar.classList.add('collapsed'); // Ensure sidebar is hidden on close
|
|
43
|
-
if (overlay) overlay.classList.remove('visible');
|
|
44
|
-
}
|
|
45
|
-
if (toggleBtn) toggleBtn.addEventListener('click', function(e) { e.stopPropagation(); toggleSidebar(); });
|
|
46
|
-
if (overlay) overlay.addEventListener('click', closeSidebar);
|
|
47
|
-
document.addEventListener('keydown', function(e) {
|
|
48
|
-
if ((e.ctrlKey || e.metaKey) && e.key === 'b') { e.preventDefault(); toggleSidebar(); }
|
|
49
|
-
});
|
|
50
|
-
window.addEventListener('conversation-selected', function() { if (isMobile()) closeSidebar(); });
|
|
51
|
-
window.addEventListener('resize', function() {
|
|
52
|
-
if (!isMobile()) { sidebar.classList.remove('mobile-visible'); if (overlay) overlay.classList.remove('visible'); }
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function setupDragAndDrop() {
|
|
57
|
-
var dropZone = document.querySelector('[data-drop-zone]');
|
|
58
|
-
var overlay = document.getElementById('dropZoneOverlay');
|
|
59
|
-
if (!dropZone || !overlay) return;
|
|
60
|
-
dropZone.addEventListener('dragenter', function(e) { e.preventDefault(); e.stopPropagation(); dragCounter++; if (dragCounter === 1) overlay.classList.add('visible'); });
|
|
61
|
-
dropZone.addEventListener('dragover', function(e) { e.preventDefault(); e.stopPropagation(); });
|
|
62
|
-
dropZone.addEventListener('dragleave', function(e) { e.preventDefault(); e.stopPropagation(); dragCounter--; if (dragCounter <= 0) { dragCounter = 0; overlay.classList.remove('visible'); } });
|
|
63
|
-
dropZone.addEventListener('drop', function(e) {
|
|
64
|
-
e.preventDefault(); e.stopPropagation(); dragCounter = 0; overlay.classList.remove('visible');
|
|
65
|
-
if (!currentConversation) { if (window.UIDialog) window.UIDialog.showToast('Select a conversation first', 'error'); return; }
|
|
66
|
-
var files = e.dataTransfer.files;
|
|
67
|
-
if (!files || files.length === 0) return;
|
|
68
|
-
uploadFiles(files);
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function uploadFiles(files) {
|
|
73
|
-
if (!currentConversation) { if (window.UIDialog) window.UIDialog.showToast('No conversation selected', 'error'); return; }
|
|
74
|
-
var formData = new FormData();
|
|
75
|
-
for (var i = 0; i < files.length; i++) formData.append('file', files[i]);
|
|
76
|
-
if (window.UIDialog) window.UIDialog.showToast('Uploading ' + files.length + ' file(s)...', 'info');
|
|
77
|
-
fetch(BASE + '/api/upload/' + currentConversation, { method: 'POST', body: formData })
|
|
78
|
-
.then(function(res) { return res.json(); })
|
|
79
|
-
.then(function(data) {
|
|
80
|
-
if (data.ok) { if (window.UIDialog) window.UIDialog.showToast(data.count + ' file(s) uploaded', 'success'); }
|
|
81
|
-
else { if (window.UIDialog) window.UIDialog.showToast('Upload failed: ' + (data.error || 'Unknown error'), 'error'); }
|
|
82
|
-
})
|
|
83
|
-
.catch(function(err) { if (window.UIDialog) window.UIDialog.showToast('Upload failed: ' + err.message, 'error'); });
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function setupViewToggle() {
|
|
87
|
-
var bar = document.getElementById('viewToggleBar');
|
|
88
|
-
if (!bar) return;
|
|
89
|
-
bar.querySelectorAll('.view-toggle-btn').forEach(function(btn) {
|
|
90
|
-
btn.addEventListener('click', function() { switchView(btn.dataset.view); });
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function setupModelProgressIndicator() {
|
|
95
|
-
var indicator = document.getElementById('modelDlIndicator');
|
|
96
|
-
var tooltip = document.getElementById('modelDlTooltip');
|
|
97
|
-
var progressCircle = indicator ? indicator.querySelector('.progress') : null;
|
|
98
|
-
var circumference = 62.83;
|
|
99
|
-
|
|
100
|
-
window.addEventListener('ws-message', function(e) {
|
|
101
|
-
var data = e.detail;
|
|
102
|
-
if (!data || data.type !== 'model_download_progress') return;
|
|
103
|
-
var progress = data.progress || data;
|
|
104
|
-
if (progress.done && progress.complete) {
|
|
105
|
-
if (indicator) indicator.classList.remove('active');
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
if (progress.error || progress.status === 'failed') {
|
|
109
|
-
if (indicator) indicator.classList.remove('active');
|
|
110
|
-
if (tooltip) tooltip.textContent = 'Voice model download failed: ' + (progress.error || 'unknown');
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
if (progress.started || progress.downloading || progress.status === 'downloading') {
|
|
114
|
-
if (indicator) indicator.classList.add('active');
|
|
115
|
-
var pct = progress.percentComplete || 0;
|
|
116
|
-
if (progress.completedFiles && progress.totalFiles) {
|
|
117
|
-
pct = Math.round((progress.completedFiles / progress.totalFiles) * 100);
|
|
118
|
-
}
|
|
119
|
-
if (progressCircle) {
|
|
120
|
-
progressCircle.style.strokeDashoffset = circumference - (circumference * pct / 100);
|
|
121
|
-
}
|
|
122
|
-
var msg = 'Downloading voice models... ' + pct + '%';
|
|
123
|
-
if (progress.file) msg = 'Downloading ' + progress.file + '...';
|
|
124
|
-
if (tooltip) tooltip.textContent = msg;
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
if (window.wsClient) {
|
|
129
|
-
window.wsClient.rpc('speech.status')
|
|
130
|
-
.then(function(status) {
|
|
131
|
-
if (status.modelsComplete) {
|
|
132
|
-
if (indicator) indicator.classList.remove('active');
|
|
133
|
-
} else if (status.modelsDownloading) {
|
|
134
|
-
if (indicator) indicator.classList.add('active');
|
|
135
|
-
}
|
|
136
|
-
})
|
|
137
|
-
.catch(function() {});
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function switchView(view) {
|
|
142
|
-
currentView = view;
|
|
143
|
-
var bar = document.getElementById('viewToggleBar');
|
|
144
|
-
var chatArea = document.getElementById('output-scroll');
|
|
145
|
-
var execPanel = document.querySelector('.input-section');
|
|
146
|
-
var fileBrowser = document.getElementById('fileBrowserContainer');
|
|
147
|
-
var fileIframe = document.getElementById('fileBrowserIframe');
|
|
148
|
-
var terminalContainer = document.getElementById('terminalContainer');
|
|
149
|
-
if (!bar) return;
|
|
150
|
-
bar.querySelectorAll('.view-toggle-btn').forEach(function(btn) {
|
|
151
|
-
btn.classList.toggle('active', btn.dataset.view === view);
|
|
152
|
-
});
|
|
153
|
-
if (chatArea) chatArea.style.display = view === 'chat' ? '' : 'none';
|
|
154
|
-
if (execPanel) execPanel.style.display = view === 'chat' ? '' : 'none';
|
|
155
|
-
if (fileBrowser) fileBrowser.style.display = view === 'files' ? 'flex' : 'none';
|
|
156
|
-
if (terminalContainer) terminalContainer.style.display = view === 'terminal' ? 'flex' : 'none';
|
|
157
|
-
if (view === 'files' && fileIframe && currentConversation) {
|
|
158
|
-
var src = BASE + '/files/' + currentConversation + '/';
|
|
159
|
-
if (fileIframe.src !== location.origin + src) fileIframe.src = src;
|
|
160
|
-
}
|
|
161
|
-
window.dispatchEvent(new CustomEvent('view-switched', { detail: { view: view } }));
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function updateViewToggleVisibility() {
|
|
165
|
-
var bar = document.getElementById('viewToggleBar');
|
|
166
|
-
if (!bar) return;
|
|
167
|
-
bar.style.display = currentConversation ? 'flex' : 'none';
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function setupConversationListener() {
|
|
171
|
-
window.addEventListener('conversation-selected', function(e) {
|
|
172
|
-
currentConversation = e.detail.conversationId;
|
|
173
|
-
updateViewToggleVisibility();
|
|
174
|
-
if (currentView === 'files') switchView('files');
|
|
175
|
-
});
|
|
176
|
-
window.addEventListener('conversation-deselected', function() {
|
|
177
|
-
currentConversation = null;
|
|
178
|
-
updateViewToggleVisibility();
|
|
179
|
-
switchView('chat');
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
window.switchView = switchView;
|
|
184
|
-
|
|
185
|
-
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
|
|
186
|
-
else init();
|
|
187
|
-
})();
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
Object.assign(ImageLoader.prototype, {
|
|
3
|
-
createImageElement(imagePath, options = {}) {
|
|
4
|
-
const container = document.createElement('div');
|
|
5
|
-
container.className = 'image-container';
|
|
6
|
-
container.dataset.imagePath = imagePath;
|
|
7
|
-
container.style.cssText = `
|
|
8
|
-
display: flex;
|
|
9
|
-
flex-direction: column;
|
|
10
|
-
gap: 0.5rem;
|
|
11
|
-
padding: 0.75rem;
|
|
12
|
-
border-radius: 0.375rem;
|
|
13
|
-
background: var(--color-bg-secondary);
|
|
14
|
-
border: 1px solid var(--color-border);
|
|
15
|
-
`;
|
|
16
|
-
|
|
17
|
-
const placeholder = document.createElement('div');
|
|
18
|
-
placeholder.className = 'image-placeholder';
|
|
19
|
-
placeholder.style.cssText = `
|
|
20
|
-
background: linear-gradient(90deg, var(--color-bg-tertiary) 25%, var(--color-bg-secondary) 50%, var(--color-bg-tertiary) 75%);
|
|
21
|
-
background-size: 200% 100%;
|
|
22
|
-
animation: loading 1.5s infinite;
|
|
23
|
-
border-radius: 0.375rem;
|
|
24
|
-
aspect-ratio: 16/9;
|
|
25
|
-
display: flex;
|
|
26
|
-
align-items: center;
|
|
27
|
-
justify-content: center;
|
|
28
|
-
color: var(--color-text-secondary);
|
|
29
|
-
font-size: 0.875rem;
|
|
30
|
-
`;
|
|
31
|
-
placeholder.innerHTML = 'Loading image...';
|
|
32
|
-
placeholder.dataset.path = imagePath;
|
|
33
|
-
|
|
34
|
-
const img = document.createElement('img');
|
|
35
|
-
img.className = 'lazy-image';
|
|
36
|
-
img.alt = imagePath;
|
|
37
|
-
img.style.cssText = `
|
|
38
|
-
max-width: 100%;
|
|
39
|
-
max-height: ${this.config.maxImageDisplaySize};
|
|
40
|
-
border-radius: 0.375rem;
|
|
41
|
-
display: none;
|
|
42
|
-
`;
|
|
43
|
-
img.dataset.src = imagePath;
|
|
44
|
-
|
|
45
|
-
const caption = document.createElement('div');
|
|
46
|
-
caption.className = 'image-caption';
|
|
47
|
-
caption.style.cssText = `
|
|
48
|
-
font-size: 0.75rem;
|
|
49
|
-
color: var(--color-text-secondary);
|
|
50
|
-
word-break: break-all;
|
|
51
|
-
font-family: 'Monaco', 'Menlo', monospace;
|
|
52
|
-
`;
|
|
53
|
-
caption.textContent = imagePath;
|
|
54
|
-
|
|
55
|
-
container.appendChild(placeholder);
|
|
56
|
-
container.appendChild(img);
|
|
57
|
-
container.appendChild(caption);
|
|
58
|
-
|
|
59
|
-
img.addEventListener('load', () => {
|
|
60
|
-
placeholder.style.display = 'none';
|
|
61
|
-
img.style.display = 'block';
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
img.addEventListener('error', () => {
|
|
65
|
-
placeholder.textContent = 'Failed to load image';
|
|
66
|
-
placeholder.style.background = 'var(--color-bg-error)';
|
|
67
|
-
placeholder.style.color = 'var(--color-text-error)';
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
if (this.intersectionObserver) {
|
|
71
|
-
this.intersectionObserver.observe(container);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return container;
|
|
75
|
-
}
|
|
76
|
-
});
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
class ImageLoader {
|
|
3
|
-
constructor(config = {}) {
|
|
4
|
-
this.config = {
|
|
5
|
-
supportedExts: ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg'],
|
|
6
|
-
lazyLoadThreshold: config.lazyLoadThreshold || 0.5,
|
|
7
|
-
maxImageDisplaySize: config.maxImageDisplaySize || '600px',
|
|
8
|
-
...config
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
this.imageCache = new Map();
|
|
12
|
-
this.pendingImages = new Map();
|
|
13
|
-
this.intersectionObserver = null;
|
|
14
|
-
this.drawerObserver = null;
|
|
15
|
-
this.initIntersectionObserver();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
isImagePath(filePath) {
|
|
19
|
-
if (!filePath || typeof filePath !== 'string') return false;
|
|
20
|
-
const ext = this.getExtension(filePath).toLowerCase();
|
|
21
|
-
return this.config.supportedExts.includes(ext);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
getExtension(filePath) {
|
|
25
|
-
const match = filePath.match(/\.([^.]+)$/);
|
|
26
|
-
return match ? match[1] : '';
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
extractImagePaths(content) {
|
|
30
|
-
if (typeof content !== 'string') return [];
|
|
31
|
-
|
|
32
|
-
const paths = [];
|
|
33
|
-
const pathPattern = /(?:\/[a-zA-Z0-9_.\-]+)+\/[a-zA-Z0-9_.\-]+\.(?:png|jpg|jpeg|gif|webp|svg)/gi;
|
|
34
|
-
|
|
35
|
-
let match;
|
|
36
|
-
while ((match = pathPattern.exec(content)) !== null) {
|
|
37
|
-
if (this.isImagePath(match[0])) {
|
|
38
|
-
paths.push(match[0]);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return [...new Set(paths)];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
registerImagesFromEvent(event) {
|
|
46
|
-
const images = [];
|
|
47
|
-
|
|
48
|
-
if (event.type === 'file_read' && event.path && this.isImagePath(event.path)) {
|
|
49
|
-
images.push({
|
|
50
|
-
path: event.path,
|
|
51
|
-
type: 'file_read',
|
|
52
|
-
eventId: event.id || event.sessionId,
|
|
53
|
-
timestamp: event.timestamp || Date.now()
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (event.content && typeof event.content === 'string') {
|
|
58
|
-
const paths = this.extractImagePaths(event.content);
|
|
59
|
-
paths.forEach(path => {
|
|
60
|
-
images.push({
|
|
61
|
-
path,
|
|
62
|
-
type: 'extracted',
|
|
63
|
-
eventId: event.id || event.sessionId,
|
|
64
|
-
timestamp: event.timestamp || Date.now()
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (event.output && typeof event.output === 'string') {
|
|
70
|
-
const paths = this.extractImagePaths(event.output);
|
|
71
|
-
paths.forEach(path => {
|
|
72
|
-
images.push({
|
|
73
|
-
path,
|
|
74
|
-
type: 'extracted',
|
|
75
|
-
eventId: event.id || event.sessionId,
|
|
76
|
-
timestamp: event.timestamp || Date.now()
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
images.forEach(img => {
|
|
82
|
-
const key = img.path;
|
|
83
|
-
if (!this.imageCache.has(key)) {
|
|
84
|
-
this.imageCache.set(key, img);
|
|
85
|
-
this.pendingImages.set(key, img);
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
return images;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
initIntersectionObserver() {
|
|
93
|
-
this.intersectionObserver = new IntersectionObserver(
|
|
94
|
-
(entries) => {
|
|
95
|
-
entries.forEach(entry => {
|
|
96
|
-
if (entry.isIntersecting) {
|
|
97
|
-
const img = entry.target.querySelector('img.lazy-image');
|
|
98
|
-
if (img && img.dataset.src && !img.src) {
|
|
99
|
-
img.src = img.dataset.src;
|
|
100
|
-
this.intersectionObserver.unobserve(entry.target);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
},
|
|
105
|
-
{ threshold: this.config.lazyLoadThreshold }
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
setupDrawerObserver(drawerSelector = '.drawer-panel, [role="dialog"]') {
|
|
110
|
-
const drawers = document.querySelectorAll(drawerSelector);
|
|
111
|
-
drawers.forEach(drawer => {
|
|
112
|
-
const observer = new MutationObserver(() => {
|
|
113
|
-
if (drawer.offsetHeight > 0 && drawer.offsetWidth > 0) {
|
|
114
|
-
this.loadVisibleImages(drawer);
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
observer.observe(drawer, { attributes: true, attributeFilter: ['style', 'class'] });
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
loadVisibleImages(container = document) {
|
|
123
|
-
const images = container.querySelectorAll('img.lazy-image[data-src]');
|
|
124
|
-
images.forEach(img => {
|
|
125
|
-
if (!img.src && img.dataset.src) {
|
|
126
|
-
img.src = img.dataset.src;
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
getImages(eventId = null) {
|
|
132
|
-
if (!eventId) {
|
|
133
|
-
return Array.from(this.imageCache.values());
|
|
134
|
-
}
|
|
135
|
-
return Array.from(this.imageCache.values()).filter(img => img.eventId === eventId);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
clear() {
|
|
139
|
-
this.imageCache.clear();
|
|
140
|
-
this.pendingImages.clear();
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (typeof module !== 'undefined' && module.exports) {
|
|
145
|
-
module.exports = ImageLoader;
|
|
146
|
-
}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
(function() {
|
|
2
|
-
const { createMachine, createActor, assign } = XState;
|
|
3
|
-
|
|
4
|
-
const promptMachine = createMachine({
|
|
5
|
-
id: 'prompt-area',
|
|
6
|
-
initial: 'ready',
|
|
7
|
-
context: {
|
|
8
|
-
conversationId: null,
|
|
9
|
-
queueLength: 0,
|
|
10
|
-
},
|
|
11
|
-
states: {
|
|
12
|
-
ready: {
|
|
13
|
-
on: {
|
|
14
|
-
LOADING: 'loading',
|
|
15
|
-
STREAMING: {
|
|
16
|
-
target: 'streaming',
|
|
17
|
-
actions: assign(({ event }) => ({ conversationId: event.conversationId || null })),
|
|
18
|
-
},
|
|
19
|
-
DISABLED: 'disabled',
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
loading: {
|
|
23
|
-
on: {
|
|
24
|
-
READY: 'ready',
|
|
25
|
-
STREAMING: {
|
|
26
|
-
target: 'streaming',
|
|
27
|
-
actions: assign(({ event }) => ({ conversationId: event.conversationId || null })),
|
|
28
|
-
},
|
|
29
|
-
DISABLED: 'disabled',
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
streaming: {
|
|
33
|
-
on: {
|
|
34
|
-
QUEUED: {
|
|
35
|
-
target: 'queued',
|
|
36
|
-
actions: assign(({ event }) => ({ queueLength: event.queueLength || 1 })),
|
|
37
|
-
},
|
|
38
|
-
READY: {
|
|
39
|
-
target: 'ready',
|
|
40
|
-
actions: assign({ conversationId: null, queueLength: 0 }),
|
|
41
|
-
},
|
|
42
|
-
STREAMING: {
|
|
43
|
-
actions: assign(({ event }) => ({ conversationId: event.conversationId || null })),
|
|
44
|
-
},
|
|
45
|
-
QUEUE_UPDATE: {
|
|
46
|
-
actions: assign(({ event }) => ({ queueLength: event.queueLength || 0 })),
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
|
-
queued: {
|
|
51
|
-
on: {
|
|
52
|
-
STREAMING: {
|
|
53
|
-
target: 'streaming',
|
|
54
|
-
actions: assign(({ event }) => ({ conversationId: event.conversationId || null, queueLength: 0 })),
|
|
55
|
-
},
|
|
56
|
-
READY: {
|
|
57
|
-
target: 'ready',
|
|
58
|
-
actions: assign({ conversationId: null, queueLength: 0 }),
|
|
59
|
-
},
|
|
60
|
-
QUEUE_UPDATE: {
|
|
61
|
-
actions: assign(({ event }) => ({ queueLength: event.queueLength || 0 })),
|
|
62
|
-
guard: ({ event }) => (event.queueLength || 0) > 0,
|
|
63
|
-
},
|
|
64
|
-
QUEUE_EMPTY: {
|
|
65
|
-
target: 'ready',
|
|
66
|
-
actions: assign({ conversationId: null, queueLength: 0 }),
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
disabled: {
|
|
71
|
-
on: {
|
|
72
|
-
READY: 'ready',
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
const actor = createActor(promptMachine);
|
|
79
|
-
actor.start();
|
|
80
|
-
|
|
81
|
-
function sendEvent(event) {
|
|
82
|
-
actor.send(event);
|
|
83
|
-
return actor.getSnapshot();
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function getState() {
|
|
87
|
-
return actor.getSnapshot().value;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function isReady() {
|
|
91
|
-
return getState() === 'ready';
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function isStreaming() {
|
|
95
|
-
return getState() === 'streaming';
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function isDisabled() {
|
|
99
|
-
return getState() === 'disabled';
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function subscribe(fn) {
|
|
103
|
-
return actor.subscribe(fn);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
window.__promptMachine = actor;
|
|
107
|
-
window.promptMachineAPI = { send: sendEvent, getState, isReady, isStreaming, isDisabled, subscribe };
|
|
108
|
-
})();
|