agentgui 1.0.26 → 1.0.28

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.
@@ -0,0 +1,284 @@
1
+ # Automatic Continuous Importing Feature
2
+
3
+ ## Overview
4
+ AgentGUI now automatically and continuously imports Claude Code conversations **without requiring any user action**. This ensures conversations are always available and up-to-date.
5
+
6
+ ## How It Works
7
+
8
+ ### Server-Side (Every 30 Seconds)
9
+ ```
10
+ Server startup
11
+
12
+ [IMMEDIATE] Import Claude Code conversations (first run)
13
+
14
+ [EVERY 30 SECONDS] Auto-import new conversations
15
+
16
+ If new conversations found:
17
+ • Add them to database
18
+ • Broadcast 'conversations_updated' event to all connected clients
19
+ • Log: "[AUTO-IMPORT] Imported X new Claude Code conversations"
20
+ ```
21
+
22
+ ### Frontend-Side
23
+ ```
24
+ Page loads
25
+
26
+ [IMMEDIATE] Fetch conversations from API
27
+
28
+ [EVERY 10 SECONDS] Fetch conversations again (as fallback)
29
+
30
+ [ON SYNC EVENT] Receive 'conversations_updated' from server
31
+
32
+ Immediately refresh conversation list
33
+
34
+ Users see new conversations appear in real-time
35
+ ```
36
+
37
+ ## Key Features
38
+
39
+ ✅ **Automatic**: No user action needed
40
+ ✅ **Continuous**: Runs every 30 seconds (server) and 10 seconds (client)
41
+ ✅ **Real-time**: New conversations appear immediately via WebSocket
42
+ ✅ **No Duplicates**: Skips conversations already imported
43
+ ✅ **Cross-tab**: Broadcasts via BroadcastChannel API
44
+ ✅ **Resilient**: Fallback mechanism if WebSocket fails
45
+ ✅ **Logging**: All imports logged for debugging
46
+
47
+ ## Where Conversations Come From
48
+
49
+ ### Automatically Discovered From:
50
+ 1. **Claude Code Projects** (~/.claude/projects/)
51
+ - Scans sessions-index.json files
52
+ - Reads .jsonl message files
53
+ - Imports with "[project] title" format
54
+
55
+ 2. **Created in AgentGUI**
56
+ - New conversations created via UI
57
+ - Automatically stored in database
58
+
59
+ ## Example Flow
60
+
61
+ ### Scenario: User Uses Claude Code, Then Opens AgentGUI
62
+
63
+ ```
64
+ 11:00:00 - User creates conversation in Claude Code
65
+ 11:00:15 - AgentGUI server detects new conversation in ~/.claude/projects/
66
+ 11:00:20 - Server imports conversation automatically
67
+ 11:00:20 - Server broadcasts 'conversations_updated' event
68
+ 11:00:21 - All connected browser tabs receive update
69
+ 11:00:21 - Users see new conversation appear in sidebar
70
+ ```
71
+
72
+ ### Scenario: Multiple Tabs Open
73
+
74
+ ```
75
+ Tab 1 opens AgentGUI
76
+ Tab 2 opens AgentGUI (few seconds later)
77
+
78
+ Tab 1 receives 'conversations_updated' from server
79
+ Tab 1 uses BroadcastChannel to notify Tab 2
80
+ Tab 2 also refreshes conversation list
81
+ Both tabs show latest conversations in sync
82
+ ```
83
+
84
+ ## Server Logs
85
+
86
+ You'll see logs like:
87
+ ```
88
+ [AUTO-IMPORT] Imported 2 new Claude Code conversations (42 already exist)
89
+ [AUTO-IMPORT] Imported 1 new Claude Code conversation (43 already exist)
90
+ [AUTO-IMPORT] (nothing new this cycle)
91
+ ```
92
+
93
+ ## Client Logs
94
+
95
+ In browser console:
96
+ ```
97
+ [SYNC] Server imported 3 new conversations, refreshing...
98
+ [DEBUG] Init: Auto-imported Claude Code conversations
99
+ [DEBUG] Loaded conversations, total: 86
100
+ ```
101
+
102
+ ## Configuration
103
+
104
+ ### Import Frequency (Server)
105
+ Current: **30 seconds**
106
+ Location: `server.js` line `setInterval(performAutoImport, 30000);`
107
+
108
+ To change:
109
+ ```javascript
110
+ setInterval(performAutoImport, 60000); // 60 seconds
111
+ setInterval(performAutoImport, 5000); // 5 seconds
112
+ ```
113
+
114
+ ### Refresh Frequency (Client)
115
+ Current: **10 seconds**
116
+ Location: `app.js` line `setInterval(() => { ... }, 10000);`
117
+
118
+ To change:
119
+ ```javascript
120
+ }, 60000); // 60 seconds
121
+ }, 5000); // 5 seconds
122
+ ```
123
+
124
+ ## Data Flow Diagram
125
+
126
+ ```
127
+ ┌─────────────────────────────────────────────────────┐
128
+ │ Claude Code │
129
+ │ ~/.claude/projects/*/sessions-index.json │
130
+ └─────────────────┬───────────────────────────────────┘
131
+ │ (monitors every 30s)
132
+
133
+ ┌─────────────────────────────────────────────────────┐
134
+ │ AgentGUI Server │
135
+ │ • queries.importClaudeCodeConversations() │
136
+ │ • Stores in ~/.gmgui/data.db │
137
+ │ • Broadcasts via WebSocket │
138
+ └──────┬──────────────────────────┬────────────────────┘
139
+ │ │
140
+ │ (WebSocket event) │ (HTTP API)
141
+ ↓ ↓
142
+ ┌─────────────────────────────────────────────────────┐
143
+ │ Browser (Frontend) │
144
+ │ • Listens on sync WebSocket │
145
+ │ • Receives 'conversations_updated' event │
146
+ │ • Calls fetchConversations() │
147
+ │ • Calls renderChatHistory() │
148
+ └──────┬──────────────────────────────────────────────┘
149
+
150
+
151
+ ┌─────────────────────────────────────────────────────┐
152
+ │ Chat Sidebar │
153
+ │ • Displays conversation list │
154
+ │ • User can click to view conversation │
155
+ └─────────────────────────────────────────────────────┘
156
+ ```
157
+
158
+ ## Troubleshooting
159
+
160
+ ### Conversations Not Appearing
161
+
162
+ **Check 1: Server Auto-Import**
163
+ ```bash
164
+ # Look for these logs in server output
165
+ grep "\[AUTO-IMPORT\]" server.log
166
+
167
+ # If no logs, auto-import might not be running
168
+ ```
169
+
170
+ **Check 2: Claude Code Availability**
171
+ ```bash
172
+ # Check if Claude Code projects exist
173
+ ls -la ~/.claude/projects/
174
+
175
+ # Count projects with conversations
176
+ find ~/.claude/projects -name "sessions-index.json" | wc -l
177
+ ```
178
+
179
+ **Check 3: Browser Sync**
180
+ ```javascript
181
+ // In browser console
182
+ // Check if WebSocket is connected
183
+ console.log('WebSocket state:', app.syncWs.ws?.readyState);
184
+
185
+ // Try manual refresh
186
+ await app.fetchConversations();
187
+ app.renderChatHistory();
188
+ ```
189
+
190
+ **Check 4: Database**
191
+ ```bash
192
+ # Check total conversations in DB
193
+ node -e "
194
+ const DB = require('better-sqlite3');
195
+ const db = new DB(process.env.HOME + '/.gmgui/data.db');
196
+ const count = db.prepare('SELECT COUNT(*) as c FROM conversations').get();
197
+ console.log('Database has:', count.c, 'conversations');
198
+ db.close();
199
+ "
200
+ ```
201
+
202
+ ### Too Many Import Logs
203
+
204
+ If server logs are too verbose:
205
+ 1. Increase `setInterval` time (30000 → 60000 or more)
206
+ 2. Add log level filtering
207
+
208
+ ### Conversations Take Too Long to Appear
209
+
210
+ If new conversations take > 1 minute:
211
+ 1. Check server auto-import interval (default 30s)
212
+ 2. Check client refresh interval (default 10s)
213
+ 3. Check network connectivity
214
+ 4. Check browser console for errors
215
+
216
+ ## Performance Considerations
217
+
218
+ ### Import Impact
219
+ - **Minimal**: Import skips existing conversations
220
+ - **Fast**: Only processes new conversations
221
+ - **Efficient**: Uses database transactions
222
+
223
+ ### Client Impact
224
+ - **WebSocket**: Real-time updates, low bandwidth
225
+ - **Polling**: Every 10 seconds, minimal traffic
226
+ - **Rendering**: Only updates when conversations change
227
+
228
+ ## Security Notes
229
+
230
+ - Only imports from user's local `.claude/projects/`
231
+ - No external network access needed
232
+ - All conversations stored locally
233
+ - Respects filesystem permissions
234
+
235
+ ## Future Enhancements
236
+
237
+ Potential improvements:
238
+ - Configurable import interval via UI
239
+ - Import from multiple sources
240
+ - Batch import optimization
241
+ - Import history/logs viewer
242
+ - Import statistics dashboard
243
+ - Per-project import settings
244
+
245
+ ## Testing
246
+
247
+ ### Manual Test: Add Claude Code Conversation
248
+ ```bash
249
+ # 1. Use Claude Code (creates ~/.claude/projects/*/sessions-index.json)
250
+ # 2. Wait up to 30 seconds
251
+ # 3. Check browser - should see new conversation appear
252
+ # 4. Confirm console logs show "[AUTO-IMPORT] Imported X..."
253
+ ```
254
+
255
+ ### Manual Test: Force Import
256
+ ```javascript
257
+ // In browser console
258
+ await fetch('/gm/api/import/claude-code')
259
+ .then(r => r.json())
260
+ .then(d => console.log('Manual import result:', d));
261
+
262
+ // Then refresh
263
+ await app.fetchConversations();
264
+ app.renderChatHistory();
265
+ ```
266
+
267
+ ## Related Files
268
+
269
+ - `server.js` - Server auto-import implementation
270
+ - `app.js` - Frontend sync handling
271
+ - `database.js` - Query functions
272
+ - `acp-launcher.js` - Claude Code connection
273
+
274
+ ## Changelog
275
+
276
+ ### Version 1.1.0 (Current)
277
+ - ✅ Added automatic server-side importing every 30 seconds
278
+ - ✅ Added WebSocket broadcast for instant updates
279
+ - ✅ Added client-side sync event handler
280
+ - ✅ Integrated with existing periodic sync
281
+
282
+ ### Version 1.0.0 (Previous)
283
+ - Manual import on demand via `/api/import/claude-code`
284
+ - No automatic background importing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.26",
3
+ "version": "1.0.28",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
package/static/app.js CHANGED
@@ -90,7 +90,13 @@ class GMGUIApp {
90
90
  this.settings = { autoScroll: true, connectTimeout: 30000 };
91
91
  this.pendingMessages = new Map();
92
92
  this.idempotencyKeys = new Map();
93
- this.init();
93
+
94
+ // Start async initialization and handle errors
95
+ this.initPromise = this.init().catch(err => {
96
+ console.error('[CRITICAL] GMGUIApp.init() failed:', err);
97
+ console.error('[CRITICAL] Stack:', err.stack);
98
+ throw err;
99
+ });
94
100
  }
