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,200 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
class StreamingRenderer {
|
|
3
|
-
constructor(config = {}) {
|
|
4
|
-
this.config = {
|
|
5
|
-
batchSize: config.batchSize || 50,
|
|
6
|
-
batchInterval: config.batchInterval || 16, // ~60fps
|
|
7
|
-
maxQueueSize: config.maxQueueSize || 10000,
|
|
8
|
-
maxEventHistory: config.maxEventHistory || 1000,
|
|
9
|
-
virtualScrollThreshold: config.virtualScrollThreshold || 500,
|
|
10
|
-
debounceDelay: config.debounceDelay || 100,
|
|
11
|
-
...config
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
this.eventQueue = [];
|
|
15
|
-
this.eventHistory = [];
|
|
16
|
-
this.isProcessing = false;
|
|
17
|
-
this.batchTimer = null;
|
|
18
|
-
this.dedupMap = new Map();
|
|
19
|
-
this.renderCache = new Map();
|
|
20
|
-
this.domNodeCount = 0;
|
|
21
|
-
this.lastRenderTime = 0;
|
|
22
|
-
this.performanceMetrics = {
|
|
23
|
-
totalEvents: 0,
|
|
24
|
-
totalBatches: 0,
|
|
25
|
-
avgBatchSize: 0,
|
|
26
|
-
avgRenderTime: 0,
|
|
27
|
-
avgProcessTime: 0
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
this.outputContainer = null;
|
|
31
|
-
this.scrollContainer = null;
|
|
32
|
-
this.virtualScroller = null;
|
|
33
|
-
|
|
34
|
-
this.listeners = {
|
|
35
|
-
'event:queued': [],
|
|
36
|
-
'event:dequeued': [],
|
|
37
|
-
'batch:start': [],
|
|
38
|
-
'batch:complete': [],
|
|
39
|
-
'render:start': [],
|
|
40
|
-
'render:complete': [],
|
|
41
|
-
'error:render': []
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
this.observer = null;
|
|
45
|
-
this.resizeObserver = null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
init(outputContainerId, scrollContainerId = null) {
|
|
49
|
-
this.outputContainer = document.getElementById(outputContainerId);
|
|
50
|
-
this.scrollContainer = scrollContainerId ? document.getElementById(scrollContainerId) : this.outputContainer;
|
|
51
|
-
|
|
52
|
-
if (!this.outputContainer) {
|
|
53
|
-
throw new Error(`Output container not found: ${outputContainerId}`);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
this.setupScrollOptimization();
|
|
57
|
-
StreamingRenderer._setupGlobalLazyHL();
|
|
58
|
-
return this;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
setupScrollOptimization() {
|
|
62
|
-
if (!this.scrollContainer) return;
|
|
63
|
-
this._userScrolledUp = false;
|
|
64
|
-
this.scrollContainer.addEventListener('scroll', () => {
|
|
65
|
-
if (this._programmaticScroll) return;
|
|
66
|
-
const sc = this.scrollContainer;
|
|
67
|
-
const distFromBottom = sc.scrollHeight - sc.scrollTop - sc.clientHeight;
|
|
68
|
-
this._userScrolledUp = distFromBottom > 80;
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
queueEvent(event) {
|
|
73
|
-
if (!event || typeof event !== 'object') return false;
|
|
74
|
-
|
|
75
|
-
if (!event.timestamp) {
|
|
76
|
-
event.timestamp = Date.now();
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (this.isDuplicate(event)) {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (this.eventQueue.length >= this.config.maxQueueSize) {
|
|
84
|
-
console.warn('Event queue overflow, dropping oldest events');
|
|
85
|
-
this.eventQueue.shift();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
this.eventQueue.push(event);
|
|
89
|
-
this.eventHistory.push(event);
|
|
90
|
-
|
|
91
|
-
if (this.eventHistory.length > this.config.maxEventHistory) {
|
|
92
|
-
this.eventHistory.shift();
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
this.emit('event:queued', { event, queueLength: this.eventQueue.length });
|
|
96
|
-
this.scheduleBatchProcess();
|
|
97
|
-
return true;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
isDuplicate(event) {
|
|
101
|
-
const key = this.getEventKey(event);
|
|
102
|
-
if (!key) return false;
|
|
103
|
-
|
|
104
|
-
const lastSeq = this.dedupMap.get(key);
|
|
105
|
-
|
|
106
|
-
if (event.type === 'streaming_progress' && event.seq !== undefined && lastSeq !== undefined) {
|
|
107
|
-
if (event.seq <= lastSeq) {
|
|
108
|
-
return true; // Same or older seq = duplicate
|
|
109
|
-
}
|
|
110
|
-
this.dedupMap.set(key, event.seq);
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const now = Date.now();
|
|
115
|
-
if (lastSeq && typeof lastSeq === 'number' && lastSeq > now - 500) {
|
|
116
|
-
return true; // Recent duplicate
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
this.dedupMap.set(key, now);
|
|
120
|
-
if (this.dedupMap.size > 5000) {
|
|
121
|
-
const cutoff = now - 5000;
|
|
122
|
-
for (const [k, v] of this.dedupMap) {
|
|
123
|
-
if (typeof v === 'number' && v < cutoff) this.dedupMap.delete(k);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return false;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
getEventKey(event) {
|
|
130
|
-
if (!event.type) return null;
|
|
131
|
-
if (event.sessionId) {
|
|
132
|
-
return `${event.sessionId}:${event.type}`;
|
|
133
|
-
}
|
|
134
|
-
return `${event.type}:${event.id || ''}`;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
scheduleBatchProcess() {
|
|
138
|
-
if (this.isProcessing || this.batchTimer) return;
|
|
139
|
-
|
|
140
|
-
if (this.eventQueue.length >= this.config.batchSize) {
|
|
141
|
-
this.processBatch();
|
|
142
|
-
} else {
|
|
143
|
-
this.batchTimer = setTimeout(() => {
|
|
144
|
-
this.batchTimer = null;
|
|
145
|
-
if (this.eventQueue.length > 0) {
|
|
146
|
-
this.processBatch();
|
|
147
|
-
}
|
|
148
|
-
}, this.config.batchInterval);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
processBatch() {
|
|
153
|
-
if (this.isProcessing) return;
|
|
154
|
-
if (this.eventQueue.length === 0) return;
|
|
155
|
-
|
|
156
|
-
this.isProcessing = true;
|
|
157
|
-
const processStart = performance.now();
|
|
158
|
-
const batchSize = Math.min(this.eventQueue.length, this.config.batchSize);
|
|
159
|
-
const batch = this.eventQueue.splice(0, batchSize);
|
|
160
|
-
|
|
161
|
-
this.emit('batch:start', { batchSize, queueLength: this.eventQueue.length });
|
|
162
|
-
|
|
163
|
-
try {
|
|
164
|
-
const renderStart = performance.now();
|
|
165
|
-
this.renderBatch(batch);
|
|
166
|
-
const renderTime = performance.now() - renderStart;
|
|
167
|
-
|
|
168
|
-
this.performanceMetrics.totalBatches++;
|
|
169
|
-
this.performanceMetrics.totalEvents += batchSize;
|
|
170
|
-
this.performanceMetrics.avgBatchSize = this.performanceMetrics.totalEvents / this.performanceMetrics.totalBatches;
|
|
171
|
-
this.performanceMetrics.avgRenderTime = (this.performanceMetrics.avgRenderTime * (this.performanceMetrics.totalBatches - 1) + renderTime) / this.performanceMetrics.totalBatches;
|
|
172
|
-
|
|
173
|
-
this.emit('batch:complete', {
|
|
174
|
-
batchSize,
|
|
175
|
-
renderTime,
|
|
176
|
-
metrics: this.performanceMetrics
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
if (this.eventQueue.length >= this.config.batchSize) {
|
|
180
|
-
this.isProcessing = false;
|
|
181
|
-
setImmediate(() => this.processBatch());
|
|
182
|
-
} else {
|
|
183
|
-
this.isProcessing = false;
|
|
184
|
-
if (this.eventQueue.length > 0) {
|
|
185
|
-
this.scheduleBatchProcess();
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
} catch (error) {
|
|
189
|
-
console.error('Batch processing error:', error);
|
|
190
|
-
this.isProcessing = false;
|
|
191
|
-
this.emit('error:render', { error, batch });
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const processTime = performance.now() - processStart;
|
|
195
|
-
this.performanceMetrics.avgProcessTime = this.performanceMetrics.avgProcessTime || processTime;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
if (typeof module !== 'undefined' && module.exports) {
|
|
199
|
-
module.exports = StreamingRenderer;
|
|
200
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
Object.assign(SyntaxHighlighter.prototype, {
|
|
2
|
-
async highlight(code, language = 'plaintext') {
|
|
3
|
-
if (!code) return '';
|
|
4
|
-
if (this.config.lazyLoad) {
|
|
5
|
-
try {
|
|
6
|
-
await this.ensureLoaded();
|
|
7
|
-
} catch (error) {
|
|
8
|
-
console.warn('Prism loading failed, returning unformatted code');
|
|
9
|
-
return this.escapeHtml(code);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
const cacheKey = `${language}:${code}`;
|
|
13
|
-
if (this.config.enableCache && this.highlightCache.has(cacheKey)) return this.highlightCache.get(cacheKey);
|
|
14
|
-
let highlighted;
|
|
15
|
-
try {
|
|
16
|
-
if (typeof Prism !== 'undefined' && Prism.languages[language]) {
|
|
17
|
-
highlighted = Prism.highlight(code, Prism.languages[language], language);
|
|
18
|
-
} else {
|
|
19
|
-
highlighted = this.escapeHtml(code);
|
|
20
|
-
}
|
|
21
|
-
} catch (error) {
|
|
22
|
-
console.error('Highlight error:', error);
|
|
23
|
-
highlighted = this.escapeHtml(code);
|
|
24
|
-
}
|
|
25
|
-
if (this.config.enableCache) {
|
|
26
|
-
this.highlightCache.set(cacheKey, highlighted);
|
|
27
|
-
if (this.highlightCache.size > this.config.maxCacheSize) {
|
|
28
|
-
const firstKey = this.highlightCache.keys().next().value;
|
|
29
|
-
this.highlightCache.delete(firstKey);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return highlighted;
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
async createHighlightedElement(code, language = 'plaintext') {
|
|
36
|
-
const pre = document.createElement('pre');
|
|
37
|
-
const code_el = document.createElement('code');
|
|
38
|
-
code_el.className = `language-${language}`;
|
|
39
|
-
if (this.config.lazyLoad) {
|
|
40
|
-
try {
|
|
41
|
-
await this.ensureLoaded();
|
|
42
|
-
const highlighted = await this.highlight(code, language);
|
|
43
|
-
code_el.innerHTML = highlighted;
|
|
44
|
-
} catch (error) {
|
|
45
|
-
code_el.textContent = code;
|
|
46
|
-
}
|
|
47
|
-
} else {
|
|
48
|
-
code_el.textContent = code;
|
|
49
|
-
}
|
|
50
|
-
pre.appendChild(code_el);
|
|
51
|
-
return pre;
|
|
52
|
-
},
|
|
53
|
-
|
|
54
|
-
async highlightElement(element) {
|
|
55
|
-
if (!element || !element.querySelector('code')) return;
|
|
56
|
-
if (this.config.lazyLoad) {
|
|
57
|
-
try {
|
|
58
|
-
await this.ensureLoaded();
|
|
59
|
-
} catch (error) {
|
|
60
|
-
console.warn('Prism loading failed, skipping highlighting');
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (typeof Prism !== 'undefined') {
|
|
65
|
-
try {
|
|
66
|
-
Prism.highlightElement(element.querySelector('code'));
|
|
67
|
-
} catch (error) {
|
|
68
|
-
console.error('Element highlighting error:', error);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
});
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
class SyntaxHighlighter {
|
|
3
|
-
constructor(config = {}) {
|
|
4
|
-
this.config = {
|
|
5
|
-
cdnUrl: config.cdnUrl || 'https://cdn.jsdelivr.net/npm/prismjs@1.29.0',
|
|
6
|
-
lazyLoad: config.lazyLoad !== false,
|
|
7
|
-
enableCache: config.enableCache !== false,
|
|
8
|
-
maxCacheSize: config.maxCacheSize || 500,
|
|
9
|
-
supportedLanguages: config.supportedLanguages || [
|
|
10
|
-
'javascript', 'typescript', 'python', 'java', 'cpp', 'c', 'csharp', 'go', 'rust',
|
|
11
|
-
'php', 'ruby', 'swift', 'kotlin', 'sql', 'html', 'css', 'scss', 'bash', 'shell',
|
|
12
|
-
'json', 'xml', 'yaml', 'markdown', 'plaintext'
|
|
13
|
-
],
|
|
14
|
-
...config
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
this.isLoaded = false;
|
|
18
|
-
this.isLoading = false;
|
|
19
|
-
this.highlightCache = new Map();
|
|
20
|
-
this.loadPromise = null;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async ensureLoaded() {
|
|
24
|
-
if (typeof Prism !== 'undefined' && this.isLoaded) {
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (this.isLoading && this.loadPromise) {
|
|
29
|
-
return this.loadPromise;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
this.isLoading = true;
|
|
33
|
-
this.loadPromise = this.loadPrism();
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
const result = await this.loadPromise;
|
|
37
|
-
this.isLoaded = true;
|
|
38
|
-
return result;
|
|
39
|
-
} catch (error) {
|
|
40
|
-
console.error('Failed to load Prism:', error);
|
|
41
|
-
this.isLoading = false;
|
|
42
|
-
this.loadPromise = null;
|
|
43
|
-
throw error;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async loadPrism() {
|
|
48
|
-
return new Promise((resolve, reject) => {
|
|
49
|
-
try {
|
|
50
|
-
const script = document.createElement('script');
|
|
51
|
-
script.src = `${this.config.cdnUrl}/prism.js`;
|
|
52
|
-
script.async = true;
|
|
53
|
-
|
|
54
|
-
script.onload = () => {
|
|
55
|
-
this.loadLanguages();
|
|
56
|
-
this.isLoading = false;
|
|
57
|
-
resolve(true);
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
script.onerror = () => {
|
|
61
|
-
this.isLoading = false;
|
|
62
|
-
reject(new Error('Failed to load Prism.js'));
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
document.head.appendChild(script);
|
|
66
|
-
} catch (error) {
|
|
67
|
-
this.isLoading = false;
|
|
68
|
-
reject(error);
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
loadLanguages() {
|
|
74
|
-
const languages = ['javascript', 'python', 'sql', 'bash', 'json'];
|
|
75
|
-
|
|
76
|
-
for (const lang of languages) {
|
|
77
|
-
const script = document.createElement('script');
|
|
78
|
-
script.src = `${this.config.cdnUrl}/components/prism-${lang}.js`;
|
|
79
|
-
script.async = true;
|
|
80
|
-
document.head.appendChild(script);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
detectLanguage(code) {
|
|
85
|
-
if (!code) return 'plaintext';
|
|
86
|
-
|
|
87
|
-
if (code.startsWith('#!/')) {
|
|
88
|
-
if (code.includes('python')) return 'python';
|
|
89
|
-
if (code.includes('node') || code.includes('node.js')) return 'javascript';
|
|
90
|
-
if (code.includes('bash') || code.includes('sh')) return 'bash';
|
|
91
|
-
if (code.includes('ruby')) return 'ruby';
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (code.includes('def ') && code.includes(':')) return 'python';
|
|
95
|
-
if (code.includes('function') || code.includes('=>')) return 'javascript';
|
|
96
|
-
if (code.includes('fn ') && code.includes('->')) return 'rust';
|
|
97
|
-
if (code.includes('public static') || code.includes('class ')) return 'java';
|
|
98
|
-
if (code.includes('SELECT') || code.includes('INSERT')) return 'sql';
|
|
99
|
-
if (code.includes('<html') || code.includes('<div')) return 'html';
|
|
100
|
-
if (code.includes('::') && code.includes('use ')) return 'rust';
|
|
101
|
-
|
|
102
|
-
return 'plaintext';
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
getSupportedLanguages() {
|
|
106
|
-
return [...this.config.supportedLanguages];
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
isSupportedLanguage(language) {
|
|
110
|
-
return this.config.supportedLanguages.includes(language);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
clearCache() {
|
|
114
|
-
this.highlightCache.clear();
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
getCacheStats() {
|
|
118
|
-
return {
|
|
119
|
-
size: this.highlightCache.size,
|
|
120
|
-
maxSize: this.config.maxCacheSize
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
escapeHtml(text) {
|
|
125
|
-
return window._escHtml(text);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (typeof module !== 'undefined' && module.exports) {
|
|
130
|
-
module.exports = SyntaxHighlighter;
|
|
131
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
(function() {
|
|
2
|
-
const { createMachine, createActor, assign } = XState;
|
|
3
|
-
|
|
4
|
-
const terminalMachine = createMachine({
|
|
5
|
-
id: 'terminal',
|
|
6
|
-
initial: 'inactive',
|
|
7
|
-
context: {
|
|
8
|
-
cwd: null,
|
|
9
|
-
},
|
|
10
|
-
states: {
|
|
11
|
-
inactive: {
|
|
12
|
-
on: {
|
|
13
|
-
START: { target: 'initializing' },
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
initializing: {
|
|
17
|
-
on: {
|
|
18
|
-
READY: { target: 'active' },
|
|
19
|
-
ERROR: { target: 'inactive' },
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
active: {
|
|
23
|
-
on: {
|
|
24
|
-
STOP: { target: 'inactive' },
|
|
25
|
-
SESSION_EXIT: { target: 'restarting' },
|
|
26
|
-
SET_CWD: {
|
|
27
|
-
actions: assign(({ event }) => ({ cwd: event.cwd })),
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
restarting: {
|
|
32
|
-
on: {
|
|
33
|
-
READY: { target: 'active' },
|
|
34
|
-
ERROR: { target: 'inactive' },
|
|
35
|
-
STOP: { target: 'inactive' },
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
const actor = createActor(terminalMachine);
|
|
42
|
-
actor.start();
|
|
43
|
-
|
|
44
|
-
window.terminalMachineAPI = {
|
|
45
|
-
send: function(event) { actor.send(event); },
|
|
46
|
-
getState: function() { return actor.getSnapshot().value; },
|
|
47
|
-
isActive: function() { var s = actor.getSnapshot().value; return s === 'active' || s === 'restarting'; },
|
|
48
|
-
subscribe: function(fn) { return actor.subscribe(fn); },
|
|
49
|
-
};
|
|
50
|
-
window.__terminalMachine = actor;
|
|
51
|
-
})();
|
package/static/js/terminal.js
DELETED
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
(function() {
|
|
2
|
-
var term = null;
|
|
3
|
-
var fitAddon = null;
|
|
4
|
-
var termActive = false;
|
|
5
|
-
var BASE = window.__BASE_URL || '';
|
|
6
|
-
var _wsListener = null;
|
|
7
|
-
|
|
8
|
-
function getCwd() {
|
|
9
|
-
try {
|
|
10
|
-
if (window.conversationManager && window.conversationManager.activeId) {
|
|
11
|
-
var mgr = window.conversationManager;
|
|
12
|
-
var conv = mgr.conversations && mgr.conversations.find(function(c) { return c.id === mgr.activeId; });
|
|
13
|
-
if (conv && conv.workingDirectory) return conv.workingDirectory;
|
|
14
|
-
}
|
|
15
|
-
if (window.currentConversation && window.conversationManager && window.conversationManager.conversations) {
|
|
16
|
-
var match = window.conversationManager.conversations.find(function(c) { return c.id === window.currentConversation; });
|
|
17
|
-
if (match && match.workingDirectory) return match.workingDirectory;
|
|
18
|
-
}
|
|
19
|
-
} catch (_) {}
|
|
20
|
-
return undefined;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function wsSend(obj) {
|
|
24
|
-
if (window.wsManager && window.wsManager.sendMessage) {
|
|
25
|
-
window.wsManager.sendMessage(obj);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function ensureTerm() {
|
|
30
|
-
var output = document.getElementById('terminalOutput');
|
|
31
|
-
if (!output) return false;
|
|
32
|
-
if (term) return true;
|
|
33
|
-
if (!window.Terminal || !window.FitAddon) return false;
|
|
34
|
-
|
|
35
|
-
term = new Terminal({
|
|
36
|
-
cursorBlink: true,
|
|
37
|
-
fontSize: 14,
|
|
38
|
-
fontFamily: 'Menlo, Monaco, "Courier New", monospace',
|
|
39
|
-
theme: {
|
|
40
|
-
background: '#0d1117',
|
|
41
|
-
foreground: '#e6edf3',
|
|
42
|
-
cursor: '#e6edf3',
|
|
43
|
-
selectionBackground: '#3b4455'
|
|
44
|
-
},
|
|
45
|
-
convertEol: true,
|
|
46
|
-
scrollback: 5000
|
|
47
|
-
});
|
|
48
|
-
fitAddon = new FitAddon.FitAddon();
|
|
49
|
-
term.loadAddon(fitAddon);
|
|
50
|
-
output.innerHTML = '';
|
|
51
|
-
term.open(output);
|
|
52
|
-
fitAddon.fit();
|
|
53
|
-
|
|
54
|
-
term.onData(function(data) {
|
|
55
|
-
var encoded = btoa(unescape(encodeURIComponent(data)));
|
|
56
|
-
wsSend({ type: 'terminal_input', data: encoded });
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
term.onResize(function(size) {
|
|
60
|
-
wsSend({ type: 'terminal_resize', cols: size.cols, rows: size.rows });
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
var resizeTimer;
|
|
64
|
-
window.addEventListener('resize', function() {
|
|
65
|
-
if (fitAddon) {
|
|
66
|
-
try { fitAddon.fit(); } catch(_) {}
|
|
67
|
-
clearTimeout(resizeTimer);
|
|
68
|
-
resizeTimer = setTimeout(function() {
|
|
69
|
-
if (term) wsSend({ type: 'terminal_resize', cols: term.cols, rows: term.rows });
|
|
70
|
-
}, 200);
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
document.getElementById('terminalOutput').addEventListener('click', function() {
|
|
75
|
-
if (term && term.focus) term.focus();
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
return true;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function installWsListener() {
|
|
82
|
-
if (_wsListener || !window.wsManager) return;
|
|
83
|
-
_wsListener = function(msg) {
|
|
84
|
-
if (!termActive) return;
|
|
85
|
-
if (msg.type === 'terminal_output' && term) {
|
|
86
|
-
var raw = msg.encoding === 'base64'
|
|
87
|
-
? decodeURIComponent(escape(atob(msg.data)))
|
|
88
|
-
: msg.data;
|
|
89
|
-
term.write(raw);
|
|
90
|
-
} else if (msg.type === 'terminal_exit' && term) {
|
|
91
|
-
term.write('\r\n[Process exited with code ' + msg.code + ']\r\n');
|
|
92
|
-
if (termActive) setTimeout(startSession, 2000);
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
window.wsManager.on('message', _wsListener);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function startSession() {
|
|
99
|
-
if (!window.wsManager) return;
|
|
100
|
-
installWsListener();
|
|
101
|
-
var cwd = getCwd();
|
|
102
|
-
var dims = term ? { cols: term.cols, rows: term.rows } : { cols: 80, rows: 24 };
|
|
103
|
-
wsSend({ type: 'terminal_start', cwd: cwd, cols: dims.cols, rows: dims.rows });
|
|
104
|
-
if (tmApi()) tmApi().send({ type: 'READY' });
|
|
105
|
-
setTimeout(function() { if (term && term.focus) term.focus(); }, 100);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function tmApi() { return window.terminalMachineAPI; }
|
|
109
|
-
|
|
110
|
-
function startTerminal() {
|
|
111
|
-
if (tmApi()) tmApi().send({ type: 'START' });
|
|
112
|
-
if (!ensureTerm()) {
|
|
113
|
-
setTimeout(startTerminal, 200);
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
termActive = true;
|
|
117
|
-
if (window.wsManager && window.wsManager.isConnected) {
|
|
118
|
-
startSession();
|
|
119
|
-
} else if (window.wsManager) {
|
|
120
|
-
var onConnected = function() {
|
|
121
|
-
window.wsManager.off('connected', onConnected);
|
|
122
|
-
startSession();
|
|
123
|
-
};
|
|
124
|
-
window.wsManager.on('connected', onConnected);
|
|
125
|
-
}
|
|
126
|
-
setTimeout(function() { if (fitAddon) try { fitAddon.fit(); } catch(_) {} }, 100);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function stopTerminal() {
|
|
130
|
-
termActive = false;
|
|
131
|
-
if (tmApi()) tmApi().send({ type: 'STOP' });
|
|
132
|
-
if (_wsListener && window.wsManager) { window.wsManager.off('message', _wsListener); _wsListener = null; }
|
|
133
|
-
wsSend({ type: 'terminal_stop' });
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function initTerminalEarly() {
|
|
137
|
-
if (!ensureTerm()) {
|
|
138
|
-
setTimeout(initTerminalEarly, 200);
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (document.readyState === 'loading') {
|
|
144
|
-
document.addEventListener('DOMContentLoaded', initTerminalEarly);
|
|
145
|
-
} else {
|
|
146
|
-
initTerminalEarly();
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
window.addEventListener('view-switched', function(e) {
|
|
150
|
-
if (e.detail.view === 'terminal') {
|
|
151
|
-
if (!ensureTerm()) {
|
|
152
|
-
setTimeout(function() { window.dispatchEvent(new CustomEvent('view-switched', { detail: { view: 'terminal' } })); }, 200);
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
termActive = true;
|
|
156
|
-
startSession();
|
|
157
|
-
setTimeout(function() { if (fitAddon) try { fitAddon.fit(); } catch(_) {} }, 50);
|
|
158
|
-
setTimeout(function() { if (fitAddon) try { fitAddon.fit(); } catch(_) {} }, 300);
|
|
159
|
-
} else if (termActive) {
|
|
160
|
-
stopTerminal();
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
window.addEventListener('conversation-changed', function() {
|
|
165
|
-
if (!termActive) return;
|
|
166
|
-
var cwd = getCwd();
|
|
167
|
-
var dims = term ? { cols: term.cols, rows: term.rows } : { cols: 80, rows: 24 };
|
|
168
|
-
wsSend({ type: 'terminal_start', cwd: cwd, cols: dims.cols, rows: dims.rows });
|
|
169
|
-
if (term) term.write('\r\n\x1b[33m[Switched to: ' + (cwd || '/') + ']\x1b[0m\r\n');
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
window.terminalModule = {
|
|
173
|
-
start: startTerminal,
|
|
174
|
-
stop: stopTerminal,
|
|
175
|
-
getTerminal: function() { return term; },
|
|
176
|
-
isActive: function() { return termActive; }
|
|
177
|
-
};
|
|
178
|
-
})();
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
Object.assign(UIComponents, {
|
|
2
|
-
escapeHtml(text) { return window._escHtml ? window._escHtml(String(text)) : String(text).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); },
|
|
3
|
-
|
|
4
|
-
copyToClipboard(text) {
|
|
5
|
-
return navigator.clipboard.writeText(text).catch(() => false);
|
|
6
|
-
},
|
|
7
|
-
|
|
8
|
-
downloadFile(data, filename, mimeType = 'text/plain') {
|
|
9
|
-
const blob = new Blob([data], { type: mimeType });
|
|
10
|
-
const url = URL.createObjectURL(blob);
|
|
11
|
-
const link = document.createElement('a');
|
|
12
|
-
link.href = url; link.download = filename;
|
|
13
|
-
document.body.appendChild(link); link.click(); document.body.removeChild(link);
|
|
14
|
-
URL.revokeObjectURL(url);
|
|
15
|
-
},
|
|
16
|
-
|
|
17
|
-
createInput(config = {}) {
|
|
18
|
-
const { type = 'text', name = '', label = '', placeholder = '', value = '', required = false } = config;
|
|
19
|
-
const container = document.createElement('div');
|
|
20
|
-
container.className = 'form-group mb-4';
|
|
21
|
-
let html = '';
|
|
22
|
-
if (label) html += `<label class="block text-sm font-medium mb-2">${UIComponents.escapeHtml(label)}</label>`;
|
|
23
|
-
html += `<input type="${type}" name="${name}" placeholder="${UIComponents.escapeHtml(placeholder)}" value="${UIComponents.escapeHtml(value)}" ${required ? 'required' : ''} class="input input-block input-solid" />`;
|
|
24
|
-
container.innerHTML = html;
|
|
25
|
-
return container;
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
createSelect(config = {}) {
|
|
29
|
-
const { name = '', label = '', options = [], value = '', required = false } = config;
|
|
30
|
-
const container = document.createElement('div');
|
|
31
|
-
container.className = 'form-group mb-4';
|
|
32
|
-
let html = '';
|
|
33
|
-
if (label) html += `<label class="block text-sm font-medium mb-2">${UIComponents.escapeHtml(label)}</label>`;
|
|
34
|
-
html += `<select name="${name}" ${required ? 'required' : ''} class="select select-block select-solid">${options.map(opt => `<option value="${opt.value}" ${opt.value === value ? 'selected' : ''}>${UIComponents.escapeHtml(opt.label)}</option>`).join('')}</select>`;
|
|
35
|
-
container.innerHTML = html;
|
|
36
|
-
return container;
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
createButtonGroup(config = {}) {
|
|
40
|
-
const { buttons = [], vertical = false } = config;
|
|
41
|
-
const container = document.createElement('div');
|
|
42
|
-
container.className = `button-group flex gap-2 ${vertical ? 'flex-col' : 'flex-row'}`;
|
|
43
|
-
buttons.forEach(btn => {
|
|
44
|
-
const button = document.createElement('button');
|
|
45
|
-
button.className = `btn btn-${btn.variant || 'secondary'} flex-${vertical ? '1' : 'none'}`;
|
|
46
|
-
button.textContent = btn.label;
|
|
47
|
-
if (btn.onClick) button.addEventListener('click', btn.onClick);
|
|
48
|
-
container.appendChild(button);
|
|
49
|
-
});
|
|
50
|
-
return container;
|
|
51
|
-
},
|
|
52
|
-
|
|
53
|
-
createBadge(config = {}) {
|
|
54
|
-
const { label = '', variant = 'default', size = 'medium' } = config;
|
|
55
|
-
const sizeClasses = { small: 'badge-sm', medium: 'badge-md', large: 'badge-lg' };
|
|
56
|
-
const variantClasses = { default: 'badge-flat', primary: 'badge-flat-primary', success: 'badge-flat-success', warning: 'badge-flat-warning', error: 'badge-flat-error' };
|
|
57
|
-
const badge = document.createElement('span');
|
|
58
|
-
badge.className = `badge ${sizeClasses[size] || sizeClasses.medium} ${variantClasses[variant] || variantClasses.default}`;
|
|
59
|
-
badge.textContent = label;
|
|
60
|
-
return badge;
|
|
61
|
-
}
|
|
62
|
-
});
|