@remnic/core 10.0.39 → 10.0.41

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 (199) hide show
  1. package/dist/access-admin-ops-surface.js +14 -14
  2. package/dist/access-authorization-probe.js +15 -15
  3. package/dist/access-boundary.js +14 -14
  4. package/dist/access-cli.js +53 -53
  5. package/dist/access-extraction-force-flush.js +14 -14
  6. package/dist/access-http-briefing.js +15 -15
  7. package/dist/access-http-query.js +16 -16
  8. package/dist/access-http.js +30 -30
  9. package/dist/access-identity-continuity-surface.js +14 -14
  10. package/dist/access-lcm-surface.js +14 -14
  11. package/dist/access-mcp.js +23 -23
  12. package/dist/access-namespace-preflight.js +14 -14
  13. package/dist/access-observe-write-surface.js +14 -14
  14. package/dist/access-operations-batch.js +15 -15
  15. package/dist/access-operations.js +22 -22
  16. package/dist/access-recall-concurrency.js +14 -14
  17. package/dist/access-recall-response.js +14 -14
  18. package/dist/access-recall-surface.js +14 -14
  19. package/dist/access-service.d.ts +2 -2
  20. package/dist/access-service.d.ts.map +1 -1
  21. package/dist/access-service.js +14 -14
  22. package/dist/access-surface-catalog.js +16 -16
  23. package/dist/active-recall.js +2 -2
  24. package/dist/briefing.js +3 -3
  25. package/dist/causal-consolidation.js +4 -4
  26. package/dist/{chunk-M7KGIW5F.js → chunk-4KS4IHKH.js} +2 -2
  27. package/dist/{chunk-JORSMFL6.js → chunk-574N53FL.js} +5 -5
  28. package/dist/{chunk-BUKZ7MTN.js → chunk-5TRU6QQC.js} +2 -2
  29. package/dist/{chunk-SRPGA6WN.js → chunk-7BCYAJKP.js} +2 -2
  30. package/dist/{chunk-MD3W2H3G.js → chunk-7G4O5EQT.js} +31 -31
  31. package/dist/{chunk-MD3W2H3G.js.map → chunk-7G4O5EQT.js.map} +1 -1
  32. package/dist/{chunk-F2IU6A2L.js → chunk-7XGWW3LQ.js} +16 -16
  33. package/dist/{chunk-ZXFKG7VZ.js → chunk-AOBDA3VC.js} +2 -2
  34. package/dist/{chunk-JRTKYFFY.js → chunk-AY6LO7GD.js} +2 -2
  35. package/dist/{chunk-5KZNWERU.js → chunk-BIYVUPC6.js} +19 -3
  36. package/dist/{chunk-5KZNWERU.js.map → chunk-BIYVUPC6.js.map} +1 -1
  37. package/dist/{chunk-V2XMG7GM.js → chunk-CHNZPOWX.js} +3 -2
  38. package/dist/{chunk-V2XMG7GM.js.map → chunk-CHNZPOWX.js.map} +1 -1
  39. package/dist/{chunk-GPVGAHXL.js → chunk-CNAL35D5.js} +2 -2
  40. package/dist/{chunk-NJ2DZYEK.js → chunk-DBM2NQBG.js} +2 -2
  41. package/dist/{chunk-U66CTIF5.js → chunk-F2RDRE7M.js} +2 -2
  42. package/dist/{chunk-VIS23B6O.js → chunk-F7MP76CB.js} +15 -13
  43. package/dist/chunk-F7MP76CB.js.map +1 -0
  44. package/dist/{chunk-B7VKRCAG.js → chunk-FNEYSTB6.js} +2 -2
  45. package/dist/{chunk-GSBSGT43.js → chunk-FPHU6KVI.js} +2 -2
  46. package/dist/{chunk-RO2NNWR5.js → chunk-GAUS4XGN.js} +3 -3
  47. package/dist/{chunk-4UT2NUAC.js → chunk-GCDIHTWF.js} +2 -2
  48. package/dist/{chunk-4HJ2QK32.js → chunk-GDOI4U4D.js} +2 -2
  49. package/dist/{chunk-VCOCOBUS.js → chunk-GZMHBRIR.js} +3 -3
  50. package/dist/{chunk-LJXBFVI2.js → chunk-ICTJOOWZ.js} +2 -2
  51. package/dist/{chunk-6Z2ZWBOV.js → chunk-IWDFHVPJ.js} +2 -2
  52. package/dist/{chunk-TTQYX7VU.js → chunk-J3FPMHQG.js} +2 -2
  53. package/dist/{chunk-GCW7UT5I.js → chunk-JJSMSS45.js} +2 -2
  54. package/dist/{chunk-O2O4FDAH.js → chunk-JXQTECMU.js} +2 -2
  55. package/dist/{chunk-ANV373S5.js → chunk-KYYN2FK4.js} +2 -2
  56. package/dist/{chunk-PJRKLB4Z.js → chunk-L5PM7B3I.js} +16 -2
  57. package/dist/{chunk-PJRKLB4Z.js.map → chunk-L5PM7B3I.js.map} +1 -1
  58. package/dist/{chunk-5TJEOU6Y.js → chunk-LKRXGOQW.js} +18 -8
  59. package/dist/{chunk-5TJEOU6Y.js.map → chunk-LKRXGOQW.js.map} +1 -1
  60. package/dist/{chunk-B3I2QQU7.js → chunk-LWIU5BMA.js} +3 -3
  61. package/dist/{chunk-WQYS47G4.js → chunk-N3PUGD7E.js} +2 -2
  62. package/dist/{chunk-EKR6OO4P.js → chunk-NTD3VWJ2.js} +2 -2
  63. package/dist/{chunk-JQCP5QW3.js → chunk-O67H7OXJ.js} +2 -2
  64. package/dist/{chunk-4LLV2N3R.js → chunk-ONIVKGNC.js} +2 -2
  65. package/dist/{chunk-GLB6VV3J.js → chunk-OUYYEPXD.js} +3 -3
  66. package/dist/{chunk-RWW5KPIY.js → chunk-PCZZMMBL.js} +12 -12
  67. package/dist/chunk-PCZZMMBL.js.map +1 -0
  68. package/dist/{chunk-WT2VVYBM.js → chunk-PJXSBXEC.js} +2 -2
  69. package/dist/{chunk-P3YUEPSQ.js → chunk-PUMP554C.js} +2 -2
  70. package/dist/{chunk-SJHFU52W.js → chunk-Q47WGGKI.js} +5 -5
  71. package/dist/chunk-Q47WGGKI.js.map +1 -0
  72. package/dist/{chunk-RIAKNXZB.js → chunk-Q77SLBWT.js} +3 -3
  73. package/dist/{chunk-22YJQTPN.js → chunk-QGNZ5QPV.js} +2 -2
  74. package/dist/{chunk-GE5ZNDLE.js → chunk-R42VUN5V.js} +3 -3
  75. package/dist/{chunk-7IANFJ24.js → chunk-RWMLDC2F.js} +17 -17
  76. package/dist/chunk-RWMLDC2F.js.map +1 -0
  77. package/dist/{chunk-LPD6I2U6.js → chunk-SLVR3U4E.js} +2 -2
  78. package/dist/{chunk-IAOW2L6K.js → chunk-TNTYAH7T.js} +2 -2
  79. package/dist/{chunk-CR72WZ3M.js → chunk-UBGFPD62.js} +4 -4
  80. package/dist/{chunk-CR72WZ3M.js.map → chunk-UBGFPD62.js.map} +1 -1
  81. package/dist/{chunk-JZFJZLJY.js → chunk-UGV256H3.js} +2 -2
  82. package/dist/{chunk-L74NWAD4.js → chunk-UKIIAEJF.js} +2 -2
  83. package/dist/{chunk-5Q6CR65T.js → chunk-VTZSIG6O.js} +2 -2
  84. package/dist/{chunk-IZRNMXZC.js → chunk-WCUYCTTG.js} +2 -2
  85. package/dist/{chunk-JT3IXJIL.js → chunk-XBHUMPIQ.js} +7 -7
  86. package/dist/{chunk-JM6U3SAE.js → chunk-XJ77IOAD.js} +2 -2
  87. package/dist/{chunk-ODJ2HRFW.js → chunk-XXBCUIYQ.js} +7 -7
  88. package/dist/{chunk-JOOGPZJE.js → chunk-XXW3P3RX.js} +2 -2
  89. package/dist/cli.js +40 -40
  90. package/dist/coding/export-okf-codegraph.js +2 -2
  91. package/dist/compounding/engine.js +4 -4
  92. package/dist/config.js +2 -2
  93. package/dist/connectors/codex-materialize-runner.js +3 -3
  94. package/dist/connectors/index.js +4 -4
  95. package/dist/convergence-refresh.js +5 -5
  96. package/dist/corpus-watermark.js +5 -5
  97. package/dist/entity-retrieval.js +3 -3
  98. package/dist/external-wiki-access.js +15 -15
  99. package/dist/extraction-error-classification.d.ts +15 -0
  100. package/dist/extraction-error-classification.d.ts.map +1 -1
  101. package/dist/extraction-error-classification.js +7 -3
  102. package/dist/extraction.js +8 -8
  103. package/dist/harmonic-retrieval.js +3 -3
  104. package/dist/index.js +53 -53
  105. package/dist/location/index.js +5 -5
  106. package/dist/maintenance/memory-governance.js +3 -3
  107. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  108. package/dist/maintenance/rebuild-memory-projection-runner.js +5 -5
  109. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  110. package/dist/memory-browse-operations.js +15 -15
  111. package/dist/namespaces/migrate.js +4 -4
  112. package/dist/namespaces/search.d.ts +1 -0
  113. package/dist/namespaces/search.d.ts.map +1 -1
  114. package/dist/namespaces/search.js +5 -3
  115. package/dist/namespaces/storage.js +3 -3
  116. package/dist/operator-doctor-corpus.js +6 -6
  117. package/dist/operator-toolkit.js +11 -11
  118. package/dist/orchestration/maintenance.js +13 -13
  119. package/dist/orchestration/qmd-result-resolver.d.ts +5 -0
  120. package/dist/orchestration/qmd-result-resolver.d.ts.map +1 -1
  121. package/dist/orchestration/recall-search-pipeline.d.ts.map +1 -1
  122. package/dist/orchestrator.js +53 -53
  123. package/dist/recall-navigation-operations.js +15 -15
  124. package/dist/recall-navigation.js +14 -14
  125. package/dist/resume-bundles.js +2 -2
  126. package/dist/runtime/daemon-health.d.ts.map +1 -1
  127. package/dist/semantic-consolidation.js +4 -4
  128. package/dist/semantic-rule-promotion.js +3 -3
  129. package/dist/semantic-rule-verifier.js +3 -3
  130. package/dist/source-agent-qualifier.js +6 -6
  131. package/dist/standup/build.js +3 -3
  132. package/dist/storage.js +2 -2
  133. package/dist/support-passport/index.js +17 -17
  134. package/dist/transfer/export-okf.js +3 -3
  135. package/dist/verified-recall.js +3 -3
  136. package/dist/who-knows-cli.js +4 -4
  137. package/dist/who-knows.js +3 -3
  138. package/package.json +3 -3
  139. package/src/access-entity-principal.test.ts +190 -0
  140. package/src/access-http.ts +2 -2
  141. package/src/access-operations-batch.ts +2 -2
  142. package/src/access-service.ts +7 -6
  143. package/src/chat/chat-executor.ts +1 -1
  144. package/src/extraction-error-classification.ts +23 -0
  145. package/src/extraction-local-failure-class.test.ts +55 -0
  146. package/src/extraction.ts +9 -9
  147. package/src/namespaces/search.ts +1 -1
  148. package/src/orchestration/extraction-run.test.ts +83 -2
  149. package/src/orchestration/qmd-result-resolver.ts +26 -1
  150. package/src/orchestration/recall-search-pipeline.ts +11 -12
  151. package/src/runtime/daemon-health.test.ts +85 -0
  152. package/src/runtime/daemon-health.ts +20 -7
  153. package/dist/chunk-7IANFJ24.js.map +0 -1
  154. package/dist/chunk-RWW5KPIY.js.map +0 -1
  155. package/dist/chunk-SJHFU52W.js.map +0 -1
  156. package/dist/chunk-VIS23B6O.js.map +0 -1
  157. /package/dist/{chunk-M7KGIW5F.js.map → chunk-4KS4IHKH.js.map} +0 -0
  158. /package/dist/{chunk-JORSMFL6.js.map → chunk-574N53FL.js.map} +0 -0
  159. /package/dist/{chunk-BUKZ7MTN.js.map → chunk-5TRU6QQC.js.map} +0 -0
  160. /package/dist/{chunk-SRPGA6WN.js.map → chunk-7BCYAJKP.js.map} +0 -0
  161. /package/dist/{chunk-F2IU6A2L.js.map → chunk-7XGWW3LQ.js.map} +0 -0
  162. /package/dist/{chunk-ZXFKG7VZ.js.map → chunk-AOBDA3VC.js.map} +0 -0
  163. /package/dist/{chunk-JRTKYFFY.js.map → chunk-AY6LO7GD.js.map} +0 -0
  164. /package/dist/{chunk-GPVGAHXL.js.map → chunk-CNAL35D5.js.map} +0 -0
  165. /package/dist/{chunk-NJ2DZYEK.js.map → chunk-DBM2NQBG.js.map} +0 -0
  166. /package/dist/{chunk-U66CTIF5.js.map → chunk-F2RDRE7M.js.map} +0 -0
  167. /package/dist/{chunk-B7VKRCAG.js.map → chunk-FNEYSTB6.js.map} +0 -0
  168. /package/dist/{chunk-GSBSGT43.js.map → chunk-FPHU6KVI.js.map} +0 -0
  169. /package/dist/{chunk-RO2NNWR5.js.map → chunk-GAUS4XGN.js.map} +0 -0
  170. /package/dist/{chunk-4UT2NUAC.js.map → chunk-GCDIHTWF.js.map} +0 -0
  171. /package/dist/{chunk-4HJ2QK32.js.map → chunk-GDOI4U4D.js.map} +0 -0
  172. /package/dist/{chunk-VCOCOBUS.js.map → chunk-GZMHBRIR.js.map} +0 -0
  173. /package/dist/{chunk-LJXBFVI2.js.map → chunk-ICTJOOWZ.js.map} +0 -0
  174. /package/dist/{chunk-6Z2ZWBOV.js.map → chunk-IWDFHVPJ.js.map} +0 -0
  175. /package/dist/{chunk-TTQYX7VU.js.map → chunk-J3FPMHQG.js.map} +0 -0
  176. /package/dist/{chunk-GCW7UT5I.js.map → chunk-JJSMSS45.js.map} +0 -0
  177. /package/dist/{chunk-O2O4FDAH.js.map → chunk-JXQTECMU.js.map} +0 -0
  178. /package/dist/{chunk-ANV373S5.js.map → chunk-KYYN2FK4.js.map} +0 -0
  179. /package/dist/{chunk-B3I2QQU7.js.map → chunk-LWIU5BMA.js.map} +0 -0
  180. /package/dist/{chunk-WQYS47G4.js.map → chunk-N3PUGD7E.js.map} +0 -0
  181. /package/dist/{chunk-EKR6OO4P.js.map → chunk-NTD3VWJ2.js.map} +0 -0
  182. /package/dist/{chunk-JQCP5QW3.js.map → chunk-O67H7OXJ.js.map} +0 -0
  183. /package/dist/{chunk-4LLV2N3R.js.map → chunk-ONIVKGNC.js.map} +0 -0
  184. /package/dist/{chunk-GLB6VV3J.js.map → chunk-OUYYEPXD.js.map} +0 -0
  185. /package/dist/{chunk-WT2VVYBM.js.map → chunk-PJXSBXEC.js.map} +0 -0
  186. /package/dist/{chunk-P3YUEPSQ.js.map → chunk-PUMP554C.js.map} +0 -0
  187. /package/dist/{chunk-RIAKNXZB.js.map → chunk-Q77SLBWT.js.map} +0 -0
  188. /package/dist/{chunk-22YJQTPN.js.map → chunk-QGNZ5QPV.js.map} +0 -0
  189. /package/dist/{chunk-GE5ZNDLE.js.map → chunk-R42VUN5V.js.map} +0 -0
  190. /package/dist/{chunk-LPD6I2U6.js.map → chunk-SLVR3U4E.js.map} +0 -0
  191. /package/dist/{chunk-IAOW2L6K.js.map → chunk-TNTYAH7T.js.map} +0 -0
  192. /package/dist/{chunk-JZFJZLJY.js.map → chunk-UGV256H3.js.map} +0 -0
  193. /package/dist/{chunk-L74NWAD4.js.map → chunk-UKIIAEJF.js.map} +0 -0
  194. /package/dist/{chunk-5Q6CR65T.js.map → chunk-VTZSIG6O.js.map} +0 -0
  195. /package/dist/{chunk-IZRNMXZC.js.map → chunk-WCUYCTTG.js.map} +0 -0
  196. /package/dist/{chunk-JT3IXJIL.js.map → chunk-XBHUMPIQ.js.map} +0 -0
  197. /package/dist/{chunk-JM6U3SAE.js.map → chunk-XJ77IOAD.js.map} +0 -0
  198. /package/dist/{chunk-ODJ2HRFW.js.map → chunk-XXBCUIYQ.js.map} +0 -0
  199. /package/dist/{chunk-JOOGPZJE.js.map → chunk-XXW3P3RX.js.map} +0 -0
