@remnic/core 9.3.653 → 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 (273) hide show
  1. package/dist/access-cli.js +24 -24
  2. package/dist/access-http.d.ts +4 -4
  3. package/dist/access-http.js +17 -17
  4. package/dist/access-mcp.d.ts +4 -4
  5. package/dist/access-mcp.js +16 -16
  6. package/dist/access-schema.d.ts +12 -12
  7. package/dist/{access-service-CdJFd3_b.d.ts → access-service-BEJvriUt.d.ts} +11 -2
  8. package/dist/access-service.d.ts +4 -4
  9. package/dist/access-service.js +15 -15
  10. package/dist/action-confidence.d.ts +1 -1
  11. package/dist/active-memory-bridge.d.ts +1 -1
  12. package/dist/active-recall.d.ts +1 -1
  13. package/dist/active-recall.js +1 -1
  14. package/dist/behavior-learner.d.ts +1 -1
  15. package/dist/behavior-signals.d.ts +1 -1
  16. package/dist/bootstrap.d.ts +3 -3
  17. package/dist/briefing.d.ts +1 -1
  18. package/dist/briefing.js +3 -3
  19. package/dist/buffer-surprise-report.d.ts +1 -1
  20. package/dist/buffer.d.ts +1 -1
  21. package/dist/calibration.d.ts +1 -1
  22. package/dist/causal-behavior.d.ts +1 -1
  23. package/dist/causal-consolidation.d.ts +1 -1
  24. package/dist/causal-consolidation.js +4 -4
  25. package/dist/{chunk-GI45G4BK.js → chunk-2RCGZ67B.js} +4 -4
  26. package/dist/{chunk-BEMWL2FZ.js → chunk-54LOUIBE.js} +2 -2
  27. package/dist/{chunk-E3J6O6N7.js → chunk-55ZMNKMQ.js} +20 -9
  28. package/dist/{chunk-E3J6O6N7.js.map → chunk-55ZMNKMQ.js.map} +1 -1
  29. package/dist/{chunk-7WEB3FLJ.js → chunk-5PLUC5OB.js} +2 -2
  30. package/dist/{chunk-SPMZZUEJ.js → chunk-5QD3QD76.js} +2684 -401
  31. package/dist/chunk-5QD3QD76.js.map +1 -0
  32. package/dist/{chunk-WLGE6KEO.js → chunk-67G4T7KI.js} +3 -3
  33. package/dist/{chunk-JX2RINDR.js → chunk-6G5JEN55.js} +2 -2
  34. package/dist/{chunk-R3PQUPQ4.js → chunk-6IMKOIZ6.js} +85 -3
  35. package/dist/chunk-6IMKOIZ6.js.map +1 -0
  36. package/dist/{chunk-KJDKZVF3.js → chunk-A3Y37UWI.js} +3 -3
  37. package/dist/{chunk-CFOCZPIQ.js → chunk-BGKXTVNG.js} +2 -2
  38. package/dist/{chunk-QQHIQ7JD.js → chunk-COVZLGMR.js} +87 -18
  39. package/dist/chunk-COVZLGMR.js.map +1 -0
  40. package/dist/{chunk-JVRPJ7D4.js → chunk-EKQMQQ3U.js} +48 -12
  41. package/dist/chunk-EKQMQQ3U.js.map +1 -0
  42. package/dist/{chunk-H3PHZLMF.js → chunk-GKKAXVAJ.js} +20 -11
  43. package/dist/chunk-GKKAXVAJ.js.map +1 -0
  44. package/dist/{chunk-JBHXMCYN.js → chunk-GRYAECRV.js} +2 -2
  45. package/dist/{chunk-EHQLDFSH.js → chunk-IQ53ZSXV.js} +2 -2
  46. package/dist/{chunk-C63WC454.js → chunk-KOI765XP.js} +125 -1
  47. package/dist/chunk-KOI765XP.js.map +1 -0
  48. package/dist/{chunk-IVYSVAC6.js → chunk-KZZ4YAEC.js} +2 -2
  49. package/dist/{chunk-2DGQLOOM.js → chunk-M3VYPE2H.js} +1 -1
  50. package/dist/{chunk-2DGQLOOM.js.map → chunk-M3VYPE2H.js.map} +1 -1
  51. package/dist/{chunk-JF7SFXTG.js → chunk-NCSJKK23.js} +2 -2
  52. package/dist/{chunk-XMN6MMTU.js → chunk-NRBGRZW4.js} +2 -2
  53. package/dist/{chunk-NOBL7OUP.js → chunk-OKW6F5S5.js} +12 -5
  54. package/dist/{chunk-NOBL7OUP.js.map → chunk-OKW6F5S5.js.map} +1 -1
  55. package/dist/{chunk-BNFRL6QW.js → chunk-PTMJ2FH2.js} +2 -2
  56. package/dist/{chunk-KWM33SPU.js → chunk-PVE7KSQP.js} +2 -2
  57. package/dist/{chunk-EW52H5EM.js → chunk-QDVQ4AN2.js} +12 -5
  58. package/dist/chunk-QDVQ4AN2.js.map +1 -0
  59. package/dist/{chunk-PYWNNF2I.js → chunk-QRSKPI62.js} +99 -66
  60. package/dist/chunk-QRSKPI62.js.map +1 -0
  61. package/dist/{chunk-YM3LR4LS.js → chunk-SSSXWIBP.js} +5 -5
  62. package/dist/{chunk-C43KEWEV.js → chunk-TDZSSJV4.js} +1 -1
  63. package/dist/chunk-TDZSSJV4.js.map +1 -0
  64. package/dist/{chunk-Y7NWBBHV.js → chunk-TEO46GMM.js} +2 -2
  65. package/dist/{chunk-AJE7FJVE.js → chunk-UCEABZZN.js} +2 -2
  66. package/dist/{chunk-IENGGY2C.js → chunk-UCEDY5M7.js} +2 -2
  67. package/dist/{chunk-PRQXUSQV.js → chunk-UYNFWZWG.js} +2 -2
  68. package/dist/{chunk-V4UDXYGG.js → chunk-WDTUYOLS.js} +2 -2
  69. package/dist/{chunk-RZOBQ23O.js → chunk-XOFXKASO.js} +2 -2
  70. package/dist/chunk-XRKQOQLY.js +212 -0
  71. package/dist/chunk-XRKQOQLY.js.map +1 -0
  72. package/dist/{chunk-WTI35CVJ.js → chunk-YYN3LIYA.js} +5 -5
  73. package/dist/{cli-DDo7Qgs-.d.ts → cli-BGahB_d3.d.ts} +3 -3
  74. package/dist/cli.d.ts +5 -5
  75. package/dist/cli.js +29 -29
  76. package/dist/compounding/engine.d.ts +1 -1
  77. package/dist/compounding/engine.js +3 -3
  78. package/dist/compounding/preference-consolidator.d.ts +1 -1
  79. package/dist/compression-optimizer.d.ts +1 -1
  80. package/dist/config.d.ts +1 -1
  81. package/dist/config.js +1 -1
  82. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  83. package/dist/connectors/codex-materialize-runner.js +3 -3
  84. package/dist/connectors/codex-materialize.d.ts +1 -1
  85. package/dist/connectors/index.d.ts +1 -1
  86. package/dist/connectors/index.js +3 -3
  87. package/dist/consolidation-provenance-check.d.ts +1 -1
  88. package/dist/consolidation-undo.d.ts +1 -1
  89. package/dist/contradiction/index.d.ts +19 -1
  90. package/dist/contradiction/index.js +1 -1
  91. package/dist/conversation-index/backend.d.ts +1 -1
  92. package/dist/conversation-index/chunker.d.ts +1 -1
  93. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  94. package/dist/conversation-index/indexer.d.ts +1 -1
  95. package/dist/conversation-index/search.d.ts +1 -1
  96. package/dist/day-summary.d.ts +1 -1
  97. package/dist/delinearize.d.ts +1 -1
  98. package/dist/direct-answer-wiring.d.ts +1 -1
  99. package/dist/direct-answer.d.ts +1 -1
  100. package/dist/embedding-fallback.d.ts +1 -1
  101. package/dist/enrichment/index.d.ts +1 -1
  102. package/dist/entity-retrieval.d.ts +1 -1
  103. package/dist/entity-retrieval.js +3 -3
  104. package/dist/entity-schema.d.ts +1 -1
  105. package/dist/explicit-capture.d.ts +3 -3
  106. package/dist/explicit-capture.js +1 -1
  107. package/dist/extraction-judge-telemetry.d.ts +1 -1
  108. package/dist/extraction-judge-training.d.ts +1 -1
  109. package/dist/extraction-judge.d.ts +1 -1
  110. package/dist/extraction.d.ts +1 -1
  111. package/dist/fallback-llm.d.ts +1 -1
  112. package/dist/identity-continuity.d.ts +1 -1
  113. package/dist/importance.d.ts +1 -1
  114. package/dist/index.d.ts +8 -8
  115. package/dist/index.js +37 -35
  116. package/dist/index.js.map +1 -1
  117. package/dist/intent.d.ts +1 -1
  118. package/dist/lcm/engine.d.ts +1 -1
  119. package/dist/lcm/index.d.ts +1 -1
  120. package/dist/lcm/tools.d.ts +1 -1
  121. package/dist/lifecycle.d.ts +1 -1
  122. package/dist/live-connectors-runner.d.ts +1 -1
  123. package/dist/local-llm.d.ts +1 -1
  124. package/dist/maintenance/memory-governance.d.ts +1 -1
  125. package/dist/maintenance/memory-governance.js +3 -3
  126. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  127. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  128. package/dist/mcp-memory-inspector-app.d.ts +4 -4
  129. package/dist/memory-action-policy.d.ts +1 -1
  130. package/dist/memory-cache.d.ts +1 -1
  131. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  132. package/dist/memory-projection-store.d.ts +1 -1
  133. package/dist/memory-provenance.d.ts +1 -1
  134. package/dist/memory-worth-outcomes.d.ts +1 -1
  135. package/dist/models-json.d.ts +1 -1
  136. package/dist/namespaces/migrate.d.ts +1 -1
  137. package/dist/namespaces/migrate.js +11 -11
  138. package/dist/namespaces/principal.d.ts +1 -1
  139. package/dist/namespaces/search.d.ts +15 -4
  140. package/dist/namespaces/search.js +7 -7
  141. package/dist/namespaces/storage.d.ts +52 -3
  142. package/dist/namespaces/storage.js +9 -5
  143. package/dist/native-knowledge.d.ts +1 -1
  144. package/dist/operator-toolkit.d.ts +1 -1
  145. package/dist/operator-toolkit.js +14 -14
  146. package/dist/{orchestrator-8fTZsa0y.d.ts → orchestrator-BgzZlWxH.d.ts} +500 -3
  147. package/dist/orchestrator.d.ts +3 -3
  148. package/dist/orchestrator.js +20 -20
  149. package/dist/patterns-cli.d.ts +1 -1
  150. package/dist/policy-runtime.d.ts +1 -1
  151. package/dist/qmd-recall-cache.d.ts +1 -1
  152. package/dist/qmd.d.ts +5 -1
  153. package/dist/qmd.js +2 -2
  154. package/dist/recall-disclosure-escalation.d.ts +1 -1
  155. package/dist/recall-explain-renderer.d.ts +1 -1
  156. package/dist/recall-explain-renderer.js +3 -3
  157. package/dist/recall-planner-llm.d.ts +1 -1
  158. package/dist/recall-state.d.ts +1 -1
  159. package/dist/recall-tag-filter.d.ts +1 -1
  160. package/dist/recall-xray-cli.d.ts +1 -1
  161. package/dist/recall-xray-cli.js +4 -4
  162. package/dist/recall-xray-renderer.d.ts +1 -1
  163. package/dist/recall-xray-renderer.js +3 -3
  164. package/dist/recall-xray.d.ts +1 -1
  165. package/dist/recall-xray.js +2 -2
  166. package/dist/{resolution-3SAP4SH2.js → resolution-IDTEBJFS.js} +2 -2
  167. package/dist/resolve-auth-token.d.ts +1 -1
  168. package/dist/resume-bundles.js +2 -2
  169. package/dist/retrieval-agents.d.ts +1 -1
  170. package/dist/retrieval-tiers.d.ts +1 -1
  171. package/dist/routing/engine.d.ts +1 -1
  172. package/dist/routing/store.d.ts +1 -1
  173. package/dist/schemas.d.ts +22 -22
  174. package/dist/search/embed-helper.d.ts +1 -1
  175. package/dist/search/factory.d.ts +1 -1
  176. package/dist/search/factory.js +6 -6
  177. package/dist/search/index.d.ts +1 -1
  178. package/dist/search/index.js +6 -6
  179. package/dist/search/lancedb-backend.d.ts +1 -1
  180. package/dist/search/lancedb-backend.js +2 -2
  181. package/dist/search/meilisearch-backend.d.ts +1 -1
  182. package/dist/search/meilisearch-backend.js +2 -2
  183. package/dist/search/noop-backend.d.ts +1 -1
  184. package/dist/search/orama-backend.d.ts +1 -1
  185. package/dist/search/orama-backend.js +2 -2
  186. package/dist/search/port.d.ts +17 -1
  187. package/dist/search/port.js +1 -1
  188. package/dist/search/remote-backend.d.ts +1 -1
  189. package/dist/{semantic-consolidation-DKdYzQOg.d.ts → semantic-consolidation-Z8d_uMq8.d.ts} +1 -1
  190. package/dist/semantic-consolidation.d.ts +2 -2
  191. package/dist/semantic-consolidation.js +4 -4
  192. package/dist/semantic-rule-promotion.js +3 -3
  193. package/dist/semantic-rule-verifier.d.ts +1 -1
  194. package/dist/semantic-rule-verifier.js +3 -3
  195. package/dist/session-observer-bands.d.ts +1 -1
  196. package/dist/session-observer-state.d.ts +1 -1
  197. package/dist/shared-context/manager.d.ts +1 -1
  198. package/dist/signal.d.ts +1 -1
  199. package/dist/storage.d.ts +1 -1
  200. package/dist/storage.js +2 -2
  201. package/dist/summarizer.d.ts +1 -1
  202. package/dist/summary-snapshot.d.ts +1 -1
  203. package/dist/temporal-supersession.d.ts +1 -1
  204. package/dist/temporal-validity.d.ts +1 -1
  205. package/dist/threading.d.ts +1 -1
  206. package/dist/tier-migration.d.ts +1 -1
  207. package/dist/tier-routing.d.ts +1 -1
  208. package/dist/topics.d.ts +1 -1
  209. package/dist/transcript.d.ts +1 -1
  210. package/dist/transfer/types.d.ts +12 -12
  211. package/dist/{types-D8yUmSik.d.ts → types-2OPlQWJG.d.ts} +23 -0
  212. package/dist/types.d.ts +1 -1
  213. package/dist/types.js +1 -1
  214. package/dist/utility-runtime.d.ts +1 -1
  215. package/dist/verified-recall.js +3 -3
  216. package/package.json +1 -1
  217. package/src/access-http.ts +7 -0
  218. package/src/access-mcp.ts +7 -0
  219. package/src/access-service.ts +12 -0
  220. package/src/cli.ts +104 -0
  221. package/src/config.test.ts +109 -0
  222. package/src/config.ts +164 -0
  223. package/src/contradiction/contradiction.test.ts +284 -0
  224. package/src/contradiction/resolution.ts +151 -4
  225. package/src/explicit-capture.ts +31 -10
  226. package/src/index.ts +10 -0
  227. package/src/maintenance/namespace-planner.test.ts +1120 -0
  228. package/src/maintenance/namespace-planner.ts +893 -0
  229. package/src/namespaces/catalog.test.ts +3356 -0
  230. package/src/namespaces/catalog.ts +2123 -0
  231. package/src/namespaces/search.test.ts +130 -2
  232. package/src/namespaces/search.ts +71 -10
  233. package/src/namespaces/storage.ts +210 -30
  234. package/src/orchestrator-flush.test.ts +720 -0
  235. package/src/orchestrator.ts +881 -239
  236. package/src/qmd-client.test.ts +59 -0
  237. package/src/qmd.ts +124 -84
  238. package/src/search/port.ts +16 -0
  239. package/src/types.ts +23 -0
  240. package/dist/chunk-C43KEWEV.js.map +0 -1
  241. package/dist/chunk-C63WC454.js.map +0 -1
  242. package/dist/chunk-EW52H5EM.js.map +0 -1
  243. package/dist/chunk-H3PHZLMF.js.map +0 -1
  244. package/dist/chunk-JVRPJ7D4.js.map +0 -1
  245. package/dist/chunk-ORGWWNJG.js +0 -131
  246. package/dist/chunk-ORGWWNJG.js.map +0 -1
  247. package/dist/chunk-PYWNNF2I.js.map +0 -1
  248. package/dist/chunk-QQHIQ7JD.js.map +0 -1
  249. package/dist/chunk-R3PQUPQ4.js.map +0 -1
  250. package/dist/chunk-SPMZZUEJ.js.map +0 -1
  251. /package/dist/{chunk-GI45G4BK.js.map → chunk-2RCGZ67B.js.map} +0 -0
  252. /package/dist/{chunk-BEMWL2FZ.js.map → chunk-54LOUIBE.js.map} +0 -0
  253. /package/dist/{chunk-7WEB3FLJ.js.map → chunk-5PLUC5OB.js.map} +0 -0
  254. /package/dist/{chunk-WLGE6KEO.js.map → chunk-67G4T7KI.js.map} +0 -0
  255. /package/dist/{chunk-JX2RINDR.js.map → chunk-6G5JEN55.js.map} +0 -0
  256. /package/dist/{chunk-KJDKZVF3.js.map → chunk-A3Y37UWI.js.map} +0 -0
  257. /package/dist/{chunk-CFOCZPIQ.js.map → chunk-BGKXTVNG.js.map} +0 -0
  258. /package/dist/{chunk-JBHXMCYN.js.map → chunk-GRYAECRV.js.map} +0 -0
  259. /package/dist/{chunk-EHQLDFSH.js.map → chunk-IQ53ZSXV.js.map} +0 -0
  260. /package/dist/{chunk-IVYSVAC6.js.map → chunk-KZZ4YAEC.js.map} +0 -0
  261. /package/dist/{chunk-JF7SFXTG.js.map → chunk-NCSJKK23.js.map} +0 -0
  262. /package/dist/{chunk-XMN6MMTU.js.map → chunk-NRBGRZW4.js.map} +0 -0
  263. /package/dist/{chunk-BNFRL6QW.js.map → chunk-PTMJ2FH2.js.map} +0 -0
  264. /package/dist/{chunk-KWM33SPU.js.map → chunk-PVE7KSQP.js.map} +0 -0
  265. /package/dist/{chunk-YM3LR4LS.js.map → chunk-SSSXWIBP.js.map} +0 -0
  266. /package/dist/{chunk-Y7NWBBHV.js.map → chunk-TEO46GMM.js.map} +0 -0
  267. /package/dist/{chunk-AJE7FJVE.js.map → chunk-UCEABZZN.js.map} +0 -0
  268. /package/dist/{chunk-IENGGY2C.js.map → chunk-UCEDY5M7.js.map} +0 -0
  269. /package/dist/{chunk-PRQXUSQV.js.map → chunk-UYNFWZWG.js.map} +0 -0
  270. /package/dist/{chunk-V4UDXYGG.js.map → chunk-WDTUYOLS.js.map} +0 -0
  271. /package/dist/{chunk-RZOBQ23O.js.map → chunk-XOFXKASO.js.map} +0 -0
  272. /package/dist/{chunk-WTI35CVJ.js.map → chunk-YYN3LIYA.js.map} +0 -0
  273. /package/dist/{resolution-3SAP4SH2.js.map → resolution-IDTEBJFS.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createSearchBackend
3
- } from "./chunk-YM3LR4LS.js";
3
+ } from "./chunk-SSSXWIBP.js";
4
4
  import {
5
5
  namespaceIdentityToken,
6
6
  normalizeNamespaceIdentity
@@ -95,29 +95,35 @@ var NamespaceSearchRouter = class {
95
95
  * signal that no backend was eligible — useful for success-verification in
96
96
  * startup-sync when namespacesEnabled is true.
97
97
  */
98
- async updateNamespaces(namespaces, execution) {
98
+ async updateNamespaces(namespaces, execution, options) {
99
+ return (await this.updateNamespacesDetailed(namespaces, execution, options)).backendCount;
100
+ }
101
+ async updateNamespacesDetailed(namespaces, execution, options) {
99
102
  const unique = Array.from(new Set(namespaces.map((value) => value.trim()).filter(Boolean)));
100
103
  const eligible = (await Promise.all(
101
104
  unique.map(async (namespace) => {
102
105
  const record = await this.backendRecordFor(namespace);
103
- return record.available && record.collectionState !== "missing" ? record : null;
106
+ return record.available && record.collectionState !== "missing" ? { namespace, record } : null;
104
107
  })
105
- )).filter((record) => record !== null);
106
- const globalRecord = eligible.find((record) => record.backend.updatesAllCollections?.() === true);
107
- const scopedRecords = globalRecord ? eligible.filter((record) => record.backend.updatesAllCollections?.() !== true) : eligible;
108
+ )).filter((entry) => entry !== null);
109
+ const globalEntry = eligible.find(({ record }) => record.backend.updatesAllCollections?.() === true);
110
+ const scopedEntries = globalEntry ? eligible.filter(({ record }) => record.backend.updatesAllCollections?.() !== true) : eligible;
108
111
  await Promise.all([
109
- globalRecord ? globalRecord.backend.update(execution) : Promise.resolve(),
110
- ...scopedRecords.map((record) => record.backend.update(execution))
112
+ globalEntry ? updateBackendRecord(globalEntry.record, execution, options) : Promise.resolve(),
113
+ ...scopedEntries.map(({ record }) => updateBackendRecord(record, execution, options))
111
114
  ]);
112
- return (globalRecord ? 1 : 0) + scopedRecords.length;
115
+ return {
116
+ backendCount: (globalEntry ? 1 : 0) + scopedEntries.length,
117
+ eligibleNamespaces: eligible.map(({ namespace }) => namespace)
118
+ };
113
119
  }
114
- async embedNamespaces(namespaces) {
120
+ async embedNamespaces(namespaces, options) {
115
121
  const unique = Array.from(new Set(namespaces.map((value) => value.trim()).filter(Boolean)));
116
122
  await Promise.all(
117
123
  unique.map(async (namespace) => {
118
124
  const record = await this.backendRecordFor(namespace);
119
125
  if (!record.available || record.collectionState === "missing") return;
120
- await record.backend.embed();
126
+ await embedBackendRecord(record, options);
121
127
  })
122
128
  );
123
129
  }
@@ -298,6 +304,36 @@ function backendSearchLimit(record, maxResults) {
298
304
  NESTED_NAMESPACE_FILTER_OVERFETCH_MIN
299
305
  );
300
306
  }
307
+ async function updateBackendRecord(record, execution, options) {
308
+ if (options?.strict === true) {
309
+ if (record.backend.updatesAllCollections?.() === true && typeof record.backend.updateStrict === "function") {
310
+ await record.backend.updateStrict(execution);
311
+ return;
312
+ }
313
+ if (typeof record.backend.updateCollectionStrict === "function") {
314
+ await record.backend.updateCollectionStrict(record.collection, execution);
315
+ return;
316
+ }
317
+ }
318
+ await record.backend.update(execution);
319
+ }
320
+ async function embedBackendRecord(record, options) {
321
+ if (options?.strict === true) {
322
+ if (typeof record.backend.embedCollectionStrict === "function") {
323
+ await record.backend.embedCollectionStrict(record.collection);
324
+ return;
325
+ }
326
+ if (typeof record.backend.embedStrict === "function") {
327
+ await record.backend.embedStrict();
328
+ return;
329
+ }
330
+ }
331
+ if (typeof record.backend.embedCollection === "function") {
332
+ await record.backend.embedCollection(record.collection);
333
+ return;
334
+ }
335
+ await record.backend.embed();
336
+ }
301
337
  function daemonModeForBackend(backend) {
302
338
  return "isDaemonMode" in backend && typeof backend.isDaemonMode === "function" ? backend.isDaemonMode() === true : null;
303
339
  }
@@ -357,4 +393,4 @@ export {
357
393
  namespaceCollectionName,
358
394
  NamespaceSearchRouter
359
395
  };
360
- //# sourceMappingURL=chunk-JVRPJ7D4.js.map
396
+ //# sourceMappingURL=chunk-EKQMQQ3U.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/namespaces/search.ts"],"sourcesContent":["import path from \"node:path\";\nimport type { PluginConfig, QmdSearchResult } from \"../types.js\";\nimport type {\n SearchBackend,\n SearchExecutionOptions,\n SearchQueryOptions,\n} from \"../search/port.js\";\nimport { createSearchBackend } from \"../search/factory.js\";\nimport { namespaceIdentityToken, normalizeNamespaceIdentity } from \"./identity.js\";\n\nconst NESTED_NAMESPACE_FILTER_OVERFETCH_FACTOR = 4;\nconst NESTED_NAMESPACE_FILTER_OVERFETCH_MIN = 50;\n\nexport function namespaceCollectionName(\n baseCollection: string,\n namespace: string,\n options?: {\n defaultNamespace?: string;\n useLegacyDefaultCollection?: boolean;\n },\n): string {\n const trimmed = normalizeNamespaceIdentity(namespace);\n const defaultNamespace = normalizeNamespaceIdentity(options?.defaultNamespace ?? \"\") || \"default\";\n if (\n options?.useLegacyDefaultCollection === true &&\n trimmed === defaultNamespace\n ) {\n return baseCollection;\n }\n\n return `${baseCollection}--${namespaceIdentityToken(trimmed || defaultNamespace)}`;\n}\n\ntype StorageRouterLike = {\n storageFor(namespace: string): Promise<{ dir: string }>;\n};\n\ntype NamespaceBackendRecord = {\n backend: SearchBackend;\n collection: string;\n memoryDir: string;\n available: boolean;\n collectionState: CollectionState;\n filtersNestedNamespaces: boolean;\n};\n\nexport interface NamespaceUpdateResult {\n backendCount: number;\n eligibleNamespaces: string[];\n}\n\nexport type CollectionState = \"present\" | \"missing\" | \"unknown\" | \"skipped\";\n\nexport interface NamespaceSearchHealth {\n collection: string;\n memoryDir: string;\n available: boolean;\n collectionState: CollectionState;\n debugStatus: string;\n installedVersion: string | null;\n supportedVersion: string | null;\n supported: boolean | null;\n upgradeAvailable: boolean | null;\n doctorAvailable: boolean | null;\n daemonMode: boolean | null;\n}\n\ntype NamespaceScopedSearchConfig = PluginConfig & {\n hostEmbeddingProviderScope?: string;\n};\n\ntype BackendRecordOptions = {\n autoCreateCollection: boolean;\n abortAsUnavailable: boolean;\n failOpenMissingGuardedCollection: boolean;\n};\n\nexport class NamespaceSearchRouter {\n private readonly cache = new Map<string, Promise<NamespaceBackendRecord>>();\n\n constructor(\n private readonly config: PluginConfig,\n private readonly storageRouter: StorageRouterLike,\n private readonly createBackend: (config: PluginConfig) => SearchBackend = createSearchBackend,\n ) {}\n\n async collectionForNamespace(namespace: string): Promise<string> {\n return (await this.backendRecordFor(namespace)).collection;\n }\n\n async searchAcrossNamespaces(options: {\n query: string;\n namespaces: string[];\n maxResults?: number;\n mode?: \"search\" | \"hybrid\" | \"bm25\" | \"vector\";\n searchOptions?: SearchQueryOptions;\n execution?: SearchExecutionOptions;\n }): Promise<QmdSearchResult[]> {\n const query = options.query.trim();\n if (!query) return [];\n const maxResults = Math.max(0, Math.floor(options.maxResults ?? this.config.qmdMaxResults));\n if (maxResults === 0) return [];\n\n const method = options.mode ?? \"search\";\n const namespaces = Array.from(new Set(options.namespaces.map((value) => value.trim()).filter(Boolean)));\n if (namespaces.length === 0) return [];\n\n const resultsByNamespace = await Promise.all(\n namespaces.map(async (namespace) => {\n const record = await this.backendRecordFor(namespace);\n if (!record.available || record.collectionState === \"missing\") {\n return { namespace, results: [] as QmdSearchResult[] };\n }\n const backendLimit = backendSearchLimit(record, maxResults);\n let results: QmdSearchResult[];\n switch (method) {\n case \"hybrid\":\n results = await record.backend.hybridSearch(\n query,\n record.collection,\n backendLimit,\n options.execution,\n );\n break;\n case \"bm25\":\n results = await record.backend.bm25Search(\n query,\n record.collection,\n backendLimit,\n options.execution,\n );\n break;\n case \"vector\":\n results = await record.backend.vectorSearch(\n query,\n record.collection,\n backendLimit,\n options.execution,\n );\n break;\n default:\n results = await record.backend.search(\n query,\n record.collection,\n backendLimit,\n options.searchOptions,\n options.execution,\n );\n break;\n }\n results = filterNamespaceSubtreeResults(record, results);\n return { namespace, results };\n }),\n );\n\n return mergeNamespaceSearchResults(resultsByNamespace, maxResults);\n }\n\n /**\n * Update all namespace backends.\n * Returns the number of backends for which an update was attempted\n * (i.e., available and collection present). Callers can treat 0 as a\n * signal that no backend was eligible — useful for success-verification in\n * startup-sync when namespacesEnabled is true.\n */\n async updateNamespaces(\n namespaces: string[],\n execution?: SearchExecutionOptions,\n options?: { strict?: boolean },\n ): Promise<number> {\n return (await this.updateNamespacesDetailed(namespaces, execution, options)).backendCount;\n }\n\n async updateNamespacesDetailed(\n namespaces: string[],\n execution?: SearchExecutionOptions,\n options?: { strict?: boolean },\n ): Promise<NamespaceUpdateResult> {\n const unique = Array.from(new Set(namespaces.map((value) => value.trim()).filter(Boolean)));\n const eligible = (await Promise.all(\n unique.map(async (namespace) => {\n const record = await this.backendRecordFor(namespace);\n return record.available && record.collectionState !== \"missing\"\n ? { namespace, record }\n : null;\n }),\n )).filter((entry): entry is { namespace: string; record: NamespaceBackendRecord } => entry !== null);\n\n const globalEntry = eligible.find(({ record }) => record.backend.updatesAllCollections?.() === true);\n const scopedEntries = globalEntry\n ? eligible.filter(({ record }) => record.backend.updatesAllCollections?.() !== true)\n : eligible;\n\n await Promise.all([\n globalEntry\n ? updateBackendRecord(globalEntry.record, execution, options)\n : Promise.resolve(),\n ...scopedEntries.map(({ record }) => updateBackendRecord(record, execution, options)),\n ]);\n\n return {\n backendCount: (globalEntry ? 1 : 0) + scopedEntries.length,\n eligibleNamespaces: eligible.map(({ namespace }) => namespace),\n };\n }\n\n async embedNamespaces(namespaces: string[], options?: { strict?: boolean }): Promise<void> {\n const unique = Array.from(new Set(namespaces.map((value) => value.trim()).filter(Boolean)));\n await Promise.all(\n unique.map(async (namespace) => {\n const record = await this.backendRecordFor(namespace);\n if (!record.available || record.collectionState === \"missing\") return;\n await embedBackendRecord(record, options);\n }),\n );\n }\n\n async ensureNamespaceCollection(\n namespace: string,\n execution?: SearchExecutionOptions,\n ): Promise<\"present\" | \"missing\" | \"unknown\" | \"skipped\"> {\n const record = await this.backendRecordFor(namespace, execution);\n return record.collectionState;\n }\n\n async healthForNamespace(\n namespace: string,\n execution?: SearchExecutionOptions,\n ): Promise<NamespaceSearchHealth> {\n const key = namespace.trim() || this.config.defaultNamespace;\n const record = await this.createBackendRecordFor(\n key,\n execution,\n {\n autoCreateCollection: false,\n abortAsUnavailable: true,\n failOpenMissingGuardedCollection: false,\n },\n );\n try {\n const liveRecord = await this.liveCachedRecordForHealth(key, record, execution);\n const diagnosticBackend = liveRecord?.backend ?? record.backend;\n const versionStatus =\n \"getVersionStatus\" in diagnosticBackend &&\n typeof diagnosticBackend.getVersionStatus === \"function\"\n ? diagnosticBackend.getVersionStatus()\n : null;\n const daemonMode = daemonModeForBackend(diagnosticBackend);\n const collectionState =\n liveRecord?.collectionState === \"missing\"\n ? \"missing\"\n : record.collectionState;\n\n return {\n collection: record.collection,\n memoryDir: record.memoryDir,\n available: liveRecord?.available ?? record.available,\n collectionState,\n debugStatus: diagnosticBackend.debugStatus(),\n installedVersion: versionStatus?.installedVersion ?? null,\n supportedVersion: versionStatus?.supportedVersion ?? null,\n supported: versionStatus?.supported ?? null,\n upgradeAvailable: versionStatus?.upgradeAvailable ?? null,\n doctorAvailable: versionStatus?.capabilities?.doctor ?? null,\n daemonMode,\n };\n } finally {\n const dispose = (record.backend as { dispose?: () => void | Promise<void> }).dispose;\n await dispose?.call(record.backend);\n }\n }\n\n private async liveCachedRecordForHealth(\n key: string,\n disposableRecord: NamespaceBackendRecord,\n execution?: SearchExecutionOptions,\n ): Promise<NamespaceBackendRecord | null> {\n const pending = this.cache.get(key);\n if (!pending) return null;\n const cachedRecord = await awaitWithAbort(pending, execution?.signal).catch(() => null);\n if (!cachedRecord) return null;\n if (cachedRecord.collection !== disposableRecord.collection) return null;\n if (cachedRecord.memoryDir !== disposableRecord.memoryDir) return null;\n return cachedRecord;\n }\n\n /** Clear cached backend records so the next access re-probes availability. */\n clearCache(): void {\n this.cache.clear();\n }\n\n /** Release any per-namespace backend handles held by cached records. */\n async dispose(): Promise<void> {\n const pendingRecords = Array.from(this.cache.values());\n this.cache.clear();\n const settled = await Promise.allSettled(pendingRecords);\n await Promise.allSettled(\n settled.flatMap((entry) => {\n if (entry.status !== \"fulfilled\") return [];\n const dispose = (entry.value.backend as { dispose?: () => void | Promise<void> }).dispose;\n return dispose ? [dispose.call(entry.value.backend)] : [];\n }),\n );\n }\n\n private async backendRecordFor(\n namespace: string,\n execution?: SearchExecutionOptions,\n ): Promise<NamespaceBackendRecord> {\n const key = namespace.trim() || this.config.defaultNamespace;\n const existing = this.cache.get(key);\n if (existing) return await existing;\n\n const pending = this.createBackendRecordFor(key, execution, {\n autoCreateCollection: true,\n abortAsUnavailable: false,\n failOpenMissingGuardedCollection: true,\n }).catch((error) => {\n this.cache.delete(key);\n throw error;\n });\n\n this.cache.set(key, pending);\n return await pending;\n }\n\n private async createBackendRecordFor(\n namespace: string,\n execution: SearchExecutionOptions | undefined,\n options: BackendRecordOptions,\n ): Promise<NamespaceBackendRecord> {\n const key = namespace.trim() || this.config.defaultNamespace;\n const storage = await this.storageRouter.storageFor(key);\n const useLegacyDefaultCollection =\n key === this.config.defaultNamespace && storage.dir === this.config.memoryDir;\n const filtersNestedNamespaces =\n this.config.namespacesEnabled === true && useLegacyDefaultCollection;\n const rootHostEmbeddingScope =\n (this.config as NamespaceScopedSearchConfig).hostEmbeddingProviderScope ??\n this.config.memoryDir;\n const scopedConfig: NamespaceScopedSearchConfig = {\n ...this.config,\n memoryDir: storage.dir,\n hostEmbeddingProviderScope: rootHostEmbeddingScope,\n qmdCollection: namespaceCollectionName(this.config.qmdCollection, key, {\n defaultNamespace: this.config.defaultNamespace,\n useLegacyDefaultCollection,\n }),\n };\n\n const backend = this.createBackend(scopedConfig);\n try {\n const availabilityProbe =\n options.autoCreateCollection || typeof backend.checkAvailability !== \"function\"\n ? backend.probe()\n : backend.checkAvailability({ signal: execution?.signal });\n const available = await awaitWithAbort(availabilityProbe, execution?.signal).catch((error) => {\n if (error instanceof NamespaceSearchAbortError && !options.abortAsUnavailable) {\n throw error;\n }\n return false;\n });\n const collectionState = available\n ? await awaitWithAbort(\n this.collectionStateForBackend(backend, storage.dir, scopedConfig.qmdCollection, {\n autoCreate: options.autoCreateCollection,\n failOpenMissingGuardedCollection: options.failOpenMissingGuardedCollection,\n skipAutoCreate: filtersNestedNamespaces,\n execution,\n }),\n execution?.signal,\n ).catch((error) => {\n if (error instanceof NamespaceSearchAbortError && !options.abortAsUnavailable) {\n throw error;\n }\n return \"unknown\" as const;\n })\n : \"unknown\";\n return {\n backend,\n collection: scopedConfig.qmdCollection,\n memoryDir: storage.dir,\n available,\n collectionState,\n filtersNestedNamespaces,\n };\n } catch (error) {\n const dispose = (backend as { dispose?: () => void | Promise<void> }).dispose;\n if (dispose) {\n await Promise.resolve(dispose.call(backend)).catch(() => {});\n }\n throw error;\n }\n }\n\n private async collectionStateForBackend(\n backend: SearchBackend,\n memoryDir: string,\n collection: string,\n options: {\n autoCreate: boolean;\n failOpenMissingGuardedCollection: boolean;\n skipAutoCreate: boolean;\n execution?: SearchExecutionOptions;\n },\n ): Promise<CollectionState> {\n if (!options.autoCreate || options.skipAutoCreate) {\n if (!backend.checkCollection) return \"unknown\";\n const collectionState = await backend\n .checkCollection(collection, options.execution)\n .catch(() => \"unknown\" as const);\n return options.failOpenMissingGuardedCollection && collectionState === \"missing\"\n ? \"unknown\"\n : collectionState;\n }\n return await backend.ensureCollection(memoryDir, collection, options.execution).catch(() => \"unknown\" as const);\n }\n}\n\nclass NamespaceSearchAbortError extends Error {\n constructor() {\n super(\"operation aborted\");\n }\n}\n\nfunction awaitWithAbort<T>(operation: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) return operation;\n if (signal.aborted) return Promise.reject(new NamespaceSearchAbortError());\n\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(new NamespaceSearchAbortError());\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n operation.then(resolve, reject).finally(() => {\n signal.removeEventListener(\"abort\", onAbort);\n });\n });\n}\n\nfunction filterNamespaceSubtreeResults(\n record: NamespaceBackendRecord,\n results: QmdSearchResult[],\n): QmdSearchResult[] {\n if (!record.filtersNestedNamespaces) return results;\n return results.filter((result) =>\n !pathIsInsideNamespaceSubtree(record.memoryDir, record.collection, result.path)\n );\n}\n\nfunction backendSearchLimit(\n record: NamespaceBackendRecord,\n maxResults: number,\n): number {\n if (!record.filtersNestedNamespaces) return maxResults;\n return Math.max(\n maxResults,\n maxResults * NESTED_NAMESPACE_FILTER_OVERFETCH_FACTOR,\n NESTED_NAMESPACE_FILTER_OVERFETCH_MIN,\n );\n}\n\nasync function updateBackendRecord(\n record: NamespaceBackendRecord,\n execution?: SearchExecutionOptions,\n options?: { strict?: boolean },\n): Promise<void> {\n if (options?.strict === true) {\n if (\n record.backend.updatesAllCollections?.() === true &&\n typeof record.backend.updateStrict === \"function\"\n ) {\n await record.backend.updateStrict(execution);\n return;\n }\n if (typeof record.backend.updateCollectionStrict === \"function\") {\n await record.backend.updateCollectionStrict(record.collection, execution);\n return;\n }\n }\n await record.backend.update(execution);\n}\n\nasync function embedBackendRecord(\n record: NamespaceBackendRecord,\n options?: { strict?: boolean },\n): Promise<void> {\n if (options?.strict === true) {\n if (typeof record.backend.embedCollectionStrict === \"function\") {\n await record.backend.embedCollectionStrict(record.collection);\n return;\n }\n if (typeof record.backend.embedStrict === \"function\") {\n await record.backend.embedStrict();\n return;\n }\n }\n if (typeof record.backend.embedCollection === \"function\") {\n await record.backend.embedCollection(record.collection);\n return;\n }\n await record.backend.embed();\n}\n\nfunction daemonModeForBackend(backend: SearchBackend): boolean | null {\n return \"isDaemonMode\" in backend && typeof backend.isDaemonMode === \"function\"\n ? backend.isDaemonMode() === true\n : null;\n}\n\nfunction pathIsInsideNamespaceSubtree(\n memoryDir: string,\n collection: string,\n resultPath: string | undefined,\n): boolean {\n if (!resultPath) return false;\n const normalizedResultPath = normalizeQmdResultPath(resultPath, collection);\n const memoryRoot = path.resolve(memoryDir);\n const namespacesRoot = path.join(memoryRoot, \"namespaces\");\n const candidate = path.isAbsolute(normalizedResultPath)\n ? path.normalize(normalizedResultPath)\n : path.resolve(memoryRoot, normalizedResultPath);\n const relative = path.relative(namespacesRoot, candidate);\n return relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative));\n}\n\nfunction normalizeQmdResultPath(resultPath: string, collection: string): string {\n let value = resultPath.trim();\n if (value.startsWith(\"qmd://\")) {\n try {\n const parsed = new URL(value);\n if (parsed.protocol === \"qmd:\" && parsed.hostname === collection) {\n value = decodeURIComponent(parsed.pathname.replace(/^\\/+/, \"\"));\n }\n } catch {\n const remainder = value.slice(\"qmd://\".length);\n const slashIndex = remainder.indexOf(\"/\");\n if (slashIndex !== -1) {\n value = remainder.slice(slashIndex + 1);\n }\n }\n }\n\n const collectionPrefix = `${collection}/`;\n if (value.startsWith(collectionPrefix)) {\n value = value.slice(collectionPrefix.length);\n }\n return value;\n}\n\nfunction mergeNamespaceSearchResults(\n lists: Array<{ namespace: string; results: QmdSearchResult[] }>,\n maxResults: number,\n): QmdSearchResult[] {\n const merged = new Map<string, QmdSearchResult>();\n\n for (const { namespace, results } of lists) {\n for (const result of results) {\n const key = `${namespace}\\0${result.path || result.docid}`;\n const existing = merged.get(key);\n if (!existing) {\n merged.set(key, result);\n continue;\n }\n if (result.score > existing.score) {\n merged.set(key, {\n ...result,\n snippet: existing.snippet || result.snippet || \"\",\n });\n }\n }\n }\n\n return [...merged.values()]\n .sort((a, b) => b.score - a.score)\n .slice(0, maxResults);\n}\n"],"mappings":";;;;;;;;;AAAA,OAAO,UAAU;AAUjB,IAAM,2CAA2C;AACjD,IAAM,wCAAwC;AAEvC,SAAS,wBACd,gBACA,WACA,SAIQ;AACR,QAAM,UAAU,2BAA2B,SAAS;AACpD,QAAM,mBAAmB,2BAA2B,SAAS,oBAAoB,EAAE,KAAK;AACxF,MACE,SAAS,+BAA+B,QACxC,YAAY,kBACZ;AACA,WAAO;AAAA,EACT;AAEA,SAAO,GAAG,cAAc,KAAK,uBAAuB,WAAW,gBAAgB,CAAC;AAClF;AA8CO,IAAM,wBAAN,MAA4B;AAAA,EAGjC,YACmB,QACA,eACA,gBAAyD,qBAC1E;AAHiB;AACA;AACA;AAAA,EAChB;AAAA,EAHgB;AAAA,EACA;AAAA,EACA;AAAA,EALF,QAAQ,oBAAI,IAA6C;AAAA,EAQ1E,MAAM,uBAAuB,WAAoC;AAC/D,YAAQ,MAAM,KAAK,iBAAiB,SAAS,GAAG;AAAA,EAClD;AAAA,EAEA,MAAM,uBAAuB,SAOE;AAC7B,UAAM,QAAQ,QAAQ,MAAM,KAAK;AACjC,QAAI,CAAC,MAAO,QAAO,CAAC;AACpB,UAAM,aAAa,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,cAAc,KAAK,OAAO,aAAa,CAAC;AAC1F,QAAI,eAAe,EAAG,QAAO,CAAC;AAE9B,UAAM,SAAS,QAAQ,QAAQ;AAC/B,UAAM,aAAa,MAAM,KAAK,IAAI,IAAI,QAAQ,WAAW,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC,CAAC;AACtG,QAAI,WAAW,WAAW,EAAG,QAAO,CAAC;AAErC,UAAM,qBAAqB,MAAM,QAAQ;AAAA,MACvC,WAAW,IAAI,OAAO,cAAc;AAClC,cAAM,SAAS,MAAM,KAAK,iBAAiB,SAAS;AACpD,YAAI,CAAC,OAAO,aAAa,OAAO,oBAAoB,WAAW;AAC7D,iBAAO,EAAE,WAAW,SAAS,CAAC,EAAuB;AAAA,QACvD;AACA,cAAM,eAAe,mBAAmB,QAAQ,UAAU;AAC1D,YAAI;AACJ,gBAAQ,QAAQ;AAAA,UACd,KAAK;AACH,sBAAU,MAAM,OAAO,QAAQ;AAAA,cAC7B;AAAA,cACA,OAAO;AAAA,cACP;AAAA,cACA,QAAQ;AAAA,YACV;AACA;AAAA,UACF,KAAK;AACH,sBAAU,MAAM,OAAO,QAAQ;AAAA,cAC7B;AAAA,cACA,OAAO;AAAA,cACP;AAAA,cACA,QAAQ;AAAA,YACV;AACA;AAAA,UACF,KAAK;AACH,sBAAU,MAAM,OAAO,QAAQ;AAAA,cAC7B;AAAA,cACA,OAAO;AAAA,cACP;AAAA,cACA,QAAQ;AAAA,YACV;AACA;AAAA,UACF;AACE,sBAAU,MAAM,OAAO,QAAQ;AAAA,cAC7B;AAAA,cACA,OAAO;AAAA,cACP;AAAA,cACA,QAAQ;AAAA,cACR,QAAQ;AAAA,YACV;AACA;AAAA,QACJ;AACA,kBAAU,8BAA8B,QAAQ,OAAO;AACvD,eAAO,EAAE,WAAW,QAAQ;AAAA,MAC9B,CAAC;AAAA,IACH;AAEA,WAAO,4BAA4B,oBAAoB,UAAU;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,iBACJ,YACA,WACA,SACiB;AACjB,YAAQ,MAAM,KAAK,yBAAyB,YAAY,WAAW,OAAO,GAAG;AAAA,EAC/E;AAAA,EAEA,MAAM,yBACJ,YACA,WACA,SACgC;AAChC,UAAM,SAAS,MAAM,KAAK,IAAI,IAAI,WAAW,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC,CAAC;AAC1F,UAAM,YAAY,MAAM,QAAQ;AAAA,MAC9B,OAAO,IAAI,OAAO,cAAc;AAC9B,cAAM,SAAS,MAAM,KAAK,iBAAiB,SAAS;AACpD,eAAO,OAAO,aAAa,OAAO,oBAAoB,YAClD,EAAE,WAAW,OAAO,IACpB;AAAA,MACN,CAAC;AAAA,IACH,GAAG,OAAO,CAAC,UAA0E,UAAU,IAAI;AAEnG,UAAM,cAAc,SAAS,KAAK,CAAC,EAAE,OAAO,MAAM,OAAO,QAAQ,wBAAwB,MAAM,IAAI;AACnG,UAAM,gBAAgB,cAClB,SAAS,OAAO,CAAC,EAAE,OAAO,MAAM,OAAO,QAAQ,wBAAwB,MAAM,IAAI,IACjF;AAEJ,UAAM,QAAQ,IAAI;AAAA,MAChB,cACI,oBAAoB,YAAY,QAAQ,WAAW,OAAO,IAC1D,QAAQ,QAAQ;AAAA,MACpB,GAAG,cAAc,IAAI,CAAC,EAAE,OAAO,MAAM,oBAAoB,QAAQ,WAAW,OAAO,CAAC;AAAA,IACtF,CAAC;AAED,WAAO;AAAA,MACL,eAAe,cAAc,IAAI,KAAK,cAAc;AAAA,MACpD,oBAAoB,SAAS,IAAI,CAAC,EAAE,UAAU,MAAM,SAAS;AAAA,IAC/D;AAAA,EACF;AAAA,EAEA,MAAM,gBAAgB,YAAsB,SAA+C;AACzF,UAAM,SAAS,MAAM,KAAK,IAAI,IAAI,WAAW,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC,CAAC;AAC1F,UAAM,QAAQ;AAAA,MACZ,OAAO,IAAI,OAAO,cAAc;AAC9B,cAAM,SAAS,MAAM,KAAK,iBAAiB,SAAS;AACpD,YAAI,CAAC,OAAO,aAAa,OAAO,oBAAoB,UAAW;AAC/D,cAAM,mBAAmB,QAAQ,OAAO;AAAA,MAC1C,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAM,0BACJ,WACA,WACwD;AACxD,UAAM,SAAS,MAAM,KAAK,iBAAiB,WAAW,SAAS;AAC/D,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAM,mBACJ,WACA,WACgC;AAChC,UAAM,MAAM,UAAU,KAAK,KAAK,KAAK,OAAO;AAC5C,UAAM,SAAS,MAAM,KAAK;AAAA,MACxB;AAAA,MACA;AAAA,MACA;AAAA,QACE,sBAAsB;AAAA,QACtB,oBAAoB;AAAA,QACpB,kCAAkC;AAAA,MACpC;AAAA,IACF;AACA,QAAI;AACF,YAAM,aAAa,MAAM,KAAK,0BAA0B,KAAK,QAAQ,SAAS;AAC9E,YAAM,oBAAoB,YAAY,WAAW,OAAO;AACxD,YAAM,gBACJ,sBAAsB,qBACtB,OAAO,kBAAkB,qBAAqB,aAC1C,kBAAkB,iBAAiB,IACnC;AACN,YAAM,aAAa,qBAAqB,iBAAiB;AACzD,YAAM,kBACJ,YAAY,oBAAoB,YAC5B,YACA,OAAO;AAEb,aAAO;AAAA,QACL,YAAY,OAAO;AAAA,QACnB,WAAW,OAAO;AAAA,QAClB,WAAW,YAAY,aAAa,OAAO;AAAA,QAC3C;AAAA,QACA,aAAa,kBAAkB,YAAY;AAAA,QAC3C,kBAAkB,eAAe,oBAAoB;AAAA,QACrD,kBAAkB,eAAe,oBAAoB;AAAA,QACrD,WAAW,eAAe,aAAa;AAAA,QACvC,kBAAkB,eAAe,oBAAoB;AAAA,QACrD,iBAAiB,eAAe,cAAc,UAAU;AAAA,QACxD;AAAA,MACF;AAAA,IACF,UAAE;AACA,YAAM,UAAW,OAAO,QAAqD;AAC7E,YAAM,SAAS,KAAK,OAAO,OAAO;AAAA,IACpC;AAAA,EACF;AAAA,EAEA,MAAc,0BACZ,KACA,kBACA,WACwC;AACxC,UAAM,UAAU,KAAK,MAAM,IAAI,GAAG;AAClC,QAAI,CAAC,QAAS,QAAO;AACrB,UAAM,eAAe,MAAM,eAAe,SAAS,WAAW,MAAM,EAAE,MAAM,MAAM,IAAI;AACtF,QAAI,CAAC,aAAc,QAAO;AAC1B,QAAI,aAAa,eAAe,iBAAiB,WAAY,QAAO;AACpE,QAAI,aAAa,cAAc,iBAAiB,UAAW,QAAO;AAClE,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,aAAmB;AACjB,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA;AAAA,EAGA,MAAM,UAAyB;AAC7B,UAAM,iBAAiB,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC;AACrD,SAAK,MAAM,MAAM;AACjB,UAAM,UAAU,MAAM,QAAQ,WAAW,cAAc;AACvD,UAAM,QAAQ;AAAA,MACZ,QAAQ,QAAQ,CAAC,UAAU;AACzB,YAAI,MAAM,WAAW,YAAa,QAAO,CAAC;AAC1C,cAAM,UAAW,MAAM,MAAM,QAAqD;AAClF,eAAO,UAAU,CAAC,QAAQ,KAAK,MAAM,MAAM,OAAO,CAAC,IAAI,CAAC;AAAA,MAC1D,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAc,iBACZ,WACA,WACiC;AACjC,UAAM,MAAM,UAAU,KAAK,KAAK,KAAK,OAAO;AAC5C,UAAM,WAAW,KAAK,MAAM,IAAI,GAAG;AACnC,QAAI,SAAU,QAAO,MAAM;AAE3B,UAAM,UAAU,KAAK,uBAAuB,KAAK,WAAW;AAAA,MAC1D,sBAAsB;AAAA,MACtB,oBAAoB;AAAA,MACpB,kCAAkC;AAAA,IACpC,CAAC,EAAE,MAAM,CAAC,UAAU;AAClB,WAAK,MAAM,OAAO,GAAG;AACrB,YAAM;AAAA,IACR,CAAC;AAED,SAAK,MAAM,IAAI,KAAK,OAAO;AAC3B,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,MAAc,uBACZ,WACA,WACA,SACiC;AACjC,UAAM,MAAM,UAAU,KAAK,KAAK,KAAK,OAAO;AAC5C,UAAM,UAAU,MAAM,KAAK,cAAc,WAAW,GAAG;AACvD,UAAM,6BACJ,QAAQ,KAAK,OAAO,oBAAoB,QAAQ,QAAQ,KAAK,OAAO;AACtE,UAAM,0BACJ,KAAK,OAAO,sBAAsB,QAAQ;AAC5C,UAAM,yBACH,KAAK,OAAuC,8BAC7C,KAAK,OAAO;AACd,UAAM,eAA4C;AAAA,MAChD,GAAG,KAAK;AAAA,MACR,WAAW,QAAQ;AAAA,MACnB,4BAA4B;AAAA,MAC5B,eAAe,wBAAwB,KAAK,OAAO,eAAe,KAAK;AAAA,QACrE,kBAAkB,KAAK,OAAO;AAAA,QAC9B;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,UAAU,KAAK,cAAc,YAAY;AAC/C,QAAI;AACF,YAAM,oBACJ,QAAQ,wBAAwB,OAAO,QAAQ,sBAAsB,aACjE,QAAQ,MAAM,IACd,QAAQ,kBAAkB,EAAE,QAAQ,WAAW,OAAO,CAAC;AAC7D,YAAM,YAAY,MAAM,eAAe,mBAAmB,WAAW,MAAM,EAAE,MAAM,CAAC,UAAU;AAC5F,YAAI,iBAAiB,6BAA6B,CAAC,QAAQ,oBAAoB;AAC7E,gBAAM;AAAA,QACR;AACA,eAAO;AAAA,MACT,CAAC;AACD,YAAM,kBAAkB,YACpB,MAAM;AAAA,QACN,KAAK,0BAA0B,SAAS,QAAQ,KAAK,aAAa,eAAe;AAAA,UAC/E,YAAY,QAAQ;AAAA,UACpB,kCAAkC,QAAQ;AAAA,UAC1C,gBAAgB;AAAA,UAChB;AAAA,QACF,CAAC;AAAA,QACD,WAAW;AAAA,MACb,EAAE,MAAM,CAAC,UAAU;AACjB,YAAI,iBAAiB,6BAA6B,CAAC,QAAQ,oBAAoB;AAC7E,gBAAM;AAAA,QACR;AACA,eAAO;AAAA,MACT,CAAC,IACC;AACJ,aAAO;AAAA,QACL;AAAA,QACA,YAAY,aAAa;AAAA,QACzB,WAAW,QAAQ;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,UAAW,QAAqD;AACtE,UAAI,SAAS;AACX,cAAM,QAAQ,QAAQ,QAAQ,KAAK,OAAO,CAAC,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MAC7D;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAc,0BACZ,SACA,WACA,YACA,SAM0B;AAC1B,QAAI,CAAC,QAAQ,cAAc,QAAQ,gBAAgB;AACjD,UAAI,CAAC,QAAQ,gBAAiB,QAAO;AACrC,YAAM,kBAAkB,MAAM,QAC3B,gBAAgB,YAAY,QAAQ,SAAS,EAC7C,MAAM,MAAM,SAAkB;AACjC,aAAO,QAAQ,oCAAoC,oBAAoB,YACnE,YACA;AAAA,IACN;AACA,WAAO,MAAM,QAAQ,iBAAiB,WAAW,YAAY,QAAQ,SAAS,EAAE,MAAM,MAAM,SAAkB;AAAA,EAChH;AACF;AAEA,IAAM,4BAAN,cAAwC,MAAM;AAAA,EAC5C,cAAc;AACZ,UAAM,mBAAmB;AAAA,EAC3B;AACF;AAEA,SAAS,eAAkB,WAAuB,QAAkC;AAClF,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,OAAO,QAAS,QAAO,QAAQ,OAAO,IAAI,0BAA0B,CAAC;AAEzE,SAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AACzC,UAAM,UAAU,MAAM;AACpB,aAAO,oBAAoB,SAAS,OAAO;AAC3C,aAAO,IAAI,0BAA0B,CAAC;AAAA,IACxC;AACA,WAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AACxD,cAAU,KAAK,SAAS,MAAM,EAAE,QAAQ,MAAM;AAC5C,aAAO,oBAAoB,SAAS,OAAO;AAAA,IAC7C,CAAC;AAAA,EACH,CAAC;AACH;AAEA,SAAS,8BACP,QACA,SACmB;AACnB,MAAI,CAAC,OAAO,wBAAyB,QAAO;AAC5C,SAAO,QAAQ;AAAA,IAAO,CAAC,WACrB,CAAC,6BAA6B,OAAO,WAAW,OAAO,YAAY,OAAO,IAAI;AAAA,EAChF;AACF;AAEA,SAAS,mBACP,QACA,YACQ;AACR,MAAI,CAAC,OAAO,wBAAyB,QAAO;AAC5C,SAAO,KAAK;AAAA,IACV;AAAA,IACA,aAAa;AAAA,IACb;AAAA,EACF;AACF;AAEA,eAAe,oBACb,QACA,WACA,SACe;AACf,MAAI,SAAS,WAAW,MAAM;AAC5B,QACE,OAAO,QAAQ,wBAAwB,MAAM,QAC7C,OAAO,OAAO,QAAQ,iBAAiB,YACvC;AACA,YAAM,OAAO,QAAQ,aAAa,SAAS;AAC3C;AAAA,IACF;AACA,QAAI,OAAO,OAAO,QAAQ,2BAA2B,YAAY;AAC/D,YAAM,OAAO,QAAQ,uBAAuB,OAAO,YAAY,SAAS;AACxE;AAAA,IACF;AAAA,EACF;AACA,QAAM,OAAO,QAAQ,OAAO,SAAS;AACvC;AAEA,eAAe,mBACb,QACA,SACe;AACf,MAAI,SAAS,WAAW,MAAM;AAC5B,QAAI,OAAO,OAAO,QAAQ,0BAA0B,YAAY;AAC9D,YAAM,OAAO,QAAQ,sBAAsB,OAAO,UAAU;AAC5D;AAAA,IACF;AACA,QAAI,OAAO,OAAO,QAAQ,gBAAgB,YAAY;AACpD,YAAM,OAAO,QAAQ,YAAY;AACjC;AAAA,IACF;AAAA,EACF;AACA,MAAI,OAAO,OAAO,QAAQ,oBAAoB,YAAY;AACxD,UAAM,OAAO,QAAQ,gBAAgB,OAAO,UAAU;AACtD;AAAA,EACF;AACA,QAAM,OAAO,QAAQ,MAAM;AAC7B;AAEA,SAAS,qBAAqB,SAAwC;AACpE,SAAO,kBAAkB,WAAW,OAAO,QAAQ,iBAAiB,aAChE,QAAQ,aAAa,MAAM,OAC3B;AACN;AAEA,SAAS,6BACP,WACA,YACA,YACS;AACT,MAAI,CAAC,WAAY,QAAO;AACxB,QAAM,uBAAuB,uBAAuB,YAAY,UAAU;AAC1E,QAAM,aAAa,KAAK,QAAQ,SAAS;AACzC,QAAM,iBAAiB,KAAK,KAAK,YAAY,YAAY;AACzD,QAAM,YAAY,KAAK,WAAW,oBAAoB,IAClD,KAAK,UAAU,oBAAoB,IACnC,KAAK,QAAQ,YAAY,oBAAoB;AACjD,QAAM,WAAW,KAAK,SAAS,gBAAgB,SAAS;AACxD,SAAO,aAAa,MAAO,CAAC,SAAS,WAAW,IAAI,KAAK,CAAC,KAAK,WAAW,QAAQ;AACpF;AAEA,SAAS,uBAAuB,YAAoB,YAA4B;AAC9E,MAAI,QAAQ,WAAW,KAAK;AAC5B,MAAI,MAAM,WAAW,QAAQ,GAAG;AAC9B,QAAI;AACF,YAAM,SAAS,IAAI,IAAI,KAAK;AAC5B,UAAI,OAAO,aAAa,UAAU,OAAO,aAAa,YAAY;AAChE,gBAAQ,mBAAmB,OAAO,SAAS,QAAQ,QAAQ,EAAE,CAAC;AAAA,MAChE;AAAA,IACF,QAAQ;AACN,YAAM,YAAY,MAAM,MAAM,SAAS,MAAM;AAC7C,YAAM,aAAa,UAAU,QAAQ,GAAG;AACxC,UAAI,eAAe,IAAI;AACrB,gBAAQ,UAAU,MAAM,aAAa,CAAC;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,mBAAmB,GAAG,UAAU;AACtC,MAAI,MAAM,WAAW,gBAAgB,GAAG;AACtC,YAAQ,MAAM,MAAM,iBAAiB,MAAM;AAAA,EAC7C;AACA,SAAO;AACT;AAEA,SAAS,4BACP,OACA,YACmB;AACnB,QAAM,SAAS,oBAAI,IAA6B;AAEhD,aAAW,EAAE,WAAW,QAAQ,KAAK,OAAO;AAC1C,eAAW,UAAU,SAAS;AAC5B,YAAM,MAAM,GAAG,SAAS,KAAK,OAAO,QAAQ,OAAO,KAAK;AACxD,YAAM,WAAW,OAAO,IAAI,GAAG;AAC/B,UAAI,CAAC,UAAU;AACb,eAAO,IAAI,KAAK,MAAM;AACtB;AAAA,MACF;AACA,UAAI,OAAO,QAAQ,SAAS,OAAO;AACjC,eAAO,IAAI,KAAK;AAAA,UACd,GAAG;AAAA,UACH,SAAS,SAAS,WAAW,OAAO,WAAW;AAAA,QACjD,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO,CAAC,GAAG,OAAO,OAAO,CAAC,EACvB,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAChC,MAAM,GAAG,UAAU;AACxB;","names":[]}
@@ -321,6 +321,9 @@ async function persistExplicitCapture(orchestrator, candidate, source) {
321
321
  expiresAt: candidate.expiresAt,
322
322
  source: source === "inline" ? "explicit-inline" : "explicit"
323
323
  });
