@remnic/core 9.9.1 → 9.9.3

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 (149) hide show
  1. package/dist/access-admin-ops-surface.js +24 -23
  2. package/dist/access-boundary.js +24 -23
  3. package/dist/access-citation-namespace.d.ts +19 -0
  4. package/dist/access-citation-namespace.js +13 -0
  5. package/dist/access-cli.js +67 -66
  6. package/dist/access-cli.js.map +1 -1
  7. package/dist/access-http.js +31 -30
  8. package/dist/access-identity-continuity-surface.js +24 -23
  9. package/dist/access-lcm-surface.js +24 -23
  10. package/dist/access-mcp.js +29 -28
  11. package/dist/access-observe-write-surface.js +24 -23
  12. package/dist/access-operations-batch.js +26 -25
  13. package/dist/access-operations.js +28 -27
  14. package/dist/access-recall-concurrency.js +24 -23
  15. package/dist/access-recall-response.js +24 -23
  16. package/dist/access-recall-surface.js +24 -23
  17. package/dist/access-schema.js +5 -5
  18. package/dist/access-service.js +27 -26
  19. package/dist/active-recall.js +3 -3
  20. package/dist/briefing.js +6 -6
  21. package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-GWVG7LGC.js} +2 -2
  22. package/dist/capsule-crypto-GWVG7LGC.js.map +1 -0
  23. package/dist/causal-consolidation.js +9 -9
  24. package/dist/{chunk-LEPOP46W.js → chunk-227UFSEQ.js} +4 -4
  25. package/dist/{chunk-MC5Q3J7S.js → chunk-3332THSR.js} +10 -10
  26. package/dist/chunk-3PDOVUHC.js +48 -0
  27. package/dist/chunk-3PDOVUHC.js.map +1 -0
  28. package/dist/{chunk-EEC7UJPX.js → chunk-46OH3OVK.js} +2 -2
  29. package/dist/{chunk-VDX2J7OX.js → chunk-5W7CTZ2E.js} +4 -4
  30. package/dist/{chunk-KAVBJSBQ.js → chunk-7G7DVA2C.js} +2 -2
  31. package/dist/{chunk-4BJQODZF.js → chunk-7HZMTXXB.js} +14 -14
  32. package/dist/{chunk-GFPZS3F5.js → chunk-A56B2AJR.js} +5 -5
  33. package/dist/{chunk-A6USBZTO.js → chunk-AAP5T6QG.js} +5 -5
  34. package/dist/{chunk-AJ7QCSIS.js → chunk-ALSGMEJR.js} +5 -5
  35. package/dist/{chunk-57OWKFUQ.js → chunk-AS6UOOXF.js} +2 -2
  36. package/dist/{chunk-OGCAYLNA.js → chunk-B4C3JSJT.js} +3 -3
  37. package/dist/{chunk-WON4APQY.js → chunk-CAZ2SHEP.js} +2 -2
  38. package/dist/{chunk-7RNBVZZO.js → chunk-CQ6WP3PA.js} +2 -2
  39. package/dist/{chunk-FUTF72MJ.js → chunk-DF552QUN.js} +5 -5
  40. package/dist/{chunk-ZVAYK7GU.js → chunk-DZQZHQQ4.js} +13 -13
  41. package/dist/{chunk-72VAXGEI.js → chunk-E4OCKU67.js} +4 -4
  42. package/dist/{chunk-5Q7EVV4X.js → chunk-HLG7VAZP.js} +2 -2
  43. package/dist/{chunk-IFH6LWTO.js → chunk-IAHNKI2E.js} +22 -8
  44. package/dist/chunk-IAHNKI2E.js.map +1 -0
  45. package/dist/{chunk-FFPJINJE.js → chunk-IQFS4AU7.js} +2 -2
  46. package/dist/{chunk-EKBNDKDY.js → chunk-KN6UGAQB.js} +4 -4
  47. package/dist/{chunk-XQDRKZ7V.js → chunk-KQILYXND.js} +34 -35
  48. package/dist/chunk-KQILYXND.js.map +1 -0
  49. package/dist/{chunk-44XZ75OQ.js → chunk-O4K3DWK2.js} +5 -5
  50. package/dist/{chunk-BXLOS5AJ.js → chunk-OWHERGF2.js} +2 -2
  51. package/dist/{chunk-6DRPPQEJ.js → chunk-P5FPO2BR.js} +4 -4
  52. package/dist/{chunk-2UFO7X4Q.js → chunk-QZGN4773.js} +6 -6
  53. package/dist/{chunk-PMUD7ERF.js → chunk-SOTYFJOA.js} +48 -48
  54. package/dist/{chunk-2VEOKUPP.js → chunk-TC5HBIIT.js} +3 -3
  55. package/dist/{chunk-A72SWTWW.js → chunk-TY6NBWV4.js} +2 -2
  56. package/dist/{chunk-DQEMWVMT.js → chunk-UVYI6VIX.js} +1 -1
  57. package/dist/{chunk-MYFQ3ED4.js → chunk-W2OST2HH.js} +2 -2
  58. package/dist/{chunk-QVT3E4CE.js → chunk-WSHJAY5M.js} +6 -6
  59. package/dist/{chunk-6O22TZSB.js → chunk-XMAD32BW.js} +2 -2
  60. package/dist/{chunk-EHCBW6DN.js → chunk-XPR7572Y.js} +62 -61
  61. package/dist/{chunk-EHCBW6DN.js.map → chunk-XPR7572Y.js.map} +1 -1
  62. package/dist/{chunk-CXZQOVIE.js → chunk-XRNU7OEQ.js} +5 -5
  63. package/dist/{chunk-R26ZMXR2.js → chunk-Y6XODVJ4.js} +15 -15
  64. package/dist/{chunk-OQJIB32H.js → chunk-YO3ZB3PJ.js} +8 -8
  65. package/dist/{chunk-C6XBRYVD.js → chunk-YQQYS2K4.js} +2 -2
  66. package/dist/{chunk-F7GAIWFA.js → chunk-YSDVEPV2.js} +7 -7
  67. package/dist/{chunk-YROFNEG5.js → chunk-YUQOAKPX.js} +2 -2
  68. package/dist/cli.js +50 -49
  69. package/dist/compounding/engine.js +6 -6
  70. package/dist/config.js +3 -3
  71. package/dist/connectors/codex-materialize-runner.js +7 -7
  72. package/dist/connectors/index.js +8 -8
  73. package/dist/contradiction/index.js +4 -4
  74. package/dist/conversation-index/backend.js +2 -2
  75. package/dist/entity-retrieval.js +6 -6
  76. package/dist/extraction.js +2 -2
  77. package/dist/index.js +95 -94
  78. package/dist/maintenance/memory-governance.js +6 -6
  79. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +6 -6
  80. package/dist/maintenance/rebuild-memory-projection.js +7 -7
  81. package/dist/namespaces/migrate.js +15 -15
  82. package/dist/namespaces/search.js +8 -8
  83. package/dist/namespaces/storage.js +7 -7
  84. package/dist/offline-sync-impression-drain.js +4 -4
  85. package/dist/offline-sync.js +2 -2
  86. package/dist/operator-toolkit.js +22 -22
  87. package/dist/orchestration/maintenance.js +12 -12
  88. package/dist/orchestrator.js +67 -66
  89. package/dist/resume-bundles.js +7 -7
  90. package/dist/search/factory.js +7 -7
  91. package/dist/search/index.js +11 -11
  92. package/dist/search/lancedb-backend.js +1 -1
  93. package/dist/search/meilisearch-backend.js +1 -1
  94. package/dist/search/orama-backend.js +1 -1
  95. package/dist/semantic-consolidation.js +8 -8
  96. package/dist/semantic-rule-promotion.js +6 -6
  97. package/dist/semantic-rule-verifier.js +6 -6
  98. package/dist/session-transcript-migration.js +2 -2
  99. package/dist/storage.js +5 -5
  100. package/dist/summarizer.js +3 -3
  101. package/dist/summary-snapshot.js +2 -2
  102. package/dist/transfer/backup.js +2 -2
  103. package/dist/transfer/capsule-export.js +2 -2
  104. package/dist/transfer/capsule-import.js +2 -2
  105. package/dist/verified-recall.js +6 -6
  106. package/package.json +2 -2
  107. package/src/access-citation-namespace.ts +74 -0
  108. package/src/access-service.ts +7 -11
  109. package/src/namespaces/search.ts +54 -11
  110. package/src/wearables/registry.ts +1 -0
  111. package/dist/chunk-IFH6LWTO.js.map +0 -1
  112. package/dist/chunk-XQDRKZ7V.js.map +0 -1
  113. /package/dist/{capsule-crypto-YO5QJ6L3.js.map → access-citation-namespace.js.map} +0 -0
  114. /package/dist/{chunk-LEPOP46W.js.map → chunk-227UFSEQ.js.map} +0 -0
  115. /package/dist/{chunk-MC5Q3J7S.js.map → chunk-3332THSR.js.map} +0 -0
  116. /package/dist/{chunk-EEC7UJPX.js.map → chunk-46OH3OVK.js.map} +0 -0
  117. /package/dist/{chunk-VDX2J7OX.js.map → chunk-5W7CTZ2E.js.map} +0 -0
  118. /package/dist/{chunk-KAVBJSBQ.js.map → chunk-7G7DVA2C.js.map} +0 -0
  119. /package/dist/{chunk-4BJQODZF.js.map → chunk-7HZMTXXB.js.map} +0 -0
  120. /package/dist/{chunk-GFPZS3F5.js.map → chunk-A56B2AJR.js.map} +0 -0
  121. /package/dist/{chunk-A6USBZTO.js.map → chunk-AAP5T6QG.js.map} +0 -0
  122. /package/dist/{chunk-AJ7QCSIS.js.map → chunk-ALSGMEJR.js.map} +0 -0
  123. /package/dist/{chunk-57OWKFUQ.js.map → chunk-AS6UOOXF.js.map} +0 -0
  124. /package/dist/{chunk-OGCAYLNA.js.map → chunk-B4C3JSJT.js.map} +0 -0
  125. /package/dist/{chunk-WON4APQY.js.map → chunk-CAZ2SHEP.js.map} +0 -0
  126. /package/dist/{chunk-7RNBVZZO.js.map → chunk-CQ6WP3PA.js.map} +0 -0
  127. /package/dist/{chunk-FUTF72MJ.js.map → chunk-DF552QUN.js.map} +0 -0
  128. /package/dist/{chunk-ZVAYK7GU.js.map → chunk-DZQZHQQ4.js.map} +0 -0
  129. /package/dist/{chunk-72VAXGEI.js.map → chunk-E4OCKU67.js.map} +0 -0
  130. /package/dist/{chunk-5Q7EVV4X.js.map → chunk-HLG7VAZP.js.map} +0 -0
  131. /package/dist/{chunk-FFPJINJE.js.map → chunk-IQFS4AU7.js.map} +0 -0
  132. /package/dist/{chunk-EKBNDKDY.js.map → chunk-KN6UGAQB.js.map} +0 -0
  133. /package/dist/{chunk-44XZ75OQ.js.map → chunk-O4K3DWK2.js.map} +0 -0
  134. /package/dist/{chunk-BXLOS5AJ.js.map → chunk-OWHERGF2.js.map} +0 -0
  135. /package/dist/{chunk-6DRPPQEJ.js.map → chunk-P5FPO2BR.js.map} +0 -0
  136. /package/dist/{chunk-2UFO7X4Q.js.map → chunk-QZGN4773.js.map} +0 -0
  137. /package/dist/{chunk-PMUD7ERF.js.map → chunk-SOTYFJOA.js.map} +0 -0
  138. /package/dist/{chunk-2VEOKUPP.js.map → chunk-TC5HBIIT.js.map} +0 -0
  139. /package/dist/{chunk-A72SWTWW.js.map → chunk-TY6NBWV4.js.map} +0 -0
  140. /package/dist/{chunk-DQEMWVMT.js.map → chunk-UVYI6VIX.js.map} +0 -0
  141. /package/dist/{chunk-MYFQ3ED4.js.map → chunk-W2OST2HH.js.map} +0 -0
  142. /package/dist/{chunk-QVT3E4CE.js.map → chunk-WSHJAY5M.js.map} +0 -0
  143. /package/dist/{chunk-6O22TZSB.js.map → chunk-XMAD32BW.js.map} +0 -0
  144. /package/dist/{chunk-CXZQOVIE.js.map → chunk-XRNU7OEQ.js.map} +0 -0
  145. /package/dist/{chunk-R26ZMXR2.js.map → chunk-Y6XODVJ4.js.map} +0 -0
  146. /package/dist/{chunk-OQJIB32H.js.map → chunk-YO3ZB3PJ.js.map} +0 -0
  147. /package/dist/{chunk-C6XBRYVD.js.map → chunk-YQQYS2K4.js.map} +0 -0
  148. /package/dist/{chunk-F7GAIWFA.js.map → chunk-YSDVEPV2.js.map} +0 -0
  149. /package/dist/{chunk-YROFNEG5.js.map → chunk-YUQOAKPX.js.map} +0 -0
