agentgui 1.0.251 → 1.0.253

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.251",
3
+ "version": "1.0.253",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
package/server.js CHANGED
@@ -2555,9 +2555,9 @@ const server = http.createServer(async (req, res) => {
2555
2555
  const isWindows = os.platform() === 'win32';
2556
2556
  const result = execSync('git remote get-url origin' + (isWindows ? '' : ' 2>/dev/null'), { encoding: 'utf-8', cwd: STARTUP_CWD, shell: isWindows });
2557
2557
  const remoteUrl = result.trim();
2558
- const statusResult = execSync('git status --porcelain', { encoding: 'utf-8', cwd: STARTUP_CWD });
2558
+ const statusResult = execSync('git status --porcelain' + (isWindows ? '' : ' 2>/dev/null'), { encoding: 'utf-8', cwd: STARTUP_CWD, shell: isWindows });
2559
2559
  const hasChanges = statusResult.trim().length > 0;
2560
- const unpushedResult = execSync('git rev-list --count --not --remotes 2>/dev/null', { encoding: 'utf-8', cwd: STARTUP_CWD });
2560
+ const unpushedResult = execSync('git rev-list --count --not --remotes' + (isWindows ? '' : ' 2>/dev/null'), { encoding: 'utf-8', cwd: STARTUP_CWD, shell: isWindows });
2561
2561
  const hasUnpushed = parseInt(unpushedResult.trim() || '0', 10) > 0;
2562
2562
  const ownsRemote = !remoteUrl.includes('github.com/') || remoteUrl.includes(process.env.GITHUB_USER || '');
2563
2563
  sendJSON(req, res, 200, { ownsRemote, hasChanges, hasUnpushed, remoteUrl });
@@ -2570,7 +2570,10 @@ const server = http.createServer(async (req, res) => {
2570
2570
  if (pathOnly === '/api/git/push' && req.method === 'POST') {
2571
2571
  try {
2572
2572
  const isWindows = os.platform() === 'win32';
2573
- execSync('git add -A && git commit -m "Auto-commit" && git push', { encoding: 'utf-8', cwd: STARTUP_CWD, shell: isWindows });
2573
+ const gitCommand = isWindows
2574
+ ? 'git add -A & git commit -m "Auto-commit" & git push'
2575
+ : 'git add -A && git commit -m "Auto-commit" && git push';
2576
+ execSync(gitCommand, { encoding: 'utf-8', cwd: STARTUP_CWD, shell: isWindows });
2574
2577
  sendJSON(req, res, 200, { success: true });
2575
2578
  } catch (err) {
2576
2579
  sendJSON(req, res, 500, { error: err.message });
package/static/app.js CHANGED
@@ -678,8 +678,8 @@ function closeNewChatModal() {
678
678
  }
679
679
  }
680
680
 
681
- function createChatInWorkspace() {
682
- const title = prompt('Enter a title for the conversation:', 'New Conversation');
681
+ async function createChatInWorkspace() {
682
+ const title = await window.UIDialog.prompt('Enter a title for the conversation:', 'New Conversation', 'New Chat');
683
683
  if (title) {
684
684
  app.createConversation(title);
685
685
  closeNewChatModal();
@@ -49,6 +49,15 @@ class ConversationManager {
49
49
  this.setupCloneUI();
50
50
 
51
51
  this._pollInterval = setInterval(() => this.loadConversations(), 30000);
52
+
53
+ window.addEventListener('beforeunload', () => this.destroy());
54
+ }
55
+
56
+ destroy() {
57
+ if (this._pollInterval) {
58
+ clearInterval(this._pollInterval);
59
+ this._pollInterval = null;
60
+ }
52
61
  }
53
62
 
54
63
  async loadAgents() {
@@ -466,7 +475,10 @@ class ConversationManager {
466
475
  }
467
476
 
468
477
  async confirmDelete(convId, title) {
469
- const confirmed = confirm(`Delete conversation "${title || 'Untitled'}"?\n\nThis will also delete any associated Claude Code session data. This action cannot be undone.`);
478
+ const confirmed = await window.UIDialog.confirm(
479
+ `Delete conversation "${title || 'Untitled'}"?\n\nThis will also delete any associated Claude Code session data. This action cannot be undone.`,
480
+ 'Delete Conversation'
481
+ );
470
482
  if (!confirmed) return;
471
483
 
472
484
  try {
@@ -477,15 +489,14 @@ class ConversationManager {
477
489
 
478
490
  if (res.ok) {
479
491
  console.log(`[ConversationManager] Deleted conversation ${convId}`);
480
- // Remove from local list immediately for responsive UI
481
492
  this.deleteConversation(convId);
482
493
  } else {
483
494
  const error = await res.json().catch(() => ({ error: 'Failed to delete' }));
484
- alert('Failed to delete conversation: ' + (error.error || 'Unknown error'));
495
+ window.UIDialog.alert('Failed to delete conversation: ' + (error.error || 'Unknown error'), 'Error');
485
496
  }
486
497
  } catch (err) {
487
498
  console.error('[ConversationManager] Delete error:', err);
488
- alert('Failed to delete conversation: ' + err.message);
499
+ window.UIDialog.alert('Failed to delete conversation: ' + err.message, 'Error');
489
500
  }
490
501
  }
491
502
 
@@ -0,0 +1,267 @@
1
+ (function() {
2
+ var activeDialogs = [];
3
+ var dialogZIndex = 10000;
4
+
5
+ function escapeHtml(text) {
6
+ var map = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' };
7
+ return String(text).replace(/[&<>"']/g, function(c) { return map[c]; });
8
+ }
9
+
10
+ function createOverlay() {
11
+ var overlay = document.createElement('div');
12
+ overlay.className = 'dialog-overlay';
13
+ overlay.innerHTML = '<div class="dialog-backdrop"></div>';
14
+ return overlay;
15
+ }
16
+
17
+ function showDialog(dialog, overlay) {
18
+ dialogZIndex++;
19
+ if (overlay) {
20
+ overlay.style.zIndex = dialogZIndex;
21
+ document.body.appendChild(overlay);
22
+ }
23
+ dialog.style.zIndex = dialogZIndex + 1;
24
+ document.body.appendChild(dialog);
25
+ activeDialogs.push({ dialog: dialog, overlay: overlay });
26
+
27
+ requestAnimationFrame(function() {
28
+ dialog.classList.add('visible');
29
+ if (overlay) overlay.classList.add('visible');
30
+ var input = dialog.querySelector('input, textarea');
31
+ if (input) input.focus();
32
+ else {
33
+ var btn = dialog.querySelector('.dialog-btn-primary');
34
+ if (btn) btn.focus();
35
+ }
36
+ });
37
+ }
38
+
39
+ function closeDialog(dialog, overlay) {
40
+ dialog.classList.remove('visible');
41
+ if (overlay) overlay.classList.remove('visible');
42
+ setTimeout(function() {
43
+ if (dialog.parentNode) dialog.remove();
44
+ if (overlay && overlay.parentNode) overlay.remove();
45
+ }, 200);
46
+ activeDialogs = activeDialogs.filter(function(d) {
47
+ return d.dialog !== dialog;
48
+ });
49
+ }
50
+
51
+ function closeAllDialogs() {
52
+ activeDialogs.forEach(function(d) {
53
+ closeDialog(d.dialog, d.overlay);
54
+ });
55
+ }
56
+
57
+ window.UIDialog = {
58
+ alert: function(message, title) {
59
+ return new Promise(function(resolve) {
60
+ var overlay = createOverlay();
61
+ var dialog = document.createElement('div');
62
+ dialog.className = 'dialog-container';
63
+ dialog.innerHTML =
64
+ '<div class="dialog-box">' +
65
+ '<div class="dialog-header">' +
66
+ '<h3 class="dialog-title">' + escapeHtml(title || 'Alert') + '</h3>' +
67
+ '</div>' +
68
+ '<div class="dialog-body">' +
69
+ '<p class="dialog-message">' + escapeHtml(message) + '</p>' +
70
+ '</div>' +
71
+ '<div class="dialog-footer">' +
72
+ '<button class="dialog-btn dialog-btn-primary" data-action="ok">OK</button>' +
73
+ '</div>' +
74
+ '</div>';
75
+
76
+ var okBtn = dialog.querySelector('[data-action="ok"]');
77
+ okBtn.addEventListener('click', function() {
78
+ closeDialog(dialog, overlay);
79
+ resolve(true);
80
+ });
81
+
82
+ overlay.querySelector('.dialog-backdrop').addEventListener('click', function() {
83
+ closeDialog(dialog, overlay);
84
+ resolve(true);
85
+ });
86
+
87
+ document.addEventListener('keydown', function handler(e) {
88
+ if (e.key === 'Escape' || e.key === 'Enter') {
89
+ document.removeEventListener('keydown', handler);
90
+ closeDialog(dialog, overlay);
91
+ resolve(true);
92
+ }
93
+ });
94
+
95
+ showDialog(dialog, overlay);
96
+ });
97
+ },
98
+
99
+ confirm: function(message, title) {
100
+ return new Promise(function(resolve) {
101
+ var overlay = createOverlay();
102
+ var dialog = document.createElement('div');
103
+ dialog.className = 'dialog-container';
104
+ dialog.innerHTML =
105
+ '<div class="dialog-box">' +
106
+ '<div class="dialog-header">' +
107
+ '<h3 class="dialog-title">' + escapeHtml(title || 'Confirm') + '</h3>' +
108
+ '</div>' +
109
+ '<div class="dialog-body">' +
110
+ '<p class="dialog-message">' + escapeHtml(message).replace(/\n/g, '<br>') + '</p>' +
111
+ '</div>' +
112
+ '<div class="dialog-footer">' +
113
+ '<button class="dialog-btn dialog-btn-secondary" data-action="cancel">Cancel</button>' +
114
+ '<button class="dialog-btn dialog-btn-primary dialog-btn-danger" data-action="confirm">Confirm</button>' +
115
+ '</div>' +
116
+ '</div>';
117
+
118
+ var cancelBtn = dialog.querySelector('[data-action="cancel"]');
119
+ var confirmBtn = dialog.querySelector('[data-action="confirm"]');
120
+
121
+ cancelBtn.addEventListener('click', function() {
122
+ closeDialog(dialog, overlay);
123
+ resolve(false);
124
+ });
125
+
126
+ confirmBtn.addEventListener('click', function() {
127
+ closeDialog(dialog, overlay);
128
+ resolve(true);
129
+ });
130
+
131
+ overlay.querySelector('.dialog-backdrop').addEventListener('click', function() {
132
+ closeDialog(dialog, overlay);
133
+ resolve(false);
134
+ });
135
+
136
+ document.addEventListener('keydown', function handler(e) {
137
+ if (e.key === 'Escape') {
138
+ document.removeEventListener('keydown', handler);
139
+ closeDialog(dialog, overlay);
140
+ resolve(false);
141
+ } else if (e.key === 'Enter') {
142
+ document.removeEventListener('keydown', handler);
143
+ closeDialog(dialog, overlay);
144
+ resolve(true);
145
+ }
146
+ });
147
+
148
+ showDialog(dialog, overlay);
149
+ });
150
+ },
151
+
152
+ prompt: function(message, defaultValue, title) {
153
+ return new Promise(function(resolve) {
154
+ var overlay = createOverlay();
155
+ var dialog = document.createElement('div');
156
+ dialog.className = 'dialog-container';
157
+ dialog.innerHTML =
158
+ '<div class="dialog-box">' +
159
+ '<div class="dialog-header">' +
160
+ '<h3 class="dialog-title">' + escapeHtml(title || 'Input') + '</h3>' +
161
+ '</div>' +
162
+ '<div class="dialog-body">' +
163
+ '<label class="dialog-label">' + escapeHtml(message) + '</label>' +
164
+ '<input type="text" class="dialog-input" value="' + escapeHtml(defaultValue || '') + '">' +
165
+ '</div>' +
166
+ '<div class="dialog-footer">' +
167
+ '<button class="dialog-btn dialog-btn-secondary" data-action="cancel">Cancel</button>' +
168
+ '<button class="dialog-btn dialog-btn-primary" data-action="ok">OK</button>' +
169
+ '</div>' +
170
+ '</div>';
171
+
172
+ var input = dialog.querySelector('.dialog-input');
173
+ var cancelBtn = dialog.querySelector('[data-action="cancel"]');
174
+ var okBtn = dialog.querySelector('[data-action="ok"]');
175
+
176
+ cancelBtn.addEventListener('click', function() {
177
+ closeDialog(dialog, overlay);
178
+ resolve(null);
179
+ });
180
+
181
+ okBtn.addEventListener('click', function() {
182
+ closeDialog(dialog, overlay);
183
+ resolve(input.value);
184
+ });
185
+
186
+ input.addEventListener('keydown', function(e) {
187
+ if (e.key === 'Enter') {
188
+ closeDialog(dialog, overlay);
189
+ resolve(input.value);
190
+ }
191
+ });
192
+
193
+ overlay.querySelector('.dialog-backdrop').addEventListener('click', function() {
194
+ closeDialog(dialog, overlay);
195
+ resolve(null);
196
+ });
197
+
198
+ document.addEventListener('keydown', function handler(e) {
199
+ if (e.key === 'Escape') {
200
+ document.removeEventListener('keydown', handler);
201
+ closeDialog(dialog, overlay);
202
+ resolve(null);
203
+ }
204
+ });
205
+
206
+ showDialog(dialog, overlay);
207
+ });
208
+ },
209
+
210
+ showProgress: function(config) {
211
+ var overlay = createOverlay();
212
+ var dialog = document.createElement('div');
213
+ dialog.className = 'dialog-container';
214
+ dialog.innerHTML =
215
+ '<div class="dialog-box dialog-box-progress">' +
216
+ '<div class="dialog-header">' +
217
+ '<h3 class="dialog-title">' + escapeHtml(config.title || 'Please wait') + '</h3>' +
218
+ '</div>' +
219
+ '<div class="dialog-body">' +
220
+ '<p class="dialog-message progress-message">' + escapeHtml(config.message || 'Loading...') + '</p>' +
221
+ '<div class="dialog-progress-bar">' +
222
+ '<div class="dialog-progress-fill" style="width: 0%"></div>' +
223
+ '</div>' +
224
+ '<p class="dialog-progress-percent">0%</p>' +
225
+ '</div>' +
226
+ '</div>';
227
+
228
+ showDialog(dialog, overlay);
229
+
230
+ var progressFill = dialog.querySelector('.dialog-progress-fill');
231
+ var progressPercent = dialog.querySelector('.dialog-progress-percent');
232
+ var progressMessage = dialog.querySelector('.progress-message');
233
+
234
+ return {
235
+ update: function(percent, message) {
236
+ progressFill.style.width = percent + '%';
237
+ progressPercent.textContent = Math.round(percent) + '%';
238
+ if (message) progressMessage.textContent = message;
239
+ },
240
+ close: function() {
241
+ closeDialog(dialog, overlay);
242
+ }
243
+ };
244
+ },
245
+
246
+ showToast: function(message, type, duration) {
247
+ var existing = document.querySelector('.toast-notification');
248
+ if (existing) existing.remove();
249
+
250
+ var toast = document.createElement('div');
251
+ toast.className = 'toast-notification toast-' + (type || 'info');
252
+ toast.innerHTML = '<span class="toast-message">' + escapeHtml(message) + '</span>';
253
+ document.body.appendChild(toast);
254
+
255
+ requestAnimationFrame(function() {
256
+ toast.classList.add('visible');
257
+ });
258
+
259
+ setTimeout(function() {
260
+ toast.classList.remove('visible');
261
+ setTimeout(function() { if (toast.parentNode) toast.remove(); }, 300);
262
+ }, duration || 3000);
263
+ },
264
+
265
+ closeAll: closeAllDialogs
266
+ };
267
+ })();
@@ -123,7 +123,7 @@
123
123
  overlay.classList.remove('visible');
124
124
 
125
125
  if (!currentConversation) {
126
- showToast('Select a conversation first', 'error');
126
+ if (window.UIDialog) window.UIDialog.showToast('Select a conversation first', 'error');
127
127
  return;
128
128
  }
129
129
 
@@ -136,7 +136,7 @@
136
136
 
137
137
  function uploadFiles(files) {
138
138
  if (!currentConversation) {
139
- showToast('No conversation selected', 'error');
139
+ if (window.UIDialog) window.UIDialog.showToast('No conversation selected', 'error');
140
140
  return;
141
141
  }
142
142
 
@@ -145,7 +145,7 @@
145
145
  formData.append('file', files[i]);
146
146
  }
147
147
 
148
- showToast('Uploading ' + files.length + ' file(s)...', 'info');
148
+ if (window.UIDialog) window.UIDialog.showToast('Uploading ' + files.length + ' file(s)...', 'info');
149
149
 
150
150
  fetch(BASE + '/api/upload/' + currentConversation, {
151
151
  method: 'POST',
@@ -154,13 +154,13 @@
154
154
  .then(function(res) { return res.json(); })
155
155
  .then(function(data) {
156
156
  if (data.ok) {
157
- showToast(data.count + ' file(s) uploaded', 'success');
157
+ if (window.UIDialog) window.UIDialog.showToast(data.count + ' file(s) uploaded', 'success');
158
158
  } else {
159
- showToast('Upload failed: ' + (data.error || 'Unknown error'), 'error');
159
+ if (window.UIDialog) window.UIDialog.showToast('Upload failed: ' + (data.error || 'Unknown error'), 'error');
160
160
  }
161
161
  })
162
162
  .catch(function(err) {
163
- showToast('Upload failed: ' + err.message, 'error');
163
+ if (window.UIDialog) window.UIDialog.showToast('Upload failed: ' + err.message, 'error');
164
164
  });
165
165
  }
166
166
 
@@ -197,6 +197,42 @@
197
197
  });
198
198
  }
199
199
 
200
+ function showVoiceDownloadProgress() {
201
+ if (window._voiceProgressDialog) return;
202
+
203
+ window._voiceProgressDialog = window.UIDialog.showProgress({
204
+ title: 'Downloading Voice Models',
205
+ message: 'Preparing speech recognition and synthesis models...'
206
+ });
207
+
208
+ var checkInterval = setInterval(function() {
209
+ if (isVoiceReady()) {
210
+ clearInterval(checkInterval);
211
+ if (window._voiceProgressDialog) {
212
+ window._voiceProgressDialog.close();
213
+ window._voiceProgressDialog = null;
214
+ }
215
+ switchView('voice');
216
+ }
217
+ }, 500);
218
+
219
+ setTimeout(function() {
220
+ clearInterval(checkInterval);
221
+ if (window._voiceProgressDialog) {
222
+ window._voiceProgressDialog.close();
223
+ window._voiceProgressDialog = null;
224
+ }
225
+ }, 120000);
226
+ }
227
+
228
+ function updateVoiceProgress(percent, message) {
229
+ if (window._voiceProgressDialog) {
230
+ window._voiceProgressDialog.update(percent, message);
231
+ }
232
+ }
233
+
234
+ window.__updateVoiceProgress = updateVoiceProgress;
235
+
200
236
  function isVoiceReady() {
201
237
  var client = window.agentGUIClient;
202
238
  if (!client) return false;