@aiplumber/session-recall 1.6.0 → 1.6.7

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 +87 -58
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiplumber/session-recall",
3
- "version": "1.6.0",
3
+ "version": "1.6.7",
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,8 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ const VERSION = '1.6.7';
4
+
3
5
  const fs = require('fs');
4
6
  const path = require('path');
5
7
 
8
+ // Cross-platform home directory
9
+ const HOME = HOME || process.env.USERPROFILE;
10
+
6
11
  // Filter patterns
7
12
  const SHELL_PREFIXES = ['ls ', 'cat ', 'npm ', 'cd ', 'git ', 'mkdir ', 'rm ', 'cp ', 'mv ', 'grep ', 'find '];
8
13
  const NOISE_TYPES = ['progress', 'file-history-snapshot', 'system', 'queue-operation'];
@@ -983,7 +988,7 @@ function cwdToProjectFolder() {
983
988
  // Both / and . are replaced with -
984
989
  const cwd = process.cwd();
985
990
  const projectName = cwd.replace(/[\/\.]/g, '-');
986
- const projectsDir = path.join(process.env.HOME, '.claude', 'projects');
991
+ const projectsDir = path.join(HOME, '.claude', 'projects');
987
992
  const projectPath = path.join(projectsDir, projectName);
988
993
 
989
994
  if (fs.existsSync(projectPath)) {
@@ -996,7 +1001,7 @@ function cmdLast(arg1, arg2, opts) {
996
1001
  // Usage: last [N] [folder]
997
1002
  // arg1 could be: undefined, a number string, or a folder path
998
1003
  // arg2 could be: undefined, or a folder path (if arg1 was a number)
999
- const projectsDir = path.join(process.env.HOME, '.claude', 'projects');
1004
+ const projectsDir = path.join(HOME, '.claude', 'projects');
1000
1005
 
1001
1006
  let n = 1;
1002
1007
  let dir = null;
@@ -1200,26 +1205,31 @@ function cmdLast(arg1, arg2, opts) {
1200
1205
  return;
1201
1206
  }
1202
1207
 
1203
- // Output combined rinse (gotime mode)
1204
- let allMsgs = selected.flatMap(s => s.msgs);
1205
- // Sort by timestamp
1206
- allMsgs.sort((a, b) => new Date(a.timestamp || 0) - new Date(b.timestamp || 0));
1208
+ // Print header
1209
+ console.log(`[session-recall v${VERSION}] This context has been stripped of most tool results to reduce noise.`);
1210
+ console.log(`---`);
1207
1211
 
1208
- // Filter by checkpoint timestamp if --after was specified
1209
- if (filterAfterTs) {
1210
- allMsgs = allMsgs.filter(msg => {
1211
- const msgTs = msg.timestamp ? new Date(msg.timestamp).getTime() : 0;
1212
- return msgTs > filterAfterTs;
1213
- });
1214
- }
1212
+ // Process each session separately to add separators
1213
+ for (let sessionIdx = 0; sessionIdx < selected.length; sessionIdx++) {
1214
+ const session = selected[sessionIdx];
1215
+ let sessionMsgs = session.msgs;
1215
1216
 
1216
- // Build tool result metadata (size, duration)
1217
- const resultMeta = buildToolResultMeta(allMsgs);
1217
+ // Sort by timestamp
1218
+ sessionMsgs.sort((a, b) => new Date(a.timestamp || 0) - new Date(b.timestamp || 0));
1219
+
1220
+ // Filter by checkpoint timestamp if --after was specified
1221
+ if (filterAfterTs) {
1222
+ sessionMsgs = sessionMsgs.filter(msg => {
1223
+ const msgTs = msg.timestamp ? new Date(msg.timestamp).getTime() : 0;
1224
+ return msgTs > filterAfterTs;
1225
+ });
1226
+ }
1218
1227
 
1219
- // Build tag map for injection
1220
- // Tag map: { uuid -> { type, level, reason } }
1221
- const tagMap = {};
1222
- for (const session of selected) {
1228
+ // Build tool result metadata (size, duration)
1229
+ const resultMeta = buildToolResultMeta(sessionMsgs);
1230
+
1231
+ // Build tag map for this session
1232
+ const tagMap = {};
1223
1233
  const sessionTags = scanSessionTags(session.filePath);
1224
1234
  for (const tag of sessionTags) {
1225
1235
  if (tag.targetUuid) {
@@ -1230,62 +1240,69 @@ function cmdLast(arg1, arg2, opts) {
1230
1240
  };
1231
1241
  }
1232
1242
  }
1233
- }
1234
1243
 
1235
- for (const msg of allMsgs) {
1236
- if (NOISE_TYPES.includes(msg.type)) continue;
1244
+ for (const msg of sessionMsgs) {
1245
+ if (NOISE_TYPES.includes(msg.type)) continue;
1237
1246
 
1238
- // Check if this message has a tag
1239
- const toolId = getToolUseId(msg);
1240
- const msgUuid = toolId || msg.uuid;
1241
- const tag = msgUuid ? tagMap[msgUuid] : null;
1247
+ // Check if this message has a tag
1248
+ const toolId = getToolUseId(msg);
1249
+ const msgUuid = toolId || msg.uuid;
1250
+ const tag = msgUuid ? tagMap[msgUuid] : null;
1242
1251
 
1243
- // Determine if we should show this tag
1244
- const showTag = tag && (
1245
- tag.level === 'critical' ||
1246
- (tag.level === 'important' && opts.showImportant)
1247
- );
1252
+ // Determine if we should show this tag
1253
+ const showTag = tag && (
1254
+ tag.level === 'critical' ||
1255
+ (tag.level === 'important' && opts.showImportant)
1256
+ );
1248
1257
 
1249
- if (msg.type === 'user') {
1250
- if (isToolResult(msg)) continue;
1251
- const text = getUserText(msg);
1252
- if (text) {
1258
+ if (msg.type === 'user') {
1259
+ if (isToolResult(msg)) continue;
1260
+ const text = getUserText(msg);
1261
+ if (text) {
1262
+ const ts = msg.timestamp ? new Date(msg.timestamp).toISOString().substring(11, 19) : '';
1263
+ if (showTag) {
1264
+ const marker = tag.level === 'critical' ? '\u26A0' : '\u2139';
1265
+ console.log(`[${ts}] ${marker} ${tag.level.toUpperCase()} [${tag.type}] USER: ${text.substring(0, 500)}`);
1266
+ console.log(` Reason: "${tag.reason}"`);
1267
+ } else {
1268
+ console.log(`[${ts}] USER: ${text.substring(0, 500)}`);
1269
+ }
1270
+ }
1271
+ } else if (msg.type === 'assistant') {
1272
+ const text = getAssistantText(msg);
1273
+ const toolSummary = collapseToolCall(msg, resultMeta);
1253
1274
  const ts = msg.timestamp ? new Date(msg.timestamp).toISOString().substring(11, 19) : '';
1275
+
1254
1276
  if (showTag) {
1255
1277
  const marker = tag.level === 'critical' ? '\u26A0' : '\u2139';
1256
- console.log(`[${ts}] ${marker} ${tag.level.toUpperCase()} [${tag.type}] USER: ${text.substring(0, 500)}`);
1278
+ if (text) {
1279
+ console.log(`[${ts}] ${marker} ${tag.level.toUpperCase()} [${tag.type}] ASSISTANT: ${text.substring(0, 500)}`);
1280
+ } else if (toolSummary) {
1281
+ console.log(`[${ts}] ${marker} ${tag.level.toUpperCase()} [${tag.type}] ${toolSummary}`);
1282
+ }
1257
1283
  console.log(` Reason: "${tag.reason}"`);
1258
1284
  } else {
1259
- console.log(`[${ts}] USER: ${text.substring(0, 500)}`);
1285
+ if (text) {
1286
+ console.log(`[${ts}] ASSISTANT: ${text.substring(0, 500)}`);
1287
+ } else if (toolSummary) {
1288
+ console.log(`[${ts}] ASSISTANT: ${toolSummary}`);
1289
+ }
1260
1290
  }
1261
1291
  }
1262
- } else if (msg.type === 'assistant') {
1263
- const text = getAssistantText(msg);
1264
- const toolSummary = collapseToolCall(msg, resultMeta);
1265
- const ts = msg.timestamp ? new Date(msg.timestamp).toISOString().substring(11, 19) : '';
1292
+ }
1266
1293
 
1267
- if (showTag) {
1268
- const marker = tag.level === 'critical' ? '\u26A0' : '\u2139';
1269
- if (text) {
1270
- console.log(`[${ts}] ${marker} ${tag.level.toUpperCase()} [${tag.type}] ASSISTANT: ${text.substring(0, 500)}`);
1271
- } else if (toolSummary) {
1272
- console.log(`[${ts}] ${marker} ${tag.level.toUpperCase()} [${tag.type}] ${toolSummary}`);
1273
- }
1274
- console.log(` Reason: "${tag.reason}"`);
1275
- } else {
1276
- if (text) {
1277
- console.log(`[${ts}] ASSISTANT: ${text.substring(0, 500)}`);
1278
- } else if (toolSummary) {
1279
- console.log(`[${ts}] ASSISTANT: ${toolSummary}`);
1280
- }
1281
- }
1294
+ // Print session separator if not the last session
1295
+ if (sessionIdx < selected.length - 1) {
1296
+ const nextSession = selected[sessionIdx + 1];
1297
+ const nextTs = nextSession.lastTs ? nextSession.lastTs.toISOString().replace('T', ' ').substring(0, 16) : 'unknown';
1298
+ console.log(`\n=== END SESSION ${sessionIdx + 1} === NEXT SESSION: ${nextSession.project} (${nextTs}) ===\n`);
1282
1299
  }
1283
1300
  }
1284
1301
 
1285
1302
  // Print instructions for Claude
1286
1303
  console.log(``);
1287
1304
  console.log(`---`);
1288
- console.log(`To get a specific tool result: session-recall tools --show <id>`);
1305
+ console.log(`Tool results: Most are noise. Only fetch with "session-recall tools --show <id>" when you see something you actually need.`);
1289
1306
  console.log(`Session file: ${selected[0]?.filePath || 'unknown'}`);
1290
1307
  }
1291
1308
 
@@ -1349,6 +1366,10 @@ TAGGING:
1349
1366
  tags [filter] List all tags in current project
1350
1367
  Filter by type or level
1351
1368
 
1369
+ OPTIONS:
1370
+ -v, --version Show version number
1371
+ -h, --help Show this help
1372
+
1352
1373
  EXAMPLES:
1353
1374
  session-recall last 1 -d # Check what's available
1354
1375
  session-recall last 1 -f text # Pull last session
@@ -1797,6 +1818,8 @@ function parseArgs(args) {
1797
1818
  opts.showImportant = true;
1798
1819
  } else if (arg === '-h' || arg === '--help') {
1799
1820
  opts.help = true;
1821
+ } else if (arg === '-v' || arg === '--version') {
1822
+ opts.version = true;
1800
1823
  } else if (!arg.startsWith('-')) {
1801
1824
  positional.push(arg);
1802
1825
  }
@@ -1810,6 +1833,12 @@ function parseArgs(args) {
1810
1833
  const args = process.argv.slice(2);
1811
1834
  const { opts, positional } = parseArgs(args);
1812
1835
 
1836
+ // Handle --version flag
1837
+ if (opts.version) {
1838
+ console.log(`session-recall v${VERSION}`);
1839
+ process.exit(0);
1840
+ }
1841
+
1813
1842
  // Handle --checkpoint flag first (no-op marker that gets logged)
1814
1843
  if (opts.checkpoint) {
1815
1844
  // Output marker format - this IS the checkpoint storage (searched in tool_result)
@@ -1818,7 +1847,7 @@ if (opts.checkpoint) {
1818
1847
 
1819
1848
  // Detect current session UUID by finding most recently modified .jsonl
1820
1849
  let currentUuid = 'unknown';
1821
- const claudeProjectsDir = path.join(process.env.HOME, '.claude', 'projects');
1850
+ const claudeProjectsDir = path.join(HOME, '.claude', 'projects');
1822
1851
  if (fs.existsSync(claudeProjectsDir)) {
1823
1852
  let newestFile = null;
1824
1853
  let newestTime = 0;