@mmmbuto/nexuscli 0.7.3 → 0.7.4
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.
|
@@ -48,7 +48,7 @@ class CliLoader {
|
|
|
48
48
|
async loadMessagesFromCLI({
|
|
49
49
|
sessionId,
|
|
50
50
|
threadId, // optional native thread id (e.g., Codex exec thread)
|
|
51
|
-
sessionPath, // alias for compatibility
|
|
51
|
+
sessionPath, // alias kept for compatibility
|
|
52
52
|
engine = 'claude',
|
|
53
53
|
workspacePath,
|
|
54
54
|
limit = DEFAULT_LIMIT,
|
|
@@ -74,7 +74,7 @@ class CliLoader {
|
|
|
74
74
|
break;
|
|
75
75
|
|
|
76
76
|
case 'gemini':
|
|
77
|
-
result = await this.loadGeminiMessages({ sessionId, limit, before, mode });
|
|
77
|
+
result = await this.loadGeminiMessages({ sessionId, nativeId, limit, before, mode });
|
|
78
78
|
break;
|
|
79
79
|
|
|
80
80
|
default:
|
|
@@ -284,24 +284,85 @@ class CliLoader {
|
|
|
284
284
|
return null;
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
+
/**
|
|
288
|
+
* Find Gemini session file by native ID (short hash)
|
|
289
|
+
* Searches in ~/.gemini/tmp/<installation-hash>/chats/
|
|
290
|
+
*
|
|
291
|
+
* @param {string} nativeId - Short hash (first 8 chars of UUID)
|
|
292
|
+
* @returns {string|null} - Full path to session file or null
|
|
293
|
+
*/
|
|
294
|
+
findGeminiSessionFile(nativeId) {
|
|
295
|
+
const tmpDir = path.join(this.geminiPath, 'tmp');
|
|
296
|
+
|
|
297
|
+
if (!nativeId || !fs.existsSync(tmpDir)) {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
try {
|
|
302
|
+
// Extract short hash from nativeId (first 8 chars if UUID, or use as-is)
|
|
303
|
+
const shortHash = nativeId.length > 8 ? nativeId.substring(0, 8) : nativeId;
|
|
304
|
+
|
|
305
|
+
// Scan all installation hash directories
|
|
306
|
+
const installations = fs.readdirSync(tmpDir);
|
|
307
|
+
|
|
308
|
+
for (const installHash of installations) {
|
|
309
|
+
const chatsDir = path.join(tmpDir, installHash, 'chats');
|
|
310
|
+
|
|
311
|
+
if (!fs.existsSync(chatsDir)) continue;
|
|
312
|
+
|
|
313
|
+
// List all session files
|
|
314
|
+
const files = fs.readdirSync(chatsDir);
|
|
315
|
+
|
|
316
|
+
// Find file matching pattern: session-*-<shortHash>.json
|
|
317
|
+
for (const file of files) {
|
|
318
|
+
if (file.endsWith(`-${shortHash}.json`)) {
|
|
319
|
+
return path.join(chatsDir, file);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
} catch (err) {
|
|
324
|
+
console.warn(`[CliLoader] Failed to search Gemini session file: ${err.message}`);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
|
|
287
330
|
// ============================================================
|
|
288
|
-
// GEMINI - Load from ~/.gemini/
|
|
331
|
+
// GEMINI - Load from ~/.gemini/tmp/<hash>/chats/session-*.json
|
|
289
332
|
// ============================================================
|
|
290
333
|
|
|
291
|
-
async loadGeminiMessages({ sessionId, limit, before, mode }) {
|
|
292
|
-
|
|
334
|
+
async loadGeminiMessages({ sessionId, nativeId, limit, before, mode }) {
|
|
335
|
+
// Use nativeId (short hash) to find the file
|
|
336
|
+
const shortHash = nativeId
|
|
337
|
+
? (nativeId.length > 8 ? nativeId.substring(0, 8) : nativeId)
|
|
338
|
+
: (sessionId.length > 8 ? sessionId.substring(0, 8) : sessionId);
|
|
339
|
+
|
|
340
|
+
const sessionFile = this.findGeminiSessionFile(shortHash);
|
|
293
341
|
|
|
294
342
|
// Gemini CLI may not save sessions - check if file exists
|
|
295
|
-
if (!fs.existsSync(sessionFile)) {
|
|
296
|
-
console.log(`[CliLoader] Gemini session file not found
|
|
343
|
+
if (!sessionFile || !fs.existsSync(sessionFile)) {
|
|
344
|
+
console.log(`[CliLoader] Gemini session file not found (id=${shortHash})`);
|
|
297
345
|
return this._emptyResult();
|
|
298
346
|
}
|
|
299
347
|
|
|
300
|
-
|
|
348
|
+
// Parse JSON file (NOT jsonl!)
|
|
349
|
+
let sessionData;
|
|
350
|
+
try {
|
|
351
|
+
const fileContent = fs.readFileSync(sessionFile, 'utf8');
|
|
352
|
+
sessionData = JSON.parse(fileContent);
|
|
353
|
+
} catch (err) {
|
|
354
|
+
console.error(`[CliLoader] Failed to parse Gemini session file: ${err.message}`);
|
|
355
|
+
return this._emptyResult();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Extract messages array from session object
|
|
359
|
+
const rawMessages = Array.isArray(sessionData)
|
|
360
|
+
? sessionData
|
|
361
|
+
: (sessionData.messages || []);
|
|
301
362
|
|
|
302
363
|
// Filter and normalize
|
|
303
364
|
const messages = rawMessages
|
|
304
|
-
.filter(entry => entry.
|
|
365
|
+
.filter(entry => entry.type === 'user' || entry.type === 'gemini')
|
|
305
366
|
.map(entry => this._normalizeGeminiEntry(entry));
|
|
306
367
|
|
|
307
368
|
return this._paginateMessages(messages, limit, before, mode);
|
|
@@ -311,8 +372,8 @@ class CliLoader {
|
|
|
311
372
|
* Normalize Gemini session entry to message shape
|
|
312
373
|
*/
|
|
313
374
|
_normalizeGeminiEntry(entry) {
|
|
314
|
-
// Gemini uses '
|
|
315
|
-
const role = entry.
|
|
375
|
+
// Gemini uses 'gemini' instead of 'assistant' in type field
|
|
376
|
+
const role = entry.type === 'gemini' ? 'assistant' : (entry.type || 'assistant');
|
|
316
377
|
const created_at = entry.timestamp ? new Date(entry.timestamp).getTime() : Date.now();
|
|
317
378
|
|
|
318
379
|
// Gemini content format
|
|
@@ -320,7 +381,7 @@ class CliLoader {
|
|
|
320
381
|
if (typeof entry.content === 'string') {
|
|
321
382
|
content = entry.content;
|
|
322
383
|
} else if (Array.isArray(entry.parts)) {
|
|
323
|
-
// Gemini uses parts array: [{text: '...'}]
|
|
384
|
+
// Gemini API uses parts array: [{text: '...'}]
|
|
324
385
|
content = entry.parts
|
|
325
386
|
.filter(p => p.text)
|
|
326
387
|
.map(p => p.text)
|
|
@@ -336,7 +397,10 @@ class CliLoader {
|
|
|
336
397
|
engine: 'gemini',
|
|
337
398
|
created_at,
|
|
338
399
|
metadata: {
|
|
339
|
-
model: entry.model
|
|
400
|
+
model: entry.model,
|
|
401
|
+
tokens: entry.tokens, // Contatori token (input/output/cached/thoughts)
|
|
402
|
+
thoughts: entry.thoughts, // Thinking process (Gemini 3+)
|
|
403
|
+
toolCalls: entry.toolCalls // Tool usage tracking
|
|
340
404
|
}
|
|
341
405
|
};
|
|
342
406
|
}
|