@remnic/core 9.3.654 → 9.3.655

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 (246) hide show
  1. package/dist/access-cli.js +23 -23
  2. package/dist/access-http.d.ts +4 -4
  3. package/dist/access-http.js +16 -16
  4. package/dist/access-mcp.d.ts +4 -4
  5. package/dist/access-mcp.js +15 -15
  6. package/dist/{access-service-C8A5hoXJ.d.ts → access-service-BEJvriUt.d.ts} +2 -2
  7. package/dist/access-service.d.ts +4 -4
  8. package/dist/access-service.js +14 -14
  9. package/dist/action-confidence.d.ts +1 -1
  10. package/dist/active-memory-bridge.d.ts +1 -1
  11. package/dist/active-recall.d.ts +1 -1
  12. package/dist/active-recall.js +1 -1
  13. package/dist/behavior-learner.d.ts +1 -1
  14. package/dist/behavior-signals.d.ts +1 -1
  15. package/dist/bootstrap.d.ts +3 -3
  16. package/dist/briefing.d.ts +1 -1
  17. package/dist/briefing.js +3 -3
  18. package/dist/buffer-surprise-report.d.ts +1 -1
  19. package/dist/buffer.d.ts +1 -1
  20. package/dist/calibration.d.ts +1 -1
  21. package/dist/causal-behavior.d.ts +1 -1
  22. package/dist/causal-consolidation.d.ts +1 -1
  23. package/dist/causal-consolidation.js +4 -4
  24. package/dist/{chunk-BP2EV6W5.js → chunk-2RCGZ67B.js} +4 -4
  25. package/dist/{chunk-FVRBLJP6.js → chunk-54LOUIBE.js} +2 -2
  26. package/dist/{chunk-LJCEWTG3.js → chunk-55ZMNKMQ.js} +8 -8
  27. package/dist/{chunk-7WEB3FLJ.js → chunk-5PLUC5OB.js} +2 -2
  28. package/dist/{chunk-OL2364SB.js → chunk-5QD3QD76.js} +854 -223
  29. package/dist/chunk-5QD3QD76.js.map +1 -0
  30. package/dist/{chunk-DBM2BD22.js → chunk-67G4T7KI.js} +3 -3
  31. package/dist/{chunk-JX2RINDR.js → chunk-6G5JEN55.js} +2 -2
  32. package/dist/{chunk-2DSTAWNZ.js → chunk-A3Y37UWI.js} +3 -3
  33. package/dist/{chunk-T2C6QJG2.js → chunk-BGKXTVNG.js} +2 -2
  34. package/dist/{chunk-JYN7QNTA.js → chunk-COVZLGMR.js} +17 -17
  35. package/dist/{chunk-JVRPJ7D4.js → chunk-EKQMQQ3U.js} +48 -12
  36. package/dist/chunk-EKQMQQ3U.js.map +1 -0
  37. package/dist/{chunk-JBHXMCYN.js → chunk-GRYAECRV.js} +2 -2
  38. package/dist/{chunk-RGPUQ66K.js → chunk-IQ53ZSXV.js} +2 -2
  39. package/dist/{chunk-YLZLPVKK.js → chunk-KOI765XP.js} +104 -1
  40. package/dist/chunk-KOI765XP.js.map +1 -0
  41. package/dist/{chunk-QW6JZO5P.js → chunk-KZZ4YAEC.js} +2 -2
  42. package/dist/{chunk-2DGQLOOM.js → chunk-M3VYPE2H.js} +1 -1
  43. package/dist/{chunk-2DGQLOOM.js.map → chunk-M3VYPE2H.js.map} +1 -1
  44. package/dist/{chunk-QKK64Z6M.js → chunk-NCSJKK23.js} +2 -2
  45. package/dist/{chunk-NCGWXCSW.js → chunk-NRBGRZW4.js} +2 -2
  46. package/dist/{chunk-GPW2E4LN.js → chunk-OKW6F5S5.js} +3 -3
  47. package/dist/{chunk-Y2RIIF6H.js → chunk-PTMJ2FH2.js} +2 -2
  48. package/dist/{chunk-JMQSYGXS.js → chunk-PVE7KSQP.js} +2 -2
  49. package/dist/{chunk-NAZWHTYV.js → chunk-QDVQ4AN2.js} +4 -4
  50. package/dist/{chunk-PYWNNF2I.js → chunk-QRSKPI62.js} +99 -66
  51. package/dist/chunk-QRSKPI62.js.map +1 -0
  52. package/dist/{chunk-YM3LR4LS.js → chunk-SSSXWIBP.js} +5 -5
  53. package/dist/{chunk-NE2JBMLN.js → chunk-TDZSSJV4.js} +1 -1
  54. package/dist/chunk-TDZSSJV4.js.map +1 -0
  55. package/dist/{chunk-6CVI6BP6.js → chunk-TEO46GMM.js} +2 -2
  56. package/dist/{chunk-K6X553JB.js → chunk-UCEABZZN.js} +2 -2
  57. package/dist/{chunk-ENV6RDTD.js → chunk-UCEDY5M7.js} +2 -2
  58. package/dist/{chunk-ZCORQM74.js → chunk-UYNFWZWG.js} +2 -2
  59. package/dist/{chunk-XWQ6ERUG.js → chunk-WDTUYOLS.js} +2 -2
  60. package/dist/{chunk-Z5MQI7K2.js → chunk-XOFXKASO.js} +2 -2
  61. package/dist/{chunk-3RACUBII.js → chunk-XRKQOQLY.js} +2 -2
  62. package/dist/{chunk-BJA6DQOC.js → chunk-YYN3LIYA.js} +5 -5
  63. package/dist/{cli-uQgvDFNE.d.ts → cli-BGahB_d3.d.ts} +3 -3
  64. package/dist/cli.d.ts +5 -5
  65. package/dist/cli.js +28 -28
  66. package/dist/compounding/engine.d.ts +1 -1
  67. package/dist/compounding/engine.js +3 -3
  68. package/dist/compounding/preference-consolidator.d.ts +1 -1
  69. package/dist/compression-optimizer.d.ts +1 -1
  70. package/dist/config.d.ts +1 -1
  71. package/dist/config.js +1 -1
  72. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  73. package/dist/connectors/codex-materialize-runner.js +3 -3
  74. package/dist/connectors/codex-materialize.d.ts +1 -1
  75. package/dist/connectors/index.d.ts +1 -1
  76. package/dist/connectors/index.js +3 -3
  77. package/dist/consolidation-provenance-check.d.ts +1 -1
  78. package/dist/consolidation-undo.d.ts +1 -1
  79. package/dist/contradiction/index.d.ts +1 -1
  80. package/dist/conversation-index/backend.d.ts +1 -1
  81. package/dist/conversation-index/chunker.d.ts +1 -1
  82. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  83. package/dist/conversation-index/indexer.d.ts +1 -1
  84. package/dist/conversation-index/search.d.ts +1 -1
  85. package/dist/day-summary.d.ts +1 -1
  86. package/dist/delinearize.d.ts +1 -1
  87. package/dist/direct-answer-wiring.d.ts +1 -1
  88. package/dist/direct-answer.d.ts +1 -1
  89. package/dist/embedding-fallback.d.ts +1 -1
  90. package/dist/enrichment/index.d.ts +1 -1
  91. package/dist/entity-retrieval.d.ts +1 -1
  92. package/dist/entity-retrieval.js +3 -3
  93. package/dist/entity-schema.d.ts +1 -1
  94. package/dist/explicit-capture.d.ts +3 -3
  95. package/dist/extraction-judge-telemetry.d.ts +1 -1
  96. package/dist/extraction-judge-training.d.ts +1 -1
  97. package/dist/extraction-judge.d.ts +1 -1
  98. package/dist/extraction.d.ts +1 -1
  99. package/dist/fallback-llm.d.ts +1 -1
  100. package/dist/identity-continuity.d.ts +1 -1
  101. package/dist/importance.d.ts +1 -1
  102. package/dist/index.d.ts +8 -8
  103. package/dist/index.js +33 -33
  104. package/dist/intent.d.ts +1 -1
  105. package/dist/lcm/engine.d.ts +1 -1
  106. package/dist/lcm/index.d.ts +1 -1
  107. package/dist/lcm/tools.d.ts +1 -1
  108. package/dist/lifecycle.d.ts +1 -1
  109. package/dist/live-connectors-runner.d.ts +1 -1
  110. package/dist/local-llm.d.ts +1 -1
  111. package/dist/maintenance/memory-governance.d.ts +1 -1
  112. package/dist/maintenance/memory-governance.js +3 -3
  113. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  114. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  115. package/dist/mcp-memory-inspector-app.d.ts +4 -4
  116. package/dist/memory-action-policy.d.ts +1 -1
  117. package/dist/memory-cache.d.ts +1 -1
  118. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  119. package/dist/memory-projection-store.d.ts +1 -1
  120. package/dist/memory-provenance.d.ts +1 -1
  121. package/dist/memory-worth-outcomes.d.ts +1 -1
  122. package/dist/models-json.d.ts +1 -1
  123. package/dist/namespaces/migrate.d.ts +1 -1
  124. package/dist/namespaces/migrate.js +11 -11
  125. package/dist/namespaces/principal.d.ts +1 -1
  126. package/dist/namespaces/search.d.ts +15 -4
  127. package/dist/namespaces/search.js +7 -7
  128. package/dist/namespaces/storage.d.ts +1 -1
  129. package/dist/namespaces/storage.js +3 -3
  130. package/dist/native-knowledge.d.ts +1 -1
  131. package/dist/operator-toolkit.d.ts +1 -1
  132. package/dist/operator-toolkit.js +14 -14
  133. package/dist/{orchestrator-B4Y4sWQH.d.ts → orchestrator-BgzZlWxH.d.ts} +11 -14
  134. package/dist/orchestrator.d.ts +3 -3
  135. package/dist/orchestrator.js +19 -19
  136. package/dist/patterns-cli.d.ts +1 -1
  137. package/dist/policy-runtime.d.ts +1 -1
  138. package/dist/qmd-recall-cache.d.ts +1 -1
  139. package/dist/qmd.d.ts +5 -1
  140. package/dist/qmd.js +2 -2
  141. package/dist/recall-disclosure-escalation.d.ts +1 -1
  142. package/dist/recall-explain-renderer.d.ts +1 -1
  143. package/dist/recall-explain-renderer.js +3 -3
  144. package/dist/recall-planner-llm.d.ts +1 -1
  145. package/dist/recall-state.d.ts +1 -1
  146. package/dist/recall-tag-filter.d.ts +1 -1
  147. package/dist/recall-xray-cli.d.ts +1 -1
  148. package/dist/recall-xray-cli.js +4 -4
  149. package/dist/recall-xray-renderer.d.ts +1 -1
  150. package/dist/recall-xray-renderer.js +3 -3
  151. package/dist/recall-xray.d.ts +1 -1
  152. package/dist/recall-xray.js +2 -2
  153. package/dist/resolve-auth-token.d.ts +1 -1
  154. package/dist/resume-bundles.js +2 -2
  155. package/dist/retrieval-agents.d.ts +1 -1
  156. package/dist/retrieval-tiers.d.ts +1 -1
  157. package/dist/routing/engine.d.ts +1 -1
  158. package/dist/routing/store.d.ts +1 -1
  159. package/dist/schemas.d.ts +22 -22
  160. package/dist/search/embed-helper.d.ts +1 -1
  161. package/dist/search/factory.d.ts +1 -1
  162. package/dist/search/factory.js +6 -6
  163. package/dist/search/index.d.ts +1 -1
  164. package/dist/search/index.js +6 -6
  165. package/dist/search/lancedb-backend.d.ts +1 -1
  166. package/dist/search/lancedb-backend.js +2 -2
  167. package/dist/search/meilisearch-backend.d.ts +1 -1
  168. package/dist/search/meilisearch-backend.js +2 -2
  169. package/dist/search/noop-backend.d.ts +1 -1
  170. package/dist/search/orama-backend.d.ts +1 -1
  171. package/dist/search/orama-backend.js +2 -2
  172. package/dist/search/port.d.ts +17 -1
  173. package/dist/search/port.js +1 -1
  174. package/dist/search/remote-backend.d.ts +1 -1
  175. package/dist/{semantic-consolidation-BKd0Pype.d.ts → semantic-consolidation-Z8d_uMq8.d.ts} +1 -1
  176. package/dist/semantic-consolidation.d.ts +2 -2
  177. package/dist/semantic-consolidation.js +4 -4
  178. package/dist/semantic-rule-promotion.js +3 -3
  179. package/dist/semantic-rule-verifier.d.ts +1 -1
  180. package/dist/semantic-rule-verifier.js +3 -3
  181. package/dist/session-observer-bands.d.ts +1 -1
  182. package/dist/session-observer-state.d.ts +1 -1
  183. package/dist/shared-context/manager.d.ts +1 -1
  184. package/dist/signal.d.ts +1 -1
  185. package/dist/storage.d.ts +1 -1
  186. package/dist/storage.js +2 -2
  187. package/dist/summarizer.d.ts +1 -1
  188. package/dist/summary-snapshot.d.ts +1 -1
  189. package/dist/temporal-supersession.d.ts +1 -1
  190. package/dist/temporal-validity.d.ts +1 -1
  191. package/dist/threading.d.ts +1 -1
  192. package/dist/tier-migration.d.ts +1 -1
  193. package/dist/tier-routing.d.ts +1 -1
  194. package/dist/topics.d.ts +1 -1
  195. package/dist/transcript.d.ts +1 -1
  196. package/dist/transfer/types.d.ts +12 -12
  197. package/dist/{types-BgChEr0M.d.ts → types-2OPlQWJG.d.ts} +12 -0
  198. package/dist/types.d.ts +1 -1
  199. package/dist/types.js +1 -1
  200. package/dist/utility-runtime.d.ts +1 -1
  201. package/dist/verified-recall.js +3 -3
  202. package/package.json +1 -1
  203. package/src/config.test.ts +69 -0
  204. package/src/config.ts +135 -0
  205. package/src/maintenance/namespace-planner.test.ts +1120 -0
  206. package/src/maintenance/namespace-planner.ts +893 -0
  207. package/src/namespaces/search.test.ts +130 -2
  208. package/src/namespaces/search.ts +71 -10
  209. package/src/orchestrator-flush.test.ts +464 -44
  210. package/src/orchestrator.ts +97 -66
  211. package/src/qmd-client.test.ts +59 -0
  212. package/src/qmd.ts +124 -84
  213. package/src/search/port.ts +16 -0
  214. package/src/types.ts +12 -0
  215. package/dist/chunk-JVRPJ7D4.js.map +0 -1
  216. package/dist/chunk-NE2JBMLN.js.map +0 -1
  217. package/dist/chunk-OL2364SB.js.map +0 -1
  218. package/dist/chunk-PYWNNF2I.js.map +0 -1
  219. package/dist/chunk-YLZLPVKK.js.map +0 -1
  220. /package/dist/{chunk-BP2EV6W5.js.map → chunk-2RCGZ67B.js.map} +0 -0
  221. /package/dist/{chunk-FVRBLJP6.js.map → chunk-54LOUIBE.js.map} +0 -0
  222. /package/dist/{chunk-LJCEWTG3.js.map → chunk-55ZMNKMQ.js.map} +0 -0
  223. /package/dist/{chunk-7WEB3FLJ.js.map → chunk-5PLUC5OB.js.map} +0 -0
  224. /package/dist/{chunk-DBM2BD22.js.map → chunk-67G4T7KI.js.map} +0 -0
  225. /package/dist/{chunk-JX2RINDR.js.map → chunk-6G5JEN55.js.map} +0 -0
  226. /package/dist/{chunk-2DSTAWNZ.js.map → chunk-A3Y37UWI.js.map} +0 -0
  227. /package/dist/{chunk-T2C6QJG2.js.map → chunk-BGKXTVNG.js.map} +0 -0
  228. /package/dist/{chunk-JYN7QNTA.js.map → chunk-COVZLGMR.js.map} +0 -0
  229. /package/dist/{chunk-JBHXMCYN.js.map → chunk-GRYAECRV.js.map} +0 -0
  230. /package/dist/{chunk-RGPUQ66K.js.map → chunk-IQ53ZSXV.js.map} +0 -0
  231. /package/dist/{chunk-QW6JZO5P.js.map → chunk-KZZ4YAEC.js.map} +0 -0
  232. /package/dist/{chunk-QKK64Z6M.js.map → chunk-NCSJKK23.js.map} +0 -0
  233. /package/dist/{chunk-NCGWXCSW.js.map → chunk-NRBGRZW4.js.map} +0 -0
  234. /package/dist/{chunk-GPW2E4LN.js.map → chunk-OKW6F5S5.js.map} +0 -0
  235. /package/dist/{chunk-Y2RIIF6H.js.map → chunk-PTMJ2FH2.js.map} +0 -0
  236. /package/dist/{chunk-JMQSYGXS.js.map → chunk-PVE7KSQP.js.map} +0 -0
  237. /package/dist/{chunk-NAZWHTYV.js.map → chunk-QDVQ4AN2.js.map} +0 -0
  238. /package/dist/{chunk-YM3LR4LS.js.map → chunk-SSSXWIBP.js.map} +0 -0
  239. /package/dist/{chunk-6CVI6BP6.js.map → chunk-TEO46GMM.js.map} +0 -0
  240. /package/dist/{chunk-K6X553JB.js.map → chunk-UCEABZZN.js.map} +0 -0
  241. /package/dist/{chunk-ENV6RDTD.js.map → chunk-UCEDY5M7.js.map} +0 -0
  242. /package/dist/{chunk-ZCORQM74.js.map → chunk-UYNFWZWG.js.map} +0 -0
  243. /package/dist/{chunk-XWQ6ERUG.js.map → chunk-WDTUYOLS.js.map} +0 -0
  244. /package/dist/{chunk-Z5MQI7K2.js.map → chunk-XOFXKASO.js.map} +0 -0
  245. /package/dist/{chunk-3RACUBII.js.map → chunk-XRKQOQLY.js.map} +0 -0
  246. /package/dist/{chunk-BJA6DQOC.js.map → chunk-YYN3LIYA.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-UYNFWZWG.js";
33
33
  import {
34
34
  SharedContextManager
35
35
  } from "./chunk-DRD2Q7HQ.js";
@@ -175,7 +175,7 @@ import {
175
175
  buildEntityRecallSection,
176
176
  entityRecentTranscriptLookbackHours,
177
177
  readRecentEntityTranscriptEntries
178
- } from "./chunk-NCGWXCSW.js";
178
+ } from "./chunk-NRBGRZW4.js";
179
179
  import {
180
180
  buildEventOrderRecallSection,
181
181
  shouldRecallEventOrderEvidence
@@ -210,7 +210,7 @@ import {
210
210
  materializeAfterSemanticConsolidation,
211
211
  parseConsolidationResponse,
212
212
  parseOperatorAwareConsolidationResponse
213
- } from "./chunk-T2C6QJG2.js";
213
+ } from "./chunk-BGKXTVNG.js";
214
214
  import {
215
215
  normalizeReplaySessionKey
216
216
  } from "./chunk-2PRQG7PV.js";
