agentgui 1.0.880 → 1.0.882

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/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## [Unreleased] - Clear All now soft-deletes conv rows to suppress auto-import
2
+
3
+ - `deleteAllConversations` was hard-deleting rows from the conversations table. Auto-import's skip check relies on `existingConv.status === 'deleted'` — after hard delete, existingConv is null, so the JSONL scanner re-imports everything the next poll. Visible symptom: Clear All appears to work, then the same conversations reappear.
4
+ - Fix: use `UPDATE conversations SET status='deleted'` (match individual `deleteConversation` behavior). Related data (chunks/events/sessions/messages/voice_cache/stream_updates) is still hard-deleted, and the JSONL project files are still wiped from `~/.claude/projects/`.
5
+ - Verified both paths end-to-end: HTTP `DELETE /api/conversations/:id` and WS `conv.del.all`. Added regression case in test.js.
6
+
7
+ ## [Unreleased] - fix stuck "live" indicators on conversations sidebar
8
+
9
+ - Symptom: conversations show streaming dot in sidebar even when no agent is running. Root cause: `routes-conversations.js GET /api/conversations` reconcile required BOTH `!activeExecutions.has(conv.id)` AND `!activeSessionConvIds.has(conv.id)` to clear `isStreaming`. If a session crashed hard (server killed mid-stream, agent process killed without finally running), the session row stayed at `status='active'` forever, keeping the sidebar live indicator on indefinitely until next server restart triggered `recoverStaleSessions`.
10
+ - Fix: trust `activeExecutions` map as ground truth. If `isStreaming=1` but no in-memory execution, set `isStreaming=0` AND mark any orphan 'active'/'pending' session for that conv as 'interrupted'. Self-heals on every list fetch — no restart needed.
11
+
1
12
  ## [Unreleased] - surface stream chunk persistence errors
2
13
 
3
14
  - lib/stream-event-handler.js: `queries.createChunk` failures were swallowed silently in the ACP streaming path. User would see live broadcast events but reload would lose all chunks. Now logs error with conv id, seq, block type for observability.
@@ -110,7 +110,7 @@ export function addDeleteQueries(q, db, prep, generateId) {
110
110
  prep('DELETE FROM voice_cache').run();
111
111
  prep('DELETE FROM sessions').run();
112
112
  prep('DELETE FROM messages').run();
113
- prep('DELETE FROM conversations').run();
113
+ prep("UPDATE conversations SET status = 'deleted', updated_at = ? WHERE status != 'deleted'").run(Date.now());
114
114
  });
115
115
 
116
116
  deleteAllStmt();
@@ -9,9 +9,18 @@ export function register(deps) {
9
9
 
10
10
  routes['GET /api/conversations'] = async (req, res) => {
11
11
  const conversations = queries.getConversationsList();
12
- const activeSessionConvIds = new Set(queries.getActiveSessionConversationIds());
13
12
  for (const conv of conversations) {
14
- if (conv.isStreaming && !activeExecutions.has(conv.id) && !activeSessionConvIds.has(conv.id)) conv.isStreaming = 0;
13
+ if (conv.isStreaming && !activeExecutions.has(conv.id)) {
14
+ conv.isStreaming = 0;
15
+ try {
16
+ queries.setIsStreaming(conv.id, false);
17
+ for (const s of queries.getSessionsByConversation(conv.id, 5)) {
18
+ if (s.status === 'active' || s.status === 'pending') {
19
+ queries.updateSession(s.id, { status: 'interrupted', error: 'Reconciled: no active execution', completed_at: Date.now() });
20
+ }
21
+ }
22
+ } catch (err) { console.error(`[conv-list-reconcile] ${conv.id}:`, err.message); }
23
+ }
15
24
  }
16
25
  sendJSON(req, res, 200, { conversations });
17
26
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.880",
3
+ "version": "1.0.882",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "electron/main.js",
package/test.js CHANGED
@@ -178,5 +178,21 @@ section('agent-registry: hermes registered as stdio ACP', async () => {
178
178
  assert.ok(h.supportedFeatures.includes('acp-protocol'));
179
179
  });
180
180
 
181
+ section('delete-all: soft-deletes conv rows + wipes related data', () => {
182
+ const { db, prep, gid } = inMemDb();
183
+ const q = createQueries(db, prep, gid);
184
+ const c1 = q.createConversation('claude-code', 'A');
185
+ q.createConversation('claude-code', 'B');
186
+ q.createSession(c1.id);
187
+ q.createMessage(c1.id, 'user', 'hello');
188
+ const origLog = console.log; console.log = () => {};
189
+ try { q.deleteAllConversations(); } finally { console.log = origLog; }
190
+ const rows = db.prepare('SELECT status, count(*) as c FROM conversations GROUP BY status').all();
191
+ assert.deepEqual(rows, [{ status: 'deleted', c: 2 }]);
192
+ assert.equal(db.prepare('SELECT count(*) as c FROM messages').get().c, 0);
193
+ assert.equal(db.prepare('SELECT count(*) as c FROM sessions').get().c, 0);
194
+ assert.equal(q.getConversationsList().length, 0);
195
+ });
196
+
181
197
  console.log(`\n${passed} passed, ${failed} failed`);
182
198
  process.exit(failed === 0 ? 0 : 1);