claude-recall 0.24.0 → 0.24.2
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.
- package/dist/cli/claude-recall-cli.js +140 -34
- package/package.json +3 -1
|
@@ -261,6 +261,99 @@ class ClaudeRecallCLI {
|
|
|
261
261
|
});
|
|
262
262
|
this.logger.info('CLI', 'Failures displayed', { count: displayFailures.length });
|
|
263
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* Find project-local node_modules/claude-recall/ installs that shadow the
|
|
266
|
+
* global one when invoked via `npx claude-recall`. npx walks up from cwd
|
|
267
|
+
* looking for node_modules/.bin/claude-recall and uses the first match,
|
|
268
|
+
* not the globally-installed binary. A stray ~/node_modules/claude-recall/
|
|
269
|
+
* (a common WSL/Windows accident) traps every npx invocation under $HOME.
|
|
270
|
+
*
|
|
271
|
+
* Returns dir + version for each stale install found. Skips the global
|
|
272
|
+
* install (heuristic: paths containing /lib/node_modules/ or /.nvm/).
|
|
273
|
+
* Walk stops at $HOME so we never report or touch system locations.
|
|
274
|
+
*/
|
|
275
|
+
findStaleLocalInstalls() {
|
|
276
|
+
const found = [];
|
|
277
|
+
const seen = new Set();
|
|
278
|
+
const home = os.homedir();
|
|
279
|
+
const checkDir = (dir) => {
|
|
280
|
+
if (seen.has(dir))
|
|
281
|
+
return;
|
|
282
|
+
seen.add(dir);
|
|
283
|
+
const pkgPath = path.join(dir, 'node_modules', 'claude-recall', 'package.json');
|
|
284
|
+
if (!fs.existsSync(pkgPath))
|
|
285
|
+
return;
|
|
286
|
+
// Skip global install paths so we never propose nuking them.
|
|
287
|
+
if (pkgPath.includes('/lib/node_modules/'))
|
|
288
|
+
return;
|
|
289
|
+
if (pkgPath.includes('/.nvm/'))
|
|
290
|
+
return;
|
|
291
|
+
try {
|
|
292
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
293
|
+
if (pkg && typeof pkg.version === 'string') {
|
|
294
|
+
found.push({ dir, version: pkg.version });
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
// Unreadable manifest — skip silently.
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
// Walk cwd up to $HOME (don't traverse above the user's home).
|
|
302
|
+
let dir = process.cwd();
|
|
303
|
+
while (true) {
|
|
304
|
+
checkDir(dir);
|
|
305
|
+
if (dir === home)
|
|
306
|
+
break;
|
|
307
|
+
const parent = path.dirname(dir);
|
|
308
|
+
if (parent === dir)
|
|
309
|
+
break; // hit filesystem root
|
|
310
|
+
dir = parent;
|
|
311
|
+
}
|
|
312
|
+
// If cwd was outside the home tree, the walk skipped $HOME. Check it.
|
|
313
|
+
checkDir(home);
|
|
314
|
+
return found;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Print a warning about stale local installs. If `autoClean` is true,
|
|
318
|
+
* actually remove them. Otherwise print copy-paste rm commands.
|
|
319
|
+
*/
|
|
320
|
+
warnOrCleanStaleLocals(globalVersion, autoClean) {
|
|
321
|
+
const stale = this.findStaleLocalInstalls();
|
|
322
|
+
if (stale.length === 0)
|
|
323
|
+
return;
|
|
324
|
+
console.log('\n⚠ Stale local claude-recall installs detected:');
|
|
325
|
+
for (const s of stale) {
|
|
326
|
+
const drift = s.version !== globalVersion
|
|
327
|
+
? ` (drift: global is ${globalVersion})`
|
|
328
|
+
: '';
|
|
329
|
+
console.log(` ${path.join(s.dir, 'node_modules', 'claude-recall')} v${s.version}${drift}`);
|
|
330
|
+
}
|
|
331
|
+
console.log('');
|
|
332
|
+
console.log(' These shadow the global install. `npx claude-recall` walks up from cwd');
|
|
333
|
+
console.log(' looking for node_modules/.bin/claude-recall and uses the first match —');
|
|
334
|
+
console.log(` not the global v${globalVersion}.`);
|
|
335
|
+
if (autoClean) {
|
|
336
|
+
console.log('\n🧹 Removing...');
|
|
337
|
+
for (const s of stale) {
|
|
338
|
+
const target = path.join(s.dir, 'node_modules', 'claude-recall');
|
|
339
|
+
try {
|
|
340
|
+
fs.rmSync(target, { recursive: true, force: true });
|
|
341
|
+
console.log(` ✓ removed ${target}`);
|
|
342
|
+
}
|
|
343
|
+
catch (e) {
|
|
344
|
+
console.log(` ✗ failed to remove ${target}: ${e.message}`);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
console.log('\n Verify with: npx claude-recall --version');
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
console.log('\n To remove them all:');
|
|
351
|
+
for (const s of stale) {
|
|
352
|
+
console.log(` rm -rf ${path.join(s.dir, 'node_modules', 'claude-recall')}`);
|
|
353
|
+
}
|
|
354
|
+
console.log('\n Or re-run upgrade with auto-clean: claude-recall upgrade --clean-locals');
|
|
355
|
+
}
|
|
356
|
+
}
|
|
264
357
|
/**
|
|
265
358
|
* One-shot upgrade: check registry, install latest globally, clean up any
|
|
266
359
|
* running MCP servers (so fresh 0.x spawns on next Claude Code tool call).
|
|
@@ -269,8 +362,9 @@ class ClaudeRecallCLI {
|
|
|
269
362
|
* - EACCES on `/usr/lib/node_modules` → print sudo + permanent-prefix fix
|
|
270
363
|
* - No npm in PATH → actionable error
|
|
271
364
|
* - Registry unreachable → clear error, don't leave install half-done
|
|
365
|
+
* - Stale project-local installs shadowing the global → warn (or clean with --clean-locals)
|
|
272
366
|
*/
|
|
273
|
-
async upgrade() {
|
|
367
|
+
async upgrade(opts = {}) {
|
|
274
368
|
const { execSync, spawnSync } = require('child_process');
|
|
275
369
|
// Current version from package.json shipped with the installed binary
|
|
276
370
|
let current;
|
|
@@ -297,40 +391,51 @@ class ClaudeRecallCLI {
|
|
|
297
391
|
}
|
|
298
392
|
console.log(`Installed: ${current}`);
|
|
299
393
|
console.log(`Latest: ${latest}`);
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
394
|
+
const needsInstall = current !== latest;
|
|
395
|
+
if (needsInstall) {
|
|
396
|
+
console.log(`\n📦 Upgrading ${current} → ${latest}...\n`);
|
|
397
|
+
// Run npm install -g, streaming output so the user sees progress / errors live
|
|
398
|
+
const install = spawnSync('npm', ['install', '-g', 'claude-recall@latest'], {
|
|
399
|
+
stdio: 'inherit',
|
|
400
|
+
});
|
|
401
|
+
if (install.status !== 0) {
|
|
402
|
+
// npm prints its own error — add the practical remediation on top
|
|
403
|
+
console.error('\n❌ Install failed.');
|
|
404
|
+
console.error('\nMost common cause: your global npm prefix is owned by root (EACCES).');
|
|
405
|
+
console.error('\nQuick fix:');
|
|
406
|
+
console.error(' sudo npm install -g claude-recall');
|
|
407
|
+
console.error('\nPermanent fix (no more sudo for any global install on this machine):');
|
|
408
|
+
console.error(' mkdir -p ~/.npm-global');
|
|
409
|
+
console.error(" npm config set prefix ~/.npm-global");
|
|
410
|
+
console.error(" echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc");
|
|
411
|
+
console.error(' source ~/.bashrc');
|
|
412
|
+
console.error('\nThen re-run: claude-recall upgrade');
|
|
413
|
+
process.exit(install.status ?? 1);
|
|
414
|
+
}
|
|
415
|
+
// Kill any running MCP servers so Claude Code respawns them with the new binary
|
|
416
|
+
console.log('\n🧹 Cleaning up running MCP servers (Claude Code respawns them on next tool call)...');
|
|
417
|
+
try {
|
|
418
|
+
spawnSync('claude-recall', ['mcp', 'cleanup', '--all'], { stdio: 'inherit' });
|
|
419
|
+
}
|
|
420
|
+
catch {
|
|
421
|
+
// Non-fatal — the user can restart Claude Code manually if this fails
|
|
422
|
+
}
|
|
303
423
|
}
|
|
304
|
-
|
|
305
|
-
//
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
console.
|
|
313
|
-
console.
|
|
314
|
-
console.
|
|
315
|
-
console.error('\nPermanent fix (no more sudo for any global install on this machine):');
|
|
316
|
-
console.error(' mkdir -p ~/.npm-global');
|
|
317
|
-
console.error(" npm config set prefix ~/.npm-global");
|
|
318
|
-
console.error(" echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc");
|
|
319
|
-
console.error(' source ~/.bashrc');
|
|
320
|
-
console.error('\nThen re-run: claude-recall upgrade');
|
|
321
|
-
process.exit(install.status ?? 1);
|
|
322
|
-
}
|
|
323
|
-
// Kill any running MCP servers so Claude Code respawns them with the new binary
|
|
324
|
-
console.log('\n🧹 Cleaning up running MCP servers (Claude Code respawns them on next tool call)...');
|
|
325
|
-
try {
|
|
326
|
-
spawnSync('claude-recall', ['mcp', 'cleanup', '--all'], { stdio: 'inherit' });
|
|
424
|
+
// Detect stale project-local installs that would shadow the global binary
|
|
425
|
+
// when invoked via `npx claude-recall`. Runs on every upgrade invocation,
|
|
426
|
+
// including when already up-to-date — so `claude-recall upgrade` doubles
|
|
427
|
+
// as a diagnostic for the npx-walks-up-and-finds-stale-local trap, and
|
|
428
|
+
// `claude-recall upgrade --clean-locals` works as a one-shot cleanup
|
|
429
|
+
// command even when no version change is pending.
|
|
430
|
+
this.warnOrCleanStaleLocals(latest, opts.cleanLocals === true);
|
|
431
|
+
if (needsInstall) {
|
|
432
|
+
console.log(`\n✓ Upgraded to ${latest}. No need to re-run \`claude mcp add\` — existing`);
|
|
433
|
+
console.log(' registrations point at the `claude-recall` command and pick up the new');
|
|
434
|
+
console.log(' binary automatically. Just run any tool in Claude Code.');
|
|
327
435
|
}
|
|
328
|
-
|
|
329
|
-
|
|
436
|
+
else {
|
|
437
|
+
console.log('\n✓ Already up to date.');
|
|
330
438
|
}
|
|
331
|
-
console.log(`\n✓ Upgraded to ${latest}. No need to re-run \`claude mcp add\` — existing`);
|
|
332
|
-
console.log(' registrations point at the `claude-recall` command and pick up the new');
|
|
333
|
-
console.log(' binary automatically. Just run any tool in Claude Code.');
|
|
334
439
|
}
|
|
335
440
|
/**
|
|
336
441
|
* Demote rules loaded often but never cited — excludes them from future load_rules payloads.
|
|
@@ -1707,9 +1812,10 @@ async function main() {
|
|
|
1707
1812
|
program
|
|
1708
1813
|
.command('upgrade')
|
|
1709
1814
|
.description('Upgrade claude-recall to the latest version and clear stale MCP servers')
|
|
1710
|
-
.
|
|
1815
|
+
.option('--clean-locals', 'Also remove stale project-local installs that shadow the global binary')
|
|
1816
|
+
.action(async (options) => {
|
|
1711
1817
|
const cli = new ClaudeRecallCLI(program.opts());
|
|
1712
|
-
await cli.upgrade();
|
|
1818
|
+
await cli.upgrade({ cleanLocals: options.cleanLocals === true });
|
|
1713
1819
|
process.exit(0);
|
|
1714
1820
|
});
|
|
1715
1821
|
// Export command
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-recall",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.2",
|
|
4
4
|
"description": "Persistent memory for Claude Code and Pi with native Skills integration, automatic capture, failure learning, and project scoping",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -49,6 +49,8 @@
|
|
|
49
49
|
"search": "npm run claude-recall search",
|
|
50
50
|
"preuninstall": "node scripts/uninstall.js",
|
|
51
51
|
"prepare": "npm run build",
|
|
52
|
+
"prepublishOnly": "node scripts/check-publish.js",
|
|
53
|
+
"check:publish": "node scripts/check-publish.js",
|
|
52
54
|
"mcp:start": "node dist/cli/claude-recall-cli.js mcp start",
|
|
53
55
|
"mcp:dev": "ts-node src/cli/claude-recall-cli.ts mcp start",
|
|
54
56
|
"mcp:debug": "NODE_ENV=development DEBUG=claude-recall:* ts-node src/cli/claude-recall-cli.ts mcp start",
|