@remnic/core 9.3.658 → 9.3.660

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 (91) hide show
  1. package/dist/access-cli.js +17 -17
  2. package/dist/access-http.js +11 -10
  3. package/dist/access-mcp.js +10 -9
  4. package/dist/access-service.js +9 -8
  5. package/dist/briefing.js +4 -3
  6. package/dist/causal-consolidation.js +5 -4
  7. package/dist/causal-consolidation.js.map +1 -1
  8. package/dist/{chunk-QFKRE7AU.js → chunk-256W7AXC.js} +4 -4
  9. package/dist/{chunk-5PFIMBJJ.js → chunk-2EVZ5EN6.js} +12 -12
  10. package/dist/{chunk-SCPFRKIT.js → chunk-42JKGUFJ.js} +6 -2
  11. package/dist/{chunk-SCPFRKIT.js.map → chunk-42JKGUFJ.js.map} +1 -1
  12. package/dist/{chunk-2VCTTEJM.js → chunk-7H7J3ZWN.js} +3 -3
  13. package/dist/{chunk-QRSKPI62.js → chunk-7PCZGNG2.js} +2 -2
  14. package/dist/{chunk-ZCMO46YY.js → chunk-A7EF2XRO.js} +2 -2
  15. package/dist/{chunk-BNUAOLDK.js → chunk-ANJOULTP.js} +2 -2
  16. package/dist/{chunk-CPPS65WS.js → chunk-AWJ2FHCF.js} +84 -17
  17. package/dist/chunk-AWJ2FHCF.js.map +1 -0
  18. package/dist/{chunk-4PLOQDBB.js → chunk-AX5O25EF.js} +7 -5
  19. package/dist/chunk-AX5O25EF.js.map +1 -0
  20. package/dist/{chunk-7VWDC7AD.js → chunk-B57QYSWN.js} +17 -17
  21. package/dist/{chunk-BKRIAXTU.js → chunk-D2EFNQMY.js} +2 -2
  22. package/dist/{chunk-MBZAESQ3.js → chunk-F6O7IOS3.js} +2 -2
  23. package/dist/{chunk-KI6QM5AV.js → chunk-GY3V3SUI.js} +2 -2
  24. package/dist/{chunk-GGL7R2L2.js → chunk-MO77TWPS.js} +4 -4
  25. package/dist/{chunk-VJYFXDCZ.js → chunk-NMPEJV5M.js} +3 -3
  26. package/dist/{chunk-3R6OP33G.js → chunk-OYXVENIS.js} +3 -3
  27. package/dist/{chunk-7KSPKZIQ.js → chunk-PXVFMQLD.js} +3 -3
  28. package/dist/{chunk-FIS5RT6K.js → chunk-QXHBWFR3.js} +2 -2
  29. package/dist/{chunk-SSSXWIBP.js → chunk-R2EBP6CM.js} +2 -2
  30. package/dist/{chunk-6M4LYWA2.js → chunk-RP2U54GG.js} +5 -5
  31. package/dist/{chunk-G2VVBWFU.js → chunk-RQGR3ETH.js} +2 -2
  32. package/dist/{chunk-JI3LQFJH.js → chunk-TBLGI2LT.js} +2 -2
  33. package/dist/{chunk-RVT6U6PV.js → chunk-TWAJICBN.js} +2 -2
  34. package/dist/{chunk-46RXRASB.js → chunk-TYIXG4VR.js} +3 -3
  35. package/dist/{chunk-EKQMQQ3U.js → chunk-UNLHHTKN.js} +2 -2
  36. package/dist/cli.js +20 -19
  37. package/dist/compounding/engine.js +4 -3
  38. package/dist/connectors/codex-materialize-runner.js +4 -3
  39. package/dist/connectors/index.js +4 -3
  40. package/dist/entity-retrieval.js +4 -3
  41. package/dist/index.js +25 -25
  42. package/dist/maintenance/memory-governance.js +4 -3
  43. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +4 -3
  44. package/dist/maintenance/rebuild-memory-projection.js +5 -4
  45. package/dist/memory-cache.d.ts +43 -1
  46. package/dist/memory-cache.js +6 -1
  47. package/dist/namespaces/migrate.js +8 -7
  48. package/dist/namespaces/search.js +5 -4
  49. package/dist/namespaces/storage.js +4 -3
  50. package/dist/operator-toolkit.js +10 -9
  51. package/dist/orchestrator.js +15 -15
  52. package/dist/qmd-recall-cache.d.ts +4 -1
  53. package/dist/qmd-recall-cache.js +3 -1
  54. package/dist/qmd.js +3 -2
  55. package/dist/schemas.d.ts +24 -24
  56. package/dist/search/factory.js +4 -3
  57. package/dist/search/index.js +4 -3
  58. package/dist/semantic-consolidation.js +5 -4
  59. package/dist/semantic-rule-promotion.js +4 -3
  60. package/dist/semantic-rule-verifier.js +4 -3
  61. package/dist/storage.js +3 -2
  62. package/dist/verified-recall.js +4 -3
  63. package/package.json +1 -1
  64. package/src/memory-cache.test.ts +30 -0
  65. package/src/memory-cache.ts +129 -16
  66. package/src/qmd-recall-cache.ts +6 -0
  67. package/src/storage.ts +27 -3
  68. package/dist/chunk-4PLOQDBB.js.map +0 -1
  69. package/dist/chunk-CPPS65WS.js.map +0 -1
  70. /package/dist/{chunk-QFKRE7AU.js.map → chunk-256W7AXC.js.map} +0 -0
  71. /package/dist/{chunk-5PFIMBJJ.js.map → chunk-2EVZ5EN6.js.map} +0 -0
  72. /package/dist/{chunk-2VCTTEJM.js.map → chunk-7H7J3ZWN.js.map} +0 -0
  73. /package/dist/{chunk-QRSKPI62.js.map → chunk-7PCZGNG2.js.map} +0 -0
  74. /package/dist/{chunk-ZCMO46YY.js.map → chunk-A7EF2XRO.js.map} +0 -0
  75. /package/dist/{chunk-BNUAOLDK.js.map → chunk-ANJOULTP.js.map} +0 -0
  76. /package/dist/{chunk-7VWDC7AD.js.map → chunk-B57QYSWN.js.map} +0 -0
  77. /package/dist/{chunk-BKRIAXTU.js.map → chunk-D2EFNQMY.js.map} +0 -0
  78. /package/dist/{chunk-MBZAESQ3.js.map → chunk-F6O7IOS3.js.map} +0 -0
  79. /package/dist/{chunk-KI6QM5AV.js.map → chunk-GY3V3SUI.js.map} +0 -0
  80. /package/dist/{chunk-GGL7R2L2.js.map → chunk-MO77TWPS.js.map} +0 -0
  81. /package/dist/{chunk-VJYFXDCZ.js.map → chunk-NMPEJV5M.js.map} +0 -0
  82. /package/dist/{chunk-3R6OP33G.js.map → chunk-OYXVENIS.js.map} +0 -0
  83. /package/dist/{chunk-7KSPKZIQ.js.map → chunk-PXVFMQLD.js.map} +0 -0
  84. /package/dist/{chunk-FIS5RT6K.js.map → chunk-QXHBWFR3.js.map} +0 -0
  85. /package/dist/{chunk-SSSXWIBP.js.map → chunk-R2EBP6CM.js.map} +0 -0
  86. /package/dist/{chunk-6M4LYWA2.js.map → chunk-RP2U54GG.js.map} +0 -0
  87. /package/dist/{chunk-G2VVBWFU.js.map → chunk-RQGR3ETH.js.map} +0 -0
  88. /package/dist/{chunk-JI3LQFJH.js.map → chunk-TBLGI2LT.js.map} +0 -0
  89. /package/dist/{chunk-RVT6U6PV.js.map → chunk-TWAJICBN.js.map} +0 -0
  90. /package/dist/{chunk-46RXRASB.js.map → chunk-TYIXG4VR.js.map} +0 -0
  91. /package/dist/{chunk-EKQMQQ3U.js.map → chunk-UNLHHTKN.js.map} +0 -0
