agentgui 1.0.280 → 1.0.281

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.
Files changed (2) hide show
  1. package/database.js +83 -80
  2. package/package.json +1 -1
package/database.js CHANGED
@@ -1,28 +1,28 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import os from 'os';
4
- import { createRequire } from 'module';
5
-
6
- const require = createRequire(import.meta.url);
7
-
8
- function getDataDir() {
9
- if (process.env.PORTABLE_DATA_DIR) {
10
- return process.env.PORTABLE_DATA_DIR;
11
- }
12
- const exeDir = process.pkg?.path ? path.dirname(process.pkg.path) : null;
13
- if (exeDir) {
14
- return path.join(exeDir, 'data');
15
- }
16
- if (process.env.BUN_BE_BUN && process.argv[1]) {
17
- return path.join(path.dirname(process.argv[1]), 'data');
18
- }
19
- return path.join(os.homedir(), '.gmgui');
20
- }
21
-
22
- export const dataDir = getDataDir();
23
- const dbDir = dataDir;
24
- const dbFilePath = path.join(dbDir, 'data.db');
25
- const oldJsonPath = path.join(dbDir, 'data.json');
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import { createRequire } from 'module';
5
+
6
+ const require = createRequire(import.meta.url);
7
+
8
+ function getDataDir() {
9
+ if (process.env.PORTABLE_DATA_DIR) {
10
+ return process.env.PORTABLE_DATA_DIR;
11
+ }
12
+ const exeDir = process.pkg?.path ? path.dirname(process.pkg.path) : null;
13
+ if (exeDir) {
14
+ return path.join(exeDir, 'data');
15
+ }
16
+ if (process.env.BUN_BE_BUN && process.argv[1]) {
17
+ return path.join(path.dirname(process.argv[1]), 'data');
18
+ }
19
+ return path.join(os.homedir(), '.gmgui');
20
+ }
21
+
22
+ export const dataDir = getDataDir();
23
+ const dbDir = dataDir;
24
+ const dbFilePath = path.join(dbDir, 'data.db');
25
+ const oldJsonPath = path.join(dbDir, 'data.json');
26
26
 