@@ -2,10 +2,10 @@ import {
2
2
  migrateSessionTranscripts,
3
3
  planSessionTranscriptMigration,
4
4
  summarizeMigrationSources
5
- } from "./chunk-6DRPPQEJ.js";
5
+ } from "./chunk-P5FPO2BR.js";
6
6
  import "./chunk-S4DDLTPX.js";
7
- import "./chunk-FF4KLI5W.js";
8
7
  import "./chunk-RL6NEVXT.js";
8
+ import "./chunk-FF4KLI5W.js";
9
9
  import "./chunk-3WCASNQZ.js";
10
10
  import "./chunk-PZ5AY32C.js";
11
11
  export {
package/dist/storage.js CHANGED
@@ -16,7 +16,7 @@ import {
16
16
  parseFrontmatter,
17
17
  parseFrontmatterStringValue,
18
18
  serializeEntityFile
19
- } from "./chunk-4BJQODZF.js";
19
+ } from "./chunk-7HZMTXXB.js";
20
20
  import "./chunk-B3ABVQ36.js";
21
21
  import "./chunk-2QMKMVHH.js";
22
22
  import "./chunk-DEBHXHJR.js";
@@ -24,16 +24,15 @@ import "./chunk-DNHVPZOD.js";
24
24
  import "./chunk-6CIAGZ6X.js";