@@ -506,6 +506,7 @@ function mergeNamespaceSearchResults(lists, maxResults) {
506
506
  export {
507
507
  namespaceCollectionName,
508
508
  NamespaceSearchRouter,
509
- normalizeQmdResultPath
509
+ normalizeQmdResultPath,
510
+ resolveNamespaceResultPath
510
511
  };
511
- //# sourceMappingURL=chunk-V2XMG7GM.js.map
512
+ //# sourceMappingURL=chunk-CHNZPOWX.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/namespaces/search.ts"],"sourcesContent":["import { resolveNamespaceCapabilities } from \"../capabilities.js\";\nimport path from \"node:path\";\nimport { realpathSync } from \"node:fs\";\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 disposed: 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 private readonly pendingDisposals = new Set<Promise<void>>();\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)\n .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 // Reject hits whose resolved path escapes the queried namespace's\n // storage root (#2077). A stale/corrupt per-namespace collection can\n // return a path owned by another namespace; stamping it would let\n // downstream scope checks (which trust the stamped namespace) and\n // absolute-path resolution surface a foreign-namespace memory.\n .filter((result) => resolvedPathIsInsideNamespaceRoot(record.memoryDir, result.path));\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 private trackDisposal(promise: Promise<void>): void {\n this.pendingDisposals.add(promise);\n void promise.finally(() => this.pendingDisposals.delete(promise));\n }\n\n private async drainPendingDisposals(): Promise<void> {\n if (this.pendingDisposals.size === 0) return;\n await Promise.allSettled(this.pendingDisposals);\n }\n\n /** Clear cached backend records so the next access re-probes availability. */\n clearCache(): void {\n const pendingRecords = Array.from(this.cache.values());\n this.cache.clear();\n const disposal = Promise.allSettled(pendingRecords).then(async (settled) => {\n await Promise.allSettled(\n settled.flatMap((entry) =>\n entry.status === \"fulfilled\" ? [this.disposeRecord(entry.value)] : []),\n );\n });\n this.trackDisposal(disposal);\n }\n\n private async disposeRecord(record: NamespaceBackendRecord): Promise<void> {\n if (record.disposed) return;\n record.disposed = true;\n const dispose = (record.backend as { dispose?: () => void | Promise<void> }).dispose;\n await dispose?.call(record.backend);\n }\n\n /** Release any per-namespace backend handles held by cached records. */\n async dispose(): Promise<void> {\n await this.drainPendingDisposals();\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 entry.status === \"fulfilled\" ? [this.disposeRecord(entry.value)] : []),\n );\n }\n\n /**\n * Disable namespace search for this runtime while retaining the resolved\n * records as unavailable/missing. This releases concrete QMD/daemon handles\n * without letting later reads recreate a search backend after the root path\n * has been switched to NoopSearchBackend for a missing collection.\n */\n async disableSearchBackends(): Promise<void> {\n const settled = await Promise.allSettled(this.cache.values());\n await Promise.allSettled(\n settled.flatMap((entry) => {\n if (entry.status !== \"fulfilled\") return [];\n entry.value.available = false;\n entry.value.collectionState = \"missing\";\n return [this.disposeRecord(entry.value)];\n }),\n );\n }\n\n private async backendRecordFor(\n namespace: string,\n execution?: SearchExecutionOptions,\n ): Promise<NamespaceBackendRecord> {\n await this.drainPendingDisposals();\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(execution)\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 disposed: false,\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 isContainedPath(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return (\n relative === \"\" ||\n (relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))\n );\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 return isContainedPath(namespacesRoot, candidate);\n}\n\n/**\n * Reject a QMD hit whose resolved path escapes the queried namespace's storage\n * root (#2077). `resolvedPath` is the already-resolved value produced by\n * `resolveNamespaceResultPath`; a stale/corrupt per-namespace collection can\n * yield an absolute path owned by another namespace, and stamping it with the\n * queried namespace would surface a foreign-namespace memory downstream.\n *\n * Lexical containment runs first — it is cheap and the only check possible when\n * the file is not yet on disk (a stale collection may cite a since-deleted\n * path). When both root and candidate exist, their filesystem realpaths are\n * canonicalized and re-checked so a symlink planted inside the namespace root\n * cannot resolve into another namespace or outside storage. An unresolved path\n * (ENOENT) keeps the lexical result rather than rejecting the stale-collection\n * case this guard targets.\n */\nfunction resolvedPathIsInsideNamespaceRoot(memoryDir: string, resolvedPath: string): boolean {\n const root = path.resolve(memoryDir);\n const candidate = path.isAbsolute(resolvedPath)\n ? path.normalize(resolvedPath)\n : path.resolve(root, resolvedPath);\n if (!isContainedPath(root, candidate)) return false;\n try {\n return isContainedPath(realpathSync.native(root), realpathSync.native(candidate));\n } catch {\n return true;\n }\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":"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","names":[]}
1
+ {"version":3,"sources":["../src/namespaces/search.ts"],"sourcesContent":["import { resolveNamespaceCapabilities } from \"../capabilities.js\";\nimport path from \"node:path\";\nimport { realpathSync } from \"node:fs\";\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 disposed: 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 private readonly pendingDisposals = new Set<Promise<void>>();\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)\n .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 // Reject hits whose resolved path escapes the queried namespace's\n // storage root (#2077). A stale/corrupt per-namespace collection can\n // return a path owned by another namespace; stamping it would let\n // downstream scope checks (which trust the stamped namespace) and\n // absolute-path resolution surface a foreign-namespace memory.\n .filter((result) => resolvedPathIsInsideNamespaceRoot(record.memoryDir, result.path));\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 private trackDisposal(promise: Promise<void>): void {\n this.pendingDisposals.add(promise);\n void promise.finally(() => this.pendingDisposals.delete(promise));\n }\n\n private async drainPendingDisposals(): Promise<void> {\n if (this.pendingDisposals.size === 0) return;\n await Promise.allSettled(this.pendingDisposals);\n }\n\n /** Clear cached backend records so the next access re-probes availability. */\n clearCache(): void {\n const pendingRecords = Array.from(this.cache.values());\n this.cache.clear();\n const disposal = Promise.allSettled(pendingRecords).then(async (settled) => {\n await Promise.allSettled(\n settled.flatMap((entry) =>\n entry.status === \"fulfilled\" ? [this.disposeRecord(entry.value)] : []),\n );\n });\n this.trackDisposal(disposal);\n }\n\n private async disposeRecord(record: NamespaceBackendRecord): Promise<void> {\n if (record.disposed) return;\n record.disposed = true;\n const dispose = (record.backend as { dispose?: () => void | Promise<void> }).dispose;\n await dispose?.call(record.backend);\n }\n\n /** Release any per-namespace backend handles held by cached records. */\n async dispose(): Promise<void> {\n await this.drainPendingDisposals();\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 entry.status === \"fulfilled\" ? [this.disposeRecord(entry.value)] : []),\n );\n }\n\n /**\n * Disable namespace search for this runtime while retaining the resolved\n * records as unavailable/missing. This releases concrete QMD/daemon handles\n * without letting later reads recreate a search backend after the root path\n * has been switched to NoopSearchBackend for a missing collection.\n */\n async disableSearchBackends(): Promise<void> {\n const settled = await Promise.allSettled(this.cache.values());\n await Promise.allSettled(\n settled.flatMap((entry) => {\n if (entry.status !== \"fulfilled\") return [];\n entry.value.available = false;\n entry.value.collectionState = \"missing\";\n return [this.disposeRecord(entry.value)];\n }),\n );\n }\n\n private async backendRecordFor(\n namespace: string,\n execution?: SearchExecutionOptions,\n ): Promise<NamespaceBackendRecord> {\n await this.drainPendingDisposals();\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(execution)\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 disposed: false,\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 isContainedPath(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return (\n relative === \"\" ||\n (relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))\n );\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 return isContainedPath(namespacesRoot, candidate);\n}\n\n/**\n * Reject a QMD hit whose resolved path escapes the queried namespace's storage\n * root (#2077). `resolvedPath` is the already-resolved value produced by\n * `resolveNamespaceResultPath`; a stale/corrupt per-namespace collection can\n * yield an absolute path owned by another namespace, and stamping it with the\n * queried namespace would surface a foreign-namespace memory downstream.\n *\n * Lexical containment runs first — it is cheap and the only check possible when\n * the file is not yet on disk (a stale collection may cite a since-deleted\n * path). When both root and candidate exist, their filesystem realpaths are\n * canonicalized and re-checked so a symlink planted inside the namespace root\n * cannot resolve into another namespace or outside storage. An unresolved path\n * (ENOENT) keeps the lexical result rather than rejecting the stale-collection\n * case this guard targets.\n */\nfunction resolvedPathIsInsideNamespaceRoot(memoryDir: string, resolvedPath: string): boolean {\n const root = path.resolve(memoryDir);\n const candidate = path.isAbsolute(resolvedPath)\n ? path.normalize(resolvedPath)\n : path.resolve(root, resolvedPath);\n if (!isContainedPath(root, candidate)) return false;\n try {\n return isContainedPath(realpathSync.native(root), realpathSync.native(candidate));\n } catch {\n return true;\n }\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}\nexport function 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":"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","names":[]}
@@ -14,7 +14,7 @@ import {
14
14
  } from "./chunk-3UXOZBHV.js";
15
15
  import {
16
16
  StorageManager
17
- } from "./chunk-5KZNWERU.js";
17
+ } from "./chunk-BIYVUPC6.js";
18
18
  import {
19
19
  OKF_PROFILE_TYPE,
20
20
  okfTypeForMemory
@@ -272,4 +272,4 @@ export {
272
272
  exportOkfBundle,
273
273
  firstHeading
274
274
  };
275
- //# sourceMappingURL=chunk-GPVGAHXL.js.map
275
+ //# sourceMappingURL=chunk-CNAL35D5.js.map
@@ -3,7 +3,7 @@ import {
3
3
  getOperation,
4
4
  operationRequiresAuthorizedNamespace,
5
5
  operationUsesPrincipalNamespace
6
- } from "./chunk-7IANFJ24.js";
6
+ } from "./chunk-RWMLDC2F.js";
7
7
  import {
8
8
  assertOperationAuthorizationAllowed
9
9
  } from "./chunk-IG747LRN.js";
@@ -60,4 +60,4 @@ export {
60
60
  authorizationProbeNamespaces,
61
61
  authorizationProbeRequiresPrincipalNamespace
62
62
  };
63
- //# sourceMappingURL=chunk-NJ2DZYEK.js.map
63
+ //# sourceMappingURL=chunk-DBM2NQBG.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  StorageManager
3
- } from "./chunk-5KZNWERU.js";
3
+ } from "./chunk-BIYVUPC6.js";
4
4
  import {
5
5
  getCachedRuleMemories,
6
6
  setCachedRuleMemories
@@ -119,4 +119,4 @@ export {
119
119
  compareVerifiedSemanticRuleResults,
120
120
  searchVerifiedSemanticRules
121
121
  };
122
- //# sourceMappingURL=chunk-U66CTIF5.js.map
122
+ //# sourceMappingURL=chunk-F2RDRE7M.js.map
@@ -3,7 +3,7 @@ import {
3
3
  headerConnector,
4
4
  renderExtractionConversation,
5
5
  resolveSourceConnector
6
- } from "./chunk-GLB6VV3J.js";
6
+ } from "./chunk-OUYYEPXD.js";
7
7
  import {
8
8
  normalizeReasoningTrace
9
9
  } from "./chunk-54V4BZWP.js";