@@ -11,13 +11,13 @@ import {
11
11
  } from "./chunk-D24OXEPB.js";
12
12
  import {
13
13
  EngramAccessInputError
14
- } from "./chunk-6M4LYWA2.js";
14
+ } from "./chunk-RP2U54GG.js";
15
15
  import {
16
16
  projectTagProjectId
17
17
  } from "./chunk-GYSYLGNE.js";
18
18
  import {
19
19
  validateBriefingFormat
20
- } from "./chunk-KI6QM5AV.js";
20
+ } from "./chunk-GY3V3SUI.js";
21
21
  import {
22
22
  resolvePrincipal
23
23
  } from "./chunk-UZYLX7M6.js";
@@ -3117,4 +3117,4 @@ ${body}`;
3117
3117
  export {
3118
3118
  EngramMcpServer
3119
3119
  };
3120
- //# sourceMappingURL=chunk-2VCTTEJM.js.map
3120
+ //# sourceMappingURL=chunk-7H7J3ZWN.js.map
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  getCachedQmdSearch,
9
9
  setCachedQmdSearch
10
- } from "./chunk-CPPS65WS.js";
10
+ } from "./chunk-AWJ2FHCF.js";
11
11
  import {
12
12
  mergeEnv
13
13
  } from "./chunk-JUC24CTX.js";
@@ -2136,4 +2136,4 @@ export {
2136
2136
  getQmdCommandName,
2137
2137
  QmdClient
2138
2138
  };
2139
- //# sourceMappingURL=chunk-QRSKPI62.js.map
2139
+ //# sourceMappingURL=chunk-7PCZGNG2.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  StorageManager
3
- } from "./chunk-4PLOQDBB.js";
3
+ } from "./chunk-AX5O25EF.js";
4
4
  import {
5
5
  decideLifecycleTransition
6
6
  } from "./chunk-TBBDFYXW.js";
@@ -729,4 +729,4 @@ export {
729
729
  listMemoryGovernanceRuns,
730
730
  readMemoryGovernanceRunArtifact
731
731
  };
732
- //# sourceMappingURL=chunk-ZCMO46YY.js.map
732
+ //# sourceMappingURL=chunk-A7EF2XRO.js.map
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-3UXOZBHV.js";
8
8
  import {
9
9
  StorageManager
10
- } from "./chunk-4PLOQDBB.js";
10
+ } from "./chunk-AX5O25EF.js";
11
11
  import {
12
12
  isSafeRouteNamespace
13
13
  } from "./chunk-U3PN77QT.js";
@@ -118,4 +118,4 @@ export {
118
118
  runCodexMaterialize,
119
119
  runPostConsolidationMaterialize
120
120
  };
121
- //# sourceMappingURL=chunk-BNUAOLDK.js.map
121
+ //# sourceMappingURL=chunk-ANJOULTP.js.map
@@ -1,3 +1,8 @@
1
+ import {
2
+ clearQmdRecallCache,
3
+ qmdRecallCacheSize
4
+ } from "./chunk-42JKGUFJ.js";
5
+
1
6
  // src/memory-cache.ts
2
7
  var hotCacheByDir = /* @__PURE__ */ new Map();
3
8
  var archiveCacheByDir = /* @__PURE__ */ new Map();
@@ -32,8 +37,14 @@ function setCachedArchivedMemories(baseDir, memories, version) {
32
37
  archiveCacheByDir.set(baseDir, { memories: map, version, loadedAt: Date.now() });
33
38
  }
34
39
  var entityCacheByDir = /* @__PURE__ */ new Map();
35
- function buildEntityCacheKey(baseDir, schemaKey = "") {
36
- return `${baseDir}\0${schemaKey}`;
40
+ function normalizeEntitySchemaKey(schemaKey) {
41
+ return schemaKey ?? "";
42
+ }
43
+ function entityCacheKeyPrefix(baseDir) {
44
+ return `${baseDir}\0`;
45
+ }
46
+ function buildEntityCacheKey(baseDir, schemaKey) {
47
+ return `${entityCacheKeyPrefix(baseDir)}${normalizeEntitySchemaKey(schemaKey)}`;
37
48
  }
38
49
  function getCachedEntities(baseDir, currentVersion, schemaKey = "") {
39
50
  if (currentVersion === 0) return null;
@@ -49,7 +60,7 @@ function setCachedEntities(baseDir, entities, version, schemaKey = "") {
49
60
  });
50
61
  }
51
62
  function invalidateCachedEntities(baseDir) {
52
- const prefix = `${baseDir}\0`;
63
+ const prefix = entityCacheKeyPrefix(baseDir);
53
64
  for (const key of entityCacheByDir.keys()) {
54
65
  if (key.startsWith(prefix)) entityCacheByDir.delete(key);
55
66
  }
@@ -111,21 +122,75 @@ function setCachedQmdSearch(cacheKey, results) {
111
122
  }
112
123
  }
113
124
  }
125
+ var ALL_CACHE_LAYERS = [
126
+ {
127
+ name: "hot-memories",
128
+ scope: "dir",
129
+ invalidateForDir: (baseDir) => void hotCacheByDir.delete(baseDir),
130
+ clearAll: () => hotCacheByDir.clear(),
131
+ hasEntriesFor: (baseDir) => hotCacheByDir.has(baseDir)
132
+ },
133
+ {
134
+ name: "archive-memories",
135
+ scope: "dir",
136
+ invalidateForDir: (baseDir) => void archiveCacheByDir.delete(baseDir),
137
+ clearAll: () => archiveCacheByDir.clear(),
138
+ hasEntriesFor: (baseDir) => archiveCacheByDir.has(baseDir)
139
+ },
140
+ {
141
+ name: "entities",
142
+ scope: "dir",
143
+ invalidateForDir: (baseDir) => invalidateCachedEntities(baseDir),
144
+ clearAll: () => entityCacheByDir.clear(),
145
+ hasEntriesFor: (baseDir) => {
146
+ const prefix = entityCacheKeyPrefix(baseDir);
147
+ for (const key of entityCacheByDir.keys()) {
148
+ if (key.startsWith(prefix)) return true;
149
+ }
150
+ return false;
151
+ }
152
+ },
153
+ {
154
+ name: "derived-episode-map",
155
+ scope: "dir",
156
+ invalidateForDir: (baseDir) => void episodeMapByDir.delete(baseDir),
157
+ clearAll: () => episodeMapByDir.clear(),
158
+ hasEntriesFor: (baseDir) => episodeMapByDir.has(baseDir)
159
+ },
160
+ {
161
+ name: "derived-rule-memories",
162
+ scope: "dir",
163
+ invalidateForDir: (baseDir) => void ruleMemoriesByDir.delete(baseDir),
164
+ clearAll: () => ruleMemoriesByDir.clear(),
165
+ hasEntriesFor: (baseDir) => ruleMemoriesByDir.has(baseDir)
166
+ },
167
+ {
168
+ name: "qmd-search",
169
+ scope: "global",
170
+ invalidateForDir: () => qmdSearchCache.clear(),
171
+ clearAll: () => qmdSearchCache.clear(),
172
+ hasEntriesFor: () => qmdSearchCache.size > 0
173
+ },
174
+ {
175
+ name: "qmd-recall",
176
+ scope: "global",
177
+ invalidateForDir: () => clearQmdRecallCache(),
178
+ clearAll: () => clearQmdRecallCache(),
179
+ hasEntriesFor: () => qmdRecallCacheSize() > 0
180
+ }
181
+ ];
182
+ function invalidateAllForDir(baseDir) {
183
+ for (const layer of ALL_CACHE_LAYERS) {
184
+ layer.invalidateForDir(baseDir);
185
+ }
186
+ }
114
187
  function clearMemoryCache(baseDir) {
115
188
  if (baseDir) {
116
- hotCacheByDir.delete(baseDir);
117
- archiveCacheByDir.delete(baseDir);
118
- invalidateCachedEntities(baseDir);
119
- episodeMapByDir.delete(baseDir);
120
- ruleMemoriesByDir.delete(baseDir);
121
- qmdSearchCache.clear();
122
- } else {
123
- hotCacheByDir.clear();
124
- archiveCacheByDir.clear();
125
- entityCacheByDir.clear();
126
- episodeMapByDir.clear();
127
- ruleMemoriesByDir.clear();
128
- qmdSearchCache.clear();
189
+ invalidateAllForDir(baseDir);
190
+ return;
191
+ }
192
+ for (const layer of ALL_CACHE_LAYERS) {
193
+ layer.clearAll();
129
194
  }
130
195
  }
131
196
  function getMemoryCacheStats(baseDir) {
@@ -155,7 +220,9 @@ export {
155
220
  setCachedRuleMemories,
156
221
  getCachedQmdSearch,
157
222
  setCachedQmdSearch,
223
+ ALL_CACHE_LAYERS,
224
+ invalidateAllForDir,
158
225
  clearMemoryCache,
159
226
  getMemoryCacheStats
160
227
  };
161
- //# sourceMappingURL=chunk-CPPS65WS.js.map
228
+ //# sourceMappingURL=chunk-AWJ2FHCF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/memory-cache.ts"],"sourcesContent":["import type { EntityFile, MemoryFile } from \"./types.js\";\nimport { clearQmdRecallCache, qmdRecallCacheSize } from \"./qmd-recall-cache.js\";\n\ninterface CacheEntry {\n memories: Map<string, MemoryFile>; // keyed by file path\n version: number;\n loadedAt: number;\n}\n\n// Module-level singleton — shared across all StorageManager instances and sessions\nconst hotCacheByDir = new Map<string, CacheEntry>();\nconst archiveCacheByDir = new Map<string, CacheEntry>();\n\nexport function getCachedMemories(baseDir: string, currentVersion: number): MemoryFile[] | null {\n // Don't serve from cache when version tracking is unavailable (version=0).\n // This ensures tests and fresh installs without a version file always read disk.\n if (currentVersion === 0) return null;\n const entry = hotCacheByDir.get(baseDir);\n if (!entry || entry.version !== currentVersion) return null;\n return [...entry.memories.values()];\n}\n\nexport function setCachedMemories(baseDir: string, memories: MemoryFile[], version: number): void {\n const map = new Map<string, MemoryFile>();\n for (const m of memories) map.set(m.path, m);\n hotCacheByDir.set(baseDir, { memories: map, version, loadedAt: Date.now() });\n}\n\nexport function updateCacheOnWrite(baseDir: string, memory: MemoryFile): void {\n const entry = hotCacheByDir.get(baseDir);\n if (entry) entry.memories.set(memory.path, memory);\n}\n\nexport function updateCacheOnDelete(baseDir: string, filePath: string): void {\n const entry = hotCacheByDir.get(baseDir);\n if (entry) entry.memories.delete(filePath);\n}\n\n// Archive cache — same pattern, separate store\nexport function getCachedArchivedMemories(baseDir: string, currentVersion: number): MemoryFile[] | null {\n if (currentVersion === 0) return null;\n const entry = archiveCacheByDir.get(baseDir);\n if (!entry || entry.version !== currentVersion) return null;\n return [...entry.memories.values()];\n}\n\nexport function setCachedArchivedMemories(baseDir: string, memories: MemoryFile[], version: number): void {\n const map = new Map<string, MemoryFile>();\n for (const m of memories) map.set(m.path, m);\n archiveCacheByDir.set(baseDir, { memories: map, version, loadedAt: Date.now() });\n}\n\n// Entity cache — same pattern as memory cache, but keyed by schema-aware parse inputs.\nconst entityCacheByDir = new Map<string, { entities: EntityFile[]; version: number; loadedAt: number }>();\n\n/**\n * Single normalization point for the entity-cache schema key (issue #1535).\n * BOTH the set/get key builder and the prefix invalidation derive from here so\n * `undefined` vs `\"\"` (or any future normalization rule) can never diverge\n * between the write path and the invalidate path (rule 38 cousin).\n */\nfunction normalizeEntitySchemaKey(schemaKey: string | undefined): string {\n return schemaKey ?? \"\";\n}\n\n/** Prefix shared by every entity-cache key for a dir, regardless of schemaKey. */\nfunction entityCacheKeyPrefix(baseDir: string): string {\n return `${baseDir}\\u0000`;\n}\n\nfunction buildEntityCacheKey(baseDir: string, schemaKey?: string): string {\n return `${entityCacheKeyPrefix(baseDir)}${normalizeEntitySchemaKey(schemaKey)}`;\n}\n\nexport function getCachedEntities(\n baseDir: string,\n currentVersion: number,\n schemaKey: string = \"\",\n): EntityFile[] | null {\n if (currentVersion === 0) return null;\n const entry = entityCacheByDir.get(buildEntityCacheKey(baseDir, schemaKey));\n if (!entry || entry.version !== currentVersion) return null;\n return entry.entities;\n}\n\nexport function setCachedEntities(\n baseDir: string,\n entities: EntityFile[],\n version: number,\n schemaKey: string = \"\",\n): void {\n entityCacheByDir.set(buildEntityCacheKey(baseDir, schemaKey), {\n entities,\n version,\n loadedAt: Date.now(),\n });\n}\n\nexport function invalidateCachedEntities(baseDir: string): void {\n const prefix = entityCacheKeyPrefix(baseDir);\n for (const key of entityCacheByDir.keys()) {\n if (key.startsWith(prefix)) entityCacheByDir.delete(key);\n }\n}\n\n// Derived caches — pre-filtered views invalidated alongside the main cache.\n// These avoid O(146K) filter+map on every verified recall/rules call.\ninterface DerivedCacheEntry<T> {\n data: T;\n sourceVersion: number; // matches the hot cache version it was derived from\n}\n\nconst episodeMapByDir = new Map<string, DerivedCacheEntry<Map<string, MemoryFile>>>();\nconst ruleMemoriesByDir = new Map<string, DerivedCacheEntry<{ all: MemoryFile[]; byId: Map<string, MemoryFile> }>>();\n\n/** Get a pre-filtered Map of episode memories (keyed by ID). Derived from hot cache. */\nexport function getCachedEpisodeMap(baseDir: string, currentVersion: number): Map<string, MemoryFile> | null {\n if (currentVersion === 0) return null;\n const entry = episodeMapByDir.get(baseDir);\n if (!entry || entry.sourceVersion !== currentVersion) return null;\n return entry.data;\n}\n\n/** Build and cache the episode memory map from the full memory list. */\nexport function setCachedEpisodeMap(baseDir: string, memories: MemoryFile[], version: number): Map<string, MemoryFile> {\n const map = new Map<string, MemoryFile>();\n for (const m of memories) {\n if (m.frontmatter.status === \"archived\" || m.frontmatter.status === \"forgotten\") continue;\n if (m.frontmatter.memoryKind !== \"episode\") continue;\n map.set(m.frontmatter.id, m);\n }\n episodeMapByDir.set(baseDir, { data: map, sourceVersion: version });\n return map;\n}\n\n/** Get pre-filtered rule memories. Derived from hot cache. */\nexport function getCachedRuleMemories(baseDir: string, currentVersion: number): { all: MemoryFile[]; byId: Map<string, MemoryFile> } | null {\n if (currentVersion === 0) return null;\n const entry = ruleMemoriesByDir.get(baseDir);\n if (!entry || entry.sourceVersion !== currentVersion) return null;\n return entry.data;\n}\n\n/** Build and cache the rule memories from the full memory list. */\nexport function setCachedRuleMemories(baseDir: string, memories: MemoryFile[], version: number): { all: MemoryFile[]; byId: Map<string, MemoryFile> } {\n const byId = new Map<string, MemoryFile>();\n const all: MemoryFile[] = [];\n for (const m of memories) {\n byId.set(m.frontmatter.id, m);\n if (\n m.frontmatter.category === \"rule\" &&\n m.frontmatter.status !== \"archived\" &&\n m.frontmatter.status !== \"forgotten\"\n ) {\n all.push(m);\n }\n }\n const result = { all, byId };\n ruleMemoriesByDir.set(baseDir, { data: result, sourceVersion: version });\n return result;\n}\n\n// QMD search result cache — short-lived (60s TTL) to avoid stale results\n// while reducing redundant daemon calls for repeated/similar queries.\ninterface QmdCacheEntry {\n results: unknown[];\n cachedAt: number;\n}\nconst QMD_CACHE_TTL_MS = 60_000;\nconst qmdSearchCache = new Map<string, QmdCacheEntry>();\n\nexport function getCachedQmdSearch(cacheKey: string): unknown[] | null {\n const entry = qmdSearchCache.get(cacheKey);\n if (!entry) return null;\n if (Date.now() - entry.cachedAt > QMD_CACHE_TTL_MS) {\n qmdSearchCache.delete(cacheKey);\n return null;\n }\n return entry.results;\n}\n\nexport function setCachedQmdSearch(cacheKey: string, results: unknown[]): void {\n qmdSearchCache.set(cacheKey, { results, cachedAt: Date.now() });\n // Evict old entries to prevent unbounded growth\n if (qmdSearchCache.size > 200) {\n const now = Date.now();\n for (const [key, entry] of qmdSearchCache) {\n if (now - entry.cachedAt > QMD_CACHE_TTL_MS) qmdSearchCache.delete(key);\n }\n }\n}\n\n/**\n * Cache-layer registry (issue #1535).\n *\n * EVERY process-level cache that can serve memory-derived content is\n * enumerated here, and the single invalidation chokepoint\n * (`invalidateAllForDir`) iterates this list. Adding a new cache layer to\n * this module (or qmd-recall-cache.ts) REQUIRES registering it here —\n * otherwise mutations will never invalidate it (the exact bug this registry\n * exists to prevent) and the enumerate-all-layers fitness test in\n * tests/cache-invalidation-coherence.test.ts fails.\n */\nexport interface MemoryCacheLayer {\n /** Stable identifier used by tests and diagnostics. */\n readonly name: string;\n /** \"dir\" layers evict only entries for the given baseDir. \"global\" layers\n * are fully cleared on any mutation: their keys embed queries, namespaces,\n * and strategies rather than a storage dir, so a per-dir selective clear\n * is not possible without recording the dir in each entry. Full clear is\n * the simple-and-correct choice — these caches are re-warmable\n * (issue #1535, implementation guide option (b)). */\n readonly scope: \"dir\" | \"global\";\n /** Evict entries for baseDir (\"dir\" scope) or everything (\"global\" scope). */\n readonly invalidateForDir: (baseDir: string) => void;\n /** Evict every entry across all dirs. */\n readonly clearAll: () => void;\n /** True when the layer still holds entries for baseDir (\"dir\" scope) or\n * any entries at all (\"global\" scope). */\n readonly hasEntriesFor: (baseDir: string) => boolean;\n}\n\nexport const ALL_CACHE_LAYERS: readonly MemoryCacheLayer[] = [\n {\n name: \"hot-memories\",\n scope: \"dir\",\n invalidateForDir: (baseDir) => void hotCacheByDir.delete(baseDir),\n clearAll: () => hotCacheByDir.clear(),\n hasEntriesFor: (baseDir) => hotCacheByDir.has(baseDir),\n },\n {\n name: \"archive-memories\",\n scope: \"dir\",\n invalidateForDir: (baseDir) => void archiveCacheByDir.delete(baseDir),\n clearAll: () => archiveCacheByDir.clear(),\n hasEntriesFor: (baseDir) => archiveCacheByDir.has(baseDir),\n },\n {\n name: \"entities\",\n scope: \"dir\",\n invalidateForDir: (baseDir) => invalidateCachedEntities(baseDir),\n clearAll: () => entityCacheByDir.clear(),\n hasEntriesFor: (baseDir) => {\n const prefix = entityCacheKeyPrefix(baseDir);\n for (const key of entityCacheByDir.keys()) {\n if (key.startsWith(prefix)) return true;\n }\n return false;\n },\n },\n {\n name: \"derived-episode-map\",\n scope: \"dir\",\n invalidateForDir: (baseDir) => void episodeMapByDir.delete(baseDir),\n clearAll: () => episodeMapByDir.clear(),\n hasEntriesFor: (baseDir) => episodeMapByDir.has(baseDir),\n },\n {\n name: \"derived-rule-memories\",\n scope: \"dir\",\n invalidateForDir: (baseDir) => void ruleMemoriesByDir.delete(baseDir),\n clearAll: () => ruleMemoriesByDir.clear(),\n hasEntriesFor: (baseDir) => ruleMemoriesByDir.has(baseDir),\n },\n {\n name: \"qmd-search\",\n scope: \"global\",\n invalidateForDir: () => qmdSearchCache.clear(),\n clearAll: () => qmdSearchCache.clear(),\n hasEntriesFor: () => qmdSearchCache.size > 0,\n },\n {\n name: \"qmd-recall\",\n scope: \"global\",\n invalidateForDir: () => clearQmdRecallCache(),\n clearAll: () => clearQmdRecallCache(),\n hasEntriesFor: () => qmdRecallCacheSize() > 0,\n },\n];\n\n/**\n * The single invalidation chokepoint (issue #1535, rule 37).\n *\n * Every memory/entity mutation path must route through this function —\n * storage.ts calls it from its internal invalidation funnels\n * (invalidateAllMemoriesCache / invalidateColdMemoriesCache /\n * bumpMemoryStatusVersion / setSecureStoreKey). Nothing may clear an\n * individual layer ad hoc: partial clears are how the stale-recall bug\n * happened (qmdRecallCache was never invalidated on mutations, so recall\n * served pre-edit bundles for the remainder of its fresh/stale TTL window).\n */\nexport function invalidateAllForDir(baseDir: string): void {\n for (const layer of ALL_CACHE_LAYERS) {\n layer.invalidateForDir(baseDir);\n }\n}\n\nexport function clearMemoryCache(baseDir?: string): void {\n if (baseDir) {\n invalidateAllForDir(baseDir);\n return;\n }\n for (const layer of ALL_CACHE_LAYERS) {\n layer.clearAll();\n }\n}\n\nexport function getMemoryCacheStats(baseDir: string): {\n hotSize: number;\n archiveSize: number;\n hotVersion: number | null;\n archiveVersion: number | null;\n} {\n const hot = hotCacheByDir.get(baseDir);\n const archive = archiveCacheByDir.get(baseDir);\n return {\n hotSize: hot?.memories.size ?? 0,\n archiveSize: archive?.memories.size ?? 0,\n hotVersion: hot?.version ?? null,\n archiveVersion: archive?.version ?? null,\n };\n}\n"],"mappings":"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","names":[]}
@@ -16,9 +16,9 @@ import {
16
16
  } from "./chunk-AZBV4RRY.js";