324
+ if (typeof orchestrator.recordCatalogWrite === "function") {
325
+ orchestrator.recordCatalogWrite(resolvedNamespace, storage.dir);
326
+ }
324
327
  const created = (/* @__PURE__ */ new Date()).toISOString();
325
328
  const event = {
326
329
  eventId: `mle-${randomUUID()}`,
@@ -395,16 +398,22 @@ async function queueExplicitCaptureForReview(orchestrator, input, source, error)
395
398
  entityRef: sanitizeReviewMetadata(input.entityRef),
396
399
  source: source === "inline" ? "explicit-inline-review" : "explicit-review"
397
400
  });
398
- const created = await storage.getMemoryById(id);
399
- if (created) {
400
- await storage.writeMemoryFrontmatter(created, {
401
- status: "pending_review",
402
- updated: (/* @__PURE__ */ new Date()).toISOString()
403
- }, {
404
- actor: explicitCaptureActor(source),
405
- reasonCode: reason,
406
- ruleVersion: "explicit-capture.v1"
407
- });
401
+ try {
402
+ const created = await storage.getMemoryById(id);
403
+ if (created) {
404
+ await storage.writeMemoryFrontmatter(created, {
405
+ status: "pending_review",
406
+ updated: (/* @__PURE__ */ new Date()).toISOString()
407
+ }, {
408
+ actor: explicitCaptureActor(source),
409
+ reasonCode: reason,
410
+ ruleVersion: "explicit-capture.v1"
411
+ });
412
+ }
413
+ } finally {
414
+ if (typeof orchestrator.recordCatalogWrite === "function") {
415
+ orchestrator.recordCatalogWrite(queueNamespace, storage.dir);
416
+ }
408
417
  }
409
418
  const event = {
410
419
  eventId: `mle-${randomUUID()}`,
@@ -435,4 +444,4 @@ export {
435
444
  shouldSkipImplicitExtraction,
436
445
  shouldProcessInlineExplicitCapture
437
446
  };
438
- //# sourceMappingURL=chunk-H3PHZLMF.js.map
447
+ //# sourceMappingURL=chunk-GKKAXVAJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/explicit-capture.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { Orchestrator } from \"./orchestrator.js\";\nimport { isSafeRouteNamespace } from \"./routing/engine.js\";\nimport { sanitizeMemoryContent } from \"./sanitize.js\";\nimport { ContentHashIndex } from \"./storage.js\";\nimport type { CaptureMode, MemoryCategory, MemoryLifecycleEvent, PluginConfig } from \"./types.js\";\n\nexport type ExplicitCaptureInput = {\n content: string;\n category?: string;\n confidence?: number;\n namespace?: string;\n tags?: string[];\n entityRef?: string;\n ttl?: string;\n sourceReason?: string;\n};\n\nexport type ValidExplicitCapture = {\n content: string;\n category: MemoryCategory;\n confidence: number;\n namespace?: string;\n tags: string[];\n entityRef?: string;\n expiresAt?: string;\n sourceReason?: string;\n /**\n * When true, `namespace` was already resolved AND authorized by the caller\n * (the access service's `resolveCodingScopedWriteNamespace`, which auth-checks\n * the base and derives a session-owned `project-*` overlay). The persist /\n * queue layer then routes to it directly instead of re-validating against the\n * static policy allow-list — which would otherwise reject legitimately-derived\n * dynamic project namespaces (#1434). Callers that do NOT pre-authorize the\n * namespace must leave this unset so the allow-list guard still applies.\n */\n namespacePreResolved?: boolean;\n};\n\nexport type ExplicitCaptureSource = \"memory_store\" | \"memory_capture\" | \"suggestion_submit\" | \"inline\";\ntype ExplicitCaptureValidationMode = \"legacy_tool\" | \"strict_explicit\";\n\n// Bounded body {0,100000} instead of an unbounded lazy *? so scanning for the\n// closing tag cannot backtrack polynomially on unterminated <memory_note>\n// markup in hostile turn text (CodeQL js/polynomial-redos). 100 000 chars far\n// exceeds any real inline note, so matching is behavior-preserving; the outer\n// \\s* groups were also dropped (body absorbs whitespace; captures are trimmed).\nconst INLINE_NOTE_RE = /<memory_note>([\\s\\S]{0,100000}?)<\\/memory_note>/gi;\nconst INLINE_NOTE_MARKUP_RE = /<memory_note>[\\s\\S]{0,100000}?<\\/memory_note>/i;\nconst INLINE_ALLOWED_CATEGORIES = new Set<MemoryCategory>([\n \"fact\",\n \"preference\",\n \"correction\",\n \"entity\",\n \"decision\",\n \"relationship\",\n \"principle\",\n \"commitment\",\n \"moment\",\n \"skill\",\n \"rule\",\n \"procedure\",\n \"reasoning_trace\",\n]);\n\nconst SECRET_PATTERNS: RegExp[] = [\n /\\bsk-[A-Za-z0-9]{16,}\\b/,\n /\\bAKIA[0-9A-Z]{16}\\b/,\n /\\bBearer\\s+[A-Za-z0-9._-]{16,}\\b/i,\n /\\b(?:api[_-]?key|secret|token|password|passwd)\\s*[:=]\\s*[^\\s]{8,}\\b/i,\n /\\b(?:authorization)\\s*:\\s*[^\\s]{8,}\\b/i,\n];\nconst SECRET_REDACTION_PATTERNS: Array<{ pattern: RegExp; replacement: string }> = [\n { pattern: /\\bsk-[A-Za-z0-9]{16,}\\b/g, replacement: \"[redacted openai key]\" },\n { pattern: /\\bAKIA[0-9A-Z]{16}\\b/g, replacement: \"[redacted aws key]\" },\n { pattern: /\\bBearer\\s+[A-Za-z0-9._-]{16,}\\b/gi, replacement: \"Bearer [redacted token]\" },\n {\n pattern: /\\b(?:api[_-]?key|secret|token|password|passwd)\\s*[:=]\\s*[^\\s]{8,}\\b/gi,\n replacement: \"[redacted credential]\",\n },\n {\n pattern: /\\b(?:authorization)\\s*:\\s*[^\\s]{8,}\\b/gi,\n replacement: \"authorization: [redacted credential]\",\n },\n];\nconst EXPLICIT_CAPTURE_REVIEW_TAGS = [\"explicit-capture\", \"queued-review\"];\n\nfunction explicitCaptureActor(source: ExplicitCaptureSource): string {\n switch (source) {\n case \"inline\":\n return \"inline.memory_note\";\n case \"memory_store\":\n return \"tool.memory_store\";\n case \"suggestion_submit\":\n return \"tool.suggestion_submit\";\n default:\n return \"tool.memory_capture\";\n }\n}\n\nfunction asTrimmed(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n return trimmed && trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction normalizeCaptureContent(value: string): string {\n return value\n .toLowerCase()\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nfunction redactSecrets(value: string): string {\n let redacted = value;\n for (const { pattern, replacement } of SECRET_REDACTION_PATTERNS) {\n redacted = redacted.replace(pattern, replacement);\n }\n return redacted;\n}\n\nfunction containsSecretLikeValue(value: string): boolean {\n return SECRET_PATTERNS.some((pattern) => pattern.test(value));\n}\n\nfunction assertNoSecretLikeMetadata(field: string, value: string | undefined): void {\n const trimmed = asTrimmed(value);\n if (trimmed && containsSecretLikeValue(trimmed)) {\n throw new Error(`${field} appears to contain a secret or credential`);\n }\n}\n\nfunction assertNoSecretLikeMetadataList(field: string, values: string[] | undefined): void {\n for (const value of values ?? []) {\n assertNoSecretLikeMetadata(field, value);\n }\n}\n\nfunction sanitizeReviewText(value: string | undefined, fallback: string): string {\n const redacted = redactSecrets(asTrimmed(value) ?? fallback);\n const sanitized = sanitizeMemoryContent(redacted);\n const safe = sanitized.text.trim();\n return safe.length > 0 ? safe : fallback;\n}\n\nfunction sanitizeReviewMetadata(value: string | undefined): string | undefined {\n const trimmed = asTrimmed(value);\n if (!trimmed) return undefined;\n return sanitizeReviewText(trimmed, \"[redacted]\");\n}\n\nfunction sanitizeReviewTags(tags: string[] | undefined): string[] {\n return Array.from(new Set((tags ?? [])\n .map((tag) => sanitizeReviewMetadata(tag))\n .filter((tag): tag is string => typeof tag === \"string\" && tag.length > 0)));\n}\n\nfunction normalizeExplicitCaptureError(error: unknown): string {\n if (error instanceof Error && error.message.trim().length > 0) return error.message.trim();\n const rendered = String(error).trim();\n return rendered.length > 0 ? rendered : \"explicit capture failed\";\n}\n\nfunction resolveExplicitCaptureReviewNamespace(\n orchestrator: Orchestrator,\n namespace: string | undefined,\n): string | undefined {\n const normalized = asTrimmed(namespace);\n if (!normalized) return undefined;\n return resolveExplicitCaptureNamespace(orchestrator, normalized);\n}\n\nfunction resolveExplicitCaptureNamespace(\n orchestrator: Orchestrator,\n namespace: string | undefined,\n): string | undefined {\n const normalized = asTrimmed(namespace);\n if (!normalized) return undefined;\n if (!orchestrator.config.namespacesEnabled) {\n if (normalized !== orchestrator.config.defaultNamespace) {\n throw new Error(`unsupported namespace: ${normalized}`);\n }\n return normalized;\n }\n const allowed = new Set([\n orchestrator.config.defaultNamespace,\n orchestrator.config.sharedNamespace,\n ...orchestrator.config.namespacePolicies.map((policy) => policy.name),\n ].map((value) => value.trim()).filter(Boolean));\n if (!allowed.has(normalized)) {\n throw new Error(`unsupported namespace: ${normalized}`);\n }\n return normalized;\n}\n\nfunction parseExplicitCaptureTtl(ttl: string | undefined): string | undefined {\n const raw = asTrimmed(ttl);\n if (!raw) return undefined;\n\n const absoluteMs = Date.parse(raw);\n if (Number.isFinite(absoluteMs)) {\n return new Date(absoluteMs).toISOString();\n }\n\n const relative = raw.match(/^(\\d+)\\s*([mhdw])$/i);\n if (!relative) {\n throw new Error(\"ttl must be an ISO-8601 timestamp or relative duration like 30m, 12h, 7d, or 2w\");\n }\n\n const amount = Number.parseInt(relative[1] ?? \"\", 10);\n const unit = (relative[2] ?? \"\").toLowerCase();\n if (!Number.isFinite(amount) || amount <= 0) {\n throw new Error(\"ttl duration must be a positive integer\");\n }\n\n const multiplier =\n unit === \"m\" ? 60_000\n : unit === \"h\" ? 60 * 60_000\n : unit === \"d\" ? 24 * 60 * 60_000\n : 7 * 24 * 60 * 60_000;\n return new Date(Date.now() + amount * multiplier).toISOString();\n}\n\nfunction parseInlineConfidence(value: string): number {\n const trimmed = value.trim();\n if (!/^[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?$/i.test(trimmed)) {\n return Number.NaN;\n }\n const parsed = Number(trimmed);\n return Number.isFinite(parsed) ? parsed : Number.NaN;\n}\n\nfunction parseInlineNote(block: string): ExplicitCaptureInput | null {\n const lines = block.replace(/\\r/g, \"\").split(\"\\n\");\n const note: Partial<ExplicitCaptureInput> = {};\n let idx = 0;\n\n while (idx < lines.length) {\n const rawLine = lines[idx] ?? \"\";\n const line = rawLine.trim();\n idx += 1;\n if (line.length === 0) continue;\n const colonIdx = line.indexOf(\":\");\n if (colonIdx < 0) continue;\n const key = line.slice(0, colonIdx).trim();\n const value = line.slice(colonIdx + 1).trim();\n\n if (key === \"content\" && value === \"|\") {\n const contentLines: string[] = [];\n while (idx < lines.length) {\n const next = lines[idx] ?? \"\";\n if (next.startsWith(\" \") || next.startsWith(\"\\t\")) {\n contentLines.push(next.replace(/^( |\\t)/, \"\"));\n idx += 1;\n continue;\n }\n if (next.trim().length === 0) {\n contentLines.push(\"\");\n idx += 1;\n continue;\n }\n break;\n }\n note.content = contentLines.join(\"\\n\").trim();\n continue;\n }\n\n switch (key) {\n case \"content\":\n note.content = value;\n break;\n case \"category\":\n note.category = value;\n break;\n case \"confidence\":\n note.confidence = parseInlineConfidence(value);\n break;\n case \"namespace\":\n note.namespace = value;\n break;\n case \"tags\":\n note.tags = value\n .split(\",\")\n .map((entry) => entry.trim())\n .filter(Boolean);\n break;\n case \"entityRef\":\n note.entityRef = value;\n break;\n case \"ttl\":\n note.ttl = value;\n break;\n case \"sourceReason\":\n note.sourceReason = value;\n break;\n default:\n break;\n }\n }\n\n return asTrimmed(note.content) ? (note as ExplicitCaptureInput) : null;\n}\n\nexport function parseInlineExplicitCaptureNotes(text: string): ExplicitCaptureInput[] {\n const notes: ExplicitCaptureInput[] = [];\n for (const match of text.matchAll(INLINE_NOTE_RE)) {\n const parsed = parseInlineNote(match[1] ?? \"\");\n if (parsed) notes.push(parsed);\n }\n return notes;\n}\n\nexport function hasInlineExplicitCaptureMarkup(text: string): boolean {\n return INLINE_NOTE_MARKUP_RE.test(text);\n}\n\nexport function stripInlineExplicitCaptureNotes(text: string): string {\n return text.replace(INLINE_NOTE_RE, \"\").trim();\n}\n\nexport function validateExplicitCaptureInput(\n input: ExplicitCaptureInput,\n mode: ExplicitCaptureValidationMode = \"strict_explicit\",\n): ValidExplicitCapture {\n const content = asTrimmed(input.content);\n if (!content) throw new Error(\"content is required\");\n if (mode === \"strict_explicit\") {\n if (content.length < 10) throw new Error(\"content must be at least 10 characters\");\n if (content.length > 4000) throw new Error(\"content must be 4000 characters or fewer\");\n }\n if (/<memory_note>/i.test(content) || /<\\/memory_note>/i.test(content)) {\n throw new Error(\"nested memory_note blocks are not allowed\");\n }\n\n const category = (asTrimmed(input.category) ?? \"fact\") as MemoryCategory;\n if (!INLINE_ALLOWED_CATEGORIES.has(category)) {\n throw new Error(`unsupported category: ${input.category ?? category}`);\n }\n\n const sanitized = sanitizeMemoryContent(content);\n if (!sanitized.clean) {\n throw new Error(\"content failed memory sanitization\");\n }\n for (const pattern of SECRET_PATTERNS) {\n if (pattern.test(content)) {\n throw new Error(\"content appears to contain a secret or credential\");\n }\n }\n assertNoSecretLikeMetadata(\"sourceReason\", input.sourceReason);\n assertNoSecretLikeMetadata(\"entityRef\", input.entityRef);\n assertNoSecretLikeMetadata(\"ttl\", input.ttl);\n assertNoSecretLikeMetadataList(\"tags\", input.tags);\n\n if (input.confidence !== undefined && !Number.isFinite(input.confidence)) {\n throw new Error(\"confidence must be a finite number\");\n }\n const confidence = input.confidence === undefined ? 0.95 : Number(input.confidence);\n if (confidence < 0 || confidence > 1) {\n throw new Error(\"confidence must be between 0 and 1\");\n }\n const requestedNamespace = asTrimmed(input.namespace);\n if (requestedNamespace && !isSafeRouteNamespace(requestedNamespace)) {\n throw new Error(`unsafe namespace: ${requestedNamespace}`);\n }\n const expiresAt = parseExplicitCaptureTtl(input.ttl);\n\n return {\n content,\n category,\n confidence,\n namespace: asTrimmed(input.namespace),\n tags: Array.from(new Set((input.tags ?? []).map((tag) => tag.trim()).filter(Boolean))),\n entityRef: asTrimmed(input.entityRef),\n expiresAt,\n sourceReason: asTrimmed(input.sourceReason),\n };\n}\n\nasync function findDuplicateExplicitCapture(\n orchestrator: Orchestrator,\n resolvedNamespace: string | undefined,\n candidate: ValidExplicitCapture,\n): Promise<string | null> {\n const storage = await orchestrator.getStorage(resolvedNamespace);\n if (\n candidate.category === \"fact\"\n && typeof (storage as { hasFactContentHash?: (content: string) => Promise<boolean> }).hasFactContentHash === \"function\"\n ) {\n try {\n const hasHash = await (storage as { hasFactContentHash: (content: string) => Promise<boolean> }).hasFactContentHash(\n candidate.content,\n );\n if (!hasHash) {\n const authoritative =\n typeof (storage as { isFactContentHashAuthoritative?: () => Promise<boolean> | boolean }).isFactContentHashAuthoritative\n === \"function\"\n ? await (storage as { isFactContentHashAuthoritative: () => Promise<boolean> | boolean })\n .isFactContentHashAuthoritative()\n : false;\n if (authoritative) return null;\n }\n } catch (err) {\n // Fail open: hash index is only an optimization, so fall back to the full corpus scan.\n void err;\n }\n }\n const existing = await storage.readAllMemories();\n const normalizedCandidate = normalizeCaptureContent(candidate.content);\n const match = existing.find((memory) => {\n const status = memory.frontmatter.status ?? \"active\";\n if (status !== \"active\") return false;\n if (memory.frontmatter.category !== candidate.category) return false;\n return normalizeCaptureContent(memory.content) === normalizedCandidate;\n });\n return match?.frontmatter.id ?? null;\n}\n\nexport async function persistExplicitCapture(\n orchestrator: Orchestrator,\n candidate: ValidExplicitCapture,\n source: ExplicitCaptureSource,\n): Promise<{ id: string; duplicateOf?: string }> {\n const resolvedNamespace = candidate.namespacePreResolved\n ? asTrimmed(candidate.namespace)\n : resolveExplicitCaptureNamespace(orchestrator, candidate.namespace);\n const duplicateOf = await findDuplicateExplicitCapture(orchestrator, resolvedNamespace, candidate);\n if (duplicateOf) {\n return { id: duplicateOf, duplicateOf };\n }\n\n const storage = await orchestrator.getStorage(resolvedNamespace);\n const id = await storage.writeMemory(candidate.category, candidate.content, {\n confidence: candidate.confidence,\n tags: candidate.tags,\n entityRef: candidate.entityRef,\n expiresAt: candidate.expiresAt,\n source: source === \"inline\" ? \"explicit-inline\" : \"explicit\",\n });\n // Record the catalog write touch (issue #1499, round 5 codex P2). Explicit\n // captures bypass the extraction write path, so without this their namespace\n // never updates `lastWriteAt`. An undefined namespace means the DEFAULT root\n // (round 6, codex P2), which recordCatalogWrite resolves. The method is an\n // optional best-effort hook — guard so Orchestrator-like callers without it\n // don't break (rule #33). Best-effort and failure-tolerant.\n if (typeof orchestrator.recordCatalogWrite === \"function\") {\n orchestrator.recordCatalogWrite(resolvedNamespace, storage.dir);\n }\n\n const created = new Date().toISOString();\n const event: MemoryLifecycleEvent = {\n eventId: `mle-${randomUUID()}`,\n memoryId: id,\n eventType: \"explicit_capture_accepted\",\n timestamp: created,\n actor: explicitCaptureActor(source),\n reasonCode: candidate.sourceReason,\n ruleVersion: \"explicit-capture.v1\",\n };\n await storage.appendMemoryLifecycleEvents([event]);\n\n return { id };\n}\n\nfunction buildExplicitCaptureReviewContent(input: ExplicitCaptureInput, reason: string): string {\n const requestedContent = asTrimmed(input.content);\n const safeContent = sanitizeReviewText(requestedContent, \"[empty explicit capture]\");\n const safeCategory = sanitizeReviewMetadata(input.category);\n const safeNamespace = sanitizeReviewMetadata(input.namespace);\n const safeEntityRef = sanitizeReviewMetadata(input.entityRef);\n const safeTtl = sanitizeReviewMetadata(input.ttl);\n const safeSourceReason = sanitizeReviewMetadata(input.sourceReason);\n const safeTags = sanitizeReviewTags(input.tags);\n const lines = [\n \"Explicit capture queued for review.\",\n \"\",\n `Reason: ${reason}`,\n \"\",\n \"Submitted content:\",\n safeContent,\n ];\n const metadata = [\n safeCategory ? `Requested category: ${safeCategory}` : undefined,\n safeNamespace ? `Requested namespace: ${safeNamespace}` : undefined,\n safeEntityRef ? `Requested entityRef: ${safeEntityRef}` : undefined,\n safeTtl ? `Requested ttl: ${safeTtl}` : undefined,\n safeSourceReason ? `Requested sourceReason: ${safeSourceReason}` : undefined,\n safeTags.length > 0 ? `Requested tags: ${safeTags.join(\", \")}` : undefined,\n ].filter((entry): entry is string => typeof entry === \"string\" && entry.length > 0);\n if (metadata.length > 0) {\n lines.push(\"\", ...metadata);\n }\n return lines.join(\"\\n\");\n}\n\nasync function findQueuedExplicitCaptureDuplicate(\n orchestrator: Orchestrator,\n namespace: string | undefined,\n content: string,\n): Promise<string | null> {\n const storage = await orchestrator.getStorage(namespace);\n const existing = await storage.readAllMemories();\n const normalized = normalizeCaptureContent(content);\n const match = existing.find((memory) => {\n const status = memory.frontmatter.status ?? \"active\";\n if (status !== \"pending_review\") return false;\n if (!(memory.frontmatter.tags ?? []).includes(\"queued-review\")) return false;\n return normalizeCaptureContent(memory.content) === normalized;\n });\n return match?.frontmatter.id ?? null;\n}\n\nexport async function queueExplicitCaptureForReview(\n orchestrator: Orchestrator,\n input: ExplicitCaptureInput,\n source: ExplicitCaptureSource,\n error: unknown,\n): Promise<{ id: string; duplicateOf?: string }> {\n const reason = sanitizeReviewText(normalizeExplicitCaptureError(error), \"explicit capture failed\");\n const requestedNamespace = asTrimmed(input.namespace);\n // A caller-pre-authorized namespace (e.g. a session-owned project overlay\n // from the access service) routes directly; otherwise apply the static\n // policy allow-list guard (#1434).\n const queueNamespace = (input as { namespacePreResolved?: boolean }).namespacePreResolved\n ? requestedNamespace\n : resolveExplicitCaptureReviewNamespace(orchestrator, requestedNamespace);\n const content = buildExplicitCaptureReviewContent(input, reason);\n const duplicateOf = await findQueuedExplicitCaptureDuplicate(orchestrator, queueNamespace, content);\n if (duplicateOf) {\n return { id: duplicateOf, duplicateOf };\n }\n\n const requestedCategory = asTrimmed(input.category);\n const reviewCategory = requestedCategory && INLINE_ALLOWED_CATEGORIES.has(requestedCategory as MemoryCategory)\n ? requestedCategory as MemoryCategory\n : \"fact\";\n const requestedTags = sanitizeReviewTags(input.tags);\n const storage = await orchestrator.getStorage(queueNamespace);\n const id = await storage.writeMemory(reviewCategory, content, {\n confidence: 0.2,\n tags: Array.from(new Set([...EXPLICIT_CAPTURE_REVIEW_TAGS, ...requestedTags])),\n entityRef: sanitizeReviewMetadata(input.entityRef),\n source: source === \"inline\" ? \"explicit-inline-review\" : \"explicit-review\",\n });\n try {\n const created = await storage.getMemoryById(id);\n if (created) {\n await storage.writeMemoryFrontmatter(created, {\n status: \"pending_review\",\n updated: new Date().toISOString(),\n }, {\n actor: explicitCaptureActor(source),\n reasonCode: reason,\n ruleVersion: \"explicit-capture.v1\",\n });\n }\n } finally {\n // Record the catalog write touch (issue #1499, round 5/6 codex P2; NIhUg).\n // A queued review capture writes memory to the namespace's root (the DEFAULT\n // root when undefined), so its `lastWriteAt` must reflect the write once\n // `writeMemory` returns an id. If the later pending-review frontmatter update\n // fails, the memory file is still durable and must not disappear from\n // writtenSince/maintenance scheduling. Guarded optional hook (rule #33).\n if (typeof orchestrator.recordCatalogWrite === \"function\") {\n orchestrator.recordCatalogWrite(queueNamespace, storage.dir);\n }\n }\n const event: MemoryLifecycleEvent = {\n eventId: `mle-${randomUUID()}`,\n memoryId: id,\n eventType: \"explicit_capture_queued\",\n timestamp: new Date().toISOString(),\n actor: explicitCaptureActor(source),\n reasonCode: reason,\n ruleVersion: \"explicit-capture.v1\",\n };\n await storage.appendMemoryLifecycleEvents([event]);\n return { id };\n}\n\nexport function shouldSkipImplicitExtraction(cfg: Pick<PluginConfig, \"captureMode\">): boolean {\n return cfg.captureMode === \"explicit\";\n}\n\nexport function shouldProcessInlineExplicitCapture(cfg: Pick<PluginConfig, \"captureMode\">): boolean {\n return cfg.captureMode !== \"implicit\";\n}\n"],"mappings":";;;;;;;;AAAA,SAAS,kBAAkB;AA+C3B,IAAM,iBAAiB;AACvB,IAAM,wBAAwB;AAC9B,IAAM,4BAA4B,oBAAI,IAAoB;AAAA,EACxD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,kBAA4B;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACA,IAAM,4BAA6E;AAAA,EACjF,EAAE,SAAS,4BAA4B,aAAa,wBAAwB;AAAA,EAC5E,EAAE,SAAS,yBAAyB,aAAa,qBAAqB;AAAA,EACtE,EAAE,SAAS,sCAAsC,aAAa,0BAA0B;AAAA,EACxF;AAAA,IACE,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AACF;AACA,IAAM,+BAA+B,CAAC,oBAAoB,eAAe;AAEzE,SAAS,qBAAqB,QAAuC;AACnE,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,UAAU,OAA+C;AAChE,QAAM,UAAU,OAAO,KAAK;AAC5B,SAAO,WAAW,QAAQ,SAAS,IAAI,UAAU;AACnD;AAEA,SAAS,wBAAwB,OAAuB;AACtD,SAAO,MACJ,YAAY,EACZ,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACV;AAEA,SAAS,cAAc,OAAuB;AAC5C,MAAI,WAAW;AACf,aAAW,EAAE,SAAS,YAAY,KAAK,2BAA2B;AAChE,eAAW,SAAS,QAAQ,SAAS,WAAW;AAAA,EAClD;AACA,SAAO;AACT;AAEA,SAAS,wBAAwB,OAAwB;AACvD,SAAO,gBAAgB,KAAK,CAAC,YAAY,QAAQ,KAAK,KAAK,CAAC;AAC9D;AAEA,SAAS,2BAA2B,OAAe,OAAiC;AAClF,QAAM,UAAU,UAAU,KAAK;AAC/B,MAAI,WAAW,wBAAwB,OAAO,GAAG;AAC/C,UAAM,IAAI,MAAM,GAAG,KAAK,4CAA4C;AAAA,EACtE;AACF;AAEA,SAAS,+BAA+B,OAAe,QAAoC;AACzF,aAAW,SAAS,UAAU,CAAC,GAAG;AAChC,+BAA2B,OAAO,KAAK;AAAA,EACzC;AACF;AAEA,SAAS,mBAAmB,OAA2B,UAA0B;AAC/E,QAAM,WAAW,cAAc,UAAU,KAAK,KAAK,QAAQ;AAC3D,QAAM,YAAY,sBAAsB,QAAQ;AAChD,QAAM,OAAO,UAAU,KAAK,KAAK;AACjC,SAAO,KAAK,SAAS,IAAI,OAAO;AAClC;AAEA,SAAS,uBAAuB,OAA+C;AAC7E,QAAM,UAAU,UAAU,KAAK;AAC/B,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,mBAAmB,SAAS,YAAY;AACjD;AAEA,SAAS,mBAAmB,MAAsC;AAChE,SAAO,MAAM,KAAK,IAAI,KAAK,QAAQ,CAAC,GACjC,IAAI,CAAC,QAAQ,uBAAuB,GAAG,CAAC,EACxC,OAAO,CAAC,QAAuB,OAAO,QAAQ,YAAY,IAAI,SAAS,CAAC,CAAC,CAAC;AAC/E;AAEA,SAAS,8BAA8B,OAAwB;AAC7D,MAAI,iBAAiB,SAAS,MAAM,QAAQ,KAAK,EAAE,SAAS,EAAG,QAAO,MAAM,QAAQ,KAAK;AACzF,QAAM,WAAW,OAAO,KAAK,EAAE,KAAK;AACpC,SAAO,SAAS,SAAS,IAAI,WAAW;AAC1C;AAEA,SAAS,sCACP,cACA,WACoB;AACpB,QAAM,aAAa,UAAU,SAAS;AACtC,MAAI,CAAC,WAAY,QAAO;AACxB,SAAO,gCAAgC,cAAc,UAAU;AACjE;AAEA,SAAS,gCACP,cACA,WACoB;AACpB,QAAM,aAAa,UAAU,SAAS;AACtC,MAAI,CAAC,WAAY,QAAO;AACxB,MAAI,CAAC,aAAa,OAAO,mBAAmB;AAC1C,QAAI,eAAe,aAAa,OAAO,kBAAkB;AACvD,YAAM,IAAI,MAAM,0BAA0B,UAAU,EAAE;AAAA,IACxD;AACA,WAAO;AAAA,EACT;AACA,QAAM,UAAU,IAAI,IAAI;AAAA,IACtB,aAAa,OAAO;AAAA,IACpB,aAAa,OAAO;AAAA,IACpB,GAAG,aAAa,OAAO,kBAAkB,IAAI,CAAC,WAAW,OAAO,IAAI;AAAA,EACtE,EAAE,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC;AAC9C,MAAI,CAAC,QAAQ,IAAI,UAAU,GAAG;AAC5B,UAAM,IAAI,MAAM,0BAA0B,UAAU,EAAE;AAAA,EACxD;AACA,SAAO;AACT;AAEA,SAAS,wBAAwB,KAA6C;AAC5E,QAAM,MAAM,UAAU,GAAG;AACzB,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,aAAa,KAAK,MAAM,GAAG;AACjC,MAAI,OAAO,SAAS,UAAU,GAAG;AAC/B,WAAO,IAAI,KAAK,UAAU,EAAE,YAAY;AAAA,EAC1C;AAEA,QAAM,WAAW,IAAI,MAAM,qBAAqB;AAChD,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,iFAAiF;AAAA,EACnG;AAEA,QAAM,SAAS,OAAO,SAAS,SAAS,CAAC,KAAK,IAAI,EAAE;AACpD,QAAM,QAAQ,SAAS,CAAC,KAAK,IAAI,YAAY;AAC7C,MAAI,CAAC,OAAO,SAAS,MAAM,KAAK,UAAU,GAAG;AAC3C,UAAM,IAAI,MAAM,yCAAyC;AAAA,EAC3D;AAEA,QAAM,aACJ,SAAS,MAAM,MACX,SAAS,MAAM,KAAK,MAClB,SAAS,MAAM,KAAK,KAAK,MACvB,IAAI,KAAK,KAAK;AACxB,SAAO,IAAI,KAAK,KAAK,IAAI,IAAI,SAAS,UAAU,EAAE,YAAY;AAChE;AAEA,SAAS,sBAAsB,OAAuB;AACpD,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,gDAAgD,KAAK,OAAO,GAAG;AAClE,WAAO,OAAO;AAAA,EAChB;AACA,QAAM,SAAS,OAAO,OAAO;AAC7B,SAAO,OAAO,SAAS,MAAM,IAAI,SAAS,OAAO;AACnD;AAEA,SAAS,gBAAgB,OAA4C;AACnE,QAAM,QAAQ,MAAM,QAAQ,OAAO,EAAE,EAAE,MAAM,IAAI;AACjD,QAAM,OAAsC,CAAC;AAC7C,MAAI,MAAM;AAEV,SAAO,MAAM,MAAM,QAAQ;AACzB,UAAM,UAAU,MAAM,GAAG,KAAK;AAC9B,UAAM,OAAO,QAAQ,KAAK;AAC1B,WAAO;AACP,QAAI,KAAK,WAAW,EAAG;AACvB,UAAM,WAAW,KAAK,QAAQ,GAAG;AACjC,QAAI,WAAW,EAAG;AAClB,UAAM,MAAM,KAAK,MAAM,GAAG,QAAQ,EAAE,KAAK;AACzC,UAAM,QAAQ,KAAK,MAAM,WAAW,CAAC,EAAE,KAAK;AAE5C,QAAI,QAAQ,aAAa,UAAU,KAAK;AACtC,YAAM,eAAyB,CAAC;AAChC,aAAO,MAAM,MAAM,QAAQ;AACzB,cAAM,OAAO,MAAM,GAAG,KAAK;AAC3B,YAAI,KAAK,WAAW,IAAI,KAAK,KAAK,WAAW,GAAI,GAAG;AAClD,uBAAa,KAAK,KAAK,QAAQ,YAAY,EAAE,CAAC;AAC9C,iBAAO;AACP;AAAA,QACF;AACA,YAAI,KAAK,KAAK,EAAE,WAAW,GAAG;AAC5B,uBAAa,KAAK,EAAE;AACpB,iBAAO;AACP;AAAA,QACF;AACA;AAAA,MACF;AACA,WAAK,UAAU,aAAa,KAAK,IAAI,EAAE,KAAK;AAC5C;AAAA,IACF;AAEA,YAAQ,KAAK;AAAA,MACX,KAAK;AACH,aAAK,UAAU;AACf;AAAA,MACF,KAAK;AACH,aAAK,WAAW;AAChB;AAAA,MACF,KAAK;AACH,aAAK,aAAa,sBAAsB,KAAK;AAC7C;AAAA,MACF,KAAK;AACH,aAAK,YAAY;AACjB;AAAA,MACF,KAAK;AACH,aAAK,OAAO,MACT,MAAM,GAAG,EACT,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAC3B,OAAO,OAAO;AACjB;AAAA,MACF,KAAK;AACH,aAAK,YAAY;AACjB;AAAA,MACF,KAAK;AACH,aAAK,MAAM;AACX;AAAA,MACF,KAAK;AACH,aAAK,eAAe;AACpB;AAAA,MACF;AACE;AAAA,IACJ;AAAA,EACF;AAEA,SAAO,UAAU,KAAK,OAAO,IAAK,OAAgC;AACpE;AAEO,SAAS,gCAAgC,MAAsC;AACpF,QAAM,QAAgC,CAAC;AACvC,aAAW,SAAS,KAAK,SAAS,cAAc,GAAG;AACjD,UAAM,SAAS,gBAAgB,MAAM,CAAC,KAAK,EAAE;AAC7C,QAAI,OAAQ,OAAM,KAAK,MAAM;AAAA,EAC/B;AACA,SAAO;AACT;AAEO,SAAS,+BAA+B,MAAuB;AACpE,SAAO,sBAAsB,KAAK,IAAI;AACxC;AAEO,SAAS,gCAAgC,MAAsB;AACpE,SAAO,KAAK,QAAQ,gBAAgB,EAAE,EAAE,KAAK;AAC/C;AAEO,SAAS,6BACd,OACA,OAAsC,mBAChB;AACtB,QAAM,UAAU,UAAU,MAAM,OAAO;AACvC,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,qBAAqB;AACnD,MAAI,SAAS,mBAAmB;AAC9B,QAAI,QAAQ,SAAS,GAAI,OAAM,IAAI,MAAM,wCAAwC;AACjF,QAAI,QAAQ,SAAS,IAAM,OAAM,IAAI,MAAM,0CAA0C;AAAA,EACvF;AACA,MAAI,iBAAiB,KAAK,OAAO,KAAK,mBAAmB,KAAK,OAAO,GAAG;AACtE,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AAEA,QAAM,WAAY,UAAU,MAAM,QAAQ,KAAK;AAC/C,MAAI,CAAC,0BAA0B,IAAI,QAAQ,GAAG;AAC5C,UAAM,IAAI,MAAM,yBAAyB,MAAM,YAAY,QAAQ,EAAE;AAAA,EACvE;AAEA,QAAM,YAAY,sBAAsB,OAAO;AAC/C,MAAI,CAAC,UAAU,OAAO;AACpB,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACtD;AACA,aAAW,WAAW,iBAAiB;AACrC,QAAI,QAAQ,KAAK,OAAO,GAAG;AACzB,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACrE;AAAA,EACF;AACA,6BAA2B,gBAAgB,MAAM,YAAY;AAC7D,6BAA2B,aAAa,MAAM,SAAS;AACvD,6BAA2B,OAAO,MAAM,GAAG;AAC3C,iCAA+B,QAAQ,MAAM,IAAI;AAEjD,MAAI,MAAM,eAAe,UAAa,CAAC,OAAO,SAAS,MAAM,UAAU,GAAG;AACxE,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACtD;AACA,QAAM,aAAa,MAAM,eAAe,SAAY,OAAO,OAAO,MAAM,UAAU;AAClF,MAAI,aAAa,KAAK,aAAa,GAAG;AACpC,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACtD;AACA,QAAM,qBAAqB,UAAU,MAAM,SAAS;AACpD,MAAI,sBAAsB,CAAC,qBAAqB,kBAAkB,GAAG;AACnE,UAAM,IAAI,MAAM,qBAAqB,kBAAkB,EAAE;AAAA,EAC3D;AACA,QAAM,YAAY,wBAAwB,MAAM,GAAG;AAEnD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,UAAU,MAAM,SAAS;AAAA,IACpC,MAAM,MAAM,KAAK,IAAI,KAAK,MAAM,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC,CAAC;AAAA,IACrF,WAAW,UAAU,MAAM,SAAS;AAAA,IACpC;AAAA,IACA,cAAc,UAAU,MAAM,YAAY;AAAA,EAC5C;AACF;AAEA,eAAe,6BACb,cACA,mBACA,WACwB;AACxB,QAAM,UAAU,MAAM,aAAa,WAAW,iBAAiB;AAC/D,MACE,UAAU,aAAa,UACpB,OAAQ,QAA2E,uBAAuB,YAC7G;AACA,QAAI;AACF,YAAM,UAAU,MAAO,QAA0E;AAAA,QAC/F,UAAU;AAAA,MACZ;AACA,UAAI,CAAC,SAAS;AACZ,cAAM,gBACJ,OAAQ,QAAkF,mCACpF,aACF,MAAO,QACN,+BAA+B,IAChC;AACN,YAAI,cAAe,QAAO;AAAA,MAC5B;AAAA,IACF,SAAS,KAAK;AAEZ,WAAK;AAAA,IACP;AAAA,EACF;AACA,QAAM,WAAW,MAAM,QAAQ,gBAAgB;AAC/C,QAAM,sBAAsB,wBAAwB,UAAU,OAAO;AACrE,QAAM,QAAQ,SAAS,KAAK,CAAC,WAAW;AACtC,UAAM,SAAS,OAAO,YAAY,UAAU;AAC5C,QAAI,WAAW,SAAU,QAAO;AAChC,QAAI,OAAO,YAAY,aAAa,UAAU,SAAU,QAAO;AAC/D,WAAO,wBAAwB,OAAO,OAAO,MAAM;AAAA,EACrD,CAAC;AACD,SAAO,OAAO,YAAY,MAAM;AAClC;AAEA,eAAsB,uBACpB,cACA,WACA,QAC+C;AAC/C,QAAM,oBAAoB,UAAU,uBAChC,UAAU,UAAU,SAAS,IAC7B,gCAAgC,cAAc,UAAU,SAAS;AACrE,QAAM,cAAc,MAAM,6BAA6B,cAAc,mBAAmB,SAAS;AACjG,MAAI,aAAa;AACf,WAAO,EAAE,IAAI,aAAa,YAAY;AAAA,EACxC;AAEA,QAAM,UAAU,MAAM,aAAa,WAAW,iBAAiB;AAC/D,QAAM,KAAK,MAAM,QAAQ,YAAY,UAAU,UAAU,UAAU,SAAS;AAAA,IAC1E,YAAY,UAAU;AAAA,IACtB,MAAM,UAAU;AAAA,IAChB,WAAW,UAAU;AAAA,IACrB,WAAW,UAAU;AAAA,IACrB,QAAQ,WAAW,WAAW,oBAAoB;AAAA,EACpD,CAAC;AAOD,MAAI,OAAO,aAAa,uBAAuB,YAAY;AACzD,iBAAa,mBAAmB,mBAAmB,QAAQ,GAAG;AAAA,EAChE;AAEA,QAAM,WAAU,oBAAI,KAAK,GAAE,YAAY;AACvC,QAAM,QAA8B;AAAA,IAClC,SAAS,OAAO,WAAW,CAAC;AAAA,IAC5B,UAAU;AAAA,IACV,WAAW;AAAA,IACX,WAAW;AAAA,IACX,OAAO,qBAAqB,MAAM;AAAA,IAClC,YAAY,UAAU;AAAA,IACtB,aAAa;AAAA,EACf;AACA,QAAM,QAAQ,4BAA4B,CAAC,KAAK,CAAC;AAEjD,SAAO,EAAE,GAAG;AACd;AAEA,SAAS,kCAAkC,OAA6B,QAAwB;AAC9F,QAAM,mBAAmB,UAAU,MAAM,OAAO;AAChD,QAAM,cAAc,mBAAmB,kBAAkB,0BAA0B;AACnF,QAAM,eAAe,uBAAuB,MAAM,QAAQ;AAC1D,QAAM,gBAAgB,uBAAuB,MAAM,SAAS;AAC5D,QAAM,gBAAgB,uBAAuB,MAAM,SAAS;AAC5D,QAAM,UAAU,uBAAuB,MAAM,GAAG;AAChD,QAAM,mBAAmB,uBAAuB,MAAM,YAAY;AAClE,QAAM,WAAW,mBAAmB,MAAM,IAAI;AAC9C,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA,WAAW,MAAM;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,WAAW;AAAA,IACf,eAAe,uBAAuB,YAAY,KAAK;AAAA,IACvD,gBAAgB,wBAAwB,aAAa,KAAK;AAAA,IAC1D,gBAAgB,wBAAwB,aAAa,KAAK;AAAA,IAC1D,UAAU,kBAAkB,OAAO,KAAK;AAAA,IACxC,mBAAmB,2BAA2B,gBAAgB,KAAK;AAAA,IACnE,SAAS,SAAS,IAAI,mBAAmB,SAAS,KAAK,IAAI,CAAC,KAAK;AAAA,EACnE,EAAE,OAAO,CAAC,UAA2B,OAAO,UAAU,YAAY,MAAM,SAAS,CAAC;AAClF,MAAI,SAAS,SAAS,GAAG;AACvB,UAAM,KAAK,IAAI,GAAG,QAAQ;AAAA,EAC5B;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,eAAe,mCACb,cACA,WACA,SACwB;AACxB,QAAM,UAAU,MAAM,aAAa,WAAW,SAAS;AACvD,QAAM,WAAW,MAAM,QAAQ,gBAAgB;AAC/C,QAAM,aAAa,wBAAwB,OAAO;AAClD,QAAM,QAAQ,SAAS,KAAK,CAAC,WAAW;AACtC,UAAM,SAAS,OAAO,YAAY,UAAU;AAC5C,QAAI,WAAW,iBAAkB,QAAO;AACxC,QAAI,EAAE,OAAO,YAAY,QAAQ,CAAC,GAAG,SAAS,eAAe,EAAG,QAAO;AACvE,WAAO,wBAAwB,OAAO,OAAO,MAAM;AAAA,EACrD,CAAC;AACD,SAAO,OAAO,YAAY,MAAM;AAClC;AAEA,eAAsB,8BACpB,cACA,OACA,QACA,OAC+C;AAC/C,QAAM,SAAS,mBAAmB,8BAA8B,KAAK,GAAG,yBAAyB;AACjG,QAAM,qBAAqB,UAAU,MAAM,SAAS;AAIpD,QAAM,iBAAkB,MAA6C,uBACjE,qBACA,sCAAsC,cAAc,kBAAkB;AAC1E,QAAM,UAAU,kCAAkC,OAAO,MAAM;AAC/D,QAAM,cAAc,MAAM,mCAAmC,cAAc,gBAAgB,OAAO;AAClG,MAAI,aAAa;AACf,WAAO,EAAE,IAAI,aAAa,YAAY;AAAA,EACxC;AAEA,QAAM,oBAAoB,UAAU,MAAM,QAAQ;AAClD,QAAM,iBAAiB,qBAAqB,0BAA0B,IAAI,iBAAmC,IACzG,oBACA;AACJ,QAAM,gBAAgB,mBAAmB,MAAM,IAAI;AACnD,QAAM,UAAU,MAAM,aAAa,WAAW,cAAc;AAC5D,QAAM,KAAK,MAAM,QAAQ,YAAY,gBAAgB,SAAS;AAAA,IAC5D,YAAY;AAAA,IACZ,MAAM,MAAM,KAAK,oBAAI,IAAI,CAAC,GAAG,8BAA8B,GAAG,aAAa,CAAC,CAAC;AAAA,IAC7E,WAAW,uBAAuB,MAAM,SAAS;AAAA,IACjD,QAAQ,WAAW,WAAW,2BAA2B;AAAA,EAC3D,CAAC;AACD,MAAI;AACF,UAAM,UAAU,MAAM,QAAQ,cAAc,EAAE;AAC9C,QAAI,SAAS;AACX,YAAM,QAAQ,uBAAuB,SAAS;AAAA,QAC5C,QAAQ;AAAA,QACR,UAAS,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,GAAG;AAAA,QACD,OAAO,qBAAqB,MAAM;AAAA,QAClC,YAAY;AAAA,QACZ,aAAa;AAAA,MACf,CAAC;AAAA,IACH;AAAA,EACF,UAAE;AAOA,QAAI,OAAO,aAAa,uBAAuB,YAAY;AACzD,mBAAa,mBAAmB,gBAAgB,QAAQ,GAAG;AAAA,IAC7D;AAAA,EACF;AACA,QAAM,QAA8B;AAAA,IAClC,SAAS,OAAO,WAAW,CAAC;AAAA,IAC5B,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,OAAO,qBAAqB,MAAM;AAAA,IAClC,YAAY;AAAA,IACZ,aAAa;AAAA,EACf;AACA,QAAM,QAAQ,4BAA4B,CAAC,KAAK,CAAC;AACjD,SAAO,EAAE,GAAG;AACd;AAEO,SAAS,6BAA6B,KAAiD;AAC5F,SAAO,IAAI,gBAAgB;AAC7B;AAEO,SAAS,mCAAmC,KAAiD;AAClG,SAAO,IAAI,gBAAgB;AAC7B;","names":[]}
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-CINZGPSJ.js";
8
8
  import {
9
9
  resolveEnsureCollectionArgs
10
- } from "./chunk-2DGQLOOM.js";
10
+ } from "./chunk-M3VYPE2H.js";
11
11
  import {
12
12
  log
13
13
  } from "./chunk-2ODBA7MQ.js";
@@ -605,4 +605,4 @@ export {
605
605
  resolveOramaCollectionDbFilePath,
606
606
  OramaBackend
607
607
  };
608
- //# sourceMappingURL=chunk-JBHXMCYN.js.map
608
+ //# sourceMappingURL=chunk-GRYAECRV.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  StorageManager
3
- } from "./chunk-Y7NWBBHV.js";
3
+ } from "./chunk-TEO46GMM.js";
4
4
 
