claude-mem-lite 3.65.0 → 3.66.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/scoring-sql.mjs CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  import { buildNotLowSignalSql } from './lib/low-signal-patterns.mjs';
5
5
 
6
+ import { DAY_MS } from './lib/time-constants.mjs';
6
7
  // ─── Why these multipliers exist (read before "simplifying" them) ────────────
7
8
  //
8
9
  // The recency-decay, type-quality, project-boost, importance, cite, and noise
@@ -33,14 +34,14 @@ import { buildNotLowSignalSql } from './lib/low-signal-patterns.mjs';
33
34
 
34
35
  /** Recency half-life per observation type (in milliseconds) */
35
36
  export const DECAY_HALF_LIFE_BY_TYPE = {
36
- decision: 90 * 86400000, // 90 days — architectural decisions persist
37
- discovery: 60 * 86400000, // 60 days — learned patterns last
38
- feature: 30 * 86400000, // 30 days — feature work is mid-range
39
- bugfix: 14 * 86400000, // 14 days — bugs are usually one-off
40
- refactor: 14 * 86400000, // 14 days — code cleanup
41
- change: 7 * 86400000, // 7 days — routine changes decay fast
37
+ decision: 90 * DAY_MS, // 90 days — architectural decisions persist
38
+ discovery: 60 * DAY_MS, // 60 days — learned patterns last
39
+ feature: 30 * DAY_MS, // 30 days — feature work is mid-range
40
+ bugfix: 14 * DAY_MS, // 14 days — bugs are usually one-off
41
+ refactor: 14 * DAY_MS, // 14 days — code cleanup
42
+ change: 7 * DAY_MS, // 7 days — routine changes decay fast
42
43
  };
43
- export const DEFAULT_DECAY_HALF_LIFE_MS = 14 * 86400000;
44
+ export const DEFAULT_DECAY_HALF_LIFE_MS = 14 * DAY_MS;
44
45
 
45
46
  // ─── BM25 Weight Constants ──────────────────────────────────────────────────
46
47
  // Single source of truth for FTS5 BM25 weight expressions.
@@ -20,6 +20,7 @@ import { recordMetric } from '../lib/metrics.mjs';
20
20
  import { presentIdents } from '../lib/lesson-idents.mjs';
21
21
  import { neutralizeContextDelimiters } from '../format-utils.mjs';
22
22
 
23
+ import { DAY_MS } from '../lib/time-constants.mjs';
23
24
  // CLAUDE_MEM_DIR matches schema.mjs / main CLI — one env var sandboxes the
24
25
  // whole system. CLAUDE_MEM_DB_PATH / CLAUDE_MEM_RUNTIME_DIR remain as
25
26
  // per-component overrides for tests that mix isolated + real paths.
