agentgui 1.0.131 → 1.0.138

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.
@@ -192,6 +192,7 @@ class AgentGUIClient {
192
192
  */
193
193
  updateUrlForConversation(conversationId, sessionId) {
194
194
  if (!this.isValidId(conversationId)) return;
195
+ if (!this.routerState) return;
195
196
 
196
197
  this.routerState.currentConversationId = conversationId;
197
198
  if (sessionId && this.isValidId(sessionId)) {
@@ -689,7 +690,8 @@ class AgentGUIClient {
689
690
  </div>
690
691
  `;
691
692
  } else {
692
- return `<div class="message-code"><pre>${this.escapeHtml(code)}</pre></div>`;
693
+ const lineCount = code.split('\n').length;
694
+ return `<div class="message-code"><details class="collapsible-code"><summary class="collapsible-code-summary">${this.escapeHtml(language)} - ${lineCount} line${lineCount !== 1 ? 's' : ''}</summary><pre style="margin:0;border-radius:0 0 0.375rem 0.375rem">${this.escapeHtml(code)}</pre></details></div>`;
693
695
  }
694
696
  }
695
697
 
@@ -731,7 +733,8 @@ class AgentGUIClient {
731
733
  </div>
732
734
  `;
733
735
  } else {
734
- html += `<div class="message-code"><pre>${this.escapeHtml(block.code)}</pre></div>`;
736
+ const blkLineCount = block.code.split('\n').length;
737
+ html += `<div class="message-code"><details class="collapsible-code"><summary class="collapsible-code-summary">${this.escapeHtml(block.language || 'code')} - ${blkLineCount} line${blkLineCount !== 1 ? 's' : ''}</summary><pre style="margin:0;border-radius:0 0 0.375rem 0.375rem">${this.escapeHtml(block.code)}</pre></details></div>`;
735
738
  }
736
739
  } else if (block.type === 'tool_use') {
737
740
  let inputHtml = '';
@@ -1354,7 +1357,8 @@ class AgentGUIClient {
1354
1357
  </div>
1355
1358
  `;
1356
1359
  } else {
1357
- contentHtml += `<div class="message-code"><pre>${this.escapeHtml(block.code)}</pre></div>`;
1360
+ const cBlkLineCount = block.code.split('\n').length;
1361
+ contentHtml += `<div class="message-code"><details class="collapsible-code"><summary class="collapsible-code-summary">${this.escapeHtml(block.language || 'code')} - ${cBlkLineCount} line${cBlkLineCount !== 1 ? 's' : ''}</summary><pre style="margin:0;border-radius:0 0 0.375rem 0.375rem">${this.escapeHtml(block.code)}</pre></details></div>`;
1358
1362
  }
1359
1363
  } else if (block.type === 'tool_use') {
1360
1364
  let inputHtml = '';
@@ -19,7 +19,9 @@ class ConversationManager {
19
19
  listEl: null,
20
20
  breadcrumbEl: null,
21
21
  currentPath: '~',
22
- homePath: '~'
22
+ homePath: '~',
23
+ cwdPath: null,
24
+ homePathReady: null
23
25
  };
24
26
 
25
27
  if (!this.listEl) return;
@@ -55,7 +57,7 @@ class ConversationManager {
55
57
  if (e.target === this.folderBrowser.modal) this.closeFolderBrowser();
56
58
  });
57
59
 
58
- this.fetchHomePath();
60
+ this.folderBrowser.homePathReady = this.fetchHomePath();
59
61
  }
60
62
 
61
63
  async fetchHomePath() {
@@ -64,20 +66,25 @@ class ConversationManager {
64
66
  if (res.ok) {
65
67
  const data = await res.json();
66
68
  this.folderBrowser.homePath = data.home || '~';
69
+ this.folderBrowser.cwdPath = data.cwd || null;
67
70
  }
68
71
  } catch (e) {
69
72
  console.error('Failed to fetch home path:', e);
70
73
  }
71
74
  }
72
75
 
73
- openFolderBrowser() {
76
+ async openFolderBrowser() {
74
77
  if (!this.folderBrowser.modal) {
75
78
  this.createNew();
76
79
  return;
77
80
  }
78
- this.folderBrowser.currentPath = '~';
81
+ if (this.folderBrowser.homePathReady) {
82
+ await this.folderBrowser.homePathReady;
83
+ }
84
+ const startPath = this.folderBrowser.cwdPath || '~';
85
+ this.folderBrowser.currentPath = startPath;
79
86
  this.folderBrowser.modal.classList.add('visible');
80
- this.loadFolders('~');
87
+ this.loadFolders(startPath);
81
88
  }
82
89
 
83
90
  closeFolderBrowser() {
@@ -195,31 +195,31 @@
195
195
  var chatArea = document.getElementById('output-scroll');
196
196
  var execPanel = document.querySelector('.input-section');
197
197
  var fileBrowser = document.getElementById('fileBrowserContainer');
198
- var iframe = document.getElementById('fileBrowserIframe');
198
+ var fileIframe = document.getElementById('fileBrowserIframe');
199
+ var voiceContainer = document.getElementById('voiceContainer');
199
200
 
200
201
  if (!bar) return;
201
202
 
202
- // Update active button
203
203
  bar.querySelectorAll('.view-toggle-btn').forEach(function(btn) {
204
204
  btn.classList.toggle('active', btn.dataset.view === view);
205
205
  });
206
206
 
207
- if (view === 'files') {
208
- if (chatArea) chatArea.style.display = 'none';
209
- if (execPanel) execPanel.style.display = 'none';
210
- if (fileBrowser) {
211
- fileBrowser.style.display = 'flex';
212
- if (iframe && currentConversation) {
213
- var src = BASE + '/files/' + currentConversation + '/';
214
- if (iframe.src !== location.origin + src) {
215
- iframe.src = src;
216
- }
217
- }
207
+ if (chatArea) chatArea.style.display = view === 'chat' ? '' : 'none';
208
+ if (execPanel) execPanel.style.display = view === 'chat' ? '' : 'none';
209
+ if (fileBrowser) fileBrowser.style.display = view === 'files' ? 'flex' : 'none';
210
+ if (voiceContainer) voiceContainer.style.display = view === 'voice' ? 'flex' : 'none';
211
+
212
+ if (view === 'files' && fileIframe && currentConversation) {
213
+ var src = BASE + '/files/' + currentConversation + '/';
214
+ if (fileIframe.src !== location.origin + src) {
215
+ fileIframe.src = src;
218
216
  }
219
- } else {
220
- if (chatArea) chatArea.style.display = '';
221
- if (execPanel) execPanel.style.display = '';
222
- if (fileBrowser) fileBrowser.style.display = 'none';
217
+ }
218
+
219
+ if (view === 'voice' && window.voiceModule) {
220
+ window.voiceModule.activate();
221
+ } else if (view !== 'voice' && window.voiceModule) {
222
+ window.voiceModule.deactivate();
223
223
  }
224
224
  }
225
225
 
@@ -432,18 +432,24 @@ class StreamingRenderer {
432
432
 
433
433
  const code = block.code || '';
434
434
  const language = (block.language || 'plaintext').toLowerCase();
435
+ const lineCount = code.split('\n').length;
435
436
 
436
- const header = document.createElement('div');
437
- header.className = 'code-header';
438
- header.innerHTML = `
439
- <span class="lang-badge">${this.escapeHtml(language)}</span>
437
+ const details = document.createElement('details');
438
+ details.className = 'collapsible-code';
439
+
440
+ const summary = document.createElement('summary');
441
+ summary.className = 'collapsible-code-summary';
442
+ summary.innerHTML = `
443
+ <span class="collapsible-code-label">${this.escapeHtml(language)} - ${lineCount} line${lineCount !== 1 ? 's' : ''}</span>
440
444
  <button class="copy-code-btn" title="Copy code">
441
445
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>
442
446
  </button>
443
447
  `;
444
448
 
445
- const copyBtn = header.querySelector('.copy-code-btn');
446
- copyBtn.addEventListener('click', () => {
449
+ const copyBtn = summary.querySelector('.copy-code-btn');
450
+ copyBtn.addEventListener('click', (e) => {
451
+ e.preventDefault();
452
+ e.stopPropagation();
447
453
  navigator.clipboard.writeText(code).then(() => {
448
454
  const orig = copyBtn.innerHTML;
449
455
  copyBtn.innerHTML = '<svg viewBox="0 0 20 20" fill="#34d399"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/></svg>';
@@ -451,13 +457,18 @@ class StreamingRenderer {
451
457
  });
452
458
  });
453
459
 
454
- // Use syntax highlighting instead of just escaping
455
- const highlightedHTML = StreamingRenderer.renderCodeWithHighlight(code, this.escapeHtml.bind(this));
460
+ 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";
456
461
  const codeContainer = document.createElement('div');
457
- codeContainer.innerHTML = highlightedHTML;
462
+ if (typeof hljs !== 'undefined') {
463
+ const result = hljs.highlightAuto(code);
464
+ codeContainer.innerHTML = `<pre style="${preStyle}"><code class="hljs">${result.value}</code></pre>`;
465
+ } else {
466
+ codeContainer.innerHTML = `<pre style="${preStyle}"><code>${this.escapeHtml(code)}</code></pre>`;
467
+ }
458
468
 
459
- div.appendChild(header);
460
- div.appendChild(codeContainer);
469
+ details.appendChild(summary);
470
+ details.appendChild(codeContainer);
471
+ div.appendChild(details);
461
472
 
462
473
  return div;
463
474
  }
@@ -991,12 +1002,18 @@ class StreamingRenderer {
991
1002
  * Render code with basic syntax highlighting
992
1003
  */
993
1004
  static renderCodeWithHighlight(code, esc) {
994
- const preStyle = "background:#1e293b;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:#e2e8f0;border:1px solid #334155";
1005
+ 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";
1006
+ const lineCount = code.split('\n').length;
1007
+ const lang = (typeof hljs !== 'undefined') ? (hljs.highlightAuto(code).language || 'code') : 'code';
1008
+ const summaryLabel = `${lang} - ${lineCount} line${lineCount !== 1 ? 's' : ''}`;
1009
+ let codeHtml;
995
1010
  if (typeof hljs !== 'undefined') {
996
1011
  const result = hljs.highlightAuto(code);
997
- return `<pre style="${preStyle}"><code class="hljs">${result.value}</code></pre>`;
1012
+ codeHtml = `<pre style="${preStyle}"><code class="hljs">${result.value}</code></pre>`;
1013
+ } else {
1014
+ codeHtml = `<pre style="${preStyle}">${esc(code)}</pre>`;
998
1015
  }
999
- return `<pre style="${preStyle}">${esc(code)}</pre>`;
1016
+ return `<details class="collapsible-code"><summary class="collapsible-code-summary">${summaryLabel}</summary>${codeHtml}</details>`;
1000
1017
  }
1001
1018
 
1002
1019
  /**
@@ -1521,16 +1538,19 @@ class StreamingRenderer {
1521
1538
  <div class="html-content bg-white dark:bg-gray-800 p-4 overflow-x-auto">${part.code}</div>
1522
1539
  </div>`;
1523
1540
  } else {
1541
+ const partLineCount = part.code.split('\n').length;
1524
1542
  html += `<div class="mb-3 rounded-lg overflow-hidden border border-gray-200 dark:border-gray-800">
1525
- <div class="flex items-center justify-between gap-2 bg-gray-900 dark:bg-gray-950 px-4 py-2 border-b border-gray-800">
1526
- <span class="text-xs font-mono text-gray-400 uppercase">${this.escapeHtml(part.language)}</span>
1527
- <button class="copy-code-btn text-gray-400 hover:text-gray-200 transition-colors p-1 rounded hover:bg-gray-800" title="Copy code">
1528
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1529
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
1530
- </svg>
1531
- </button>
1532
- </div>
1533
- <pre class="bg-gray-900 text-gray-100 p-4 overflow-x-auto"><code class="language-${this.escapeHtml(part.language)}">${this.escapeHtml(part.code)}</code></pre>
1543
+ <details class="collapsible-code">
1544
+ <summary class="collapsible-code-summary">
1545
+ <span>${this.escapeHtml(part.language)} - ${partLineCount} line${partLineCount !== 1 ? 's' : ''}</span>
1546
+ <button class="copy-code-btn text-gray-400 hover:text-gray-200 transition-colors p-1 rounded hover:bg-gray-800" title="Copy code" onclick="event.preventDefault();event.stopPropagation();navigator.clipboard.writeText(this.closest('.collapsible-code').querySelector('code').textContent)">
1547
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1548
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
1549
+ </svg>
1550
+ </button>
1551
+ </summary>
1552
+ <pre class="bg-gray-900 text-gray-100 p-4 overflow-x-auto" style="margin:0;border-radius:0 0 0.375rem 0.375rem"><code class="language-${this.escapeHtml(part.language)}">${this.escapeHtml(part.code)}</code></pre>
1553
+ </details>
1534
1554
  </div>`;
1535
1555
  }
1536
1556
  }
@@ -1578,8 +1598,12 @@ class StreamingRenderer {
1578
1598
  </div>
1579
1599
  `;
1580
1600
  } else {
1601
+ const codeLineCount = code.split('\n').length;
1581
1602
  div.innerHTML = `
1582
- <pre class="bg-gray-900 text-gray-100 p-4 rounded overflow-x-auto"><code class="language-${this.escapeHtml(language)}">${this.escapeHtml(code)}</code></pre>
1603
+ <details class="collapsible-code">
1604
+ <summary class="collapsible-code-summary">${this.escapeHtml(language)} - ${codeLineCount} line${codeLineCount !== 1 ? 's' : ''}</summary>
1605
+ <pre class="bg-gray-900 text-gray-100 p-4 overflow-x-auto" style="margin:0;border-radius:0 0 0.375rem 0.375rem"><code class="language-${this.escapeHtml(language)}">${this.escapeHtml(code)}</code></pre>
1606
+ </details>
1583
1607
  `;
1584
1608
  }
1585
1609
  return div;
@@ -6,7 +6,7 @@
6
6
  class SyntaxHighlighter {
7
7
  constructor(config = {}) {
8
8
  this.config = {
9
- cdnUrl: config.cdnUrl || 'https://unpkg.com/prism@1.29.0',
9
+ cdnUrl: config.cdnUrl || 'https://cdn.jsdelivr.net/npm/prismjs@1.29.0',
10
10
  lazyLoad: config.lazyLoad !== false,
11
11
  enableCache: config.enableCache !== false,
12
12
  maxCacheSize: config.maxCacheSize || 500,