95
101
 
96
102
  async init() {
@@ -1336,37 +1342,62 @@ function confirmFolderSelection() {
1336
1342
 
1337
1343
  // Wait for DOM to be fully ready before initializing
1338
1344
  function initializeApp() {
1339
- console.log('[DEBUG] initializeApp: Checking if DOM is ready');
1340
- const chatList = document.getElementById('chatList');
1341
- if (!chatList) {
1342
- console.warn('[DEBUG] initializeApp: chatList not found, waiting 100ms');
1343
- setTimeout(initializeApp, 100);
1344
- return;
1345
- }
1346
-
1347
- console.log('[DEBUG] initializeApp: DOM is ready, creating GMGUIApp');
1348
- window.app = new GMGUIApp();
1349
- window._app = window.app;
1350
-
1351
- // Debug: Log app state to window for inspection
1352
- window._debug = {
1353
- get conversations() { return Array.from(window.app.conversations.values()).map(c => ({ id: c.id, title: c.title })); },
1354
- get conversationCount() { return window.app.conversations.size; },
1355
- get selectedAgent() { return window.app.selectedAgent; },
1356
- get currentConversation() { return window.app.currentConversation; },
1357
- checkChatListElement() { return document.getElementById('chatList'); },
1358
- checkChatListChildCount() { return document.getElementById('chatList')?.children?.length || 0; },
1359
- async forceRefetch() {
1360
- console.log('[FORCE] Forcing fetchConversations...');
1361
- await window.app.fetchConversations();
1362
- console.log('[FORCE] Conversations loaded:', window.app.conversations.size);
1363
- window.app.renderChatHistory();
1364
- console.log('[FORCE] renderChatHistory called');
1365
- return window.app.conversations.size;
1345
+ try {
1346
+ console.log('[DEBUG] initializeApp: Checking if DOM is ready');
1347
+ const chatList = document.getElementById('chatList');
1348
+ if (!chatList) {
1349
+ console.warn('[DEBUG] initializeApp: chatList not found, waiting 100ms');
1350
+ setTimeout(initializeApp, 100);
1351
+ return;
1352
+ }
1353
+
1354
+ console.log('[DEBUG] initializeApp: DOM is ready, creating GMGUIApp');
1355
+ try {
1356
+ window.app = new GMGUIApp();
1357
+ window._app = window.app;
1358
+ console.log('[DEBUG] initializeApp: GMGUIApp constructor completed');
1359
+ } catch (constructorError) {
1360
+ console.error('[ERROR] GMGUIApp constructor failed:', constructorError.message);
1361
+ console.error('[ERROR] Stack:', constructorError.stack);
1362
+ throw constructorError;
1363
+ }
1364
+
1365
+ // Debug: Log app state to window for inspection
1366
+ window._debug = {
1367
+ get conversations() { return Array.from(window.app.conversations.values()).map(c => ({ id: c.id, title: c.title })); },
1368
+ get conversationCount() { return window.app.conversations.size; },
1369
+ get selectedAgent() { return window.app.selectedAgent; },
1370
+ get currentConversation() { return window.app.currentConversation; },
1371
+ checkChatListElement() { return document.getElementById('chatList'); },
1372
+ checkChatListChildCount() { return document.getElementById('chatList')?.children?.length || 0; },
1373
+ async forceRefetch() {
1374
+ console.log('[FORCE] Forcing fetchConversations...');
1375
+ await window.app.fetchConversations();
1376
+ console.log('[FORCE] Conversations loaded:', window.app.conversations.size);
1377
+ window.app.renderChatHistory();
1378
+ console.log('[FORCE] renderChatHistory called');
1379
+ return window.app.conversations.size;
1380
+ }
1381
+ };
1382
+
1383
+ console.log('[DEBUG] initializeApp: GMGUIApp created successfully with', window.app.conversations.size, 'conversations');
1384
+ } catch (error) {
1385
+ console.error('[CRITICAL ERROR] initializeApp failed:', error.message);
1386
+ console.error('[CRITICAL ERROR] Stack trace:', error.stack);
1387
+
1388
+ // Show error on page
1389
+ const chatList = document.getElementById('chatList');
1390
+ if (chatList) {
1391
+ chatList.innerHTML = `
1392
+ <div style="color: red; padding: 1rem; font-family: monospace; font-size: 0.75rem;">
1393
+ <strong>INITIALIZATION ERROR</strong><br>
1394
+ ${error.message}<br>
1395
+ <br>
1396
+ Check browser console (F12) for details.
1397
+ </div>
1398
+ `;
1366
1399
  }
1367
- };
1368
-
1369
- console.log('[DEBUG] initializeApp: GMGUIApp created successfully');
1400
+ }
1370
1401
  }
1371
1402
 
1372
1403
  if (document.readyState === 'loading') {