@@ -372,7 +373,7 @@ try {
372
373
  const fileMatch = fileMatchClause('of2');
373
374
  const fileParams = fileMatchParams(filePath);
374
375
  // 60-day lookback to avoid surfacing ancient observations
375
- const cutoff = Date.now() - 60 * 86400000;
376
+ const cutoff = Date.now() - 60 * DAY_MS;
376
377
 
377
378
  // Surface actionable lessons first, then high-importance bugfix/decision observations.
378
379
  // Priority: 1) observations with lesson_learned (most actionable for preventing repeat bugs)
@@ -18,6 +18,7 @@ import { recommendSkill } from '../registry-recommend.mjs';
18
18
  import { recordHookError } from '../lib/hook-telemetry.mjs';
19
19
  import { atomicWriteFileSync } from '../lib/atomic-write.mjs';
20
20
 
21
+ import { DAY_MS } from '../lib/time-constants.mjs';
21
22
  // ─── Constants ──────────────────────────────────────────────────────────────
22
23
 
23
24
  // Telemetry sink (lib/hook-telemetry.mjs contract): env override for tests, else
@@ -37,7 +38,7 @@ const injectedIdsFileFor = (sessionId) =>
37
38
  // gated by explicit "before/previously/记得" prompts where breadth is the
38
39
  // point). Env override for projects that want broader recall or to A/B.
39
40
  const MAX_RESULTS = Number(process.env.CLAUDE_MEM_UPS_MAX_RESULTS || 3);
40
- const LOOKBACK_MS = 60 * 86400000; // 60 days
41
+ const LOOKBACK_MS = 60 * DAY_MS; // 60 days
41
42
 
42
43
  // v2.56.x: Past-similar-questions fallback row cap. Cut from 3 → 1 after
43
44
  // 30d transcript scan (#8062 follow-up, 2026-05-09) showed UPS prompt-fallback
@@ -11,6 +11,7 @@ import { porterStem } from './tfidf.mjs';
11
11
  import { CLI_INVOKE } from './cli-path.mjs';
12
12
  import { liveObsFilterSql } from './lib/inject-search-core.mjs';
13
13
 
14
+ import { DAY_MS } from './lib/time-constants.mjs';
14
15
  // ─── MCP Server Instructions Builder ───────────────────────────────────────
15
16
  // Phase A (v2.31.3+): when quiet=true, drops WHEN-TO-USE proactive-trigger and
16
17
  // Decision-rules sections; keeps the irreducible CLI/MCP tool list. Intended
@@ -302,7 +303,7 @@ export function runIdleCleanup(db) {
302
303
 
303
304
  db.transaction(() => {
304
305
  for (const { types, days } of staleThresholds) {
305
- const cutoff = Date.now() - days * 86400000;
306
+ const cutoff = Date.now() - days * DAY_MS;
306
307
 
307
308
  const marked = db.prepare(`
308
309
  UPDATE observations SET compressed_into = ${COMPRESSED_PENDING_PURGE}
package/server.mjs CHANGED
@@ -52,6 +52,7 @@ import { probeOtherSources as probeIdSources, bucketIdTokens, splitDeferredToken
52
52
  import { saveObservation } from './lib/save-observation.mjs';
53
53
  import { applyObsUpdate } from './lib/observation-write.mjs';
54
54
  import { EXPORT_COLUMNS_SQL } from './lib/export-columns.mjs';
55
+ import { liveObsFilterSql } from './lib/inject-search-core.mjs';
55
56
  import { recallByFile } from './lib/recall-core.mjs';
56
57
  import { fetchRecent } from './lib/recent-core.mjs';
57
58
  import { AUTO_MERGE_THRESHOLD } from './lib/dedup-constants.mjs';
@@ -1032,7 +1033,7 @@ server.registerTool(
1032
1033
  if (args.project) args = { ...args, project: resolveProject(args.project) };
1033
1034
  const preview = args.preview !== false;
1034
1035
  const ageDays = args.age_days ?? 30;
1035
- const cutoff = Date.now() - ageDays * 86400000;
1036
+ const cutoff = Date.now() - ageDays * DAY_MS;
1036
1037
  const candidates = selectCompressionCandidates(db, { cutoff, project: args.project || null });
1037
1038
 
1038
1039
  if (candidates.length === 0) {
@@ -1181,7 +1182,7 @@ server.registerTool(
1181
1182
  // only rows a PRIOR run marked (backed up); rows decay marks below wait one cycle.
1182
1183
  if (ops.includes('purge_stale')) {
1183
1184
  const retainDays = args.retain_days ?? 30;
1184
- const retainCutoff = Date.now() - retainDays * 86400000;
1185
+ const retainCutoff = Date.now() - retainDays * DAY_MS;
1185
1186
  if (!purgeConfirmed) {
1186
1187
  // Dry-run preview (parity with CLI `maintain` without --confirm): the other
1187
1188
  // requested non-destructive ops still run below.
@@ -1687,8 +1688,12 @@ export async function handleExportForTest(db, args) {
1687
1688
  async function runExport(db, args) {
1688
1689
  const wheres = [];
1689
1690
  const params = [];
1690
- if (!args.include_compressed) wheres.push('COALESCE(compressed_into, 0) = 0');
1691
- wheres.push('superseded_at IS NULL');
1691
+ // Composed, not hand-written: the CLI twin (mem-cli.mjs cmdExport) already
1692
+ // routes through liveObsFilterSql, and a hand-rolled copy here is how the
1693
+ // live-row predicate drifted apart on other surfaces (P2-11/D#123). With
1694
+ // include_compressed the compressed half is dropped but retractions still
1695
+ // are not — tombstone export is opt-in, supersession is never exported.
1696
+ wheres.push(args.include_compressed ? 'superseded_at IS NULL' : liveObsFilterSql(''));
1692
1697
  if (args.project) { wheres.push('project = ?'); params.push(_resolveProjectShared(db, args.project)); }
1693
1698
  if (args.type) { wheres.push('type = ?'); params.push(args.type); }
1694
1699
  // T3-P1-A: surface invalid dates instead of silently dropping the filter — mirrors
@@ -1801,6 +1806,7 @@ server.registerTool(
1801
1806
  // Handler extracted to server/fts-check.mjs (v2.41 split).
1802
1807
  import { handleMemFtsCheck } from './server/fts-check.mjs';
1803
1808
 
1809
+ import { DAY_MS } from './lib/time-constants.mjs';
1804
1810
  server.registerTool(
1805
1811
  'mem_fts_check',
1806
1812
  {
package/source-files.mjs CHANGED
@@ -123,6 +123,12 @@ export const SOURCE_FILES = [
123
123
  // scripts/user-prompt-search.js + scripts/pre-tool-recall.js. Under lib/ for
124
124
  // the same scripts-dir-rename reason as mem-override.mjs above.
125
125
  'lib/injected-ids.mjs',
126
+ // P2-13 (narrowed): millisecond time units, single-sourced from the four
127
+ // modules that each declared their own DAY_MS. Leaf module, zero imports.
128
+ 'lib/time-constants.mjs',
129
+ // D#124: Key Context marker write + injection_count bump, shared by
130
+ // handleSessionStart and handlePreCompact. Statically imported by hook.mjs.
131
+ 'lib/keyctx-marker.mjs',
126
132
  // P2-11: injection-side shared SQL core (live-row filter / clamped decay /
127
133
  // injection relevance chain). Statically imported by hook.mjs, hook-memory.mjs,
128
134
  // search-engine.mjs AND the standalone hook scripts — missing it from the
package/tier.mjs CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  import { DECAY_HALF_LIFE_BY_TYPE } from './utils.mjs';
6
6
 
7
+ import { DAY_MS } from './lib/time-constants.mjs';
7
8
  // ─── Constants ────────────────────────────────────────────────────────────────
8
9
 
9
10
  const TWO_HOURS_MS = 2 * 3600000;
@@ -125,7 +126,7 @@ export function relativeTime(epoch, now) {
125
126
  const diff = Math.max(0, now - epoch);
126
127
  if (diff < 60000) return `${Math.floor(diff / 1000)}s ago`;
127
128
  if (diff < 3600000) return `${Math.floor(diff / 60000)}min ago`;
128
- if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;
129
- if (diff < 30 * 86400000) return `${Math.floor(diff / 86400000)}d ago`;
130
- return `${Math.floor(diff / (30 * 86400000))}mo ago`;
129
+ if (diff < DAY_MS) return `${Math.floor(diff / 3600000)}h ago`;
130
+ if (diff < 30 * DAY_MS) return `${Math.floor(diff / DAY_MS)}d ago`;
131
+ return `${Math.floor(diff / (30 * DAY_MS))}mo ago`;
131
132
  }