agentgui 1.0.931 → 1.0.933

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 (129) hide show
  1. package/AGENTS.md +17 -12
  2. package/database.js +31 -2
  3. package/lib/http-handler.js +11 -25
  4. package/lib/routes-registry.js +4 -48
  5. package/lib/server-startup.js +3 -11
  6. package/lib/ws-setup.js +2 -1
  7. package/package.json +3 -3
  8. package/server.js +7 -1
  9. package/site/app/index.html +2 -2
  10. package/site/app/js/app.js +91 -86
  11. package/site/app/js/backend.js +1 -1
  12. package/static/lib/xstate.umd.min.js +1 -1
  13. package/lib/db-queries-chunks.js +0 -195
  14. package/lib/db-queries-chunks2.js +0 -82
  15. package/lib/db-queries-cleanup.js +0 -74
  16. package/lib/db-queries-del.js +0 -141
  17. package/lib/db-queries-events.js +0 -68
  18. package/lib/db-queries-import.js +0 -133
  19. package/lib/db-queries-messages.js +0 -102
  20. package/lib/db-queries-sessions.js +0 -112
  21. package/lib/db-queries-streams.js +0 -100
  22. package/lib/db-queries.js +0 -89
  23. package/lib/jsonl-parser.js +0 -190
  24. package/lib/jsonl-watcher.js +0 -64
  25. package/lib/routes-agent-actions.js +0 -61
  26. package/lib/routes-auth-config.js +0 -30
  27. package/lib/routes-conversations.js +0 -96
  28. package/lib/routes-debug.js +0 -119
  29. package/lib/routes-messages.js +0 -139
  30. package/lib/routes-runs.js +0 -156
  31. package/lib/routes-scripts.js +0 -135
  32. package/lib/routes-sessions.js +0 -144
  33. package/lib/routes-threads.js +0 -100
  34. package/lib/routes-util.js +0 -110
  35. package/lib/ws-handlers-conv.js +0 -138
  36. package/lib/ws-handlers-conv2.js +0 -169
  37. package/lib/ws-handlers-msg.js +0 -121
  38. package/lib/ws-handlers-queue.js +0 -56
  39. package/lib/ws-handlers-run.js +0 -182
  40. package/lib/ws-handlers-scripts.js +0 -66
  41. package/lib/ws-handlers-session.js +0 -105
  42. package/lib/ws-handlers-session2.js +0 -85
  43. package/lib/ws-legacy-handlers.js +0 -51
  44. package/static/app.js +0 -261
  45. package/static/css/app-shell.css +0 -419
  46. package/static/css/brand-bible.css +0 -591
  47. package/static/css/colors_and_type.css +0 -568
  48. package/static/css/gmail-skin.css +0 -663
  49. package/static/css/main.css +0 -4015
  50. package/static/css/tools-popup.css +0 -472
  51. package/static/index.html +0 -418
  52. package/static/js/agent-auth.js +0 -146
  53. package/static/js/app-shortcuts.js +0 -30
  54. package/static/js/audio-recorder-processor.js +0 -18
  55. package/static/js/client-agents.js +0 -155
  56. package/static/js/client-cache.js +0 -171
  57. package/static/js/client-conv.js +0 -198
  58. package/static/js/client-events.js +0 -164
  59. package/static/js/client-exec.js +0 -160
  60. package/static/js/client-helpers.js +0 -199
  61. package/static/js/client-load.js +0 -175
  62. package/static/js/client-render.js +0 -132
  63. package/static/js/client-scroll.js +0 -178
  64. package/static/js/client-status.js +0 -167
  65. package/static/js/client-streaming.js +0 -117
  66. package/static/js/client-streaming2.js +0 -116
  67. package/static/js/client-streaming3.js +0 -153
  68. package/static/js/client-streaming4.js +0 -194
  69. package/static/js/client-ui-controls.js +0 -170
  70. package/static/js/client-ui.js +0 -128
  71. package/static/js/client-ui2.js +0 -160
  72. package/static/js/client-url.js +0 -93
  73. package/static/js/client-utils.js +0 -174
  74. package/static/js/client-ws-msg.js +0 -88
  75. package/static/js/client-ws.js +0 -161
  76. package/static/js/client.js +0 -145
  77. package/static/js/codec.js +0 -4
  78. package/static/js/conv-list-machine.js +0 -145
  79. package/static/js/conv-list-renderer.js +0 -198
  80. package/static/js/conv-machine.js +0 -110
  81. package/static/js/conv-sidebar-actions.js +0 -188
  82. package/static/js/conv-sidebar-clone.js +0 -91
  83. package/static/js/conversations.js +0 -116
  84. package/static/js/dialogs-types.js +0 -111
  85. package/static/js/dialogs.js +0 -53
  86. package/static/js/event-filter-config.js +0 -36
  87. package/static/js/event-processor.js +0 -181
  88. package/static/js/features.js +0 -187
  89. package/static/js/image-loader-element.js +0 -76
  90. package/static/js/image-loader.js +0 -146
  91. package/static/js/prompt-machine.js +0 -108
  92. package/static/js/recording-machine.js +0 -49
  93. package/static/js/script-runner.js +0 -192
  94. package/static/js/state-barrier.js +0 -105
  95. package/static/js/streaming-renderer-dispatch.js +0 -144
  96. package/static/js/streaming-renderer-events.js +0 -163
  97. package/static/js/streaming-renderer-events2.js +0 -125
  98. package/static/js/streaming-renderer-params.js +0 -38
  99. package/static/js/streaming-renderer-render-misc.js +0 -107
  100. package/static/js/streaming-renderer-render.js +0 -181
  101. package/static/js/streaming-renderer-render2.js +0 -149
  102. package/static/js/streaming-renderer-render3.js +0 -142
  103. package/static/js/streaming-renderer-static.js +0 -181
  104. package/static/js/streaming-renderer-static2.js +0 -140
  105. package/static/js/streaming-renderer-stream.js +0 -170
  106. package/static/js/streaming-renderer-text.js +0 -185
  107. package/static/js/streaming-renderer-tools.js +0 -189
  108. package/static/js/streaming-renderer-tools2.js +0 -92
  109. package/static/js/streaming-renderer.js +0 -200
  110. package/static/js/syntax-highlighter-render.js +0 -72
  111. package/static/js/syntax-highlighter.js +0 -131
  112. package/static/js/terminal-machine.js +0 -51
  113. package/static/js/terminal.js +0 -178
  114. package/static/js/ui-components-rendering.js +0 -62
  115. package/static/js/ui-components.js +0 -88
  116. package/static/js/websocket-manager.js +0 -107
  117. package/static/js/ws-client.js +0 -87
  118. package/static/js/ws-core.js +0 -162
  119. package/static/js/ws-latency.js +0 -88
  120. package/static/js/ws-machine.js +0 -68
  121. package/static/lib/msgpackr.min.js +0 -2
  122. package/static/theme.js +0 -74
  123. package/static/vendor/highlight-js.css +0 -10
  124. package/static/vendor/highlight.min.js +0 -1244
  125. package/static/vendor/prism-dark.css +0 -129
  126. package/static/vendor/rippleui.css +0 -35
  127. package/static/vendor/xterm-addon-fit.min.js +0 -8
  128. package/static/vendor/xterm.css +0 -8
  129. package/static/vendor/xterm.min.js +0 -8
