@remnic/core 9.3.654 → 9.3.656

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 (281) hide show
  1. package/dist/access-cli.js +29 -29
  2. package/dist/access-http.d.ts +4 -4
  3. package/dist/access-http.js +17 -17
  4. package/dist/access-mcp.d.ts +4 -4
  5. package/dist/access-mcp.js +16 -16
  6. package/dist/access-schema.d.ts +10 -10
  7. package/dist/{access-service-C8A5hoXJ.d.ts → access-service-D_nbpexW.d.ts} +33 -2
  8. package/dist/access-service.d.ts +4 -4
  9. package/dist/access-service.js +15 -15
  10. package/dist/action-confidence.d.ts +1 -1
  11. package/dist/active-memory-bridge.d.ts +1 -1
  12. package/dist/active-recall.d.ts +1 -1
  13. package/dist/active-recall.js +1 -1
  14. package/dist/behavior-learner.d.ts +1 -1
  15. package/dist/behavior-signals.d.ts +1 -1
  16. package/dist/bootstrap.d.ts +3 -3
  17. package/dist/briefing.d.ts +1 -1
  18. package/dist/briefing.js +3 -3
  19. package/dist/buffer-surprise-report.d.ts +1 -1
  20. package/dist/buffer.d.ts +1 -1
  21. package/dist/calibration.d.ts +1 -1
  22. package/dist/causal-behavior.d.ts +1 -1
  23. package/dist/causal-consolidation.d.ts +1 -1
  24. package/dist/causal-consolidation.js +4 -4
  25. package/dist/{chunk-JMQSYGXS.js → chunk-2BD7DG37.js} +2 -2
  26. package/dist/{chunk-FVRBLJP6.js → chunk-2MXEVL75.js} +2 -2
  27. package/dist/{chunk-LJCEWTG3.js → chunk-4UL7VPTD.js} +277 -58
  28. package/dist/chunk-4UL7VPTD.js.map +1 -0
  29. package/dist/{chunk-JYN7QNTA.js → chunk-54XF2FY7.js} +17 -17
  30. package/dist/{chunk-7WEB3FLJ.js → chunk-5PLUC5OB.js} +2 -2
  31. package/dist/{chunk-JX2RINDR.js → chunk-6G5JEN55.js} +2 -2
  32. package/dist/{chunk-ZCORQM74.js → chunk-AGJKWOKV.js} +2 -2
  33. package/dist/{chunk-NE2JBMLN.js → chunk-AZBV4RRY.js} +1 -1
  34. package/dist/chunk-AZBV4RRY.js.map +1 -0
  35. package/dist/{chunk-YLZLPVKK.js → chunk-CTAV55JM.js} +344 -1
  36. package/dist/chunk-CTAV55JM.js.map +1 -0
  37. package/dist/{chunk-2DSTAWNZ.js → chunk-DIBWFCLA.js} +3 -3
  38. package/dist/{chunk-NAZWHTYV.js → chunk-DR67OK4E.js} +5 -5
  39. package/dist/{chunk-XBIACVCO.js → chunk-EC2AYKRX.js} +2 -2
  40. package/dist/{chunk-JVRPJ7D4.js → chunk-EKQMQQ3U.js} +48 -12
  41. package/dist/chunk-EKQMQQ3U.js.map +1 -0
  42. package/dist/{chunk-RGPUQ66K.js → chunk-GCYFUTUC.js} +2 -2
  43. package/dist/{chunk-JBHXMCYN.js → chunk-GRYAECRV.js} +2 -2
  44. package/dist/{chunk-BJA6DQOC.js → chunk-GSHW5VVD.js} +5 -5
  45. package/dist/chunk-GYSYLGNE.js +650 -0
  46. package/dist/chunk-GYSYLGNE.js.map +1 -0
  47. package/dist/{chunk-NCGWXCSW.js → chunk-IOZ5WBWD.js} +2 -2
  48. package/dist/{chunk-QKK64Z6M.js → chunk-JSVFEHLL.js} +7 -5
  49. package/dist/chunk-JSVFEHLL.js.map +1 -0
  50. package/dist/{chunk-7LWRCOP7.js → chunk-LZTFCAKE.js} +2 -2
  51. package/dist/{chunk-2DGQLOOM.js → chunk-M3VYPE2H.js} +1 -1
  52. package/dist/{chunk-2DGQLOOM.js.map → chunk-M3VYPE2H.js.map} +1 -1
  53. package/dist/{chunk-6CVI6BP6.js → chunk-NXCK7DO7.js} +2 -2
  54. package/dist/{chunk-Z5MQI7K2.js → chunk-PEPHBH2W.js} +2 -2
  55. package/dist/{chunk-PYWNNF2I.js → chunk-QRSKPI62.js} +99 -66
  56. package/dist/chunk-QRSKPI62.js.map +1 -0
  57. package/dist/{chunk-XWQ6ERUG.js → chunk-QZRKNA5F.js} +2 -2
  58. package/dist/{chunk-PS3SYNHP.js → chunk-R5DB26G6.js} +2 -2
  59. package/dist/{chunk-OL2364SB.js → chunk-RDW5G6DO.js} +1502 -335
  60. package/dist/chunk-RDW5G6DO.js.map +1 -0
  61. package/dist/{chunk-YM3LR4LS.js → chunk-SSSXWIBP.js} +5 -5
  62. package/dist/{chunk-T2C6QJG2.js → chunk-SWDHVH2P.js} +2 -2
  63. package/dist/{chunk-DBM2BD22.js → chunk-SXYCVRLK.js} +3 -3
  64. package/dist/{chunk-K6X553JB.js → chunk-TFFZUFEP.js} +7 -5
  65. package/dist/chunk-TFFZUFEP.js.map +1 -0
  66. package/dist/{chunk-ENV6RDTD.js → chunk-TIJYQXDI.js} +2 -2
  67. package/dist/{chunk-BP2EV6W5.js → chunk-VAEAGTEQ.js} +4 -4
  68. package/dist/{chunk-3RACUBII.js → chunk-WIKMCJUR.js} +2 -2
  69. package/dist/{chunk-QW6JZO5P.js → chunk-WWMHAMAY.js} +2 -2
  70. package/dist/{chunk-GPW2E4LN.js → chunk-YEZHZCUO.js} +4 -4
  71. package/dist/{chunk-5FOCXX5E.js → chunk-YVVQUAOO.js} +3 -3
  72. package/dist/{chunk-5FOCXX5E.js.map → chunk-YVVQUAOO.js.map} +1 -1
  73. package/dist/{chunk-3XGWCZ63.js → chunk-YXLT4EMM.js} +2 -2
  74. package/dist/{chunk-Y2RIIF6H.js → chunk-Z6UDTNY6.js} +2 -2
  75. package/dist/{cli-uQgvDFNE.d.ts → cli-aYxSuPvP.d.ts} +3 -3
  76. package/dist/cli.d.ts +5 -5
  77. package/dist/cli.js +29 -29
  78. package/dist/compounding/engine.d.ts +1 -1
  79. package/dist/compounding/engine.js +3 -3
  80. package/dist/compounding/preference-consolidator.d.ts +1 -1
  81. package/dist/compression-optimizer.d.ts +1 -1
  82. package/dist/config.d.ts +1 -1
  83. package/dist/config.js +1 -1
  84. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  85. package/dist/connectors/codex-materialize-runner.js +3 -3
  86. package/dist/connectors/codex-materialize.d.ts +1 -1
  87. package/dist/connectors/index.d.ts +1 -1
  88. package/dist/connectors/index.js +3 -3
  89. package/dist/consolidation-provenance-check.d.ts +1 -1
  90. package/dist/consolidation-undo.d.ts +1 -1
  91. package/dist/contradiction/index.d.ts +1 -1
  92. package/dist/conversation-index/backend.d.ts +1 -1
  93. package/dist/conversation-index/chunker.d.ts +1 -1
  94. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  95. package/dist/conversation-index/indexer.d.ts +1 -1
  96. package/dist/conversation-index/search.d.ts +1 -1
  97. package/dist/day-summary.d.ts +1 -1
  98. package/dist/delinearize.d.ts +1 -1
  99. package/dist/direct-answer-wiring.d.ts +1 -1
  100. package/dist/direct-answer.d.ts +1 -1
  101. package/dist/embedding-fallback.d.ts +1 -1
  102. package/dist/enrichment/index.d.ts +1 -1
  103. package/dist/entity-retrieval.d.ts +1 -1
  104. package/dist/entity-retrieval.js +3 -3
  105. package/dist/entity-schema.d.ts +1 -1
  106. package/dist/explicit-capture.d.ts +3 -3
  107. package/dist/explicit-cue-recall.js +2 -2
  108. package/dist/extraction-judge-telemetry.d.ts +1 -1
  109. package/dist/extraction-judge-training.d.ts +1 -1
  110. package/dist/extraction-judge.d.ts +1 -1
  111. package/dist/extraction.d.ts +1 -1
  112. package/dist/fallback-llm.d.ts +1 -1
  113. package/dist/focused-list-recall.js +2 -2
  114. package/dist/identity-continuity.d.ts +1 -1
  115. package/dist/importance.d.ts +1 -1
  116. package/dist/index.d.ts +121 -121
  117. package/dist/index.js +39 -39
  118. package/dist/intent.d.ts +1 -1
  119. package/dist/lcm/engine.d.ts +1 -1
  120. package/dist/lcm/index.d.ts +1 -1
  121. package/dist/lcm/tools.d.ts +1 -1
  122. package/dist/lcm-fallback-read.js +1 -1
  123. package/dist/lifecycle.d.ts +1 -1
  124. package/dist/live-connectors-runner.d.ts +1 -1
  125. package/dist/local-llm.d.ts +1 -1
  126. package/dist/maintenance/memory-governance.d.ts +1 -1
  127. package/dist/maintenance/memory-governance.js +3 -3
  128. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  129. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  130. package/dist/mcp-memory-inspector-app.d.ts +4 -4
  131. package/dist/memory-action-policy.d.ts +1 -1
  132. package/dist/memory-cache.d.ts +1 -1
  133. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  134. package/dist/memory-projection-store.d.ts +1 -1
  135. package/dist/memory-provenance.d.ts +1 -1
  136. package/dist/memory-worth-outcomes.d.ts +1 -1
  137. package/dist/models-json.d.ts +1 -1
  138. package/dist/namespaces/migrate.d.ts +1 -1
  139. package/dist/namespaces/migrate.js +11 -11
  140. package/dist/namespaces/principal.d.ts +1 -1
  141. package/dist/namespaces/search.d.ts +15 -4
  142. package/dist/namespaces/search.js +7 -7
  143. package/dist/namespaces/storage.d.ts +1 -1
  144. package/dist/namespaces/storage.js +3 -3
  145. package/dist/native-knowledge.d.ts +1 -1
  146. package/dist/operator-toolkit.d.ts +1 -1
  147. package/dist/operator-toolkit.js +14 -14
  148. package/dist/{orchestrator-B4Y4sWQH.d.ts → orchestrator-D1wcmPNj.d.ts} +17 -14
  149. package/dist/orchestrator.d.ts +3 -3
  150. package/dist/orchestrator.js +25 -25
  151. package/dist/patterns-cli.d.ts +1 -1
  152. package/dist/policy-runtime.d.ts +1 -1
  153. package/dist/qmd-recall-cache.d.ts +1 -1
  154. package/dist/qmd.d.ts +5 -1
  155. package/dist/qmd.js +2 -2
  156. package/dist/recall-disclosure-escalation.d.ts +1 -1
  157. package/dist/recall-explain-renderer.d.ts +1 -1
  158. package/dist/recall-explain-renderer.js +3 -3
  159. package/dist/recall-planner-llm.d.ts +1 -1
  160. package/dist/recall-state.d.ts +1 -1
  161. package/dist/recall-tag-filter.d.ts +1 -1
  162. package/dist/recall-xray-cli.d.ts +1 -1
  163. package/dist/recall-xray-cli.js +4 -4
  164. package/dist/recall-xray-renderer.d.ts +1 -1
  165. package/dist/recall-xray-renderer.js +3 -3
  166. package/dist/recall-xray.d.ts +1 -1
  167. package/dist/recall-xray.js +2 -2
  168. package/dist/resolve-auth-token.d.ts +1 -1
  169. package/dist/response-guidance-recall.js +2 -2
  170. package/dist/resume-bundles.js +2 -2
  171. package/dist/retrieval-agents.d.ts +1 -1
  172. package/dist/retrieval-tiers.d.ts +1 -1
  173. package/dist/routing/engine.d.ts +1 -1
  174. package/dist/routing/store.d.ts +1 -1
  175. package/dist/schemas.d.ts +22 -22
  176. package/dist/search/embed-helper.d.ts +1 -1
  177. package/dist/search/factory.d.ts +1 -1
  178. package/dist/search/factory.js +6 -6
  179. package/dist/search/index.d.ts +1 -1
  180. package/dist/search/index.js +6 -6
  181. package/dist/search/lancedb-backend.d.ts +1 -1
  182. package/dist/search/lancedb-backend.js +2 -2
  183. package/dist/search/meilisearch-backend.d.ts +1 -1
  184. package/dist/search/meilisearch-backend.js +2 -2
  185. package/dist/search/noop-backend.d.ts +1 -1
  186. package/dist/search/orama-backend.d.ts +1 -1
  187. package/dist/search/orama-backend.js +2 -2
  188. package/dist/search/port.d.ts +17 -1
  189. package/dist/search/port.js +1 -1
  190. package/dist/search/remote-backend.d.ts +1 -1
  191. package/dist/{semantic-consolidation-BKd0Pype.d.ts → semantic-consolidation-MWOdNtSE.d.ts} +1 -1
  192. package/dist/semantic-consolidation.d.ts +2 -2
  193. package/dist/semantic-consolidation.js +4 -4
  194. package/dist/semantic-rule-promotion.js +3 -3
  195. package/dist/semantic-rule-verifier.d.ts +3 -2
  196. package/dist/semantic-rule-verifier.js +5 -3
  197. package/dist/session-observer-bands.d.ts +1 -1
  198. package/dist/session-observer-state.d.ts +1 -1
  199. package/dist/shared-context/manager.d.ts +1 -1
  200. package/dist/signal.d.ts +1 -1
  201. package/dist/storage.d.ts +1 -1
  202. package/dist/storage.js +2 -2
  203. package/dist/summarizer.d.ts +1 -1
  204. package/dist/summary-snapshot.d.ts +1 -1
  205. package/dist/targeted-fact-recall.js +2 -2
  206. package/dist/temporal-supersession.d.ts +1 -1
  207. package/dist/temporal-validity.d.ts +1 -1
  208. package/dist/threading.d.ts +1 -1
  209. package/dist/tier-migration.d.ts +1 -1
  210. package/dist/tier-routing.d.ts +1 -1
  211. package/dist/topics.d.ts +1 -1
  212. package/dist/transcript.d.ts +1 -1
  213. package/dist/transfer/types.d.ts +12 -12
  214. package/dist/{types-BgChEr0M.d.ts → types-CgcCpUrf.d.ts} +51 -1
  215. package/dist/types.d.ts +1 -1
  216. package/dist/types.js +1 -1
  217. package/dist/utility-runtime.d.ts +1 -1
  218. package/dist/verified-recall.d.ts +2 -1
  219. package/dist/verified-recall.js +5 -3
  220. package/package.json +1 -1
  221. package/src/access-service-observe-lcm-parity.test.ts +86 -1
  222. package/src/access-service-observe-scope.test.ts +283 -1
  223. package/src/access-service-raw-excerpt-read-gate.test.ts +53 -0
  224. package/src/access-service.ts +391 -93
  225. package/src/coding/coding-namespace.ts +0 -3
  226. package/src/config.test.ts +69 -0
  227. package/src/config.ts +417 -0
  228. package/src/lcm-fallback-read.ts +2 -6
  229. package/src/maintenance/namespace-planner.test.ts +1120 -0
  230. package/src/maintenance/namespace-planner.ts +893 -0
  231. package/src/namespaces/scope-profiles.test.ts +1074 -0
  232. package/src/namespaces/scope-profiles.ts +456 -0
  233. package/src/namespaces/search.test.ts +130 -2
  234. package/src/namespaces/search.ts +71 -10
  235. package/src/orchestrator-flush.test.ts +606 -44
  236. package/src/orchestrator-source-attribution.test.ts +73 -0
  237. package/src/orchestrator.ts +932 -229
  238. package/src/qmd-client.test.ts +59 -0
  239. package/src/qmd.ts +124 -84
  240. package/src/search/port.ts +16 -0
  241. package/src/semantic-rule-verifier.ts +13 -6
  242. package/src/types.ts +64 -0
  243. package/src/verified-recall.ts +10 -6
  244. package/dist/chunk-JVRPJ7D4.js.map +0 -1
  245. package/dist/chunk-K6X553JB.js.map +0 -1
  246. package/dist/chunk-LJCEWTG3.js.map +0 -1
  247. package/dist/chunk-MMJANTJX.js +0 -339
  248. package/dist/chunk-MMJANTJX.js.map +0 -1
  249. package/dist/chunk-NE2JBMLN.js.map +0 -1
  250. package/dist/chunk-OL2364SB.js.map +0 -1
  251. package/dist/chunk-PYWNNF2I.js.map +0 -1
  252. package/dist/chunk-QKK64Z6M.js.map +0 -1
  253. package/dist/chunk-YLZLPVKK.js.map +0 -1
  254. /package/dist/{chunk-JMQSYGXS.js.map → chunk-2BD7DG37.js.map} +0 -0
  255. /package/dist/{chunk-FVRBLJP6.js.map → chunk-2MXEVL75.js.map} +0 -0
  256. /package/dist/{chunk-JYN7QNTA.js.map → chunk-54XF2FY7.js.map} +0 -0
  257. /package/dist/{chunk-7WEB3FLJ.js.map → chunk-5PLUC5OB.js.map} +0 -0
  258. /package/dist/{chunk-JX2RINDR.js.map → chunk-6G5JEN55.js.map} +0 -0
  259. /package/dist/{chunk-ZCORQM74.js.map → chunk-AGJKWOKV.js.map} +0 -0
  260. /package/dist/{chunk-2DSTAWNZ.js.map → chunk-DIBWFCLA.js.map} +0 -0
  261. /package/dist/{chunk-NAZWHTYV.js.map → chunk-DR67OK4E.js.map} +0 -0
  262. /package/dist/{chunk-XBIACVCO.js.map → chunk-EC2AYKRX.js.map} +0 -0
  263. /package/dist/{chunk-RGPUQ66K.js.map → chunk-GCYFUTUC.js.map} +0 -0
  264. /package/dist/{chunk-JBHXMCYN.js.map → chunk-GRYAECRV.js.map} +0 -0
  265. /package/dist/{chunk-BJA6DQOC.js.map → chunk-GSHW5VVD.js.map} +0 -0
  266. /package/dist/{chunk-NCGWXCSW.js.map → chunk-IOZ5WBWD.js.map} +0 -0
  267. /package/dist/{chunk-7LWRCOP7.js.map → chunk-LZTFCAKE.js.map} +0 -0
  268. /package/dist/{chunk-6CVI6BP6.js.map → chunk-NXCK7DO7.js.map} +0 -0
  269. /package/dist/{chunk-Z5MQI7K2.js.map → chunk-PEPHBH2W.js.map} +0 -0
  270. /package/dist/{chunk-XWQ6ERUG.js.map → chunk-QZRKNA5F.js.map} +0 -0
  271. /package/dist/{chunk-PS3SYNHP.js.map → chunk-R5DB26G6.js.map} +0 -0
  272. /package/dist/{chunk-YM3LR4LS.js.map → chunk-SSSXWIBP.js.map} +0 -0
  273. /package/dist/{chunk-T2C6QJG2.js.map → chunk-SWDHVH2P.js.map} +0 -0
  274. /package/dist/{chunk-DBM2BD22.js.map → chunk-SXYCVRLK.js.map} +0 -0
  275. /package/dist/{chunk-ENV6RDTD.js.map → chunk-TIJYQXDI.js.map} +0 -0
  276. /package/dist/{chunk-BP2EV6W5.js.map → chunk-VAEAGTEQ.js.map} +0 -0
  277. /package/dist/{chunk-3RACUBII.js.map → chunk-WIKMCJUR.js.map} +0 -0
  278. /package/dist/{chunk-QW6JZO5P.js.map → chunk-WWMHAMAY.js.map} +0 -0
  279. /package/dist/{chunk-GPW2E4LN.js.map → chunk-YEZHZCUO.js.map} +0 -0
  280. /package/dist/{chunk-3XGWCZ63.js.map → chunk-YXLT4EMM.js.map} +0 -0
  281. /package/dist/{chunk-Y2RIIF6H.js.map → chunk-Z6UDTNY6.js.map} +0 -0
@@ -29,7 +29,7 @@ import {
29
29
  import {
30
30
  CompoundingEngine,
31
31
  defaultTierMigrationCycleBudget
32
- } from "./chunk-ZCORQM74.js";
32
+ } from "./chunk-AGJKWOKV.js";
33
33
  import {
34
34
  SharedContextManager
35
35
  } from "./chunk-DRD2Q7HQ.js";
