coding-tool-x 3.8.0 → 3.8.1

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.
@@ -1,6 +1,13 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const { PATHS, HOME_DIR } = require('../../config/paths');
4
+ const {
5
+ listProjects: idxListProjects,
6
+ listSessions: idxListSessions,
7
+ getRecentSessions: idxGetRecent,
8
+ searchSessions: idxSearch,
9
+ getSessionStatus: idxGetSessionStatus,
10
+ } = require('./session-history-index');
4
11
  const { getOmpCommand, getOmpPaths, resolveOmpRuntime } = require('./omp-config');
5
12
 
6
13
  const PROJECT_ORDER_FILE = PATHS.ompProjectOrder;
@@ -286,18 +293,16 @@ function scanSessionFiles(rootDir = getOmpSessionPaths().sessions) {
286
293
  return files;
287
294
  }
288
295
 
289
- function getAllSessions() {
290
- return scanSessionFiles()
291
- .map((filePath) => {
292
- try {
293
- return parseSessionFile(filePath);
294
- } catch (error) {
295
- console.warn('[OMP Sessions] Failed to parse session:', filePath, error.message);
296
- return null;
297
- }
298
- })
299
- .filter(Boolean)
300
- .sort((a, b) => (b.mtimeMs || 0) - (a.mtimeMs || 0));
296
+ async function getAllSessions(options = {}) {
297
+ const projects = await idxListProjects('omp', options);
298
+ const groups = await Promise.all(projects.map(project => idxListSessions('omp', project.name, options)));
299
+ return groups.flat().map(session => normalizeSession({
300
+ ...session,
301
+ mtime: new Date(session.mtime).toISOString(),
302
+ mtimeMs: session.mtime,
303
+ directory: session.projectFullPath,
304
+ usage: session.tokens
305
+ }));
301
306
  }
302
307
 
303
308
  function getOmpUsageEvents(rootDir = getOmpSessionPaths().sessions) {
@@ -350,32 +355,20 @@ function loadSessionOrder() {
350
355
  return safeReadJson(SESSION_ORDER_FILE, {});
351
356
  }
352
357
 
353
- function getProjects(_options = {}) {
354
- const sessions = getAllSessions();
355
- const projectMap = new Map();
356
- sessions.forEach((session) => {
357
- const key = session.projectName;
358
- const existing = projectMap.get(key) || {
359
- name: key,
360
- path: session.cwd,
361
- fullPath: session.cwd,
362
- displayName: getDisplayName(session.cwd),
363
- sessionCount: 0,
364
- latestSession: null,
365
- mtime: session.mtime,
366
- mtimeMs: 0,
367
- source: 'omp'
368
- };
369
- existing.sessionCount += 1;
370
- if ((session.mtimeMs || 0) > (existing.mtimeMs || 0)) {
371
- existing.latestSession = session.sessionId;
372
- existing.mtime = session.mtime;
373
- existing.mtimeMs = session.mtimeMs;
374
- }
375
- projectMap.set(key, existing);
376
- });
358
+ async function getProjects(_options = {}) {
359
+ const idxProjects = await idxListProjects('omp');
360
+ const projects = idxProjects.map(p => ({
361
+ name: p.name,
362
+ path: p.fullPath || p.path || '',
363
+ fullPath: p.fullPath || '',
364
+ displayName: p.displayName || p.name,
365
+ sessionCount: p.sessionCount || 0,
366
+ latestSession: p.latestSession || null,
367
+ mtime: p.lastUsed || null,
368
+ mtimeMs: p.lastUsed ? new Date(p.lastUsed).getTime() : 0,
369
+ source: 'omp'
370
+ }));
377
371
 
378
- const projects = Array.from(projectMap.values());
379
372
  const order = loadProjectOrder();
380
373
  projects.sort((a, b) => {
381
374
  const ai = order.indexOf(a.name);
@@ -390,10 +383,26 @@ function getProjects(_options = {}) {
390
383
  return projects;
391
384
  }
392
385
 
393
- function getSessionsByProject(projectName, _options = {}) {
386
+ async function getSessionsByProject(projectName, _options = {}) {
387
+ const idxSessions = await idxListSessions('omp', projectName);
388
+ const sessions = idxSessions.map(s => ({
389
+ sessionId: s.sessionId,
390
+ filePath: s.filePath,
391
+ firstMessage: s.firstMessage,
392
+ gitBranch: s.gitBranch,
393
+ provider: s.provider,
394
+ model: s.model,
395
+ size: s.size,
396
+ mtime: new Date(s.mtime).toISOString(),
397
+ mtimeMs: s.mtime,
398
+ directory: s.projectFullPath,
399
+ cwd: s.projectFullPath,
400
+ messageCount: s.messageCount,
401
+ usage: s.tokens
402
+ }));
403
+
394
404
  const orderMap = loadSessionOrder();
395
405
  const order = Array.isArray(orderMap[projectName]) ? orderMap[projectName] : [];
396
- const sessions = getAllSessions().filter(session => session.projectName === projectName);
397
406
  sessions.sort((a, b) => {
398
407
  const ai = order.indexOf(a.sessionId);
399
408
  const bi = order.indexOf(b.sessionId);
@@ -427,83 +436,71 @@ function normalizeSession(session) {
427
436
  };
428
437
  }
429
438
 
430
- function getSessionById(sessionId) {
431
- return getAllSessions().find(session => session.sessionId === sessionId || path.basename(session.filePath, '.jsonl') === sessionId) || null;
439
+ async function getSessionById(sessionId) {
440
+ const status = await idxGetSessionStatus('omp', sessionId);
441
+ if (!status) return null;
442
+ return {
443
+ sessionId: status.sessionId,
444
+ filePath: status.filePath,
445
+ size: status.size,
446
+ mtime: new Date(status.lastModified).toISOString(),
447
+ mtimeMs: status.lastModified,
448
+ source: 'omp',
449
+ firstMessage: null,
450
+ gitBranch: null,
451
+ forkedFrom: null,
452
+ provider: '',
453
+ model: '',
454
+ directory: null,
455
+ messageCount: 0,
456
+ tokens: { input: 0, output: 0, cached: 0, reasoning: 0, total: 0 }
457
+ };
432
458
  }
433
-
434
- function getSessionMessages(sessionId) {
435
- const session = getSessionById(sessionId);
459
+ async function getSessionMessages(sessionId) {
460
+ const session = await getSessionById(sessionId);
436
461
  if (!session) {
437
462
  throw new Error('Session not found');
438
463
  }
439
464
  return readJsonLines(session.filePath).map(convertOmpEntry).filter(Boolean);
440
465
  }
441
466
 
442
- function getRecentSessions(limit = 5) {
443
- return getAllSessions().slice(0, limit).map(normalizeSession);
444
- }
445
-
446
- function searchSessions(keyword, contextLength = 35, projectName = null) {
447
- const needle = String(keyword || '').toLowerCase();
448
- if (!needle) return [];
449
-
450
- return getAllSessions()
451
- .filter(session => !projectName || session.projectName === projectName)
452
- .map((session) => {
453
- const messages = readJsonLines(session.filePath).map(convertOmpEntry).filter(Boolean);
454
- const matches = [];
455
- messages.forEach((message) => {
456
- const text = String(message.content || '');
457
- const index = text.toLowerCase().indexOf(needle);
458
- if (index === -1) return;
459
- const start = Math.max(0, index - contextLength);
460
- const end = Math.min(text.length, index + needle.length + contextLength);
461
- matches.push({
462
- role: message.role || message.type,
463
- context: text.slice(start, end),
464
- timestamp: message.timestamp || null
465
- });
466
- });
467
- if (matches.length === 0) return null;
468
- return {
469
- ...normalizeSession(session),
470
- projectName: session.projectName,
471
- projectDisplayName: getDisplayName(session.cwd),
472
- matchCount: matches.length,
473
- matches
474
- };
475
- })
476
- .filter(Boolean);
477
- }
478
-
479
- function deleteSession(sessionId) {
480
- const session = getSessionById(sessionId);
481
- if (!session) {
482
- throw new Error('Session not found');
483
- }
467
+ async function getRecentSessions(limit = 5) {
468
+ const indexed = await idxGetRecent('omp', limit);
469
+ return indexed.map(session => normalizeSession({
470
+ ...session,
471
+ mtime: new Date(session.mtime).toISOString(),
472
+ mtimeMs: session.mtime,
473
+ directory: session.projectFullPath,
474
+ usage: session.tokens
475
+ }));
476
+ }
477
+
478
+ async function searchSessions(keyword, contextLength = 35, projectName = null) {
479
+ return idxSearch('omp', keyword, { contextLength, projectName });
480
+ }
481
+
482
+ async function deleteSession(sessionId) {
483
+ const session = await getSessionById(sessionId);
484
+ if (!session) throw new Error('Session not found');
484
485
  fs.unlinkSync(session.filePath);
485
486
  return { success: true };
486
487
  }
487
488
 
488
- function deleteProject(projectName) {
489
- const sessions = getAllSessions().filter(session => session.projectName === projectName);
490
- if (sessions.length === 0) {
491
- throw new Error('Project not found');
492
- }
489
+ async function deleteProject(projectName) {
490
+ const sessions = await getSessionsByProject(projectName);
491
+ if (sessions.length === 0) throw new Error('Project not found');
493
492
  sessions.forEach(session => fs.unlinkSync(session.filePath));
494
493
  return { success: true, deletedSessions: sessions.length };
495
494
  }
496
495
 
497
- function forkSession(sessionId) {
498
- const session = getSessionById(sessionId);
499
- if (!session) {
500
- throw new Error('Session not found');
501
- }
502
- const parsed = path.parse(session.filePath);
503
- const forkId = `fork-${Date.now()}`;
504
- const targetPath = path.join(parsed.dir, `${parsed.name}-${forkId}${parsed.ext}`);
505
- fs.copyFileSync(session.filePath, targetPath);
506
- return { success: true, newSessionId: parseOmpSessionId(targetPath), filePath: targetPath };
496
+ async function forkSession(sessionId) {
497
+ const session = await getSessionById(sessionId);
498
+ if (!session) throw new Error('Session not found');
499
+ const newSessionId = crypto.randomUUID();
500
+ const newFile = path.join(path.dirname(session.filePath), `${newSessionId}.jsonl`);
501
+ const content = fs.readFileSync(session.filePath, 'utf8');
502
+ fs.writeFileSync(newFile, content, 'utf8');
503
+ return { success: true, sessionId: newSessionId, filePath: newFile, forkedFrom: sessionId };
507
504
  }
508
505
 
509
506
  function saveProjectOrder(order) {
@@ -516,11 +513,11 @@ function saveSessionOrder(projectName, order) {
516
513
  safeWriteJson(SESSION_ORDER_FILE, data);
517
514
  }
518
515
 
519
- function getProjectAndSessionCounts(_options = {}) {
520
- const sessions = getAllSessions();
516
+ async function getProjectAndSessionCounts(options = {}) {
517
+ const projects = await idxListProjects('omp', options);
521
518
  return {
522
- projectCount: new Set(sessions.map(session => session.projectName)).size,
523
- sessionCount: sessions.length
519
+ projectCount: projects.length,
520
+ sessionCount: projects.reduce((sum, project) => sum + (project.sessionCount || 0), 0)
524
521
  };
525
522
  }
526
523