@@ -1,142 +0,0 @@
1
- Object.assign(StreamingRenderer.prototype, {
2
- autoScroll() {
3
- if (this._scrollRafPending || this._userScrolledUp) return;
4
- this._scrollRafPending = true;
5
- requestAnimationFrame(() => {
6
- this._scrollRafPending = false;
7
- if (this.scrollContainer) {
8
- this._programmaticScroll = true;
9
- try { this.scrollContainer.scrollTop = this.scrollContainer.scrollHeight; } catch (_) {}
10
- this._programmaticScroll = false;
11
- }
12
- });
13
- },
14
-
15
- resetScrollState() {
16
- this._userScrolledUp = false;
17
- },
18
-
19
- updateDOMNodeCount() {
20
- this.domNodeCount = this.outputContainer?.querySelectorAll('[data-event-id]').length || 0;
21
- },
22
-
23
- escapeHtml(text) {
24
- return window._escHtml(text);
25
- },
26
-
27
- formatFileSize(bytes) {
28
- if (bytes === 0) return '0 B';
29
- const k = 1024;
30
- const sizes = ['B', 'KB', 'MB', 'GB'];
31
- const i = Math.floor(Math.log(bytes) / Math.log(k));
32
- return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
33
- },
34
-
35
- truncateContent(content, maxLength = 200) {
36
- if (content.length <= maxLength) return content;
37
- return content.substring(0, maxLength) + '...';
38
- },
39
-
40
- clear() {
41
- if (this.outputContainer) {
42
- this.outputContainer.innerHTML = '';
43
- }
44
- this.eventQueue = [];
45
- this.eventHistory = [];
46
- this.domNodeCount = 0;
47
- this.dedupMap.clear();
48
- },
49
-
50
- getMetrics() {
51
- return {
52
- ...this.performanceMetrics,
53
- domNodeCount: this.domNodeCount,
54
- queueLength: this.eventQueue.length,
55
- historyLength: this.eventHistory.length,
56
- lastRenderTime: this.lastRenderTime
57
- };
58
- },
59
-
60
- on(event, callback) {
61
- if (!this.listeners[event]) {
62
- this.listeners[event] = [];
63
- }
64
- this.listeners[event].push(callback);
65
- },
66
-
67
- emit(event, data) {
68
- if (this.listeners[event]) {
69
- this.listeners[event].forEach(callback => {
70
- try {
71
- callback(data);
72
- } catch (e) {
73
- console.error('Listener error:', e);
74
- }
75
- });
76
- }
77
- },
78
-
79
- renderBlockHeader(block, context = {}) {
80
- if (!block || !block.type) return null;
81
-
82
- const typeLabel = block.type.charAt(0).toUpperCase() + block.type.slice(1).replace(/_/g, ' ');
83
- const summary = document.createElement('summary');
84
- summary.style.cursor = 'pointer';
85
- summary.style.userSelect = 'none';
86
- summary.className = 'block-header-summary';
87
-
88
- let summaryText = typeLabel;
89
- if (block.type === 'code' && block.language) {
90
- summaryText += ` (${block.language})`;
91
- } else if (block.type === 'bash' && block.source) {
92
- summaryText += ` - ${block.source}`;
93
- } else if (block.type === 'tool_use' && block.name) {
94
- summaryText += ` - ${block.name}`;
95
- } else if (block.type === 'text' && block.text) {
96
- const preview = block.text.substring(0, 60).replace(/\n/g, ' ');
97
- summaryText = preview + (block.text.length > 60 ? '...' : '');
98
- }
99
-
100
- summary.textContent = summaryText;
101
-
102
- const details = document.createElement('details');
103
- details.className = `block-${block.type}`;
104
- details.classList.add(this._getBlockTypeClass(block.type));
105
- details.setAttribute('data-block-type', block.type);
106
- details.setAttribute('data-lazy-load', 'pending');
107
- details.open = block.type === 'success' || (block.type === 'tool_result' && !block.is_error);
108
- details.appendChild(summary);
109
-
110
- details.addEventListener('toggle', async (e) => {
111
- if (details.open && details.getAttribute('data-lazy-load') === 'pending') {
112
- details.setAttribute('data-lazy-load', 'loading');
113
- try {
114
- const body = this.renderBlock(block, context);
115
- if (body && body !== summary) {
116
- details.appendChild(body);
117
- }
118
- details.setAttribute('data-lazy-load', 'loaded');
119
- } catch (err) {
120
- console.error('Failed to lazy-load block:', err);
121
- details.setAttribute('data-lazy-load', 'failed');
122
- }
123
- }
124
- }, { once: false });
125
-
126
- return details;
127
- },
128
-
129
- destroy() {
130
- if (this.observer) {
131
- this.observer.disconnect();
132
- }
133
- if (this.resizeObserver) {
134
- this.resizeObserver.disconnect();
135
- }
136
- if (this.batchTimer) {
137
- clearTimeout(this.batchTimer);
138
- }
139
- this.listeners = {};
140
- this.clear();
141
- }
142
- });
@@ -1,181 +0,0 @@
1
- Object.assign(StreamingRenderer, {
2
- renderSmartContentHTML(contentStr, escapeHtml, flat = false) {
3
- const trimmed = contentStr.trim();
4
- const esc = escapeHtml || window._escHtml;
5
-
6
- if (trimmed.startsWith('data:image/')) {
7
- return `<div style="padding:0.5rem"><img src="${esc(trimmed)}" style="max-width:100%;max-height:24rem;border-radius:0.375rem" loading="lazy"></div>`;
8
- }
9
-
10
- if ((trimmed.startsWith('{') && trimmed.endsWith('}')) || (trimmed.startsWith('[') && trimmed.endsWith(']'))) {
11
- try {
12
- const parsed = JSON.parse(trimmed);
13
-
14
- if (Array.isArray(parsed) && parsed.length > 0 && parsed[0] && parsed[0].type === 'text') {
15
- const textParts = parsed.filter(b => b.type === 'text' && b.text);
16
- if (textParts.length > 0) {
17
- const combined = textParts.map(b => b.text).join('\n');
18
- return StreamingRenderer.renderSmartContentHTML(combined, esc, flat);
19
- }
20
- }
21
-
22
- if (Array.isArray(parsed) && parsed.length > 0) {
23
- const imgParts = parsed.filter(b => b.type === 'image' && b.source && b.source.type === 'base64' && b.source.data);
24
- if (imgParts.length > 0) {
25
- return imgParts.map(b => {
26
- const mime = b.source.media_type || 'image/png';
27
- return `<div style="padding:0.5rem"><img src="data:${esc(mime)};base64,${b.source.data}" style="max-width:100%;max-height:24rem;border-radius:0.375rem"></div>`;
28
- }).join('');
29
- }
30
- }
31
-
32
- return `<div style="padding:0.5rem 0.75rem">${StreamingRenderer.renderParamsHTML(parsed, 0, esc)}</div>`;
33
- } catch (e) {
34
- }
35
- }
36
-
37
- const lines = trimmed.split('\n');
38
- const isCatNOutput = lines.length > 1 && lines[0].match(/^\s*\d+→/);
39
- const isGrepOutput = lines.length > 1 && lines[0].match(/^\s*\d+-/);
40
-
41
- if (isCatNOutput || isGrepOutput) {
42
- const cleanedLines = lines.map(line => {
43
- if (line === '--') return null;
44
-
45
- const match = line.match(/^\s*\d+[→\-:](.*)/);
46
- return match ? match[1] : line;
47
- }).filter(line => line !== null);
48
- const cleanedContent = cleanedLines.join('\n');
49
-
50
- return StreamingRenderer.renderCodeWithHighlight(cleanedContent, esc, flat);
51
- }
52
-
53
- const systemReminderPattern = /<system-reminder>([\s\S]*?)<\/system-reminder>/g;
54
- const systemReminders = [];
55
- let contentWithoutReminders = trimmed;
56
-
57
- let reminderMatch;
58
- while ((reminderMatch = systemReminderPattern.exec(trimmed)) !== null) {
59
- systemReminders.push(reminderMatch[1].trim());
60
- contentWithoutReminders = contentWithoutReminders.replace(reminderMatch[0], '');
61
- }
62
-
63
- contentWithoutReminders = contentWithoutReminders.trim();
64
-
65
- const successPatterns = [
66
- /^Success\s+toolu_[\w]+$/m,
67
- /^The file .* has been (updated|created|modified)/,
68
- /^Here's the result of running `cat -n`/,
69
- /^Applied \d+ edits? to/,
70
- /^\w+ tool completed successfully/
71
- ];
72
-
73
- const hasSuccessPattern = successPatterns.some(pattern => pattern.test(contentWithoutReminders));
74
-
75
- if (hasSuccessPattern) {
76
- const contentLines = contentWithoutReminders.split('\n');
77
- let successEndIndex = -1;
78
- let codeStartIndex = -1;
79
-
80
- for (let i = 0; i < contentLines.length; i++) {
81
- const line = contentLines[i];
82
- if (line.match(/^Success\s+toolu_/)) {
83
- successEndIndex = i;
84
- for (let j = i + 1; j < contentLines.length; j++) {
85
- if (contentLines[j].trim() && !contentLines[j].match(/^The file|^Here's the result/)) {
86
- codeStartIndex = j;
87
- break;
88
- }
89
- }
90
- break;
91
- } else if (line.match(/^The file .* has been|^Applied \d+ edits? to|^Replaced|^Created|^Deleted/)) {
92
- for (let j = i + 1; j < contentLines.length; j++) {
93
- if (contentLines[j].match(/^Here's the result|^\s*\d+→/)) {
94
- if (contentLines[j].match(/^Here's the result/)) {
95
- codeStartIndex = j + 1;
96
- } else {
97
- codeStartIndex = j;
98
- }
99
- break;
100
- } else if (contentLines[j].trim() && !contentLines[j].match(/^cat -n|^Running/)) {
101
- codeStartIndex = j;
102
- break;
103
- }
104
- }
105
- if (codeStartIndex === -1) {
106
- codeStartIndex = i + 2;
107
- }
108
- successEndIndex = codeStartIndex - 1;
109
- break;
110
- }
111
- }
112
-
113
- if (codeStartIndex > 0 && codeStartIndex < contentLines.length) {
114
- const beforeCode = contentLines.slice(0, codeStartIndex).join('\n');
115
- let codeContent = contentLines.slice(codeStartIndex).join('\n');
116
-
117
- if (codeContent.match(/^\s*\d+→/m)) {
118
- const codeLines = codeContent.split('\n');
119
- codeContent = codeLines.map(line => {
120
- const match = line.match(/^\s*\d+→(.*)/);
121
- return match ? match[1] : line;
122
- }).join('\n');
123
- }
124
-
125
- let html = '';
126
-
127
- if (beforeCode.trim()) {
128
- html += `<div style="color:var(--color-success);font-weight:600;margin-bottom:0.75rem;font-size:0.9rem">${esc(beforeCode.trim())}</div>`;
129
- }
130
-
131
- if (codeContent.trim()) {
132
- html += StreamingRenderer.renderCodeWithHighlight(codeContent, esc, flat);
133
- }
134
-
135
- if (systemReminders.length > 0) {
136
- html += StreamingRenderer.renderSystemReminders(systemReminders, esc);
137
- }
138
-
139
- return html;
140
- }
141
- }
142
-
143
- if (systemReminders.length > 0) {
144
- let html = '';
145
-
146
- if (contentWithoutReminders) {
147
- if (StreamingRenderer.detectCodeContent(contentWithoutReminders)) {
148
- html += StreamingRenderer.renderCodeWithHighlight(contentWithoutReminders, esc, flat);
149
- } else {
150
- html += `<pre class="tool-result-pre">${esc(contentWithoutReminders)}</pre>`;
151
- }
152
- }
153
-
154
- html += StreamingRenderer.renderSystemReminders(systemReminders, esc);
155
- return html;
156
- }
157
-
158
- const allFilePaths = lines.length > 1 && lines.every(l => {
159
- const t = l.trim();
160
- return t === '' || t.startsWith('/') || /^[A-Za-z]:[\\\/]/.test(t);
161
- });
162
- if (allFilePaths && lines.filter(l => l.trim()).length > 0) {
163
- const fileHtml = lines.filter(l => l.trim()).map(l => {
164
- const p = l.trim();
165
- const parts = pathSplit(p);
166
- const name = parts.pop();
167
- const dir = parts.join('/');
168
- return `<div style="display:flex;align-items:center;gap:0.375rem;padding:0.1875rem 0;font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.75rem"><span style="opacity:0.5">&#128196;</span><span style="color:var(--color-text-secondary)">${esc(dir)}/</span><span style="font-weight:600">${esc(name)}</span></div>`;
169
- }).join('');
170
- return `<div style="padding:0.625rem 1rem">${fileHtml}</div>`;
171
- }
172
-
173
- const looksLikeCode = StreamingRenderer.detectCodeContent(trimmed);
174
- if (looksLikeCode) {
175
- return StreamingRenderer.renderCodeWithHighlight(trimmed, esc, flat);
176
- }
177
-
178
- const displayContent = trimmed.length > 2000 ? trimmed.substring(0, 2000) + '\n... (truncated)' : trimmed;
179
- return `<pre class="tool-result-pre">${esc(displayContent)}</pre>`;
180
- }
181
- });
@@ -1,140 +0,0 @@
1
- Object.assign(StreamingRenderer, {
2
- renderSystemReminders(reminders, esc) {
3
- if (!reminders || reminders.length === 0) return '';
4
-
5
- const reminderHtml = reminders.map(reminder => {
6
- const lines = reminder.split('\n').filter(l => l.trim());
7
- const formattedLines = lines.map(line => {
8
- if (line.includes('IMPORTANT:') || line.includes('WARNING:')) {
9
- return `<div style="font-weight:600;color:var(--color-warning);margin:0.25rem 0">${esc(line)}</div>`;
10
- }
11
- return `<div style="margin:0.125rem 0">${esc(line)}</div>`;
12
- }).join('');
13
-
14
- return formattedLines;
15
- }).join('');
16
-
17
- return `
18
- <div style="margin-top:1rem;padding:0.75rem;background:var(--color-bg-secondary);border-left:3px solid var(--color-info);border-radius:0.25rem;font-size:0.8rem;color:var(--color-text-secondary)">
19
- <div style="display:flex;align-items:center;gap:0.5rem;margin-bottom:0.5rem">
20
- <span style="color:var(--color-info)">ℹ</span>
21
- <span style="font-weight:600;font-size:0.85rem;color:var(--color-text-primary)">System Reminder</span>
22
- </div>
23
- ${reminderHtml}
24
- </div>
25
- `;
26
- },
27
-
28
- detectCodeContent(content) {
29
- const codePatterns = [
30
- /^\s*(function|const|let|var|class|import|export|async|await)/m, // JavaScript
31
- /^\s*(def|class|import|from|if __name__|lambda|async def)/m, // Python
32
- /^\s*(public|private|protected|class|interface|package|import)/m, // Java/TypeScript
33
- /^\s*(<\?php|namespace|use|trait)/m, // PHP
34
- /^\s*(#include|int main|void|struct|typedef)/m, // C/C++
35
- /[{}\[\];()]/, // Brackets and semicolons
36
- /=>|->|::/, // Arrow functions, pointers
37
- ];
38
-
39
- return codePatterns.some(pattern => pattern.test(content));
40
- },
41
-
42
- renderCodeWithHighlight(code, esc, flat = false) {
43
- const preStyle = "background:var(--color-bg-code);padding:1rem;border-radius:0.375rem;overflow-x:auto;font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.875rem;line-height:1.6;color:var(--color-code-text);border:1px solid var(--color-code-border);margin:0";
44
- const codeHtml = `<pre style="${preStyle}"><code class="lazy-hl">${esc(code)}</code></pre>`;
45
- if (flat) return codeHtml;
46
- const lineCount = code.split('\n').length;
47
- const summaryLabel = `code - ${lineCount} line${lineCount !== 1 ? 's' : ''}`;
48
- return `<details class="collapsible-code"><summary class="collapsible-code-summary">${summaryLabel}</summary>${codeHtml}</details>`;
49
- },
50
-
51
- _setupGlobalLazyHL() {
52
- if (StreamingRenderer._lazyHLSetup) return;
53
- StreamingRenderer._lazyHLSetup = true;
54
- const root = document.getElementById('output-scroll') || document.body;
55
- root.addEventListener('toggle', (e) => {
56
- const details = e.target;
57
- if (!details.open || details.tagName !== 'DETAILS') return;
58
- const codeEls = details.querySelectorAll('code.lazy-hl');
59
- if (codeEls.length === 0) return;
60
- if (typeof hljs === 'undefined') return;
61
- for (const el of codeEls) {
62
- try {
63
- const raw = el.textContent;
64
- const result = hljs.highlightAuto(raw);
65
- el.classList.remove('lazy-hl');
66
- el.classList.add('hljs');
67
- el.innerHTML = result.value;
68
- } catch (_) {}
69
- }
70
- }, true);
71
- },
72
-
73
- getToolDisplayName(toolName) {
74
- const normalized = toolName.replace(/^mcp__.*?__/, '');
75
- const knownTools = ['Read','Write','Edit','Bash','Glob','Grep','WebFetch','WebSearch','TodoWrite','Task','NotebookEdit'];
76
- if (knownTools.includes(normalized)) return normalized;
77
- if (toolName.startsWith('mcp__')) {
78
- const parts = toolName.split('__');
79
- return parts.length >= 3 ? parts[2] : parts[parts.length - 1];
80
- }
81
- return normalized || toolName;
82
- },
83
-
84
- getToolTitle(toolName, input) {
85
- const n = toolName.replace(/^mcp__.*?__/, '');
86
- if (n === 'Edit' && input.file_path) { const p = pathSplit(input.file_path); const f = p.pop(); const d = p.slice(-2).join('/'); return d ? d+'/'+f : f; }
87
- if (n === 'Read' && input.file_path) return pathBasename(input.file_path);
88
- if (n === 'Write' && input.file_path) return pathBasename(input.file_path);
89
- if ((n === 'Bash' || n === 'bash') && (input.command || input.commands)) { const c = typeof (input.command||input.commands) === 'string' ? (input.command||input.commands) : JSON.stringify(input.command||input.commands); return c.length > 60 ? c.substring(0,57)+'...' : c; }
90
- if (n === 'Glob' && input.pattern) return input.pattern;
91
- if (n === 'Grep' && input.pattern) return input.pattern;
92
- if (n === 'WebFetch' && input.url) { try { return new URL(input.url).hostname; } catch(e) { return input.url.substring(0,40); } }
93
- if (n === 'WebSearch' && input.query) return input.query.substring(0,50);
94
- if (input.file_path) return pathBasename(input.file_path);
95
- if (input.command) { const c = typeof input.command === 'string' ? input.command : JSON.stringify(input.command); return c.length > 50 ? c.substring(0,47)+'...' : c; }
96
- if (input.query) return input.query.substring(0,50);
97
- return '';
98
- },
99
-
100
- renderParamsHTML(data, depth, esc) {
101
- if (data === null || data === undefined) return `<span style="color:var(--color-text-secondary);font-style:italic">null</span>`;
102
- if (typeof data === 'boolean') return `<span style="color:#d97706;font-weight:600">${data}</span>`;
103
- if (typeof data === 'number') return `<span style="color:#7c3aed;font-weight:600">${data}</span>`;
104
-
105
- if (typeof data === 'string') {
106
- if (data.length > 200 && StreamingRenderer.detectCodeContent(data)) {
107
- const displayData = data.length > 1000 ? data.substring(0, 1000) : data;
108
- const suffix = data.length > 1000 ? `<div style="font-size:0.7rem;color:var(--color-text-secondary);text-align:center;padding:0.25rem">... ${data.length - 1000} more characters</div>` : '';
109
- return `<div style="max-height:200px;overflow-y:auto">${StreamingRenderer.renderCodeWithHighlight(displayData, esc, true)}${suffix}</div>`;
110
- }
111
- if (data.length > 500) {
112
- return `<div style="font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.75rem;white-space:pre-wrap;word-break:break-all;max-height:200px;overflow-y:auto;background:var(--color-bg-code);color:var(--color-code-text);padding:0.5rem;border-radius:0.375rem;line-height:1.5">${esc(data.substring(0, 1000))}${data.length > 1000 ? '\n... (' + (data.length - 1000) + ' more chars)' : ''}</div>`;
113
- }
114
- const looksLikePath = /^[A-Za-z]:[\\\/]/.test(data) || data.startsWith('/');
115
- if (looksLikePath && !data.includes(' ') && data.includes('.')) {
116
- const parts = pathSplit(data);
117
- const name = parts.pop();
118
- const dir = parts.join('/');
119
- return `<div style="display:flex;align-items:center;gap:0.375rem;font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.8rem"><span style="opacity:0.5">&#128196;</span><span style="color:var(--color-text-secondary)">${esc(dir)}/</span><span style="font-weight:600">${esc(name)}</span></div>`;
120
- }
121
- return `<span style="color:var(--color-text-primary)">${esc(data)}</span>`;
122
- }
123
-
124
- if (Array.isArray(data)) {
125
- if (data.length === 0) return `<span style="color:var(--color-text-secondary)">[]</span>`;
126
- if (data.every(i => typeof i === 'string') && data.length <= 20) {
127
- return `<div style="display:flex;flex-direction:column;gap:0.125rem;${depth > 0 ? 'padding-left:1rem' : ''}">${data.map((i, idx) => `<div style="display:flex;align-items:center;gap:0.375rem"><span style="color:var(--color-text-secondary);font-size:0.65rem;opacity:0.5">•</span><span style="font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.75rem">${esc(i)}</span></div>`).join('')}</div>`;
128
- }
129
- return `<div style="display:flex;flex-direction:column;gap:0.25rem;${depth > 0 ? 'padding-left:1rem' : ''}">${data.map((item, i) => `<div style="display:flex;gap:0.5rem;align-items:flex-start"><span style="color:var(--color-text-secondary);font-size:0.7rem;min-width:1.5rem;text-align:right;flex-shrink:0">${i}</span><div style="flex:1;min-width:0">${StreamingRenderer.renderParamsHTML(item, depth + 1, esc)}</div></div>`).join('')}</div>`;
130
- }
131
-
132
- if (typeof data === 'object') {
133
- const entries = Object.entries(data);
134
- if (entries.length === 0) return `<span style="color:var(--color-text-secondary)">{}</span>`;
135
- return `<div style="display:flex;flex-direction:column;gap:0.375rem;${depth > 0 ? 'padding-left:1rem' : ''}">${entries.map(([k, v]) => `<div style="display:flex;gap:0.5rem;align-items:flex-start"><span style="font-weight:600;font-size:0.75rem;color:#0891b2;flex-shrink:0;min-width:fit-content;font-family:'Monaco','Menlo','Ubuntu Mono',monospace">${esc(k)}</span><div style="flex:1;min-width:0;font-size:0.8rem">${StreamingRenderer.renderParamsHTML(v, depth + 1, esc)}</div></div>`).join('')}</div>`;
136
- }
137
-
138
- return `<span>${esc(String(data))}</span>`;
139
- }
140
- });
@@ -1,170 +0,0 @@
1
- Object.assign(StreamingRenderer.prototype, {
2
- renderStreamingStart(event) {
3
- const div = document.createElement('div');
4
- div.className = 'event-streaming-start card mb-3 p-4 alert alert-info';
5
- div.dataset.eventId = event.id || event.sessionId || '';
6
- div.dataset.eventType = 'streaming_start';
7
-
8
- const time = new Date(event.timestamp).toLocaleTimeString();
9
- div.innerHTML = `
10
- <div class="flex items-center gap-2">
11
- <svg class="w-5 h-5 text-info animate-spin" fill="none" viewBox="0 0 24 24" stroke="currentColor">
12
- <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none" opacity="0.25"></circle>
13
- <path d="M4 12a8 8 0 018-8" stroke="currentColor" stroke-width="2" stroke-linecap="round"></path>
14
- </svg>
15
- <div class="flex-1">
16
- <h4 class="font-semibold text-info-content">Streaming Started</h4>
17
- <p class="text-sm text-info-content/70">${time}</p>
18
- </div>
19
- </div>
20
- `;
21
- return div;
22
- },
23
-
24
- renderStreamingProgress(event) {
25
- if (event.block) {
26
- return this.renderBlock(event.block, event);
27
- }
28
-
29
- const div = document.createElement('div');
30
- div.className = 'event-streaming-progress mb-2 p-2';
31
- div.dataset.eventId = event.id || '';
32
- div.dataset.eventType = 'streaming_progress';
33
-
34
- const percentage = event.progress || 0;
35
- div.innerHTML = `
36
- <div class="flex items-center gap-2 text-sm">
37
- <span class="text-secondary">${percentage}%</span>
38
- <div class="progress progress-primary flex-1">
39
- <div class="progress-bar" style="width: ${percentage}%"></div>
40
- </div>
41
- </div>
42
- `;
43
- return div;
44
- },
45
-
46
- renderStreamingComplete(event) {
47
- const div = document.createElement('div');
48
- div.className = 'event-streaming-complete card mb-3 p-4 alert alert-success rounded-lg';
49
- div.dataset.eventId = event.id || event.sessionId || '';
50
- div.dataset.eventType = 'streaming_complete';
51
-
52
- const time = new Date(event.timestamp).toLocaleTimeString();
53
- const eventCount = event.eventCount || 0;
54
-
55
- div.innerHTML = `
56
- <div class="flex items-start gap-3">
57
- <div class="flex-shrink-0 mt-0.5">
58
- <svg class="w-6 h-6 text-success animate-bounce" fill="currentColor" viewBox="0 0 20 20">
59
- <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path>
60
- </svg>
61
- </div>
62
- <div class="flex-1">
63
- <h4 class="font-bold text-lg text-success-content">✨ Execution Complete</h4>
64
- <div class="mt-2 grid grid-cols-2 gap-3 text-sm">
65
- <div>
66
- <span class="text-success font-semibold">${eventCount}</span>
67
- <span class="text-success/70">events processed</span>
68
- </div>
69
- <div class="text-right">
70
- <span class="text-success/70">${time}</span>
71
- </div>
72
- </div>
73
- </div>
74
- </div>
75
- `;
76
- return div;
77
- },
78
-
79
- detectBase64Image(content) {
80
- if (!content || typeof content !== 'string') return null;
81
- const trimmed = content.trim();
82
- const signatures = {
83
- 'png': /^iVBORw0KGgo/,
84
- 'jpeg': /^\/9j\/4AAQ/,
85
- 'webp': /^UklGRi/,
86
- 'gif': /^R0lGODlh/
87
- };
88
- for (const [type, pattern] of Object.entries(signatures)) {
89
- if (pattern.test(trimmed)) {
90
- return { type, isBase64: true, data: trimmed };
91
- }
92
- }
93
- return null;
94
- },
95
-
96
- renderFileRead(event) {
97
- const fileName = event.path ? event.path.split('/').pop() : 'unknown';
98
- const details = document.createElement('details');
99
- details.className = 'block-tool-use folded-tool';
100
- details.classList.add(this._getBlockTypeClass('tool_use'));
101
- details.classList.add(this._getToolColorClass('Read'));
102
- details.dataset.eventId = event.id || '';
103
- details.dataset.eventType = 'file_read';
104
- const summary = document.createElement('summary');
105
- summary.className = 'folded-tool-bar';
106
- summary.innerHTML = `
107
- <span class="folded-tool-icon">${this.getToolIcon('Read')}</span>
108
- <span class="folded-tool-name">Read</span>
109
- <span class="folded-tool-desc">${this.escapeHtml(fileName)}</span>
110
- `;
111
- details.appendChild(summary);
112
- if (event.path || event.content) {
113
- const body = document.createElement('div');
114
- body.className = 'folded-tool-body';
115
- let html = '';
116
- if (event.path) html += this.renderFilePath(event.path);
117
- if (event.content) {
118
- let base64Data = null;
119
- let mimeType = event.media_type || 'application/octet-stream';
120
- if (typeof event.content === 'string') {
121
- const imageInfo = this.detectBase64Image(event.content);
122
- if (imageInfo) {
123
- base64Data = imageInfo.data;
124
- mimeType = imageInfo.type === 'jpeg' ? 'image/jpeg' : `image/${imageInfo.type}`;
125
- }
126
- } else if (typeof event.content === 'object' && event.content !== null) {
127
- if (event.content.source?.type === 'base64' && event.content.source?.data) {
128
- base64Data = event.content.source.data;
129
- } else if (event.content.type === 'base64' && event.content.data) {
130
- base64Data = event.content.data;
131
- }
132
- }
133
- if (base64Data) {
134
- html += `<div style="padding:0.5rem;display:flex;flex-direction:column;gap:0.5rem"><img src="data:${mimeType};base64,${this.escapeHtml(base64Data)}" style="max-width:100%;max-height:600px;border-radius:0.375rem;border:1px solid var(--color-code-border)" loading="lazy"><div style="font-size:0.7rem;color:var(--color-text-secondary);font-family:'Monaco','Menlo','Ubuntu Mono',monospace;word-break:break-all">${this.escapeHtml(event.path)}</div></div>`;
135
- } else {
136
- const contentStr = typeof event.content === 'string' ? event.content : JSON.stringify(event.content, null, 2);
137
- html += `<pre style="background:var(--color-bg-code);padding:0.75rem;border-radius:0.375rem;overflow-x:auto;font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.75rem;line-height:1.5;color:var(--color-code-text);margin:0.5rem 0 0 0"><code class="lazy-hl">${this.escapeHtml(this.truncateContent(contentStr, 2000))}</code></pre>`;
138
- }
139
- }
140
- body.innerHTML = html;
141
- details.appendChild(body);
142
- }
143
- return details;
144
- },
145
-
146
- renderFileWrite(event) {
147
- const fileName = event.path ? event.path.split('/').pop() : 'unknown';
148
- const details = document.createElement('details');
149
- details.className = 'block-tool-use folded-tool';
150
- details.classList.add(this._getBlockTypeClass('tool_use'));
151
- details.classList.add(this._getToolColorClass('Write'));
152
- details.dataset.eventId = event.id || '';
153
- details.dataset.eventType = 'file_write';
154
- const summary = document.createElement('summary');
155
- summary.className = 'folded-tool-bar';
156
- summary.innerHTML = `
157
- <span class="folded-tool-icon">${this.getToolIcon('Write')}</span>
158
- <span class="folded-tool-name">Write</span>
159
- <span class="folded-tool-desc">${this.escapeHtml(fileName)}</span>
160
- `;
161
- details.appendChild(summary);
162
- if (event.path) {
163
- const body = document.createElement('div');
164
- body.className = 'folded-tool-body';
165
- body.innerHTML = this.renderFilePath(event.path);
166
- details.appendChild(body);
167
- }
168
- return details;
169
- }
170
- });