17
17
  import {
18
18
  getCachedEntities,
19
- invalidateCachedEntities,
19
+ invalidateAllForDir,
20
20
  setCachedEntities
21
- } from "./chunk-CPPS65WS.js";
21
+ } from "./chunk-AWJ2FHCF.js";
22
22
  import {
23
23
  inferMemoryStatus,
24
24
  isArchivedMemoryPath,
@@ -1804,7 +1804,7 @@ var StorageManager = class _StorageManager {
1804
1804
  setSecureStoreKey(key, encryptOnWrite = true) {
1805
1805
  this._secureStoreKey = key;
1806
1806
  this._secureStoreEncryptOnWrite = encryptOnWrite;
1807
- invalidateCachedEntities(this.baseDir);
1807
+ invalidateAllForDir(this.baseDir);
1808
1808
  this.invalidateKnowledgeIndexCache();
1809
1809
  }
1810
1810
  getEntityCacheSecureStoreKey() {
@@ -1941,6 +1941,7 @@ var StorageManager = class _StorageManager {
1941
1941
  }
1942
1942
  bumpMemoryStatusVersion() {
1943
1943
  this.bumpSharedVersion("memory-status", _StorageManager.memoryStatusVersionByDir);
1944
+ invalidateAllForDir(this.baseDir);
1944
1945
  }
1945
1946
  getMemoryStatusVersion() {
1946
1947
  return this.readSharedVersion("memory-status", _StorageManager.memoryStatusVersionByDir);
@@ -2295,7 +2296,6 @@ var StorageManager = class _StorageManager {
2295
2296
  }
2296
2297
  async invalidateAfterOfflineSyncMutation(filePath) {
2297
2298
  this.invalidateAllMemoriesCache();
2298
- invalidateCachedEntities(this.baseDir);
2299
2299
  this.invalidateKnowledgeIndexCache();
2300
2300
  this.factHashIndexAuthoritative = false;
2301
2301
  await unlink(this.factHashIndexReadyPath).catch((error) => {
@@ -3103,6 +3103,7 @@ ${sanitized.text}
3103
3103
  * inside cold/, archiveMemory, etc.). */
3104
3104
  invalidateAllMemoriesCache() {
3105
3105
  _StorageManager.allMemoriesInFlight.delete(this.baseDir);
3106
+ invalidateAllForDir(this.baseDir);
3106
3107
  }
3107
3108
  /**
3108
3109
  * Invalidate the cold-scan cache for this storage root and bump the
@@ -3120,6 +3121,7 @@ ${sanitized.text}
3120
3121
  const coldRoot = path2.join(this.baseDir, "cold");
3121
3122
  _StorageManager.coldMemoriesCache.delete(coldRoot);
3122
3123
  this.bumpColdWriteVersion();
3124
+ invalidateAllForDir(this.baseDir);
3123
3125
  }
3124
3126
  /** Return the current cold-write version counter for this storage root.
3125
3127
  * Reads the on-disk sentinel (state/cold-write.log) so it reflects writes
@@ -5597,4 +5599,4 @@ export {
5597
5599
  serializeEntityFile,
5598
5600
  StorageManager
5599
5601
  };
5600
- //# sourceMappingURL=chunk-4PLOQDBB.js.map
5602
+ //# sourceMappingURL=chunk-AX5O25EF.js.map