agentgui 1.0.755 → 1.0.757

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/lib/db-queries.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { createACPQueries } from '../acp-queries.js';
2
-
3
- export function createQueries(db, prep, generateId) {
4
- return {
5
- _db: db,
2
+
3
+ export function createQueries(db, prep, generateId) {
4
+ return {
5
+ _db: db,
6
6
  createConversation(agentType, title = null, workingDirectory = null, model = null, subAgent = null) {
7
7
  const id = generateId('conv');
8
8
  const now = Date.now();
@@ -36,14 +36,33 @@ export function createQueries(db, prep, generateId) {
36
36
 
37
37
  getConversationsList() {
38
38
  const stmt = prep(
39
- 'SELECT id, agentId, title, agentType, created_at, updated_at, messageCount, workingDirectory, isStreaming, model, subAgent, pinned FROM conversations WHERE status != ? ORDER BY pinned DESC, updated_at DESC'
39
+ 'SELECT id, agentId, title, agentType, created_at, updated_at, messageCount, workingDirectory, isStreaming, model, subAgent, pinned FROM conversations WHERE status NOT IN (?, ?) ORDER BY pinned DESC, updated_at DESC'
40
40
  );
41
- return stmt.all('deleted');
41
+ return stmt.all('deleted', 'archived');
42
42
  },
43
43
 
44
44
  getConversations() {
45
- const stmt = prep('SELECT * FROM conversations WHERE status != ? ORDER BY pinned DESC, updated_at DESC');
46
- return stmt.all('deleted');
45
+ const stmt = prep('SELECT * FROM conversations WHERE status NOT IN (?, ?) ORDER BY pinned DESC, updated_at DESC');
46
+ return stmt.all('deleted', 'archived');
47
+ },
48
+
49
+ getArchivedConversations() {
50
+ const stmt = prep('SELECT id, agentId, title, agentType, created_at, updated_at, messageCount, workingDirectory, model, subAgent FROM conversations WHERE status = ? ORDER BY updated_at DESC');
51
+ return stmt.all('archived');
52
+ },
53
+
54
+ archiveConversation(id) {
55
+ const conv = this.getConversation(id);
56
+ if (!conv) return null;
57
+ prep('UPDATE conversations SET status = ?, updated_at = ? WHERE id = ?').run('archived', Date.now(), id);
58
+ return this.getConversation(id);
59
+ },
60
+
61
+ restoreConversation(id) {
62
+ const conv = this.getConversation(id);
63
+ if (!conv) return null;
64
+ prep('UPDATE conversations SET status = ?, updated_at = ? WHERE id = ?').run('active', Date.now(), id);
65
+ return this.getConversation(id);
47
66
  },
48
67
 
49
68
  updateConversation(id, data) {
@@ -1336,5 +1355,5 @@ export function createQueries(db, prep, generateId) {
1336
1355
 
1337
1356
  // ============ ACP-COMPATIBLE QUERIES ============
1338
1357
  ...createACPQueries(db, prep)
1339
- };
1340
- }
1358
+ };
1359
+ }
@@ -143,6 +143,22 @@ export function register(router, deps) {
143
143
  return { markdown: md, title: conv.title };
144
144
  });
145
145
 
146
+ router.handle('conv.import', (p) => {
147
+ if (!p.conversation || !p.messages) throw Object.assign(new Error('Missing conversation or messages'), { code: 400 });
148
+ const src = p.conversation;
149
+ const conv = queries.createConversation(
150
+ src.agentId || src.agentType || 'claude-code',
151
+ src.title || 'Imported Conversation',
152
+ src.workingDirectory || null,
153
+ src.model || null
154
+ );
155
+ for (const msg of p.messages) {
156
+ queries.createMessage(conv.id, msg.role || 'user', msg.content || '');
157
+ }
158
+ broadcastSync({ type: 'conversation_created', conversation: queries.getConversation(conv.id) });
159
+ return { conversation: queries.getConversation(conv.id), importedMessages: p.messages.length };
160
+ });
161
+
146
162
  router.handle('conv.sync', (p) => {
147
163
  const conv = queries.getConversation(p.id);
148
164
  if (!conv) notFound();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.755",
3
+ "version": "1.0.757",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "electron/main.js",
package/server.js CHANGED
@@ -601,6 +601,29 @@ const server = http.createServer(async (req, res) => {
601
601
  }
602
602
  }
603
603
 
604
+ if (pathOnly === '/api/conversations/archived' && req.method === 'GET') {
605
+ sendJSON(req, res, 200, { conversations: queries.getArchivedConversations() });
606
+ return;
607
+ }
608
+
609
+ const archiveMatch = pathOnly.match(/^\/api\/conversations\/([^/]+)\/archive$/);
610
+ if (archiveMatch && req.method === 'POST') {
611
+ const conv = queries.archiveConversation(archiveMatch[1]);
612
+ if (!conv) { sendJSON(req, res, 404, { error: 'Not found' }); return; }
613
+ broadcastSync({ type: 'conversation_deleted', conversationId: archiveMatch[1] });
614
+ sendJSON(req, res, 200, { conversation: conv });
615
+ return;
616
+ }
617
+
618
+ const restoreMatch = pathOnly.match(/^\/api\/conversations\/([^/]+)\/restore$/);
619
+ if (restoreMatch && req.method === 'POST') {
620
+ const conv = queries.restoreConversation(restoreMatch[1]);
621
+ if (!conv) { sendJSON(req, res, 404, { error: 'Not found' }); return; }
622
+ broadcastSync({ type: 'conversation_created', conversation: conv });
623
+ sendJSON(req, res, 200, { conversation: conv });
624
+ return;
625
+ }
626
+
604
627
  const messagesMatch = pathOnly.match(/^\/api\/conversations\/([^/]+)\/messages$/);
605
628
  if (messagesMatch) {
606
629
  if (req.method === 'GET') {
@@ -275,7 +275,8 @@
275
275
  overflow: hidden;
276
276
  }
277
277
 
278
- .conversation-item-delete {
278
+ .conversation-item-delete,
279
+ .conversation-item-archive {
279
280
  flex-shrink: 0;
280
281
  width: 28px;
281
282
  height: 28px;
@@ -292,7 +293,8 @@
292
293
  transition: all 0.15s;
293
294
  }
294
295
 
295
- .conversation-item:hover .conversation-item-delete {
296
+ .conversation-item:hover .conversation-item-delete,
297
+ .conversation-item:hover .conversation-item-archive {
296
298
  opacity: 1;
297
299
  }
298
300
 
@@ -301,11 +303,18 @@
301
303
  color: white;
302
304
  }
303
305
 
304
- .conversation-item.active .conversation-item-delete {
306
+ .conversation-item-archive:hover {
307
+ background-color: #f59e0b;
308
+ color: white;
309
+ }
310
+
311
+ .conversation-item.active .conversation-item-delete,
312
+ .conversation-item.active .conversation-item-archive {
305
313
  color: rgba(255,255,255,0.8);
306
314
  }
307
315
 
308
- .conversation-item.active .conversation-item-delete:hover {
316
+ .conversation-item.active .conversation-item-delete:hover,
317
+ .conversation-item.active .conversation-item-archive:hover {
309
318
  background-color: rgba(255,255,255,0.2);
310
319
  color: white;
311
320
  }
@@ -117,6 +117,12 @@ class ConversationManager {
117
117
 
118
118
  setupDelegatedListeners() {
119
119
  this.listEl.addEventListener('click', (e) => {
120
+ const archiveBtn = e.target.closest('[data-archive-conv]');
121
+ if (archiveBtn) {
122
+ e.stopPropagation();
123
+ this.archiveConversation(archiveBtn.dataset.archiveConv);
124
+ return;
125
+ }
120
126
  const deleteBtn = e.target.closest('[data-delete-conv]');
121
127
  if (deleteBtn) {
122
128
  e.stopPropagation();
@@ -477,6 +483,13 @@ class ConversationManager {
477
483
  h('div', { class: 'conversation-item-title' }, ...(badge ? [badge, title] : [title])),
478
484
  h('div', { class: 'conversation-item-meta' }, metaParts.join(' \u2022 '))
479
485
  ),
486
+ h('button', { class: 'conversation-item-archive', title: 'Archive conversation', 'data-archive-conv': conv.id },
487
+ h('svg', { width: '14', height: '14', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', 'stroke-width': '2' },
488
+ h('path', { d: 'M21 8v13H3V8' }),
489
+ h('path', { d: 'M1 3h22v5H1z' }),
490
+ h('path', { d: 'M10 12h4' })
491
+ )
492
+ ),
480
493
  h('button', { class: 'conversation-item-delete', title: 'Delete conversation', 'data-delete-conv': conv.id },
481
494
  h('svg', { width: '14', height: '14', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', 'stroke-width': '2' },
482
495
  h('polyline', { points: '3 6 5 6 21 6' }),
@@ -584,6 +597,16 @@ class ConversationManager {
584
597
  this.render();
585
598
  }
586
599
 
600
+ async archiveConversation(convId) {
601
+ try {
602
+ const resp = await fetch(`${window.__BASE_URL || ''}/api/conversations/${convId}/archive`, { method: 'POST' });
603
+ if (!resp.ok) return;
604
+ this.deleteConversation(convId);
605
+ } catch (e) {
606
+ console.error('[archive] Failed:', e.message);
607
+ }
608
+ }
609
+
587
610
  setupWebSocketListener() {
588
611
  window.addEventListener('ws-message', (event) => {
589
612
  const msg = event.detail;