@@ -56,7 +56,7 @@ import {
56
56
  import {
57
57
  buildTargetedFactRecallSection,
58
58
  shouldRecallTargetedFactEvidence
59
- } from "./chunk-PS3SYNHP.js";
59
+ } from "./chunk-R5DB26G6.js";
60
60
  import {
61
61
  applyTemporalSupersession,
62
62
  normalizeSupersessionKey,
@@ -71,7 +71,7 @@ import {
71
71
  import {
72
72
  buildResponseGuidanceRecallSection,
73
73
  shouldRecallResponseGuidance
74
- } from "./chunk-XBIACVCO.js";
74
+ } from "./chunk-EC2AYKRX.js";
75
75
  import {
76
76
  mergeWithAgentResults,
77
77
  runDirectAgent,
@@ -170,19 +170,19 @@ import {
170
170
  import {
171
171
  buildFocusedListRecallSection,
172
172
  shouldRecallFocusedListEvidence
173
- } from "./chunk-7LWRCOP7.js";
173
+ } from "./chunk-LZTFCAKE.js";
174
174
  import {
175
175
  buildEntityRecallSection,
176
176
  entityRecentTranscriptLookbackHours,
177
177
  readRecentEntityTranscriptEntries
178
- } from "./chunk-NCGWXCSW.js";
178
+ } from "./chunk-IOZ5WBWD.js";
179
179
  import {
180
180
  buildEventOrderRecallSection,
181
181
  shouldRecallEventOrderEvidence
182
182
  } from "./chunk-UU6MVCJ6.js";
183
183
  import {
184
184
  buildExplicitCueRecallSection
185
- } from "./chunk-3XGWCZ63.js";
185
+ } from "./chunk-YXLT4EMM.js";
186
186
  import {
187
187
  formatDaySummaryMemories
188
188
  } from "./chunk-WLEB7WCG.js";
@@ -210,7 +210,7 @@ import {
210
210
  materializeAfterSemanticConsolidation,
211
211
  parseConsolidationResponse,
212
212
  parseOperatorAwareConsolidationResponse
213
- } from "./chunk-T2C6QJG2.js";
213
+ } from "./chunk-SWDHVH2P.js";
214
214
  import {
215
215
  normalizeReplaySessionKey
216
216
  } from "./chunk-2PRQG7PV.js";
@@ -218,14 +218,16 @@ import {
218
218
  RoutingRulesStore
219
219
  } from "./chunk-X6IRLNOO.js";
220
220
  import {
221
+ compareVerifiedEpisodeResults,
221
222
  searchVerifiedEpisodes
222
- } from "./chunk-QKK64Z6M.js";
223
+ } from "./chunk-JSVFEHLL.js";
223
224
  import {
224
225
  ThreadingManager
225
226
  } from "./chunk-W4RVMTHR.js";
226
227
  import {
228
+ compareVerifiedSemanticRuleResults,
227
229
  searchVerifiedSemanticRules
228
- } from "./chunk-K6X553JB.js";
230
+ } from "./chunk-TFFZUFEP.js";
229
231
  import {
230
232
  searchWorkProductLedgerEntries
231
233
  } from "./chunk-ZRWB5D4H.js";
@@ -239,7 +241,7 @@ import {
239
241
  NamespaceStorageRouter,
240
242
  resolveDefaultNamespaceRoot,
241
243
  resolveNamespaceStorageRoot
242
- } from "./chunk-3RACUBII.js";
244
+ } from "./chunk-WIKMCJUR.js";
243
245
  import {
244
246
  isAboveImportanceThreshold,
245
247
  scoreImportance
@@ -305,9 +307,11 @@ import {
305
307
  import {
306
308
  clusterByKey,
307
309
  combineNamespaces,
310
+ expandScopeProfileReadNamespaces,
308
311
  lcmReadSessionIdsForNamespaces,
309
- resolveCodingNamespaceOverlay
310
- } from "./chunk-MMJANTJX.js";
312
+ resolveCodingNamespaceOverlay,
313
+ resolveScopeProfilePlan
314
+ } from "./chunk-GYSYLGNE.js";
311
315
  import {
312
316
  listTrustZoneRecords,
313
317
  searchTrustZoneRecords
@@ -317,14 +321,14 @@ import {
317
321
  } from "./chunk-FF4KLI5W.js";
318
322
  import {
319
323
  buildXraySnapshot
320
- } from "./chunk-FVRBLJP6.js";
324
+ } from "./chunk-2MXEVL75.js";
321
325
  import {
322
326
  NamespaceSearchRouter
323
- } from "./chunk-JVRPJ7D4.js";
327
+ } from "./chunk-EKQMQQ3U.js";
324
328
  import {
325
329
  createConversationIndexRuntime,
326
330
  createSearchBackend
327
- } from "./chunk-YM3LR4LS.js";
331
+ } from "./chunk-SSSXWIBP.js";
328
332
  import {
329
333
  NoopSearchBackend
330
334
  } from "./chunk-CYEPCZN5.js";
@@ -338,7 +342,7 @@ import {
338
342
  } from "./chunk-OIF36KGD.js";
339
343
  import {
340
344
  parseQmdExplain
341
- } from "./chunk-PYWNNF2I.js";
345
+ } from "./chunk-QRSKPI62.js";
342
346
  import {
343
347
  objectiveStateStoreOverrideForNamespace,
344
348
  searchObjectiveStateSnapshots
@@ -357,7 +361,7 @@ import {
357
361
  } from "./chunk-Y56J7CXW.js";
358
362
  import {
359
363
  buildChainFollowupGenerator
360
- } from "./chunk-Y2RIIF6H.js";
364
+ } from "./chunk-Z6UDTNY6.js";
361
365
  import {
362
366
  ALL_CATEGORY_DIRS,
363
367
  ContentHashIndex,
@@ -368,7 +372,7 @@ import {
368
372
  normalizeEntityName,
369
373
  parseEntityFile,
370
374
  stripAttributesSuffix
371
- } from "./chunk-6CVI6BP6.js";
375
+ } from "./chunk-NXCK7DO7.js";
372
376
  import {
373
377
  isValidTranscriptDate,
374
378
  loadSpeakerRegistry,
@@ -383,11 +387,14 @@ import {
383
387
  } from "./chunk-J6A3CX5N.js";
384
388
  import {
385
389
  confidenceTier
386
- } from "./chunk-NE2JBMLN.js";
390
+ } from "./chunk-AZBV4RRY.js";
387
391
  import {
388
392
  inferMemoryStatus,
389
393
  isActiveMemoryStatus
390
394
  } from "./chunk-RULE4VG5.js";
