claude-mem-lite 2.90.0 → 2.90.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.
@@ -10,7 +10,7 @@
10
10
  "plugins": [
11
11
  {
12
12
  "name": "claude-mem-lite",
13
- "version": "2.90.0",
13
+ "version": "2.90.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": "2.90.0",
3
+ "version": "2.90.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/cli.mjs CHANGED
@@ -32,7 +32,10 @@ if (cmd === '--version' || cmd === '-v') {
32
32
  // No command: show CLI help if installed, install help if not
33
33
  const { existsSync } = await import('fs');
34
34
  const { join } = await import('path');
35
- const dbPath = join(process.env.HOME || '', '.claude-mem-lite', 'claude-mem-lite.db');
35
+ // D#29: honor CLAUDE_MEM_DIR so the install-vs-CLI help routing is correct on
36
+ // relocated installs (matches schema.mjs DB_DIR; HOME fallback when env unset).
37
+ const dataDir = process.env.CLAUDE_MEM_DIR || join(process.env.HOME || '', '.claude-mem-lite');
38
+ const dbPath = join(dataDir, 'claude-mem-lite.db');
36
39
  if (existsSync(dbPath)) {
37
40
  const { run } = await import('./mem-cli.mjs');
38
41
  await run(['help']);
package/mem-cli.mjs CHANGED
@@ -26,7 +26,7 @@ import { cmdAdopt, cmdUnadopt } from './adopt-cli.mjs';
26
26
  import { parseIntFlag, isNumericToken } from './lib/cli-flags.mjs';
27
27
  import { auditMemdir, memdirPath } from './memdir.mjs';
28
28
  import { probeOtherSources as probeIdSources, bucketIdTokens } from './lib/id-routing.mjs';
29
- import { basename, join } from 'path';
29
+ import { basename, join, sep } from 'path';
30
30
  import { readFileSync, existsSync, readdirSync } from 'fs';
31
31
 
32
32
  // v2.41: shared CLI helpers extracted to cli/common.mjs. Keep this file as the
@@ -2180,7 +2180,7 @@ function cmdRegistry(_memDb, args) {
2180
2180
  for (const r of results) {
2181
2181
  const badge = r.quality_tier === 'installed' ? '[✓]' : r.quality_tier === 'verified' ? '[★]' : '[○]';
2182
2182
  const categoryLabel = r.category ? ` [${r.category}]` : '';
2183
- const isManaged = r.local_path && r.local_path.includes('/.claude-mem-lite/managed/');
2183
+ const isManaged = r.local_path && r.local_path.includes(join(DB_DIR, 'managed') + sep);
2184
2184
  const portablePath = isManaged && r.local_path.startsWith(home) ? '~' + r.local_path.slice(home.length) : (r.local_path || '');
2185
2185
  let howToUse;
2186
2186
  if (isManaged) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-mem-lite",
3
- "version": "2.90.0",
3
+ "version": "2.90.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
  "type": "module",
6
6
  "packageManager": "npm@10.9.2",
@@ -8,9 +8,12 @@ import { debugLog, isPathConfined } from './utils.mjs';
8
8
  import { createHash } from 'crypto';
9
9
  import { mkdirSync, writeFileSync } from 'fs';
10
10
  import { join } from 'path';
11
- import { homedir } from 'os';
11
+ import { DB_DIR } from './schema.mjs';
12
12
 
13
- const MANAGED_DIR = join(homedir(), '.claude-mem-lite', 'managed');
13
+ // DATA artifact managed resources live under the env-aware data dir (DB_DIR),
14
+ // NOT a hardcoded homedir, so GitHub imports land where install.mjs + registry-scanner
15
+ // read them under CLAUDE_MEM_DIR relocation (D#29). Equals homedir when the env is unset.
16
+ const MANAGED_DIR = join(DB_DIR, 'managed');
14
17
 
15
18
  // ─── Tree Discovery ─────────────────────────────────────────────────────────
16
19
 
@@ -11,9 +11,15 @@ import { recordHookError } from '../lib/hook-telemetry.mjs';
11
11
  // CLAUDE_MEM_DIR mirrors pre-tool-recall.js — one env var sandboxes everything.
12
12
  const DATA_DIR = process.env.CLAUDE_MEM_DIR || join(homedir(), '.claude-mem-lite');
13
13
  const RUNTIME_DIR = process.env.CLAUDE_MEM_RUNTIME_DIR || join(DATA_DIR, 'runtime');
14
- const REGISTRY_DB_PATH = join(homedir(), '.claude-mem-lite', 'resource-registry.db');
15
- const MANAGED_BASE = join(homedir(), '.claude-mem-lite');
16
- const MANAGED_MARKER = '/.claude-mem-lite/managed/';
14
+ // D#29: all data artifacts follow DATA_DIR (CLAUDE_MEM_DIR-aware), not a hardcoded
15
+ // homedir — previously REGISTRY_DB_PATH/MANAGED_BASE/MARKER pinned homedir while line 12
16
+ // honored the env, so relocated installs opened the wrong DB and the marker never matched
17
+ // the relocated local_path. MANAGED_MARKER is only a coarse LIKE prefilter; the exact
18
+ // MANAGED_BASE prefix check below is the real confinement gate (so LIKE-wildcard chars in
19
+ // a relocated path can at worst over-admit to that gate, never bypass it).
20
+ const REGISTRY_DB_PATH = join(DATA_DIR, 'resource-registry.db');
21
+ const MANAGED_BASE = DATA_DIR;
22
+ const MANAGED_MARKER = join(DATA_DIR, 'managed') + sep;
17
23
 
18
24
  try {
19
25
  // Skip if recursive hook
@@ -8,7 +8,7 @@ import { sanitizeFtsQuery, relaxFtsQueryToOr, truncate, typeIcon, inferProject,
8
8
  import { citeFactorClause } from '../scoring-sql.mjs';
9
9
  import { cjkPrecisionOk } from '../nlp.mjs';
10
10
  import { writeFileSync, readFileSync, existsSync, renameSync } from 'fs';
11
- import { join } from 'path';
11
+ import { join, sep } from 'path';
12
12
  import Database from 'better-sqlite3';
13
13
  import { shouldSkip, computeEffectiveLen, detectIntent, shouldSkipByDedup, extractFiles, extractErrorSignature, DEDUP_STALE_MS, matchRegistrySkillName, detectMemOverride } from './prompt-search-utils.mjs';
14
14
 
@@ -439,10 +439,18 @@ function loadManagedSkillNames() {
439
439
  const rdb = new Database(REGISTRY_DB_PATH, { readonly: true });
440
440
  rdb.pragma('busy_timeout = 500');
441
441
  try {
442
+ // D#29: derive the managed marker from the env-aware data dir, not a hardcoded
443
+ // homedir literal — under CLAUDE_MEM_DIR relocation the stored local_path lives at
444
+ // DB_DIR/managed, so the old literal matched nothing and dropped every managed skill
445
+ // from injection. Coarse LIKE prefilter; resource names are re-validated downstream.
446
+ // D#29: derive the managed marker from the env-aware data dir, not a hardcoded
447
+ // homedir literal — under CLAUDE_MEM_DIR relocation the stored local_path lives at
448
+ // DB_DIR/managed, so the old literal matched nothing and dropped every managed skill
449
+ // from injection. Coarse LIKE prefilter; resource names are re-validated downstream.
442
450
  const rows = rdb.prepare(`
443
451
  SELECT name FROM resources
444
- WHERE status = 'active' AND local_path LIKE '%/.claude-mem-lite/managed/%'
445
- `).all();
452
+ WHERE status = 'active' AND local_path LIKE ?
453
+ `).all(`%${join(DB_DIR, 'managed') + sep}%`);
446
454
  return new Set(rows.map(r => r.name.toLowerCase()));
447
455
  } finally { rdb.close(); }
448
456
  } catch { return new Set(); }
package/server.mjs CHANGED
@@ -8,7 +8,7 @@ import { ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
8
8
  import { truncate, typeIcon, sanitizeFtsQuery, relaxFtsQueryToOr, inferProject, scrubSecrets, cjkBigrams, fmtDate, debugLog, debugCatch, SESS_BM25, DEFAULT_DECAY_HALF_LIFE_MS, isPathConfined, notLowSignalTitleClause } from './utils.mjs';
9
9
  import { extractCjkLikePatterns, cjkPrecisionOk } from './nlp.mjs';
10
10
  import { resolveProject as _resolveProjectShared } from './project-utils.mjs';
11
- import { ensureDb, DB_PATH, REGISTRY_DB_PATH } from './schema.mjs';
11
+ import { ensureDb, DB_PATH, DB_DIR, REGISTRY_DB_PATH } from './schema.mjs';
12
12
  import { reRankWithContext, markSuperseded, autoBoostIfNeeded, runIdleCleanup, buildServerInstructions } from './server-internals.mjs';
13
13
  import { searchObservationsHybrid, findFtsAnchor } from './search-engine.mjs';
14
14
  import { selectCompressionCandidates, groupByProjectWeek, compressGroup } from './lib/compress-core.mjs';
@@ -30,7 +30,7 @@ function descriptionOf(name) {
30
30
  return d;
31
31
  }
32
32
  import { optimizePreview, optimizeRun } from './hook-optimize.mjs';
33
- import { basename, join } from 'path';
33
+ import { basename, join, sep } from 'path';
34
34
  import { homedir } from 'os';
35
35
  import { ensureRegistryDb, upsertResource } from './registry.mjs';
36
36
  import { searchResources } from './registry-retriever.mjs';
@@ -1506,7 +1506,7 @@ server.registerTool(
1506
1506
  const lines = results.map(r => {
1507
1507
  const qualityBadge = r.quality_tier === 'installed' ? '[✓]' : r.quality_tier === 'verified' ? '[★]' : '[○]';
1508
1508
  const categoryLabel = r.category ? ` [${r.category}]` : '';
1509
- const isManaged = r.local_path && r.local_path.includes('/.claude-mem-lite/managed/');
1509
+ const isManaged = r.local_path && r.local_path.includes(join(DB_DIR, 'managed') + sep);
1510
1510
  const portablePath = isManaged ? toPortable(r.local_path) : '';
1511
1511
  let howToUse;
1512
1512
  if (isManaged) {
@@ -1651,7 +1651,9 @@ server.registerTool(
1651
1651
  if (!row.local_path) {
1652
1652
  return { content: [{ type: 'text', text: `No local_path for ${args.name}` }], isError: true };
1653
1653
  }
1654
- const enrichBase = join(homedir(), '.claude-mem-lite');
1654
+ // Confine to the env-aware data dir (managed/ relocates with CLAUDE_MEM_DIR, D#29);
1655
+ // === homedir when the env is unset, so non-relocated confinement is unchanged.
1656
+ const enrichBase = DB_DIR;
1655
1657
  if (!isPathConfined(row.local_path, enrichBase)) {
1656
1658
  return { content: [{ type: 'text', text: `Access denied: path outside managed directory` }], isError: true };
1657
1659
  }
@@ -1719,8 +1721,10 @@ server.registerTool(
1719
1721
  }
1720
1722
  }
1721
1723
 
1722
- // 4. Path confinement check — prevent reading arbitrary files via crafted local_path
1723
- const managedBase = join(homedir(), '.claude-mem-lite');
1724
+ // 4. Path confinement check — prevent reading arbitrary files via crafted local_path.
1725
+ // Base is the env-aware data dir (D#29): managed/ relocates with CLAUDE_MEM_DIR and
1726
+ // equals homedir when unset, so this does not weaken the non-relocated confinement.
1727
+ const managedBase = DB_DIR;
1724
1728
  if (skillPath && !isPathConfined(skillPath, managedBase)) {
1725
1729
  return { content: [{ type: 'text', text: `Access denied: path "${skillPath}" is outside managed directory` }], isError: true };
1726
1730
  }