25
25
  import "./chunk-J6A3CX5N.js";
26
26
  import "./chunk-V57NLO5P.js";
27
- import "./chunk-FF4KLI5W.js";
28
27
  import "./chunk-YVKF3HEW.js";
29
28
  import "./chunk-AVPXXV6J.js";
30
29
  import "./chunk-EGGE52UU.js";
31
30
  import "./chunk-GCASGYIO.js";
32
31
  import "./chunk-WL5EBRDH.js";
32
+ import "./chunk-SCU65EZI.js";
33
33
  import "./chunk-347WD2LE.js";
34
34
  import "./chunk-RL6NEVXT.js";
35
35
  import "./chunk-ILGC6JH6.js";
36
- import "./chunk-SCU65EZI.js";
37
36
  import "./chunk-DM2T26WE.js";
38
37
  import "./chunk-LDXUBPMO.js";
39
38
  import "./chunk-CGASUJVP.js";
@@ -68,12 +67,13 @@ import "./chunk-JAKIDQB2.js";
68
67
  import "./chunk-BJMBJZ2Y.js";
69
68
  import "./chunk-UKJAGEXH.js";
70
69
  import "./chunk-FP2373TW.js";
70
+ import "./chunk-P7FMDTKL.js";
71
+ import "./chunk-SCCO46KZ.js";
72
+ import "./chunk-FF4KLI5W.js";
71
73
  import "./chunk-AIK5W3IW.js";