395
+ import {
396
+ displayErrorDetail
397
+ } from "./chunk-6KYMPV2O.js";
391
398
  import {
392
399
  lintWorkspaceFiles,
393
400
  rotateMarkdownFileToArchive
@@ -438,17 +445,17 @@ import {
438
445
  } from "./chunk-AC5LO7IU.js";
439
446
 
440
447
  // src/orchestrator.ts
441
- import path3 from "path";
448
+ import path4 from "path";
442
449
  import os from "os";
443
- import { createHash, randomBytes } from "crypto";
450
+ import { createHash as createHash2, randomBytes } from "crypto";
444
451
  import { existsSync, readFileSync } from "fs";
445
452
  import {
446
- mkdir as mkdir3,
447
- readdir as readdir2,
448
- readFile as readFile3,
449
- stat as stat2,
453
+ mkdir as mkdir4,
454
+ readdir as readdir3,
455
+ readFile as readFile4,
456
+ stat as stat3,
450
457
  unlink as unlink2,
451
- writeFile as writeFile3
458
+ writeFile as writeFile4
452
459
  } from "fs/promises";
453
460
 
454
461
  // src/procedural/procedure-recall.ts
@@ -2051,9 +2058,9 @@ var NamespaceCatalog = class {
2051
2058
  }
2052
2059
  if (await this.hasSymlinkedAncestor(candidate)) return false;
2053
2060
  try {
2054
- const stat3 = await lstat(candidate);
2055
- if (stat3.isSymbolicLink()) return false;
2056
- if (!stat3.isDirectory()) return false;
2061
+ const stat4 = await lstat(candidate);
2062
+ if (stat4.isSymbolicLink()) return false;
2063
+ if (!stat4.isDirectory()) return false;
2057
2064
  } catch {
2058
2065
  return this.isNearestExistingAncestorContained(candidate, memoryReal);
2059
2066
  }
@@ -2114,8 +2121,8 @@ var NamespaceCatalog = class {
2114
2121
  }
2115
2122
  if (!(isPathInside(memoryReal, real) || real === memoryReal)) return false;
2116
2123
  try {
2117
- const stat3 = await lstat(real);
2118
- return stat3.isDirectory();
2124
+ const stat4 = await lstat(real);
2125
+ return stat4.isDirectory();
2119
2126
  } catch {
2120
2127
  return false;
2121
2128
  }
@@ -2279,14 +2286,14 @@ var NamespaceCatalog = class {
2279
2286
  if (normalizeNamespaceIdentity(namespace) !== this.defaultNamespaceIdentity && path2.resolve(root) === path2.resolve(this.memoryDir)) {
2280
2287
  return false;
2281
2288
  }
2282
- let stat3;
2289
+ let stat4;
2283
2290
  try {
2284
- stat3 = await lstat(root);
2291
+ stat4 = await lstat(root);
2285
2292
  } catch {
2286
2293
  return false;
2287
2294
  }
2288
- if (stat3.isSymbolicLink()) return false;
2289
- if (!stat3.isDirectory()) return false;
2295
+ if (stat4.isSymbolicLink()) return false;
2296
+ if (!stat4.isDirectory()) return false;
2290
2297
  try {
2291
2298
  const real = await realpath(root);
2292
2299
  if (memoryReal && !isPathInside(memoryReal, real)) return false;
@@ -2463,18 +2470,18 @@ var NamespaceCatalog = class {
2463
2470
  for (const entry of entries) {
2464
2471
  const token = entry.name;
2465
2472
  const fullPath = path2.join(namespacesDir, token);
2466
- let stat3;
2473
+ let stat4;
2467
2474
  try {
2468
- stat3 = await lstat(fullPath);
2475
+ stat4 = await lstat(fullPath);
2469
2476
  } catch (err) {
2470
2477
  skipped.push({ token, reason: "error", detail: err instanceof Error ? err.message : String(err) });
2471
2478
  continue;
2472
2479
  }
2473
- if (stat3.isSymbolicLink()) {
2480
+ if (stat4.isSymbolicLink()) {
2474
2481
  skipped.push({ token, reason: "symlink", detail: fullPath });
2475
2482
  continue;
2476
2483
  }
2477
- if (!stat3.isDirectory()) continue;
2484
+ if (!stat4.isDirectory()) continue;
2478
2485
  try {
2479
2486
  const real = await realpath(fullPath);
2480
2487
  if (memoryReal && !isPathInside(memoryReal, real)) {
@@ -2865,6 +2872,611 @@ function isPathInside(root, child) {
2865
2872
  return relative === "" || !relative.startsWith("..") && !path2.isAbsolute(relative);
2866
2873
  }
2867
2874
 
2875
+ // src/maintenance/namespace-planner.ts
2876
+ import { createHash, randomUUID as randomUUID2 } from "crypto";
2877
+ import { lstat as lstat2, mkdir as mkdir3, open as open2, readFile as readFile3, readdir as readdir2, rename as rename2, rm, rmdir, utimes as utimes2, writeFile as writeFile3 } from "fs/promises";
2878
+ import path3 from "path";
2879
+ var DEFAULT_MAX_NAMESPACES_PER_CYCLE = 20;
2880
+ var DEFAULT_LOCK_STALE_MS = 10 * 6e4;
2881
+ var LOCK_BASE = "maintenance-locks";
2882
+ var STATUS_BASE = "namespace-maintenance-status";
2883
+ var namespaceMaintenanceFs = { open: open2, rm };
2884
+ function configuredNamespaces(config) {
2885
+ return Array.from(
2886
+ new Set(
2887
+ [config.defaultNamespace, config.sharedNamespace, ...config.namespacePolicies.map((policy) => policy.name)].map((value) => value.trim()).filter(Boolean)
2888
+ )
2889
+ );
2890
+ }
2891
+ function inferConfiguredKind(config, namespace) {
2892
+ if (namespace === config.defaultNamespace.trim()) return "default";
2893
+ if (namespace === config.sharedNamespace.trim()) return "shared";
2894
+ return "explicit";
2895
+ }
2896
+ function maxNamespacesPerCycle(config) {
2897
+ return Math.max(
2898
+ 1,
2899
+ Math.floor(
2900
+ typeof config.maintenanceMaxNamespacesPerCycle === "number" && Number.isFinite(config.maintenanceMaxNamespacesPerCycle) ? config.maintenanceMaxNamespacesPerCycle : DEFAULT_MAX_NAMESPACES_PER_CYCLE
2901
+ )
2902
+ );
2903
+ }
2904
+ function namespaceKindAllowed(config, kind) {
2905
+ switch (kind) {
2906
+ case "branch":
2907
+ return config.maintenanceIncludeBranchNamespaces === true;
2908
+ case "project":
2909
+ return config.maintenanceIncludeProjectNamespaces !== false;
2910
+ case "team-project":
2911
+ return config.maintenanceIncludeTeamProjectNamespaces !== false;
2912
+ default:
2913
+ return true;
2914
+ }
2915
+ }
2916
+ function disabledReasonForKind(kind) {
2917
+ if (kind === "branch") return "branch_disabled";
2918
+ if (kind === "project") return "project_disabled";
2919
+ if (kind === "team-project") return "team_project_disabled";
2920
+ return "fanout_disabled";
2921
+ }
2922
+ async function catalogRootIsLive(config, record) {
2923
+ if (typeof record.storageDir !== "string" || record.storageDir.length === 0) {
2924
+ return false;
2925
+ }
2926
+ try {
2927
+ const liveRoot = await resolveNamespaceStorageRoot(config, record.namespace);
2928
+ if (path3.resolve(liveRoot) !== path3.resolve(record.storageDir)) return false;
2929
+ return hasMemoryData(liveRoot);
2930
+ } catch {
2931
+ return false;
2932
+ }
2933
+ }
2934
+ function candidateSortKey(candidate) {
2935
+ const write = candidate.lastWriteAt ?? "";
2936
+ return `${write}\0${candidate.namespace}`;
2937
+ }
2938
+ function candidatePriority(candidate) {
2939
+ if (candidate.kind === "default") return 0;
2940
+ if (candidate.kind === "shared") return 1;
2941
+ if (candidate.source === "configured") return 2;
2942
+ if (candidate.kind === "team-project") return 3;
2943
+ if (candidate.kind === "project") return 4;
2944
+ if (candidate.kind === "self") return 5;
2945
+ if (candidate.kind === "legacy") return 6;
2946
+ if (candidate.kind === "branch") return 8;
2947
+ return 7;
2948
+ }
2949
+ function sortCandidates(a, b) {
2950
+ const priority = candidatePriority(a) - candidatePriority(b);
2951
+ if (priority !== 0) return priority;
2952
+ const am = Date.parse(a.lastMaintenanceAt ?? "");
2953
+ const bm = Date.parse(b.lastMaintenanceAt ?? "");
2954
+ const aMaintained = Number.isFinite(am);
2955
+ const bMaintained = Number.isFinite(bm);
2956
+ if (aMaintained && bMaintained && am !== bm) return am - bm;
2957
+ if (aMaintained !== bMaintained) return aMaintained ? 1 : -1;
2958
+ const aw = Date.parse(a.lastWriteAt ?? "");
2959
+ const bw = Date.parse(b.lastWriteAt ?? "");
2960
+ const aValid = Number.isFinite(aw);
2961
+ const bValid = Number.isFinite(bw);
2962
+ if (aValid && bValid && aw !== bw) return bw - aw;
2963
+ if (aValid !== bValid) return aValid ? -1 : 1;
2964
+ const byKey = candidateSortKey(a).localeCompare(candidateSortKey(b));
2965
+ if (byKey !== 0) return byKey;
2966
+ return a.namespace.localeCompare(b.namespace);
2967
+ }
2968
+ async function planNamespaceMaintenance(config, options) {
2969
+ const generatedAt = (options.now ?? /* @__PURE__ */ new Date()).toISOString();
2970
+ const configured = configuredNamespaces(config);
2971
+ const byNamespace = /* @__PURE__ */ new Map();
2972
+ const skipped = [];
2973
+ for (const namespace of configured) {
2974
+ const kind = inferConfiguredKind(config, namespace);
2975
+ byNamespace.set(namespace, {
2976
+ namespace,
2977
+ kind,
2978
+ source: "configured"
2979
+ });
2980
+ }
2981
+ if (config.namespacesEnabled && config.maintenanceNamespaceFanoutEnabled !== false) {
2982
+ const configuredSet = new Set(configured);
2983
+ try {
2984
+ const records = options.catalog?.enabled ? await options.catalog.listNamespaces() : [];
2985
+ for (const record of records) {
2986
+ const namespace = record.namespace.trim();
2987
+ if (!namespace) continue;
2988
+ const isConfigured = configuredSet.has(namespace);
2989
+ const kind = isConfigured ? inferConfiguredKind(config, namespace) : record.kind;
2990
+ if (!namespaceKindAllowed(config, kind)) {
2991
+ skipped.push({
2992
+ namespace,
2993
+ kind,
2994
+ reason: disabledReasonForKind(kind)
2995
+ });
2996
+ continue;
2997
+ }
2998
+ if (!isConfigured && !await catalogRootIsLive(config, record)) {
2999
+ skipped.push({
3000
+ namespace,
3001
+ kind,
3002
+ reason: "unsafe_or_stale_root"
3003
+ });
3004
+ continue;
3005
+ }
3006
+ byNamespace.set(namespace, {
3007
+ namespace,
3008
+ kind,
3009
+ storageDir: record.storageDir,
3010
+ source: isConfigured ? "configured" : "catalog",
3011
+ lastWriteAt: record.lastWriteAt,
3012
+ lastMaintenanceAt: record.lastMaintenanceAt?.[options.jobName]
3013
+ });
3014
+ }
3015
+ } catch (error) {
3016
+ skipped.push({
3017
+ namespace: "*",
3018
+ reason: "catalog_read_failed",
3019
+ detail: error instanceof Error ? error.message : String(error)
3020
+ });
3021
+ }
3022
+ } else if (config.namespacesEnabled) {
3023
+ skipped.push({
3024
+ namespace: "*",
3025
+ reason: "fanout_disabled"
3026
+ });
3027
+ }
3028
+ if (options.budgetMode !== "unbounded") {
3029
+ const latestStatusAtByNamespace = await readLatestStatusAtByNamespace(config, options.jobName);
3030
+ for (const candidate of byNamespace.values()) {
3031
+ if (!candidate.lastMaintenanceAt) {
3032
+ candidate.lastMaintenanceAt = latestStatusAtByNamespace.get(candidate.namespace);
3033
+ }
3034
+ }
3035
+ }
3036
+ const candidates = [...byNamespace.values()].filter((candidate) => namespaceKindAllowed(config, candidate.kind)).sort(sortCandidates);
3037
+ const max = maxNamespacesPerCycle(config);
3038
+ const applyCycleBudget = options.budgetMode !== "unbounded";
3039
+ const selected = applyCycleBudget ? candidates.slice(0, max) : candidates;
3040
+ if (applyCycleBudget) {
3041
+ for (const candidate of candidates.slice(max)) {
3042
+ skipped.push({
3043
+ namespace: candidate.namespace,
3044
+ kind: candidate.kind,
3045
+ reason: "budget_exhausted"
3046
+ });
3047
+ }
3048
+ }
3049
+ return {
3050
+ jobName: options.jobName,
3051
+ generatedAt,
3052
+ namespaces: selected,
3053
+ skipped,
3054
+ budget: {
3055
+ maxNamespacesPerCycle: max,
3056
+ selected: selected.length
3057
+ }
3058
+ };
3059
+ }
3060
+ function stablePathSegment(value) {
3061
+ const sanitized = value.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 128) || "unnamed";
3062
+ if (sanitized.length <= 128 && sanitized === value) return sanitized;
3063
+ return `${sanitized.slice(0, 80)}-${createHash("sha256").update(value).digest("hex").slice(0, 16)}`;
3064
+ }
3065
+ function namespacePathSegment(namespace) {
3066
+ const token = namespaceIdentityToken(namespace);
3067
+ if (token.length <= 160) return token;
3068
+ return `ns-${createHash("sha256").update(namespace).digest("hex")}`;
3069
+ }
3070
+ function lockPath(config, jobName, namespace) {
3071
+ return path3.join(
3072
+ config.memoryDir,
3073
+ "state",
3074
+ LOCK_BASE,
3075
+ stablePathSegment(jobName),
3076
+ `${namespacePathSegment(namespace)}.lock`
3077
+ );
3078
+ }
3079
+ function namespaceMaintenanceLockStaleMs(config) {
3080
+ if (typeof config.maintenanceNamespaceLockStaleMs === "number" && Number.isFinite(config.maintenanceNamespaceLockStaleMs) && config.maintenanceNamespaceLockStaleMs > 0) {
3081
+ return Math.floor(config.maintenanceNamespaceLockStaleMs);
3082
+ }
3083
+ return DEFAULT_LOCK_STALE_MS;
3084
+ }
3085
+ function namespaceMaintenanceLockHeartbeatMs(config) {
3086
+ const staleMs = namespaceMaintenanceLockStaleMs(config);
3087
+ return Math.max(1, Math.min(3e4, Math.floor(staleMs / 3) || 1));
3088
+ }
3089
+ function errorCode(error) {
3090
+ return typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
3091
+ }
3092
+ async function withNamespaceMaintenanceLockHeartbeat(config, locks, task) {
3093
+ const activeLocks = Array.isArray(locks) ? locks : [locks];
3094
+ const interval = setInterval(() => {
3095
+ for (const lock of activeLocks) {
3096
+ void lock.touch().catch(() => void 0);
3097
+ }
3098
+ }, namespaceMaintenanceLockHeartbeatMs(config));
3099
+ interval.unref?.();
3100
+ try {
3101
+ return await task();
3102
+ } finally {
3103
+ clearInterval(interval);
3104
+ }
3105
+ }
3106
+ async function removeStaleLockDirectory(filePath) {
3107
+ let entries;
3108
+ try {
3109
+ entries = await readdir2(filePath, { withFileTypes: true });
3110
+ } catch (error) {
3111
+ if (errorCode(error) === "ENOENT") return;
3112
+ throw error;
3113
+ }
3114
+ for (const entry of entries) {
3115
+ if (!entry.isFile()) continue;
3116
+ await namespaceMaintenanceFs.rm(path3.join(filePath, entry.name), { force: true });
3117
+ }
3118
+ try {
3119
+ await rmdir(filePath);
3120
+ } catch (error) {
3121
+ if (errorCode(error) === "ENOENT") return;
3122
+ throw error;
3123
+ }
3124
+ }
3125
+ async function tryAcquireNamespaceMaintenanceLock(config, jobName, namespace) {
3126
+ const filePath = lockPath(config, jobName, namespace);
3127
+ await mkdir3(path3.dirname(filePath), { recursive: true });
3128
+ try {
3129
+ const lockId = randomUUID2();
3130
+ await mkdir3(filePath);
3131
+ const ownerPath = path3.join(filePath, `${lockId}.json`);
3132
+ let handle;
3133
+ try {
3134
+ handle = await namespaceMaintenanceFs.open(ownerPath, "wx");
3135
+ await handle.writeFile(
3136
+ `${JSON.stringify({
3137
+ lockId,
3138
+ pid: process.pid,
3139
+ jobName,
3140
+ namespace,
3141
+ acquiredAt: (/* @__PURE__ */ new Date()).toISOString()
3142
+ })}
3143
+ `,
3144
+ "utf8"
3145
+ );
3146
+ await handle.close();
3147
+ } catch (setupError) {
3148
+ await handle?.close().catch(() => void 0);
3149
+ await namespaceMaintenanceFs.rm(ownerPath, { force: true }).catch(() => void 0);
3150
+ await rmdir(filePath).catch(() => void 0);
3151
+ throw setupError;
3152
+ }
3153
+ return {
3154
+ path: filePath,
3155
+ async touch() {
3156
+ try {
3157
+ const parsed = JSON.parse(await readFile3(ownerPath, "utf8"));
3158
+ if (parsed.lockId === lockId) {
3159
+ const now = /* @__PURE__ */ new Date();
3160
+ await utimes2(ownerPath, now, now);
3161
+ await utimes2(filePath, now, now);
3162
+ }
3163
+ } catch {
3164
+ }
3165
+ },
3166
+ async release() {
3167
+ try {
3168
+ const parsed = JSON.parse(await readFile3(ownerPath, "utf8"));
3169
+ if (parsed.lockId === lockId) {
3170
+ await namespaceMaintenanceFs.rm(ownerPath, { force: true });
3171
+ await rmdir(filePath).catch(() => void 0);
3172
+ }
3173
+ } catch {
3174
+ }
3175
+ }
3176
+ };
3177
+ } catch (error) {
3178
+ if (errorCode(error) === "EEXIST") {
3179
+ const staleMs = namespaceMaintenanceLockStaleMs(config);
3180
+ try {
3181
+ const s = await lstat2(filePath);
3182
+ if (s.isSymbolicLink()) {
3183
+ return null;
3184
+ }
3185
+ if ((s.isFile() || s.isDirectory()) && Date.now() - s.mtimeMs > staleMs) {
3186
+ try {
3187
+ if (s.isDirectory()) {
3188
+ await removeStaleLockDirectory(filePath);
3189
+ } else {
3190
+ await namespaceMaintenanceFs.rm(filePath, { force: true });
3191
+ }
3192
+ } catch (removeError) {
3193
+ if (errorCode(removeError) === "ENOENT") {
3194
+ return tryAcquireNamespaceMaintenanceLock(config, jobName, namespace);
3195
+ }
3196
+ if (errorCode(removeError) === "ENOTEMPTY") {
3197
+ return null;
3198
+ }
3199
+ throw removeError;
3200
+ }
3201
+ return tryAcquireNamespaceMaintenanceLock(config, jobName, namespace);
3202
+ }
3203
+ } catch (statError) {
3204
+ if (errorCode(statError) === "ENOENT") {
3205
+ return tryAcquireNamespaceMaintenanceLock(config, jobName, namespace);
3206
+ }
3207
+ throw statError;
3208
+ }
3209
+ return null;
3210
+ }
3211
+ throw error;
3212
+ }
3213
+ }
3214
+ function statusBasePath(config) {
3215
+ return path3.join(config.memoryDir, "state", STATUS_BASE);
3216
+ }
3217
+ function statusPath(config, jobName, namespace) {
3218
+ return path3.join(statusBasePath(config), stablePathSegment(jobName), `${namespacePathSegment(namespace)}.json`);
3219
+ }
3220
+ function lastRanStatusPath(config, jobName, namespace) {
3221
+ return path3.join(statusBasePath(config), stablePathSegment(jobName), `${namespacePathSegment(namespace)}.last-ran.json`);
3222
+ }
3223
+ function parseStatus(value) {
3224
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
3225
+ const v = value;
3226
+ if (typeof v.namespace === "string" && typeof v.jobName === "string" && (v.state === "ran" || v.state === "skipped" || v.state === "failed") && typeof v.startedAt === "string" && typeof v.completedAt === "string") {
3227
+ return v;
3228
+ }
3229
+ return null;
3230
+ }
3231
+ async function readLatestStatusAtByNamespace(config, jobName) {
3232
+ const latest = /* @__PURE__ */ new Map();
3233
+ const latestMs = /* @__PURE__ */ new Map();
3234
+ for (const status of [...await readStatusFiles(config), ...await readLastRanStatusFiles(config)]) {
3235
+ if (status.state !== "ran") continue;
3236
+ if (status.jobName !== jobName) continue;
3237
+ const completedAtMs = Date.parse(status.completedAt);
3238
+ if (!Number.isFinite(completedAtMs)) continue;
3239
+ const previousMs = latestMs.get(status.namespace);
3240
+ if (previousMs !== void 0 && previousMs >= completedAtMs) continue;
3241
+ latestMs.set(status.namespace, completedAtMs);
3242
+ latest.set(status.namespace, status.completedAt);
3243
+ }
3244
+ return latest;
3245
+ }
3246
+ async function readStatusFile(filePath) {
3247
+ try {
3248
+ const parsed = JSON.parse(await readFile3(filePath, "utf8"));
3249
+ return parseStatus(parsed);
3250
+ } catch {
3251
+ return null;
3252
+ }
3253
+ }
3254
+ async function readStatusFiles(config) {
3255
+ if (typeof config.memoryDir !== "string" || config.memoryDir.length === 0) {
3256
+ return [];
3257
+ }
3258
+ const root = statusBasePath(config);
3259
+ const statuses = [];
3260
+ let jobDirs;
3261
+ try {
3262
+ jobDirs = await readdir2(root, { withFileTypes: true });
3263
+ } catch {
3264
+ return statuses;
3265
+ }
3266
+ for (const jobDir of jobDirs) {
3267
+ if (!jobDir.isDirectory()) continue;
3268
+ let files;
3269
+ try {
3270
+ files = await readdir2(path3.join(root, jobDir.name), { withFileTypes: true });
3271
+ } catch {
3272
+ continue;
3273
+ }
3274
+ for (const file of files) {
3275
+ if (!file.isFile() || !file.name.endsWith(".json")) continue;
3276
+ if (file.name.endsWith(".last-ran.json")) continue;
3277
+ const status = await readStatusFile(path3.join(root, jobDir.name, file.name));
3278
+ if (status) statuses.push(status);
3279
+ }
3280
+ }
3281
+ return statuses;
3282
+ }
3283
+ async function readLastRanStatusFiles(config) {
3284
+ if (typeof config.memoryDir !== "string" || config.memoryDir.length === 0) {
3285
+ return [];
3286
+ }
3287
+ const root = statusBasePath(config);
3288
+ const statuses = [];
3289
+ let jobDirs;
3290
+ try {
3291
+ jobDirs = await readdir2(root, { withFileTypes: true });
3292
+ } catch {
3293
+ return statuses;
3294
+ }
3295
+ for (const jobDir of jobDirs) {
3296
+ if (!jobDir.isDirectory()) continue;
3297
+ let files;
3298
+ try {
3299
+ files = await readdir2(path3.join(root, jobDir.name), { withFileTypes: true });
3300
+ } catch {
3301
+ continue;
3302
+ }
3303
+ for (const file of files) {
3304
+ if (!file.isFile() || !file.name.endsWith(".last-ran.json")) continue;
3305
+ const status = await readStatusFile(path3.join(root, jobDir.name, file.name));
3306
+ if (status) statuses.push(status);
3307
+ }
3308
+ }
3309
+ return statuses;
3310
+ }
3311
+ async function writeStatusPayload(target, status) {
3312
+ const dir = path3.dirname(target);
3313
+ await mkdir3(dir, { recursive: true });
3314
+ const temp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
3315
+ const payload = {
3316
+ version: 1,
3317
+ ...status
3318
+ };
3319
+ await writeFile3(temp, `${JSON.stringify(payload, null, 2)}
3320
+ `, "utf8");
3321
+ await rename2(temp, target);
3322
+ }
3323
+ async function writeStatusFile(config, status) {
3324
+ await writeStatusPayload(statusPath(config, status.jobName, status.namespace), status);
3325
+ if (status.state === "ran") {
3326
+ await writeStatusPayload(lastRanStatusPath(config, status.jobName, status.namespace), status);
3327
+ }
3328
+ }
3329
+ async function recordNamespaceMaintenanceStatusSafely(config, status) {
3330
+ try {
3331
+ await writeStatusFile(config, status);
3332
+ } catch {
3333
+ }
3334
+ }
3335
+ function maintenanceErrorDetail(error) {
3336
+ return displayErrorDetail(error) || "Error";
3337
+ }
3338
+ async function runNamespaceMaintenanceBatchPlan(config, plan, runner, catalog, options = {}) {
3339
+ const statuses = [];
3340
+ for (const skipped of plan.skipped) {
3341
+ if (skipped.namespace === "*") continue;
3342
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3343
+ const status = {
3344
+ namespace: skipped.namespace,
3345
+ jobName: plan.jobName,
3346
+ state: "skipped",
3347
+ reason: skipped.reason,
3348
+ startedAt: now,
3349
+ completedAt: now
3350
+ };
3351
+ statuses.push(status);
3352
+ await recordNamespaceMaintenanceStatusSafely(config, status);
3353
+ }
3354
+ const acquired = [];
3355
+ try {
3356
+ for (const candidate of plan.namespaces) {
3357
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
3358
+ const lock = await tryAcquireNamespaceMaintenanceLock(config, plan.jobName, candidate.namespace);
3359
+ if (!lock) {
3360
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
3361
+ const status = {
3362
+ namespace: candidate.namespace,
3363
+ jobName: plan.jobName,
3364
+ state: "skipped",
3365
+ reason: "lock_held",
3366
+ startedAt,
3367
+ completedAt
3368
+ };
3369
+ statuses.push(status);
3370
+ await recordNamespaceMaintenanceStatusSafely(config, status);
3371
+ continue;
3372
+ }
3373
+ acquired.push({ candidate, lock, startedAt });
3374
+ }
3375
+ } catch (error) {
3376
+ await Promise.all(acquired.map(({ lock }) => lock.release().catch(() => void 0)));
3377
+ throw error;
3378
+ }
3379
+ if (options.requireAllLocks && acquired.length > 0 && acquired.length < plan.namespaces.length) {
3380
+ for (const { candidate, startedAt } of acquired) {
3381
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
3382
+ const status = {
3383
+ namespace: candidate.namespace,
3384
+ jobName: plan.jobName,
3385
+ state: "skipped",
3386
+ reason: "batch_lock_incomplete",
3387
+ startedAt,
3388
+ completedAt
3389
+ };
3390
+ statuses.push(status);
3391
+ await recordNamespaceMaintenanceStatusSafely(config, status);
3392
+ }
3393
+ await Promise.all(acquired.map(({ lock }) => lock.release().catch(() => void 0)));
3394
+ return {
3395
+ jobName: plan.jobName,
3396
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3397
+ ran: statuses.filter((s) => s.state === "ran").length,
3398
+ skipped: statuses.filter((s) => s.state === "skipped").length,
3399
+ failed: statuses.filter((s) => s.state === "failed").length,
3400
+ statuses
3401
+ };
3402
+ }
3403
+ if (acquired.length === 0) {
3404
+ return {
3405
+ jobName: plan.jobName,
3406
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3407
+ ran: statuses.filter((s) => s.state === "ran").length,
3408
+ skipped: statuses.filter((s) => s.state === "skipped").length,
3409
+ failed: statuses.filter((s) => s.state === "failed").length,
3410
+ statuses
3411
+ };
3412
+ }
3413
+ try {
3414
+ const result = await withNamespaceMaintenanceLockHeartbeat(
3415
+ config,
3416
+ acquired.map(({ lock }) => lock),
3417
+ () => runner(acquired.map(({ candidate }) => candidate))
3418
+ );
3419
+ for (const { candidate, startedAt } of acquired) {
3420
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
3421
+ const status = {
3422
+ namespace: candidate.namespace,
3423
+ jobName: plan.jobName,
3424
+ state: "ran",
3425
+ startedAt,
3426
+ completedAt,
3427
+ itemCount: itemCountForNamespace(result, candidate.namespace)
3428
+ };
3429
+ statuses.push(status);
3430
+ await recordNamespaceMaintenanceStatusSafely(config, status);
3431
+ try {
3432
+ await catalog?.markMaintenance(candidate.namespace, plan.jobName, new Date(completedAt));
3433
+ } catch {
3434
+ }
3435
+ }
3436
+ } catch (error) {
3437
+ const skipReason = options.skipReasonForError?.(error);
3438
+ for (const { candidate, startedAt } of acquired) {
3439
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
3440
+ const status = skipReason ? {
3441
+ namespace: candidate.namespace,
3442
+ jobName: plan.jobName,
3443
+ state: "skipped",
3444
+ reason: skipReason,
3445
+ startedAt,
3446
+ completedAt
3447
+ } : {
3448
+ namespace: candidate.namespace,
3449
+ jobName: plan.jobName,
3450
+ state: "failed",
3451
+ reason: "job_failed",
3452
+ startedAt,
3453
+ completedAt,
3454
+ error: maintenanceErrorDetail(error)
3455
+ };
3456
+ statuses.push(status);
3457
+ await recordNamespaceMaintenanceStatusSafely(config, status);
3458
+ }
3459
+ } finally {
3460
+ await Promise.all(acquired.map(({ lock }) => lock.release().catch(() => void 0)));
3461
+ }
3462
+ return {
3463
+ jobName: plan.jobName,
3464
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3465
+ ran: statuses.filter((s) => s.state === "ran").length,
3466
+ skipped: statuses.filter((s) => s.state === "skipped").length,
3467
+ failed: statuses.filter((s) => s.state === "failed").length,
3468
+ statuses
3469
+ };
3470
+ }
3471
+ function itemCountForNamespace(result, namespace) {
3472
+ const itemCounts = result?.itemCounts;
3473
+ if (itemCounts instanceof Map) return itemCounts.get(namespace);
3474
+ if (itemCounts && Object.prototype.hasOwnProperty.call(itemCounts, namespace)) {
3475
+ return itemCounts[namespace];
3476
+ }
3477
+ return result?.itemCount;
3478
+ }
3479
+
2868
3480
  // src/orchestrator.ts
2869
3481
  var BulkImportBatchPartialFailureError = class extends Error {
2870
3482
  partialResult;
@@ -2926,7 +3538,7 @@ function flattenStructuredSectionEvidence(sections) {
2926
3538
  );
2927
3539
  }
2928
3540
  function fingerprintEntitySynthesisEvidence(entity) {
2929
- const fingerprint = createHash("sha256");
3541
+ const fingerprint = createHash2("sha256");
2930
3542
  const timelineEntries = entity.timeline.map((entry) => [
2931
3543
  entry.timestamp,
2932
3544
  entry.source ?? "",
@@ -2976,7 +3588,7 @@ async function raceRecallAbort(promise, signal, message = "recall aborted") {
2976
3588
  }
2977
3589
  }
2978
3590
  function qmdCollectionPathParts(resultPath) {
2979
- if (!resultPath || path3.isAbsolute(resultPath)) return null;
3591
+ if (!resultPath || path4.isAbsolute(resultPath)) return null;
2980
3592
  const normalized = resultPath.replace(/\\/g, "/").replace(/^\/+/, "");
2981
3593
  const slashIndex = normalized.indexOf("/");
2982
3594
  if (slashIndex <= 0 || slashIndex >= normalized.length - 1) return null;
@@ -2989,9 +3601,9 @@ function qmdCollectionPathParts(resultPath) {
2989
3601
  }
2990
3602
  function qmdResultPathCandidates(storageDir, resultPath) {
2991
3603
  const candidates = /* @__PURE__ */ new Set();
2992
- const storageRoot = path3.resolve(storageDir);
3604
+ const storageRoot = path4.resolve(storageDir);
2993
3605
  const addCandidate = (candidate) => {
2994
- const resolved = path3.resolve(candidate);
3606
+ const resolved = path4.resolve(candidate);
2995
3607
  if (isPathInsideStorageRoot(storageRoot, resolved)) {
2996
3608
  candidates.add(resolved);
2997
3609
  }
@@ -2999,12 +3611,12 @@ function qmdResultPathCandidates(storageDir, resultPath) {
2999
3611
  const addRelativeCandidates = (relativePath) => {
3000
3612
  const normalized = relativePath.replace(/\\/g, "/").replace(/^\/+/, "");
3001
3613
  if (!normalized) return;
3002
- addCandidate(path3.join(storageRoot, normalized));
3614
+ addCandidate(path4.join(storageRoot, normalized));
3003
3615
  if (/^\d{4}-\d{2}-\d{2}\//.test(normalized)) {
3004
- addCandidate(path3.join(storageRoot, "facts", normalized));
3616
+ addCandidate(path4.join(storageRoot, "facts", normalized));
3005
3617
  }
3006
3618
  };
3007
- if (path3.isAbsolute(resultPath)) {
3619
+ if (path4.isAbsolute(resultPath)) {
3008
3620
  addCandidate(resultPath);
3009
3621
  } else {
3010
3622
  addRelativeCandidates(resultPath);
@@ -3121,11 +3733,11 @@ async function qmdStartupCollectionCheckWithTimeout(promise, controller, label)
3121
3733
  return await Promise.race([checkedPromise, timeoutPromise]);
3122
3734
  }
3123
3735
  function defaultWorkspaceDir() {
3124
- return path3.join(os.homedir(), ".openclaw", "workspace");
3736
+ return path4.join(os.homedir(), ".openclaw", "workspace");
3125
3737
  }
3126
3738
  function sanitizeSessionKeyForFilename(sessionKey) {
3127
3739
  const readable = sessionKey.replace(/[^a-zA-Z0-9._-]/g, "_");
3128
- const hash = createHash("sha256").update(sessionKey).digest("hex").slice(0, 12);
3740
+ const hash = createHash2("sha256").update(sessionKey).digest("hex").slice(0, 12);
3129
3741
  return `${readable}-${hash}`;
3130
3742
  }
3131
3743
  function latestSourceValidAtFromTurns(turns) {
@@ -3426,11 +4038,11 @@ function mergeGraphExpandedResults(primary, expanded) {
3426
4038
  return Array.from(mergedByPath.values());
3427
4039
  }
3428
4040
  function graphPathRelativeToStorage(storageDir, candidatePath) {
3429
- const absolutePath = path3.isAbsolute(candidatePath) ? candidatePath : path3.resolve(storageDir, candidatePath);
3430
- const rel = path3.relative(storageDir, absolutePath);
4041
+ const absolutePath = path4.isAbsolute(candidatePath) ? candidatePath : path4.resolve(storageDir, candidatePath);
4042
+ const rel = path4.relative(storageDir, absolutePath);
3431
4043
  if (!rel || rel === ".") return null;
3432
4044
  if (rel.startsWith("..")) return null;
3433
- return rel.split(path3.sep).join("/");
4045
+ return rel.split(path4.sep).join("/");
3434
4046
  }
3435
4047
  function normalizeGraphActivationScore(score) {
3436
4048
  const bounded = Number.isFinite(score) && score > 0 ? score : 0;
@@ -3572,7 +4184,7 @@ function buildMemoryPathById(allMemsForGraph, storageDir) {
3572
4184
  for (const mem of allMemsForGraph ?? []) {
3573
4185
  const id = mem.frontmatter.id;
3574
4186
  if (!id) continue;
3575
- pathById.set(id, path3.relative(storageDir, mem.path));
4187
+ pathById.set(id, path4.relative(storageDir, mem.path));
3576
4188
  }
3577
4189
  return pathById;
3578
4190
  }
@@ -3580,7 +4192,7 @@ function appendMemoryToGraphContext(options) {
3580
4192
  if (!Array.isArray(options.allMemsForGraph)) return;
3581
4193
  const nowIso = (/* @__PURE__ */ new Date()).toISOString();
3582
4194
  options.allMemsForGraph.push({
3583
- path: path3.join(options.storageDir, options.memoryRelPath),
4195
+ path: path4.join(options.storageDir, options.memoryRelPath),
3584
4196
  content: options.content,
3585
4197
  frontmatter: {
3586
4198
  id: options.memoryId,
@@ -3600,16 +4212,20 @@ function resolvePersistedMemoryRelativePath(options) {
3600
4212
  const persisted = options.pathById.get(options.memoryId);
3601
4213
  if (persisted) return persisted;
3602
4214
  if (options.category === "correction") {
3603
- return path3.join("corrections", `${options.memoryId}.md`);
4215
+ return path4.join("corrections", `${options.memoryId}.md`);
3604
4216
  }
3605
4217
  const subtree = options.category === "procedure" ? "procedures" : options.category === "reasoning_trace" ? "reasoning-traces" : "facts";
3606
4218
  const idParts = options.memoryId.split("-");
3607
4219
  const maybeTimestamp = Number(idParts[1]);
3608
4220
  if (Number.isFinite(maybeTimestamp) && maybeTimestamp > 0) {
3609
4221
  const day = new Date(maybeTimestamp).toISOString().slice(0, 10);
3610
- return path3.join(subtree, day, `${options.memoryId}.md`);
4222
+ return path4.join(subtree, day, `${options.memoryId}.md`);
3611
4223
  }
3612
- return path3.join(subtree, `${options.memoryId}.md`);
4224
+ return path4.join(subtree, `${options.memoryId}.md`);
4225
+ }
4226
+ function qmdMaintenanceSkipReasonForError(error) {
4227
+ const message = error instanceof Error ? error.message : String(error);
4228
+ return /^QMD (?:update|embed) skipped by .*min-interval gate$/.test(message) ? "throttled" : null;
3613
4229
  }
3614
4230
  var Orchestrator = class _Orchestrator {
3615
4231
  storage;
@@ -3716,6 +4332,7 @@ var Orchestrator = class _Orchestrator {
3716
4332
  _peerIdBySession = /* @__PURE__ */ new Map();
3717
4333
  routingRulesStore = null;
3718
4334
  contentHashIndex = null;
4335
+ contentHashIndexesByStorageDir = /* @__PURE__ */ new Map();
3719
4336
  artifactSourceStatusCache = /* @__PURE__ */ new WeakMap();
3720
4337
  static ARTIFACT_STATUS_CACHE_TTL_MS = 6e4;
3721
4338
  // Access tracking buffer (Phase 1A)
@@ -3737,6 +4354,7 @@ var Orchestrator = class _Orchestrator {
3737
4354
  qmdMaintenancePending = false;
3738
4355
  qmdMaintenanceInFlight = false;
3739
4356
  lastQmdEmbedAtMs = 0;
4357
+ lastQmdEmbedAtMsByNamespace = /* @__PURE__ */ new Map();
3740
4358
  lastQmdReprobeAtMs = 0;
3741
4359
  tierMigrationInFlight = false;
3742
4360
  lastTierMigrationRunAtMs = 0;
@@ -4038,7 +4656,7 @@ var Orchestrator = class _Orchestrator {
4038
4656
  const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
4039
4657
  if (ns !== defaultNs && !isSafeRouteNamespace(ns)) return;
4040
4658
  if (!this.storageDirMatchesNamespaceHint(ns, storageDir)) return;
4041
- const resolvedStorageDir = path3.resolve(storageDir);
4659
+ const resolvedStorageDir = path4.resolve(storageDir);
4042
4660
  let hints = this.namespaceStorageDirHints.get(resolvedStorageDir);
4043
4661
  if (!hints) {
4044
4662
  hints = /* @__PURE__ */ new Set();
@@ -4049,21 +4667,21 @@ var Orchestrator = class _Orchestrator {
4049
4667
  storageDirMatchesNamespaceHint(namespace, storageDir) {
4050
4668
  const ns = normalizeNamespaceIdentity(namespace);
4051
4669
  if (!ns) return false;
4052
- const resolvedStorageDir = path3.resolve(storageDir);
4053
- const resolvedMemoryDir = path3.resolve(this.config.memoryDir);
4670
+ const resolvedStorageDir = path4.resolve(storageDir);
4671
+ const resolvedMemoryDir = path4.resolve(this.config.memoryDir);
4054
4672
  const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
4055
4673
  if (resolvedStorageDir === resolvedMemoryDir) return ns === defaultNs;
4056
- const resolvedNamespacesDir = path3.join(resolvedMemoryDir, "namespaces");
4674
+ const resolvedNamespacesDir = path4.join(resolvedMemoryDir, "namespaces");
4057
4675
  if (!isPathInsideStorageRoot(resolvedNamespacesDir, resolvedStorageDir)) return false;
4058
- const rawRoot = path3.resolve(resolvedNamespacesDir, ns);
4059
- const tokenRoot = path3.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
4676
+ const rawRoot = path4.resolve(resolvedNamespacesDir, ns);
4677
+ const tokenRoot = path4.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
4060
4678
  return resolvedStorageDir === rawRoot || resolvedStorageDir === tokenRoot;
4061
4679
  }
4062
4680
  namespaceStorageDirHintOwnershipRank(record, resolvedStorageDir, configured) {
4063
- if (resolvedStorageDir === path3.resolve(this.config.memoryDir)) {
4681
+ if (resolvedStorageDir === path4.resolve(this.config.memoryDir)) {
4064
4682
  return record.namespace === normalizeNamespaceIdentity(this.config.defaultNamespace) ? 0 : 3;
4065
4683
  }
4066
- const leaf = path3.basename(resolvedStorageDir);
4684
+ const leaf = path4.basename(resolvedStorageDir);
4067
4685
  const tokenOwnsRoot = namespaceIdentityToken(record.namespace) === leaf;
4068
4686
  if (tokenOwnsRoot && configured.has(record.namespace)) return 0;
4069
4687
  if (record.namespace === leaf) return 1;
@@ -4091,7 +4709,7 @@ var Orchestrator = class _Orchestrator {
4091
4709
  loadNamespaceStorageDirHintsFromCatalog() {
4092
4710
  if (this.namespaceStorageDirHintsLoaded || !this.namespaceCatalog.enabled) return;
4093
4711
  this.namespaceStorageDirHintsLoaded = true;
4094
- const catalogPath = path3.join(this.config.memoryDir, "state", "namespaces.jsonl");
4712
+ const catalogPath = path4.join(this.config.memoryDir, "state", "namespaces.jsonl");
4095
4713
  if (!existsSync(catalogPath)) return;
4096
4714
  let body;
4097
4715
  try {
@@ -4128,7 +4746,7 @@ var Orchestrator = class _Orchestrator {
4128
4746
  if (!this.storageDirMatchesNamespaceHint(record.namespace, record.storageDir)) {
4129
4747
  continue;
4130
4748
  }
4131
- const resolvedStorageDir = path3.resolve(record.storageDir);
4749
+ const resolvedStorageDir = path4.resolve(record.storageDir);
4132
4750
  const current = preferredByStorageDir.get(resolvedStorageDir);
4133
4751
  preferredByStorageDir.set(
4134
4752
  resolvedStorageDir,
@@ -4145,57 +4763,27 @@ var Orchestrator = class _Orchestrator {
4145
4763
  }
4146
4764
  }
4147
4765
  /**
4148
- * Namespaces that QMD maintenance (update/embed) must cover: the CONFIGURED set
4149
- * PLUS every dynamic namespace recorded in the catalog (NGnei, codex P2). An
4150
- * extraction that writes to a coding-scoped/dynamic namespace (not in
4151
- * defaultNamespace/sharedNamespace/namespacePolicies) is only made discoverable
4152
- * via the catalog; if maintenance embeds only `configuredNamespaces()`, that
4153
- * namespace's QMD collection is never updated/embedded after writes and
4154
- * recall/search stays stale or empty until it is manually configured. We union in
4155
- * the catalog's namespaces so maintenance keeps dynamic namespaces fresh.
4156
- * `updateNamespaces`/`embedNamespaces` already trim, dedup, and skip
4157
- * unavailable/missing collections, so extra names are filtered safely. A catalog
4158
- * read failure must never break maintenance — fall back to the configured set.
4766
+ * Shared namespace maintenance planner (issue #1500). This extends the
4767
+ * #1499 catalog-union QMD helper into a reusable contract: configured
4768
+ * namespaces are always considered, dynamic catalog namespaces are admitted
4769
+ * only when their live router root still matches real memory data, and branch
4770
+ * namespaces are opt-in. Recurring jobs use the per-cycle budget; startup and
4771
+ * recovery discovery paths use the same safety filters without that cycle
4772
+ * budget so every live namespace is ensured/synced.
4159
4773
  */
4160
- async maintenanceNamespaces() {
4161
- const configured = this.configuredNamespaces();
4162
- if (!this.namespaceCatalog.enabled) return configured;
4163
- const configuredSet = new Set(configured);
4164
- let cataloged = [];
4165
- try {
4166
- const records = await this.namespaceCatalog.listNamespaces();
4167
- const safeRecords = await Promise.all(
4168
- records.map(async (record) => {
4169
- const namespace = record.namespace.trim();
4170
- if (!namespace || configuredSet.has(namespace)) return null;
4171
- return await this.isCatalogedMaintenanceRootLive(record) ? namespace : null;
4172
- })
4173
- );
4174
- cataloged = safeRecords.filter(
4175
- (namespace) => namespace !== null
4176
- );
4177
- } catch {
4178
- cataloged = [];
4179
- }
4180
- return Array.from(
4181
- new Set(
4182
- [...configured, ...cataloged].map((value) => value.trim()).filter(Boolean)
4183
- )
4184
- );
4774
+ async namespaceMaintenancePlan(jobName) {
4775
+ return planNamespaceMaintenance(this.config, {
4776
+ jobName,
4777
+ catalog: this.namespaceCatalog
4778
+ });
4185
4779
  }
4186
- async isCatalogedMaintenanceRootLive(record) {
4187
- if (typeof record.storageDir !== "string" || record.storageDir.length === 0) {
4188
- return false;
4189
- }
4190
- try {
4191
- const liveRoot = await resolveNamespaceStorageRoot(this.config, record.namespace);
4192
- if (path3.resolve(liveRoot) !== path3.resolve(record.storageDir)) {
4193
- return false;
4194
- }
4195
- return hasMemoryData(liveRoot);
4196
- } catch {
4197
- return false;
4198
- }
4780
+ async maintenanceNamespaces(jobName = "qmd", budgetMode = "unbounded") {
4781
+ const plan = await planNamespaceMaintenance(this.config, {
4782
+ jobName,
4783
+ catalog: this.namespaceCatalog,
4784
+ budgetMode
4785
+ });
4786
+ return plan.namespaces.map((candidate) => candidate.namespace);
4199
4787
  }
4200
4788
  buildConfiguredQmdSearchOptions(queryText) {
4201
4789
  const intentHint = this.config.qmdIntentHintsEnabled ? buildQmdIntentHint(inferIntentFromText(queryText)) : void 0;
@@ -4210,6 +4798,9 @@ var Orchestrator = class _Orchestrator {
4210
4798
  return Object.keys(searchOptions).length > 0 ? searchOptions : void 0;
4211
4799
  }
4212
4800
  async searchAcrossNamespaces(options) {
4801
+ if (this.config.namespacesEnabled && options.namespaces !== void 0 && options.namespaces.length === 0) {
4802
+ return [];
4803
+ }
4213
4804
  const namespaces = this.config.namespacesEnabled ? Array.from(
4214
4805
  new Set(
4215
4806
  (options.namespaces?.length ? options.namespaces : this.configuredNamespaces()).map((value) => value.trim()).filter(Boolean)
@@ -4266,12 +4857,63 @@ var Orchestrator = class _Orchestrator {
4266
4857
  }
4267
4858
  invalidateLiveContentHashIndex() {
4268
4859
  this.contentHashIndex = null;
4860
+ this.contentHashIndexesByStorageDir.clear();
4861
+ }
4862
+ async contentHashIndexForStorage(targetStorage) {
4863
+ if (!this.config.factDeduplicationEnabled) return null;
4864
+ if (targetStorage.dir === this.storage.dir) {
4865
+ if (!this.contentHashIndex) {
4866
+ this.contentHashIndex = this.storage.createContentHashIndex();
4867
+ await this.contentHashIndex.load();
4868
+ }
4869
+ return this.contentHashIndex;
4870
+ }
4871
+ const cached = this.contentHashIndexesByStorageDir.get(targetStorage.dir);
4872
+ if (cached) return cached;
4873
+ const index = targetStorage.createContentHashIndex();
4874
+ await index.load();
4875
+ this.contentHashIndexesByStorageDir.set(targetStorage.dir, index);
4876
+ log.info(
4877
+ `content-hash dedup: loaded ${index.size} hashes for storage ${targetStorage.dir}`
4878
+ );
4879
+ return index;
4880
+ }
4881
+ async hasContentHashDedup(targetStorage, content) {
4882
+ const index = await this.contentHashIndexForStorage(targetStorage);
4883
+ return index ? index.has(content) : false;
4884
+ }
4885
+ async addContentHashDedup(targetStorage, content) {
4886
+ const index = await this.contentHashIndexForStorage(targetStorage);
4887
+ if (!index) return;
4888
+ index.add(content);
4889
+ }
4890
+ async removeContentHashForMemory(targetStorage, memory, context) {
4891
+ const index = await this.contentHashIndexForStorage(targetStorage);
4892
+ if (!index) return;
4893
+ if (memory.frontmatter.contentHash) {
4894
+ index.removeByHash(memory.frontmatter.contentHash);
4895
+ return;
4896
+ }
4897
+ log.warn(
4898
+ `[${context}] removing hash for legacy memory ${memory.frontmatter.id ?? "(unknown)"} via content fallback - no contentHash in frontmatter`
4899
+ );
4900
+ index.remove(memory.content);
4901
+ }
4902
+ async saveContentHashIndexes() {
4903
+ const indexes = /* @__PURE__ */ new Set();
4904
+ if (this.contentHashIndex) indexes.add(this.contentHashIndex);
4905
+ for (const index of this.contentHashIndexesByStorageDir.values()) {
4906
+ indexes.add(index);
4907
+ }
4908
+ for (const index of indexes) {
4909
+ await index.save();
4910
+ }
4269
4911
  }
4270
4912
  constructor(config) {
4271
4913
  this.config = config;
4272
4914
  this.profiler = new ProfilingCollector({
4273
4915
  enabled: config.profilingEnabled,
4274
- storageDir: config.profilingStorageDir || path3.join(config.memoryDir, "profiling"),
4916
+ storageDir: config.profilingStorageDir || path4.join(config.memoryDir, "profiling"),
4275
4917
  maxTraces: config.profilingMaxTraces
4276
4918
  });
4277
4919
  this.namespaceCatalog = new NamespaceCatalog(config);
@@ -4316,7 +4958,7 @@ var Orchestrator = class _Orchestrator {
4316
4958
  this.compounding = config.compoundingEnabled ? new CompoundingEngine(config, this.storage) : void 0;
4317
4959
  this.buffer = new SmartBuffer(config, this.storage);
4318
4960
  this.transcript = new TranscriptManager(config);
4319
- this.conversationIndexDir = path3.join(
4961
+ this.conversationIndexDir = path4.join(
4320
4962
  config.memoryDir,
4321
4963
  "conversation-index",
4322
4964
  "chunks"
@@ -4373,7 +5015,7 @@ var Orchestrator = class _Orchestrator {
4373
5015
  this.modelRegistry
4374
5016
  );
4375
5017
  this.threading = new ThreadingManager(
4376
- path3.join(config.memoryDir, "threads"),
5018
+ path4.join(config.memoryDir, "threads"),
4377
5019
  config.threadingGapMinutes
4378
5020
  );
4379
5021
  this.tmtBuilder = new TmtBuilder(config.memoryDir, {
@@ -4452,7 +5094,7 @@ var Orchestrator = class _Orchestrator {
4452
5094
  utilityPromoteThresholdDelta: this.utilityRuntimeValues?.promoteThresholdDelta ?? 0,
4453
5095
  utilityDemoteThresholdDelta: this.utilityRuntimeValues?.demoteThresholdDelta ?? 0
4454
5096
  };
4455
- return createHash("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 12);
5097
+ return createHash2("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 12);
4456
5098
  }
4457
5099
  effectiveLifecycleThresholds() {
4458
5100
  const archiveDecayThreshold = this.config.lifecycleArchiveDecayThreshold;
@@ -4672,11 +5314,11 @@ var Orchestrator = class _Orchestrator {
4672
5314
  if (this.config.compactionResetEnabled) {
4673
5315
  try {
4674
5316
  const wsDir = this.config.workspaceDir || defaultWorkspaceDir();
4675
- const files = await readdir2(wsDir).catch(() => []);
5317
+ const files = await readdir3(wsDir).catch(() => []);
4676
5318
  for (const f of files) {
4677
5319
  if (!f.startsWith(".compaction-reset-signal-")) continue;
4678
- const fp = path3.join(wsDir, f);
4679
- const s = await stat2(fp).catch(() => null);
5320
+ const fp = path4.join(wsDir, f);
5321
+ const s = await stat3(fp).catch(() => null);
4680
5322
  if (s && Date.now() - s.mtimeMs >= COMPACTION_SIGNAL_MAX_AGE_MS) {
4681
5323
  await unlink2(fp).catch(() => {
4682
5324
  });
@@ -4954,9 +5596,9 @@ var Orchestrator = class _Orchestrator {
4954
5596
  `wearables auto-sync started: every ${this.config.wearables.autoSyncIntervalMinutes}m over ${this.config.wearables.autoSyncDays}d (deep ${this.config.wearables.autoSyncDeepDays}d daily)`
4955
5597
  );
4956
5598
  } catch (err) {
4957
- const { displayErrorDetail } = await import("./runtime/better-sqlite.js");
5599
+ const { displayErrorDetail: displayErrorDetail2 } = await import("./runtime/better-sqlite.js");
4958
5600
  log.warn(
4959
- `wearables auto-sync failed to start (non-fatal): ${displayErrorDetail(err)}`
5601
+ `wearables auto-sync failed to start (non-fatal): ${displayErrorDetail2(err)}`
4960
5602
  );
4961
5603
  }
4962
5604
  }
@@ -5069,7 +5711,7 @@ var Orchestrator = class _Orchestrator {
5069
5711
  */
5070
5712
  async autoRegisterDaySummaryCron() {
5071
5713
  const home = resolveHomeDir();
5072
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
5714
+ const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
5073
5715
  try {
5074
5716
  if (!existsSync(jobsPath)) {
5075
5717
  log.debug(
@@ -5122,7 +5764,7 @@ var Orchestrator = class _Orchestrator {
5122
5764
  }
5123
5765
  async autoRegisterNightlyGovernanceCron() {
5124
5766
  const home = resolveHomeDir();
5125
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
5767
+ const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
5126
5768
  try {
5127
5769
  if (!existsSync(jobsPath)) {
5128
5770
  log.debug("nightly governance cron: jobs.json not found, skipping auto-register");
@@ -5144,7 +5786,7 @@ var Orchestrator = class _Orchestrator {
5144
5786
  }
5145
5787
  async autoRegisterProceduralMiningCron() {
5146
5788
  const home = resolveHomeDir();
5147
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
5789
+ const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
5148
5790
  try {
5149
5791
  if (!existsSync(jobsPath)) {
5150
5792
  log.debug("procedural mining cron: jobs.json not found, skipping auto-register");
@@ -5164,7 +5806,7 @@ var Orchestrator = class _Orchestrator {
5164
5806
  }
5165
5807
  async autoRegisterContradictionScanCron() {
5166
5808
  const home = resolveHomeDir();
5167
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
5809
+ const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
5168
5810
  try {
5169
5811
  if (!existsSync(jobsPath)) {
5170
5812
  log.debug("contradiction scan cron: jobs.json not found, skipping auto-register");
@@ -5184,7 +5826,7 @@ var Orchestrator = class _Orchestrator {
5184
5826
  }
5185
5827
  async autoRegisterPatternReinforcementCron() {
5186
5828
  const home = resolveHomeDir();
5187
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
5829
+ const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
5188
5830
  try {
5189
5831
  if (!existsSync(jobsPath)) {
5190
5832
  log.debug("pattern reinforcement cron: jobs.json not found, skipping auto-register");
@@ -5246,7 +5888,7 @@ var Orchestrator = class _Orchestrator {
5246
5888
  }
5247
5889
  async autoRegisterGraphEdgeDecayCron() {
5248
5890
  const home = resolveHomeDir();
5249
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
5891
+ const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
5250
5892
  try {
5251
5893
  if (!existsSync(jobsPath)) {
5252
5894
  log.debug("graph edge decay cron: jobs.json not found, skipping auto-register");
@@ -5303,15 +5945,15 @@ ${doc.content}` : doc.content,
5303
5945
  this.lastFileHygieneRunAtMs = now;
5304
5946
  if (hygiene.rotateEnabled) {
5305
5947
  for (const rel of hygiene.rotatePaths) {
5306
- const abs = path3.isAbsolute(rel) ? rel : path3.join(this.config.workspaceDir, rel);
5948
+ const abs = path4.isAbsolute(rel) ? rel : path4.join(this.config.workspaceDir, rel);
5307
5949
  try {
5308
- const raw = await readFile3(abs, "utf-8");
5950
+ const raw = await readFile4(abs, "utf-8");
5309
5951
  if (raw.length > hygiene.rotateMaxBytes) {
5310
- const archiveDir = path3.join(
5952
+ const archiveDir = path4.join(
5311
5953
  this.config.workspaceDir,
5312
5954
  hygiene.archiveDir
5313
5955
  );
5314
- const base = path3.basename(abs);
5956
+ const base = path4.basename(abs);
5315
5957
  const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
5316
5958
  const { newContent } = await rotateMarkdownFileToArchive({
5317
5959
  filePath: abs,
@@ -5319,7 +5961,7 @@ ${doc.content}` : doc.content,
5319
5961
  archivePrefix: prefix,
5320
5962
  keepTailChars: hygiene.rotateKeepTailChars
5321
5963
  });
5322
- await writeFile3(abs, newContent, "utf-8");
5964
+ await writeFile4(abs, newContent, "utf-8");
5323
5965
  }
5324
5966
  } catch {
5325
5967
  }
@@ -5336,8 +5978,8 @@ ${doc.content}` : doc.content,
5336
5978
  log.warn(w.message);
5337
5979
  }
5338
5980
  if (hygiene.warningsLogEnabled && warnings.length > 0) {
5339
- const fp = path3.join(this.config.memoryDir, hygiene.warningsLogPath);
5340
- await mkdir3(path3.dirname(fp), { recursive: true });
5981
+ const fp = path4.join(this.config.memoryDir, hygiene.warningsLogPath);
5982
+ await mkdir4(path4.dirname(fp), { recursive: true });
5341
5983
  const stamp = (/* @__PURE__ */ new Date()).toISOString();
5342
5984
  const block = `
5343
5985
 
@@ -5346,11 +5988,11 @@ ${doc.content}` : doc.content,
5346
5988
  ` + warnings.map((w) => `- ${w.message}`).join("\n") + "\n";
5347
5989
  let existing = "";
5348
5990
  try {
5349
- existing = await readFile3(fp, "utf-8");
5991
+ existing = await readFile4(fp, "utf-8");
5350
5992
  } catch {
5351
5993
  existing = "# Engram File Hygiene Warnings\n";
5352
5994
  }
5353
- await writeFile3(fp, existing + block, "utf-8");
5995
+ await writeFile4(fp, existing + block, "utf-8");
5354
5996
  }
5355
5997
  }
5356
5998
  }
@@ -5545,16 +6187,11 @@ ${doc.content}` : doc.content,
5545
6187
  relatedMemoryIds: [canonicalId]
5546
6188
  });
5547
6189
  if (archiveResult) {
5548
- if (this.contentHashIndex) {
5549
- if (m.frontmatter.contentHash) {
5550
- this.contentHashIndex.removeByHash(m.frontmatter.contentHash);
5551
- } else {
5552
- log.warn(
5553
- `[semantic-consolidation] removing hash for legacy memory ${m.frontmatter.id ?? "(unknown)"} via content fallback \u2014 no contentHash in frontmatter`
5554
- );
5555
- this.contentHashIndex.remove(m.content);
5556
- }
5557
- }
6190
+ await this.removeContentHashForMemory(
6191
+ targetStorage,
6192
+ m,
6193
+ "semantic-consolidation"
6194
+ );
5558
6195
  try {
5559
6196
  await this.embeddingFallback.removeFromIndex(m.frontmatter.id);
5560
6197
  if (this.config.queryAwareIndexingEnabled && m.path && m.frontmatter?.created) {
@@ -5590,8 +6227,8 @@ ${doc.content}` : doc.content,
5590
6227
  }
5591
6228
  }
5592
6229
  }
5593
- if (result.memoriesArchived > 0 && this.contentHashIndex) {
5594
- await this.contentHashIndex.save().catch(
6230
+ if (result.memoriesArchived > 0) {
6231
+ await this.saveContentHashIndexes().catch(
5595
6232
  (err) => log.warn(
5596
6233
  `[semantic-consolidation] content-hash index save failed: ${err}`
5597
6234
  )
@@ -5820,18 +6457,18 @@ ${evidenceText}`
5820
6457
  const now = options.now instanceof Date && Number.isFinite(options.now.getTime()) ? options.now : /* @__PURE__ */ new Date();
5821
6458
  const targetLocalDate = formatDateInTimeZone(now, timeZone);
5822
6459
  const datesToScan = utcDateKeysForLocalDay(now, timeZone);
5823
- const factsBaseDir = path3.join(storage.dir, "facts");
6460
+ const factsBaseDir = path4.join(storage.dir, "facts");
5824
6461
  const MAX_CHARS = 1e5;
5825
6462
  const facts = [];
5826
6463
  for (const date of datesToScan) {
5827
- const factsDir = path3.join(factsBaseDir, date);
6464
+ const factsDir = path4.join(factsBaseDir, date);
5828
6465
  try {
5829
- const entries = await readdir2(factsDir, { withFileTypes: true });
6466
+ const entries = await readdir3(factsDir, { withFileTypes: true });
5830
6467
  for (const entry of entries) {
5831
6468
  if (!entry.name.endsWith(".md")) continue;
5832
- const fullPath = path3.join(factsDir, entry.name);
6469
+ const fullPath = path4.join(factsDir, entry.name);
5833
6470
  try {
5834
- const raw = await readFile3(fullPath, "utf-8");
6471
+ const raw = await readFile4(fullPath, "utf-8");
5835
6472
  const fmMatch = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
5836
6473
  if (!fmMatch) continue;
5837
6474
  const fmBlock = fmMatch[1];
@@ -5850,7 +6487,7 @@ ${evidenceText}`
5850
6487
  facts.push({
5851
6488
  path: fullPath,
5852
6489
  frontmatter: {
5853
- id: fm.id || path3.basename(entry.name, ".md"),
6490
+ id: fm.id || path4.basename(entry.name, ".md"),
5854
6491
  category: fm.category || "fact",
5855
6492
  created,
5856
6493
  updated: fm.updated || created,
@@ -5872,15 +6509,15 @@ ${evidenceText}`
5872
6509
  return a.frontmatter.created < b.frontmatter.created ? -1 : 1;
5873
6510
  });
5874
6511
  const hourlySummaries = [];
5875
- const hourlyBaseDir = path3.join(storage.dir, "summaries", "hourly");
6512
+ const hourlyBaseDir = path4.join(storage.dir, "summaries", "hourly");
5876
6513
  try {
5877
- const sessionKeys = await readdir2(hourlyBaseDir, { withFileTypes: true });
6514
+ const sessionKeys = await readdir3(hourlyBaseDir, { withFileTypes: true });
5878
6515
  for (const sk of sessionKeys) {
5879
6516
  if (!sk.isDirectory()) continue;
5880
6517
  for (const date of datesToScan) {
5881
- const summaryFile = path3.join(hourlyBaseDir, sk.name, `${date}.md`);
6518
+ const summaryFile = path4.join(hourlyBaseDir, sk.name, `${date}.md`);
5882
6519
  try {
5883
- const raw = await readFile3(summaryFile, "utf-8");
6520
+ const raw = await readFile4(summaryFile, "utf-8");
5884
6521
  const filtered = filterHourlySummaryMarkdownForLocalDay(
5885
6522
  raw,
5886
6523
  date,
@@ -5982,13 +6619,13 @@ ${evidenceText}`
5982
6619
  }
5983
6620
  async getLastGraphRecallSnapshot(namespace) {
5984
6621
  const storage = await this.getStorage(namespace);
5985
- const snapshotPath = path3.join(
6622
+ const snapshotPath = path4.join(
5986
6623
  storage.dir,
5987
6624
  "state",
5988
6625
  "last_graph_recall.json"
5989
6626
  );
5990
6627
  try {
5991
- const raw = await readFile3(snapshotPath, "utf-8");
6628
+ const raw = await readFile4(snapshotPath, "utf-8");
5992
6629
  const parsed = JSON.parse(raw);
5993
6630
  if (!parsed || typeof parsed !== "object") return null;
5994
6631
  return {
@@ -6021,9 +6658,9 @@ ${evidenceText}`
6021
6658
  }
6022
6659
  async getLastIntentSnapshot(namespace) {
6023
6660
  const storage = await this.getStorage(namespace);
6024
- const snapshotPath = path3.join(storage.dir, "state", "last_intent.json");
6661
+ const snapshotPath = path4.join(storage.dir, "state", "last_intent.json");
6025
6662
  try {
6026
- const raw = await readFile3(snapshotPath, "utf-8");
6663
+ const raw = await readFile4(snapshotPath, "utf-8");
6027
6664
  const parsed = JSON.parse(raw);
6028
6665
  if (!parsed || typeof parsed !== "object") return null;
6029
6666
  const graphDecision = parsed.graphDecision && typeof parsed.graphDecision === "object" ? parsed.graphDecision : void 0;
@@ -6054,13 +6691,13 @@ ${evidenceText}`
6054
6691
  }
6055
6692
  async getLastQmdRecallSnapshot(namespace) {
6056
6693
  const storage = await this.getStorage(namespace);
6057
- const snapshotPath = path3.join(
6694
+ const snapshotPath = path4.join(
6058
6695
  storage.dir,
6059
6696
  "state",
6060
6697
  "last_qmd_recall.json"
6061
6698
  );
6062
6699
  try {
6063
- const raw = await readFile3(snapshotPath, "utf-8");
6700
+ const raw = await readFile4(snapshotPath, "utf-8");
6064
6701
  const parsed = JSON.parse(raw);
6065
6702
  if (!parsed || typeof parsed !== "object") return null;
6066
6703
  return {
@@ -6204,10 +6841,10 @@ ${r.snippet.trim()}
6204
6841
  }
6205
6842
  async countConversationChunkDocs(dir) {
6206
6843
  try {
6207
- const entries = await readdir2(dir, { withFileTypes: true });
6844
+ const entries = await readdir3(dir, { withFileTypes: true });
6208
6845
  let total = 0;
6209
6846
  for (const entry of entries) {
6210
- const fullPath = path3.join(dir, entry.name);
6847
+ const fullPath = path4.join(dir, entry.name);
6211
6848
  if (entry.isDirectory()) {
6212
6849
  total += await this.countConversationChunkDocs(fullPath);
6213
6850
  continue;
@@ -6499,7 +7136,8 @@ ${r.snippet.trim()}
6499
7136
  this.enqueueDirectAnswerObservation(
6500
7137
  prompt,
6501
7138
  sessionKey,
6502
- options.namespace?.trim() || void 0
7139
+ options.namespace?.trim() || void 0,
7140
+ options.principalOverride
6503
7141
  );
6504
7142
  } catch (err) {
6505
7143
  log.debug(`direct-answer observation setup failed: ${err}`);
@@ -6554,17 +7192,32 @@ ${r.snippet.trim()}
6554
7192
  if (timeoutHandle) clearTimeout(timeoutHandle);
6555
7193
  }
6556
7194
  }
6557
- enqueueDirectAnswerObservation(prompt, sessionKey, namespaceOverride) {
7195
+ enqueueDirectAnswerObservation(prompt, sessionKey, namespaceOverride, principalOverride) {
6558
7196
  const expectedSnapshot = this.lastRecall.get(sessionKey);
6559
7197
  if (expectedSnapshot === null) return;
6560
7198
  if (expectedSnapshot.plannerMode === "no_recall") return;
6561
- const principal = resolvePrincipal(sessionKey, this.config);
7199
+ const principal = principalOverride ?? resolvePrincipal(sessionKey, this.config);
6562
7200
  const observationCodingOverlay = namespaceOverride && canReadNamespace(principal, namespaceOverride, this.config) ? null : this.applyCodingRecallOverlay(sessionKey);
6563
7201
  const observationPrincipalSelf = defaultNamespaceForPrincipal(principal, this.config);
6564
7202
  const observationCodingSelf = observationCodingOverlay ? combineNamespaces(observationPrincipalSelf, observationCodingOverlay.namespace) : null;
7203
+ const observationScopeProfilePlan = namespaceOverride && canReadNamespace(principal, namespaceOverride, this.config) ? null : resolveScopeProfilePlan({
7204
+ config: this.config,
7205
+ principal,
7206
+ codingContext: sessionKey ? this.getCodingContextForSession(sessionKey) : null,
7207
+ codingOverlay: observationCodingOverlay
7208
+ });
6565
7209
  let observationNamespaces;
6566
7210
  if (namespaceOverride && canReadNamespace(principal, namespaceOverride, this.config)) {
6567
7211
  observationNamespaces = [namespaceOverride];
7212
+ } else if (observationScopeProfilePlan) {
7213
+ observationNamespaces = expandScopeProfileReadNamespaces({
7214
+ profilePlan: observationScopeProfilePlan,
7215
+ principalSelfNamespace: observationScopeProfilePlan.baseNamespace,
7216
+ config: this.config,
7217
+ principal,
7218
+ codingOverlay: observationCodingOverlay,
7219
+ legacyRecallNamespaces: recallNamespacesForPrincipal(principal, this.config)
7220
+ });
6568
7221
  } else if (observationCodingOverlay && observationCodingSelf) {
6569
7222
  const base = recallNamespacesForPrincipal(principal, this.config);
6570
7223
  const mapped = base.map(
@@ -6933,7 +7586,7 @@ ${r.snippet.trim()}
6933
7586
  if (!options.onDebugSnapshot) return;
6934
7587
  await options.onDebugSnapshot({
6935
7588
  recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
6936
- queryHash: createHash("sha256").update(prompt).digest("hex"),
7589
+ queryHash: createHash2("sha256").update(prompt).digest("hex"),
6937
7590
  queryLength: prompt.length,
6938
7591
  collection: options.collection,
6939
7592
  namespaces: options.recallNamespaces,
@@ -7106,7 +7759,7 @@ ${r.snippet.trim()}
7106
7759
  resolvedPath = resolvedCold.result.path;
7107
7760
  resolvedResult = resolvedCold.result;
7108
7761
  }
7109
- if (!path3.isAbsolute(resolvedPath)) {
7762
+ if (!path4.isAbsolute(resolvedPath)) {
7110
7763
  resolvedAmbiguousSeeds.set(result.path, null);
7111
7764
  return null;
7112
7765
  }
@@ -7131,7 +7784,7 @@ ${r.snippet.trim()}
7131
7784
  }
7132
7785
  continue;
7133
7786
  }
7134
- if (path3.isAbsolute(result.path)) {
7787
+ if (path4.isAbsolute(result.path)) {
7135
7788
  const resolved = await resolveAmbiguousSeedOwner(result, null);
7136
7789
  if (resolved) {
7137
7790
  addResultForNamespace(resolved.namespace, resolved.result);
@@ -7174,7 +7827,7 @@ ${r.snippet.trim()}
7174
7827
  0
7175
7828
  );
7176
7829
  seedPaths.push(
7177
- ...seedRelativePaths.map((rel) => path3.join(storage.dir, rel))
7830
+ ...seedRelativePaths.map((rel) => path4.join(storage.dir, rel))
7178
7831
  );
7179
7832
  const seedSet = new Set(seedRelativePaths);
7180
7833
  const expanded = await this.graphIndexFor(storage).spreadingActivation(
@@ -7190,7 +7843,7 @@ ${r.snippet.trim()}
7190
7843
  for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
7191
7844
  if (deadlineExpired()) break;
7192
7845
  if (seedSet.has(candidate.path)) continue;
7193
- const memoryPath = path3.resolve(storage.dir, candidate.path);
7846
+ const memoryPath = path4.resolve(storage.dir, candidate.path);
7194
7847
  const memory = await storage.readMemoryByPath(memoryPath);
7195
7848
  if (deadlineExpired()) break;
7196
7849
  if (!memory) continue;
@@ -7215,7 +7868,7 @@ ${r.snippet.trim()}
7215
7868
  path: memory.path,
7216
7869
  score,
7217
7870
  namespace,
7218
- seed: path3.resolve(storage.dir, candidate.seed),
7871
+ seed: path4.resolve(storage.dir, candidate.seed),
7219
7872
  hopDepth: candidate.hopDepth,
7220
7873
  decayedWeight: candidate.decayedWeight,
7221
7874
  graphType: candidate.graphType,
@@ -7236,12 +7889,12 @@ ${r.snippet.trim()}
7236
7889
  }
7237
7890
  async recordLastGraphRecallSnapshot(options) {
7238
7891
  try {
7239
- const snapshotPath = path3.join(
7892
+ const snapshotPath = path4.join(
7240
7893
  options.storage.dir,
7241
7894
  "state",
7242
7895
  "last_graph_recall.json"
7243
7896
  );
7244
- await mkdir3(path3.dirname(snapshotPath), { recursive: true });
7897
+ await mkdir4(path4.dirname(snapshotPath), { recursive: true });
7245
7898
  const now = (/* @__PURE__ */ new Date()).toISOString();
7246
7899
  const totalSeedCount = options.seedPaths.length;
7247
7900
  const totalExpandedCount = options.expandedPaths.length;
@@ -7253,7 +7906,7 @@ ${r.snippet.trim()}
7253
7906
  const payload = {
7254
7907
  recordedAt: now,
7255
7908
  mode: options.recallMode,
7256
- queryHash: createHash("sha256").update(options.prompt).digest("hex"),
7909
+ queryHash: createHash2("sha256").update(options.prompt).digest("hex"),
7257
7910
  queryLength: options.prompt.length,
7258
7911
  namespaces: options.recallNamespaces,
7259
7912
  seedCount: totalSeedCount,
@@ -7268,20 +7921,20 @@ ${r.snippet.trim()}
7268
7921
  finalResults: (options.finalResults ?? []).slice(0, 64),
7269
7922
  shadowComparison: options.shadowComparison
7270
7923
  };
7271
- await writeFile3(snapshotPath, JSON.stringify(payload, null, 2), "utf-8");
7924
+ await writeFile4(snapshotPath, JSON.stringify(payload, null, 2), "utf-8");
7272
7925
  } catch (err) {
7273
7926
  log.debug(`last graph recall write failed: ${err}`);
7274
7927
  }
7275
7928
  }
7276
7929
  async recordLastIntentSnapshot(options) {
7277
7930
  try {
7278
- const snapshotPath = path3.join(
7931
+ const snapshotPath = path4.join(
7279
7932
  options.storage.dir,
7280
7933
  "state",
7281
7934
  "last_intent.json"
7282
7935
  );
7283
- await mkdir3(path3.dirname(snapshotPath), { recursive: true });
7284
- await writeFile3(
7936
+ await mkdir4(path4.dirname(snapshotPath), { recursive: true });
7937
+ await writeFile4(
7285
7938
  snapshotPath,
7286
7939
  JSON.stringify(options.snapshot, null, 2),
7287
7940
  "utf-8"
@@ -7292,13 +7945,13 @@ ${r.snippet.trim()}
7292
7945
  }
7293
7946
  async recordLastQmdRecallSnapshot(options) {
7294
7947
  try {
7295
- const snapshotPath = path3.join(
7948
+ const snapshotPath = path4.join(
7296
7949
  options.storage.dir,
7297
7950
  "state",
7298
7951
  "last_qmd_recall.json"
7299
7952
  );
7300
- await mkdir3(path3.dirname(snapshotPath), { recursive: true });
7301
- await writeFile3(
7953
+ await mkdir4(path4.dirname(snapshotPath), { recursive: true });
7954
+ await writeFile4(
7302
7955
  snapshotPath,
7303
7956
  JSON.stringify(options.snapshot, null, 2),
7304
7957
  "utf-8"
@@ -7312,9 +7965,9 @@ ${r.snippet.trim()}
7312
7965
  const stateDir = await this.resolveStateDirForNamespace(
7313
7966
  options.namespace
7314
7967
  );
7315
- const snapshotPath = path3.join(stateDir, "last_intent.json");
7316
- await mkdir3(path3.dirname(snapshotPath), { recursive: true });
7317
- await writeFile3(
7968
+ const snapshotPath = path4.join(stateDir, "last_intent.json");
7969
+ await mkdir4(path4.dirname(snapshotPath), { recursive: true });
7970
+ await writeFile4(
7318
7971
  snapshotPath,
7319
7972
  JSON.stringify(options.snapshot, null, 2),
7320
7973
  "utf-8"
@@ -7325,24 +7978,24 @@ ${r.snippet.trim()}
7325
7978
  }
7326
7979
  async resolveStateDirForNamespace(namespace) {
7327
7980
  if (!this.config.namespacesEnabled) {
7328
- return path3.join(this.config.memoryDir, "state");
7981
+ return path4.join(this.config.memoryDir, "state");
7329
7982
  }
7330
7983
  if (namespace !== this.config.defaultNamespace) {
7331
- return path3.join(this.config.memoryDir, "namespaces", namespace, "state");
7984
+ return path4.join(this.config.memoryDir, "namespaces", namespace, "state");
7332
7985
  }
7333
- const candidate = path3.join(
7986
+ const candidate = path4.join(
7334
7987
  this.config.memoryDir,
7335
7988
  "namespaces",
7336
7989
  this.config.defaultNamespace
7337
7990
  );
7338
7991
  try {
7339
- const candidateStat = await stat2(candidate);
7992
+ const candidateStat = await stat3(candidate);
7340
7993
  if (candidateStat.isDirectory()) {
7341
- return path3.join(candidate, "state");
7994
+ return path4.join(candidate, "state");
7342
7995
  }
7343
7996
  } catch {
7344
7997
  }
7345
- return path3.join(this.config.memoryDir, "state");
7998
+ return path4.join(this.config.memoryDir, "state");
7346
7999
  }
7347
8000
  buildGraphRecallRankedResults(results, sourceLabelResolver, limit = 64) {
7348
8001
  return results.slice(0, limit).map((result) => ({
@@ -7584,8 +8237,8 @@ ${r.snippet.trim()}
7584
8237
  timings,
7585
8238
  logger: log
7586
8239
  });
7587
- const promptHash = createHash("sha256").update(prompt).digest("hex");
7588
- const traceId = createHash("sha256").update(`${sessionKey ?? "default"}:${recallStart}:${promptHash}`).digest("hex").slice(0, 16);
8240
+ const promptHash = createHash2("sha256").update(prompt).digest("hex");
8241
+ const traceId = createHash2("sha256").update(`${sessionKey ?? "default"}:${recallStart}:${promptHash}`).digest("hex").slice(0, 16);
7589
8242
  const sectionBuckets = /* @__PURE__ */ new Map();
7590
8243
  const queryPolicy = buildRecallQueryPolicy(prompt, sessionKey, {
7591
8244
  cronRecallPolicyEnabled: this.config.cronRecallPolicyEnabled,
@@ -7594,7 +8247,7 @@ ${r.snippet.trim()}
7594
8247
  cronConversationRecallMode: this.config.cronConversationRecallMode
7595
8248
  });
7596
8249
  const retrievalQuery = queryPolicy.retrievalQuery || prompt;
7597
- const retrievalQueryHash = createHash("sha256").update(retrievalQuery).digest("hex");
8250
+ const retrievalQueryHash = createHash2("sha256").update(retrievalQuery).digest("hex");
7598
8251
  const policyVersion = this.currentPolicyVersion();
7599
8252
  let impressionRecorded = false;
7600
8253
  let recallSource = "none";
@@ -7697,10 +8350,26 @@ ${r.snippet.trim()}
7697
8350
  const codingOverlay = namespaceOverride ? null : this.applyCodingRecallOverlay(sessionKey);
7698
8351
  const principalSelfNamespace = defaultNamespaceForPrincipal(principal, this.config);
7699
8352
  const codingSelfNamespace = codingOverlay ? combineNamespaces(principalSelfNamespace, codingOverlay.namespace) : null;
7700
- const selfNamespace = namespaceOverride ?? codingSelfNamespace ?? principalSelfNamespace;
8353
+ const scopeProfilePlan = namespaceOverride ? null : resolveScopeProfilePlan({
8354
+ config: this.config,
8355
+ principal,
8356
+ codingContext: sessionKey ? this.getCodingContextForSession(sessionKey) : null,
8357
+ codingOverlay
8358
+ });
8359
+ const profileEffectiveNamespace = scopeProfilePlan?.writeNamespace || scopeProfilePlan?.readNamespaces[0];
8360
+ const selfNamespace = namespaceOverride ?? profileEffectiveNamespace ?? codingSelfNamespace ?? principalSelfNamespace;
7701
8361
  let recallNamespaces;
7702
8362
  if (namespaceOverride) {
7703
8363
  recallNamespaces = [namespaceOverride];
8364
+ } else if (scopeProfilePlan) {
8365
+ recallNamespaces = expandScopeProfileReadNamespaces({
8366
+ profilePlan: scopeProfilePlan,
8367
+ principalSelfNamespace: scopeProfilePlan.baseNamespace,
8368
+ config: this.config,
8369
+ principal,
8370
+ codingOverlay,
8371
+ legacyRecallNamespaces: readableRecallNamespaces
8372
+ });
7704
8373
  } else if (codingOverlay && codingSelfNamespace) {
7705
8374
  const mapped = readableRecallNamespaces.map(
7706
8375
  (ns) => ns === principalSelfNamespace ? codingSelfNamespace : ns
@@ -7712,10 +8381,12 @@ ${r.snippet.trim()}
7712
8381
  } else {
7713
8382
  recallNamespaces = readableRecallNamespaces;
7714
8383
  }
7715
- const codingOverlaySelfReadable = codingOverlay !== null && readableRecallNamespaces.includes(principalSelfNamespace);
8384
+ const codingOverlaySelfReadable = codingOverlay !== null && (scopeProfilePlan ? scopeProfilePlan.layers.some((layer) => layer.id === "userProject" && layer.readable) : readableRecallNamespaces.includes(principalSelfNamespace));
7716
8385
  let lcmReadNamespaces;
7717
8386
  if (namespaceOverride) {
7718
8387
  lcmReadNamespaces = [namespaceOverride];
8388
+ } else if (scopeProfilePlan) {
8389
+ lcmReadNamespaces = recallNamespaces;
7719
8390
  } else if (codingOverlay && codingSelfNamespace && codingOverlaySelfReadable) {
7720
8391
  const fallbackNs = codingOverlay.readFallbacks.map(
7721
8392
  (fallback) => combineNamespaces(principalSelfNamespace, fallback)
@@ -7724,7 +8395,7 @@ ${r.snippet.trim()}
7724
8395
  } else {
7725
8396
  lcmReadNamespaces = [this.config.defaultNamespace];
7726
8397
  }
7727
- const lcmReadSessionIds = lcmReadSessionIdsForNamespaces(
8398
+ const lcmReadSessionIds = scopeProfilePlan && !sessionKey ? [] : lcmReadSessionIdsForNamespaces(
7728
8399
  lcmReadNamespaces,
7729
8400
  sessionKey,
7730
8401
  this.config.defaultNamespace
@@ -7752,7 +8423,7 @@ ${r.snippet.trim()}
7752
8423
  const graphExpandedResultPaths = /* @__PURE__ */ new Set();
7753
8424
  const graphSourceLabelsForPath = (resultPath) => {
7754
8425
  const labels = [];
7755
- const normalizedPath = resultPath.split(path3.sep).join("/");
8426
+ const normalizedPath = resultPath.split(path4.sep).join("/");
7756
8427
  const isEntityPath = normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/");
7757
8428
  if (graphBaselinePaths.has(resultPath)) labels.push("baseline");
7758
8429
  if (graphExpandedResultPaths.has(resultPath))
@@ -7897,7 +8568,144 @@ ${r.snippet.trim()}
7897
8568
  });
7898
8569
  return "";
7899
8570
  }
7900
- const profileStorage = await this.storageRouter.storageFor(selfNamespace);
8571
+ const profileStorageNamespaces = scopeProfilePlan ? recallNamespaces : [selfNamespace];
8572
+ const profileStorages = await Promise.all(
8573
+ profileStorageNamespaces.map((namespace) => this.storageRouter.storageFor(namespace))
8574
+ );
8575
+ const emptyProfileStorage = new Proxy(
8576
+ { dir: path4.join(this.config.memoryDir, ".empty-scope-profile") },
8577
+ {
8578
+ get(target, prop) {
8579
+ if (prop in target) return target[prop];
8580
+ if (prop === "readProfile") return async () => "";
8581
+ if (prop === "readQuestions" || prop === "listEntityNames" || prop === "readContinuityIncidents")
8582
+ return async () => [];
8583
+ if (prop === "readIdentityAnchor" || prop === "readIdentityImprovementLoops")
8584
+ return async () => "";
8585
+ if (prop === "readEntity" || prop === "readMemoryByPath")
8586
+ return async () => null;
8587
+ return async () => [];
8588
+ }
8589
+ }
8590
+ );
8591
+ const profileStorage = profileStorages.length <= 1 ? profileStorages[0] ?? emptyProfileStorage : new Proxy(profileStorages[0], {
8592
+ get(target, prop) {
8593
+ if (prop === "readProfile") {
8594
+ return async () => {
8595
+ for (const storage of profileStorages) {
8596
+ const profile2 = await storage.readProfile();
8597
+ if (profile2.trim().length > 0) return profile2;
8598
+ }
8599
+ return "";
8600
+ };
8601
+ }
8602
+ if (prop === "readQuestions") {
8603
+ return async (...args) => {
8604
+ const merged = [];
8605
+ const seen = /* @__PURE__ */ new Set();
8606
+ const priorityOf = (question) => {
8607
+ const priority = Number(question?.priority ?? 0);
8608
+ return Number.isFinite(priority) ? priority : 0;
8609
+ };
8610
+ for (const storage of profileStorages) {
8611
+ const questions = await storage.readQuestions(...args);
8612
+ for (const question of questions) {
8613
+ const key = typeof question === "string" ? question : JSON.stringify(question);
8614
+ if (seen.has(key)) continue;
8615
+ seen.add(key);
8616
+ merged.push(question);
8617
+ }
8618
+ }
8619
+ return merged.sort(
8620
+ (left, right) => priorityOf(right) - priorityOf(left) || String(left?.id ?? "").localeCompare(String(right?.id ?? ""))
8621
+ );
8622
+ };
8623
+ }
8624
+ if (prop === "readIdentityAnchor") {
8625
+ return async () => {
8626
+ for (const storage of profileStorages) {
8627
+ const anchor = await storage.readIdentityAnchor() ?? "";
8628
+ if (anchor.trim().length > 0) return anchor;
8629
+ }
8630
+ return "";
8631
+ };
8632
+ }
8633
+ if (prop === "readIdentityImprovementLoops") {
8634
+ return async () => {
8635
+ const sections = [];
8636
+ const seen = /* @__PURE__ */ new Set();
8637
+ for (const storage of profileStorages) {
8638
+ const loops = (await storage.readIdentityImprovementLoops() ?? "").trim();
8639
+ if (!loops || seen.has(loops)) continue;
8640
+ seen.add(loops);
8641
+ sections.push(loops);
8642
+ }
8643
+ return sections.join("\n\n");
8644
+ };
8645
+ }
8646
+ if (prop === "readContinuityIncidents") {
8647
+ return async (...args) => {
8648
+ const limit = typeof args[0] === "number" && Number.isFinite(args[0]) ? Math.max(0, args[0]) : void 0;
8649
+ const incidents = [];
8650
+ const seen = /* @__PURE__ */ new Set();
8651
+ const incidentTime = (incident) => {
8652
+ const raw = incident?.updatedAt ?? incident?.openedAt ?? incident?.createdAt;
8653
+ const parsed = typeof raw === "string" ? Date.parse(raw) : Number.NaN;
8654
+ return Number.isFinite(parsed) ? parsed : 0;
8655
+ };
8656
+ for (const storage of profileStorages) {
8657
+ for (const incident of await storage.readContinuityIncidents(...args)) {
8658
+ const key = JSON.stringify(incident);
8659
+ if (seen.has(key)) continue;
8660
+ seen.add(key);
8661
+ incidents.push(incident);
8662
+ }
8663
+ }
8664
+ incidents.sort(
8665
+ (left, right) => incidentTime(right) - incidentTime(left) || String(left?.id ?? "").localeCompare(String(right?.id ?? ""))
8666
+ );
8667
+ return limit === void 0 ? incidents : incidents.slice(0, limit);
8668
+ };
8669
+ }
8670
+ if (prop === "listEntityNames") {
8671
+ return async (...args) => {
8672
+ const names = /* @__PURE__ */ new Set();
8673
+ for (const storage of profileStorages) {
8674
+ for (const name of await storage.listEntityNames(...args)) names.add(name);
8675
+ }
8676
+ return [...names];
8677
+ };
8678
+ }
8679
+ if (prop === "readEntity" || prop === "readMemoryByPath") {
8680
+ return async (...args) => {
8681
+ for (const storage of profileStorages) {
8682
+ const value = await storage[prop](...args);
8683
+ if (value) return value;
8684
+ }
8685
+ return null;
8686
+ };
8687
+ }
8688
+ if (prop === "readAllMemories") {
8689
+ return async (...args) => {
8690
+ const memories = [];
8691
+ const seen = /* @__PURE__ */ new Set();
8692
+ for (const storage of profileStorages) {
8693
+ for (const memory of await storage.readAllMemories(...args)) {
8694
+ const key = String(memory?.path ?? memory?.frontmatter?.id ?? JSON.stringify(memory));
8695
+ if (seen.has(key)) continue;
8696
+ seen.add(key);
8697
+ memories.push(memory);
8698
+ }
8699
+ }
8700
+ return memories;
8701
+ };
8702
+ }
8703
+ return target[prop];
8704
+ }
8705
+ });
8706
+ const profileStorageDirs = Array.from(
8707
+ new Set(profileStorages.map((storage) => storage.dir).filter((dir) => typeof dir === "string" && dir.length > 0))
8708
+ );
7901
8709
  throwIfRecallAborted(options.abortSignal);
7902
8710
  if (this.namespaceCatalog.enabled && recallResultLimit > 0 && !options.abortSignal?.aborted) {
7903
8711
  for (const ns of recallNamespaces) this.markCatalogRead(ns);
@@ -7909,6 +8717,8 @@ ${r.snippet.trim()}
7909
8717
  ))
7910
8718
  return null;
7911
8719
  if (!this.sharedContext) return null;
8720
+ if (scopeProfilePlan && !(scopeProfilePlan.profile.readOrder.includes("serverShared") && scopeProfilePlan.readNamespaces.includes(this.config.sharedNamespace)))
8721
+ return null;
7912
8722
  const t0 = Date.now();
7913
8723
  const [priorities, roundtable, crossSignals] = await Promise.all([
7914
8724
  this.sharedContext.readPriorities(),
@@ -8133,13 +8943,52 @@ ${lines.join("\n\n")}`;
8133
8943
  if (!this.config.knowledgeIndexEnabled) return null;
8134
8944
  const t0 = Date.now();
8135
8945
  try {
8136
- const ki = await this.storage.buildKnowledgeIndex(this.config, {
8137
- maxEntities: this.getRecallSectionNumber(
8138
- "knowledge-index",
8139
- "maxEntities"
8140
- ),
8141
- maxChars: this.getRecallSectionNumber("knowledge-index", "maxChars")
8142
- });
8946
+ const knowledgeIndexMaxChars = this.getRecallSectionNumber("knowledge-index", "maxChars") ?? this.config.knowledgeIndexMaxChars;
8947
+ const knowledgeIndexMaxEntities = this.getRecallSectionNumber("knowledge-index", "maxEntities") ?? this.config.knowledgeIndexMaxEntities;
8948
+ const knowledgeIndexOptions = {
8949
+ maxEntities: knowledgeIndexMaxEntities,
8950
+ maxChars: knowledgeIndexMaxChars
8951
+ };
8952
+ const ki = scopeProfilePlan ? await (async () => {
8953
+ const perLayerOptions = {
8954
+ ...knowledgeIndexOptions,
8955
+ maxEntities: Number.MAX_SAFE_INTEGER,
8956
+ maxChars: Number.MAX_SAFE_INTEGER
8957
+ };
8958
+ const results = await Promise.all(
8959
+ profileStorages.map(
8960
+ (storage) => storage.buildKnowledgeIndex(this.config, perLayerOptions)
8961
+ )
8962
+ );
8963
+ const sections = results.map((result) => result.result.trim()).filter((section) => section.length > 0);
8964
+ const maxRows = Math.max(0, Math.floor(knowledgeIndexMaxEntities));
8965
+ const rows = [];
8966
+ let header = null;
8967
+ for (const section of sections) {
8968
+ const lines = section.split("\n").map((line) => line.trimEnd()).filter((line) => line.length > 0);
8969
+ const tableHeaderIndex = lines.findIndex(
8970
+ (line) => line.startsWith("| Entity |")
8971
+ );
8972
+ if (tableHeaderIndex === -1) continue;
8973
+ header ??= lines.slice(0, tableHeaderIndex + 2);
8974
+ for (const row of lines.slice(tableHeaderIndex + 2)) {
8975
+ if (!row.startsWith("|")) continue;
8976
+ if (rows.length >= maxRows) break;
8977
+ rows.push(row);
8978
+ }
8979
+ if (rows.length >= maxRows) break;
8980
+ }
8981
+ const merged = header && rows.length > 0 ? `${header.join("\n")}
8982
+ ${rows.join("\n")}
8983
+ ` : "";
8984
+ return {
8985
+ result: this.truncateRecallSectionToBudget(
8986
+ merged,
8987
+ knowledgeIndexMaxChars
8988
+ ),
8989
+ cached: results.every((result) => result.cached)
8990
+ };
8991
+ })() : await this.storage.buildKnowledgeIndex(this.config, knowledgeIndexOptions);
8143
8992
  recordRecallSectionMetric({
8144
8993
  section: "ki",
8145
8994
  priority: "core",
@@ -8506,15 +9355,30 @@ ${lines.join("\n\n")}`;
8506
9355
  });
8507
9356
  return null;
8508
9357
  }
8509
- const results = await searchHarmonicRetrieval({
8510
- memoryDir: this.config.memoryDir,
8511
- abstractionNodeStoreDir: this.config.abstractionNodeStoreDir,
8512
- query: retrievalQuery,
8513
- maxResults,
8514
- sessionKey,
8515
- anchorsEnabled: this.config.abstractionAnchorsEnabled,
8516
- abortSignal: harmonicRetrievalAbort.signal
8517
- });
9358
+ const harmonicSearchDirs = scopeProfilePlan ? profileStorageDirs : [this.config.memoryDir];
9359
+ const harmonicResultsByDir = await Promise.all(
9360
+ harmonicSearchDirs.map(
9361
+ (memoryDir) => searchHarmonicRetrieval({
9362
+ memoryDir,
9363
+ abstractionNodeStoreDir: scopeProfilePlan ? void 0 : this.config.abstractionNodeStoreDir,
9364
+ query: retrievalQuery,
9365
+ maxResults,
9366
+ sessionKey,
9367
+ anchorsEnabled: this.config.abstractionAnchorsEnabled,
9368
+ abortSignal: harmonicRetrievalAbort.signal
9369
+ })
9370
+ )
9371
+ );
9372
+ const harmonicByNodeId = /* @__PURE__ */ new Map();
9373
+ for (const result of harmonicResultsByDir.flat()) {
9374
+ const existing = harmonicByNodeId.get(result.node.nodeId);
9375
+ if (!existing || result.score > existing.score) {
9376
+ harmonicByNodeId.set(result.node.nodeId, result);
9377
+ }
9378
+ }
9379
+ const results = [...harmonicByNodeId.values()].sort(
9380
+ (left, right) => right.score - left.score || right.anchorScore - left.anchorScore || right.node.recordedAt.localeCompare(left.node.recordedAt) || left.node.nodeId.localeCompare(right.node.nodeId)
9381
+ ).slice(0, maxResults);
8518
9382
  recordRecallSectionMetric({
8519
9383
  section: "harmonicRetrieval",
8520
9384
  priority: "enrichment",
@@ -8560,11 +9424,28 @@ ${lines.join("\n\n")}`;
8560
9424
  const VERIFIED_RECALL_TIMEOUT_MS = 15e3;
8561
9425
  let timeoutHandle;
8562
9426
  const results = await Promise.race([
8563
- searchVerifiedEpisodes({
8564
- memoryDir: profileStorage.dir,
8565
- query: retrievalQuery,
8566
- maxResults,
8567
- boxRecallDays: this.config.boxRecallDays
9427
+ Promise.all(
9428
+ profileStorageDirs.map(
9429
+ (memoryDir) => searchVerifiedEpisodes({
9430
+ memoryDir,
9431
+ query: retrievalQuery,
9432
+ maxResults,
9433
+ boxRecallDays: this.config.boxRecallDays
9434
+ }).catch((err) => {
9435
+ log.debug(`verified recall directory scan failed: ${err}`);
9436
+ return [];
9437
+ })
9438
+ )
9439
+ ).then((groups) => {
9440
+ const merged = [];
9441
+ const seen = /* @__PURE__ */ new Set();
9442
+ for (const result of groups.flat()) {
9443
+ const key = result.box.id || JSON.stringify(result);
9444
+ if (seen.has(key)) continue;
9445
+ seen.add(key);
9446
+ merged.push(result);
9447
+ }
9448
+ return merged.sort(compareVerifiedEpisodeResults).slice(0, maxResults);
8568
9449
  }),
8569
9450
  new Promise((resolve) => {
8570
9451
  timeoutHandle = setTimeout(
@@ -8623,10 +9504,27 @@ ${lines.join("\n\n")}`;
8623
9504
  const VERIFIED_RULES_TIMEOUT_MS = 15e3;
8624
9505
  let rulesTimeoutHandle;
8625
9506
  const results = await Promise.race([
8626
- searchVerifiedSemanticRules({
8627
- memoryDir: this.config.memoryDir,
8628
- query: retrievalQuery,
8629
- maxResults
9507
+ Promise.all(
9508
+ profileStorageDirs.map(
9509
+ (memoryDir) => searchVerifiedSemanticRules({
9510
+ memoryDir,
9511
+ query: retrievalQuery,
9512
+ maxResults
9513
+ }).catch((err) => {
9514
+ log.debug(`verified rules directory scan failed: ${err}`);
9515
+ return [];
9516
+ })
9517
+ )
9518
+ ).then((groups) => {
9519
+ const merged = [];
9520
+ const seen = /* @__PURE__ */ new Set();
9521
+ for (const result of groups.flat()) {
9522
+ const key = result.rule.frontmatter.id || result.rule.path || JSON.stringify(result);
9523
+ if (seen.has(key)) continue;
9524
+ seen.add(key);
9525
+ merged.push(result);
9526
+ }
9527
+ return merged.sort(compareVerifiedSemanticRuleResults).slice(0, maxResults);
8630
9528
  }),
8631
9529
  new Promise((resolve) => {
8632
9530
  rulesTimeoutHandle = setTimeout(
@@ -8682,13 +9580,28 @@ ${lines.join("\n\n")}`;
8682
9580
  });
8683
9581
  return null;
8684
9582
  }
8685
- const results = await searchWorkProductLedgerEntries({
8686
- memoryDir: this.config.memoryDir,
8687
- workProductLedgerDir: this.config.workProductLedgerDir,
8688
- query: retrievalQuery,
8689
- maxResults,
8690
- sessionKey
8691
- });
9583
+ const workProductSearchDirs = scopeProfilePlan ? profileStorageDirs : [this.config.memoryDir];
9584
+ const workProductResultsByDir = await Promise.all(
9585
+ workProductSearchDirs.map(
9586
+ (memoryDir) => searchWorkProductLedgerEntries({
9587
+ memoryDir,
9588
+ workProductLedgerDir: scopeProfilePlan ? void 0 : this.config.workProductLedgerDir,
9589
+ query: retrievalQuery,
9590
+ maxResults,
9591
+ sessionKey
9592
+ })
9593
+ )
9594
+ );
9595
+ const workProductByEntryId = /* @__PURE__ */ new Map();
9596
+ for (const result of workProductResultsByDir.flat()) {
9597
+ const existing = workProductByEntryId.get(result.entry.entryId);
9598
+ if (!existing || result.score > existing.score) {
9599
+ workProductByEntryId.set(result.entry.entryId, result);
9600
+ }
9601
+ }
9602
+ const results = [...workProductByEntryId.values()].sort(
9603
+ (left, right) => right.score - left.score || right.entry.recordedAt.localeCompare(left.entry.recordedAt) || left.entry.entryId.localeCompare(right.entry.entryId)
9604
+ ).slice(0, maxResults);
8692
9605
  recordRecallSectionMetric({
8693
9606
  section: "workProducts",
8694
9607
  priority: "core",
@@ -8862,22 +9775,50 @@ ${lines.join("\n\n")}`;
8862
9775
  }
8863
9776
  const maxPerAgent = this.config.parallelMaxResultsPerAgent;
8864
9777
  const specializedAgentPromise = !queryAwarePrefilterIsEmpty && this.config.parallelRetrievalEnabled && maxPerAgent > 0 ? Promise.all([
8865
- shouldRunAgent("direct", retrievalQuery, 0) ? runDirectAgent(
8866
- retrievalQuery,
8867
- profileStorage.dir,
8868
- maxPerAgent
8869
- ).catch((err) => {
8870
- log.debug(`DirectAgent pre-start failed: ${err}`);
8871
- return [];
9778
+ shouldRunAgent("direct", retrievalQuery, 0) ? Promise.all(
9779
+ profileStorageDirs.map(
9780
+ (memoryDir) => runDirectAgent(
9781
+ retrievalQuery,
9782
+ memoryDir,
9783
+ maxPerAgent
9784
+ ).catch((err) => {
9785
+ log.debug(`DirectAgent pre-start failed: ${err}`);
9786
+ return [];
9787
+ })
9788
+ )
9789
+ ).then((groups) => {
9790
+ const merged = [];
9791
+ const seen = /* @__PURE__ */ new Set();
9792
+ for (const result of groups.flat()) {
9793
+ const key = result.path ?? JSON.stringify(result);
9794
+ if (seen.has(key)) continue;
9795
+ seen.add(key);
9796
+ merged.push(result);
9797
+ }
9798
+ return merged.sort((a, b) => b.score - a.score).slice(0, maxPerAgent);
8872
9799
  }) : Promise.resolve([]),
8873
- shouldRunAgent("temporal", retrievalQuery, 0) ? runTemporalAgent(
8874
- retrievalQuery,
8875
- this.config.memoryDir,
8876
- maxPerAgent,
8877
- queryAwarePrefilter.candidatePaths
8878
- ).catch((err) => {
8879
- log.debug(`TemporalAgent pre-start failed: ${err}`);
8880
- return [];
9800
+ shouldRunAgent("temporal", retrievalQuery, 0) ? Promise.all(
9801
+ profileStorageDirs.map(
9802
+ (memoryDir) => runTemporalAgent(
9803
+ retrievalQuery,
9804
+ memoryDir,
9805
+ maxPerAgent,
9806
+ queryAwarePrefilter.candidatePaths
9807
+ ).catch((err) => {
9808
+ log.debug(`TemporalAgent pre-start failed for ${memoryDir}: ${err}`);
9809
+ return [];
9810
+ })
9811
+ )
9812
+ ).then((groups) => {
9813
+ const merged = [];
9814
+ const seen = /* @__PURE__ */ new Set();
9815
+ for (const result of groups.flat()) {
9816
+ const key = result.path ?? JSON.stringify(result);
9817
+ if (seen.has(key)) continue;
9818
+ seen.add(key);
9819
+ merged.push(result);
9820
+ }
9821
+ return merged.sort((a, b) => b.score - a.score).slice(0, maxPerAgent);
8881
9822
  }) : Promise.resolve([])
8882
9823
  ]) : null;
8883
9824
  try {
@@ -9070,16 +10011,16 @@ ${formatted}`;
9070
10011
  if (!this.config.compactionResetEnabled) return null;
9071
10012
  const workspaceDir = compactionWorkspaceDir || this.config.workspaceDir || defaultWorkspaceDir();
9072
10013
  const safeSessionKey = sanitizeSessionKeyForFilename(effectiveSessionKey);
9073
- const signalPath = path3.join(
10014
+ const signalPath = path4.join(
9074
10015
  workspaceDir,
9075
10016
  `.compaction-reset-signal-${safeSessionKey}`
9076
10017
  );
9077
- const bootPath = path3.join(workspaceDir, "BOOT.md");
10018
+ const bootPath = path4.join(workspaceDir, "BOOT.md");
9078
10019
  try {
9079
- const signalStat = await stat2(signalPath).catch(() => null);
10020
+ const signalStat = await stat3(signalPath).catch(() => null);
9080
10021
  if (!signalStat) return null;
9081
10022
  const signalAge = Date.now() - signalStat.mtimeMs;
9082
- const signalData = JSON.parse(await readFile3(signalPath, "utf-8"));
10023
+ const signalData = JSON.parse(await readFile4(signalPath, "utf-8"));
9083
10024
  if (signalData.sessionKey !== effectiveSessionKey) {
9084
10025
  log.debug(
9085
10026
  `recall: compaction signal is for ${signalData.sessionKey}, not ${effectiveSessionKey} \u2014 skipping`
@@ -9099,7 +10040,7 @@ ${formatted}`;
9099
10040
 
9100
10041
  `;
9101
10042
  try {
9102
- const bootContent = await readFile3(bootPath, "utf-8");
10043
+ const bootContent = await readFile4(bootPath, "utf-8");
9103
10044
  section += "### BOOT.md (working state before compaction)\n\n";
9104
10045
  section += bootContent + "\n";
9105
10046
  } catch {
@@ -9352,7 +10293,27 @@ ${formatted}`;
9352
10293
  this.isRecallSectionEnabled(
9353
10294
  "memory-boxes",
9354
10295
  this.config.memoryBoxesEnabled === true
9355
- ) && this.config.memoryBoxesEnabled && this.config.boxRecallDays > 0 ? this.boxBuilderFor(profileStorage).readRecentBoxes(this.config.boxRecallDays).catch(() => []) : Promise.resolve([])
10296
+ ) && this.config.memoryBoxesEnabled && this.config.boxRecallDays > 0 ? Promise.all(
10297
+ profileStorages.map(
10298
+ (storage) => this.boxBuilderFor(storage).readRecentBoxes(this.config.boxRecallDays).catch(() => [])
10299
+ )
10300
+ ).then((groups) => {
10301
+ const boxes = [];
10302
+ const seen = /* @__PURE__ */ new Set();
10303
+ for (const box of groups.flat()) {
10304
+ const key = JSON.stringify(box);
10305
+ if (seen.has(key)) continue;
10306
+ seen.add(key);
10307
+ boxes.push(box);
10308
+ }
10309
+ return boxes.sort((a, b) => {
10310
+ const aTime = Date.parse(a.sealedAt ?? "");
10311
+ const bTime = Date.parse(b.sealedAt ?? "");
10312
+ const aRank = Number.isFinite(aTime) ? aTime : 0;
10313
+ const bRank = Number.isFinite(bTime) ? bTime : 0;
10314
+ return bRank - aRank;
10315
+ });
10316
+ }) : Promise.resolve([])
9356
10317
  );
9357
10318
  this.profiler.startSpan("phase-1-parallel", profileTraceId);
9358
10319
  const phase1Start = Date.now();
@@ -11204,7 +12165,7 @@ _Context: ${topQuestion.context}_`
11204
12165
  const shouldUseStableBatchKey = turns.some(
11205
12166
  (turn) => turn.persistProcessedFingerprint === true || typeof turn.turnFingerprint === "string" && turn.turnFingerprint.length > 0
11206
12167
  );
11207
- const stableBatchFingerprint = shouldUseStableBatchKey ? createHash("sha256").update(
12168
+ const stableBatchFingerprint = shouldUseStableBatchKey ? createHash2("sha256").update(
11208
12169
  turns.map(
11209
12170
  (turn) => [
11210
12171
  turn.role,
@@ -11461,7 +12422,7 @@ _Context: ${topQuestion.context}_`
11461
12422
  buildExtractionFingerprint(turns, bufferKey) {
11462
12423
  const normalized = this.normalizeExtractionFingerprintTurns(turns).join("\n");
11463
12424
  if (!normalized) return null;
11464
- return createHash("sha256").update(`${bufferKey}
12425
+ return createHash2("sha256").update(`${bufferKey}
11465
12426
  ${normalized}`).digest("hex");
11466
12427
  }
11467
12428
  shouldQueueExtraction(turns, options = {}) {
@@ -11609,7 +12570,41 @@ ${normalized}`).digest("hex");
11609
12570
  };
11610
12571
  }
11611
12572
  const principal = typeof options.principalOverride === "string" && options.principalOverride.length > 0 ? options.principalOverride : resolvePrincipal(sessionKey, this.config);
11612
- const selfNamespace = typeof options.writeNamespaceOverride === "string" && options.writeNamespaceOverride.length > 0 ? options.writeNamespaceOverride : this.applyCodingNamespaceOverlay(
12573
+ const explicitWriteNamespace = typeof options.writeNamespaceOverride === "string" && options.writeNamespaceOverride.length > 0 ? options.writeNamespaceOverride : void 0;
12574
+ const codingContextForWrite = sessionKey ? this.getCodingContextForSession(sessionKey) : null;
12575
+ const codingOverlayForWrite = resolveCodingNamespaceOverlay(
12576
+ codingContextForWrite,
12577
+ this.config.codingMode,
12578
+ this.config.defaultNamespace
12579
+ );
12580
+ const scopeProfileGatePlan = resolveScopeProfilePlan({
12581
+ config: this.config,
12582
+ principal,
12583
+ codingContext: codingContextForWrite,
12584
+ codingOverlay: codingOverlayForWrite
12585
+ });
12586
+ const scopeProfileWritePlan = explicitWriteNamespace ? null : scopeProfileGatePlan;
12587
+ if (scopeProfileWritePlan) {
12588
+ const selectedLayer = scopeProfileWritePlan.layers.find(
12589
+ (layer) => layer.id === scopeProfileWritePlan.writeLayer
12590
+ );
12591
+ const writeNamespaceReadable = scopeProfileWritePlan.readNamespaces.includes(
12592
+ scopeProfileWritePlan.writeNamespace
12593
+ );
12594
+ if (!selectedLayer?.writable || !writeNamespaceReadable) {
12595
+ log.warn(
12596
+ `runExtraction: skipping scope profile ${scopeProfileWritePlan.profileId} because write layer ${scopeProfileWritePlan.writeLayer} is not writable inside the profile read stack`
12597
+ );
12598
+ await clearBuffer();
12599
+ return {
12600
+ status: "skipped",
12601
+ reason: "scope_profile_no_writable_layer",
12602
+ persistedCount: 0,
12603
+ durableOutputCount: 0
12604
+ };
12605
+ }
12606
+ }
12607
+ const selfNamespace = explicitWriteNamespace ?? scopeProfileWritePlan?.writeNamespace ?? this.applyCodingNamespaceOverlay(
11613
12608
  sessionKey,
11614
12609
  defaultNamespaceForPrincipal(principal, this.config)
11615
12610
  );
@@ -11737,7 +12732,8 @@ ${normalized}`).digest("hex");
11737
12732
  { sessionKey, principal, validAt: sourceValidAt },
11738
12733
  // Pass the KNOWN base namespace (NHIdx) so the catalog write touch records the
11739
12734
  // real namespace rather than a guess decoded from the storage dir.
11740
- selfNamespace
12735
+ selfNamespace,
12736
+ scopeProfileGatePlan
11741
12737
  );
11742
12738
  let postPersistMetadataFailed = false;
11743
12739
  meta ??= await storage.loadMeta();
@@ -11951,7 +12947,7 @@ ${normalized}`).digest("hex");
11951
12947
  );
11952
12948
  this.tierMigrationInFlight = true;
11953
12949
  try {
11954
- const coldStorage = new StorageManager(path3.join(storage.dir, "cold"));
12950
+ const coldStorage = new StorageManager(path4.join(storage.dir, "cold"));
11955
12951
  const [hotMemories, coldMemories] = await Promise.all([
11956
12952
  storage.readAllMemories(),
11957
12953
  coldStorage.readAllMemories()
@@ -12095,13 +13091,61 @@ ${normalized}`).digest("hex");
12095
13091
  this.qmdMaintenancePending = false;
12096
13092
  try {
12097
13093
  if (this.config.namespacesEnabled) {
12098
- const maintenanceNamespaces = await this.maintenanceNamespaces();
12099
- await this.namespaceSearchRouter.updateNamespaces(maintenanceNamespaces);
13094
+ const plan = await this.namespaceMaintenancePlan("qmd");
12100
13095
  const now = Date.now();
12101
- if (this.config.qmdAutoEmbedEnabled && now - this.lastQmdEmbedAtMs >= this.config.qmdEmbedMinIntervalMs) {
12102
- await this.namespaceSearchRouter.embedNamespaces(maintenanceNamespaces);
13096
+ const lastEmbedAtByNamespace = this.lastQmdEmbedAtMsByNamespace ?? (this.lastQmdEmbedAtMsByNamespace = /* @__PURE__ */ new Map());
13097
+ const dueEmbedNamespaces = (namespaces) => {
13098
+ if (!this.config.qmdAutoEmbedEnabled) return [];
13099
+ return namespaces.filter(
13100
+ (namespace) => now - (lastEmbedAtByNamespace.get(namespace) ?? 0) >= this.config.qmdEmbedMinIntervalMs
13101
+ );
13102
+ };
13103
+ const markEmbedded = (namespaces) => {
13104
+ if (namespaces.length === 0) return;
13105
+ for (const namespace of namespaces) {
13106
+ lastEmbedAtByNamespace.set(namespace, now);
13107
+ }
12103
13108
  this.lastQmdEmbedAtMs = now;
12104
- }
13109
+ };
13110
+ await runNamespaceMaintenanceBatchPlan(
13111
+ this.config,
13112
+ plan,
13113
+ async (candidates) => {
13114
+ const namespaces = candidates.map((candidate) => candidate.namespace);
13115
+ const embedNamespaces = dueEmbedNamespaces(namespaces);
13116
+ let result;
13117
+ try {
13118
+ result = await this.namespaceSearchRouter.updateNamespacesDetailed(
13119
+ namespaces,
13120
+ void 0,
13121
+ { strict: true }
13122
+ );
13123
+ } catch (error) {
13124
+ if (embedNamespaces.length > 0 && qmdMaintenanceSkipReasonForError(error) === "throttled") {
13125
+ await this.namespaceSearchRouter.embedNamespaces(embedNamespaces, { strict: true });
13126
+ markEmbedded(embedNamespaces);
13127
+ }
13128
+ throw error;
13129
+ }
13130
+ if (result.backendCount <= 0) {
13131
+ throw new Error("no eligible QMD backend for selected namespaces");
13132
+ }
13133
+ if (result.eligibleNamespaces.length !== namespaces.length) {
13134
+ const eligible = new Set(result.eligibleNamespaces);
13135
+ const missing = namespaces.filter((namespace) => !eligible.has(namespace));
13136
+ throw new Error(`QMD backend ineligible for selected namespaces (${missing.length})`);
13137
+ }
13138
+ if (embedNamespaces.length > 0) {
13139
+ await this.namespaceSearchRouter.embedNamespaces(embedNamespaces, { strict: true });
13140
+ markEmbedded(embedNamespaces);
13141
+ }
13142
+ return { itemCount: result.backendCount };
13143
+ },
13144
+ this.namespaceCatalog,
13145
+ {
13146
+ skipReasonForError: qmdMaintenanceSkipReasonForError
13147
+ }
13148
+ );
12105
13149
  } else {
12106
13150
  await this.qmd.update();
12107
13151
  const now = Date.now();
@@ -12117,7 +13161,7 @@ ${normalized}`).digest("hex");
12117
13161
  }
12118
13162
  }
12119
13163
  }
12120
- async persistExtraction(result, storage, threadIdForExtraction, sourceContext, baseNamespace) {
13164
+ async persistExtraction(result, storage, threadIdForExtraction, sourceContext, baseNamespace, scopeProfileWritePlan) {
12121
13165
  const citationEnabled = this.config.inlineSourceAttributionEnabled === true;
12122
13166
  const citationTemplate = this.config.inlineSourceAttributionFormat;
12123
13167
  const citationContextBase = citationEnabled ? {
@@ -12171,22 +13215,128 @@ ${normalized}`).digest("hex");
12171
13215
  "inferred",
12172
13216
  "speculative"
12173
13217
  ];
13218
+ const sharedProfileLayer = scopeProfileWritePlan?.layers.find(
13219
+ (layer) => layer.id === "serverShared" && layer.namespace === this.config.sharedNamespace
13220
+ );
13221
+ const sharedPromotionTarget = scopeProfileWritePlan?.promotionTargets.find(
13222
+ (target) => target.target === "serverShared" && target.namespace === this.config.sharedNamespace
13223
+ );
13224
+ const profileAllowsSharedWrites = !scopeProfileWritePlan || Boolean(
13225
+ scopeProfileWritePlan.profile.readOrder.includes("serverShared") && scopeProfileWritePlan.readNamespaces.includes(this.config.sharedNamespace) && sharedProfileLayer?.readable && sharedProfileLayer.writable && sharedPromotionTarget?.authorized
13226
+ );
13227
+ const profileAutoPromotionAllows = (category, confidence) => {
13228
+ if (!scopeProfileWritePlan) return false;
13229
+ const actualTier = confidenceTier(confidence);
13230
+ const actualRank = confidenceTierOrder.indexOf(actualTier);
13231
+ if (actualRank === -1) return false;
13232
+ const autoPromote = scopeProfileWritePlan.profile.autoPromote;
13233
+ if (!autoPromote.enabled) return false;
13234
+ if (!autoPromote.categories.includes(category)) return false;
13235
+ const minimumRank = confidenceTierOrder.indexOf(autoPromote.minConfidenceTier);
13236
+ return minimumRank !== -1 && actualRank <= minimumRank;
13237
+ };
13238
+ const sharedAutoPromotionAllows = (category, confidence) => {
13239
+ if (!scopeProfileWritePlan) {
13240
+ const actualTier = confidenceTier(confidence);
13241
+ const actualRank = confidenceTierOrder.indexOf(actualTier);
13242
+ if (actualRank === -1) return false;
13243
+ if (!this.config.autoPromoteToSharedEnabled) return false;
13244
+ if (!this.config.autoPromoteToSharedCategories.includes(category))
13245
+ return false;
13246
+ const minimumRank = confidenceTierOrder.indexOf(
13247
+ this.config.autoPromoteMinConfidenceTier
13248
+ );
13249
+ return minimumRank !== -1 && actualRank <= minimumRank;
13250
+ }
13251
+ return scopeProfileWritePlan.profile.autoPromote.targets.includes("serverShared") && profileAutoPromotionAllows(category, confidence);
13252
+ };
12174
13253
  const shouldPromoteToShared = (targetStorage, category, confidence) => {
12175
- if (!this.config.namespacesEnabled || !this.config.autoPromoteToSharedEnabled)
13254
+ if (!this.config.namespacesEnabled || !profileAllowsSharedWrites || !sharedAutoPromotionAllows(category, confidence))
12176
13255
  return false;
12177
13256
  if (this.namespaceFromStorageDir(targetStorage.dir) === this.config.sharedNamespace)
12178
13257
  return false;
12179
- if (!this.config.autoPromoteToSharedCategories.includes(category))
12180
- return false;
12181
- const actualTier = confidenceTier(confidence);
12182
- const actualRank = confidenceTierOrder.indexOf(actualTier);
12183
- const minimumRank = confidenceTierOrder.indexOf(
12184
- this.config.autoPromoteMinConfidenceTier
13258
+ return true;
13259
+ };
13260
+ const promoteMemoryToProfileTargets = async (options) => {
13261
+ if (!scopeProfileWritePlan || !profileAutoPromotionAllows(options.category, options.confidence))
13262
+ return;
13263
+ const autoTargets = new Set(scopeProfileWritePlan.profile.autoPromote.targets);
13264
+ const targets = scopeProfileWritePlan.promotionTargets.filter(
13265
+ (target) => target.target !== "serverShared" && autoTargets.has(target.target) && target.authorized && target.namespace
12185
13266
  );
12186
- if (actualRank === -1 || minimumRank === -1) return false;
12187
- return actualRank <= minimumRank;
13267
+ if (targets.length === 0) return;
13268
+ const rawContent = citationEnabled && hasCitationForTemplate(options.content, citationTemplate) ? stripCitationForTemplate(options.content, citationTemplate) : options.content;
13269
+ const citedContent = applyInlineCitation(rawContent);
13270
+ const sanitizedBase = sanitizeMemoryContent(rawContent);
13271
+ const dedupContent = options.category === "fact" && options.structuredAttributes && Object.keys(options.structuredAttributes).length > 0 ? `${sanitizedBase.text}
13272
+ [Attributes: ${normalizeAttributePairs(options.structuredAttributes)}]` : sanitizedBase.text;
13273
+ for (const target of targets) {
13274
+ if (!target.namespace) continue;
13275
+ try {
13276
+ const targetStorage = await this.storageRouter.storageFor(target.namespace);
13277
+ if (targetStorage.dir === options.sourceStorage.dir) continue;
13278
+ if (options.category === "fact" && await targetStorage.hasFactContentHash(dedupContent)) {
13279
+ continue;
13280
+ }
13281
+ const promotedId = await targetStorage.writeMemory(
13282
+ options.category,
13283
+ citedContent,
13284
+ {
13285
+ confidence: options.confidence,
13286
+ tags: [...options.tags, `${target.target}-promotion`],
13287
+ entityRef: options.entityRef,
13288
+ structuredAttributes: options.structuredAttributes,
13289
+ source: `${options.source}-${target.target}-promotion`,
13290
+ importance: options.importance,
13291
+ lineage: [options.sourceMemoryId],
13292
+ sourceMemoryId: options.sourceMemoryId,
13293
+ intentGoal: options.intentGoal,
13294
+ intentActionType: options.intentActionType,
13295
+ intentEntityTypes: options.intentEntityTypes,
13296
+ memoryKind: options.memoryKind,
13297
+ validAt: options.validAt,
13298
+ contentHashSource: options.category === "fact" ? dedupContent : rawContent
13299
+ }
13300
+ );
13301
+ if (this.config.temporalSupersessionEnabled && options.category === "fact" && options.entityRef && options.structuredAttributes && Object.keys(options.structuredAttributes).length > 0) {
13302
+ try {
13303
+ await applyTemporalSupersession({
13304
+ storage: targetStorage,
13305
+ newMemoryId: promotedId,
13306
+ entityRef: options.entityRef,
13307
+ structuredAttributes: options.structuredAttributes,
13308
+ createdAt: supersessionOrderingAt(options.validAt),
13309
+ enabled: true
13310
+ });
13311
+ } catch (profileSupersessionErr) {
13312
+ log.warn(
13313
+ `persistExtraction: ${target.target} promotion temporal supersession failed open for promoted ${promotedId}: ${profileSupersessionErr}`
13314
+ );
13315
+ }
13316
+ }
13317
+ this.markCatalogWrite(target.namespace, targetStorage.dir);
13318
+ trackPersistedId(targetStorage, promotedId, { includeReturnedIds: false });
13319
+ await this.indexPersistedMemory(targetStorage, promotedId);
13320
+ trackBehaviorSignals(
13321
+ targetStorage,
13322
+ buildBehaviorSignalsForMemory({
13323
+ memoryId: promotedId,
13324
+ category: options.category,
13325
+ content: options.content,
13326
+ namespace: target.namespace,
13327
+ confidence: options.confidence,
13328
+ source: "extraction"
13329
+ })
13330
+ );
13331
+ } catch (err) {
13332
+ log.warn(
13333
+ `persistExtraction: ${target.target} promotion failed open for ${options.sourceMemoryId}: ${err}`
13334
+ );
13335
+ }
13336
+ }
12188
13337
  };
12189
13338
  const promoteMemoryToShared = async (options) => {
13339
+ await promoteMemoryToProfileTargets(options);
12190
13340
  if (!shouldPromoteToShared(
12191
13341
  options.sourceStorage,
12192
13342
  options.category,
@@ -12273,11 +13423,10 @@ ${normalized}`).digest("hex");
12273
13423
  intentEntityTypes: options.intentEntityTypes,
12274
13424
  memoryKind: options.memoryKind,
12275
13425
  validAt: options.validAt,
12276
- // Index the RAW content hash so hasFactContentHash(rawContent)
12277
- // returns true on subsequent extractions. Without this, the index
12278
- // would record the hash of citedContent (which changes every call
12279
- // due to an updated timestamp), causing duplicate promotions.
12280
- contentHashSource: rawContent
13426
+ // Index the same canonical body used by hasFactContentHash above.
13427
+ // For structured facts this includes the normalized Attributes
13428
+ // suffix, matching StorageManager.writeMemory enrichment.
13429
+ contentHashSource: options.category === "fact" ? dedupContent : rawContent
12281
13430
  }
12282
13431
  );
12283
13432
  if (this.config.temporalSupersessionEnabled && options.entityRef && options.structuredAttributes && Object.keys(options.structuredAttributes).length > 0) {
@@ -12551,7 +13700,7 @@ ${normalized}`).digest("hex");
12551
13700
  }
12552
13701
  if (this.config.extractionScopeClassificationEnabled && this.config.namespacesEnabled && fact.scope === "global" && !routedNamespaceExplicit) {
12553
13702
  const currentNs = this.namespaceFromStorageDir(targetStorage.dir);
12554
- if (currentNs !== this.config.sharedNamespace) {
13703
+ if (currentNs !== this.config.sharedNamespace && profileAllowsSharedWrites) {
12555
13704
  try {
12556
13705
  targetStorage = await this.storageRouter.storageFor(
12557
13706
  this.config.sharedNamespace
@@ -12565,13 +13714,28 @@ ${normalized}`).digest("hex");
12565
13714
  `scope-routing: failed to resolve shared namespace storage; writing to session namespace (fail-open): ${scopeRouteErr}`
12566
13715
  );
12567
13716
  }
13717
+ } else if (currentNs !== this.config.sharedNamespace) {
13718
+ log.debug(
13719
+ `scope-routing: skipped shared namespace for global fact because active scope profile ${scopeProfileWritePlan?.profileId ?? "none"} does not authorize serverShared writes`
13720
+ );
12568
13721
  }
12569
13722
  }
12570
13723
  const canonicalContentForHash = citationEnabled && hasCitationForTemplate(fact.content, citationTemplate) ? stripCitationForTemplate(fact.content, citationTemplate) : fact.content;
12571
13724
  const contentHashDedupKey = writeCategory === "procedure" ? buildProcedurePersistBody(fact.content, fact.procedureSteps) : canonicalContentForHash;
12572
- if (this.contentHashIndex && this.contentHashIndex.has(contentHashDedupKey)) {
13725
+ let exactDuplicate = false;
13726
+ try {
13727
+ exactDuplicate = await this.hasContentHashDedup(
13728
+ targetStorage,
13729
+ contentHashDedupKey
13730
+ );
13731
+ } catch (err) {
13732
+ log.warn(
13733
+ `content-hash dedup lookup failed for storage ${targetStorage.dir}; writing fact fail-open: ${err}`
13734
+ );
13735
+ }
13736
+ if (exactDuplicate) {
12573
13737
  log.debug(
12574
- `dedup: skipping duplicate fact "${fact.content.slice(0, 60)}\u2026"`
13738
+ `dedup: skipping duplicate fact "${fact.content.slice(0, 60)}\u2026" in storage ${targetStorage.dir}`
12575
13739
  );
12576
13740
  dedupedCount++;
12577
13741
  continue;
@@ -12834,9 +13998,13 @@ ${normalized}`).digest("hex");
12834
13998
  validAt: sourceContext?.validAt,
12835
13999
  source: extractionWriteSource
12836
14000
  });
12837
- if (this.contentHashIndex) {
14001
+ try {
12838
14002
  const canonicalChunkedContent = citationEnabled && hasCitationForTemplate(fact.content, citationTemplate) ? stripCitationForTemplate(fact.content, citationTemplate) : fact.content;
12839
- this.contentHashIndex.add(canonicalChunkedContent);
14003
+ await this.addContentHashDedup(targetStorage, canonicalChunkedContent);
14004
+ } catch (err) {
14005
+ log.warn(
14006
+ `content-hash dedup registration failed for chunked memory ${parentId}: ${err}`
14007
+ );
12840
14008
  }
12841
14009
  for (const chunk of chunkResult.chunks) {
12842
14010
  const chunkId = `${parentId}-chunk-${chunk.index}`;
@@ -13038,10 +14206,14 @@ ${normalized}`).digest("hex");
13038
14206
  intentEntityTypes: inferredIntent?.entityTypes
13039
14207
  });
13040
14208
  }
13041
- if (this.contentHashIndex) {
14209
+ try {
13042
14210
  const canonicalFactContent = citationEnabled && hasCitationForTemplate(fact.content, citationTemplate) ? stripCitationForTemplate(fact.content, citationTemplate) : fact.content;
13043
14211
  const hashRegisterKey = writeCategory === "procedure" ? buildProcedurePersistBody(fact.content, fact.procedureSteps) : canonicalFactContent;
13044
- this.contentHashIndex.add(hashRegisterKey);
14212
+ await this.addContentHashDedup(targetStorage, hashRegisterKey);
14213
+ } catch (err) {
14214
+ log.warn(
14215
+ `content-hash dedup registration failed for memory ${memoryId}: ${err}`
14216
+ );
13045
14217
  }
13046
14218
  } finally {
13047
14219
  this.markCatalogWrite(targetNamespaceName, targetStorage.dir);
@@ -13141,9 +14313,9 @@ ${normalized}`).digest("hex");
13141
14313
  if (durableNonFactWritten) {
13142
14314
  touchBaseNonFactNamespace();
13143
14315
  }
13144
- if (this.contentHashIndex) {
13145
- await this.contentHashIndex.save().catch((err) => log.warn(`content-hash index save failed: ${err}`));
13146
- }
14316
+ await this.saveContentHashIndexes().catch(
14317
+ (err) => log.warn(`content-hash index save failed: ${err}`)
14318
+ );
13147
14319
  for (const {
13148
14320
  storage: targetStorage,
13149
14321
  events
@@ -13196,7 +14368,7 @@ ${normalized}`).digest("hex");
13196
14368
  const allMems = allMemsForGraph ?? [];
13197
14369
  for (const m of allMems) {
13198
14370
  if (m.frontmatter.entityRef === entityRef) {
13199
- const rel = path3.relative(storage.dir, m.path);
14371
+ const rel = path4.relative(storage.dir, m.path);
13200
14372
  if (rel !== memoryRelPath) entitySiblings.push(rel);
13201
14373
  }
13202
14374
  }
@@ -13512,14 +14684,14 @@ ${normalized}`).digest("hex");
13512
14684
  }
13513
14685
  if (this.config.semanticConsolidationEnabled) {
13514
14686
  try {
13515
- const stateFilePath = path3.join(
14687
+ const stateFilePath = path4.join(
13516
14688
  this.config.memoryDir,
13517
14689
  "state",
13518
14690
  "semantic-consolidation-last-run.json"
13519
14691
  );
13520
14692
  let shouldRun = true;
13521
14693
  try {
13522
- const stateRaw = await readFile3(stateFilePath, "utf-8");
14694
+ const stateRaw = await readFile4(stateFilePath, "utf-8");
13523
14695
  const stateData = JSON.parse(stateRaw);
13524
14696
  if (stateData.lastRunAt) {
13525
14697
  const lastRunMs = new Date(stateData.lastRunAt).getTime();
@@ -13560,9 +14732,9 @@ ${normalized}`).digest("hex");
13560
14732
  );
13561
14733
  }
13562
14734
  if (semResult.errors === 0 || semResult.memoriesArchived > 0) {
13563
- const stateDir = path3.join(this.config.memoryDir, "state");
13564
- await mkdir3(stateDir, { recursive: true });
13565
- await writeFile3(
14735
+ const stateDir = path4.join(this.config.memoryDir, "state");
14736
+ await mkdir4(stateDir, { recursive: true });
14737
+ await writeFile4(
13566
14738
  stateFilePath,
13567
14739
  JSON.stringify({ lastRunAt: (/* @__PURE__ */ new Date()).toISOString() }),
13568
14740
  "utf-8"
@@ -13761,7 +14933,7 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
13761
14933
  }
13762
14934
  });
13763
14935
  const content = renderCompressionGuidelinesMarkdown(refinedCandidate);
13764
- const contentHash = createHash("sha256").update(content).digest("hex");
14936
+ const contentHash = createHash2("sha256").update(content).digest("hex");
13765
14937
  const semanticRefinementApplied = JSON.stringify(refinedCandidate.ruleUpdates) !== JSON.stringify(candidate.ruleUpdates);
13766
14938
  const changedRules = refinedCandidate.ruleUpdates.filter(
13767
14939
  (rule) => rule.delta !== 0
@@ -14064,13 +15236,13 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
14064
15236
  protectedCategories: this.config.lifecycleProtectedCategories
14065
15237
  }
14066
15238
  };
14067
- const metricsPath = path3.join(
15239
+ const metricsPath = path4.join(
14068
15240
  storage.dir,
14069
15241
  "state",
14070
15242
  "lifecycle-metrics.json"
14071
15243
  );
14072
- await mkdir3(path3.dirname(metricsPath), { recursive: true });
14073
- await writeFile3(metricsPath, JSON.stringify(metrics, null, 2), "utf-8");
15244
+ await mkdir4(path4.dirname(metricsPath), { recursive: true });
15245
+ await writeFile4(metricsPath, JSON.stringify(metrics, null, 2), "utf-8");
14074
15246
  return updatedCount;
14075
15247
  }
14076
15248
  /**
@@ -14098,16 +15270,11 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
14098
15270
  if (accessCount > this.config.factArchivalMaxAccessCount) continue;
14099
15271
  const result = await this.storage.archiveMemory(memory);
14100
15272
  if (result) {
14101
- if (this.contentHashIndex) {
14102
- if (memory.frontmatter.contentHash) {
14103
- this.contentHashIndex.removeByHash(memory.frontmatter.contentHash);
14104
- } else {
14105
- log.warn(
14106
- `[fact-archival] removing hash for legacy memory ${memory.frontmatter.id ?? "(unknown)"} via content fallback \u2014 no contentHash in frontmatter`
14107
- );
14108
- this.contentHashIndex.remove(memory.content);
14109
- }
14110
- }
15273
+ await this.removeContentHashForMemory(
15274
+ this.storage,
15275
+ memory,
15276
+ "fact-archival"
15277
+ );
14111
15278
  await this.embeddingFallback.removeFromIndex(memory.frontmatter.id);
14112
15279
  if (this.config.queryAwareIndexingEnabled && memory.path && memory.frontmatter?.created) {
14113
15280
  deindexMemory(
@@ -14120,8 +15287,8 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
14120
15287
  archivedCount++;
14121
15288
  }
14122
15289
  }
14123
- if (archivedCount > 0 && this.contentHashIndex) {
14124
- await this.contentHashIndex.save().catch(
15290
+ if (archivedCount > 0) {
15291
+ await this.saveContentHashIndexes().catch(
14125
15292
  (err) => log.warn(`content-hash index save failed during archival: ${err}`)
14126
15293
  );
14127
15294
  }
@@ -14603,7 +15770,7 @@ ${lines.join("\n\n")}`;
14603
15770
  const seenStorageDirs = /* @__PURE__ */ new Set();
14604
15771
  const addStorage = (storage) => {
14605
15772
  const storageDir = storageDirFor(storage);
14606
- const storageKey = storageDir ? path3.resolve(storageDir) : `storage-without-dir-${storages.length}`;
15773
+ const storageKey = storageDir ? path4.resolve(storageDir) : `storage-without-dir-${storages.length}`;
14607
15774
  if (seenStorageDirs.has(storageKey)) return;
14608
15775
  seenStorageDirs.add(storageKey);
14609
15776
  storages.push(storage);
@@ -14633,7 +15800,7 @@ ${lines.join("\n\n")}`;
14633
15800
  continue;
14634
15801
  }
14635
15802
  try {
14636
- const coldRoot = path3.join(storageDir, "cold");
15803
+ const coldRoot = path4.join(storageDir, "cold");
14637
15804
  for (const candidate of qmdResultPathCandidates(
14638
15805
  coldRoot,
14639
15806
  parts.relativePath
@@ -14674,7 +15841,7 @@ ${lines.join("\n\n")}`;
14674
15841
  return null;
14675
15842
  }
14676
15843
  }
14677
- if (path3.isAbsolute(resultPath)) {
15844
+ if (path4.isAbsolute(resultPath)) {
14678
15845
  if (!fallbackStorageDir) {
14679
15846
  return await fallbackStorage.readMemoryByPath(resultPath);
14680
15847
  }
@@ -14713,7 +15880,7 @@ ${lines.join("\n\n")}`;
14713
15880
  );
14714
15881
  if (!memory) return null;
14715
15882
  let ownerNamespace = null;
14716
- if (path3.isAbsolute(memory.path)) {
15883
+ if (path4.isAbsolute(memory.path)) {
14717
15884
  const ownerStorage = await this.storageForAbsoluteQmdResultPath(
14718
15885
  memory.path,
14719
15886
  fallbackStorage,
@@ -14737,16 +15904,16 @@ ${lines.join("\n\n")}`;
14737
15904
  };
14738
15905
  }
14739
15906
  async storageForAbsoluteQmdResultPath(resultPath, fallbackStorage, recallNamespaces = []) {
14740
- const resolvedPath = path3.resolve(resultPath);
14741
- const memoryRoot = path3.resolve(this.config.memoryDir);
14742
- const namespacesRoot = path3.join(memoryRoot, "namespaces");
15907
+ const resolvedPath = path4.resolve(resultPath);
15908
+ const memoryRoot = path4.resolve(this.config.memoryDir);
15909
+ const namespacesRoot = path4.join(memoryRoot, "namespaces");
14743
15910
  const fallbackStorageDir = typeof fallbackStorage.dir === "string" && fallbackStorage.dir ? fallbackStorage.dir : null;
14744
15911
  const matches = [];
14745
15912
  const seenDirs = /* @__PURE__ */ new Set();
14746
15913
  const maybeAddStorage = (storage, namespace) => {
14747
15914
  const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
14748
15915
  if (!storageDir) return;
14749
- const candidateRoot = path3.resolve(storageDir);
15916
+ const candidateRoot = path4.resolve(storageDir);
14750
15917
  if (seenDirs.has(candidateRoot)) return;
14751
15918
  if (!isPathInsideStorageRoot(candidateRoot, resolvedPath)) return;
14752
15919
  if (candidateRoot === memoryRoot && isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
@@ -14764,7 +15931,7 @@ ${lines.join("\n\n")}`;
14764
15931
  candidateNamespaces.add(ns);
14765
15932
  }
14766
15933
  if (isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
14767
- const relativeToNamespaces = path3.relative(namespacesRoot, resolvedPath);
15934
+ const relativeToNamespaces = path4.relative(namespacesRoot, resolvedPath);
14768
15935
  const [namespaceSegment] = relativeToNamespaces.split(/[\\/]/);
14769
15936
  if (namespaceSegment) {
14770
15937
  candidateNamespaces.add(
@@ -14809,7 +15976,7 @@ ${lines.join("\n\n")}`;
14809
15976
  nsMap = buildMemoryWorthCounterMap(memories);
14810
15977
  this.memoryWorthCounterCache.set(ns, { at: nowMs, counters: nsMap });
14811
15978
  }
14812
- for (const [path4, c] of nsMap) counters.set(path4, c);
15979
+ for (const [path5, c] of nsMap) counters.set(path5, c);
14813
15980
  } catch (err) {
14814
15981
  log.debug("memory-worth: failed to read namespace, skipping", {
14815
15982
  namespace: ns,
@@ -14980,12 +16147,12 @@ ${lines.join("\n\n")}`;
14980
16147
  */
14981
16148
  semanticDedupScopeFor(targetStorage) {
14982
16149
  if (!this.config.namespacesEnabled) return {};
14983
- const memoryDir = path3.resolve(this.config.memoryDir);
14984
- const storageDir = path3.resolve(targetStorage.dir);
16150
+ const memoryDir = path4.resolve(this.config.memoryDir);
16151
+ const storageDir = path4.resolve(targetStorage.dir);
14985
16152
  if (storageDir === memoryDir) {
14986
16153
  return { pathExcludePrefixes: ["namespaces/"] };
14987
16154
  }
14988
- let rel = path3.relative(memoryDir, storageDir);
16155
+ let rel = path4.relative(memoryDir, storageDir);
14989
16156
  if (!rel || rel.startsWith("..")) {
14990
16157
  log.debug(
14991
16158
  `semantic dedup: target storage dir ${storageDir} is outside memoryDir ${memoryDir}; scoping lookup to absolute path prefix`
@@ -15004,7 +16171,7 @@ ${lines.join("\n\n")}`;
15004
16171
  if (hits.length === 0) return [];
15005
16172
  const results = [];
15006
16173
  for (const hit of hits) {
15007
- const fullPath = path3.isAbsolute(hit.path) ? hit.path : path3.join(this.config.memoryDir, hit.path);
16174
+ const fullPath = path4.isAbsolute(hit.path) ? hit.path : path4.join(this.config.memoryDir, hit.path);
15008
16175
  const memory = await this.storage.readMemoryByPath(fullPath);
15009
16176
  if (!memory) continue;
15010
16177
  results.push({
@@ -15179,7 +16346,7 @@ ${lines.join("\n\n")}`;
15179
16346
  const storage = await this.storageRouter.storageFor(namespace);
15180
16347
  const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
15181
16348
  if (!storageDir) continue;
15182
- const recallRoot = path3.resolve(storageDir);
16349
+ const recallRoot = path4.resolve(storageDir);
15183
16350
  if (seenRecallRoots.has(recallRoot)) continue;
15184
16351
  seenRecallRoots.add(recallRoot);
15185
16352
  recallRoots.push(recallRoot);
@@ -15203,8 +16370,8 @@ ${lines.join("\n\n")}`;
15203
16370
  if (resolvedCold) scopedResults.push(resolvedCold.result);
15204
16371
  continue;
15205
16372
  }
15206
- if (path3.isAbsolute(result.path)) {
15207
- const resolvedPath = path3.resolve(result.path);
16373
+ if (path4.isAbsolute(result.path)) {
16374
+ const resolvedPath = path4.resolve(result.path);
15208
16375
  if (recallRoots.some(
15209
16376
  (recallRoot) => isPathInsideStorageRoot(recallRoot, resolvedPath)
15210
16377
  )) {
@@ -15945,8 +17112,8 @@ ${lines.join("\n\n")}`;
15945
17112
  }
15946
17113
  namespaceFromStorageDir(storageDir) {
15947
17114
  if (!this.config.namespacesEnabled) return this.config.defaultNamespace;
15948
- const resolvedStorageDir = path3.resolve(storageDir);
15949
- const resolvedMemoryDir = path3.resolve(this.config.memoryDir);
17115
+ const resolvedStorageDir = path4.resolve(storageDir);
17116
+ const resolvedMemoryDir = path4.resolve(this.config.memoryDir);
15950
17117
  if (resolvedStorageDir === resolvedMemoryDir)
15951
17118
  return this.config.defaultNamespace;
15952
17119
  const m = resolvedStorageDir.match(/[\\/]namespaces[\\/]([^\\/]+)$/);
@@ -16076,4 +17243,4 @@ export {
16076
17243
  resolvePersistedMemoryRelativePath,
16077
17244
  Orchestrator
16078
17245
  };
16079
- //# sourceMappingURL=chunk-OL2364SB.js.map
17246
+ //# sourceMappingURL=chunk-RDW5G6DO.js.map