antri_cli 1.27.0 → 1.28.0
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/README.md +89 -42
- package/assets/desktop_panel.png +0 -0
- package/assets/home.png +0 -0
- package/dist/cli/promptToolkit.d.ts.map +1 -1
- package/dist/cli/promptToolkit.js +1 -0
- package/dist/cli/promptToolkit.js.map +1 -1
- package/dist/cli/shortcuts.d.ts.map +1 -1
- package/dist/cli/shortcuts.js +6 -0
- package/dist/cli/shortcuts.js.map +1 -1
- package/dist/core/config.js +1 -1
- package/dist/core/updater.d.ts +1 -1
- package/dist/core/updater.js +1 -1
- package/dist/desktop/public/app.js +248 -8
- package/dist/desktop/public/index.html +24 -4
- package/dist/desktop/public/style.css +152 -2
- package/dist/desktop/server.d.ts.map +1 -1
- package/dist/desktop/server.js +51 -5
- package/dist/desktop/server.js.map +1 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/mobile/public/app.js +449 -0
- package/dist/mobile/public/index.html +287 -0
- package/dist/mobile/public/manifest.json +16 -0
- package/dist/mobile/public/style.css +589 -0
- package/dist/mobile/server.d.ts +14 -0
- package/dist/mobile/server.d.ts.map +1 -0
- package/dist/mobile/server.js +232 -0
- package/dist/mobile/server.js.map +1 -0
- package/package.json +3 -2
|
@@ -2,10 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
let currentConfig = null;
|
|
4
4
|
let activeTab = 'chat';
|
|
5
|
+
let attachedFiles = [];
|
|
6
|
+
let availableCommands = [];
|
|
7
|
+
let activePaletteMatches = [];
|
|
8
|
+
let paletteSelectedIndex = 0;
|
|
9
|
+
let activePaletteMode = null; // 'slash' | 'file' | null
|
|
5
10
|
|
|
6
11
|
// Initialize on Load
|
|
7
12
|
document.addEventListener('DOMContentLoaded', async () => {
|
|
8
13
|
await loadStatus();
|
|
14
|
+
await loadCommands();
|
|
9
15
|
await loadProfiles();
|
|
10
16
|
await loadSkills();
|
|
11
17
|
await loadMemory();
|
|
@@ -34,6 +40,17 @@ async function loadStatus() {
|
|
|
34
40
|
}
|
|
35
41
|
}
|
|
36
42
|
|
|
43
|
+
// Load Slash Commands for Prompt Toolkit
|
|
44
|
+
async function loadCommands() {
|
|
45
|
+
try {
|
|
46
|
+
const res = await fetch('/api/commands');
|
|
47
|
+
const data = await res.json();
|
|
48
|
+
availableCommands = data.commands || [];
|
|
49
|
+
} catch (err) {
|
|
50
|
+
console.error('Failed to load commands:', err);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
37
54
|
// Load Models for Provider
|
|
38
55
|
async function loadModels() {
|
|
39
56
|
try {
|
|
@@ -132,13 +149,243 @@ function showTab(tabName) {
|
|
|
132
149
|
if (navButtons[navIndex]) navButtons[navIndex].classList.add('active');
|
|
133
150
|
}
|
|
134
151
|
|
|
152
|
+
// File Upload Handler (Images & Files)
|
|
153
|
+
async function handleFileSelected(event) {
|
|
154
|
+
const files = event.target.files;
|
|
155
|
+
if (!files || files.length === 0) return;
|
|
156
|
+
|
|
157
|
+
for (const file of files) {
|
|
158
|
+
const reader = new FileReader();
|
|
159
|
+
reader.onload = async (e) => {
|
|
160
|
+
const data = e.target.result;
|
|
161
|
+
try {
|
|
162
|
+
const res = await fetch('/api/upload', {
|
|
163
|
+
method: 'POST',
|
|
164
|
+
headers: { 'Content-Type': 'application/json' },
|
|
165
|
+
body: JSON.stringify({
|
|
166
|
+
fileName: file.name,
|
|
167
|
+
fileType: file.type || 'text/plain',
|
|
168
|
+
data,
|
|
169
|
+
}),
|
|
170
|
+
});
|
|
171
|
+
const uploadRes = await res.json();
|
|
172
|
+
if (uploadRes.success) {
|
|
173
|
+
attachedFiles.push({
|
|
174
|
+
name: file.name,
|
|
175
|
+
path: uploadRes.filePath,
|
|
176
|
+
isImage: uploadRes.isImage,
|
|
177
|
+
dataUrl: uploadRes.isImage ? data : null,
|
|
178
|
+
});
|
|
179
|
+
renderAttachmentChips();
|
|
180
|
+
}
|
|
181
|
+
} catch (err) {
|
|
182
|
+
console.error('File upload failed:', err);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
if (file.type.startsWith('image/')) {
|
|
186
|
+
reader.readAsDataURL(file);
|
|
187
|
+
} else {
|
|
188
|
+
reader.readAsText(file);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Reset input
|
|
193
|
+
event.target.value = '';
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function renderAttachmentChips() {
|
|
197
|
+
const tray = document.getElementById('attachment-preview-tray');
|
|
198
|
+
if (!tray) return;
|
|
199
|
+
|
|
200
|
+
if (attachedFiles.length === 0) {
|
|
201
|
+
tray.classList.add('hidden');
|
|
202
|
+
tray.innerHTML = '';
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
tray.classList.remove('hidden');
|
|
207
|
+
tray.innerHTML = '';
|
|
208
|
+
|
|
209
|
+
attachedFiles.forEach((file, index) => {
|
|
210
|
+
const chip = document.createElement('div');
|
|
211
|
+
chip.className = 'attachment-chip';
|
|
212
|
+
if (file.isImage && file.dataUrl) {
|
|
213
|
+
chip.innerHTML = `
|
|
214
|
+
<img src="${file.dataUrl}" alt="preview" />
|
|
215
|
+
<span>${file.name}</span>
|
|
216
|
+
<button class="remove-chip-btn" onclick="removeAttachment(${index})">×</button>
|
|
217
|
+
`;
|
|
218
|
+
} else {
|
|
219
|
+
chip.innerHTML = `
|
|
220
|
+
<span>${file.name}</span>
|
|
221
|
+
<button class="remove-chip-btn" onclick="removeAttachment(${index})">×</button>
|
|
222
|
+
`;
|
|
223
|
+
}
|
|
224
|
+
tray.appendChild(chip);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function removeAttachment(index) {
|
|
229
|
+
attachedFiles.splice(index, 1);
|
|
230
|
+
renderAttachmentChips();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Prompt Toolkit Text & Key Handler
|
|
234
|
+
async function handleInputText(event) {
|
|
235
|
+
const val = event.target.value;
|
|
236
|
+
const cursorPos = event.target.selectionStart;
|
|
237
|
+
|
|
238
|
+
// 1. Slash command mode
|
|
239
|
+
if (val.startsWith('/')) {
|
|
240
|
+
const query = val.toLowerCase();
|
|
241
|
+
activePaletteMatches = availableCommands.filter((cmd) => {
|
|
242
|
+
const baseName = cmd.name.split(' ')[0].toLowerCase();
|
|
243
|
+
return baseName.startsWith(query) || cmd.name.toLowerCase().startsWith(query);
|
|
244
|
+
});
|
|
245
|
+
activePaletteMode = 'slash';
|
|
246
|
+
renderPalette('Commands', activePaletteMatches);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// 2. Attachment file mode (@)
|
|
251
|
+
const lastAt = val.lastIndexOf('@', cursorPos - 1);
|
|
252
|
+
if (lastAt !== -1 && (lastAt === 0 || val[lastAt - 1] === ' ')) {
|
|
253
|
+
const query = val.slice(lastAt + 1, cursorPos);
|
|
254
|
+
if (!query.includes(' ')) {
|
|
255
|
+
try {
|
|
256
|
+
const res = await fetch(`/api/files?query=${encodeURIComponent(query)}`);
|
|
257
|
+
const data = await res.json();
|
|
258
|
+
activePaletteMatches = data.items.map((item) => ({
|
|
259
|
+
name: item.name,
|
|
260
|
+
description: item.isDirectory ? 'Directory' : item.relativePath,
|
|
261
|
+
relativePath: item.relativePath,
|
|
262
|
+
isDirectory: item.isDirectory,
|
|
263
|
+
}));
|
|
264
|
+
activePaletteMode = 'file';
|
|
265
|
+
renderPalette(`Files: ${data.currentDir}`, activePaletteMatches);
|
|
266
|
+
return;
|
|
267
|
+
} catch (e) {}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
hidePalette();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function renderPalette(title, items) {
|
|
275
|
+
const palette = document.getElementById('prompt-toolkit-palette');
|
|
276
|
+
const header = document.getElementById('palette-header');
|
|
277
|
+
const list = document.getElementById('palette-list');
|
|
278
|
+
|
|
279
|
+
if (!palette || !items || items.length === 0) {
|
|
280
|
+
hidePalette();
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
header.textContent = title;
|
|
285
|
+
list.innerHTML = '';
|
|
286
|
+
paletteSelectedIndex = Math.min(paletteSelectedIndex, items.length - 1);
|
|
287
|
+
if (paletteSelectedIndex < 0) paletteSelectedIndex = 0;
|
|
288
|
+
|
|
289
|
+
items.slice(0, 10).forEach((item, idx) => {
|
|
290
|
+
const el = document.createElement('div');
|
|
291
|
+
el.className = `palette-item ${idx === paletteSelectedIndex ? 'active' : ''}`;
|
|
292
|
+
el.innerHTML = `
|
|
293
|
+
<span class="palette-name">${item.name}</span>
|
|
294
|
+
<span class="palette-desc">${item.description || ''}</span>
|
|
295
|
+
${item.isDirectory ? '<span class="palette-tag">dir</span>' : ''}
|
|
296
|
+
`;
|
|
297
|
+
el.onclick = () => selectPaletteItem(idx);
|
|
298
|
+
list.appendChild(el);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
palette.classList.remove('hidden');
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function hidePalette() {
|
|
305
|
+
const palette = document.getElementById('prompt-toolkit-palette');
|
|
306
|
+
if (palette) palette.classList.add('hidden');
|
|
307
|
+
activePaletteMode = null;
|
|
308
|
+
activePaletteMatches = [];
|
|
309
|
+
paletteSelectedIndex = 0;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function selectPaletteItem(index) {
|
|
313
|
+
const item = activePaletteMatches[index];
|
|
314
|
+
if (!item) return;
|
|
315
|
+
|
|
316
|
+
const input = document.getElementById('prompt-input');
|
|
317
|
+
|
|
318
|
+
if (activePaletteMode === 'slash') {
|
|
319
|
+
const rawCmd = item.name.split(' ')[0];
|
|
320
|
+
input.value = rawCmd + ' ';
|
|
321
|
+
hidePalette();
|
|
322
|
+
input.focus();
|
|
323
|
+
} else if (activePaletteMode === 'file') {
|
|
324
|
+
const val = input.value;
|
|
325
|
+
const cursorPos = input.selectionStart;
|
|
326
|
+
const lastAt = val.lastIndexOf('@', cursorPos - 1);
|
|
327
|
+
if (lastAt !== -1) {
|
|
328
|
+
input.value = val.slice(0, lastAt) + '@' + item.relativePath + ' ' + val.slice(cursorPos);
|
|
329
|
+
}
|
|
330
|
+
hidePalette();
|
|
331
|
+
input.focus();
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function handleInputKey(event) {
|
|
336
|
+
const palette = document.getElementById('prompt-toolkit-palette');
|
|
337
|
+
const isPaletteVisible = palette && !palette.classList.contains('hidden');
|
|
338
|
+
|
|
339
|
+
if (isPaletteVisible && activePaletteMatches.length > 0) {
|
|
340
|
+
if (event.key === 'ArrowUp') {
|
|
341
|
+
event.preventDefault();
|
|
342
|
+
paletteSelectedIndex = (paletteSelectedIndex - 1 + activePaletteMatches.length) % activePaletteMatches.length;
|
|
343
|
+
renderPalette(document.getElementById('palette-header').textContent, activePaletteMatches);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (event.key === 'ArrowDown') {
|
|
347
|
+
event.preventDefault();
|
|
348
|
+
paletteSelectedIndex = (paletteSelectedIndex + 1) % activePaletteMatches.length;
|
|
349
|
+
renderPalette(document.getElementById('palette-header').textContent, activePaletteMatches);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
if (event.key === 'Tab' || event.key === 'Enter') {
|
|
353
|
+
if (!event.ctrlKey && !event.metaKey) {
|
|
354
|
+
event.preventDefault();
|
|
355
|
+
selectPaletteItem(paletteSelectedIndex);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (event.key === 'Escape') {
|
|
360
|
+
hidePalette();
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Ctrl + Enter to submit prompt
|
|
366
|
+
if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {
|
|
367
|
+
event.preventDefault();
|
|
368
|
+
submitPrompt();
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
135
372
|
// Chat Prompt Submission with SSE Streaming
|
|
136
373
|
async function submitPrompt() {
|
|
137
374
|
const input = document.getElementById('prompt-input');
|
|
138
|
-
|
|
375
|
+
let prompt = input.value.trim();
|
|
376
|
+
|
|
377
|
+
// Attach any uploaded files to prompt
|
|
378
|
+
if (attachedFiles.length > 0) {
|
|
379
|
+
const attachmentsText = attachedFiles.map((f) => `\n[Attached File: ${f.name} (${f.path})]`).join('');
|
|
380
|
+
prompt = prompt + '\n' + attachmentsText;
|
|
381
|
+
attachedFiles = [];
|
|
382
|
+
renderAttachmentChips();
|
|
383
|
+
}
|
|
384
|
+
|
|
139
385
|
if (!prompt) return;
|
|
140
386
|
|
|
141
387
|
input.value = '';
|
|
388
|
+
hidePalette();
|
|
142
389
|
|
|
143
390
|
// Intercept /debate or /goal inside chat
|
|
144
391
|
if (prompt.startsWith('/debate')) {
|
|
@@ -232,13 +479,6 @@ function setPrompt(text) {
|
|
|
232
479
|
input.focus();
|
|
233
480
|
}
|
|
234
481
|
|
|
235
|
-
function handleInputKey(event) {
|
|
236
|
-
if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {
|
|
237
|
-
event.preventDefault();
|
|
238
|
-
submitPrompt();
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
482
|
// Dialectic Debate Runner
|
|
243
483
|
async function startDebate() {
|
|
244
484
|
const input = document.getElementById('debate-query-input');
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<header class="app-header">
|
|
16
16
|
<div class="brand-zone">
|
|
17
17
|
<span class="logo-mark">ANTRI</span>
|
|
18
|
-
<span class="version-tag">v1.
|
|
18
|
+
<span class="version-tag">v1.28.0</span>
|
|
19
19
|
</div>
|
|
20
20
|
|
|
21
21
|
<!-- Mode Toggle -->
|
|
@@ -116,12 +116,32 @@
|
|
|
116
116
|
</div>
|
|
117
117
|
</div>
|
|
118
118
|
|
|
119
|
-
<!-- Bottom Prompt Box -->
|
|
119
|
+
<!-- Bottom Prompt Box & Prompt Toolkit -->
|
|
120
120
|
<div class="chat-input-bar">
|
|
121
|
+
<!-- Prompt Toolkit Dropdown Palette -->
|
|
122
|
+
<div id="prompt-toolkit-palette" class="prompt-toolkit-palette hidden">
|
|
123
|
+
<div class="palette-header" id="palette-header">Commands</div>
|
|
124
|
+
<div class="palette-list" id="palette-list">
|
|
125
|
+
<!-- Dynamically populated -->
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<!-- Attached Files Preview Tray -->
|
|
130
|
+
<div id="attachment-preview-tray" class="attachment-preview-tray hidden"></div>
|
|
131
|
+
|
|
121
132
|
<div class="input-container">
|
|
122
|
-
|
|
133
|
+
<!-- Hidden File Input -->
|
|
134
|
+
<input type="file" id="file-upload-input" multiple accept="image/*,.txt,.ts,.js,.json,.py,.md,.csv,.html,.css" style="display:none;" onchange="handleFileSelected(event)" />
|
|
135
|
+
|
|
136
|
+
<div class="input-row">
|
|
137
|
+
<button id="btn-attach-file" class="attach-btn" title="Upload image or file" onclick="document.getElementById('file-upload-input').click()">
|
|
138
|
+
+
|
|
139
|
+
</button>
|
|
140
|
+
<textarea id="prompt-input" placeholder="Ask ANTRI, type / for commands, @ for files..." rows="2" onkeydown="handleInputKey(event)" oninput="handleInputText(event)"></textarea>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
123
143
|
<div class="input-actions">
|
|
124
|
-
<span class="shortcut-tip">Press Ctrl + Enter to send ·
|
|
144
|
+
<span class="shortcut-tip">Press <b>Ctrl + Enter</b> to send · <b>/</b> commands · <b>@</b> files</span>
|
|
125
145
|
<button id="send-btn" class="send-btn" onclick="submitPrompt()">
|
|
126
146
|
<span>Send</span>
|
|
127
147
|
</button>
|
|
@@ -394,25 +394,175 @@ body.antri-app {
|
|
|
394
394
|
display: inline-block;
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
-
/* Chat Input Bar */
|
|
397
|
+
/* Chat Input Bar & Attachments */
|
|
398
398
|
.chat-input-bar {
|
|
399
399
|
position: absolute;
|
|
400
400
|
bottom: 1.25rem;
|
|
401
401
|
left: 2.75rem;
|
|
402
402
|
right: 2.75rem;
|
|
403
|
+
z-index: 50;
|
|
403
404
|
}
|
|
404
405
|
|
|
405
406
|
.input-container {
|
|
406
407
|
background: var(--bg-card);
|
|
407
408
|
border: 1px solid var(--border-main);
|
|
408
409
|
border-radius: var(--radius-lg);
|
|
409
|
-
padding:
|
|
410
|
+
padding: 0.9rem 1.25rem;
|
|
410
411
|
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.04);
|
|
411
412
|
display: flex;
|
|
412
413
|
flex-direction: column;
|
|
414
|
+
gap: 0.5rem;
|
|
415
|
+
position: relative;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.input-row {
|
|
419
|
+
display: flex;
|
|
420
|
+
align-items: flex-start;
|
|
413
421
|
gap: 0.75rem;
|
|
414
422
|
}
|
|
415
423
|
|
|
424
|
+
.attach-btn {
|
|
425
|
+
width: 32px;
|
|
426
|
+
height: 32px;
|
|
427
|
+
min-width: 32px;
|
|
428
|
+
border-radius: var(--radius-sm);
|
|
429
|
+
border: 1px solid var(--border-main);
|
|
430
|
+
background: var(--bg-subtle);
|
|
431
|
+
color: var(--text-primary);
|
|
432
|
+
font-size: 1.15rem;
|
|
433
|
+
font-weight: 500;
|
|
434
|
+
display: flex;
|
|
435
|
+
align-items: center;
|
|
436
|
+
justify-content: center;
|
|
437
|
+
cursor: pointer;
|
|
438
|
+
transition: all 0.15s ease;
|
|
439
|
+
margin-top: 2px;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.attach-btn:hover {
|
|
443
|
+
background: var(--bg-hover);
|
|
444
|
+
border-color: var(--text-primary);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.attachment-preview-tray {
|
|
448
|
+
display: flex;
|
|
449
|
+
flex-wrap: wrap;
|
|
450
|
+
gap: 0.5rem;
|
|
451
|
+
padding: 0.4rem 0.2rem;
|
|
452
|
+
border-bottom: 1px solid var(--border-light);
|
|
453
|
+
margin-bottom: 0.25rem;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
.attachment-chip {
|
|
457
|
+
display: flex;
|
|
458
|
+
align-items: center;
|
|
459
|
+
gap: 0.4rem;
|
|
460
|
+
background: var(--bg-subtle);
|
|
461
|
+
border: 1px solid var(--border-main);
|
|
462
|
+
padding: 0.25rem 0.6rem;
|
|
463
|
+
border-radius: var(--radius-xs);
|
|
464
|
+
font-size: 0.75rem;
|
|
465
|
+
font-family: var(--font-mono);
|
|
466
|
+
color: var(--text-primary);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
.attachment-chip img {
|
|
470
|
+
width: 18px;
|
|
471
|
+
height: 18px;
|
|
472
|
+
object-fit: cover;
|
|
473
|
+
border-radius: 2px;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.attachment-chip .remove-chip-btn {
|
|
477
|
+
background: transparent;
|
|
478
|
+
border: none;
|
|
479
|
+
color: var(--text-tertiary);
|
|
480
|
+
font-weight: 700;
|
|
481
|
+
cursor: pointer;
|
|
482
|
+
padding: 0 0.2rem;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.attachment-chip .remove-chip-btn:hover {
|
|
486
|
+
color: var(--accent-warning);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/* Prompt Toolkit Autocomplete Palette */
|
|
490
|
+
.prompt-toolkit-palette {
|
|
491
|
+
position: absolute;
|
|
492
|
+
bottom: calc(100% + 0.5rem);
|
|
493
|
+
left: 0;
|
|
494
|
+
right: 0;
|
|
495
|
+
background: var(--bg-card);
|
|
496
|
+
border: 1px solid var(--border-main);
|
|
497
|
+
border-radius: var(--radius-md);
|
|
498
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
|
|
499
|
+
max-height: 280px;
|
|
500
|
+
overflow-y: auto;
|
|
501
|
+
display: flex;
|
|
502
|
+
flex-direction: column;
|
|
503
|
+
z-index: 100;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.palette-header {
|
|
507
|
+
padding: 0.5rem 0.9rem;
|
|
508
|
+
background: var(--bg-sidebar);
|
|
509
|
+
border-bottom: 1px solid var(--border-main);
|
|
510
|
+
font-size: 0.7rem;
|
|
511
|
+
text-transform: uppercase;
|
|
512
|
+
letter-spacing: 0.05em;
|
|
513
|
+
font-weight: 700;
|
|
514
|
+
color: var(--text-tertiary);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
.palette-list {
|
|
518
|
+
display: flex;
|
|
519
|
+
flex-direction: column;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
.palette-item {
|
|
523
|
+
display: flex;
|
|
524
|
+
align-items: center;
|
|
525
|
+
justify-content: space-between;
|
|
526
|
+
padding: 0.6rem 1rem;
|
|
527
|
+
cursor: pointer;
|
|
528
|
+
border-bottom: 1px solid var(--border-light);
|
|
529
|
+
transition: all 0.1s ease;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
.palette-item:last-child {
|
|
533
|
+
border-bottom: none;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
.palette-item.active,
|
|
537
|
+
.palette-item:hover {
|
|
538
|
+
background: var(--bg-subtle);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
.palette-name {
|
|
542
|
+
font-family: var(--font-mono);
|
|
543
|
+
font-size: 0.84rem;
|
|
544
|
+
font-weight: 600;
|
|
545
|
+
color: var(--text-primary);
|
|
546
|
+
min-width: 140px;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
.palette-desc {
|
|
550
|
+
font-size: 0.78rem;
|
|
551
|
+
color: var(--text-secondary);
|
|
552
|
+
flex: 1;
|
|
553
|
+
margin-left: 1rem;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
.palette-tag {
|
|
557
|
+
font-size: 0.7rem;
|
|
558
|
+
color: var(--text-tertiary);
|
|
559
|
+
font-family: var(--font-mono);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
.hidden {
|
|
563
|
+
display: none !important;
|
|
564
|
+
}
|
|
565
|
+
|
|
416
566
|
.input-container textarea {
|
|
417
567
|
background: transparent;
|
|
418
568
|
border: none;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/desktop/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/desktop/server.ts"],"names":[],"mappings":"AAoCA,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,IAAI,CAAQ;IACpB,OAAO,CAAC,WAAW,CAAa;;IAMnB,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAqExB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAUpB,SAAS;WAyPH,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;CAyBnD"}
|
package/dist/desktop/server.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import http from 'http';
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
4
5
|
import { fileURLToPath } from 'url';
|
|
5
6
|
import { spawn } from 'child_process';
|
|
6
7
|
import { configManager } from '../core/config.js';
|
|
@@ -12,6 +13,8 @@ import { memoryManager } from '../memory/manager.js';
|
|
|
12
13
|
import { SkillSynthesizer } from '../core/skillSynthesizer.js';
|
|
13
14
|
import { getAllActiveTools } from '../core/tools.js';
|
|
14
15
|
import { getAvailableModels } from '../providers/models.js';
|
|
16
|
+
import { PROMPT_TOOLKIT_COMMANDS } from '../cli/promptToolkit.js';
|
|
17
|
+
import { FilePickerService } from '../cli/dialogs/filePicker.js';
|
|
15
18
|
import chalk from 'chalk';
|
|
16
19
|
const __filename = fileURLToPath(import.meta.url);
|
|
17
20
|
const __dirname = path.dirname(__filename);
|
|
@@ -52,7 +55,7 @@ export class DesktopServer {
|
|
|
52
55
|
const pathname = url.pathname;
|
|
53
56
|
// 1. API Endpoints
|
|
54
57
|
if (pathname.startsWith('/api/')) {
|
|
55
|
-
await this.handleApi(pathname, req, res);
|
|
58
|
+
await this.handleApi(pathname, url, req, res);
|
|
56
59
|
return;
|
|
57
60
|
}
|
|
58
61
|
// 2. Static File Serving
|
|
@@ -68,6 +71,9 @@ export class DesktopServer {
|
|
|
68
71
|
'.json': 'application/json',
|
|
69
72
|
'.png': 'image/png',
|
|
70
73
|
'.svg': 'image/svg+xml',
|
|
74
|
+
'.jpg': 'image/jpeg',
|
|
75
|
+
'.jpeg': 'image/jpeg',
|
|
76
|
+
'.webp': 'image/webp',
|
|
71
77
|
};
|
|
72
78
|
try {
|
|
73
79
|
const data = fs.readFileSync(filePath);
|
|
@@ -103,7 +109,7 @@ export class DesktopServer {
|
|
|
103
109
|
}
|
|
104
110
|
});
|
|
105
111
|
}
|
|
106
|
-
async handleApi(pathname, req, res) {
|
|
112
|
+
async handleApi(pathname, url, req, res) {
|
|
107
113
|
const config = configManager.get();
|
|
108
114
|
// GET /api/status
|
|
109
115
|
if (pathname === '/api/status' && req.method === 'GET') {
|
|
@@ -115,6 +121,20 @@ export class DesktopServer {
|
|
|
115
121
|
}));
|
|
116
122
|
return;
|
|
117
123
|
}
|
|
124
|
+
// GET /api/commands (Prompt Toolkit Slash Commands)
|
|
125
|
+
if (pathname === '/api/commands' && req.method === 'GET') {
|
|
126
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
127
|
+
res.end(JSON.stringify({ commands: PROMPT_TOOLKIT_COMMANDS }));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
// GET /api/files (Prompt Toolkit File Browser for @)
|
|
131
|
+
if (pathname === '/api/files' && req.method === 'GET') {
|
|
132
|
+
const query = url.searchParams.get('query') || '';
|
|
133
|
+
const { currentDir, items } = FilePickerService.listDirectory(config.workingDir, query);
|
|
134
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
135
|
+
res.end(JSON.stringify({ currentDir, items }));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
118
138
|
// GET /api/models
|
|
119
139
|
if (pathname === '/api/models' && req.method === 'GET') {
|
|
120
140
|
const models = await getAvailableModels(config);
|
|
@@ -153,6 +173,33 @@ export class DesktopServer {
|
|
|
153
173
|
req.on('end', async () => {
|
|
154
174
|
try {
|
|
155
175
|
const payload = body ? JSON.parse(body) : {};
|
|
176
|
+
// POST /api/upload (File and Image Uploader)
|
|
177
|
+
if (pathname === '/api/upload' && req.method === 'POST') {
|
|
178
|
+
const fileName = payload.fileName || `upload_${Date.now()}.bin`;
|
|
179
|
+
const fileData = payload.data || ''; // Base64 or text data
|
|
180
|
+
const fileType = payload.fileType || 'text/plain';
|
|
181
|
+
const uploadDir = path.join(os.homedir(), '.antri', 'attachments');
|
|
182
|
+
if (!fs.existsSync(uploadDir)) {
|
|
183
|
+
fs.mkdirSync(uploadDir, { recursive: true });
|
|
184
|
+
}
|
|
185
|
+
const savedPath = path.join(uploadDir, fileName);
|
|
186
|
+
if (fileData.startsWith('data:')) {
|
|
187
|
+
const base64Data = fileData.split(',')[1];
|
|
188
|
+
fs.writeFileSync(savedPath, Buffer.from(base64Data, 'base64'));
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
fs.writeFileSync(savedPath, fileData, 'utf-8');
|
|
192
|
+
}
|
|
193
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
194
|
+
res.end(JSON.stringify({
|
|
195
|
+
success: true,
|
|
196
|
+
filePath: savedPath,
|
|
197
|
+
fileName,
|
|
198
|
+
fileType,
|
|
199
|
+
isImage: fileType.startsWith('image/'),
|
|
200
|
+
}));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
156
203
|
// POST /api/chat (SSE Streaming)
|
|
157
204
|
if (pathname === '/api/chat' && req.method === 'POST') {
|
|
158
205
|
res.writeHead(200, {
|
|
@@ -262,7 +309,7 @@ export class DesktopServer {
|
|
|
262
309
|
// POST /api/profile/save
|
|
263
310
|
if (pathname === '/api/profile/save' && req.method === 'POST') {
|
|
264
311
|
const active = profileManager.getActiveProfileName();
|
|
265
|
-
const filePath = path.join(
|
|
312
|
+
const filePath = path.join(os.homedir(), '.antri', 'profiles', `${active}.md`);
|
|
266
313
|
fs.writeFileSync(filePath, payload.content, 'utf-8');
|
|
267
314
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
268
315
|
res.end(JSON.stringify({ success: true }));
|
|
@@ -289,7 +336,7 @@ export class DesktopServer {
|
|
|
289
336
|
const port = await desktop.start();
|
|
290
337
|
const url = `http://localhost:${port}`;
|
|
291
338
|
console.log();
|
|
292
|
-
console.log(chalk.bgHex('#7c3aed').bold.white('
|
|
339
|
+
console.log(chalk.bgHex('#7c3aed').bold.white(' ANTRI DESKTOP APP LAUNCHED '));
|
|
293
340
|
console.log(chalk.hex('#a5b4fc')(`Local Desktop Control Plane running at: ${chalk.bold.cyan(url)}`));
|
|
294
341
|
console.log(chalk.hex('#64748b')('Shared Memory, Thinking Profiles, Skills & Providers actively synced with CLI.'));
|
|
295
342
|
console.log();
|
|
@@ -297,7 +344,6 @@ export class DesktopServer {
|
|
|
297
344
|
const platform = process.platform;
|
|
298
345
|
try {
|
|
299
346
|
if (platform === 'win32') {
|
|
300
|
-
// Try launching Microsoft Edge or Chrome in standalone App Mode window
|
|
301
347
|
spawn('cmd.exe', ['/c', 'start', 'msedge', `--app=${url}`], { detached: true, stdio: 'ignore' });
|
|
302
348
|
}
|
|
303
349
|
else if (platform === 'darwin') {
|