@agent-link/server 0.1.53 → 0.1.55
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/web/app.js +72 -4
- package/web/modules/connection.js +4 -0
- package/web/modules/sidebar.js +67 -0
- package/web/style.css +167 -0
package/package.json
CHANGED
package/web/app.js
CHANGED
|
@@ -64,6 +64,14 @@ const App = {
|
|
|
64
64
|
const folderPickerLoading = ref(false);
|
|
65
65
|
const folderPickerSelected = ref('');
|
|
66
66
|
|
|
67
|
+
// Delete confirmation dialog state
|
|
68
|
+
const deleteConfirmOpen = ref(false);
|
|
69
|
+
const deleteConfirmTitle = ref('');
|
|
70
|
+
|
|
71
|
+
// Working directory history state
|
|
72
|
+
const workDirHistory = ref([]);
|
|
73
|
+
const workDirHistoryOpen = ref(false);
|
|
74
|
+
|
|
67
75
|
// File attachment state
|
|
68
76
|
const attachments = ref([]);
|
|
69
77
|
const fileInputRef = ref(null);
|
|
@@ -136,6 +144,8 @@ const App = {
|
|
|
136
144
|
loadingSessions, loadingHistory, workDir, visibleLimit,
|
|
137
145
|
folderPickerOpen, folderPickerPath, folderPickerEntries,
|
|
138
146
|
folderPickerLoading, folderPickerSelected, streaming,
|
|
147
|
+
deleteConfirmOpen, deleteConfirmTitle,
|
|
148
|
+
workDirHistory, workDirHistoryOpen,
|
|
139
149
|
});
|
|
140
150
|
|
|
141
151
|
const { connect, wsSend, closeWs } = createConnection({
|
|
@@ -268,6 +278,16 @@ const App = {
|
|
|
268
278
|
folderPickerEnter: sidebar.folderPickerEnter,
|
|
269
279
|
folderPickerGoToPath: sidebar.folderPickerGoToPath,
|
|
270
280
|
confirmFolderPicker: sidebar.confirmFolderPicker,
|
|
281
|
+
// Delete session
|
|
282
|
+
deleteConfirmOpen, deleteConfirmTitle,
|
|
283
|
+
deleteSession: sidebar.deleteSession,
|
|
284
|
+
confirmDeleteSession: sidebar.confirmDeleteSession,
|
|
285
|
+
cancelDeleteSession: sidebar.cancelDeleteSession,
|
|
286
|
+
// Working directory history
|
|
287
|
+
workDirHistory, workDirHistoryOpen,
|
|
288
|
+
selectWorkDirHistory: sidebar.selectWorkDirHistory,
|
|
289
|
+
removeWorkDirHistory: sidebar.removeWorkDirHistory,
|
|
290
|
+
toggleWorkDirHistory: sidebar.toggleWorkDirHistory,
|
|
271
291
|
// File attachments
|
|
272
292
|
attachments, fileInputRef, dragOver,
|
|
273
293
|
triggerFileInput: fileAttach.triggerFileInput,
|
|
@@ -325,11 +345,33 @@ const App = {
|
|
|
325
345
|
</div>
|
|
326
346
|
<div class="sidebar-workdir-header">
|
|
327
347
|
<div class="sidebar-workdir-label">Working Directory</div>
|
|
328
|
-
<
|
|
329
|
-
<
|
|
330
|
-
|
|
348
|
+
<div class="sidebar-workdir-actions">
|
|
349
|
+
<button class="sidebar-change-dir-btn" @click="toggleWorkDirHistory" title="Recent directories" :disabled="isProcessing" v-if="workDirHistory.length > 1">
|
|
350
|
+
<svg viewBox="0 0 24 24" width="12" height="12"><path fill="currentColor" d="M13 3a9 9 0 0 0-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42A8.954 8.954 0 0 0 13 21a9 9 0 0 0 0-18zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z"/></svg>
|
|
351
|
+
</button>
|
|
352
|
+
<button class="sidebar-change-dir-btn" @click="openFolderPicker" title="Change working directory" :disabled="isProcessing">
|
|
353
|
+
<svg viewBox="0 0 24 24" width="12" height="12"><path fill="currentColor" d="M10 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/></svg>
|
|
354
|
+
</button>
|
|
355
|
+
</div>
|
|
331
356
|
</div>
|
|
332
357
|
<div class="sidebar-workdir-path" :title="workDir">{{ workDir }}</div>
|
|
358
|
+
<!-- Workdir history dropdown -->
|
|
359
|
+
<div v-if="workDirHistoryOpen && workDirHistory.length > 1" class="workdir-history-dropdown">
|
|
360
|
+
<div
|
|
361
|
+
v-for="dir in workDirHistory" :key="dir"
|
|
362
|
+
:class="['workdir-history-item', { active: dir === workDir }]"
|
|
363
|
+
@click="selectWorkDirHistory(dir)"
|
|
364
|
+
:title="dir"
|
|
365
|
+
>
|
|
366
|
+
<span class="workdir-history-path">{{ dir }}</span>
|
|
367
|
+
<button
|
|
368
|
+
v-if="dir !== workDir"
|
|
369
|
+
class="workdir-history-remove"
|
|
370
|
+
@click.stop="removeWorkDirHistory(dir)"
|
|
371
|
+
title="Remove from history"
|
|
372
|
+
>×</button>
|
|
373
|
+
</div>
|
|
374
|
+
</div>
|
|
333
375
|
</div>
|
|
334
376
|
</div>
|
|
335
377
|
|
|
@@ -362,7 +404,17 @@ const App = {
|
|
|
362
404
|
:title="s.preview"
|
|
363
405
|
>
|
|
364
406
|
<div class="session-title">{{ s.title }}</div>
|
|
365
|
-
<div class="session-meta">
|
|
407
|
+
<div class="session-meta">
|
|
408
|
+
<span>{{ formatRelativeTime(s.lastModified) }}</span>
|
|
409
|
+
<button
|
|
410
|
+
v-if="currentClaudeSessionId !== s.sessionId"
|
|
411
|
+
class="session-delete-btn"
|
|
412
|
+
@click.stop="deleteSession(s)"
|
|
413
|
+
title="Delete session"
|
|
414
|
+
>
|
|
415
|
+
<svg viewBox="0 0 24 24" width="12" height="12"><path fill="currentColor" d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></svg>
|
|
416
|
+
</button>
|
|
417
|
+
</div>
|
|
366
418
|
</div>
|
|
367
419
|
</div>
|
|
368
420
|
</div>
|
|
@@ -614,6 +666,22 @@ const App = {
|
|
|
614
666
|
</div>
|
|
615
667
|
</div>
|
|
616
668
|
</div>
|
|
669
|
+
|
|
670
|
+
<!-- Delete Session Confirmation Dialog -->
|
|
671
|
+
<div class="folder-picker-overlay" v-if="deleteConfirmOpen" @click.self="cancelDeleteSession">
|
|
672
|
+
<div class="delete-confirm-dialog">
|
|
673
|
+
<div class="delete-confirm-header">Delete Session</div>
|
|
674
|
+
<div class="delete-confirm-body">
|
|
675
|
+
<p>Are you sure you want to delete this session?</p>
|
|
676
|
+
<p class="delete-confirm-title">{{ deleteConfirmTitle }}</p>
|
|
677
|
+
<p class="delete-confirm-warning">This action cannot be undone.</p>
|
|
678
|
+
</div>
|
|
679
|
+
<div class="delete-confirm-footer">
|
|
680
|
+
<button class="folder-picker-cancel" @click="cancelDeleteSession">Cancel</button>
|
|
681
|
+
<button class="delete-confirm-btn" @click="confirmDeleteSession">Delete</button>
|
|
682
|
+
</div>
|
|
683
|
+
</div>
|
|
684
|
+
</div>
|
|
617
685
|
</div>
|
|
618
686
|
`
|
|
619
687
|
};
|
|
@@ -145,6 +145,7 @@ export function createConnection(deps) {
|
|
|
145
145
|
hostname.value = msg.agent.hostname || '';
|
|
146
146
|
workDir.value = msg.agent.workDir;
|
|
147
147
|
agentVersion.value = msg.agent.version || '';
|
|
148
|
+
sidebar.addToWorkDirHistory(msg.agent.workDir);
|
|
148
149
|
const savedDir = localStorage.getItem('agentlink-workdir');
|
|
149
150
|
if (savedDir && savedDir !== msg.agent.workDir) {
|
|
150
151
|
wsSend({ type: 'change_workdir', workDir: savedDir });
|
|
@@ -257,6 +258,8 @@ export function createConnection(deps) {
|
|
|
257
258
|
} else if (msg.type === 'sessions_list') {
|
|
258
259
|
historySessions.value = msg.sessions || [];
|
|
259
260
|
loadingSessions.value = false;
|
|
261
|
+
} else if (msg.type === 'session_deleted') {
|
|
262
|
+
historySessions.value = historySessions.value.filter(s => s.sessionId !== msg.sessionId);
|
|
260
263
|
} else if (msg.type === 'conversation_resumed') {
|
|
261
264
|
currentClaudeSessionId.value = msg.claudeSessionId;
|
|
262
265
|
if (msg.history && Array.isArray(msg.history)) {
|
|
@@ -339,6 +342,7 @@ export function createConnection(deps) {
|
|
|
339
342
|
} else if (msg.type === 'workdir_changed') {
|
|
340
343
|
workDir.value = msg.workDir;
|
|
341
344
|
localStorage.setItem('agentlink-workdir', msg.workDir);
|
|
345
|
+
sidebar.addToWorkDirHistory(msg.workDir);
|
|
342
346
|
messages.value = [];
|
|
343
347
|
toolMsgMap.clear();
|
|
344
348
|
visibleLimit.value = 50;
|
package/web/modules/sidebar.js
CHANGED
|
@@ -31,6 +31,44 @@ export function createSidebar(deps) {
|
|
|
31
31
|
folderPickerLoading, folderPickerSelected, streaming,
|
|
32
32
|
} = deps;
|
|
33
33
|
|
|
34
|
+
// ── Working directory history ──
|
|
35
|
+
|
|
36
|
+
const WORKDIR_HISTORY_KEY = 'agentlink-workdir-history';
|
|
37
|
+
const MAX_HISTORY = 10;
|
|
38
|
+
const workDirHistory = deps.workDirHistory;
|
|
39
|
+
const workDirHistoryOpen = deps.workDirHistoryOpen;
|
|
40
|
+
|
|
41
|
+
// Load from localStorage on init
|
|
42
|
+
try {
|
|
43
|
+
const saved = localStorage.getItem(WORKDIR_HISTORY_KEY);
|
|
44
|
+
if (saved) workDirHistory.value = JSON.parse(saved);
|
|
45
|
+
} catch { /* ignore */ }
|
|
46
|
+
|
|
47
|
+
function addToWorkDirHistory(dir) {
|
|
48
|
+
if (!dir) return;
|
|
49
|
+
const list = workDirHistory.value.filter(d => d !== dir);
|
|
50
|
+
list.unshift(dir);
|
|
51
|
+
if (list.length > MAX_HISTORY) list.length = MAX_HISTORY;
|
|
52
|
+
workDirHistory.value = list;
|
|
53
|
+
localStorage.setItem(WORKDIR_HISTORY_KEY, JSON.stringify(list));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function selectWorkDirHistory(dir) {
|
|
57
|
+
workDirHistoryOpen.value = false;
|
|
58
|
+
if (dir === workDir.value) return;
|
|
59
|
+
wsSend({ type: 'change_workdir', workDir: dir });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function removeWorkDirHistory(dir) {
|
|
63
|
+
const list = workDirHistory.value.filter(d => d !== dir);
|
|
64
|
+
workDirHistory.value = list;
|
|
65
|
+
localStorage.setItem(WORKDIR_HISTORY_KEY, JSON.stringify(list));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function toggleWorkDirHistory() {
|
|
69
|
+
workDirHistoryOpen.value = !workDirHistoryOpen.value;
|
|
70
|
+
}
|
|
71
|
+
|
|
34
72
|
// ── Session management ──
|
|
35
73
|
|
|
36
74
|
function requestSessionList() {
|
|
@@ -79,6 +117,33 @@ export function createSidebar(deps) {
|
|
|
79
117
|
sidebarOpen.value = !sidebarOpen.value;
|
|
80
118
|
}
|
|
81
119
|
|
|
120
|
+
// ── Delete session ──
|
|
121
|
+
|
|
122
|
+
/** Session pending delete confirmation (null = dialog closed) */
|
|
123
|
+
let pendingDeleteSession = null;
|
|
124
|
+
const deleteConfirmOpen = deps.deleteConfirmOpen;
|
|
125
|
+
const deleteConfirmTitle = deps.deleteConfirmTitle;
|
|
126
|
+
|
|
127
|
+
function deleteSession(session) {
|
|
128
|
+
if (isProcessing.value) return;
|
|
129
|
+
if (currentClaudeSessionId.value === session.sessionId) return; // guard
|
|
130
|
+
pendingDeleteSession = session;
|
|
131
|
+
deleteConfirmTitle.value = session.title || session.sessionId.slice(0, 8);
|
|
132
|
+
deleteConfirmOpen.value = true;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function confirmDeleteSession() {
|
|
136
|
+
if (!pendingDeleteSession) return;
|
|
137
|
+
wsSend({ type: 'delete_session', sessionId: pendingDeleteSession.sessionId });
|
|
138
|
+
deleteConfirmOpen.value = false;
|
|
139
|
+
pendingDeleteSession = null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function cancelDeleteSession() {
|
|
143
|
+
deleteConfirmOpen.value = false;
|
|
144
|
+
pendingDeleteSession = null;
|
|
145
|
+
}
|
|
146
|
+
|
|
82
147
|
// ── Folder picker ──
|
|
83
148
|
|
|
84
149
|
function openFolderPicker() {
|
|
@@ -179,6 +244,8 @@ export function createSidebar(deps) {
|
|
|
179
244
|
|
|
180
245
|
return {
|
|
181
246
|
requestSessionList, resumeSession, newConversation, toggleSidebar,
|
|
247
|
+
deleteSession, confirmDeleteSession, cancelDeleteSession,
|
|
248
|
+
addToWorkDirHistory, selectWorkDirHistory, removeWorkDirHistory, toggleWorkDirHistory,
|
|
182
249
|
openFolderPicker, folderPickerNavigateUp, folderPickerSelectItem,
|
|
183
250
|
folderPickerEnter, folderPickerGoToPath, confirmFolderPicker,
|
|
184
251
|
groupedSessions,
|
package/web/style.css
CHANGED
|
@@ -438,6 +438,100 @@ body {
|
|
|
438
438
|
font-size: 0.7rem;
|
|
439
439
|
color: var(--text-secondary);
|
|
440
440
|
margin-top: 2px;
|
|
441
|
+
display: flex;
|
|
442
|
+
align-items: center;
|
|
443
|
+
justify-content: space-between;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
.session-delete-btn {
|
|
447
|
+
display: none;
|
|
448
|
+
align-items: center;
|
|
449
|
+
justify-content: center;
|
|
450
|
+
width: 20px;
|
|
451
|
+
height: 20px;
|
|
452
|
+
background: none;
|
|
453
|
+
border: none;
|
|
454
|
+
border-radius: 4px;
|
|
455
|
+
color: var(--text-secondary);
|
|
456
|
+
cursor: pointer;
|
|
457
|
+
padding: 0;
|
|
458
|
+
transition: color 0.15s, background 0.15s;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
.session-item:hover .session-delete-btn {
|
|
462
|
+
display: flex;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.session-delete-btn:hover {
|
|
466
|
+
color: var(--error);
|
|
467
|
+
background: rgba(239, 68, 68, 0.1);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/* ── Delete confirmation dialog ── */
|
|
471
|
+
.delete-confirm-dialog {
|
|
472
|
+
width: 360px;
|
|
473
|
+
background: var(--bg-secondary);
|
|
474
|
+
border: 1px solid var(--border);
|
|
475
|
+
border-radius: 12px;
|
|
476
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
.delete-confirm-header {
|
|
480
|
+
padding: 12px 16px;
|
|
481
|
+
font-size: 0.95rem;
|
|
482
|
+
font-weight: 600;
|
|
483
|
+
border-bottom: 1px solid var(--border);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
.delete-confirm-body {
|
|
487
|
+
padding: 16px;
|
|
488
|
+
font-size: 0.88rem;
|
|
489
|
+
line-height: 1.5;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.delete-confirm-body p {
|
|
493
|
+
margin-bottom: 6px;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.delete-confirm-title {
|
|
497
|
+
font-weight: 500;
|
|
498
|
+
color: var(--text-primary);
|
|
499
|
+
overflow: hidden;
|
|
500
|
+
text-overflow: ellipsis;
|
|
501
|
+
white-space: nowrap;
|
|
502
|
+
padding: 6px 10px;
|
|
503
|
+
background: var(--bg-tertiary);
|
|
504
|
+
border-radius: 6px;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
.delete-confirm-warning {
|
|
508
|
+
font-size: 0.78rem;
|
|
509
|
+
color: var(--text-secondary);
|
|
510
|
+
margin-top: 4px;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
.delete-confirm-footer {
|
|
514
|
+
padding: 10px 16px;
|
|
515
|
+
display: flex;
|
|
516
|
+
justify-content: flex-end;
|
|
517
|
+
gap: 8px;
|
|
518
|
+
border-top: 1px solid var(--border);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
.delete-confirm-btn {
|
|
522
|
+
padding: 6px 20px;
|
|
523
|
+
background: var(--error);
|
|
524
|
+
color: #fff;
|
|
525
|
+
border: none;
|
|
526
|
+
border-radius: 8px;
|
|
527
|
+
font-size: 0.85rem;
|
|
528
|
+
font-weight: 600;
|
|
529
|
+
cursor: pointer;
|
|
530
|
+
transition: background 0.15s;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
.delete-confirm-btn:hover {
|
|
534
|
+
background: #dc2626;
|
|
441
535
|
}
|
|
442
536
|
|
|
443
537
|
/* ── Chat area (message list + input) ── */
|
|
@@ -1449,6 +1543,79 @@ body {
|
|
|
1449
1543
|
cursor: not-allowed;
|
|
1450
1544
|
}
|
|
1451
1545
|
|
|
1546
|
+
.sidebar-workdir-actions {
|
|
1547
|
+
display: flex;
|
|
1548
|
+
gap: 4px;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
/* ── Workdir history dropdown ── */
|
|
1552
|
+
.workdir-history-dropdown {
|
|
1553
|
+
margin-top: 6px;
|
|
1554
|
+
border: 1px solid var(--border);
|
|
1555
|
+
border-radius: 6px;
|
|
1556
|
+
background: var(--bg-secondary);
|
|
1557
|
+
max-height: 200px;
|
|
1558
|
+
overflow-y: auto;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
.workdir-history-item {
|
|
1562
|
+
display: flex;
|
|
1563
|
+
align-items: center;
|
|
1564
|
+
padding: 6px 8px;
|
|
1565
|
+
font-size: 0.75rem;
|
|
1566
|
+
font-family: 'SF Mono', 'Fira Code', Consolas, monospace;
|
|
1567
|
+
color: var(--text-primary);
|
|
1568
|
+
cursor: pointer;
|
|
1569
|
+
transition: background 0.1s;
|
|
1570
|
+
gap: 4px;
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
.workdir-history-item:hover {
|
|
1574
|
+
background: var(--bg-tertiary);
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
.workdir-history-item.active {
|
|
1578
|
+
color: var(--accent);
|
|
1579
|
+
font-weight: 600;
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
.workdir-history-item + .workdir-history-item {
|
|
1583
|
+
border-top: 1px solid var(--border);
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
.workdir-history-path {
|
|
1587
|
+
flex: 1;
|
|
1588
|
+
overflow: hidden;
|
|
1589
|
+
text-overflow: ellipsis;
|
|
1590
|
+
white-space: nowrap;
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
.workdir-history-remove {
|
|
1594
|
+
flex-shrink: 0;
|
|
1595
|
+
display: none;
|
|
1596
|
+
align-items: center;
|
|
1597
|
+
justify-content: center;
|
|
1598
|
+
width: 18px;
|
|
1599
|
+
height: 18px;
|
|
1600
|
+
background: none;
|
|
1601
|
+
border: none;
|
|
1602
|
+
border-radius: 3px;
|
|
1603
|
+
color: var(--text-secondary);
|
|
1604
|
+
font-size: 0.85rem;
|
|
1605
|
+
cursor: pointer;
|
|
1606
|
+
padding: 0;
|
|
1607
|
+
line-height: 1;
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
.workdir-history-item:hover .workdir-history-remove {
|
|
1611
|
+
display: flex;
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
.workdir-history-remove:hover {
|
|
1615
|
+
color: var(--error);
|
|
1616
|
+
background: rgba(239, 68, 68, 0.1);
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1452
1619
|
/* ── Folder Picker Modal ── */
|
|
1453
1620
|
.folder-picker-overlay {
|
|
1454
1621
|
position: fixed;
|