@aiplumber/session-recall 1.9.0 → 1.9.3

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/package.json +1 -1
  2. package/session-recall +53 -13
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiplumber/session-recall",
3
- "version": "1.9.0",
3
+ "version": "1.9.3",
4
4
  "description": "Pull context from previous Claude Code sessions. Sessions end, context resets - this tool lets you continue where you left off.",
5
5
  "bin": {
6
6
  "session-recall": "./session-recall"
package/session-recall CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const VERSION = '1.9.0';
3
+ const VERSION = '1.9.3';
4
4
 
5
5
  const fs = require('fs');
6
6
  const path = require('path');
@@ -121,8 +121,8 @@ async function streamScanCompactions(filePath) {
121
121
 
122
122
  rl.on('line', (line) => {
123
123
  lineNum++;
124
- // Quick string check before parsing
125
- if (!line.includes('SessionStart:compact')) return;
124
+ // Quick string check before parsing - check both old and new formats
125
+ if (!line.includes('SessionStart:compact') && !line.includes('compact_boundary')) return;
126
126
 
127
127
  try {
128
128
  const msg = JSON.parse(line);
@@ -1293,9 +1293,16 @@ async function cmdLast(arg1, arg2, opts) {
1293
1293
  const candidateCount = Math.min(allSessions.length, n + 5);
1294
1294
  for (let i = 0; i < candidateCount; i++) {
1295
1295
  const s = allSessions[i];
1296
- // Use streaming for large files, sync for small files
1297
1296
  const stats = fs.statSync(s.filePath);
1298
1297
  const sizeMB = stats.size / (1024 * 1024);
1298
+
1299
+ // If we need compaction markers (for --before-compaction or --compactions),
1300
+ // scan for them FIRST before loading messages (since streaming filters them out)
1301
+ if ((opts.beforeCompaction || opts.compactionPhases) && sizeMB > 100) {
1302
+ s.compactionMarkers = await streamScanCompactions(s.filePath);
1303
+ }
1304
+
1305
+ // Use streaming for large files, sync for small files
1299
1306
  if (sizeMB > 100) {
1300
1307
  s.msgs = await streamReadJsonl(s.filePath);
1301
1308
  } else {
@@ -1329,8 +1336,32 @@ async function cmdLast(arg1, arg2, opts) {
1329
1336
 
1330
1337
  // Handle --compactions mode: show last N compaction phases instead of sessions
1331
1338
  if (opts.compactionPhases) {
1332
- const session = selected[0]; // Use only the most recent session
1333
- const compactions = scanCompactionMarkers(session.msgs);
1339
+ let session = selected[0]; // Use only the most recent session
1340
+ // Use pre-scanned markers if available (for large files), otherwise scan now
1341
+ let compactions = session.compactionMarkers || scanCompactionMarkers(session.msgs);
1342
+
1343
+ // If no compactions in current session, check previous session (new session fallback)
1344
+ if (compactions.length === 0 && inactiveSessions.length > 1) {
1345
+ const prevSession = inactiveSessions[1];
1346
+ // Load previous session if not already loaded
1347
+ if (!prevSession.msgs) {
1348
+ const stats = fs.statSync(prevSession.filePath);
1349
+ const sizeMB = stats.size / (1024 * 1024);
1350
+ if (sizeMB > 100) {
1351
+ prevSession.compactionMarkers = await streamScanCompactions(prevSession.filePath);
1352
+ prevSession.msgs = await streamReadJsonl(prevSession.filePath);
1353
+ } else {
1354
+ prevSession.msgs = readJsonl(prevSession.filePath);
1355
+ }
1356
+ }
1357
+ const prevCompactions = prevSession.compactionMarkers || scanCompactionMarkers(prevSession.msgs);
1358
+ if (prevCompactions.length > 0) {
1359
+ console.log('[session-recall v' + VERSION + '] No compactions in current session - using previous session');
1360
+ console.log('---');
1361
+ session = prevSession;
1362
+ compactions = prevCompactions;
1363
+ }
1364
+ }
1334
1365
 
1335
1366
  if (compactions.length === 0) {
1336
1367
  console.log('[session-recall v' + VERSION + '] No compaction events found - showing full session as single phase');
@@ -1545,7 +1576,8 @@ async function cmdLast(arg1, arg2, opts) {
1545
1576
  }
1546
1577
  // Apply before-compaction filter for dry-run
1547
1578
  if (opts.beforeCompaction && selected.length > 0) {
1548
- const compactions = scanCompactionMarkers(selected[0].msgs);
1579
+ // Use pre-scanned markers if available (for large files), otherwise scan now
1580
+ const compactions = selected[0].compactionMarkers || scanCompactionMarkers(selected[0].msgs);
1549
1581
  if (compactions.length > 0) {
1550
1582
  const n = opts.beforeCompactionN || compactions.length;
1551
1583
  if (n < 1 || n > compactions.length) {
@@ -1627,7 +1659,8 @@ async function cmdLast(arg1, arg2, opts) {
1627
1659
 
1628
1660
  // Filter to only show messages BEFORE the selected compaction boundary
1629
1661
  if (opts.beforeCompaction) {
1630
- const compactions = scanCompactionMarkers(session.msgs);
1662
+ // Use pre-scanned markers if available (for large files), otherwise scan now
1663
+ const compactions = session.compactionMarkers || scanCompactionMarkers(session.msgs);
1631
1664
  if (compactions.length > 0) {
1632
1665
  const n = opts.beforeCompactionN || compactions.length;
1633
1666
  if (n < 1 || n > compactions.length) {
@@ -2394,12 +2427,19 @@ function scanSessionTangents(filePath) {
2394
2427
  // ========== COMPACTION DETECTION ==========
2395
2428
 
2396
2429
  // Check if a message is a compaction marker
2430
+ // Supports both old format (progress + hook) and new format (system + subtype)
2397
2431
  function isCompactionMarker(msg) {
2398
- if (msg.type !== 'progress') return false;
2399
- if (!msg.data) return false;
2400
- return msg.data.type === 'hook_progress' &&
2401
- msg.data.hookEvent === 'SessionStart' &&
2402
- msg.data.hookName === 'SessionStart:compact';
2432
+ // New format (Claude Code 2.1+): system message with compact_boundary subtype
2433
+ if (msg.type === 'system' && msg.subtype === 'compact_boundary') {
2434
+ return true;
2435
+ }
2436
+ // Old format: progress message with hook
2437
+ if (msg.type === 'progress' && msg.data) {
2438
+ return msg.data.type === 'hook_progress' &&
2439
+ msg.data.hookEvent === 'SessionStart' &&
2440
+ msg.data.hookName === 'SessionStart:compact';
2441
+ }
2442
+ return false;
2403
2443
  }
2404
2444
 
2405
2445
  // Scan session for compaction markers with deduplication