claude-mem-lite 3.57.0 → 3.58.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/adopt-cli.mjs +13 -7
- package/claudemd.mjs +14 -0
- package/hook-shared.mjs +4 -2
- package/hook-update.mjs +26 -0
- package/install.mjs +1 -1
- package/mem-cli.mjs +5 -3
- package/npm-shrinkwrap.json +4777 -0
- package/package.json +2 -1
- package/schema.mjs +43 -0
- package/scripts/launch.mjs +29 -3
- package/scripts/setup.sh +93 -7
- package/server.mjs +15 -26
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"plugins": [
|
|
11
11
|
{
|
|
12
12
|
"name": "claude-mem-lite",
|
|
13
|
-
"version": "3.
|
|
13
|
+
"version": "3.58.1",
|
|
14
14
|
"source": "./",
|
|
15
15
|
"description": "Persistent long-term memory for Claude Code via MCP — captures coding decisions, bugfixes, and context across sessions. Hybrid FTS5 + TF-IDF search with episode batching. Single SQLite DB, no external services. A lighter, lower-cost alternative to claude-mem (episode batching + a smaller model; cost savings are an internal estimate, not a measured benchmark)."
|
|
16
16
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-mem-lite",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.58.1",
|
|
4
4
|
"description": "Persistent long-term memory for Claude Code via MCP — captures coding decisions, bugfixes, and context across sessions. Hybrid FTS5 + TF-IDF search with episode batching. Single SQLite DB, no external services. A lighter, lower-cost alternative to claude-mem (episode batching + a smaller model; cost savings are an internal estimate, not a measured benchmark).",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "sdsrss"
|
package/adopt-cli.mjs
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
} from './memdir.mjs';
|
|
23
23
|
import {
|
|
24
24
|
writeManaged, removeManaged, isAdopted as claudeMdIsAdopted,
|
|
25
|
+
hasResidue as claudeMdHasResidue,
|
|
25
26
|
needsRefresh, migrateLegacyMemoryDir, hasLegacyMemdirSentinel,
|
|
26
27
|
claudeMdPath, detailDocPath,
|
|
27
28
|
} from './claudemd.mjs';
|
|
@@ -311,8 +312,8 @@ function statusAll() {
|
|
|
311
312
|
|
|
312
313
|
const known = listKnownProjectDirs();
|
|
313
314
|
let adoptedCount = 0;
|
|
314
|
-
for (const dir of known) if (
|
|
315
|
-
log(`[adopt --status] known projects (~/.claude.json): ${known.length} scanned, ${adoptedCount} with a CLAUDE.md managed block.`);
|
|
315
|
+
for (const dir of known) if (claudeMdHasResidue(dir, PLUGIN_SLUG)) adoptedCount++;
|
|
316
|
+
log(`[adopt --status] known projects (~/.claude.json): ${known.length} scanned, ${adoptedCount} with a CLAUDE.md managed block or partial residue (detail doc/state).`);
|
|
316
317
|
if (adoptedCount > 0) log('[adopt --status] run `claude-mem-lite unadopt --all` to remove every CLAUDE.md block.');
|
|
317
318
|
|
|
318
319
|
const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT ? 'set' : 'unset';
|
|
@@ -347,16 +348,20 @@ function unadoptAll(args) {
|
|
|
347
348
|
|
|
348
349
|
// 1. New scheme: scrub CLAUDE.md managed blocks across known project paths.
|
|
349
350
|
const projectDirs = listKnownProjectDirs();
|
|
350
|
-
let blocks = 0;
|
|
351
|
+
let blocks = 0, partial = 0;
|
|
351
352
|
for (const dir of projectDirs) {
|
|
352
|
-
|
|
353
|
+
// hasResidue, not isAdopted: the sweep must also catch PARTIAL residue
|
|
354
|
+
// (block without detail doc, or an orphaned doc/state sidecar) —
|
|
355
|
+
// isAdopted's block-AND-doc gate skipped those projects forever.
|
|
356
|
+
if (!claudeMdHasResidue(dir, PLUGIN_SLUG)) continue;
|
|
353
357
|
if (dryRun) {
|
|
354
|
-
log(`[unadopt --all --dry-run] ${dir} → would-remove CLAUDE.md block
|
|
358
|
+
log(`[unadopt --all --dry-run] ${dir} → would-remove plugin residue (CLAUDE.md block and/or detail doc/state)`);
|
|
355
359
|
blocks++;
|
|
356
360
|
continue;
|
|
357
361
|
}
|
|
358
362
|
const r = removeManaged(dir, PLUGIN_SLUG);
|
|
359
363
|
if (r.action === 'removed') { log(`[unadopt --all] ${dir} → removed`); blocks++; }
|
|
364
|
+
else { log(`[unadopt --all] ${dir} → cleaned partial residue (detail doc/state, no block)`); partial++; }
|
|
360
365
|
}
|
|
361
366
|
|
|
362
367
|
// 2. Legacy memory-dir cleanup across every memdir (foreign-content guarded).
|
|
@@ -372,7 +377,8 @@ function unadoptAll(args) {
|
|
|
372
377
|
}
|
|
373
378
|
|
|
374
379
|
log('');
|
|
375
|
-
|
|
380
|
+
const partialNote = partial > 0 ? ` (+${partial} partial-residue cleanup(s))` : '';
|
|
381
|
+
log(`[unadopt --all] ${dryRun ? 'would remove' : 'removed'} ${blocks} CLAUDE.md block(s)${partialNote} across ${projectDirs.length} known project(s); ${legacy} legacy memory-dir sentinel(s) ${dryRun ? 'pending' : 'cleaned'}.`);
|
|
376
382
|
if (projectDirs.length === 0) {
|
|
377
383
|
log('[unadopt --all] no known projects found in ~/.claude.json — if a project was adopted but never opened in Claude Code, run `claude-mem-lite unadopt` from inside it.');
|
|
378
384
|
}
|
|
@@ -389,7 +395,7 @@ export function cmdUnadopt(args = []) {
|
|
|
389
395
|
|
|
390
396
|
const cwd = detectCwd();
|
|
391
397
|
if (dryRun) {
|
|
392
|
-
const blockState =
|
|
398
|
+
const blockState = claudeMdHasResidue(cwd, PLUGIN_SLUG) ? 'would-remove CLAUDE.md block + detail doc' : 'no CLAUDE.md block';
|
|
393
399
|
const legacy = hasLegacyMemdirSentinel(cwd, PLUGIN_SLUG) ? 'would-clean legacy memory-dir sentinel' : 'no legacy residue';
|
|
394
400
|
log(`[unadopt --dry-run] ${cwd}`);
|
|
395
401
|
log(` ${blockState}`);
|
package/claudemd.mjs
CHANGED
|
@@ -98,6 +98,20 @@ export function isAdopted(cwd, slug) {
|
|
|
98
98
|
return blk.body !== null && existsSync(detailDocPath(cwd, slug));
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Any trace of adoption that unadopt should clean: managed block OR detail doc
|
|
103
|
+
* OR state sidecar. Deliberately weaker than isAdopted (whose AND lets a
|
|
104
|
+
* half-written adopt self-heal on the next SessionStart): the unadopt sweep
|
|
105
|
+
* gated on isAdopted skipped partial residue forever — e.g. a user deleted the
|
|
106
|
+
* detail doc but the CLAUDE.md block remained, and `unadopt --all` never
|
|
107
|
+
* removed it. removeManaged cleans all three pieces, so sweep on any of them.
|
|
108
|
+
*/
|
|
109
|
+
export function hasResidue(cwd, slug) {
|
|
110
|
+
return readBlock(cwd, slug).body !== null
|
|
111
|
+
|| existsSync(detailDocPath(cwd, slug))
|
|
112
|
+
|| existsSync(stateFilePath(cwd, slug));
|
|
113
|
+
}
|
|
114
|
+
|
|
101
115
|
/**
|
|
102
116
|
* Whether the installed block/doc has drifted from the shipped content — i.e.
|
|
103
117
|
* a version bump or a template edit means we should refresh. Returns true when
|
package/hook-shared.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { randomUUID } from 'crypto';
|
|
|
6
6
|
import { join } from 'path';
|
|
7
7
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, renameSync, readdirSync, statSync, unlinkSync, chmodSync } from 'fs';
|
|
8
8
|
import { inferProject, debugCatch } from './utils.mjs';
|
|
9
|
-
import {
|
|
9
|
+
import { ensureDbWithWalRecovery, DB_DIR } from './schema.mjs';
|
|
10
10
|
import { getClaudePath as getClaudePathShared, resolveModel as resolveModelShared, flattenForCLI as _flattenForCLI, detectMode as detectLLMMode, callHaiku } from './haiku-client.mjs';
|
|
11
11
|
// Phase D: invited-memory sentinel detection. memdir.mjs/claudemd.mjs only pull in
|
|
12
12
|
// fs/path/os/crypto; adopt-content.mjs is pure strings. No circular deps —
|
|
@@ -154,7 +154,9 @@ export function createSessionId() {
|
|
|
154
154
|
|
|
155
155
|
export function openDb() {
|
|
156
156
|
try {
|
|
157
|
-
|
|
157
|
+
// WAL-corruption self-heal (was server.mjs-only): without it, hooks stayed
|
|
158
|
+
// silently dead (null DB) on a corrupt WAL until the next MCP server start.
|
|
159
|
+
return ensureDbWithWalRecovery();
|
|
158
160
|
} catch {
|
|
159
161
|
return null;
|
|
160
162
|
}
|
package/hook-update.mjs
CHANGED
|
@@ -635,6 +635,32 @@ function smokeInstalledRelease(targetDir) {
|
|
|
635
635
|
const p = join(targetDir, entry);
|
|
636
636
|
if (existsSync(p)) execSync(`${q(process.execPath)} --check ${q(p)}`, { timeout: 10000, stdio: 'ignore' });
|
|
637
637
|
}
|
|
638
|
+
// `cli.mjs help` exits without opening the DB, so it cannot see a
|
|
639
|
+
// present-but-unusable better-sqlite3 binding: npm >= 12 blocks
|
|
640
|
+
// install/lifecycle scripts by default, so the staging `npm install`
|
|
641
|
+
// above exits 0 with the native .node never compiled (a Node major bump
|
|
642
|
+
// strands a stale ABI the same way). Direct installs register server.mjs
|
|
643
|
+
// without the launch.mjs probe, so this gate is their only check. Probe
|
|
644
|
+
// in a child process (execSync so the unit-test mock intercepts, and so
|
|
645
|
+
// the running old-version process's require cache can't mask it); on
|
|
646
|
+
// failure rebuild with scripts enabled for just this dep — plain-rebuild
|
|
647
|
+
// fallback for older npm — then re-probe. A still-broken binding throws
|
|
648
|
+
// out of the try, smoke fails, and the caller rolls back to the old
|
|
649
|
+
// (working) install.
|
|
650
|
+
if (existsSync(join(targetDir, 'node_modules', 'better-sqlite3'))) {
|
|
651
|
+
const probeSrc = 'const{createRequire}=require("node:module");const D=createRequire(process.argv[1])("better-sqlite3");new D(":memory:").close();';
|
|
652
|
+
const probeCmd = `${q(process.execPath)} -e ${q(probeSrc)} ${q(join(targetDir, 'package.json'))}`;
|
|
653
|
+
try {
|
|
654
|
+
execSync(probeCmd, { timeout: 20000, stdio: 'ignore' });
|
|
655
|
+
} catch {
|
|
656
|
+
try {
|
|
657
|
+
execSync('npm rebuild better-sqlite3 --dangerously-allow-all-scripts', { cwd: targetDir, timeout: 120000, stdio: 'ignore' });
|
|
658
|
+
} catch {
|
|
659
|
+
execSync('npm rebuild better-sqlite3', { cwd: targetDir, timeout: 120000, stdio: 'ignore' });
|
|
660
|
+
}
|
|
661
|
+
execSync(probeCmd, { timeout: 20000, stdio: 'ignore' });
|
|
662
|
+
}
|
|
663
|
+
}
|
|
638
664
|
return true;
|
|
639
665
|
} catch (e) {
|
|
640
666
|
debugLog('WARN', 'hook-update', `post-install smoke failed (rolling back): ${e.message}`);
|
package/install.mjs
CHANGED
|
@@ -466,7 +466,7 @@ if (IS_DEV) {
|
|
|
466
466
|
ok(`better-sqlite3: ${verify.action}`);
|
|
467
467
|
} else {
|
|
468
468
|
fail(`better-sqlite3 binding unusable after rebuild: ${verify.error}`);
|
|
469
|
-
log('Try manually: cd ' + INSTALL_DIR + ' && npm rebuild better-sqlite3 --
|
|
469
|
+
log('Try manually: cd ' + INSTALL_DIR + ' && npm rebuild better-sqlite3 --dangerously-allow-all-scripts');
|
|
470
470
|
process.exit(1);
|
|
471
471
|
}
|
|
472
472
|
}
|
package/mem-cli.mjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// No MCP SDK or heavy deps — only imports schema.mjs and utils.mjs
|
|
4
4
|
|
|
5
5
|
import { homedir } from 'os';
|
|
6
|
-
import {
|
|
6
|
+
import { ensureDbWithWalRecovery, DB_PATH, DB_DIR, REGISTRY_DB_PATH } from './schema.mjs';
|
|
7
7
|
import { truncate, typeIcon, inferProject, scrubSecrets } from './utils.mjs';
|
|
8
8
|
import { resolveProject } from './project-utils.mjs';
|
|
9
9
|
import { TIER_CASE_SQL, tierSqlParams } from './tier.mjs';
|
|
@@ -3156,14 +3156,16 @@ export async function run(argv) {
|
|
|
3156
3156
|
}
|
|
3157
3157
|
|
|
3158
3158
|
// adopt / unadopt do pure filesystem work on ~/.claude/projects/<encoded>/memory/ —
|
|
3159
|
-
// no DB needed. Route them before
|
|
3159
|
+
// no DB needed. Route them before the DB open so an unbootable DB doesn't block.
|
|
3160
3160
|
if (cmd === 'adopt') { cmdAdopt(cmdArgs); return; }
|
|
3161
3161
|
if (cmd === 'unadopt') { cmdUnadopt(cmdArgs); return; }
|
|
3162
3162
|
if (cmd === 'memdir-audit') { cmdMemdirAudit(cmdArgs); return; }
|
|
3163
3163
|
|
|
3164
3164
|
let db;
|
|
3165
3165
|
try {
|
|
3166
|
-
|
|
3166
|
+
// Corruption-gated WAL recovery (shared with server/hooks) — a corrupt WAL
|
|
3167
|
+
// previously threw here with no auto-repair until the next MCP start.
|
|
3168
|
+
db = ensureDbWithWalRecovery({ warn: (m) => process.stderr.write(`[mem] ${m}\n`) });
|
|
3167
3169
|
} catch (e) {
|
|
3168
3170
|
out(`[mem] Error: Cannot open database: ${e.message}`);
|
|
3169
3171
|
out(`[mem] DB path: ${DB_PATH}`);
|