72
74
  import "./chunk-A6XUJE5D.js";
73
75
  import "./chunk-5UZXUTVO.js";
74
- import "./chunk-P7FMDTKL.js";
75
76
  import "./chunk-VS2IYZRU.js";
76
- import "./chunk-SCCO46KZ.js";
77
77
  import "./chunk-3WCASNQZ.js";
78
78
  import "./chunk-PZ5AY32C.js";
79
79
  export {
@@ -1,12 +1,11 @@
1
1
  import {
2
2
  HourlySummarizer
3
- } from "./chunk-QVT3E4CE.js";
4
- import "./chunk-A6USBZTO.js";
3
+ } from "./chunk-WSHJAY5M.js";
4
+ import "./chunk-AAP5T6QG.js";
5
5
  import "./chunk-WLZYGLJ4.js";
6
6
  import "./chunk-6KIQT7RG.js";
7
7
  import "./chunk-S4DDLTPX.js";
8
8
  import "./chunk-O75CRYGF.js";
9
- import "./chunk-FF4KLI5W.js";
10
9
  import "./chunk-WL5EBRDH.js";
11
10
  import "./chunk-C23BYTJV.js";
12
11
  import "./chunk-QIEUU4UK.js";
@@ -17,6 +16,7 @@ import "./chunk-N7RWREIQ.js";
17
16
  import "./chunk-EYIEWJNI.js";
18
17
  import "./chunk-JUC24CTX.js";
19
18
  import "./chunk-SCCO46KZ.js";
19
+ import "./chunk-FF4KLI5W.js";
20
20
  import "./chunk-3WCASNQZ.js";
21
21
  import "./chunk-PZ5AY32C.js";
22
22
  export {
@@ -3,9 +3,9 @@ import {
3
3
  summarySnapshotPath,
4
4
  upsertSummarySnapshot,
5
5
  writeSummarySnapshot
6
- } from "./chunk-A6USBZTO.js";
7
- import "./chunk-FF4KLI5W.js";
6
+ } from "./chunk-AAP5T6QG.js";
8
7
  import "./chunk-WL5EBRDH.js";
8
+ import "./chunk-FF4KLI5W.js";
9
9
  import "./chunk-PZ5AY32C.js";
10
10
  export {
11
11
  readSummarySnapshot,
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  backupMemoryDir
3
- } from "../chunk-BXLOS5AJ.js";
3
+ } from "../chunk-OWHERGF2.js";
4
4
  import "../chunk-765K3SAT.js";
5
- import "../chunk-DQEMWVMT.js";
5
+ import "../chunk-UVYI6VIX.js";
6
6
  import "../chunk-J4EB7DNW.js";
7
7
  import "../chunk-BJMBJZ2Y.js";
8
8
  import "../chunk-UKJAGEXH.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  exportCapsule,
3
3
  isValidCapsuleSince
4
- } from "../chunk-VDX2J7OX.js";
4
+ } from "../chunk-5W7CTZ2E.js";
5
+ import "../chunk-UVYI6VIX.js";
5
6
  import "../chunk-WEHSQBFR.js";
6
- import "../chunk-DQEMWVMT.js";
7
7
  import "../chunk-J4EB7DNW.js";
8
8
  import "../chunk-BJMBJZ2Y.js";
9
9
  import "../chunk-UKJAGEXH.js";
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  importCapsule
3
- } from "../chunk-AJ7QCSIS.js";
3
+ } from "../chunk-ALSGMEJR.js";
4
4
  import "../chunk-5VQJBH2G.js";
5
5
  import "../chunk-AITCS2RC.js";
6
6
  import "../chunk-XMMESCPD.js";
7
7
  import "../chunk-42JKGUFJ.js";
8
8
  import "../chunk-PDJTHRAW.js";
9
+ import "../chunk-UVYI6VIX.js";
9
10
  import "../chunk-WEHSQBFR.js";
10
- import "../chunk-DQEMWVMT.js";
11
11
  import "../chunk-BJMBJZ2Y.js";
12
12
  import "../chunk-UKJAGEXH.js";
13
13
  import "../chunk-FP2373TW.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  compareVerifiedEpisodeResults,
3
3
  searchVerifiedEpisodes
4
- } from "./chunk-MYFQ3ED4.js";
4
+ } from "./chunk-W2OST2HH.js";
5
5
  import "./chunk-B7RWBZXW.js";
6
- import "./chunk-4BJQODZF.js";
6
+ import "./chunk-7HZMTXXB.js";
7
7
  import "./chunk-B3ABVQ36.js";
8
8
  import "./chunk-2QMKMVHH.js";
9
9
  import "./chunk-DEBHXHJR.js";
@@ -11,16 +11,15 @@ import "./chunk-DNHVPZOD.js";
11
11
  import "./chunk-6CIAGZ6X.js";
12
12
  import "./chunk-J6A3CX5N.js";
13
13
  import "./chunk-V57NLO5P.js";
14
- import "./chunk-FF4KLI5W.js";
15
14
  import "./chunk-YVKF3HEW.js";
16
15
  import "./chunk-AVPXXV6J.js";
17
16
  import "./chunk-EGGE52UU.js";
18
17
  import "./chunk-GCASGYIO.js";
19
18
  import "./chunk-WL5EBRDH.js";