@@ -41,10 +41,12 @@ import {
41
41
  isPlainRecord
42
42
  } from "./chunk-BVRZSI7Q.js";
43
43
  import {
44
+ LocalLlmRejectedError,
44
45
  classifyExtractionThrownError,
45
46
  classifyFallbackParseFailure,
46
- formatExtractionParseFailureLog
47
- } from "./chunk-PJRKLB4Z.js";
47
+ formatExtractionParseFailureLog,
48
+ localRejectionStatus
49
+ } from "./chunk-L5PM7B3I.js";
48
50
  import {
49
51
  delinearize
50
52
  } from "./chunk-VEWZZM3H.js";
@@ -1023,7 +1025,7 @@ var ExtractionEngine = class {
1023
1025
  entities: [],
1024
1026
  questions: [],
1025
1027
  extractionFailure: "local_llm_error",
1026
- extractionFailureClass: "provider_retryable"
1028
+ extractionFailureClass: err instanceof LocalLlmRejectedError ? "parse_empty" : classifyExtractionThrownError(err)
1027
1029
  };
1028
1030
  }
1029
1031
  log.info("extraction: local LLM error, falling back to gateway default AI:", err);
@@ -1268,9 +1270,8 @@ ${extractionResponseShape(this.config.extraction?.spanMode ?? "off")}
1268
1270
 