5
5
  // src/semantic-rule-promotion.ts
6
6
  import { createHash, randomUUID } from "crypto";
@@ -529,4 +529,4 @@ export {
529
529
  setSemanticRulePromotionTestHooks,
530
530
  promoteSemanticRuleFromMemory
531
531
  };
532
- //# sourceMappingURL=chunk-EHQLDFSH.js.map
532
+ //# sourceMappingURL=chunk-IQ53ZSXV.js.map
@@ -595,6 +595,55 @@ function resolveEmitLegacyTools(configValue) {
595
595
  }
596
596
  return true;
597
597
  }
598
+ function resolveNamespaceCatalogEnabled(configValue) {
599
+ const ACCEPTED = "true/false/1/0/yes/no/on/off";
600
+ if (configValue !== void 0 && configValue !== null) {
601
+ const coerced = coerceBooleanLike(configValue);
602
+ if (coerced === void 0) {
603
+ throw new Error(
604
+ `namespaceCatalogEnabled must be a boolean-like value (${ACCEPTED}); got ${JSON.stringify(configValue)}`
605
+ );
606
+ }
607
+ return coerced;
608
+ }
609
+ return true;
610
+ }
611
+ function readNestedConfig(cfg, blockName, key) {
612
+ const block = validateNestedConfigBlock(cfg, blockName);
613
+ if (!block) return void 0;
614
+ return block[key];
615
+ }
616
+ function validateNestedConfigBlock(cfg, blockName) {
617
+ const block = cfg[blockName];
618
+ if (block === void 0 || block === null) return void 0;
619
+ if (typeof block !== "object" || Array.isArray(block)) {
620
+ throw new Error(`${blockName} must be a plain object`);
621
+ }
622
+ return block;
623
+ }
624
+ function readFlatOrNestedConfig(cfg, flatKey, blockName, nestedKey) {
625
+ return cfg[flatKey] !== void 0 ? cfg[flatKey] : readNestedConfig(cfg, blockName, nestedKey);
626
+ }
627
+ function resolveBooleanConfig(value, defaultValue, keyName) {
628
+ if (value === void 0 || value === null) return defaultValue;
629
+ const coerced = coerceBool(value);
630
+ if (coerced === void 0) {
631
+ throw new Error(
632
+ `${keyName} must be a boolean-like value (true/false/1/0/yes/no/on/off); got ${JSON.stringify(value)}`
633
+ );
634
+ }
635
+ return coerced;
636
+ }
637
+ function resolvePositiveIntegerConfig(value, defaultValue, keyName) {
638
+ if (value === void 0 || value === null) return defaultValue;
639
+ const coerced = coerceNumber(value);
640
+ if (coerced === void 0 || !Number.isFinite(coerced) || !Number.isInteger(coerced) || coerced < 1) {
641
+ throw new Error(
642
+ `${keyName} must be a positive integer; got ${JSON.stringify(value)}`
643
+ );
644
+ }
645
+ return coerced;
646
+ }
598
647
  function isOpenaiApiKeyDisabled(value) {
599
648
  return value === false || typeof value === "string" && value.trim().toLowerCase() === "false";
600
649
  }