@@ -219,13 +219,13 @@ import {
219
219
  } from "./chunk-X6IRLNOO.js";
220
220
  import {
221
221
  searchVerifiedEpisodes
222
- } from "./chunk-QKK64Z6M.js";
222
+ } from "./chunk-NCSJKK23.js";
223
223
  import {
224
224
  ThreadingManager
225
225
  } from "./chunk-W4RVMTHR.js";
226
226
  import {
227
227
  searchVerifiedSemanticRules
228
- } from "./chunk-K6X553JB.js";
228
+ } from "./chunk-UCEABZZN.js";
229
229
  import {
230
230
  searchWorkProductLedgerEntries
231
231
  } from "./chunk-ZRWB5D4H.js";
@@ -239,7 +239,7 @@ import {
239
239
  NamespaceStorageRouter,
240
240
  resolveDefaultNamespaceRoot,
241
241
  resolveNamespaceStorageRoot
242
- } from "./chunk-3RACUBII.js";
242
+ } from "./chunk-XRKQOQLY.js";
243
243
  import {
244
244
  isAboveImportanceThreshold,
245
245
  scoreImportance
@@ -317,14 +317,14 @@ import {
317
317
  } from "./chunk-FF4KLI5W.js";
318
318
  import {
319
319
  buildXraySnapshot
320
- } from "./chunk-FVRBLJP6.js";
320
+ } from "./chunk-54LOUIBE.js";
321
321
  import {
322
322
  NamespaceSearchRouter
323
- } from "./chunk-JVRPJ7D4.js";
323
+ } from "./chunk-EKQMQQ3U.js";
324
324
  import {
325
325
  createConversationIndexRuntime,
326
326
  createSearchBackend
327
- } from "./chunk-YM3LR4LS.js";
327
+ } from "./chunk-SSSXWIBP.js";
328
328
  import {
329
329
  NoopSearchBackend
330
330
  } from "./chunk-CYEPCZN5.js";
@@ -338,7 +338,7 @@ import {
338
338
  } from "./chunk-OIF36KGD.js";
339
339
  import {
340
340
  parseQmdExplain
341
- } from "./chunk-PYWNNF2I.js";
341
+ } from "./chunk-QRSKPI62.js";
342
342
  import {
343
343
  objectiveStateStoreOverrideForNamespace,
344
344
  searchObjectiveStateSnapshots
@@ -357,7 +357,7 @@ import {
357
357
  } from "./chunk-Y56J7CXW.js";
358
358
  import {
359
359
  buildChainFollowupGenerator
360
- } from "./chunk-Y2RIIF6H.js";
360
+ } from "./chunk-PTMJ2FH2.js";
361
361
  import {
362
362
  ALL_CATEGORY_DIRS,
363
363
  ContentHashIndex,
@@ -368,7 +368,7 @@ import {
368
368
  normalizeEntityName,
369
369
  parseEntityFile,
370
370
  stripAttributesSuffix
371
- } from "./chunk-6CVI6BP6.js";
371
+ } from "./chunk-TEO46GMM.js";
372
372
  import {
373
373
  isValidTranscriptDate,
374
374
  loadSpeakerRegistry,
@@ -383,11 +383,14 @@ import {
383
383
  } from "./chunk-J6A3CX5N.js";
384
384
  import {
385
385
  confidenceTier
386
- } from "./chunk-NE2JBMLN.js";
386
+ } from "./chunk-TDZSSJV4.js";
387
387
  import {
388
388
  inferMemoryStatus,
389
389
  isActiveMemoryStatus
390
390
  } from "./chunk-RULE4VG5.js";