27
27
  if (!fs.existsSync(dbDir)) {
28
28
  fs.mkdirSync(dbDir, { recursive: true });
@@ -326,6 +326,63 @@ try {
326
326
  console.error('[Migration] IPFS schema update warning:', err.message);
327
327
  }
328
328
 
329
+ // Migration: Backfill messages for conversations imported without message content
330
+ try {
331
+ const emptyImported = db.prepare(`
332
+ SELECT c.id, c.sourcePath FROM conversations c
333
+ LEFT JOIN messages m ON c.id = m.conversationId
334
+ WHERE c.sourcePath IS NOT NULL AND c.status != 'deleted'
335
+ GROUP BY c.id HAVING COUNT(m.id) = 0
336
+ `).all();
337
+
338
+ if (emptyImported.length > 0) {
339
+ console.log(`[Migration] Backfilling messages for ${emptyImported.length} imported conversation(s)`);
340
+ const insertMsg = db.prepare(`INSERT OR IGNORE INTO messages (id, conversationId, role, content, created_at) VALUES (?, ?, ?, ?, ?)`);
341
+ const backfill = db.transaction(() => {
342
+ for (const conv of emptyImported) {
343
+ if (!fs.existsSync(conv.sourcePath)) continue;
344
+ try {
345
+ const lines = fs.readFileSync(conv.sourcePath, 'utf-8').split('\n');
346
+ let count = 0;
347
+ for (const line of lines) {
348
+ if (!line.trim()) continue;
349
+ try {
350
+ const obj = JSON.parse(line);
351
+ const msgId = obj.uuid || `msg-${Date.now()}-${Math.random().toString(36).substr(2,9)}`;
352
+ const ts = obj.timestamp ? new Date(obj.timestamp).getTime() : Date.now();
353
+ if (obj.type === 'user' && obj.message?.content) {
354
+ const raw = obj.message.content;
355
+ const text = typeof raw === 'string' ? raw
356
+ : Array.isArray(raw) ? raw.filter(c => c.type === 'text').map(c => c.text).join('\n')
357
+ : JSON.stringify(raw);
358
+ if (text && !text.startsWith('[{"tool_use_id"')) {
359
+ insertMsg.run(msgId, conv.id, 'user', text, ts);
360
+ count++;
361
+ }
362
+ } else if (obj.type === 'assistant' && obj.message?.content) {
363
+ const raw = obj.message.content;
364
+ const text = Array.isArray(raw)
365
+ ? raw.filter(c => c.type === 'text' && c.text).map(c => c.text).join('\n\n')
366
+ : typeof raw === 'string' ? raw : '';
367
+ if (text) {
368
+ insertMsg.run(msgId, conv.id, 'assistant', text, ts);
369
+ count++;
370
+ }
371
+ }
372
+ } catch (_) {}
373
+ }
374
+ if (count > 0) console.log(`[Migration] Backfilled ${count} messages for conversation ${conv.id}`);
375
+ } catch (e) {
376
+ console.error(`[Migration] Error backfilling ${conv.id}:`, e.message);
377
+ }
378
+ }
379
+ });
380
+ backfill();
381
+ }
382
+ } catch (err) {
383
+ console.error('[Migration] Backfill error:', err.message);
384
+ }
385
+
329
386
  // Register official IPFS CIDs for voice models
330
387
  try {
331
388
  const LIGHTHOUSE_GATEWAY = 'https://gateway.lighthouse.storage/ipfs';
@@ -942,7 +999,7 @@ export const queries = {
942
999
 
943
1000
  for (const conv of discovered) {
944
1001
  try {
945
- const existingConv = prep('SELECT id, status FROM conversations WHERE id = ?').get(conv.id);
1002
+ const existingConv = prep('SELECT id, status FROM conversations WHERE id = ? OR externalId = ?').get(conv.id, conv.id);
946
1003
  if (existingConv) {
947
1004
  imported.push({ id: conv.id, status: 'skipped', reason: existingConv.status === 'deleted' ? 'deleted' : 'exists' });
948
1005
  continue;
@@ -1078,60 +1135,6 @@ export const queries = {
1078
1135
  return stmt.all('imported', 'deleted');
1079
1136
  },
1080
1137
 
1081
- importClaudeCodeConversations() {
1082
- const projectsDir = path.join(os.homedir(), '.claude', 'projects');
1083
- if (!fs.existsSync(projectsDir)) return [];
1084
-
1085
- const imported = [];
1086
- const projects = fs.readdirSync(projectsDir);
1087
-
1088
- for (const projectName of projects) {
1089
- const indexPath = path.join(projectsDir, projectName, 'sessions-index.json');
1090
- if (!fs.existsSync(indexPath)) continue;
1091
-
1092
- try {
1093
- const index = JSON.parse(fs.readFileSync(indexPath, 'utf-8'));
1094
- const entries = index.entries || [];
1095
-
1096
- for (const entry of entries) {
1097
- try {
1098
- const existing = this.getConversationByExternalId('claude-code', entry.sessionId);
1099
- if (existing) {
1100
- imported.push({ status: 'skipped', id: existing.id });
1101
- continue;
1102
- }
1103
-
1104
- this.createImportedConversation({
1105
- externalId: entry.sessionId,
1106
- agentType: 'claude-code',
1107
- title: entry.summary || entry.firstPrompt || `Conversation ${entry.sessionId.slice(0, 8)}`,
1108
- firstPrompt: entry.firstPrompt,
1109
- messageCount: entry.messageCount || 0,
1110
- created: new Date(entry.created).getTime(),
1111
- modified: new Date(entry.modified).getTime(),
1112
- projectPath: entry.projectPath,
1113
- gitBranch: entry.gitBranch,
1114
- sourcePath: entry.fullPath,
1115
- source: 'imported'
1116
- });
1117
-
1118
- imported.push({
1119
- status: 'imported',
1120
- id: entry.sessionId,
1121
- title: entry.summary || entry.firstPrompt
1122
- });
1123
- } catch (err) {
1124
- console.error(`[DB] Error importing session ${entry.sessionId}:`, err.message);
1125
- }
1126
- }
1127
- } catch (err) {
1128
- console.error(`[DB] Error reading ${indexPath}:`, err.message);
1129
- }
1130
- }
1131
-
1132
- return imported;
1133
- },
1134
-
1135
1138
  createChunk(sessionId, conversationId, sequence, type, data) {
1136
1139
  const id = generateId('chunk');
1137
1140
  const now = Date.now();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.280",
3
+ "version": "1.0.281",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",