1269
1271
  Conversation:
1270
1272
  ${truncatedConversation}`;
1271
- log.debug(
1272
- `extractWithLocalLlm: calling localLlm.chatCompletion with prompt length ${localPrompt.length}...`
1273
- );
1273
+ log.debug(`extractWithLocalLlm: calling localLlm.chatCompletion with prompt length ${localPrompt.length}...`);
1274
+ const failureDiag = {};
1274
1275
  const response = await this.localLlm.chatCompletion(
1275
1276
  [
1276
1277
  { role: "system", content: "You are a memory extraction system. Output valid JSON only." },
@@ -1283,10 +1284,13 @@ ${truncatedConversation}`;
1283
1284
  responseFormat: extractionProviderResponseFormat(this.config.extraction?.spanMode ?? "off"),
1284
1285
  disableThinking: shouldEnableLocalExtractionThinking(this.config, conversation.length) ? false : void 0,
1285
1286
  priority: "background",
1286
- signal
1287
+ signal,
1288
+ failureDiag
1287
1289
  }
1288
1290
  );
1289
1291
  if (!response?.content) {
1292
+ const rejected = localRejectionStatus(failureDiag);
1293
+ if (rejected !== void 0) throw new LocalLlmRejectedError(rejected);
1290
1294
  log.debug("extractWithLocalLlm: chatCompletion returned null or empty content");
1291
1295
  return null;
1292
1296
  }
@@ -1310,12 +1314,10 @@ ${truncatedConversation}`;
1310
1314
  log.debug("extractWithLocalLlm: JSON parse failed, attempting partial extraction...");
1311
1315
  const partial = this.extractPartialFacts(content);
1312
1316
  if (partial.facts.length > 0 || partial.entities.length > 0) {
1313
- log.debug(
1314
- `extractWithLocalLlm: extracted ${partial.facts.length} partial facts from truncated JSON`
1315
- );
1317
+ log.debug(`extractWithLocalLlm: extracted ${partial.facts.length} partial facts from truncated JSON`);
1316
1318
  return partial;
1317
1319
  }
1318
- return null;
1320
+ throw new LocalLlmRejectedError();
1319
1321
  }
1320
1322
  /**
1321
1323
  * Extract memories using direct OpenAI-compatible client (Chat Completions API).
@@ -2439,4 +2441,4 @@ export {
2439
2441
  shouldEnableLocalExtractionThinking,
2440
2442
  ExtractionEngine
2441
2443
  };
2442
- //# sourceMappingURL=chunk-VIS23B6O.js.map
2444
+ //# sourceMappingURL=chunk-F7MP76CB.js.map