@@ -875,6 +924,7 @@ function parseConfig(raw) {
875
924
  } else {
876
925
  cfg = baseCfg;
877
926
  }
927
+ validateNestedConfigBlock(cfg, "maintenance");
878
928
  const modelSource = cfg.modelSource === "gateway" ? "gateway" : "plugin";
879
929
  const openaiApiKeyDisabled = isOpenaiApiKeyDisabled(cfg.openaiApiKey);
880
930
  let apiKey;
@@ -1137,6 +1187,66 @@ function parseConfig(raw) {
1137
1187
  const sharedCrossSignalSemanticEnabled = cfg.sharedCrossSignalSemanticEnabled === true || cfg.crossSignalsSemanticEnabled === true;
1138
1188
  const sharedCrossSignalSemanticTimeoutMs = typeof cfg.sharedCrossSignalSemanticTimeoutMs === "number" ? Math.max(1, Math.floor(cfg.sharedCrossSignalSemanticTimeoutMs)) : typeof cfg.crossSignalsSemanticTimeoutMs === "number" ? Math.max(1, Math.floor(cfg.crossSignalsSemanticTimeoutMs)) : 4e3;
1139
1189
  const recallPipelineConfig = buildRecallPipelineConfig(cfg);
1190
+ const maintenanceNamespaceFanoutEnabled = resolveBooleanConfig(
1191
+ readFlatOrNestedConfig(
1192
+ cfg,
1193
+ "maintenanceNamespaceFanoutEnabled",
1194
+ "maintenance",
1195
+ "namespaceFanoutEnabled"
1196
+ ),
1197
+ true,
1198
+ "maintenance.namespaceFanoutEnabled"
1199
+ );
1200
+ const maintenanceMaxNamespacesPerCycle = resolvePositiveIntegerConfig(
1201
+ readFlatOrNestedConfig(
1202
+ cfg,
1203
+ "maintenanceMaxNamespacesPerCycle",
1204
+ "maintenance",
1205
+ "maxNamespacesPerCycle"
1206
+ ),
1207
+ 20,
1208
+ "maintenance.maxNamespacesPerCycle"
1209
+ );
1210
+ const maintenanceIncludeProjectNamespaces = resolveBooleanConfig(
1211
+ readFlatOrNestedConfig(
1212
+ cfg,
1213
+ "maintenanceIncludeProjectNamespaces",
1214
+ "maintenance",
1215
+ "includeProjectNamespaces"
1216
+ ),
1217
+ true,
1218
+ "maintenance.includeProjectNamespaces"
1219
+ );
1220
+ const maintenanceIncludeBranchNamespaces = resolveBooleanConfig(
1221
+ readFlatOrNestedConfig(
1222
+ cfg,
1223
+ "maintenanceIncludeBranchNamespaces",
1224
+ "maintenance",
1225
+ "includeBranchNamespaces"
1226
+ ),
1227
+ false,
1228
+ "maintenance.includeBranchNamespaces"
1229
+ );
1230
+ const maintenanceIncludeTeamProjectNamespaces = resolveBooleanConfig(
1231
+ readFlatOrNestedConfig(
1232
+ cfg,
1233
+ "maintenanceIncludeTeamProjectNamespaces",
1234
+ "maintenance",
1235
+ "includeTeamProjectNamespaces"
1236
+ ),
1237
+ true,
1238
+ "maintenance.includeTeamProjectNamespaces"
1239
+ );
1240
+ const maintenanceNamespaceLockStaleMs = resolvePositiveIntegerConfig(
1241
+ readFlatOrNestedConfig(
1242
+ cfg,
1243
+ "maintenanceNamespaceLockStaleMs",
1244
+ "maintenance",
1245
+ "namespaceLockStaleMs"
1246
+ ),
1247
+ 10 * 6e4,
1248
+ "maintenance.namespaceLockStaleMs"
1249
+ );
1140
1250
  return {
1141
1251
  openaiApiKey: apiKey,
1142
1252
  openaiBaseUrl: baseUrl,
@@ -1840,6 +1950,12 @@ function parseConfig(raw) {
1840
1950
  // QMD maintenance (debounced singleflight)
1841
1951
  qmdMaintenanceEnabled: cfg.qmdMaintenanceEnabled !== false,
1842
1952
  qmdMaintenanceDebounceMs: typeof cfg.qmdMaintenanceDebounceMs === "number" ? cfg.qmdMaintenanceDebounceMs : 3e4,
1953
+ maintenanceNamespaceFanoutEnabled,
1954
+ maintenanceMaxNamespacesPerCycle,
1955
+ maintenanceIncludeProjectNamespaces,
1956
+ maintenanceIncludeBranchNamespaces,
1957
+ maintenanceIncludeTeamProjectNamespaces,
1958
+ maintenanceNamespaceLockStaleMs,
1843
1959
  qmdAutoEmbedEnabled: cfg.qmdAutoEmbedEnabled === true,
1844
1960
  qmdEmbedMinIntervalMs: typeof cfg.qmdEmbedMinIntervalMs === "number" ? cfg.qmdEmbedMinIntervalMs : 60 * 6e4,
1845
1961
  qmdUpdateTimeoutMs: typeof cfg.qmdUpdateTimeoutMs === "number" ? cfg.qmdUpdateTimeoutMs : 9e4,
@@ -1879,6 +1995,14 @@ function parseConfig(raw) {
1879
1995
  taskModelChain,
1880
1996
  // v3.0 namespaces (default off)
1881
1997
  namespacesEnabled: cfg.namespacesEnabled === true,
1998
+ // Namespace catalog (issue #1499): default ON, but only does anything when
1999
+ // namespacesEnabled is also true (the catalog is inert otherwise). Operators
2000
+ // opt out with namespaceCatalogEnabled: false. Boolean-like opt-outs from
2001
+ // CLI/env/JSON ("false", "0", "no", "off") are honored (CLAUDE.md rule #36);
2002
+ // a PRESENT but unrecognized value ("flase", 2) is REJECTED rather than
2003
+ // silently defaulting to enabled (CLAUDE.md rule #51); default to enabled
2004
+ // only when the value is absent.
2005
+ namespaceCatalogEnabled: resolveNamespaceCatalogEnabled(cfg.namespaceCatalogEnabled),
1882
2006
  // NOTE: namespace identifiers are intentionally NOT sanitized here — the
1883
2007
  // codebase rejects unsafe namespaces at the point of use (see
1884
2008
  // codex-materialize-runner and NamespaceStorageRouter / resolveNamespaceDir),
@@ -2805,4 +2929,4 @@ export {
2805
2929
  VALID_MEMORY_CATEGORIES,
2806
2930
  parseConfig
2807
2931
  };
2808
- //# sourceMappingURL=chunk-C63WC454.js.map
2932
+ //# sourceMappingURL=chunk-KOI765XP.js.map