391
+ import {
392
+ displayErrorDetail
393
+ } from "./chunk-6KYMPV2O.js";
391
394
  import {
392
395
  lintWorkspaceFiles,
393
396
  rotateMarkdownFileToArchive
@@ -438,17 +441,17 @@ import {
438
441
  } from "./chunk-AC5LO7IU.js";
439
442
 
440
443
  // src/orchestrator.ts
441
- import path3 from "path";
444
+ import path4 from "path";
442
445
  import os from "os";
443
- import { createHash, randomBytes } from "crypto";
446
+ import { createHash as createHash2, randomBytes } from "crypto";
444
447
  import { existsSync, readFileSync } from "fs";
445
448
  import {
446
- mkdir as mkdir3,
447
- readdir as readdir2,
448
- readFile as readFile3,
449
- stat as stat2,
449
+ mkdir as mkdir4,
450
+ readdir as readdir3,
451
+ readFile as readFile4,
452
+ stat as stat3,
450
453
  unlink as unlink2,
451
- writeFile as writeFile3
454
+ writeFile as writeFile4
452
455
  } from "fs/promises";
453
456
 
454
457
  // src/procedural/procedure-recall.ts
@@ -2051,9 +2054,9 @@ var NamespaceCatalog = class {
2051
2054
  }
2052
2055
  if (await this.hasSymlinkedAncestor(candidate)) return false;
2053
2056
  try {
2054
- const stat3 = await lstat(candidate);
2055
- if (stat3.isSymbolicLink()) return false;
2056
- if (!stat3.isDirectory()) return false;
2057
+ const stat4 = await lstat(candidate);
2058
+ if (stat4.isSymbolicLink()) return false;
2059
+ if (!stat4.isDirectory()) return false;
2057
2060
  } catch {
2058
2061
  return this.isNearestExistingAncestorContained(candidate, memoryReal);
2059
2062
  }
@@ -2114,8 +2117,8 @@ var NamespaceCatalog = class {
2114
2117
  }
2115
2118
  if (!(isPathInside(memoryReal, real) || real === memoryReal)) return false;
2116
2119
  try {
2117
- const stat3 = await lstat(real);
2118
- return stat3.isDirectory();
2120
+ const stat4 = await lstat(real);
2121
+ return stat4.isDirectory();
2119
2122
  } catch {
2120
2123
  return false;
2121
2124
  }
@@ -2279,14 +2282,14 @@ var NamespaceCatalog = class {
2279
2282
  if (normalizeNamespaceIdentity(namespace) !== this.defaultNamespaceIdentity && path2.resolve(root) === path2.resolve(this.memoryDir)) {
2280
2283
  return false;
2281
2284
  }
2282
- let stat3;
2285
+ let stat4;
2283
2286
  try {
2284
- stat3 = await lstat(root);
2287
+ stat4 = await lstat(root);
2285
2288
  } catch {
2286
2289
  return false;
2287
2290
  }
2288
- if (stat3.isSymbolicLink()) return false;
2289
- if (!stat3.isDirectory()) return false;
2291
+ if (stat4.isSymbolicLink()) return false;
2292
+ if (!stat4.isDirectory()) return false;
2290
2293
  try {
2291
2294
  const real = await realpath(root);
2292
2295
  if (memoryReal && !isPathInside(memoryReal, real)) return false;
@@ -2463,18 +2466,18 @@ var NamespaceCatalog = class {
2463
2466
  for (const entry of entries) {
2464
2467
  const token = entry.name;
2465
2468
  const fullPath = path2.join(namespacesDir, token);
2466
- let stat3;
2469
+ let stat4;
2467
2470
  try {
2468
- stat3 = await lstat(fullPath);
2471
+ stat4 = await lstat(fullPath);
2469
2472
  } catch (err) {
2470
2473
  skipped.push({ token, reason: "error", detail: err instanceof Error ? err.message : String(err) });
2471
2474
  continue;
2472
2475
  }
2473
- if (stat3.isSymbolicLink()) {
2476
+ if (stat4.isSymbolicLink()) {
2474
2477
  skipped.push({ token, reason: "symlink", detail: fullPath });
2475
2478
  continue;
2476
2479
  }
2477
- if (!stat3.isDirectory()) continue;
2480
+ if (!stat4.isDirectory()) continue;
2478
2481
  try {
2479
2482
  const real = await realpath(fullPath);
2480
2483
  if (memoryReal && !isPathInside(memoryReal, real)) {
@@ -2865,6 +2868,611 @@ function isPathInside(root, child) {
2865
2868
  return relative === "" || !relative.startsWith("..") && !path2.isAbsolute(relative);
2866
2869
  }
2867
2870
 
2871
+ // src/maintenance/namespace-planner.ts
2872
+ import { createHash, randomUUID as randomUUID2 } from "crypto";
2873
+ 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";
2874
+ import path3 from "path";
2875
+ var DEFAULT_MAX_NAMESPACES_PER_CYCLE = 20;
2876
+ var DEFAULT_LOCK_STALE_MS = 10 * 6e4;
2877
+ var LOCK_BASE = "maintenance-locks";
2878
+ var STATUS_BASE = "namespace-maintenance-status";
2879
+ var namespaceMaintenanceFs = { open: open2, rm };
2880
+ function configuredNamespaces(config) {
2881
+ return Array.from(
2882
+ new Set(
2883
+ [config.defaultNamespace, config.sharedNamespace, ...config.namespacePolicies.map((policy) => policy.name)].map((value) => value.trim()).filter(Boolean)
2884
+ )
2885
+ );
2886
+ }
2887
+ function inferConfiguredKind(config, namespace) {
2888
+ if (namespace === config.defaultNamespace.trim()) return "default";
2889
+ if (namespace === config.sharedNamespace.trim()) return "shared";
2890
+ return "explicit";
2891
+ }
2892
+ function maxNamespacesPerCycle(config) {
2893
+ return Math.max(
2894
+ 1,
2895
+ Math.floor(
2896
+ typeof config.maintenanceMaxNamespacesPerCycle === "number" && Number.isFinite(config.maintenanceMaxNamespacesPerCycle) ? config.maintenanceMaxNamespacesPerCycle : DEFAULT_MAX_NAMESPACES_PER_CYCLE
2897
+ )
2898
+ );
2899
+ }
2900
+ function namespaceKindAllowed(config, kind) {
2901
+ switch (kind) {
2902
+ case "branch":
2903
+ return config.maintenanceIncludeBranchNamespaces === true;
2904
+ case "project":
2905
+ return config.maintenanceIncludeProjectNamespaces !== false;
2906
+ case "team-project":
2907
+ return config.maintenanceIncludeTeamProjectNamespaces !== false;
2908
+ default:
2909
+ return true;
2910
+ }
2911
+ }
2912
+ function disabledReasonForKind(kind) {
2913
+ if (kind === "branch") return "branch_disabled";
2914
+ if (kind === "project") return "project_disabled";
2915
+ if (kind === "team-project") return "team_project_disabled";
2916
+ return "fanout_disabled";
2917
+ }
2918
+ async function catalogRootIsLive(config, record) {
2919
+ if (typeof record.storageDir !== "string" || record.storageDir.length === 0) {
2920
+ return false;
2921
+ }
2922
+ try {
2923
+ const liveRoot = await resolveNamespaceStorageRoot(config, record.namespace);
2924
+ if (path3.resolve(liveRoot) !== path3.resolve(record.storageDir)) return false;
2925
+ return hasMemoryData(liveRoot);
2926
+ } catch {
2927
+ return false;
2928
+ }
2929
+ }
2930
+ function candidateSortKey(candidate) {
2931
+ const write = candidate.lastWriteAt ?? "";
2932
+ return `${write}\0${candidate.namespace}`;
2933
+ }
2934
+ function candidatePriority(candidate) {
2935
+ if (candidate.kind === "default") return 0;
2936
+ if (candidate.kind === "shared") return 1;
2937
+ if (candidate.source === "configured") return 2;
2938
+ if (candidate.kind === "team-project") return 3;
2939
+ if (candidate.kind === "project") return 4;
2940
+ if (candidate.kind === "self") return 5;
2941
+ if (candidate.kind === "legacy") return 6;
2942
+ if (candidate.kind === "branch") return 8;
2943
+ return 7;
2944
+ }
2945
+ function sortCandidates(a, b) {
2946
+ const priority = candidatePriority(a) - candidatePriority(b);
2947
+ if (priority !== 0) return priority;
2948
+ const am = Date.parse(a.lastMaintenanceAt ?? "");
2949
+ const bm = Date.parse(b.lastMaintenanceAt ?? "");
2950
+ const aMaintained = Number.isFinite(am);
2951
+ const bMaintained = Number.isFinite(bm);
2952
+ if (aMaintained && bMaintained && am !== bm) return am - bm;
2953
+ if (aMaintained !== bMaintained) return aMaintained ? 1 : -1;
2954
+ const aw = Date.parse(a.lastWriteAt ?? "");
2955
+ const bw = Date.parse(b.lastWriteAt ?? "");
2956
+ const aValid = Number.isFinite(aw);
2957
+ const bValid = Number.isFinite(bw);
2958
+ if (aValid && bValid && aw !== bw) return bw - aw;
2959
+ if (aValid !== bValid) return aValid ? -1 : 1;
2960
+ const byKey = candidateSortKey(a).localeCompare(candidateSortKey(b));
2961
+ if (byKey !== 0) return byKey;
2962
+ return a.namespace.localeCompare(b.namespace);
2963
+ }
2964
+ async function planNamespaceMaintenance(config, options) {
2965
+ const generatedAt = (options.now ?? /* @__PURE__ */ new Date()).toISOString();
2966
+ const configured = configuredNamespaces(config);
2967
+ const byNamespace = /* @__PURE__ */ new Map();
2968
+ const skipped = [];
2969
+ for (const namespace of configured) {
2970
+ const kind = inferConfiguredKind(config, namespace);
2971
+ byNamespace.set(namespace, {
2972
+ namespace,
2973
+ kind,
2974
+ source: "configured"
2975
+ });
2976
+ }
2977
+ if (config.namespacesEnabled && config.maintenanceNamespaceFanoutEnabled !== false) {
2978
+ const configuredSet = new Set(configured);
2979
+ try {
2980
+ const records = options.catalog?.enabled ? await options.catalog.listNamespaces() : [];
2981
+ for (const record of records) {
2982
+ const namespace = record.namespace.trim();
2983
+ if (!namespace) continue;
2984
+ const isConfigured = configuredSet.has(namespace);
2985
+ const kind = isConfigured ? inferConfiguredKind(config, namespace) : record.kind;
2986
+ if (!namespaceKindAllowed(config, kind)) {
2987
+ skipped.push({
2988
+ namespace,
2989
+ kind,
2990
+ reason: disabledReasonForKind(kind)
2991
+ });
2992
+ continue;
2993
+ }
2994
+ if (!isConfigured && !await catalogRootIsLive(config, record)) {
2995
+ skipped.push({
2996
+ namespace,
2997
+ kind,
2998
+ reason: "unsafe_or_stale_root"
2999
+ });
3000
+ continue;
3001
+ }
3002
+ byNamespace.set(namespace, {
3003
+ namespace,
3004
+ kind,
3005
+ storageDir: record.storageDir,
3006
+ source: isConfigured ? "configured" : "catalog",
3007
+ lastWriteAt: record.lastWriteAt,
3008
+ lastMaintenanceAt: record.lastMaintenanceAt?.[options.jobName]
3009
+ });
3010
+ }
3011
+ } catch (error) {
3012
+ skipped.push({
3013
+ namespace: "*",
3014
+ reason: "catalog_read_failed",
3015
+ detail: error instanceof Error ? error.message : String(error)
3016
+ });
3017
+ }
3018
+ } else if (config.namespacesEnabled) {
3019
+ skipped.push({
3020
+ namespace: "*",
3021
+ reason: "fanout_disabled"
3022
+ });
3023
+ }
3024
+ if (options.budgetMode !== "unbounded") {
3025
+ const latestStatusAtByNamespace = await readLatestStatusAtByNamespace(config, options.jobName);
3026
+ for (const candidate of byNamespace.values()) {
3027
+ if (!candidate.lastMaintenanceAt) {
3028
+ candidate.lastMaintenanceAt = latestStatusAtByNamespace.get(candidate.namespace);
3029
+ }
3030
+ }
3031
+ }
3032
+ const candidates = [...byNamespace.values()].filter((candidate) => namespaceKindAllowed(config, candidate.kind)).sort(sortCandidates);
3033
+ const max = maxNamespacesPerCycle(config);
3034
+ const applyCycleBudget = options.budgetMode !== "unbounded";
3035
+ const selected = applyCycleBudget ? candidates.slice(0, max) : candidates;
3036
+ if (applyCycleBudget) {
3037
+ for (const candidate of candidates.slice(max)) {
3038
+ skipped.push({
3039
+ namespace: candidate.namespace,
3040
+ kind: candidate.kind,
3041
+ reason: "budget_exhausted"
3042
+ });
3043
+ }
3044
+ }
3045
+ return {
3046
+ jobName: options.jobName,
3047
+ generatedAt,
3048
+ namespaces: selected,
3049
+ skipped,
3050
+ budget: {
3051
+ maxNamespacesPerCycle: max,
3052
+ selected: selected.length
3053
+ }
3054
+ };
3055
+ }
3056
+ function stablePathSegment(value) {
3057
+ const sanitized = value.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 128) || "unnamed";
3058
+ if (sanitized.length <= 128 && sanitized === value) return sanitized;
3059
+ return `${sanitized.slice(0, 80)}-${createHash("sha256").update(value).digest("hex").slice(0, 16)}`;
3060
+ }
3061
+ function namespacePathSegment(namespace) {
3062
+ const token = namespaceIdentityToken(namespace);
3063
+ if (token.length <= 160) return token;
3064
+ return `ns-${createHash("sha256").update(namespace).digest("hex")}`;
3065
+ }
3066
+ function lockPath(config, jobName, namespace) {
3067
+ return path3.join(
3068
+ config.memoryDir,
3069
+ "state",
3070
+ LOCK_BASE,
3071
+ stablePathSegment(jobName),
3072
+ `${namespacePathSegment(namespace)}.lock`
3073
+ );
3074
+ }
3075
+ function namespaceMaintenanceLockStaleMs(config) {
3076
+ if (typeof config.maintenanceNamespaceLockStaleMs === "number" && Number.isFinite(config.maintenanceNamespaceLockStaleMs) && config.maintenanceNamespaceLockStaleMs > 0) {
3077
+ return Math.floor(config.maintenanceNamespaceLockStaleMs);
3078
+ }
3079
+ return DEFAULT_LOCK_STALE_MS;
3080
+ }
3081
+ function namespaceMaintenanceLockHeartbeatMs(config) {
3082
+ const staleMs = namespaceMaintenanceLockStaleMs(config);
3083
+ return Math.max(1, Math.min(3e4, Math.floor(staleMs / 3) || 1));
3084
+ }
3085
+ function errorCode(error) {
3086
+ return typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
3087
+ }
3088
+ async function withNamespaceMaintenanceLockHeartbeat(config, locks, task) {
3089
+ const activeLocks = Array.isArray(locks) ? locks : [locks];
3090
+ const interval = setInterval(() => {
3091
+ for (const lock of activeLocks) {
3092
+ void lock.touch().catch(() => void 0);
3093
+ }
3094
+ }, namespaceMaintenanceLockHeartbeatMs(config));
3095
+ interval.unref?.();
3096
+ try {
3097
+ return await task();
3098
+ } finally {
3099
+ clearInterval(interval);
3100
+ }
3101
+ }
3102
+ async function removeStaleLockDirectory(filePath) {
3103
+ let entries;
3104
+ try {
3105
+ entries = await readdir2(filePath, { withFileTypes: true });
3106
+ } catch (error) {
3107
+ if (errorCode(error) === "ENOENT") return;
3108
+ throw error;
3109
+ }
3110
+ for (const entry of entries) {
3111
+ if (!entry.isFile()) continue;
3112
+ await namespaceMaintenanceFs.rm(path3.join(filePath, entry.name), { force: true });
3113
+ }
3114
+ try {
3115
+ await rmdir(filePath);
3116
+ } catch (error) {
3117
+ if (errorCode(error) === "ENOENT") return;
3118
+ throw error;
3119
+ }
3120
+ }
3121
+ async function tryAcquireNamespaceMaintenanceLock(config, jobName, namespace) {
3122
+ const filePath = lockPath(config, jobName, namespace);
3123
+ await mkdir3(path3.dirname(filePath), { recursive: true });
3124
+ try {
3125
+ const lockId = randomUUID2();
3126
+ await mkdir3(filePath);
3127
+ const ownerPath = path3.join(filePath, `${lockId}.json`);
3128
+ let handle;
3129
+ try {
3130
+ handle = await namespaceMaintenanceFs.open(ownerPath, "wx");
3131
+ await handle.writeFile(
3132
+ `${JSON.stringify({
3133
+ lockId,
3134
+ pid: process.pid,
3135
+ jobName,
3136
+ namespace,
3137
+ acquiredAt: (/* @__PURE__ */ new Date()).toISOString()
3138
+ })}
3139
+ `,
3140
+ "utf8"
3141
+ );
3142
+ await handle.close();
3143
+ } catch (setupError) {
3144
+ await handle?.close().catch(() => void 0);
3145
+ await namespaceMaintenanceFs.rm(ownerPath, { force: true }).catch(() => void 0);
3146
+ await rmdir(filePath).catch(() => void 0);
3147
+ throw setupError;
3148
+ }
3149
+ return {
3150
+ path: filePath,
3151
+ async touch() {
3152
+ try {
3153
+ const parsed = JSON.parse(await readFile3(ownerPath, "utf8"));
3154
+ if (parsed.lockId === lockId) {
3155
+ const now = /* @__PURE__ */ new Date();
3156
+ await utimes2(ownerPath, now, now);
3157
+ await utimes2(filePath, now, now);
3158
+ }
3159
+ } catch {
3160
+ }
3161
+ },
3162
+ async release() {
3163
+ try {
3164
+ const parsed = JSON.parse(await readFile3(ownerPath, "utf8"));
3165
+ if (parsed.lockId === lockId) {
3166
+ await namespaceMaintenanceFs.rm(ownerPath, { force: true });
3167
+ await rmdir(filePath).catch(() => void 0);
3168
+ }
3169
+ } catch {
3170
+ }
3171
+ }
3172
+ };
3173
+ } catch (error) {
3174
+ if (errorCode(error) === "EEXIST") {
3175
+ const staleMs = namespaceMaintenanceLockStaleMs(config);
3176
+ try {
3177
+ const s = await lstat2(filePath);
3178
+ if (s.isSymbolicLink()) {
3179
+ return null;
3180
+ }
3181
+ if ((s.isFile() || s.isDirectory()) && Date.now() - s.mtimeMs > staleMs) {
3182
+ try {
3183
+ if (s.isDirectory()) {
3184
+ await removeStaleLockDirectory(filePath);
3185
+ } else {
3186
+ await namespaceMaintenanceFs.rm(filePath, { force: true });
3187
+ }
3188
+ } catch (removeError) {
3189
+ if (errorCode(removeError) === "ENOENT") {
3190
+ return tryAcquireNamespaceMaintenanceLock(config, jobName, namespace);
3191
+ }
3192
+ if (errorCode(removeError) === "ENOTEMPTY") {
3193
+ return null;
3194
+ }
3195
+ throw removeError;
3196
+ }
3197
+ return tryAcquireNamespaceMaintenanceLock(config, jobName, namespace);
3198
+ }
3199
+ } catch (statError) {
3200
+ if (errorCode(statError) === "ENOENT") {
3201
+ return tryAcquireNamespaceMaintenanceLock(config, jobName, namespace);
3202
+ }
3203
+ throw statError;
3204
+ }
3205
+ return null;
3206
+ }
3207
+ throw error;
3208
+ }
3209
+ }
3210
+ function statusBasePath(config) {
3211
+ return path3.join(config.memoryDir, "state", STATUS_BASE);
3212
+ }
3213
+ function statusPath(config, jobName, namespace) {
3214
+ return path3.join(statusBasePath(config), stablePathSegment(jobName), `${namespacePathSegment(namespace)}.json`);
3215
+ }
3216
+ function lastRanStatusPath(config, jobName, namespace) {
3217
+ return path3.join(statusBasePath(config), stablePathSegment(jobName), `${namespacePathSegment(namespace)}.last-ran.json`);
3218
+ }
3219
+ function parseStatus(value) {
3220
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
3221
+ const v = value;
3222
+ 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") {
3223
+ return v;
3224
+ }
3225
+ return null;
3226
+ }
3227
+ async function readLatestStatusAtByNamespace(config, jobName) {
3228
+ const latest = /* @__PURE__ */ new Map();
3229
+ const latestMs = /* @__PURE__ */ new Map();
3230
+ for (const status of [...await readStatusFiles(config), ...await readLastRanStatusFiles(config)]) {
3231
+ if (status.state !== "ran") continue;
3232
+ if (status.jobName !== jobName) continue;
3233
+ const completedAtMs = Date.parse(status.completedAt);
3234
+ if (!Number.isFinite(completedAtMs)) continue;
3235
+ const previousMs = latestMs.get(status.namespace);
3236
+ if (previousMs !== void 0 && previousMs >= completedAtMs) continue;
3237
+ latestMs.set(status.namespace, completedAtMs);
3238
+ latest.set(status.namespace, status.completedAt);
3239
+ }
3240
+ return latest;
3241
+ }
3242
+ async function readStatusFile(filePath) {
3243
+ try {
3244
+ const parsed = JSON.parse(await readFile3(filePath, "utf8"));
3245
+ return parseStatus(parsed);
3246
+ } catch {
3247
+ return null;
3248
+ }
3249
+ }
3250
+ async function readStatusFiles(config) {
3251
+ if (typeof config.memoryDir !== "string" || config.memoryDir.length === 0) {
3252
+ return [];
3253
+ }
3254
+ const root = statusBasePath(config);
3255
+ const statuses = [];
3256
+ let jobDirs;
3257
+ try {
3258
+ jobDirs = await readdir2(root, { withFileTypes: true });
3259
+ } catch {
3260
+ return statuses;
3261
+ }
3262
+ for (const jobDir of jobDirs) {
3263
+ if (!jobDir.isDirectory()) continue;
3264
+ let files;
3265
+ try {
3266
+ files = await readdir2(path3.join(root, jobDir.name), { withFileTypes: true });
3267
+ } catch {
3268
+ continue;
3269
+ }
3270
+ for (const file of files) {
3271
+ if (!file.isFile() || !file.name.endsWith(".json")) continue;
3272
+ if (file.name.endsWith(".last-ran.json")) continue;
3273
+ const status = await readStatusFile(path3.join(root, jobDir.name, file.name));
3274
+ if (status) statuses.push(status);
3275
+ }
3276
+ }
3277
+ return statuses;
3278
+ }
3279
+ async function readLastRanStatusFiles(config) {
3280
+ if (typeof config.memoryDir !== "string" || config.memoryDir.length === 0) {
3281
+ return [];
3282
+ }
3283
+ const root = statusBasePath(config);
3284
+ const statuses = [];
3285
+ let jobDirs;
3286
+ try {
3287
+ jobDirs = await readdir2(root, { withFileTypes: true });
3288
+ } catch {
3289
+ return statuses;
3290
+ }
3291
+ for (const jobDir of jobDirs) {
3292
+ if (!jobDir.isDirectory()) continue;
3293
+ let files;
3294
+ try {
3295
+ files = await readdir2(path3.join(root, jobDir.name), { withFileTypes: true });
3296
+ } catch {
3297
+ continue;
3298
+ }
3299
+ for (const file of files) {
3300
+ if (!file.isFile() || !file.name.endsWith(".last-ran.json")) continue;
3301
+ const status = await readStatusFile(path3.join(root, jobDir.name, file.name));
3302
+ if (status) statuses.push(status);
3303
+ }
3304
+ }
3305
+ return statuses;
3306
+ }
3307
+ async function writeStatusPayload(target, status) {
3308
+ const dir = path3.dirname(target);
3309
+ await mkdir3(dir, { recursive: true });
3310
+ const temp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
3311
+ const payload = {
3312
+ version: 1,
3313
+ ...status
3314
+ };
3315
+ await writeFile3(temp, `${JSON.stringify(payload, null, 2)}
3316
+ `, "utf8");
3317
+ await rename2(temp, target);
3318
+ }
3319
+ async function writeStatusFile(config, status) {
3320
+ await writeStatusPayload(statusPath(config, status.jobName, status.namespace), status);
3321
+ if (status.state === "ran") {
3322
+ await writeStatusPayload(lastRanStatusPath(config, status.jobName, status.namespace), status);
3323
+ }
3324
+ }
3325
+ async function recordNamespaceMaintenanceStatusSafely(config, status) {
3326
+ try {
3327
+ await writeStatusFile(config, status);
3328
+ } catch {
3329
+ }
3330
+ }
3331
+ function maintenanceErrorDetail(error) {
3332
+ return displayErrorDetail(error) || "Error";
3333
+ }
3334
+ async function runNamespaceMaintenanceBatchPlan(config, plan, runner, catalog, options = {}) {
3335
+ const statuses = [];
3336
+ for (const skipped of plan.skipped) {
3337
+ if (skipped.namespace === "*") continue;
3338
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3339
+ const status = {
3340
+ namespace: skipped.namespace,
3341
+ jobName: plan.jobName,
3342
+ state: "skipped",
3343
+ reason: skipped.reason,
3344
+ startedAt: now,
3345
+ completedAt: now
3346
+ };
3347
+ statuses.push(status);
3348
+ await recordNamespaceMaintenanceStatusSafely(config, status);
3349
+ }
3350
+ const acquired = [];
3351
+ try {
3352
+ for (const candidate of plan.namespaces) {
3353
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
3354
+ const lock = await tryAcquireNamespaceMaintenanceLock(config, plan.jobName, candidate.namespace);
3355
+ if (!lock) {
3356
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
3357
+ const status = {
3358
+ namespace: candidate.namespace,
3359
+ jobName: plan.jobName,
3360
+ state: "skipped",
3361
+ reason: "lock_held",
3362
+ startedAt,
3363
+ completedAt
3364
+ };
3365
+ statuses.push(status);
3366
+ await recordNamespaceMaintenanceStatusSafely(config, status);
3367
+ continue;
3368
+ }
3369
+ acquired.push({ candidate, lock, startedAt });
3370
+ }
3371
+ } catch (error) {
3372
+ await Promise.all(acquired.map(({ lock }) => lock.release().catch(() => void 0)));
3373
+ throw error;
3374
+ }
3375
+ if (options.requireAllLocks && acquired.length > 0 && acquired.length < plan.namespaces.length) {
3376
+ for (const { candidate, startedAt } of acquired) {
3377
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
3378
+ const status = {
3379
+ namespace: candidate.namespace,
3380
+ jobName: plan.jobName,
3381
+ state: "skipped",
3382
+ reason: "batch_lock_incomplete",
3383
+ startedAt,
3384
+ completedAt
3385
+ };
3386
+ statuses.push(status);
3387
+ await recordNamespaceMaintenanceStatusSafely(config, status);
3388
+ }
3389
+ await Promise.all(acquired.map(({ lock }) => lock.release().catch(() => void 0)));
3390
+ return {
3391
+ jobName: plan.jobName,
3392
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3393
+ ran: statuses.filter((s) => s.state === "ran").length,
3394
+ skipped: statuses.filter((s) => s.state === "skipped").length,
3395
+ failed: statuses.filter((s) => s.state === "failed").length,
3396
+ statuses
3397
+ };
3398
+ }
3399
+ if (acquired.length === 0) {
3400
+ return {
3401
+ jobName: plan.jobName,
3402
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3403
+ ran: statuses.filter((s) => s.state === "ran").length,
3404
+ skipped: statuses.filter((s) => s.state === "skipped").length,
3405
+ failed: statuses.filter((s) => s.state === "failed").length,
3406
+ statuses
3407
+ };
3408
+ }
3409
+ try {
3410
+ const result = await withNamespaceMaintenanceLockHeartbeat(
3411
+ config,
3412
+ acquired.map(({ lock }) => lock),
3413
+ () => runner(acquired.map(({ candidate }) => candidate))
3414
+ );
3415
+ for (const { candidate, startedAt } of acquired) {
3416
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
3417
+ const status = {
3418
+ namespace: candidate.namespace,
3419
+ jobName: plan.jobName,
3420
+ state: "ran",
3421
+ startedAt,
3422
+ completedAt,
3423
+ itemCount: itemCountForNamespace(result, candidate.namespace)
3424
+ };
3425
+ statuses.push(status);
3426
+ await recordNamespaceMaintenanceStatusSafely(config, status);
3427
+ try {
3428
+ await catalog?.markMaintenance(candidate.namespace, plan.jobName, new Date(completedAt));
3429
+ } catch {
3430
+ }
3431
+ }
3432
+ } catch (error) {
3433
+ const skipReason = options.skipReasonForError?.(error);
3434
+ for (const { candidate, startedAt } of acquired) {
3435
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
3436
+ const status = skipReason ? {
3437
+ namespace: candidate.namespace,
3438
+ jobName: plan.jobName,
3439
+ state: "skipped",
3440
+ reason: skipReason,
3441
+ startedAt,
3442
+ completedAt
3443
+ } : {
3444
+ namespace: candidate.namespace,
3445
+ jobName: plan.jobName,
3446
+ state: "failed",
3447
+ reason: "job_failed",
3448
+ startedAt,
3449
+ completedAt,
3450
+ error: maintenanceErrorDetail(error)
3451
+ };
3452
+ statuses.push(status);
3453
+ await recordNamespaceMaintenanceStatusSafely(config, status);
3454
+ }
3455
+ } finally {
3456
+ await Promise.all(acquired.map(({ lock }) => lock.release().catch(() => void 0)));
3457
+ }
3458
+ return {
3459
+ jobName: plan.jobName,
3460
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3461
+ ran: statuses.filter((s) => s.state === "ran").length,
3462
+ skipped: statuses.filter((s) => s.state === "skipped").length,
3463
+ failed: statuses.filter((s) => s.state === "failed").length,
3464
+ statuses
3465
+ };
3466
+ }
3467
+ function itemCountForNamespace(result, namespace) {
3468
+ const itemCounts = result?.itemCounts;
3469
+ if (itemCounts instanceof Map) return itemCounts.get(namespace);
3470
+ if (itemCounts && Object.prototype.hasOwnProperty.call(itemCounts, namespace)) {
3471
+ return itemCounts[namespace];
3472
+ }
3473
+ return result?.itemCount;
3474
+ }
3475
+
2868
3476
  // src/orchestrator.ts
2869
3477
  var BulkImportBatchPartialFailureError = class extends Error {
2870
3478
  partialResult;
@@ -2926,7 +3534,7 @@ function flattenStructuredSectionEvidence(sections) {
2926
3534
  );
2927
3535
  }
2928
3536
  function fingerprintEntitySynthesisEvidence(entity) {
2929
- const fingerprint = createHash("sha256");
3537
+ const fingerprint = createHash2("sha256");
2930
3538
  const timelineEntries = entity.timeline.map((entry) => [
2931
3539
  entry.timestamp,
2932
3540
  entry.source ?? "",
@@ -2976,7 +3584,7 @@ async function raceRecallAbort(promise, signal, message = "recall aborted") {
2976
3584
  }
2977
3585
  }
2978
3586
  function qmdCollectionPathParts(resultPath) {
2979
- if (!resultPath || path3.isAbsolute(resultPath)) return null;
3587
+ if (!resultPath || path4.isAbsolute(resultPath)) return null;
2980
3588
  const normalized = resultPath.replace(/\\/g, "/").replace(/^\/+/, "");
2981
3589
  const slashIndex = normalized.indexOf("/");
2982
3590
  if (slashIndex <= 0 || slashIndex >= normalized.length - 1) return null;
@@ -2989,9 +3597,9 @@ function qmdCollectionPathParts(resultPath) {
2989
3597
  }
2990
3598
  function qmdResultPathCandidates(storageDir, resultPath) {
2991
3599
  const candidates = /* @__PURE__ */ new Set();
2992
- const storageRoot = path3.resolve(storageDir);
3600
+ const storageRoot = path4.resolve(storageDir);
2993
3601
  const addCandidate = (candidate) => {
2994
- const resolved = path3.resolve(candidate);
3602
+ const resolved = path4.resolve(candidate);
2995
3603
  if (isPathInsideStorageRoot(storageRoot, resolved)) {
2996
3604
  candidates.add(resolved);
2997
3605
  }
@@ -2999,12 +3607,12 @@ function qmdResultPathCandidates(storageDir, resultPath) {
2999
3607
  const addRelativeCandidates = (relativePath) => {
3000
3608
  const normalized = relativePath.replace(/\\/g, "/").replace(/^\/+/, "");
3001
3609
  if (!normalized) return;
3002
- addCandidate(path3.join(storageRoot, normalized));
3610
+ addCandidate(path4.join(storageRoot, normalized));
3003
3611
  if (/^\d{4}-\d{2}-\d{2}\//.test(normalized)) {
3004
- addCandidate(path3.join(storageRoot, "facts", normalized));
3612
+ addCandidate(path4.join(storageRoot, "facts", normalized));
3005
3613
  }
3006
3614
  };
3007
- if (path3.isAbsolute(resultPath)) {
3615
+ if (path4.isAbsolute(resultPath)) {
3008
3616
  addCandidate(resultPath);
3009
3617
  } else {
3010
3618
  addRelativeCandidates(resultPath);
@@ -3121,11 +3729,11 @@ async function qmdStartupCollectionCheckWithTimeout(promise, controller, label)
3121
3729
  return await Promise.race([checkedPromise, timeoutPromise]);
3122
3730
  }
3123
3731
  function defaultWorkspaceDir() {
3124
- return path3.join(os.homedir(), ".openclaw", "workspace");
3732
+ return path4.join(os.homedir(), ".openclaw", "workspace");
3125
3733
  }
3126
3734
  function sanitizeSessionKeyForFilename(sessionKey) {
3127
3735
  const readable = sessionKey.replace(/[^a-zA-Z0-9._-]/g, "_");
3128
- const hash = createHash("sha256").update(sessionKey).digest("hex").slice(0, 12);
3736
+ const hash = createHash2("sha256").update(sessionKey).digest("hex").slice(0, 12);
3129
3737
  return `${readable}-${hash}`;
3130
3738
  }
3131
3739
  function latestSourceValidAtFromTurns(turns) {
@@ -3426,11 +4034,11 @@ function mergeGraphExpandedResults(primary, expanded) {
3426
4034
  return Array.from(mergedByPath.values());
3427
4035
  }
3428
4036
  function graphPathRelativeToStorage(storageDir, candidatePath) {
3429
- const absolutePath = path3.isAbsolute(candidatePath) ? candidatePath : path3.resolve(storageDir, candidatePath);
3430
- const rel = path3.relative(storageDir, absolutePath);
4037
+ const absolutePath = path4.isAbsolute(candidatePath) ? candidatePath : path4.resolve(storageDir, candidatePath);
4038
+ const rel = path4.relative(storageDir, absolutePath);
3431
4039
  if (!rel || rel === ".") return null;
3432
4040
  if (rel.startsWith("..")) return null;
3433
- return rel.split(path3.sep).join("/");
4041
+ return rel.split(path4.sep).join("/");
3434
4042
  }
3435
4043
  function normalizeGraphActivationScore(score) {
3436
4044
  const bounded = Number.isFinite(score) && score > 0 ? score : 0;
@@ -3572,7 +4180,7 @@ function buildMemoryPathById(allMemsForGraph, storageDir) {
3572
4180
  for (const mem of allMemsForGraph ?? []) {
3573
4181
  const id = mem.frontmatter.id;
3574
4182
  if (!id) continue;
3575
- pathById.set(id, path3.relative(storageDir, mem.path));
4183
+ pathById.set(id, path4.relative(storageDir, mem.path));
3576
4184
  }
3577
4185
  return pathById;
3578
4186
  }
@@ -3580,7 +4188,7 @@ function appendMemoryToGraphContext(options) {
3580
4188
  if (!Array.isArray(options.allMemsForGraph)) return;
3581
4189
  const nowIso = (/* @__PURE__ */ new Date()).toISOString();
3582
4190
  options.allMemsForGraph.push({
3583
- path: path3.join(options.storageDir, options.memoryRelPath),
4191
+ path: path4.join(options.storageDir, options.memoryRelPath),
3584
4192
  content: options.content,
3585
4193
  frontmatter: {
3586
4194
  id: options.memoryId,
@@ -3600,16 +4208,20 @@ function resolvePersistedMemoryRelativePath(options) {
3600
4208
  const persisted = options.pathById.get(options.memoryId);
3601
4209
  if (persisted) return persisted;
3602
4210
  if (options.category === "correction") {
3603
- return path3.join("corrections", `${options.memoryId}.md`);
4211
+ return path4.join("corrections", `${options.memoryId}.md`);
3604
4212
  }
3605
4213
  const subtree = options.category === "procedure" ? "procedures" : options.category === "reasoning_trace" ? "reasoning-traces" : "facts";
3606
4214
  const idParts = options.memoryId.split("-");
3607
4215
  const maybeTimestamp = Number(idParts[1]);
3608
4216
  if (Number.isFinite(maybeTimestamp) && maybeTimestamp > 0) {
3609
4217
  const day = new Date(maybeTimestamp).toISOString().slice(0, 10);
3610
- return path3.join(subtree, day, `${options.memoryId}.md`);
4218
+ return path4.join(subtree, day, `${options.memoryId}.md`);
3611
4219
  }
3612
- return path3.join(subtree, `${options.memoryId}.md`);
4220
+ return path4.join(subtree, `${options.memoryId}.md`);
4221
+ }
4222
+ function qmdMaintenanceSkipReasonForError(error) {
4223
+ const message = error instanceof Error ? error.message : String(error);
4224
+ return /^QMD (?:update|embed) skipped by .*min-interval gate$/.test(message) ? "throttled" : null;
3613
4225
  }
3614
4226
  var Orchestrator = class _Orchestrator {
3615
4227
  storage;
@@ -3737,6 +4349,7 @@ var Orchestrator = class _Orchestrator {
3737
4349
  qmdMaintenancePending = false;
3738
4350
  qmdMaintenanceInFlight = false;
3739
4351
  lastQmdEmbedAtMs = 0;
4352
+ lastQmdEmbedAtMsByNamespace = /* @__PURE__ */ new Map();
3740
4353
  lastQmdReprobeAtMs = 0;
3741
4354
  tierMigrationInFlight = false;
3742
4355
  lastTierMigrationRunAtMs = 0;
@@ -4038,7 +4651,7 @@ var Orchestrator = class _Orchestrator {
4038
4651
  const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
4039
4652
  if (ns !== defaultNs && !isSafeRouteNamespace(ns)) return;
4040
4653
  if (!this.storageDirMatchesNamespaceHint(ns, storageDir)) return;
4041
- const resolvedStorageDir = path3.resolve(storageDir);
4654
+ const resolvedStorageDir = path4.resolve(storageDir);
4042
4655
  let hints = this.namespaceStorageDirHints.get(resolvedStorageDir);
4043
4656
  if (!hints) {
4044
4657
  hints = /* @__PURE__ */ new Set();
@@ -4049,21 +4662,21 @@ var Orchestrator = class _Orchestrator {
4049
4662
  storageDirMatchesNamespaceHint(namespace, storageDir) {
4050
4663
  const ns = normalizeNamespaceIdentity(namespace);
4051
4664
  if (!ns) return false;
4052
- const resolvedStorageDir = path3.resolve(storageDir);
4053
- const resolvedMemoryDir = path3.resolve(this.config.memoryDir);
4665
+ const resolvedStorageDir = path4.resolve(storageDir);
4666
+ const resolvedMemoryDir = path4.resolve(this.config.memoryDir);
4054
4667
  const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
4055
4668
  if (resolvedStorageDir === resolvedMemoryDir) return ns === defaultNs;
4056
- const resolvedNamespacesDir = path3.join(resolvedMemoryDir, "namespaces");
4669
+ const resolvedNamespacesDir = path4.join(resolvedMemoryDir, "namespaces");
4057
4670
  if (!isPathInsideStorageRoot(resolvedNamespacesDir, resolvedStorageDir)) return false;
4058
- const rawRoot = path3.resolve(resolvedNamespacesDir, ns);
4059
- const tokenRoot = path3.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
4671
+ const rawRoot = path4.resolve(resolvedNamespacesDir, ns);
4672
+ const tokenRoot = path4.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
4060
4673
  return resolvedStorageDir === rawRoot || resolvedStorageDir === tokenRoot;
4061
4674
  }
4062
4675
  namespaceStorageDirHintOwnershipRank(record, resolvedStorageDir, configured) {
4063
- if (resolvedStorageDir === path3.resolve(this.config.memoryDir)) {
4676
+ if (resolvedStorageDir === path4.resolve(this.config.memoryDir)) {
4064
4677
  return record.namespace === normalizeNamespaceIdentity(this.config.defaultNamespace) ? 0 : 3;
4065
4678
  }
4066
- const leaf = path3.basename(resolvedStorageDir);
4679
+ const leaf = path4.basename(resolvedStorageDir);
4067
4680
  const tokenOwnsRoot = namespaceIdentityToken(record.namespace) === leaf;
4068
4681
  if (tokenOwnsRoot && configured.has(record.namespace)) return 0;
4069
4682
  if (record.namespace === leaf) return 1;
@@ -4091,7 +4704,7 @@ var Orchestrator = class _Orchestrator {
4091
4704
  loadNamespaceStorageDirHintsFromCatalog() {
4092
4705
  if (this.namespaceStorageDirHintsLoaded || !this.namespaceCatalog.enabled) return;
4093
4706
  this.namespaceStorageDirHintsLoaded = true;
4094
- const catalogPath = path3.join(this.config.memoryDir, "state", "namespaces.jsonl");
4707
+ const catalogPath = path4.join(this.config.memoryDir, "state", "namespaces.jsonl");
4095
4708
  if (!existsSync(catalogPath)) return;
4096
4709
  let body;
4097
4710
  try {
@@ -4128,7 +4741,7 @@ var Orchestrator = class _Orchestrator {
4128
4741
  if (!this.storageDirMatchesNamespaceHint(record.namespace, record.storageDir)) {
4129
4742
  continue;
4130
4743
  }
4131
- const resolvedStorageDir = path3.resolve(record.storageDir);
4744
+ const resolvedStorageDir = path4.resolve(record.storageDir);
4132
4745
  const current = preferredByStorageDir.get(resolvedStorageDir);
4133
4746
  preferredByStorageDir.set(
4134
4747
  resolvedStorageDir,
@@ -4145,57 +4758,27 @@ var Orchestrator = class _Orchestrator {
4145
4758
  }
4146
4759
  }
4147
4760
  /**
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.
4761
+ * Shared namespace maintenance planner (issue #1500). This extends the
4762
+ * #1499 catalog-union QMD helper into a reusable contract: configured
4763
+ * namespaces are always considered, dynamic catalog namespaces are admitted
4764
+ * only when their live router root still matches real memory data, and branch
4765
+ * namespaces are opt-in. Recurring jobs use the per-cycle budget; startup and
4766
+ * recovery discovery paths use the same safety filters without that cycle
4767
+ * budget so every live namespace is ensured/synced.
4159
4768
  */
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
- );
4769
+ async namespaceMaintenancePlan(jobName) {
4770
+ return planNamespaceMaintenance(this.config, {
4771
+ jobName,
4772
+ catalog: this.namespaceCatalog
4773
+ });
4185
4774
  }
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
- }
4775
+ async maintenanceNamespaces(jobName = "qmd", budgetMode = "unbounded") {
4776
+ const plan = await planNamespaceMaintenance(this.config, {
4777
+ jobName,
4778
+ catalog: this.namespaceCatalog,
4779
+ budgetMode
4780
+ });
4781
+ return plan.namespaces.map((candidate) => candidate.namespace);
4199
4782
  }
4200
4783
  buildConfiguredQmdSearchOptions(queryText) {
4201
4784
  const intentHint = this.config.qmdIntentHintsEnabled ? buildQmdIntentHint(inferIntentFromText(queryText)) : void 0;
@@ -4271,7 +4854,7 @@ var Orchestrator = class _Orchestrator {
4271
4854
  this.config = config;
4272
4855
  this.profiler = new ProfilingCollector({
4273
4856
  enabled: config.profilingEnabled,
4274
- storageDir: config.profilingStorageDir || path3.join(config.memoryDir, "profiling"),
4857
+ storageDir: config.profilingStorageDir || path4.join(config.memoryDir, "profiling"),
4275
4858
  maxTraces: config.profilingMaxTraces
4276
4859
  });
4277
4860
  this.namespaceCatalog = new NamespaceCatalog(config);
@@ -4316,7 +4899,7 @@ var Orchestrator = class _Orchestrator {
4316
4899
  this.compounding = config.compoundingEnabled ? new CompoundingEngine(config, this.storage) : void 0;
4317
4900
  this.buffer = new SmartBuffer(config, this.storage);
4318
4901
  this.transcript = new TranscriptManager(config);
4319
- this.conversationIndexDir = path3.join(
4902
+ this.conversationIndexDir = path4.join(
4320
4903
  config.memoryDir,
4321
4904
  "conversation-index",
4322
4905
  "chunks"
@@ -4373,7 +4956,7 @@ var Orchestrator = class _Orchestrator {
4373
4956
  this.modelRegistry
4374
4957
  );
4375
4958
  this.threading = new ThreadingManager(
4376
- path3.join(config.memoryDir, "threads"),
4959
+ path4.join(config.memoryDir, "threads"),
4377
4960
  config.threadingGapMinutes
4378
4961
  );
4379
4962
  this.tmtBuilder = new TmtBuilder(config.memoryDir, {
@@ -4452,7 +5035,7 @@ var Orchestrator = class _Orchestrator {
4452
5035
  utilityPromoteThresholdDelta: this.utilityRuntimeValues?.promoteThresholdDelta ?? 0,
4453
5036
  utilityDemoteThresholdDelta: this.utilityRuntimeValues?.demoteThresholdDelta ?? 0
4454
5037
  };
4455
- return createHash("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 12);
5038
+ return createHash2("sha256").update(JSON.stringify(payload)).digest("hex").slice(0, 12);
4456
5039
  }
4457
5040
  effectiveLifecycleThresholds() {
4458
5041
  const archiveDecayThreshold = this.config.lifecycleArchiveDecayThreshold;
@@ -4672,11 +5255,11 @@ var Orchestrator = class _Orchestrator {
4672
5255
  if (this.config.compactionResetEnabled) {
4673
5256
  try {
4674
5257
  const wsDir = this.config.workspaceDir || defaultWorkspaceDir();
4675
- const files = await readdir2(wsDir).catch(() => []);
5258
+ const files = await readdir3(wsDir).catch(() => []);
4676
5259
  for (const f of files) {
4677
5260
  if (!f.startsWith(".compaction-reset-signal-")) continue;
4678
- const fp = path3.join(wsDir, f);
4679
- const s = await stat2(fp).catch(() => null);
5261
+ const fp = path4.join(wsDir, f);
5262
+ const s = await stat3(fp).catch(() => null);
4680
5263
  if (s && Date.now() - s.mtimeMs >= COMPACTION_SIGNAL_MAX_AGE_MS) {
4681
5264
  await unlink2(fp).catch(() => {
4682
5265
  });
@@ -4954,9 +5537,9 @@ var Orchestrator = class _Orchestrator {
4954
5537
  `wearables auto-sync started: every ${this.config.wearables.autoSyncIntervalMinutes}m over ${this.config.wearables.autoSyncDays}d (deep ${this.config.wearables.autoSyncDeepDays}d daily)`
4955
5538
  );
4956
5539
  } catch (err) {
4957
- const { displayErrorDetail } = await import("./runtime/better-sqlite.js");
5540
+ const { displayErrorDetail: displayErrorDetail2 } = await import("./runtime/better-sqlite.js");
4958
5541
  log.warn(
4959
- `wearables auto-sync failed to start (non-fatal): ${displayErrorDetail(err)}`
5542
+ `wearables auto-sync failed to start (non-fatal): ${displayErrorDetail2(err)}`
4960
5543
  );
4961
5544
  }
4962
5545
  }
@@ -5069,7 +5652,7 @@ var Orchestrator = class _Orchestrator {
5069
5652
  */
5070
5653
  async autoRegisterDaySummaryCron() {
5071
5654
  const home = resolveHomeDir();
5072
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
5655
+ const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
5073
5656
  try {
5074
5657
  if (!existsSync(jobsPath)) {
5075
5658
  log.debug(
@@ -5122,7 +5705,7 @@ var Orchestrator = class _Orchestrator {
5122
5705
  }
5123
5706
  async autoRegisterNightlyGovernanceCron() {
5124
5707
  const home = resolveHomeDir();
5125
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
5708
+ const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
5126
5709
  try {
5127
5710
  if (!existsSync(jobsPath)) {
5128
5711
  log.debug("nightly governance cron: jobs.json not found, skipping auto-register");
@@ -5144,7 +5727,7 @@ var Orchestrator = class _Orchestrator {
5144
5727
  }
5145
5728
  async autoRegisterProceduralMiningCron() {
5146
5729
  const home = resolveHomeDir();
5147
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
5730
+ const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
5148
5731
  try {
5149
5732
  if (!existsSync(jobsPath)) {
5150
5733
  log.debug("procedural mining cron: jobs.json not found, skipping auto-register");
@@ -5164,7 +5747,7 @@ var Orchestrator = class _Orchestrator {
5164
5747
  }
5165
5748
  async autoRegisterContradictionScanCron() {
5166
5749
  const home = resolveHomeDir();
5167
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
5750
+ const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
5168
5751
  try {
5169
5752
  if (!existsSync(jobsPath)) {
5170
5753
  log.debug("contradiction scan cron: jobs.json not found, skipping auto-register");
@@ -5184,7 +5767,7 @@ var Orchestrator = class _Orchestrator {
5184
5767
  }
5185
5768
  async autoRegisterPatternReinforcementCron() {
5186
5769
  const home = resolveHomeDir();
5187
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
5770
+ const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
5188
5771
  try {
5189
5772
  if (!existsSync(jobsPath)) {
5190
5773
  log.debug("pattern reinforcement cron: jobs.json not found, skipping auto-register");
@@ -5246,7 +5829,7 @@ var Orchestrator = class _Orchestrator {
5246
5829
  }
5247
5830
  async autoRegisterGraphEdgeDecayCron() {
5248
5831
  const home = resolveHomeDir();
5249
- const jobsPath = path3.join(home, ".openclaw", "cron", "jobs.json");
5832
+ const jobsPath = path4.join(home, ".openclaw", "cron", "jobs.json");
5250
5833
  try {
5251
5834
  if (!existsSync(jobsPath)) {
5252
5835
  log.debug("graph edge decay cron: jobs.json not found, skipping auto-register");
@@ -5303,15 +5886,15 @@ ${doc.content}` : doc.content,
5303
5886
  this.lastFileHygieneRunAtMs = now;
5304
5887
  if (hygiene.rotateEnabled) {
5305
5888
  for (const rel of hygiene.rotatePaths) {
5306
- const abs = path3.isAbsolute(rel) ? rel : path3.join(this.config.workspaceDir, rel);
5889
+ const abs = path4.isAbsolute(rel) ? rel : path4.join(this.config.workspaceDir, rel);
5307
5890
  try {
5308
- const raw = await readFile3(abs, "utf-8");
5891
+ const raw = await readFile4(abs, "utf-8");
5309
5892
  if (raw.length > hygiene.rotateMaxBytes) {
5310
- const archiveDir = path3.join(
5893
+ const archiveDir = path4.join(
5311
5894
  this.config.workspaceDir,
5312
5895
  hygiene.archiveDir
5313
5896
  );
5314
- const base = path3.basename(abs);
5897
+ const base = path4.basename(abs);
5315
5898
  const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
5316
5899
  const { newContent } = await rotateMarkdownFileToArchive({
5317
5900
  filePath: abs,
@@ -5319,7 +5902,7 @@ ${doc.content}` : doc.content,
5319
5902
  archivePrefix: prefix,
5320
5903
  keepTailChars: hygiene.rotateKeepTailChars
5321
5904
  });
5322
- await writeFile3(abs, newContent, "utf-8");
5905
+ await writeFile4(abs, newContent, "utf-8");
5323
5906
  }
5324
5907
  } catch {
5325
5908
  }
@@ -5336,8 +5919,8 @@ ${doc.content}` : doc.content,
5336
5919
  log.warn(w.message);
5337
5920
  }
5338
5921
  if (hygiene.warningsLogEnabled && warnings.length > 0) {
5339
- const fp = path3.join(this.config.memoryDir, hygiene.warningsLogPath);
5340
- await mkdir3(path3.dirname(fp), { recursive: true });
5922
+ const fp = path4.join(this.config.memoryDir, hygiene.warningsLogPath);
5923
+ await mkdir4(path4.dirname(fp), { recursive: true });
5341
5924
  const stamp = (/* @__PURE__ */ new Date()).toISOString();
5342
5925
  const block = `
5343
5926
 
@@ -5346,11 +5929,11 @@ ${doc.content}` : doc.content,
5346
5929
  ` + warnings.map((w) => `- ${w.message}`).join("\n") + "\n";
5347
5930
  let existing = "";
5348
5931
  try {
5349
- existing = await readFile3(fp, "utf-8");
5932
+ existing = await readFile4(fp, "utf-8");
5350
5933
  } catch {
5351
5934
  existing = "# Engram File Hygiene Warnings\n";
5352
5935
  }
5353
- await writeFile3(fp, existing + block, "utf-8");
5936
+ await writeFile4(fp, existing + block, "utf-8");
5354
5937
  }
5355
5938
  }
5356
5939
  }
@@ -5820,18 +6403,18 @@ ${evidenceText}`
5820
6403
  const now = options.now instanceof Date && Number.isFinite(options.now.getTime()) ? options.now : /* @__PURE__ */ new Date();
5821
6404
  const targetLocalDate = formatDateInTimeZone(now, timeZone);
5822
6405
  const datesToScan = utcDateKeysForLocalDay(now, timeZone);
5823
- const factsBaseDir = path3.join(storage.dir, "facts");
6406
+ const factsBaseDir = path4.join(storage.dir, "facts");
5824
6407
  const MAX_CHARS = 1e5;
5825
6408
  const facts = [];
5826
6409
  for (const date of datesToScan) {
5827
- const factsDir = path3.join(factsBaseDir, date);
6410
+ const factsDir = path4.join(factsBaseDir, date);
5828
6411
  try {
5829
- const entries = await readdir2(factsDir, { withFileTypes: true });
6412
+ const entries = await readdir3(factsDir, { withFileTypes: true });
5830
6413
  for (const entry of entries) {
5831
6414
  if (!entry.name.endsWith(".md")) continue;
5832
- const fullPath = path3.join(factsDir, entry.name);
6415
+ const fullPath = path4.join(factsDir, entry.name);
5833
6416
  try {
5834
- const raw = await readFile3(fullPath, "utf-8");
6417
+ const raw = await readFile4(fullPath, "utf-8");
5835
6418
  const fmMatch = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
5836
6419
  if (!fmMatch) continue;
5837
6420
  const fmBlock = fmMatch[1];
@@ -5850,7 +6433,7 @@ ${evidenceText}`
5850
6433
  facts.push({
5851
6434
  path: fullPath,
5852
6435
  frontmatter: {
5853
- id: fm.id || path3.basename(entry.name, ".md"),
6436
+ id: fm.id || path4.basename(entry.name, ".md"),
5854
6437
  category: fm.category || "fact",
5855
6438
  created,
5856
6439
  updated: fm.updated || created,
@@ -5872,15 +6455,15 @@ ${evidenceText}`
5872
6455
  return a.frontmatter.created < b.frontmatter.created ? -1 : 1;
5873
6456
  });
5874
6457
  const hourlySummaries = [];
5875
- const hourlyBaseDir = path3.join(storage.dir, "summaries", "hourly");
6458
+ const hourlyBaseDir = path4.join(storage.dir, "summaries", "hourly");
5876
6459
  try {
5877
- const sessionKeys = await readdir2(hourlyBaseDir, { withFileTypes: true });
6460
+ const sessionKeys = await readdir3(hourlyBaseDir, { withFileTypes: true });
5878
6461
  for (const sk of sessionKeys) {
5879
6462
  if (!sk.isDirectory()) continue;
5880
6463
  for (const date of datesToScan) {
5881
- const summaryFile = path3.join(hourlyBaseDir, sk.name, `${date}.md`);
6464
+ const summaryFile = path4.join(hourlyBaseDir, sk.name, `${date}.md`);
5882
6465
  try {
5883
- const raw = await readFile3(summaryFile, "utf-8");
6466
+ const raw = await readFile4(summaryFile, "utf-8");
5884
6467
  const filtered = filterHourlySummaryMarkdownForLocalDay(
5885
6468
  raw,
5886
6469
  date,
@@ -5982,13 +6565,13 @@ ${evidenceText}`
5982
6565
  }
5983
6566
  async getLastGraphRecallSnapshot(namespace) {
5984
6567
  const storage = await this.getStorage(namespace);
5985
- const snapshotPath = path3.join(
6568
+ const snapshotPath = path4.join(
5986
6569
  storage.dir,
5987
6570
  "state",
5988
6571
  "last_graph_recall.json"
5989
6572
  );
5990
6573
  try {
5991
- const raw = await readFile3(snapshotPath, "utf-8");
6574
+ const raw = await readFile4(snapshotPath, "utf-8");
5992
6575
  const parsed = JSON.parse(raw);
5993
6576
  if (!parsed || typeof parsed !== "object") return null;
5994
6577
  return {
@@ -6021,9 +6604,9 @@ ${evidenceText}`
6021
6604
  }
6022
6605
  async getLastIntentSnapshot(namespace) {
6023
6606
  const storage = await this.getStorage(namespace);
6024
- const snapshotPath = path3.join(storage.dir, "state", "last_intent.json");
6607
+ const snapshotPath = path4.join(storage.dir, "state", "last_intent.json");
6025
6608
  try {
6026
- const raw = await readFile3(snapshotPath, "utf-8");
6609
+ const raw = await readFile4(snapshotPath, "utf-8");
6027
6610
  const parsed = JSON.parse(raw);
6028
6611
  if (!parsed || typeof parsed !== "object") return null;
6029
6612
  const graphDecision = parsed.graphDecision && typeof parsed.graphDecision === "object" ? parsed.graphDecision : void 0;
@@ -6054,13 +6637,13 @@ ${evidenceText}`
6054
6637
  }
6055
6638
  async getLastQmdRecallSnapshot(namespace) {
6056
6639
  const storage = await this.getStorage(namespace);
6057
- const snapshotPath = path3.join(
6640
+ const snapshotPath = path4.join(
6058
6641
  storage.dir,
6059
6642
  "state",
6060
6643
  "last_qmd_recall.json"
6061
6644
  );
6062
6645
  try {
6063
- const raw = await readFile3(snapshotPath, "utf-8");
6646
+ const raw = await readFile4(snapshotPath, "utf-8");
6064
6647
  const parsed = JSON.parse(raw);
6065
6648
  if (!parsed || typeof parsed !== "object") return null;
6066
6649
  return {
@@ -6204,10 +6787,10 @@ ${r.snippet.trim()}
6204
6787
  }
6205
6788
  async countConversationChunkDocs(dir) {
6206
6789
  try {
6207
- const entries = await readdir2(dir, { withFileTypes: true });
6790
+ const entries = await readdir3(dir, { withFileTypes: true });
6208
6791
  let total = 0;
6209
6792
  for (const entry of entries) {
6210
- const fullPath = path3.join(dir, entry.name);
6793
+ const fullPath = path4.join(dir, entry.name);
6211
6794
  if (entry.isDirectory()) {
6212
6795
  total += await this.countConversationChunkDocs(fullPath);
6213
6796
  continue;
@@ -6933,7 +7516,7 @@ ${r.snippet.trim()}
6933
7516
  if (!options.onDebugSnapshot) return;
6934
7517
  await options.onDebugSnapshot({
6935
7518
  recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
6936
- queryHash: createHash("sha256").update(prompt).digest("hex"),
7519
+ queryHash: createHash2("sha256").update(prompt).digest("hex"),
6937
7520
  queryLength: prompt.length,
6938
7521
  collection: options.collection,
6939
7522
  namespaces: options.recallNamespaces,
@@ -7106,7 +7689,7 @@ ${r.snippet.trim()}
7106
7689
  resolvedPath = resolvedCold.result.path;
7107
7690
  resolvedResult = resolvedCold.result;
7108
7691
  }
7109
- if (!path3.isAbsolute(resolvedPath)) {
7692
+ if (!path4.isAbsolute(resolvedPath)) {
7110
7693
  resolvedAmbiguousSeeds.set(result.path, null);
7111
7694
  return null;
7112
7695
  }
@@ -7131,7 +7714,7 @@ ${r.snippet.trim()}
7131
7714
  }
7132
7715
  continue;
7133
7716
  }
7134
- if (path3.isAbsolute(result.path)) {
7717
+ if (path4.isAbsolute(result.path)) {
7135
7718
  const resolved = await resolveAmbiguousSeedOwner(result, null);
7136
7719
  if (resolved) {
7137
7720
  addResultForNamespace(resolved.namespace, resolved.result);
@@ -7174,7 +7757,7 @@ ${r.snippet.trim()}
7174
7757
  0
7175
7758
  );
7176
7759
  seedPaths.push(
7177
- ...seedRelativePaths.map((rel) => path3.join(storage.dir, rel))
7760
+ ...seedRelativePaths.map((rel) => path4.join(storage.dir, rel))
7178
7761
  );
7179
7762
  const seedSet = new Set(seedRelativePaths);
7180
7763
  const expanded = await this.graphIndexFor(storage).spreadingActivation(
@@ -7190,7 +7773,7 @@ ${r.snippet.trim()}
7190
7773
  for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
7191
7774
  if (deadlineExpired()) break;
7192
7775
  if (seedSet.has(candidate.path)) continue;
7193
- const memoryPath = path3.resolve(storage.dir, candidate.path);
7776
+ const memoryPath = path4.resolve(storage.dir, candidate.path);
7194
7777
  const memory = await storage.readMemoryByPath(memoryPath);
7195
7778
  if (deadlineExpired()) break;
7196
7779
  if (!memory) continue;
@@ -7215,7 +7798,7 @@ ${r.snippet.trim()}
7215
7798
  path: memory.path,
7216
7799
  score,
7217
7800
  namespace,
7218
- seed: path3.resolve(storage.dir, candidate.seed),
7801
+ seed: path4.resolve(storage.dir, candidate.seed),
7219
7802
  hopDepth: candidate.hopDepth,
7220
7803
  decayedWeight: candidate.decayedWeight,
7221
7804
  graphType: candidate.graphType,
@@ -7236,12 +7819,12 @@ ${r.snippet.trim()}
7236
7819
  }
7237
7820
  async recordLastGraphRecallSnapshot(options) {
7238
7821
  try {
7239
- const snapshotPath = path3.join(
7822
+ const snapshotPath = path4.join(
7240
7823
  options.storage.dir,
7241
7824
  "state",
7242
7825
  "last_graph_recall.json"
7243
7826
  );
7244
- await mkdir3(path3.dirname(snapshotPath), { recursive: true });
7827
+ await mkdir4(path4.dirname(snapshotPath), { recursive: true });
7245
7828
  const now = (/* @__PURE__ */ new Date()).toISOString();
7246
7829
  const totalSeedCount = options.seedPaths.length;
7247
7830
  const totalExpandedCount = options.expandedPaths.length;
@@ -7253,7 +7836,7 @@ ${r.snippet.trim()}
7253
7836
  const payload = {
7254
7837
  recordedAt: now,
7255
7838
  mode: options.recallMode,
7256
- queryHash: createHash("sha256").update(options.prompt).digest("hex"),
7839
+ queryHash: createHash2("sha256").update(options.prompt).digest("hex"),
7257
7840
  queryLength: options.prompt.length,
7258
7841
  namespaces: options.recallNamespaces,
7259
7842
  seedCount: totalSeedCount,
@@ -7268,20 +7851,20 @@ ${r.snippet.trim()}
7268
7851
  finalResults: (options.finalResults ?? []).slice(0, 64),
7269
7852
  shadowComparison: options.shadowComparison
7270
7853
  };
7271
- await writeFile3(snapshotPath, JSON.stringify(payload, null, 2), "utf-8");
7854
+ await writeFile4(snapshotPath, JSON.stringify(payload, null, 2), "utf-8");
7272
7855
  } catch (err) {
7273
7856
  log.debug(`last graph recall write failed: ${err}`);
7274
7857
  }
7275
7858
  }
7276
7859
  async recordLastIntentSnapshot(options) {
7277
7860
  try {
7278
- const snapshotPath = path3.join(
7861
+ const snapshotPath = path4.join(
7279
7862
  options.storage.dir,
7280
7863
  "state",
7281
7864
  "last_intent.json"
7282
7865
  );
7283
- await mkdir3(path3.dirname(snapshotPath), { recursive: true });
7284
- await writeFile3(
7866
+ await mkdir4(path4.dirname(snapshotPath), { recursive: true });
7867
+ await writeFile4(
7285
7868
  snapshotPath,
7286
7869
  JSON.stringify(options.snapshot, null, 2),
7287
7870
  "utf-8"
@@ -7292,13 +7875,13 @@ ${r.snippet.trim()}
7292
7875
  }
7293
7876
  async recordLastQmdRecallSnapshot(options) {
7294
7877
  try {
7295
- const snapshotPath = path3.join(
7878
+ const snapshotPath = path4.join(
7296
7879
  options.storage.dir,
7297
7880
  "state",
7298
7881
  "last_qmd_recall.json"
7299
7882
  );
7300
- await mkdir3(path3.dirname(snapshotPath), { recursive: true });
7301
- await writeFile3(
7883
+ await mkdir4(path4.dirname(snapshotPath), { recursive: true });
7884
+ await writeFile4(
7302
7885
  snapshotPath,
7303
7886
  JSON.stringify(options.snapshot, null, 2),
7304
7887
  "utf-8"
@@ -7312,9 +7895,9 @@ ${r.snippet.trim()}
7312
7895
  const stateDir = await this.resolveStateDirForNamespace(
7313
7896
  options.namespace
7314
7897
  );
7315
- const snapshotPath = path3.join(stateDir, "last_intent.json");
7316
- await mkdir3(path3.dirname(snapshotPath), { recursive: true });
7317
- await writeFile3(
7898
+ const snapshotPath = path4.join(stateDir, "last_intent.json");
7899
+ await mkdir4(path4.dirname(snapshotPath), { recursive: true });
7900
+ await writeFile4(
7318
7901
  snapshotPath,
7319
7902
  JSON.stringify(options.snapshot, null, 2),
7320
7903
  "utf-8"
@@ -7325,24 +7908,24 @@ ${r.snippet.trim()}
7325
7908
  }
7326
7909
  async resolveStateDirForNamespace(namespace) {
7327
7910
  if (!this.config.namespacesEnabled) {
7328
- return path3.join(this.config.memoryDir, "state");
7911
+ return path4.join(this.config.memoryDir, "state");
7329
7912
  }
7330
7913
  if (namespace !== this.config.defaultNamespace) {
7331
- return path3.join(this.config.memoryDir, "namespaces", namespace, "state");
7914
+ return path4.join(this.config.memoryDir, "namespaces", namespace, "state");
7332
7915
  }
7333
- const candidate = path3.join(
7916
+ const candidate = path4.join(
7334
7917
  this.config.memoryDir,
7335
7918
  "namespaces",
7336
7919
  this.config.defaultNamespace
7337
7920
  );
7338
7921
  try {
7339
- const candidateStat = await stat2(candidate);
7922
+ const candidateStat = await stat3(candidate);
7340
7923
  if (candidateStat.isDirectory()) {
7341
- return path3.join(candidate, "state");
7924
+ return path4.join(candidate, "state");
7342
7925
  }
7343
7926
  } catch {
7344
7927
  }
7345
- return path3.join(this.config.memoryDir, "state");
7928
+ return path4.join(this.config.memoryDir, "state");
7346
7929
  }
7347
7930
  buildGraphRecallRankedResults(results, sourceLabelResolver, limit = 64) {
7348
7931
  return results.slice(0, limit).map((result) => ({
@@ -7584,8 +8167,8 @@ ${r.snippet.trim()}
7584
8167
  timings,
7585
8168
  logger: log
7586
8169
  });
7587
- const promptHash = createHash("sha256").update(prompt).digest("hex");
7588
- const traceId = createHash("sha256").update(`${sessionKey ?? "default"}:${recallStart}:${promptHash}`).digest("hex").slice(0, 16);
8170
+ const promptHash = createHash2("sha256").update(prompt).digest("hex");
8171
+ const traceId = createHash2("sha256").update(`${sessionKey ?? "default"}:${recallStart}:${promptHash}`).digest("hex").slice(0, 16);
7589
8172
  const sectionBuckets = /* @__PURE__ */ new Map();
7590
8173
  const queryPolicy = buildRecallQueryPolicy(prompt, sessionKey, {
7591
8174
  cronRecallPolicyEnabled: this.config.cronRecallPolicyEnabled,
@@ -7594,7 +8177,7 @@ ${r.snippet.trim()}
7594
8177
  cronConversationRecallMode: this.config.cronConversationRecallMode
7595
8178
  });
7596
8179
  const retrievalQuery = queryPolicy.retrievalQuery || prompt;
7597
- const retrievalQueryHash = createHash("sha256").update(retrievalQuery).digest("hex");
8180
+ const retrievalQueryHash = createHash2("sha256").update(retrievalQuery).digest("hex");
7598
8181
  const policyVersion = this.currentPolicyVersion();
7599
8182
  let impressionRecorded = false;
7600
8183
  let recallSource = "none";
@@ -7752,7 +8335,7 @@ ${r.snippet.trim()}
7752
8335
  const graphExpandedResultPaths = /* @__PURE__ */ new Set();
7753
8336
  const graphSourceLabelsForPath = (resultPath) => {
7754
8337
  const labels = [];
7755
- const normalizedPath = resultPath.split(path3.sep).join("/");
8338
+ const normalizedPath = resultPath.split(path4.sep).join("/");
7756
8339
  const isEntityPath = normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/");
7757
8340
  if (graphBaselinePaths.has(resultPath)) labels.push("baseline");
7758
8341
  if (graphExpandedResultPaths.has(resultPath))
@@ -9070,16 +9653,16 @@ ${formatted}`;
9070
9653
  if (!this.config.compactionResetEnabled) return null;
9071
9654
  const workspaceDir = compactionWorkspaceDir || this.config.workspaceDir || defaultWorkspaceDir();
9072
9655
  const safeSessionKey = sanitizeSessionKeyForFilename(effectiveSessionKey);
9073
- const signalPath = path3.join(
9656
+ const signalPath = path4.join(
9074
9657
  workspaceDir,
9075
9658
  `.compaction-reset-signal-${safeSessionKey}`
9076
9659
  );
9077
- const bootPath = path3.join(workspaceDir, "BOOT.md");
9660
+ const bootPath = path4.join(workspaceDir, "BOOT.md");
9078
9661
  try {
9079
- const signalStat = await stat2(signalPath).catch(() => null);
9662
+ const signalStat = await stat3(signalPath).catch(() => null);
9080
9663
  if (!signalStat) return null;
9081
9664
  const signalAge = Date.now() - signalStat.mtimeMs;
9082
- const signalData = JSON.parse(await readFile3(signalPath, "utf-8"));
9665
+ const signalData = JSON.parse(await readFile4(signalPath, "utf-8"));
9083
9666
  if (signalData.sessionKey !== effectiveSessionKey) {
9084
9667
  log.debug(
9085
9668
  `recall: compaction signal is for ${signalData.sessionKey}, not ${effectiveSessionKey} \u2014 skipping`
@@ -9099,7 +9682,7 @@ ${formatted}`;
9099
9682
 
9100
9683
  `;
9101
9684
  try {
9102
- const bootContent = await readFile3(bootPath, "utf-8");
9685
+ const bootContent = await readFile4(bootPath, "utf-8");
9103
9686
  section += "### BOOT.md (working state before compaction)\n\n";
9104
9687
  section += bootContent + "\n";
9105
9688
  } catch {
@@ -11204,7 +11787,7 @@ _Context: ${topQuestion.context}_`
11204
11787
  const shouldUseStableBatchKey = turns.some(
11205
11788
  (turn) => turn.persistProcessedFingerprint === true || typeof turn.turnFingerprint === "string" && turn.turnFingerprint.length > 0
11206
11789
  );
11207
- const stableBatchFingerprint = shouldUseStableBatchKey ? createHash("sha256").update(
11790
+ const stableBatchFingerprint = shouldUseStableBatchKey ? createHash2("sha256").update(
11208
11791
  turns.map(
11209
11792
  (turn) => [
11210
11793
  turn.role,
@@ -11461,7 +12044,7 @@ _Context: ${topQuestion.context}_`
11461
12044
  buildExtractionFingerprint(turns, bufferKey) {
11462
12045
  const normalized = this.normalizeExtractionFingerprintTurns(turns).join("\n");
11463
12046
  if (!normalized) return null;
11464
- return createHash("sha256").update(`${bufferKey}
12047
+ return createHash2("sha256").update(`${bufferKey}
11465
12048
  ${normalized}`).digest("hex");
11466
12049
  }
11467
12050
  shouldQueueExtraction(turns, options = {}) {
@@ -11951,7 +12534,7 @@ ${normalized}`).digest("hex");
11951
12534
  );
11952
12535
  this.tierMigrationInFlight = true;
11953
12536
  try {
11954
- const coldStorage = new StorageManager(path3.join(storage.dir, "cold"));
12537
+ const coldStorage = new StorageManager(path4.join(storage.dir, "cold"));
11955
12538
  const [hotMemories, coldMemories] = await Promise.all([
11956
12539
  storage.readAllMemories(),
11957
12540
  coldStorage.readAllMemories()
@@ -12095,13 +12678,61 @@ ${normalized}`).digest("hex");
12095
12678
  this.qmdMaintenancePending = false;
12096
12679
  try {
12097
12680
  if (this.config.namespacesEnabled) {
12098
- const maintenanceNamespaces = await this.maintenanceNamespaces();
12099
- await this.namespaceSearchRouter.updateNamespaces(maintenanceNamespaces);
12681
+ const plan = await this.namespaceMaintenancePlan("qmd");
12100
12682
  const now = Date.now();
12101
- if (this.config.qmdAutoEmbedEnabled && now - this.lastQmdEmbedAtMs >= this.config.qmdEmbedMinIntervalMs) {
12102
- await this.namespaceSearchRouter.embedNamespaces(maintenanceNamespaces);
12683
+ const lastEmbedAtByNamespace = this.lastQmdEmbedAtMsByNamespace ?? (this.lastQmdEmbedAtMsByNamespace = /* @__PURE__ */ new Map());
12684
+ const dueEmbedNamespaces = (namespaces) => {
12685
+ if (!this.config.qmdAutoEmbedEnabled) return [];
12686
+ return namespaces.filter(
12687
+ (namespace) => now - (lastEmbedAtByNamespace.get(namespace) ?? 0) >= this.config.qmdEmbedMinIntervalMs
12688
+ );
12689
+ };
12690
+ const markEmbedded = (namespaces) => {
12691
+ if (namespaces.length === 0) return;
12692
+ for (const namespace of namespaces) {
12693
+ lastEmbedAtByNamespace.set(namespace, now);
12694
+ }
12103
12695
  this.lastQmdEmbedAtMs = now;
12104
- }
12696
+ };
12697
+ await runNamespaceMaintenanceBatchPlan(
12698
+ this.config,
12699
+ plan,
12700
+ async (candidates) => {
12701
+ const namespaces = candidates.map((candidate) => candidate.namespace);
12702
+ const embedNamespaces = dueEmbedNamespaces(namespaces);
12703
+ let result;
12704
+ try {
12705
+ result = await this.namespaceSearchRouter.updateNamespacesDetailed(
12706
+ namespaces,
12707
+ void 0,
12708
+ { strict: true }
12709
+ );
12710
+ } catch (error) {
12711
+ if (embedNamespaces.length > 0 && qmdMaintenanceSkipReasonForError(error) === "throttled") {
12712
+ await this.namespaceSearchRouter.embedNamespaces(embedNamespaces, { strict: true });
12713
+ markEmbedded(embedNamespaces);
12714
+ }
12715
+ throw error;
12716
+ }
12717
+ if (result.backendCount <= 0) {
12718
+ throw new Error("no eligible QMD backend for selected namespaces");
12719
+ }
12720
+ if (result.eligibleNamespaces.length !== namespaces.length) {
12721
+ const eligible = new Set(result.eligibleNamespaces);
12722
+ const missing = namespaces.filter((namespace) => !eligible.has(namespace));
12723
+ throw new Error(`QMD backend ineligible for selected namespaces (${missing.length})`);
12724
+ }
12725
+ if (embedNamespaces.length > 0) {
12726
+ await this.namespaceSearchRouter.embedNamespaces(embedNamespaces, { strict: true });
12727
+ markEmbedded(embedNamespaces);
12728
+ }
12729
+ return { itemCount: result.backendCount };
12730
+ },
12731
+ this.namespaceCatalog,
12732
+ {
12733
+ skipReasonForError: qmdMaintenanceSkipReasonForError
12734
+ }
12735
+ );
12105
12736
  } else {
12106
12737
  await this.qmd.update();
12107
12738
  const now = Date.now();
@@ -13196,7 +13827,7 @@ ${normalized}`).digest("hex");
13196
13827
  const allMems = allMemsForGraph ?? [];
13197
13828
  for (const m of allMems) {
13198
13829
  if (m.frontmatter.entityRef === entityRef) {
13199
- const rel = path3.relative(storage.dir, m.path);
13830
+ const rel = path4.relative(storage.dir, m.path);
13200
13831
  if (rel !== memoryRelPath) entitySiblings.push(rel);
13201
13832
  }
13202
13833
  }
@@ -13512,14 +14143,14 @@ ${normalized}`).digest("hex");
13512
14143
  }
13513
14144
  if (this.config.semanticConsolidationEnabled) {
13514
14145
  try {
13515
- const stateFilePath = path3.join(
14146
+ const stateFilePath = path4.join(
13516
14147
  this.config.memoryDir,
13517
14148
  "state",
13518
14149
  "semantic-consolidation-last-run.json"
13519
14150
  );
13520
14151
  let shouldRun = true;
13521
14152
  try {
13522
- const stateRaw = await readFile3(stateFilePath, "utf-8");
14153
+ const stateRaw = await readFile4(stateFilePath, "utf-8");
13523
14154
  const stateData = JSON.parse(stateRaw);
13524
14155
  if (stateData.lastRunAt) {
13525
14156
  const lastRunMs = new Date(stateData.lastRunAt).getTime();
@@ -13560,9 +14191,9 @@ ${normalized}`).digest("hex");
13560
14191
  );
13561
14192
  }
13562
14193
  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(
14194
+ const stateDir = path4.join(this.config.memoryDir, "state");
14195
+ await mkdir4(stateDir, { recursive: true });
14196
+ await writeFile4(
13566
14197
  stateFilePath,
13567
14198
  JSON.stringify({ lastRunAt: (/* @__PURE__ */ new Date()).toISOString() }),
13568
14199
  "utf-8"
@@ -13761,7 +14392,7 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
13761
14392
  }
13762
14393
  });
13763
14394
  const content = renderCompressionGuidelinesMarkdown(refinedCandidate);
13764
- const contentHash = createHash("sha256").update(content).digest("hex");
14395
+ const contentHash = createHash2("sha256").update(content).digest("hex");
13765
14396
  const semanticRefinementApplied = JSON.stringify(refinedCandidate.ruleUpdates) !== JSON.stringify(candidate.ruleUpdates);
13766
14397
  const changedRules = refinedCandidate.ruleUpdates.filter(
13767
14398
  (rule) => rule.delta !== 0
@@ -14064,13 +14695,13 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
14064
14695
  protectedCategories: this.config.lifecycleProtectedCategories
14065
14696
  }
14066
14697
  };
14067
- const metricsPath = path3.join(
14698
+ const metricsPath = path4.join(
14068
14699
  storage.dir,
14069
14700
  "state",
14070
14701
  "lifecycle-metrics.json"
14071
14702
  );
14072
- await mkdir3(path3.dirname(metricsPath), { recursive: true });
14073
- await writeFile3(metricsPath, JSON.stringify(metrics, null, 2), "utf-8");
14703
+ await mkdir4(path4.dirname(metricsPath), { recursive: true });
14704
+ await writeFile4(metricsPath, JSON.stringify(metrics, null, 2), "utf-8");
14074
14705
  return updatedCount;
14075
14706
  }
14076
14707
  /**
@@ -14603,7 +15234,7 @@ ${lines.join("\n\n")}`;
14603
15234
  const seenStorageDirs = /* @__PURE__ */ new Set();
14604
15235
  const addStorage = (storage) => {
14605
15236
  const storageDir = storageDirFor(storage);
14606
- const storageKey = storageDir ? path3.resolve(storageDir) : `storage-without-dir-${storages.length}`;
15237
+ const storageKey = storageDir ? path4.resolve(storageDir) : `storage-without-dir-${storages.length}`;
14607
15238
  if (seenStorageDirs.has(storageKey)) return;
14608
15239
  seenStorageDirs.add(storageKey);
14609
15240
  storages.push(storage);
@@ -14633,7 +15264,7 @@ ${lines.join("\n\n")}`;
14633
15264
  continue;
14634
15265
  }
14635
15266
  try {
14636
- const coldRoot = path3.join(storageDir, "cold");
15267
+ const coldRoot = path4.join(storageDir, "cold");
14637
15268
  for (const candidate of qmdResultPathCandidates(
14638
15269
  coldRoot,
14639
15270
  parts.relativePath
@@ -14674,7 +15305,7 @@ ${lines.join("\n\n")}`;
14674
15305
  return null;
14675
15306
  }
14676
15307
  }
14677
- if (path3.isAbsolute(resultPath)) {
15308
+ if (path4.isAbsolute(resultPath)) {
14678
15309
  if (!fallbackStorageDir) {
14679
15310
  return await fallbackStorage.readMemoryByPath(resultPath);
14680
15311
  }
@@ -14713,7 +15344,7 @@ ${lines.join("\n\n")}`;
14713
15344
  );
14714
15345
  if (!memory) return null;
14715
15346
  let ownerNamespace = null;
14716
- if (path3.isAbsolute(memory.path)) {
15347
+ if (path4.isAbsolute(memory.path)) {
14717
15348
  const ownerStorage = await this.storageForAbsoluteQmdResultPath(
14718
15349
  memory.path,
14719
15350
  fallbackStorage,
@@ -14737,16 +15368,16 @@ ${lines.join("\n\n")}`;
14737
15368
  };
14738
15369
  }
14739
15370
  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");
15371
+ const resolvedPath = path4.resolve(resultPath);
15372
+ const memoryRoot = path4.resolve(this.config.memoryDir);
15373
+ const namespacesRoot = path4.join(memoryRoot, "namespaces");
14743
15374
  const fallbackStorageDir = typeof fallbackStorage.dir === "string" && fallbackStorage.dir ? fallbackStorage.dir : null;
14744
15375
  const matches = [];
14745
15376
  const seenDirs = /* @__PURE__ */ new Set();
14746
15377
  const maybeAddStorage = (storage, namespace) => {
14747
15378
  const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
14748
15379
  if (!storageDir) return;
14749
- const candidateRoot = path3.resolve(storageDir);
15380
+ const candidateRoot = path4.resolve(storageDir);
14750
15381
  if (seenDirs.has(candidateRoot)) return;
14751
15382
  if (!isPathInsideStorageRoot(candidateRoot, resolvedPath)) return;
14752
15383
  if (candidateRoot === memoryRoot && isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
@@ -14764,7 +15395,7 @@ ${lines.join("\n\n")}`;
14764
15395
  candidateNamespaces.add(ns);
14765
15396
  }
14766
15397
  if (isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
14767
- const relativeToNamespaces = path3.relative(namespacesRoot, resolvedPath);
15398
+ const relativeToNamespaces = path4.relative(namespacesRoot, resolvedPath);
14768
15399
  const [namespaceSegment] = relativeToNamespaces.split(/[\\/]/);
14769
15400
  if (namespaceSegment) {
14770
15401
  candidateNamespaces.add(
@@ -14809,7 +15440,7 @@ ${lines.join("\n\n")}`;
14809
15440
  nsMap = buildMemoryWorthCounterMap(memories);
14810
15441
  this.memoryWorthCounterCache.set(ns, { at: nowMs, counters: nsMap });
14811
15442
  }
14812
- for (const [path4, c] of nsMap) counters.set(path4, c);
15443
+ for (const [path5, c] of nsMap) counters.set(path5, c);
14813
15444
  } catch (err) {
14814
15445
  log.debug("memory-worth: failed to read namespace, skipping", {
14815
15446
  namespace: ns,
@@ -14980,12 +15611,12 @@ ${lines.join("\n\n")}`;
14980
15611
  */
14981
15612
  semanticDedupScopeFor(targetStorage) {
14982
15613
  if (!this.config.namespacesEnabled) return {};
14983
- const memoryDir = path3.resolve(this.config.memoryDir);
14984
- const storageDir = path3.resolve(targetStorage.dir);
15614
+ const memoryDir = path4.resolve(this.config.memoryDir);
15615
+ const storageDir = path4.resolve(targetStorage.dir);
14985
15616
  if (storageDir === memoryDir) {
14986
15617
  return { pathExcludePrefixes: ["namespaces/"] };
14987
15618
  }
14988
- let rel = path3.relative(memoryDir, storageDir);
15619
+ let rel = path4.relative(memoryDir, storageDir);
14989
15620
  if (!rel || rel.startsWith("..")) {
14990
15621
  log.debug(
14991
15622
  `semantic dedup: target storage dir ${storageDir} is outside memoryDir ${memoryDir}; scoping lookup to absolute path prefix`
@@ -15004,7 +15635,7 @@ ${lines.join("\n\n")}`;
15004
15635
  if (hits.length === 0) return [];
15005
15636
  const results = [];
15006
15637
  for (const hit of hits) {
15007
- const fullPath = path3.isAbsolute(hit.path) ? hit.path : path3.join(this.config.memoryDir, hit.path);
15638
+ const fullPath = path4.isAbsolute(hit.path) ? hit.path : path4.join(this.config.memoryDir, hit.path);
15008
15639
  const memory = await this.storage.readMemoryByPath(fullPath);
15009
15640
  if (!memory) continue;
15010
15641
  results.push({
@@ -15179,7 +15810,7 @@ ${lines.join("\n\n")}`;
15179
15810
  const storage = await this.storageRouter.storageFor(namespace);
15180
15811
  const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
15181
15812
  if (!storageDir) continue;
15182
- const recallRoot = path3.resolve(storageDir);
15813
+ const recallRoot = path4.resolve(storageDir);
15183
15814
  if (seenRecallRoots.has(recallRoot)) continue;
15184
15815
  seenRecallRoots.add(recallRoot);
15185
15816
  recallRoots.push(recallRoot);
@@ -15203,8 +15834,8 @@ ${lines.join("\n\n")}`;
15203
15834
  if (resolvedCold) scopedResults.push(resolvedCold.result);
15204
15835
  continue;
15205
15836
  }
15206
- if (path3.isAbsolute(result.path)) {
15207
- const resolvedPath = path3.resolve(result.path);
15837
+ if (path4.isAbsolute(result.path)) {
15838
+ const resolvedPath = path4.resolve(result.path);
15208
15839
  if (recallRoots.some(
15209
15840
  (recallRoot) => isPathInsideStorageRoot(recallRoot, resolvedPath)
15210
15841
  )) {
@@ -15945,8 +16576,8 @@ ${lines.join("\n\n")}`;
15945
16576
  }
15946
16577
  namespaceFromStorageDir(storageDir) {
15947
16578
  if (!this.config.namespacesEnabled) return this.config.defaultNamespace;
15948
- const resolvedStorageDir = path3.resolve(storageDir);
15949
- const resolvedMemoryDir = path3.resolve(this.config.memoryDir);
16579
+ const resolvedStorageDir = path4.resolve(storageDir);
16580
+ const resolvedMemoryDir = path4.resolve(this.config.memoryDir);
15950
16581
  if (resolvedStorageDir === resolvedMemoryDir)
15951
16582
  return this.config.defaultNamespace;
15952
16583
  const m = resolvedStorageDir.match(/[\\/]namespaces[\\/]([^\\/]+)$/);
@@ -16076,4 +16707,4 @@ export {
16076
16707
  resolvePersistedMemoryRelativePath,
16077
16708
  Orchestrator
16078
16709
  };
16079
- //# sourceMappingURL=chunk-OL2364SB.js.map
16710
+ //# sourceMappingURL=chunk-5QD3QD76.js.map