19
+ import "./chunk-SCU65EZI.js";
20
20
  import "./chunk-347WD2LE.js";
21
21
  import "./chunk-RL6NEVXT.js";
22
22
  import "./chunk-ILGC6JH6.js";
23
- import "./chunk-SCU65EZI.js";
24
23
  import "./chunk-DM2T26WE.js";
25
24
  import "./chunk-LDXUBPMO.js";
26
25
  import "./chunk-CGASUJVP.js";
@@ -53,12 +52,13 @@ import "./chunk-ZBJMUXZH.js";
53
52
  import "./chunk-BJMBJZ2Y.js";
54
53
  import "./chunk-UKJAGEXH.js";
55
54
  import "./chunk-FP2373TW.js";
55
+ import "./chunk-P7FMDTKL.js";
56
+ import "./chunk-SCCO46KZ.js";
57
+ import "./chunk-FF4KLI5W.js";
56
58
  import "./chunk-AIK5W3IW.js";
57
59
  import "./chunk-A6XUJE5D.js";
58
60
  import "./chunk-5UZXUTVO.js";
59
- import "./chunk-P7FMDTKL.js";
60
61
  import "./chunk-VS2IYZRU.js";
61
- import "./chunk-SCCO46KZ.js";
62
62
  import "./chunk-3WCASNQZ.js";
63
63
  import "./chunk-PZ5AY32C.js";
64
64
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "9.9.1",
3
+ "version": "9.9.3",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -3045,7 +3045,7 @@
3045
3045
  "core"
3046
3046
  ],
3047
3047
  "peerDependencies": {
3048
- "@remnic/coding-graph": "^9.9.1"
3048
+ "@remnic/coding-graph": "^9.9.3"
3049
3049
  },
