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.
- package/AUTOMATIC_IMPORT.md +284 -0
- package/package.json +1 -1
- package/static/app.js +62 -31
|
@@ -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
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
|
-
|
|
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
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
window.app.
|
|
1364
|
-
|
|
1365
|
-
return
|
|
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') {
|