@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/sessions/<sessionId>.jsonl
331
+ // GEMINI - Load from ~/.gemini/tmp/<hash>/chats/session-*.json
289
332
  // ============================================================
290
333
 
291
- async loadGeminiMessages({ sessionId, limit, before, mode }) {
292
- const sessionFile = path.join(this.geminiPath, 'sessions', `${sessionId}.jsonl`);
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: ${sessionFile}`);
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
- const rawMessages = await this._parseJsonlFile(sessionFile);
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.role === 'user' || entry.role === 'model' || entry.role === 'assistant')
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 'model' instead of 'assistant'
315
- const role = entry.role === 'model' ? 'assistant' : (entry.role || 'assistant');
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmmbuto/nexuscli",
3
- "version": "0.7.3",
3
+ "version": "0.7.4",
4
4
  "description": "NexusCLI - TRI CLI Control Plane (Claude/Codex/Gemini)",
5
5
  "main": "lib/server/server.js",
6
6
  "bin": {