agentgui 1.0.152 → 1.0.154
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/database.js +25 -0
- package/lib/claude-runner.js +23 -2
- package/package.json +1 -1
- package/server.js +82 -11
- package/static/index.html +95 -33
- package/static/js/client.js +200 -127
- package/static/js/conversations.js +63 -15
- package/static/js/event-processor.js +1 -3
- package/static/js/streaming-renderer.js +130 -158
- package/static/js/syntax-highlighter.js +1 -3
- package/static/js/ui-components.js +1 -3
|
@@ -69,6 +69,7 @@ class StreamingRenderer {
|
|
|
69
69
|
this.setupDOMObserver();
|
|
70
70
|
this.setupResizeObserver();
|
|
71
71
|
this.setupScrollOptimization();
|
|
72
|
+
StreamingRenderer._setupGlobalLazyHL();
|
|
72
73
|
return this;
|
|
73
74
|
}
|
|
74
75
|
|
|
@@ -460,10 +461,7 @@ class StreamingRenderer {
|
|
|
460
461
|
|
|
461
462
|
const preStyle = "background:#1e293b;padding:1rem;border-radius:0 0 0.375rem 0.375rem;overflow-x:auto;font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.875rem;line-height:1.6;color:#e2e8f0;border:1px solid #334155;border-top:none;margin:0";
|
|
462
463
|
const codeContainer = document.createElement('div');
|
|
463
|
-
codeContainer.innerHTML = `<pre style="${preStyle}"><code>${this.escapeHtml(code)}</code></pre>`;
|
|
464
|
-
if (typeof hljs !== 'undefined') {
|
|
465
|
-
this.lazyHighlight(codeContainer, code);
|
|
466
|
-
}
|
|
464
|
+
codeContainer.innerHTML = `<pre style="${preStyle}"><code class="lazy-hl">${this.escapeHtml(code)}</code></pre>`;
|
|
467
465
|
|
|
468
466
|
details.appendChild(summary);
|
|
469
467
|
details.appendChild(codeContainer);
|
|
@@ -702,40 +700,26 @@ class StreamingRenderer {
|
|
|
702
700
|
renderBlockToolUse(block, context) {
|
|
703
701
|
const toolName = block.name || 'unknown';
|
|
704
702
|
const input = block.input || {};
|
|
705
|
-
const shouldFold = toolName.startsWith('mcp__') || toolName === 'Edit';
|
|
706
|
-
|
|
707
|
-
if (shouldFold) {
|
|
708
|
-
const details = document.createElement('details');
|
|
709
|
-
details.className = 'block-tool-use folded-tool';
|
|
710
|
-
const summary = document.createElement('summary');
|
|
711
|
-
summary.className = 'folded-tool-bar';
|
|
712
|
-
const displayName = this.getToolUseDisplayName(toolName);
|
|
713
|
-
const titleInfo = this.getToolUseTitle(toolName, input);
|
|
714
|
-
summary.innerHTML = `
|
|
715
|
-
<span class="folded-tool-icon">${this.getToolIcon(toolName)}</span>
|
|
716
|
-
<span class="folded-tool-name">${this.escapeHtml(displayName)}</span>
|
|
717
|
-
${titleInfo ? `<span class="folded-tool-desc">${this.escapeHtml(titleInfo)}</span>` : ''}
|
|
718
|
-
`;
|
|
719
|
-
details.appendChild(summary);
|
|
720
|
-
if (Object.keys(input).length > 0) {
|
|
721
|
-
const paramsDiv = document.createElement('div');
|
|
722
|
-
paramsDiv.className = 'folded-tool-body';
|
|
723
|
-
paramsDiv.innerHTML = this.renderSmartParams(toolName, input);
|
|
724
|
-
details.appendChild(paramsDiv);
|
|
725
|
-
}
|
|
726
|
-
return details;
|
|
727
|
-
}
|
|
728
703
|
|
|
729
|
-
const
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
704
|
+
const details = document.createElement('details');
|
|
705
|
+
details.className = 'block-tool-use folded-tool';
|
|
706
|
+
const summary = document.createElement('summary');
|
|
707
|
+
summary.className = 'folded-tool-bar';
|
|
708
|
+
const displayName = this.getToolUseDisplayName(toolName);
|
|
709
|
+
const titleInfo = this.getToolUseTitle(toolName, input);
|
|
710
|
+
summary.innerHTML = `
|
|
711
|
+
<span class="folded-tool-icon">${this.getToolIcon(toolName)}</span>
|
|
712
|
+
<span class="folded-tool-name">${this.escapeHtml(displayName)}</span>
|
|
713
|
+
${titleInfo ? `<span class="folded-tool-desc">${this.escapeHtml(titleInfo)}</span>` : ''}
|
|
737
714
|
`;
|
|
738
|
-
|
|
715
|
+
details.appendChild(summary);
|
|
716
|
+
if (Object.keys(input).length > 0) {
|
|
717
|
+
const paramsDiv = document.createElement('div');
|
|
718
|
+
paramsDiv.className = 'folded-tool-body';
|
|
719
|
+
paramsDiv.innerHTML = this.renderSmartParams(toolName, input);
|
|
720
|
+
details.appendChild(paramsDiv);
|
|
721
|
+
}
|
|
722
|
+
return details;
|
|
739
723
|
}
|
|
740
724
|
|
|
741
725
|
/**
|
|
@@ -820,7 +804,7 @@ class StreamingRenderer {
|
|
|
820
804
|
*/
|
|
821
805
|
static renderSmartContentHTML(contentStr, escapeHtml) {
|
|
822
806
|
const trimmed = contentStr.trim();
|
|
823
|
-
const esc = escapeHtml ||
|
|
807
|
+
const esc = escapeHtml || window._escHtml;
|
|
824
808
|
|
|
825
809
|
if (trimmed.startsWith('data:image/')) {
|
|
826
810
|
return `<div style="padding:0.5rem"><img src="${esc(trimmed)}" style="max-width:100%;max-height:24rem;border-radius:0.375rem" loading="lazy"></div>`;
|
|
@@ -1071,18 +1055,33 @@ class StreamingRenderer {
|
|
|
1071
1055
|
static renderCodeWithHighlight(code, esc) {
|
|
1072
1056
|
const preStyle = "background:#1e293b;padding:1rem;border-radius:0 0 0.375rem 0.375rem;overflow-x:auto;font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.875rem;line-height:1.6;color:#e2e8f0;border:1px solid #334155;border-top:none;margin:0";
|
|
1073
1057
|
const lineCount = code.split('\n').length;
|
|
1074
|
-
const
|
|
1075
|
-
const
|
|
1076
|
-
let codeHtml;
|
|
1077
|
-
if (typeof hljs !== 'undefined') {
|
|
1078
|
-
const result = hljs.highlightAuto(code);
|
|
1079
|
-
codeHtml = `<pre style="${preStyle}"><code class="hljs">${result.value}</code></pre>`;
|
|
1080
|
-
} else {
|
|
1081
|
-
codeHtml = `<pre style="${preStyle}">${esc(code)}</pre>`;
|
|
1082
|
-
}
|
|
1058
|
+
const summaryLabel = `code - ${lineCount} line${lineCount !== 1 ? 's' : ''}`;
|
|
1059
|
+
const codeHtml = `<pre style="${preStyle}"><code class="lazy-hl">${esc(code)}</code></pre>`;
|
|
1083
1060
|
return `<details class="collapsible-code"><summary class="collapsible-code-summary">${summaryLabel}</summary>${codeHtml}</details>`;
|
|
1084
1061
|
}
|
|
1085
1062
|
|
|
1063
|
+
static _setupGlobalLazyHL() {
|
|
1064
|
+
if (StreamingRenderer._lazyHLSetup) return;
|
|
1065
|
+
StreamingRenderer._lazyHLSetup = true;
|
|
1066
|
+
const root = document.getElementById('output-scroll') || document.body;
|
|
1067
|
+
root.addEventListener('toggle', (e) => {
|
|
1068
|
+
const details = e.target;
|
|
1069
|
+
if (!details.open || details.tagName !== 'DETAILS') return;
|
|
1070
|
+
const codeEls = details.querySelectorAll('code.lazy-hl');
|
|
1071
|
+
if (codeEls.length === 0) return;
|
|
1072
|
+
if (typeof hljs === 'undefined') return;
|
|
1073
|
+
for (const el of codeEls) {
|
|
1074
|
+
try {
|
|
1075
|
+
const raw = el.textContent;
|
|
1076
|
+
const result = hljs.highlightAuto(raw);
|
|
1077
|
+
el.classList.remove('lazy-hl');
|
|
1078
|
+
el.classList.add('hljs');
|
|
1079
|
+
el.innerHTML = result.value;
|
|
1080
|
+
} catch (_) {}
|
|
1081
|
+
}
|
|
1082
|
+
}, true);
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1086
1085
|
static getToolDisplayName(toolName) {
|
|
1087
1086
|
const normalized = toolName.replace(/^mcp__[^_]+__/, '');
|
|
1088
1087
|
const knownTools = ['Read','Write','Edit','Bash','Glob','Grep','WebFetch','WebSearch','TodoWrite','Task','NotebookEdit'];
|
|
@@ -1439,64 +1438,57 @@ class StreamingRenderer {
|
|
|
1439
1438
|
* Render file read event
|
|
1440
1439
|
*/
|
|
1441
1440
|
renderFileRead(event) {
|
|
1442
|
-
const div = document.createElement('div');
|
|
1443
|
-
div.className = 'event-file-read card mb-3 p-4';
|
|
1444
|
-
div.dataset.eventId = event.id || '';
|
|
1445
|
-
div.dataset.eventType = 'file_read';
|
|
1446
|
-
|
|
1447
1441
|
const fileName = event.path ? event.path.split('/').pop() : 'unknown';
|
|
1448
|
-
const
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
<h4 class="font-semibold text-sm truncate">${this.escapeHtml(fileName)}</h4>
|
|
1459
|
-
<p class="text-xs text-secondary truncate" title="${this.escapeHtml(event.path || '')}">${this.escapeHtml(event.path || '')}</p>
|
|
1460
|
-
</div>
|
|
1461
|
-
</div>
|
|
1462
|
-
<span class="badge badge-sm flex-shrink-0">${this.escapeHtml(sizeStr)}</span>
|
|
1463
|
-
</div>
|
|
1464
|
-
${event.content ? `
|
|
1465
|
-
<pre class="bg-gray-50 dark:bg-gray-900 p-3 rounded border text-xs overflow-x-auto"><code>${this.escapeHtml(this.truncateContent(event.content, 500))}</code></pre>
|
|
1466
|
-
` : ''}
|
|
1442
|
+
const details = document.createElement('details');
|
|
1443
|
+
details.className = 'block-tool-use folded-tool';
|
|
1444
|
+
details.dataset.eventId = event.id || '';
|
|
1445
|
+
details.dataset.eventType = 'file_read';
|
|
1446
|
+
const summary = document.createElement('summary');
|
|
1447
|
+
summary.className = 'folded-tool-bar';
|
|
1448
|
+
summary.innerHTML = `
|
|
1449
|
+
<span class="folded-tool-icon">${this.getToolIcon('Read')}</span>
|
|
1450
|
+
<span class="folded-tool-name">Read</span>
|
|
1451
|
+
<span class="folded-tool-desc">${this.escapeHtml(fileName)}</span>
|
|
1467
1452
|
`;
|
|
1468
|
-
|
|
1453
|
+
details.appendChild(summary);
|
|
1454
|
+
if (event.path || event.content) {
|
|
1455
|
+
const body = document.createElement('div');
|
|
1456
|
+
body.className = 'folded-tool-body';
|
|
1457
|
+
let html = '';
|
|
1458
|
+
if (event.path) html += this.renderFilePath(event.path);
|
|
1459
|
+
if (event.content) {
|
|
1460
|
+
html += `<pre style="background:#1e293b;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:#e2e8f0;margin:0.5rem 0 0 0"><code class="lazy-hl">${this.escapeHtml(this.truncateContent(event.content, 2000))}</code></pre>`;
|
|
1461
|
+
}
|
|
1462
|
+
body.innerHTML = html;
|
|
1463
|
+
details.appendChild(body);
|
|
1464
|
+
}
|
|
1465
|
+
return details;
|
|
1469
1466
|
}
|
|
1470
1467
|
|
|
1471
1468
|
/**
|
|
1472
1469
|
* Render file write event
|
|
1473
1470
|
*/
|
|
1474
1471
|
renderFileWrite(event) {
|
|
1475
|
-
const div = document.createElement('div');
|
|
1476
|
-
div.className = 'event-file-write card mb-3 p-4 border-l-4 border-yellow-500';
|
|
1477
|
-
div.dataset.eventId = event.id || '';
|
|
1478
|
-
div.dataset.eventType = 'file_write';
|
|
1479
|
-
|
|
1480
1472
|
const fileName = event.path ? event.path.split('/').pop() : 'unknown';
|
|
1481
|
-
const
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
<h4 class="font-semibold text-sm truncate">${this.escapeHtml(fileName)}</h4>
|
|
1492
|
-
<p class="text-xs text-secondary truncate" title="${this.escapeHtml(event.path || '')}">${this.escapeHtml(event.path || '')}</p>
|
|
1493
|
-
</div>
|
|
1494
|
-
</div>
|
|
1495
|
-
<span class="badge badge-sm bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200 flex-shrink-0">Written</span>
|
|
1496
|
-
</div>
|
|
1497
|
-
<span class="text-xs text-secondary">${this.escapeHtml(sizeStr)}</span>
|
|
1473
|
+
const details = document.createElement('details');
|
|
1474
|
+
details.className = 'block-tool-use folded-tool';
|
|
1475
|
+
details.dataset.eventId = event.id || '';
|
|
1476
|
+
details.dataset.eventType = 'file_write';
|
|
1477
|
+
const summary = document.createElement('summary');
|
|
1478
|
+
summary.className = 'folded-tool-bar';
|
|
1479
|
+
summary.innerHTML = `
|
|
1480
|
+
<span class="folded-tool-icon">${this.getToolIcon('Write')}</span>
|
|
1481
|
+
<span class="folded-tool-name">Write</span>
|
|
1482
|
+
<span class="folded-tool-desc">${this.escapeHtml(fileName)}</span>
|
|
1498
1483
|
`;
|
|
1499
|
-
|
|
1484
|
+
details.appendChild(summary);
|
|
1485
|
+
if (event.path) {
|
|
1486
|
+
const body = document.createElement('div');
|
|
1487
|
+
body.className = 'folded-tool-body';
|
|
1488
|
+
body.innerHTML = this.renderFilePath(event.path);
|
|
1489
|
+
details.appendChild(body);
|
|
1490
|
+
}
|
|
1491
|
+
return details;
|
|
1500
1492
|
}
|
|
1501
1493
|
|
|
1502
1494
|
/**
|
|
@@ -1536,57 +1528,64 @@ class StreamingRenderer {
|
|
|
1536
1528
|
* Render command execution event
|
|
1537
1529
|
*/
|
|
1538
1530
|
renderCommand(event) {
|
|
1539
|
-
const div = document.createElement('div');
|
|
1540
|
-
div.className = 'event-command card mb-3 p-4 font-mono text-sm';
|
|
1541
|
-
div.dataset.eventId = event.id || '';
|
|
1542
|
-
div.dataset.eventType = 'command_execute';
|
|
1543
|
-
|
|
1544
1531
|
const command = event.command || '';
|
|
1545
1532
|
const output = event.output || '';
|
|
1546
1533
|
const exitCode = event.exitCode !== undefined ? event.exitCode : null;
|
|
1534
|
+
const cmdPreview = command.length > 60 ? command.substring(0, 57) + '...' : command;
|
|
1547
1535
|
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
<div class="text-xs mt-2 ${exitCode === 0 ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'}">
|
|
1559
|
-
Exit code: ${exitCode}
|
|
1560
|
-
</div>
|
|
1561
|
-
` : ''}
|
|
1536
|
+
const details = document.createElement('details');
|
|
1537
|
+
details.className = 'block-tool-use folded-tool';
|
|
1538
|
+
details.dataset.eventId = event.id || '';
|
|
1539
|
+
details.dataset.eventType = 'command_execute';
|
|
1540
|
+
const summary = document.createElement('summary');
|
|
1541
|
+
summary.className = 'folded-tool-bar';
|
|
1542
|
+
summary.innerHTML = `
|
|
1543
|
+
<span class="folded-tool-icon">${this.getToolIcon('Bash')}</span>
|
|
1544
|
+
<span class="folded-tool-name">Bash</span>
|
|
1545
|
+
<span class="folded-tool-desc">${this.escapeHtml(cmdPreview)}</span>
|
|
1562
1546
|
`;
|
|
1563
|
-
|
|
1547
|
+
details.appendChild(summary);
|
|
1548
|
+
|
|
1549
|
+
const body = document.createElement('div');
|
|
1550
|
+
body.className = 'folded-tool-body';
|
|
1551
|
+
let html = `<div class="tool-param-command"><span class="prompt-char">$</span><span class="command-text">${this.escapeHtml(command)}</span></div>`;
|
|
1552
|
+
if (output) {
|
|
1553
|
+
html += `<pre style="background:#1e293b;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:#e2e8f0;margin:0.5rem 0 0 0"><code class="lazy-hl">${this.escapeHtml(this.truncateContent(output, 2000))}</code></pre>`;
|
|
1554
|
+
}
|
|
1555
|
+
if (exitCode !== null && exitCode !== 0) {
|
|
1556
|
+
html += `<div style="margin-top:0.375rem;font-size:0.75rem;color:#ef4444;font-weight:600">Exit code: ${exitCode}</div>`;
|
|
1557
|
+
}
|
|
1558
|
+
body.innerHTML = html;
|
|
1559
|
+
details.appendChild(body);
|
|
1560
|
+
return details;
|
|
1564
1561
|
}
|
|
1565
1562
|
|
|
1566
1563
|
/**
|
|
1567
1564
|
* Render error event
|
|
1568
1565
|
*/
|
|
1569
1566
|
renderError(event) {
|
|
1570
|
-
const div = document.createElement('div');
|
|
1571
|
-
div.className = 'event-error card mb-3 p-4 bg-red-50 dark:bg-red-900 border-l-4 border-red-500';
|
|
1572
|
-
div.dataset.eventId = event.id || '';
|
|
1573
|
-
div.dataset.eventType = 'error';
|
|
1574
|
-
|
|
1575
1567
|
const message = event.message || event.error || 'Unknown error';
|
|
1576
1568
|
const severity = event.severity || 'error';
|
|
1569
|
+
const msgPreview = message.length > 80 ? message.substring(0, 77) + '...' : message;
|
|
1577
1570
|
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
</
|
|
1571
|
+
const details = document.createElement('details');
|
|
1572
|
+
details.className = 'folded-tool folded-tool-error';
|
|
1573
|
+
details.dataset.eventId = event.id || '';
|
|
1574
|
+
details.dataset.eventType = 'error';
|
|
1575
|
+
const summary = document.createElement('summary');
|
|
1576
|
+
summary.className = 'folded-tool-bar';
|
|
1577
|
+
summary.innerHTML = `
|
|
1578
|
+
<span class="folded-tool-icon"><svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/></svg></span>
|
|
1579
|
+
<span class="folded-tool-name">Error</span>
|
|
1580
|
+
<span class="folded-tool-desc">${this.escapeHtml(msgPreview)}</span>
|
|
1588
1581
|
`;
|
|
1589
|
-
|
|
1582
|
+
details.appendChild(summary);
|
|
1583
|
+
|
|
1584
|
+
const body = document.createElement('div');
|
|
1585
|
+
body.className = 'folded-tool-body';
|
|
1586
|
+
body.innerHTML = `<div style="font-size:0.8rem;white-space:pre-wrap;word-break:break-word;line-height:1.5">${this.escapeHtml(message)}</div>`;
|
|
1587
|
+
details.appendChild(body);
|
|
1588
|
+
return details;
|
|
1590
1589
|
}
|
|
1591
1590
|
|
|
1592
1591
|
isHtmlContent(text) {
|
|
@@ -1806,31 +1805,6 @@ class StreamingRenderer {
|
|
|
1806
1805
|
});
|
|
1807
1806
|
}
|
|
1808
1807
|
|
|
1809
|
-
lazyHighlight(container, code) {
|
|
1810
|
-
if (!this._hlObserver) {
|
|
1811
|
-
this._hlObserver = new IntersectionObserver((entries) => {
|
|
1812
|
-
for (const entry of entries) {
|
|
1813
|
-
if (!entry.isIntersecting) continue;
|
|
1814
|
-
const el = entry.target;
|
|
1815
|
-
const raw = el._rawCode;
|
|
1816
|
-
if (!raw) continue;
|
|
1817
|
-
this._hlObserver.unobserve(el);
|
|
1818
|
-
try {
|
|
1819
|
-
const codeEl = el.querySelector('code');
|
|
1820
|
-
if (codeEl && typeof hljs !== 'undefined') {
|
|
1821
|
-
const result = hljs.highlightAuto(raw);
|
|
1822
|
-
codeEl.classList.add('hljs');
|
|
1823
|
-
codeEl.innerHTML = result.value;
|
|
1824
|
-
}
|
|
1825
|
-
} catch (_) {}
|
|
1826
|
-
delete el._rawCode;
|
|
1827
|
-
}
|
|
1828
|
-
}, { rootMargin: '200px' });
|
|
1829
|
-
}
|
|
1830
|
-
container._rawCode = code;
|
|
1831
|
-
this._hlObserver.observe(container);
|
|
1832
|
-
}
|
|
1833
|
-
|
|
1834
1808
|
updateVirtualScroll() {
|
|
1835
1809
|
}
|
|
1836
1810
|
|
|
@@ -1845,9 +1819,7 @@ class StreamingRenderer {
|
|
|
1845
1819
|
* HTML escape utility
|
|
1846
1820
|
*/
|
|
1847
1821
|
escapeHtml(text) {
|
|
1848
|
-
|
|
1849
|
-
div.textContent = text;
|
|
1850
|
-
return div.innerHTML;
|
|
1822
|
+
return window._escHtml(text);
|
|
1851
1823
|
}
|
|
1852
1824
|
|
|
1853
1825
|
/**
|