agentgui 1.0.252 → 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 +1 -1
- package/server.js +6 -3
- package/static/app.js +2 -2
- package/static/js/conversations.js +6 -4
- package/static/js/dialogs.js +267 -0
- package/static/js/features.js +42 -6
package/package.json
CHANGED
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
|
-
|
|
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();
|
|
@@ -475,7 +475,10 @@ class ConversationManager {
|
|
|
475
475
|
}
|
|
476
476
|
|
|
477
477
|
async confirmDelete(convId, title) {
|
|
478
|
-
const confirmed = confirm(
|
|
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
|
+
);
|
|
479
482
|
if (!confirmed) return;
|
|
480
483
|
|
|
481
484
|
try {
|
|
@@ -486,15 +489,14 @@ class ConversationManager {
|
|
|
486
489
|
|
|
487
490
|
if (res.ok) {
|
|
488
491
|
console.log(`[ConversationManager] Deleted conversation ${convId}`);
|
|
489
|
-
// Remove from local list immediately for responsive UI
|
|
490
492
|
this.deleteConversation(convId);
|
|
491
493
|
} else {
|
|
492
494
|
const error = await res.json().catch(() => ({ error: 'Failed to delete' }));
|
|
493
|
-
alert('Failed to delete conversation: ' + (error.error || 'Unknown error'));
|
|
495
|
+
window.UIDialog.alert('Failed to delete conversation: ' + (error.error || 'Unknown error'), 'Error');
|
|
494
496
|
}
|
|
495
497
|
} catch (err) {
|
|
496
498
|
console.error('[ConversationManager] Delete error:', err);
|
|
497
|
-
alert('Failed to delete conversation: ' + err.message);
|
|
499
|
+
window.UIDialog.alert('Failed to delete conversation: ' + err.message, 'Error');
|
|
498
500
|
}
|
|
499
501
|
}
|
|
500
502
|
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
(function() {
|
|
2
|
+
var activeDialogs = [];
|
|
3
|
+
var dialogZIndex = 10000;
|
|
4
|
+
|
|
5
|
+
function escapeHtml(text) {
|
|
6
|
+
var map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' };
|
|
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
|
+
})();
|
package/static/js/features.js
CHANGED
|
@@ -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;
|