agentgui 1.0.4 → 1.0.5

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/database.js CHANGED
@@ -441,6 +441,86 @@ export const queries = {
441
441
 
442
442
  clearIdempotencyKey(key) {
443
443
  db.run('DELETE FROM idempotencyKeys WHERE key = ?', [key]);
444
+ },
445
+
446
+ discoverClaudeCodeConversations() {
447
+ const claudeHomeDir = path.join(os.homedir(), '.claude-code');
448
+ const conversationsDir = path.join(claudeHomeDir, 'conversations');
449
+
450
+ if (!fs.existsSync(conversationsDir)) {
451
+ return [];
452
+ }
453
+
454
+ const discovered = [];
455
+ try {
456
+ const items = fs.readdirSync(conversationsDir, { withFileTypes: true });
457
+ for (const item of items) {
458
+ if (!item.isDirectory()) continue;
459
+
460
+ const metadataPath = path.join(conversationsDir, item.name, 'metadata.json');
461
+ const messagesPath = path.join(conversationsDir, item.name, 'messages.json');
462
+
463
+ if (!fs.existsSync(metadataPath) || !fs.existsSync(messagesPath)) continue;
464
+
465
+ try {
466
+ const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf-8'));
467
+ const messages = JSON.parse(fs.readFileSync(messagesPath, 'utf-8'));
468
+
469
+ discovered.push({
470
+ id: item.name,
471
+ metadata,
472
+ messages,
473
+ source: 'claude-code'
474
+ });
475
+ } catch (e) {
476
+ console.error(`Error reading Claude Code conversation ${item.name}:`, e.message);
477
+ }
478
+ }
479
+ } catch (e) {
480
+ console.error('Error discovering Claude Code conversations:', e.message);
481
+ }
482
+
483
+ return discovered;
484
+ },
485
+
486
+ importClaudeCodeConversations() {
487
+ const discovered = this.discoverClaudeCodeConversations();
488
+ const imported = [];
489
+
490
+ for (const conv of discovered) {
491
+ try {
492
+ const existingConv = db.prepare('SELECT id FROM conversations WHERE id = ?').get(conv.id);
493
+ if (existingConv) {
494
+ imported.push({ id: conv.id, status: 'skipped', reason: 'Already imported' });
495
+ continue;
496
+ }
497
+
498
+ const title = conv.metadata?.title || 'Claude Code Conversation';
499
+ const createdAt = conv.metadata?.created_at || Date.now();
500
+ const updatedAt = conv.metadata?.updated_at || Date.now();
501
+
502
+ db.prepare(
503
+ `INSERT INTO conversations (id, agentId, title, created_at, updated_at, status) VALUES (?, ?, ?, ?, ?, ?)`
504
+ ).run(conv.id, 'claude-code', title, createdAt, updatedAt, 'active');
505
+
506
+ for (const msg of (conv.messages || [])) {
507
+ try {
508
+ db.prepare(
509
+ `INSERT INTO messages (id, conversationId, role, content, created_at) VALUES (?, ?, ?, ?, ?)`
510
+ ).run(msg.id || generateId('msg'), conv.id, msg.role || 'user', msg.content || '', msg.created_at || Date.now());
511
+ } catch (e) {
512
+ console.error(`Error importing message in conversation ${conv.id}:`, e.message);
513
+ }
514
+ }
515
+
516
+ imported.push({ id: conv.id, status: 'imported', title });
517
+ } catch (e) {
518
+ console.error(`Error importing Claude Code conversation ${conv.id}:`, e.message);
519
+ imported.push({ id: conv.id, status: 'error', error: e.message });
520
+ }
521
+ }
522
+
523
+ return imported;
444
524
  }
445
525
  };
446
526
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",
package/server.js CHANGED
@@ -195,6 +195,20 @@ const server = http.createServer(async (req, res) => {
195
195
  return;
196
196
  }
197
197
 
198
+ if (routePath === '/api/import/claude-code' && req.method === 'GET') {
199
+ const result = queries.importClaudeCodeConversations();
200
+ res.writeHead(200, { 'Content-Type': 'application/json' });
201
+ res.end(JSON.stringify({ imported: result }));
202
+ return;
203
+ }
204
+
205
+ if (routePath === '/api/discover/claude-code' && req.method === 'GET') {
206
+ const discovered = queries.discoverClaudeCodeConversations();
207
+ res.writeHead(200, { 'Content-Type': 'application/json' });
208
+ res.end(JSON.stringify({ discovered }));
209
+ return;
210
+ }
211
+
198
212
  if (routePath === '/api/home' && req.method === 'GET') {
199
213
  res.writeHead(200, { 'Content-Type': 'application/json' });
200
214
  res.end(JSON.stringify({ home: process.env.HOME || '/config' }));
package/static/app.js CHANGED
@@ -886,6 +886,44 @@ function createChatInFolder() {
886
886
  app.openFolderBrowser();
887
887
  }
888
888
 
889
+ async function importClaudeCodeConversations() {
890
+ closeNewChatModal();
891
+ try {
892
+ const res = await fetch(BASE_URL + '/api/import/claude-code');
893
+ const data = await res.json();
894
+
895
+ if (!data.imported) {
896
+ alert('No Claude Code conversations found to import.');
897
+ return;
898
+ }
899
+
900
+ const imported = data.imported.filter(r => r.status === 'imported');
901
+ const skipped = data.imported.filter(r => r.status === 'skipped');
902
+ const errors = data.imported.filter(r => r.status === 'error');
903
+
904
+ let message = `Import complete!\n\n`;
905
+ if (imported.length > 0) {
906
+ message += `✓ Imported: ${imported.length} conversation(s)\n`;
907
+ }
908
+ if (skipped.length > 0) {
909
+ message += `⊘ Skipped: ${skipped.length} (already imported)\n`;
910
+ }
911
+ if (errors.length > 0) {
912
+ message += `✗ Errors: ${errors.length}\n`;
913
+ }
914
+
915
+ alert(message.trim());
916
+
917
+ if (imported.length > 0) {
918
+ await app.fetchConversations();
919
+ app.renderAll();
920
+ }
921
+ } catch (e) {
922
+ console.error('Import error:', e);
923
+ alert('Failed to import Claude Code conversations: ' + e.message);
924
+ }
925
+ }
926
+
889
927
  function sendMessage() { app.sendMessage(); }
890
928
 
891
929
  function toggleSidebar() {
package/static/index.html CHANGED
@@ -129,6 +129,13 @@
129
129
  <div class="chat-option-desc">Contextualize chat to a specific folder</div>
130
130
  </div>
131
131
  </button>
132
+ <button class="chat-option-btn" onclick="importClaudeCodeConversations()">
133
+ <span class="chat-option-icon">📥</span>
134
+ <div class="chat-option-content">
135
+ <div class="chat-option-title">Import Claude Code conversations</div>
136
+ <div class="chat-option-desc">Load existing conversations from Claude Code</div>
137
+ </div>
138
+ </button>
132
139
  </div>
133
140
  </div>
134
141
  </div>