3050
3050
  "peerDependenciesMeta": {
3051
3051
  "@remnic/coding-graph": {
@@ -0,0 +1,74 @@
1
+ import * as nodePath from "node:path";
2
+ import { isPathInsideStorageRoot } from "./storage-paths.js";
3
+ import { SecureStoreLockedError } from "./secure-store/secure-fs.js";
4
+ import { ALL_CATEGORY_DIRS } from "./utils/category-dir.js";
5
+
6
+ /** Minimal storage surface the citation namespace decoder probes. */
7
+ interface CitationProbeStorage {
8
+ dir: string;
9
+ readMemoryByPath(filePath: string): Promise<unknown | null>;
10
+ }
11
+
12
+ type CitationStorageResolver = (namespace: string) => Promise<CitationProbeStorage>;
13
+
14
+ /**
15
+ * Probe whether `namespace` actually stores a memory at the cited relative
16
+ * path (#2077). Used to disambiguate a namespace whose name equals a memory
17
+ * category dir (e.g. `facts`) from a bare default category lead: a namespaced
18
+ * citation `facts/facts/a.md` (namespace `facts`, remaining `facts/a.md`) is
19
+ * owned, while a default `facts/a.md` (remaining `a.md`, no category dir) is
20
+ * not. Returns false on any resolution/read failure or path escape — except a
21
+ * locked encrypted store (`SecureStoreLockedError`), which propagates so a
22
+ * locked read is never silently mistaken for "not owned" (AGENTS.md §6).
23
+ */
24
+ async function namespaceOwnsRelativePath(
25
+ getStorage: CitationStorageResolver,
26
+ namespace: string,
27
+ relativePath: string,
28
+ ): Promise<boolean> {
29
+ const remainder = relativePath === namespace ? "" : relativePath.slice(namespace.length + 1);
30
+ if (!remainder) return false;
31
+ let storage: CitationProbeStorage;
32
+ try {
33
+ storage = await getStorage(namespace);
34
+ } catch {
35
+ return false;
36
+ }
37
+ const storageRoot = nodePath.resolve(storage.dir);
38
+ const candidate = nodePath.resolve(storageRoot, remainder);
39
+ if (!isPathInsideStorageRoot(storageRoot, candidate)) return false;
40
+ const memory = await storage.readMemoryByPath(candidate).catch((err: unknown) => {
41
+ if (err instanceof SecureStoreLockedError) throw err;
42
+ return null;
43
+ });
44
+ return memory !== null;
45
+ }
46
+
47
+ /**
48
+ * Resolve which authorized namespace owns a *relative* cited path.
49
+ *
50
+ * Attributes to the longest authorized namespace that prefixes the cited path
51
+ * (namespace names may contain "/"). A bare category lead like a default
52
+ * `facts/a.md` is not a namespace. A namespace whose name equals a category dir
53
+ * (e.g. `facts`, rendered `facts/facts/a.md`) is ambiguous with that bare lead,
54
+ * so it counts only when its storage actually owns the remaining relative path
55
+ * (#2077). Falls back to `fallbackNamespace` when nothing matches.
56
+ */
57
+ export async function decodeCitationNamespace(
58
+ getStorage: CitationStorageResolver,
59
+ authorizedNamespaces: readonly string[],
60
+ memoryPath: string,
61
+ fallbackNamespace: string,
62
+ ): Promise<string> {
63
+ let nsMatch = "";
64
+ for (const ns of authorizedNamespaces) {
65
+ if (!ns) continue;
66
+ const isPrefix = memoryPath === ns || memoryPath.startsWith(`${ns}/`);
67
+ if (!isPrefix || ns.length <= nsMatch.length) continue;
68
+ if (ALL_CATEGORY_DIRS.includes(ns) && !(await namespaceOwnsRelativePath(getStorage, ns, memoryPath))) {
69
+ continue;
70
+ }
71
+ nsMatch = ns;
72
+ }
73
+ return nsMatch || fallbackNamespace;
74
+ }
@@ -11,6 +11,7 @@ import {
11
11
  type CitationUsageRequest,
12
12
  type CitationUsageResult,
13
13
  } from "./access-citation.js";
14
+ import { decodeCitationNamespace } from "./access-citation-namespace.js";
14
15
  import { coordinateRecall, type RecallCoordinatorHost, type RecallExecResult } from "./access-recall-concurrency.js";
15
16
  import { resolveNamespaceCapabilities,
16
17
  resolveMemoryLifecycleCapabilities,
@@ -165,7 +166,6 @@ import {
165
166
  type GraphSnapshotNodeMetadata,
166
167
  } from "./graph-snapshot.js";
167
168
  import * as nodePath from "node:path";
168
- import { ALL_CATEGORY_DIRS } from "./utils/category-dir.js";
169
169
  import {
170
170
  buildBriefing,
171
171
  FileCalendarSource,
@@ -5037,16 +5037,12 @@ export class EngramAccessService {
5037
5037
  if (nodePath.isAbsolute(memoryPath)) {
5038
5038
  throw new EngramAccessInputError("cited path is outside the caller's readable namespaces");
5039
5039
  }
5040
- // Attribute to the longest authorized namespace that prefixes the cited
5041
- // path (namespace names may contain "/"); a bare category lead like a
5042
- // default `facts/a.md` is not a namespace (#2020).
5043
- let nsMatch = "";
5044
- for (const ns of authorizedNamespaces) {
5045
- if (!ns || ALL_CATEGORY_DIRS.includes(ns)) continue;
5046
- if ((memoryPath === ns || memoryPath.startsWith(`${ns}/`)) && ns.length > nsMatch.length) nsMatch = ns;
5047
- }
5048
- if (nsMatch) return nsMatch;
5049
- return fallbackNamespace;
5040
+ return decodeCitationNamespace(
5041
+ (ns) => this.orchestrator.getStorage(ns),
5042
+ authorizedNamespaces,
5043
+ memoryPath,
5044
+ fallbackNamespace,
5045
+ );
5050
5046
  }
5051
5047
  return resolved.namespace;
5052
5048
  },
@@ -1,5 +1,6 @@
1
1
  import { resolveNamespaceCapabilities } from "../capabilities.js";
2
2
  import path from "node:path";
3
+ import { realpathSync } from "node:fs";
3
4
  import type { PluginConfig, QmdSearchResult } from "../types.js";
4
5
  import type {
5
6
  SearchBackend,
@@ -181,15 +182,22 @@ export class NamespaceSearchRouter {
181
182
  );
182
183
  break;
183
184
  }
184
- results = filterNamespaceSubtreeResults(record, results).map((result) => ({
185
- ...result,
186
- namespace,
187
- // Resolve to an absolute path so the (namespace, path) identity is
188
- // globally unique same-relative-path hits from different namespaces
189
- // stay distinct across every downstream consumer with no special
190
- // handling. Display/citation surfaces relativize for portability (#2020).
191
- path: resolveNamespaceResultPath(record.memoryDir, record.collection, result.path),
192
- }));
185
+ results = filterNamespaceSubtreeResults(record, results)
186
+ .map((result) => ({
187
+ ...result,
188
+ namespace,
189
+ // Resolve to an absolute path so the (namespace, path) identity is
190
+ // globally unique same-relative-path hits from different namespaces
191
+ // stay distinct across every downstream consumer with no special
192
+ // handling. Display/citation surfaces relativize for portability (#2020).
193
+ path: resolveNamespaceResultPath(record.memoryDir, record.collection, result.path),
194
+ }))
195
+ // Reject hits whose resolved path escapes the queried namespace's
196
+ // storage root (#2077). A stale/corrupt per-namespace collection can
197
+ // return a path owned by another namespace; stamping it would let
198
+ // downstream scope checks (which trust the stamped namespace) and
199
+ // absolute-path resolution surface a foreign-namespace memory.
200
+ .filter((result) => resolvedPathIsInsideNamespaceRoot(record.memoryDir, result.path));
193
201
  return { namespace, results };
194
202
  }),
195
203
  );
@@ -570,6 +578,14 @@ function daemonModeForBackend(backend: SearchBackend): boolean | null {
570
578
  : null;
571
579
  }
572
580
 
