@ekkos/cli 1.2.16 → 1.2.17

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.
@@ -1419,18 +1419,50 @@ async function run(options) {
1419
1419
  // Claude creates the transcript file BEFORE outputting the session name
1420
1420
  // So we watch for new files rather than parsing TUI output (which is slower)
1421
1421
  // ════════════════════════════════════════════════════════════════════════════
1422
- const encodedCwd = process.cwd().replace(/\//g, '-');
1423
- const projectDir = path.join(os.homedir(), '.claude', 'projects', encodedCwd);
1422
+ const projectPath = process.cwd();
1423
+ const projectsRoot = path.join(os.homedir(), '.claude', 'projects');
1424
+ const projectDirCandidates = (() => {
1425
+ // Claude's project-dir encoding is platform/version dependent.
1426
+ // Probe a small set of known-safe variants to avoid missing the session file.
1427
+ const encodings = new Set([
1428
+ projectPath.replace(/\//g, '-'),
1429
+ projectPath.replace(/[\\/]/g, '-'),
1430
+ projectPath.replace(/[:\\/]/g, '-'),
1431
+ `-${projectPath.replace(/[:\\/]/g, '-').replace(/^-+/, '')}`,
1432
+ projectPath.replace(/[^a-zA-Z0-9]/g, '-'),
1433
+ `-${projectPath.replace(/^[\\/]+/, '').replace(/[^a-zA-Z0-9]/g, '-')}`,
1434
+ ]);
1435
+ return [...encodings]
1436
+ .filter(Boolean)
1437
+ .map(encoded => path.join(projectsRoot, encoded));
1438
+ })();
1424
1439
  const launchTime = Date.now();
1440
+ function listCandidateJsonlFiles() {
1441
+ const jsonlFiles = [];
1442
+ for (const candidateDir of projectDirCandidates) {
1443
+ if (!fs.existsSync(candidateDir))
1444
+ continue;
1445
+ try {
1446
+ for (const file of fs.readdirSync(candidateDir)) {
1447
+ if (file.endsWith('.jsonl')) {
1448
+ jsonlFiles.push(path.join(candidateDir, file));
1449
+ }
1450
+ }
1451
+ }
1452
+ catch {
1453
+ // Ignore candidate-dir read errors and keep scanning others.
1454
+ }
1455
+ }
1456
+ return jsonlFiles;
1457
+ }
1425
1458
  // Track existing jsonl files at startup
1426
1459
  let existingJsonlFiles = new Set();
1427
1460
  try {
1428
- const files = fs.readdirSync(projectDir);
1429
- existingJsonlFiles = new Set(files.filter(f => f.endsWith('.jsonl')));
1461
+ existingJsonlFiles = new Set(listCandidateJsonlFiles());
1430
1462
  dlog(`[TRANSCRIPT] Found ${existingJsonlFiles.size} existing jsonl files at startup`);
1431
1463
  }
1432
1464
  catch {
1433
- dlog('[TRANSCRIPT] Project dir does not exist yet');
1465
+ dlog('[TRANSCRIPT] No candidate project dir exists yet');
1434
1466
  }
1435
1467
  // Poll for new transcript file every 500ms for up to 30 seconds.
1436
1468
  // Safety rule: do NOT guess using "most recent" files; that can cross-bind sessions.
@@ -1450,13 +1482,11 @@ async function run(options) {
1450
1482
  // In proxy mode this is intentionally disabled to avoid cross-session mixing.
1451
1483
  if (!proxyModeEnabled && !transcriptPath) {
1452
1484
  try {
1453
- const files = fs.readdirSync(projectDir);
1454
- const jsonlFiles = files
1455
- .filter(f => f.endsWith('.jsonl'))
1456
- .map(f => ({
1457
- name: f,
1458
- path: path.join(projectDir, f),
1459
- mtime: fs.statSync(path.join(projectDir, f)).mtimeMs
1485
+ const jsonlFiles = listCandidateJsonlFiles()
1486
+ .map(fullPath => ({
1487
+ name: path.basename(fullPath),
1488
+ path: fullPath,
1489
+ mtime: fs.statSync(fullPath).mtimeMs
1460
1490
  }))
1461
1491
  .sort((a, b) => b.mtime - a.mtime);
1462
1492
  if (jsonlFiles.length > 0) {
@@ -1486,14 +1516,13 @@ async function run(options) {
1486
1516
  return;
1487
1517
  }
1488
1518
  try {
1489
- const currentFiles = fs.readdirSync(projectDir);
1490
- const jsonlFiles = currentFiles.filter(f => f.endsWith('.jsonl'));
1519
+ const jsonlFiles = listCandidateJsonlFiles();
1491
1520
  // Find NEW files (created after we started)
1492
1521
  for (const file of jsonlFiles) {
1493
1522
  if (!existingJsonlFiles.has(file)) {
1494
1523
  // New file! This is our transcript
1495
- const fullPath = path.join(projectDir, file);
1496
- const sessionId = file.replace('.jsonl', '');
1524
+ const fullPath = file;
1525
+ const sessionId = path.basename(file).replace('.jsonl', '');
1497
1526
  transcriptPath = fullPath;
1498
1527
  currentSessionId = sessionId;
1499
1528
  currentSession = (0, state_1.uuidToWords)(sessionId);
@@ -1608,8 +1637,10 @@ async function run(options) {
1608
1637
  function resolveTranscriptFromSessionId(source) {
1609
1638
  if (!currentSessionId || transcriptPath)
1610
1639
  return;
1611
- const candidate = path.join(projectDir, `${currentSessionId}.jsonl`);
1612
- if (!fs.existsSync(candidate))
1640
+ const candidate = projectDirCandidates
1641
+ .map(projectDir => path.join(projectDir, `${currentSessionId}.jsonl`))
1642
+ .find(fullPath => fs.existsSync(fullPath));
1643
+ if (!candidate)
1613
1644
  return;
1614
1645
  transcriptPath = candidate;
1615
1646
  evictionDebugLog('TRANSCRIPT_SET', `Set from session ID (${source})`, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekkos/cli",
3
- "version": "1.2.16",
3
+ "version": "1.2.17",
4
4
  "description": "Setup ekkOS memory for AI coding assistants (Claude Code, Cursor, Windsurf)",
5
5
  "main": "dist/index.js",
6
6
  "bin": {