581
+ function isContainedPath(root: string, candidate: string): boolean {
582
+ const relative = path.relative(root, candidate);
583
+ return (
584
+ relative === "" ||
585
+ (relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))
586
+ );
587
+ }
588
+
573
589
  function pathIsInsideNamespaceSubtree(
574
590
  memoryDir: string,
575
591
  collection: string,
@@ -582,8 +598,35 @@ function pathIsInsideNamespaceSubtree(
582
598
  const candidate = path.isAbsolute(normalizedResultPath)
583
599
  ? path.normalize(normalizedResultPath)
584
600
  : path.resolve(memoryRoot, normalizedResultPath);
585
- const relative = path.relative(namespacesRoot, candidate);
586
- return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
601
+ return isContainedPath(namespacesRoot, candidate);
602
+ }
603
+
604
+ /**
605
+ * Reject a QMD hit whose resolved path escapes the queried namespace's storage
606
+ * root (#2077). `resolvedPath` is the already-resolved value produced by
607
+ * `resolveNamespaceResultPath`; a stale/corrupt per-namespace collection can
608
+ * yield an absolute path owned by another namespace, and stamping it with the
609
+ * queried namespace would surface a foreign-namespace memory downstream.
610
+ *
611
+ * Lexical containment runs first — it is cheap and the only check possible when
612
+ * the file is not yet on disk (a stale collection may cite a since-deleted
613
+ * path). When both root and candidate exist, their filesystem realpaths are
614
+ * canonicalized and re-checked so a symlink planted inside the namespace root
615
+ * cannot resolve into another namespace or outside storage. An unresolved path
616
+ * (ENOENT) keeps the lexical result rather than rejecting the stale-collection
617
+ * case this guard targets.
618
+ */
619
+ function resolvedPathIsInsideNamespaceRoot(memoryDir: string, resolvedPath: string): boolean {
620
+ const root = path.resolve(memoryDir);
621
+ const candidate = path.isAbsolute(resolvedPath)
622
+ ? path.normalize(resolvedPath)
623
+ : path.resolve(root, resolvedPath);
624
+ if (!isContainedPath(root, candidate)) return false;
625
+ try {
626
+ return isContainedPath(realpathSync.native(root), realpathSync.native(candidate));
627
+ } catch {
628
+ return true;
629
+ }
587
630
  }
588
631
  export function normalizeQmdResultPath(resultPath: string, collection: string): string {
589
632
  let value = resultPath.trim();
@@ -85,6 +85,7 @@ const BUILT_IN_CONNECTOR_PACKAGES: Array<{ id: string; suffix: string }> = [
85
85
  { id: "bee", suffix: "connector-bee" },
86
86
  { id: "omi", suffix: "connector-omi" },
87
87
  { id: "fireflies", suffix: "connector-fireflies" },
88
+ { id: "granola", suffix: "connector-granola" },
88
89
  ];
89
90
 
90
91
  const loadFailuresWarned = new Set<string>();
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/namespaces/search.ts"],"sourcesContent":["import { resolveNamespaceCapabilities } from \"../capabilities.js\";\nimport 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\";\nimport { ALL_CATEGORY_DIRS } from \"../utils/category-dir.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 pendingEmbeddings: number | null;\n oldestPendingAgeMs: number | null;\n embeddingBacklogThreshold: number;\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 /**\n * Resolve the search backend for a namespace (#2019). Returns `unknown` so\n * callers (e.g. the prioritized-embed path) duck-type for capability like\n * `embedFiles` rather than depending on a concrete QMD shape. Reuses the\n * cached backend record, so this never re-creates a backend. Returns `null`\n * when the namespace backend is unavailable.\n */\n async backendForNamespace(namespace: string): Promise<unknown> {\n const record = await this.backendRecordFor(namespace);\n return record.available ? record.backend : null;\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 // A per-namespace backend that is unavailable (or missing its\n // collection) must report like any other QMD skip (#1536): its\n // empty contribution is otherwise indistinguishable from a true\n // no-matches for that namespace (codex round-5 review on #1544).\n try {\n options.execution?.onDegradation?.({\n backend: \"qmd\",\n code: \"backend_unavailable\",\n detail:\n record.collectionState === \"missing\"\n ? `namespace collection missing: ${namespace}`\n : `namespace backend unavailable: ${namespace}`,\n });\n } catch {\n // Observers must never break search.\n }\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).map((result) => ({\n ...result,\n namespace,\n // Resolve to an absolute path so the (namespace, path) identity is\n // globally unique — same-relative-path hits from different namespaces\n // stay distinct across every downstream consumer with no special\n // handling. Display/citation surfaces relativize for portability (#2020).\n path: resolveNamespaceResultPath(record.memoryDir, record.collection, result.path),\n }));\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 backendStatus =\n \"status\" in diagnosticBackend &&\n typeof diagnosticBackend.status === \"function\"\n ? await Promise.race([\n diagnosticBackend.status().catch(() => null),\n new Promise<null>((resolve) => setTimeout(() => resolve(null), 5_000).unref?.()),\n ])\n : null;\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 pendingEmbeddings: backendStatus?.pendingEmbeddings ?? null,\n oldestPendingAgeMs: backendStatus?.oldestPendingAgeMs ?? null,\n embeddingBacklogThreshold: this.config.qmdEmbeddingBacklogThreshold,\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 resolveNamespaceCapabilities(this.config).namespaces === 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 // The legacy default namespace at the flat root (`filtersNestedNamespaces`)\n // shares its `memoryDir` with the `namespaces/` container, so its base\n // collection is a \"broad root\" that also indexes nested-namespace files.\n // We STILL auto-create it (issue #1929): the search side already targets\n // this exact base collection and `filterNamespaceSubtreeResults` strips\n // the nested `namespaces/` subtree out of its results, so index and\n // search stay symmetric. Skipping creation left a configured default\n // namespace (e.g. `geek`) with maintenance \"ran\" but no collection and 0\n // recall results. `ensureCollection` is a no-op when the collection is\n // already present, so legacy installs that pre-created the broad root are\n // unaffected.\n this.collectionStateForBackend(backend, storage.dir, scopedConfig.qmdCollection, {\n autoCreate: options.autoCreateCollection,\n failOpenMissingGuardedCollection: options.failOpenMissingGuardedCollection,\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 execution?: SearchExecutionOptions;\n },\n ): Promise<CollectionState> {\n if (!options.autoCreate) {\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}\nexport function 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 // Only strip a genuine QMD collection prefix — never when the collection name\n // collides with a memory category dir (e.g. qmdCollection == \"facts\"), or a\n // bare \"facts/<id>.md\" hit would be corrupted to \"<id>.md\" and fail namespace\n // reads/access tracking (#2020).\n const collectionPrefix = `${collection}/`;\n if (value.startsWith(collectionPrefix) && !ALL_CATEGORY_DIRS.includes(collection)) {\n value = value.slice(collectionPrefix.length);\n }\n return value;\n}\nfunction resolveNamespaceResultPath(\n memoryDir: string,\n collection: string,\n resultPath: string,\n): string {\n const normalized = normalizeQmdResultPath(resultPath, collection);\n if (path.isAbsolute(normalized)) return normalized;\n const root = path.resolve(memoryDir);\n const resolved = path.resolve(root, normalized);\n const relative = path.relative(root, resolved);\n if (relative === \"\" || relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n return resultPath;\n }\n return resolved;\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, namespace });\n continue;\n }\n if (result.score > existing.score) {\n merged.set(key, {\n ...result,\n namespace,\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":";;;;;;;;;;;;;;;AACA,OAAO,UAAU;AAWjB,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;AAiDO,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,oBAAoB,WAAqC;AAC7D,UAAM,SAAS,MAAM,KAAK,iBAAiB,SAAS;AACpD,WAAO,OAAO,YAAY,OAAO,UAAU;AAAA,EAC7C;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;AAK7D,cAAI;AACF,oBAAQ,WAAW,gBAAgB;AAAA,cACjC,SAAS;AAAA,cACT,MAAM;AAAA,cACN,QACE,OAAO,oBAAoB,YACvB,iCAAiC,SAAS,KAC1C,kCAAkC,SAAS;AAAA,YACnD,CAAC;AAAA,UACH,QAAQ;AAAA,UAER;AACA,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,EAAE,IAAI,CAAC,YAAY;AAAA,UACxE,GAAG;AAAA,UACH;AAAA;AAAA;AAAA;AAAA;AAAA,UAKA,MAAM,2BAA2B,OAAO,WAAW,OAAO,YAAY,OAAO,IAAI;AAAA,QACnF,EAAE;AACF,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,gBACJ,YAAY,qBACZ,OAAO,kBAAkB,WAAW,aAChC,MAAM,QAAQ,KAAK;AAAA,QACjB,kBAAkB,OAAO,EAAE,MAAM,MAAM,IAAI;AAAA,QAC3C,IAAI,QAAc,CAAC,YAAY,WAAW,MAAM,QAAQ,IAAI,GAAG,GAAK,EAAE,QAAQ,CAAC;AAAA,MACjF,CAAC,IACD;AACN,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,QACA,mBAAmB,eAAe,qBAAqB;AAAA,QACvD,oBAAoB,eAAe,sBAAsB;AAAA,QACzD,2BAA2B,KAAK,OAAO;AAAA,MACzC;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,6BAA6B,KAAK,MAAM,EAAE,eAAe,QAAQ;AACnE,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAYN,KAAK,0BAA0B,SAAS,QAAQ,KAAK,aAAa,eAAe;AAAA,UAC/E,YAAY,QAAQ;AAAA,UACpB,kCAAkC,QAAQ;AAAA,UAC1C;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,SAK0B;AAC1B,QAAI,CAAC,QAAQ,YAAY;AACvB,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;AACO,SAAS,uBAAuB,YAAoB,YAA4B;AACrF,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;AAMA,QAAM,mBAAmB,GAAG,UAAU;AACtC,MAAI,MAAM,WAAW,gBAAgB,KAAK,CAAC,kBAAkB,SAAS,UAAU,GAAG;AACjF,YAAQ,MAAM,MAAM,iBAAiB,MAAM;AAAA,EAC7C;AACA,SAAO;AACT;AACA,SAAS,2BACP,WACA,YACA,YACQ;AACR,QAAM,aAAa,uBAAuB,YAAY,UAAU;AAChE,MAAI,KAAK,WAAW,UAAU,EAAG,QAAO;AACxC,QAAM,OAAO,KAAK,QAAQ,SAAS;AACnC,QAAM,WAAW,KAAK,QAAQ,MAAM,UAAU;AAC9C,QAAM,WAAW,KAAK,SAAS,MAAM,QAAQ;AAC7C,MAAI,aAAa,MAAM,SAAS,WAAW,IAAI,KAAK,KAAK,WAAW,QAAQ,GAAG;AAC7E,WAAO;AAAA,EACT;AACA,SAAO;AACT;AACA,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,EAAE,GAAG,QAAQ,UAAU,CAAC;AACxC;AAAA,MACF;AACA,UAAI,OAAO,QAAQ,SAAS,OAAO;AACjC,eAAO,IAAI,KAAK;AAAA,UACd,GAAG;AAAA,UACH;AAAA,UACA,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":[]}