@remnic/core 9.15.0 → 9.15.2

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 (354) hide show
  1. package/dist/access-admin-ops-surface.d.ts +10 -7
  2. package/dist/access-admin-ops-surface.js +21 -21
  3. package/dist/access-boundary.d.ts +10 -7
  4. package/dist/access-boundary.js +21 -22
  5. package/dist/access-cli.js +73 -75
  6. package/dist/access-cli.js.map +1 -1
  7. package/dist/access-http.d.ts +8 -7
  8. package/dist/access-http.js +27 -28
  9. package/dist/access-identity-continuity-surface.d.ts +6 -6
  10. package/dist/access-identity-continuity-surface.js +21 -21
  11. package/dist/access-lcm-surface.d.ts +10 -7
  12. package/dist/access-lcm-surface.js +21 -21
  13. package/dist/access-mcp.d.ts +10 -7
  14. package/dist/access-mcp.js +26 -27
  15. package/dist/access-memory-search-fanout.d.ts +2 -2
  16. package/dist/access-namespace-preflight-B9e5GnyZ.d.ts +146 -0
  17. package/dist/access-namespace-preflight.d.ts +8 -0
  18. package/dist/access-namespace-preflight.js +158 -0
  19. package/dist/access-observe-write-surface.d.ts +10 -7
  20. package/dist/access-observe-write-surface.js +21 -21
  21. package/dist/access-operations-batch.js +23 -24
  22. package/dist/access-operations.d.ts +11 -8
  23. package/dist/access-operations.js +25 -26
  24. package/dist/access-recall-concurrency.d.ts +10 -7
  25. package/dist/access-recall-concurrency.js +21 -21
  26. package/dist/access-recall-response.d.ts +10 -7
  27. package/dist/access-recall-response.js +21 -21
  28. package/dist/access-recall-surface.d.ts +10 -7
  29. package/dist/access-recall-surface.js +21 -21
  30. package/dist/access-schema.js +3 -3
  31. package/dist/{access-service-DbZ1G3zV.d.ts → access-service-DgmJd_A-.d.ts} +10 -118
  32. package/dist/access-service.d.ts +10 -7
  33. package/dist/access-service.js +21 -21
  34. package/dist/access-surface-catalog.d.ts +10 -7
  35. package/dist/action-confidence.d.ts +1 -1
  36. package/dist/active-memory-bridge.d.ts +1 -1
  37. package/dist/active-recall.d.ts +1 -1
  38. package/dist/active-recall.js +2 -2
  39. package/dist/behavior-learner.d.ts +1 -1
  40. package/dist/behavior-signals.d.ts +1 -1
  41. package/dist/bootstrap.d.ts +6 -6
  42. package/dist/briefing.d.ts +2 -2
  43. package/dist/briefing.js +6 -6
  44. package/dist/buffer-surprise-report.d.ts +1 -1
  45. package/dist/buffer.d.ts +2 -2
  46. package/dist/bulk-import/index.d.ts +3 -3
  47. package/dist/calibration.d.ts +1 -1
  48. package/dist/capabilities.d.ts +1 -1
  49. package/dist/{capsule-crypto-GWVG7LGC.js → capsule-crypto-7FJQINUR.js} +2 -2
  50. package/dist/capsule-crypto-7FJQINUR.js.map +1 -0
  51. package/dist/{catalog-BWqHb5HT.d.ts → catalog-g_dfT6oL.d.ts} +1 -1
  52. package/dist/causal-behavior.d.ts +1 -1
  53. package/dist/causal-consolidation.d.ts +1 -1
  54. package/dist/causal-consolidation.js +7 -7
  55. package/dist/causal-trajectory-graph.d.ts +1 -1
  56. package/dist/{chunk-OWHERGF2.js → chunk-2NLLXCJG.js} +2 -2
  57. package/dist/{chunk-YQQYS2K4.js → chunk-42DJZZUB.js} +2 -2
  58. package/dist/{chunk-YUQOAKPX.js → chunk-47WFEKT7.js} +5 -5
  59. package/dist/{chunk-YO3ZB3PJ.js → chunk-4E5H4FPC.js} +30 -15
  60. package/dist/chunk-4E5H4FPC.js.map +1 -0
  61. package/dist/{chunk-226RNKRU.js → chunk-5HFIHWOF.js} +37 -37
  62. package/dist/{chunk-A56B2AJR.js → chunk-5MDE5MIC.js} +3 -3
  63. package/dist/{chunk-W2OST2HH.js → chunk-6EJL2O3G.js} +2 -2
  64. package/dist/{chunk-ALSGMEJR.js → chunk-7CPOZH6Y.js} +5 -5
  65. package/dist/{chunk-MMGGVZ4Q.js → chunk-7VZWZVYG.js} +40 -18
  66. package/dist/{chunk-MMGGVZ4Q.js.map → chunk-7VZWZVYG.js.map} +1 -1
  67. package/dist/{chunk-WSHJAY5M.js → chunk-B57BIBXI.js} +2 -2
  68. package/dist/{chunk-KN6UGAQB.js → chunk-B6NCHYAK.js} +7 -2
  69. package/dist/chunk-B6NCHYAK.js.map +1 -0
  70. package/dist/{chunk-AS6UOOXF.js → chunk-BNH2VVWP.js} +2 -2
  71. package/dist/{chunk-6KIQT7RG.js → chunk-BZ52BJ6C.js} +2 -2
  72. package/dist/chunk-BZ52BJ6C.js.map +1 -0
  73. package/dist/{chunk-5RZHHANR.js → chunk-CXFVZ3PK.js} +54 -54
  74. package/dist/{chunk-SK7AMF2J.js → chunk-DETNBTZS.js} +3 -3
  75. package/dist/{chunk-TY6NBWV4.js → chunk-EEUZQQRJ.js} +2 -2
  76. package/dist/{chunk-YVKF3HEW.js → chunk-FJ5IQ3SI.js} +1 -1
  77. package/dist/chunk-FJ5IQ3SI.js.map +1 -0
  78. package/dist/{chunk-HLG7VAZP.js → chunk-GQOKO77V.js} +2 -2
  79. package/dist/{chunk-CAZ2SHEP.js → chunk-H4MDUPER.js} +2 -2
  80. package/dist/{chunk-TC5HBIIT.js → chunk-HBYQAOED.js} +2 -2
  81. package/dist/{chunk-YSDVEPV2.js → chunk-IRX5UCGN.js} +10 -10
  82. package/dist/{chunk-3HYWNJDA.js → chunk-JN4N2TMQ.js} +423 -45
  83. package/dist/chunk-JN4N2TMQ.js.map +1 -0
  84. package/dist/{chunk-IQFS4AU7.js → chunk-JTW4TGPV.js} +2 -2
  85. package/dist/{chunk-I4NJ2CDY.js → chunk-KLXG4BBO.js} +4 -6
  86. package/dist/{chunk-I4NJ2CDY.js.map → chunk-KLXG4BBO.js.map} +1 -1
  87. package/dist/{chunk-5W7CTZ2E.js → chunk-KQAFEZQX.js} +4 -4
  88. package/dist/{chunk-PYHOAXTI.js → chunk-LRGSLV7M.js} +4 -4
  89. package/dist/{chunk-Y6XODVJ4.js → chunk-NAY25BGS.js} +9 -9
  90. package/dist/{chunk-7HZMTXXB.js → chunk-O7ACJAHR.js} +18 -11
  91. package/dist/{chunk-7HZMTXXB.js.map → chunk-O7ACJAHR.js.map} +1 -1
  92. package/dist/{chunk-QJAQNXWI.js → chunk-ONHRRJZM.js} +6 -6
  93. package/dist/{chunk-O4K3DWK2.js → chunk-OOGGUXAG.js} +2 -2
  94. package/dist/{chunk-CQ6WP3PA.js → chunk-P53HGVJS.js} +5 -5
  95. package/dist/{chunk-U3ZAVRP3.js → chunk-PXJEL55X.js} +2 -2
  96. package/dist/{chunk-DF552QUN.js → chunk-QCLQ4BGA.js} +5 -5
  97. package/dist/{chunk-IAHNKI2E.js → chunk-QDNE35FU.js} +2 -2
  98. package/dist/{chunk-XMAD32BW.js → chunk-RRS5CDB6.js} +2 -2
  99. package/dist/{chunk-3QAH2S33.js → chunk-SYCVU556.js} +3 -3
  100. package/dist/{chunk-QZGN4773.js → chunk-T4EAQPQQ.js} +3 -3
  101. package/dist/{chunk-7G7DVA2C.js → chunk-T4OTDMX4.js} +2 -2
  102. package/dist/{chunk-XRNU7OEQ.js → chunk-U6QWUFSM.js} +3 -3
  103. package/dist/{chunk-UDIJMITR.js → chunk-UJIBXOJA.js} +23 -23
  104. package/dist/chunk-UJIBXOJA.js.map +1 -0
  105. package/dist/{chunk-CQMEM5CC.js → chunk-WIKOHCQZ.js} +2 -2
  106. package/dist/{chunk-UVYI6VIX.js → chunk-X7Y7WX73.js} +1 -1
  107. package/dist/{chunk-3332THSR.js → chunk-XJT6LNLY.js} +4 -4
  108. package/dist/{chunk-AVPXXV6J.js → chunk-XKGPIWGI.js} +4 -4
  109. package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
  110. package/dist/{chunk-46OH3OVK.js → chunk-YXTSUIXC.js} +5 -1
  111. package/dist/chunk-YXTSUIXC.js.map +1 -0
  112. package/dist/{cli-5tNLVTvJ.d.ts → cli-BXCd2cgK.d.ts} +5 -5
  113. package/dist/cli.d.ts +12 -9
  114. package/dist/cli.js +51 -52
  115. package/dist/compounding/engine.d.ts +2 -2
  116. package/dist/compounding/engine.js +6 -6
  117. package/dist/compounding/preference-consolidator.d.ts +1 -1
  118. package/dist/compression-optimizer.d.ts +1 -1
  119. package/dist/config.d.ts +1 -1
  120. package/dist/config.js +2 -2
  121. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  122. package/dist/connectors/codex-materialize-runner.js +6 -6
  123. package/dist/connectors/codex-materialize.d.ts +1 -1
  124. package/dist/connectors/index.d.ts +1 -1
  125. package/dist/connectors/index.js +6 -6
  126. package/dist/consolidation-provenance-check.d.ts +2 -2
  127. package/dist/consolidation-undo.d.ts +2 -2
  128. package/dist/contradiction/index.d.ts +2 -2
  129. package/dist/contradiction/index.js +4 -4
  130. package/dist/conversation-index/backend.d.ts +1 -1
  131. package/dist/conversation-index/chunker.d.ts +1 -1
  132. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  133. package/dist/conversation-index/indexer.d.ts +1 -1
  134. package/dist/conversation-index/search.d.ts +1 -1
  135. package/dist/dashboard-runtime.js +2 -2
  136. package/dist/day-summary.d.ts +1 -1
  137. package/dist/delinearize.d.ts +1 -1
  138. package/dist/direct-answer-wiring.d.ts +1 -1
  139. package/dist/direct-answer.d.ts +1 -1
  140. package/dist/embedding-fallback.d.ts +1 -1
  141. package/dist/enrichment/index.d.ts +1 -1
  142. package/dist/entity-retrieval.d.ts +2 -2
  143. package/dist/entity-retrieval.js +6 -6
  144. package/dist/entity-schema.d.ts +1 -1
  145. package/dist/explicit-capture.d.ts +6 -6
  146. package/dist/extraction-faithfulness.d.ts +1 -1
  147. package/dist/extraction-judge-telemetry.d.ts +1 -1
  148. package/dist/extraction-judge-training.d.ts +1 -1
  149. package/dist/extraction-judge.d.ts +1 -1
  150. package/dist/extraction.d.ts +3 -2
  151. package/dist/extraction.js +6 -4
  152. package/dist/fallback-llm.d.ts +1 -1
  153. package/dist/graph-dashboard-diff.d.ts +1 -1
  154. package/dist/graph-dashboard-key.d.ts +1 -1
  155. package/dist/graph-dashboard-parser.d.ts +1 -1
  156. package/dist/graph-edge-reinforcement.d.ts +1 -1
  157. package/dist/graph-snapshot.d.ts +1 -1
  158. package/dist/graph.d.ts +1 -1
  159. package/dist/importance.d.ts +1 -1
  160. package/dist/importers/index.d.ts +1 -1
  161. package/dist/in-flight-reads.d.ts +1 -1
  162. package/dist/index.d.ts +16 -15
  163. package/dist/index.js +84 -86
  164. package/dist/intent.d.ts +1 -1
  165. package/dist/lcm/engine.d.ts +1 -1
  166. package/dist/lcm/index.d.ts +1 -1
  167. package/dist/lcm/index.js +3 -3
  168. package/dist/lcm/tools.d.ts +1 -1
  169. package/dist/lifecycle.d.ts +1 -1
  170. package/dist/live-connectors-runner.d.ts +1 -1
  171. package/dist/local-llm.d.ts +2 -1
  172. package/dist/local-llm.js +1 -1
  173. package/dist/local-model-endpoint.d.ts +1 -1
  174. package/dist/maintenance/memory-governance.d.ts +1 -1
  175. package/dist/maintenance/memory-governance.js +6 -6
  176. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  177. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +6 -6
  178. package/dist/maintenance/rebuild-memory-projection.js +7 -7
  179. package/dist/mcp-memory-inspector-app.d.ts +10 -7
  180. package/dist/memory-action-policy.d.ts +1 -1
  181. package/dist/memory-cache.d.ts +1 -1
  182. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  183. package/dist/memory-projection-store.d.ts +1 -1
  184. package/dist/memory-provenance.d.ts +1 -1
  185. package/dist/memory-worth-outcomes.d.ts +2 -2
  186. package/dist/models-json.d.ts +1 -1
  187. package/dist/namespaces/migrate.d.ts +3 -3
  188. package/dist/namespaces/migrate.js +12 -12
  189. package/dist/namespaces/principal.d.ts +1 -1
  190. package/dist/namespaces/search.d.ts +1 -1
  191. package/dist/namespaces/search.js +5 -5
  192. package/dist/namespaces/storage.d.ts +3 -3
  193. package/dist/namespaces/storage.js +6 -6
  194. package/dist/native-knowledge.d.ts +1 -1
  195. package/dist/offline-sync-impression-drain.d.ts +1 -1
  196. package/dist/offline-sync-impression-drain.js +4 -4
  197. package/dist/operator-toolkit.d.ts +2 -2
  198. package/dist/operator-toolkit.js +18 -18
  199. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  200. package/dist/orchestration/maintenance.d.ts +3 -3
  201. package/dist/orchestration/maintenance.js +10 -10
  202. package/dist/{orchestrator-CQJ8U7En.d.ts → orchestrator-BHfWtvEJ.d.ts} +5 -5
  203. package/dist/orchestrator.d.ts +6 -6
  204. package/dist/orchestrator.js +74 -75
  205. package/dist/patterns-cli.d.ts +1 -1
  206. package/dist/{pipeline-Cn-kvYeV.d.ts → pipeline-CBYcnmDC.d.ts} +1 -1
  207. package/dist/policy-runtime.d.ts +1 -1
  208. package/dist/proactive-contention.d.ts +1 -1
  209. package/dist/provenance.d.ts +1 -1
  210. package/dist/{qmd-oh9VXz1d.d.ts → qmd-BIq-jrV4.d.ts} +1 -1
  211. package/dist/qmd-preflight.d.ts +2 -2
  212. package/dist/qmd-recall-cache.d.ts +1 -1
  213. package/dist/qmd.d.ts +2 -2
  214. package/dist/qmd.js +4 -4
  215. package/dist/recall-concurrency-config.d.ts +1 -1
  216. package/dist/recall-disclosure-escalation.d.ts +1 -1
  217. package/dist/recall-explain-renderer.d.ts +1 -1
  218. package/dist/recall-explain-renderer.js +3 -3
  219. package/dist/recall-memory-map.d.ts +1 -1
  220. package/dist/recall-planner-llm.d.ts +1 -1
  221. package/dist/recall-state.d.ts +1 -1
  222. package/dist/recall-tag-filter.d.ts +1 -1
  223. package/dist/recall-timings.d.ts +1 -1
  224. package/dist/recall-xray-cli.d.ts +1 -1
  225. package/dist/recall-xray-cli.js +4 -4
  226. package/dist/recall-xray-renderer.d.ts +1 -1
  227. package/dist/recall-xray-renderer.js +3 -3
  228. package/dist/recall-xray.d.ts +1 -1
  229. package/dist/recall-xray.js +2 -2
  230. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  231. package/dist/replay/normalizers/claude.d.ts +1 -1
  232. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  233. package/dist/replay/normalizers/shared.d.ts +1 -1
  234. package/dist/replay/runner.d.ts +1 -1
  235. package/dist/replay/types.d.ts +1 -1
  236. package/dist/resolve-auth-token.d.ts +1 -1
  237. package/dist/resume-bundles.js +3 -3
  238. package/dist/retrieval-agents.d.ts +2 -2
  239. package/dist/retrieval-tiers.d.ts +1 -1
  240. package/dist/routing/engine.d.ts +1 -1
  241. package/dist/routing/store.d.ts +1 -1
  242. package/dist/salvage-envelope.d.ts +1 -1
  243. package/dist/{scope-profiles-EpJG7yKP.d.ts → scope-profiles-DDno-uvy.d.ts} +1 -1
  244. package/dist/search/embed-helper.d.ts +1 -1
  245. package/dist/search/factory.d.ts +1 -1
  246. package/dist/search/factory.js +4 -4
  247. package/dist/search/index.d.ts +1 -1
  248. package/dist/search/index.js +6 -6
  249. package/dist/search/lancedb-backend.d.ts +1 -1
  250. package/dist/search/meilisearch-backend.d.ts +1 -1
  251. package/dist/search/noop-backend.d.ts +1 -1
  252. package/dist/search/orama-backend.d.ts +1 -1
  253. package/dist/search/port.d.ts +1 -1
  254. package/dist/search/remote-backend.d.ts +1 -1
  255. package/dist/{semantic-consolidation-DILZEQq3.d.ts → semantic-consolidation-7RIJFDwY.d.ts} +1 -1
  256. package/dist/semantic-consolidation.d.ts +2 -2
  257. package/dist/semantic-consolidation.js +7 -7
  258. package/dist/semantic-rule-promotion.js +6 -6
  259. package/dist/semantic-rule-verifier.d.ts +1 -1
  260. package/dist/semantic-rule-verifier.js +6 -6
  261. package/dist/session-observer-bands.d.ts +1 -1
  262. package/dist/session-observer-state.d.ts +1 -1
  263. package/dist/shared-context/manager.d.ts +1 -1
  264. package/dist/signal.d.ts +1 -1
  265. package/dist/{storage-NIyKYD8g.d.ts → storage-DkphZiOJ.d.ts} +1 -1
  266. package/dist/storage.d.ts +2 -2
  267. package/dist/storage.js +5 -5
  268. package/dist/summarizer.d.ts +1 -1
  269. package/dist/summarizer.js +2 -2
  270. package/dist/summary-snapshot.d.ts +1 -1
  271. package/dist/temporal-supersession.d.ts +2 -2
  272. package/dist/temporal-timeline-recall.d.ts +1 -1
  273. package/dist/temporal-validity.d.ts +1 -1
  274. package/dist/threading.d.ts +1 -1
  275. package/dist/tier-migration.d.ts +2 -2
  276. package/dist/tier-routing.d.ts +1 -1
  277. package/dist/topics.d.ts +1 -1
  278. package/dist/transcript.d.ts +1 -1
  279. package/dist/transfer/backup.js +2 -2
  280. package/dist/transfer/capsule-export.js +2 -2
  281. package/dist/transfer/capsule-import.js +2 -2
  282. package/dist/transfer/import-sqlite.js +2 -2
  283. package/dist/trust-score-stage.d.ts +1 -1
  284. package/dist/trust-score.d.ts +1 -1
  285. package/dist/{types-D_fG2ix8.d.ts → types-2q_MRFcM.d.ts} +6 -0
  286. package/dist/types.d.ts +1 -1
  287. package/dist/types.js +1 -1
  288. package/dist/utility-runtime.d.ts +1 -1
  289. package/dist/verified-recall.js +6 -6
  290. package/dist/write-envelope.d.ts +1 -1
  291. package/package.json +2 -2
  292. package/src/access-http.test.ts +91 -0
  293. package/src/access-http.ts +13 -14
  294. package/src/access-namespace-preflight.test.ts +111 -0
  295. package/src/access-namespace-preflight.ts +111 -0
  296. package/src/access-operations-batch.ts +25 -2
  297. package/src/access-service-observe-scope.test.ts +81 -0
  298. package/src/access-service.ts +64 -78
  299. package/src/config.test.ts +7 -0
  300. package/src/config.ts +6 -0
  301. package/src/extraction-thinking.test.ts +44 -0
  302. package/src/extraction.ts +12 -0
  303. package/src/local-llm-thinking.test.ts +13 -1
  304. package/src/local-llm.ts +2 -1
  305. package/src/orchestration/qmd-result-resolver.test.ts +103 -0
  306. package/src/orchestration/qmd-result-resolver.ts +11 -0
  307. package/src/scopes/scope-plan.ts +66 -0
  308. package/src/types.ts +6 -0
  309. package/dist/chunk-3HYWNJDA.js.map +0 -1
  310. package/dist/chunk-46OH3OVK.js.map +0 -1
  311. package/dist/chunk-6KIQT7RG.js.map +0 -1
  312. package/dist/chunk-KF5EUVKQ.js +0 -289
  313. package/dist/chunk-KF5EUVKQ.js.map +0 -1
  314. package/dist/chunk-KN6UGAQB.js.map +0 -1
  315. package/dist/chunk-UDIJMITR.js.map +0 -1
  316. package/dist/chunk-YO3ZB3PJ.js.map +0 -1
  317. package/dist/chunk-YVKF3HEW.js.map +0 -1
  318. /package/dist/{capsule-crypto-GWVG7LGC.js.map → access-namespace-preflight.js.map} +0 -0
  319. /package/dist/{chunk-OWHERGF2.js.map → chunk-2NLLXCJG.js.map} +0 -0
  320. /package/dist/{chunk-YQQYS2K4.js.map → chunk-42DJZZUB.js.map} +0 -0
  321. /package/dist/{chunk-YUQOAKPX.js.map → chunk-47WFEKT7.js.map} +0 -0
  322. /package/dist/{chunk-226RNKRU.js.map → chunk-5HFIHWOF.js.map} +0 -0
  323. /package/dist/{chunk-A56B2AJR.js.map → chunk-5MDE5MIC.js.map} +0 -0
  324. /package/dist/{chunk-W2OST2HH.js.map → chunk-6EJL2O3G.js.map} +0 -0
  325. /package/dist/{chunk-ALSGMEJR.js.map → chunk-7CPOZH6Y.js.map} +0 -0
  326. /package/dist/{chunk-WSHJAY5M.js.map → chunk-B57BIBXI.js.map} +0 -0
  327. /package/dist/{chunk-AS6UOOXF.js.map → chunk-BNH2VVWP.js.map} +0 -0
  328. /package/dist/{chunk-5RZHHANR.js.map → chunk-CXFVZ3PK.js.map} +0 -0
  329. /package/dist/{chunk-SK7AMF2J.js.map → chunk-DETNBTZS.js.map} +0 -0
  330. /package/dist/{chunk-TY6NBWV4.js.map → chunk-EEUZQQRJ.js.map} +0 -0
  331. /package/dist/{chunk-HLG7VAZP.js.map → chunk-GQOKO77V.js.map} +0 -0
  332. /package/dist/{chunk-CAZ2SHEP.js.map → chunk-H4MDUPER.js.map} +0 -0
  333. /package/dist/{chunk-TC5HBIIT.js.map → chunk-HBYQAOED.js.map} +0 -0
  334. /package/dist/{chunk-YSDVEPV2.js.map → chunk-IRX5UCGN.js.map} +0 -0
  335. /package/dist/{chunk-IQFS4AU7.js.map → chunk-JTW4TGPV.js.map} +0 -0
  336. /package/dist/{chunk-5W7CTZ2E.js.map → chunk-KQAFEZQX.js.map} +0 -0
  337. /package/dist/{chunk-PYHOAXTI.js.map → chunk-LRGSLV7M.js.map} +0 -0
  338. /package/dist/{chunk-Y6XODVJ4.js.map → chunk-NAY25BGS.js.map} +0 -0
  339. /package/dist/{chunk-QJAQNXWI.js.map → chunk-ONHRRJZM.js.map} +0 -0
  340. /package/dist/{chunk-O4K3DWK2.js.map → chunk-OOGGUXAG.js.map} +0 -0
  341. /package/dist/{chunk-CQ6WP3PA.js.map → chunk-P53HGVJS.js.map} +0 -0
  342. /package/dist/{chunk-U3ZAVRP3.js.map → chunk-PXJEL55X.js.map} +0 -0
  343. /package/dist/{chunk-DF552QUN.js.map → chunk-QCLQ4BGA.js.map} +0 -0
  344. /package/dist/{chunk-IAHNKI2E.js.map → chunk-QDNE35FU.js.map} +0 -0
  345. /package/dist/{chunk-XMAD32BW.js.map → chunk-RRS5CDB6.js.map} +0 -0
  346. /package/dist/{chunk-3QAH2S33.js.map → chunk-SYCVU556.js.map} +0 -0
  347. /package/dist/{chunk-QZGN4773.js.map → chunk-T4EAQPQQ.js.map} +0 -0
  348. /package/dist/{chunk-7G7DVA2C.js.map → chunk-T4OTDMX4.js.map} +0 -0
  349. /package/dist/{chunk-XRNU7OEQ.js.map → chunk-U6QWUFSM.js.map} +0 -0
  350. /package/dist/{chunk-CQMEM5CC.js.map → chunk-WIKOHCQZ.js.map} +0 -0
  351. /package/dist/{chunk-UVYI6VIX.js.map → chunk-X7Y7WX73.js.map} +0 -0
  352. /package/dist/{chunk-3332THSR.js.map → chunk-XJT6LNLY.js.map} +0 -0
  353. /package/dist/{chunk-AVPXXV6J.js.map → chunk-XKGPIWGI.js.map} +0 -0
  354. /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
@@ -6,6 +6,7 @@ import { readdirSync, unlinkSync } from "node:fs";
6
6
  import { createHash } from "node:crypto";
7
7
  import { ZodError } from "zod";
8
8
  import { AccessIdempotencyStore, hashAccessIdempotencyPayload } from "./access-idempotency.js";
9
+ import { enforceNamespaceAllowList, tokenCapabilityStore } from "./access-token-capabilities.js";
9
10
  import {
10
11
  recordCitationUsage as recordCitationUsageForAccess,
11
12
  type CitationUsageRequest,
@@ -130,8 +131,11 @@ import {
130
131
  import {
131
132
  type ScopePlan,
132
133
  resolveScopePlan,
134
+ resolveScopedWritableNamespaceValue,
133
135
  resolveWritableNamespaceValue,
136
+ type WritableNamespaceResult,
134
137
  } from "./scopes/scope-plan.js";
138
+ import { resolveNamespaceWritablePreflight, type EngramAccessNamespaceWritableRequest } from "./access-namespace-preflight.js";
135
139
  import { namespaceIdentityFromToken } from "./namespaces/identity.js";
136
140
  import { namespaceCollectionName } from "./namespaces/search.js";
137
141
  import { SecureStoreLockedError } from "./secure-store/index.js";
@@ -277,52 +281,6 @@ import { EngramAccessInputError, NamespaceNotWritableError } from "./access-erro
277
281
  // working after these classes moved to ./access-errors (issue #1888).
278
282
  export { EngramAccessInputError, NamespaceNotWritableError } from "./access-errors.js";
279
283
 
280
- function qmdCollectionPathParts(resultPath: string): {
281
- collection: string;
282
- relativePath: string;
283
- } | null {
284
- if (!resultPath || nodePath.isAbsolute(resultPath)) return null;
285
- const normalized = resultPath.replace(/\\/g, "/").replace(/^\/+/, "");
286
- const slashIndex = normalized.indexOf("/");
287
- if (slashIndex <= 0 || slashIndex >= normalized.length - 1) return null;
288
- const collection = normalized.slice(0, slashIndex);
289
- if (/^\d{4}-\d{2}-\d{2}$/.test(collection)) return null;
290
- return {
291
- collection,
292
- relativePath: normalized.slice(slashIndex + 1),
293
- };
294
- }
295
-
296
- function qmdResultPathCandidates(
297
- storageDir: string,
298
- resultPath: string,
299
- ): string[] {
300
- const candidates = new Set<string>();
301
- const storageRoot = nodePath.resolve(storageDir);
302
- const addCandidate = (candidate: string) => {
303
- const resolved = nodePath.resolve(candidate);
304
- if (isPathInsideStorageRoot(storageRoot, resolved)) {
305
- candidates.add(resolved);
306
- }
307
- };
308
- const addRelativeCandidates = (relativePath: string) => {
309
- const normalized = relativePath.replace(/\\/g, "/").replace(/^\/+/, "");
310
- if (!normalized) return;
311
- addCandidate(nodePath.join(storageRoot, normalized));
312
- if (/^\d{4}-\d{2}-\d{2}\//.test(normalized)) {
313
- addCandidate(nodePath.join(storageRoot, "facts", normalized));
314
- }
315
- };
316
-
317
- if (nodePath.isAbsolute(resultPath)) {
318
- addCandidate(resultPath);
319
- } else {
320
- addRelativeCandidates(resultPath);
321
- }
322
-
323
- return [...candidates];
324
- }
325
-
326
284
  export type AccessProfilingReportRequest = {
327
285
  format?: string;
328
286
  limit?: number;
@@ -958,7 +916,7 @@ export interface CodingScopedWriteInput {
958
916
  cwd?: string;
959
917
  projectTag?: string;
960
918
  }
961
-
919
+ export type { EngramAccessNamespaceWritableRequest } from "./access-namespace-preflight.js";
962
920
  /**
963
921
  * Internal, single-resolution plan describing the effective memory scope for a
964
922
  * write-producing access request (#1495, seed for epic #1494). One plan is
@@ -1588,6 +1546,14 @@ export class EngramAccessService {
1588
1546
  return { principal, codingContext, overlay, profilePlan };
1589
1547
  }
1590
1548
 
1549
+ private assertTokenCanWriteNamespace(namespace: string): void {
1550
+ enforceNamespaceAllowList(
1551
+ tokenCapabilityStore.getStore(),
1552
+ namespace,
1553
+ this.orchestrator.config.defaultNamespace,
1554
+ );
1555
+ }
1556
+
1591
1557
  /**
1592
1558
  * Resolve the write namespace for explicit-write tools (memory_store /
1593
1559
  * suggestion_submit), project-scoping the write the same way recall does so a
@@ -1603,49 +1569,56 @@ export class EngramAccessService {
1603
1569
  sessionKey?: string;
1604
1570
  authenticatedPrincipal?: string;
1605
1571
  },
1572
+ enforceToken: boolean = true,
1606
1573
  ): Promise<string> {
1607
- const hasExplicitNamespace =
1608
- typeof request.namespace === "string" && request.namespace.trim().length > 0;
1609
- if (hasExplicitNamespace) {
1610
- return this.writableNamespaceFor(
1611
- request.namespace,
1574
+ const requested = request.namespace?.trim();
1575
+ if (requested) {
1576
+ const namespace = this.writableNamespaceFor(
1577
+ requested,
1612
1578
  request.sessionKey,
1613
1579
  request.authenticatedPrincipal,
1614
1580
  );
1581
+ if (enforceToken) this.assertTokenCanWriteNamespace(namespace);
1582
+ return namespace;
1615
1583
  }
1584
+
1616
1585
  const { principal, overlay, profilePlan } = await this.resolveCodingScopeInputs(request);
1617
- if (profilePlan) {
1618
- const selectedLayer = profilePlan.layers.find((layer) => layer.id === profilePlan.writeLayer);
1619
- const writeNamespaceReadable =
1620
- profilePlan.writeNamespace.length > 0 &&
1621
- profilePlan.readNamespaces.includes(profilePlan.writeNamespace);
1622
- if (!selectedLayer?.writable || !writeNamespaceReadable) {
1623
- throw new NamespaceNotWritableError(profilePlan.writeNamespace, principal,
1624
- `scope profile ${profilePlan.profileId} has no writable layer for principal ${principal ?? "anonymous"}`);
1625
- }
1626
- return profilePlan.writeNamespace;
1586
+ const result = resolveScopedWritableNamespaceValue({
1587
+ sessionKey: request.sessionKey,
1588
+ authenticatedPrincipal: request.authenticatedPrincipal,
1589
+ principal,
1590
+ codingOverlay: overlay,
1591
+ scopeProfile: profilePlan,
1592
+ config: this.orchestrator.config,
1593
+ });
1594
+ if (result.ok) {
1595
+ if (enforceToken) this.assertTokenCanWriteNamespace(result.namespace);
1596
+ return result.namespace;
1627
1597
  }
1628
- if (!overlay) {
1629
- // No coding overlay → unqualified write stays on config.defaultNamespace,
1630
- // exactly the pre-#1434 behavior (auth-checked, like the legacy path).
1631
- return this.writableNamespaceFor(
1632
- undefined,
1633
- request.sessionKey,
1634
- request.authenticatedPrincipal,
1598
+ if (profilePlan && result.namespace === profilePlan.writeNamespace) {
1599
+ throw new NamespaceNotWritableError(
1600
+ result.namespace,
1601
+ principal,
1602
+ `scope profile ${profilePlan.profileId} has no writable layer for principal ${principal ?? "anonymous"}`,
1635
1603
  );
1636
1604
  }
1637
- // Coding overlay → overlay onto the principal self base, the SAME namespace
1638
- // recall/observe/buffer-flush use. The result is a principal-owned
1639
- // `project-*` sub-namespace derived from this authorized base, so it needs
1640
- // no separate write policy.
1641
- const base = defaultNamespaceForPrincipal(principal, this.orchestrator.config);
1642
- if (!canWriteNamespace(principal, base, this.orchestrator.config)) {
1643
- throw new NamespaceNotWritableError(base, principal);
1605
+
1606
+ if (result.reason === "unsupported") {
1607
+ throw new EngramAccessInputError(`unsupported namespace: ${result.namespace}`);
1644
1608
  }
1645
- return combineNamespaces(base, overlay.namespace);
1609
+ throw new NamespaceNotWritableError(result.namespace, principal);
1610
+ }
1611
+
1612
+ async namespaceWritablePreflight(
1613
+ request: EngramAccessNamespaceWritableRequest,
1614
+ ): Promise<WritableNamespaceResult> {
1615
+ return resolveNamespaceWritablePreflight(
1616
+ request,
1617
+ (preflightRequest) => this.resolveCodingScopedWriteNamespace(preflightRequest, false),
1618
+ );
1646
1619
  }
1647
1620
 
1648
- /** Read-side mirror of {@link resolveCodingScopedWriteNamespace}. Decision
1621
+ /**
1649
1622
  * `list`/`get` use this so a record written by a project-scoped session is
1650
1623
  * listable/fetchable by the SAME session without manually supplying the
1651
1624
  * overlaid namespace (review P2). Derivation is IDENTICAL to the write path
@@ -1748,6 +1721,7 @@ export class EngramAccessService {
1748
1721
  request.sessionKey,
1749
1722
  request.authenticatedPrincipal,
1750
1723
  );
1724
+ this.assertTokenCanWriteNamespace(writeNamespace);
1751
1725
  return {
1752
1726
  principal,
1753
1727
  explicitNamespace: request.namespace!.trim(),
@@ -1825,6 +1799,15 @@ export class EngramAccessService {
1825
1799
  this.orchestrator.setCodingContextForSession(request.sessionKey!, null);
1826
1800
  }
1827
1801
  };
1802
+ const assertWriteNamespaceAllowed = (namespace: string): void => {
1803
+ try {
1804
+ this.assertTokenCanWriteNamespace(namespace);
1805
+ } catch (error) {
1806
+ clearSeededContext();
1807
+ throw error;
1808
+ }
1809
+ };
1810
+
1828
1811
 
1829
1812
  const overlaidBase = this.orchestrator.applyCodingNamespaceOverlay(
1830
1813
  request.sessionKey,
@@ -1876,6 +1859,7 @@ export class EngramAccessService {
1876
1859
  readNamespaces.includes(layer.namespace),
1877
1860
  ),
1878
1861
  );
1862
+ assertWriteNamespaceAllowed(profilePlan.writeNamespace);
1879
1863
  return {
1880
1864
  principal,
1881
1865
  baseNamespace: profilePlan.baseNamespace,
@@ -1928,6 +1912,7 @@ export class EngramAccessService {
1928
1912
  clearSeededContext();
1929
1913
  throw new NamespaceNotWritableError(baseNamespace, principal);
1930
1914
  }
1915
+ assertWriteNamespaceAllowed(writeNamespace);
1931
1916
  return {
1932
1917
  principal,
1933
1918
  // scopeDebug.baseNamespace must report the principal SELF base
@@ -1965,6 +1950,7 @@ export class EngramAccessService {
1965
1950
  const ns = combineNamespaces(baseNamespace, fallback);
1966
1951
  if (!readNamespaces.includes(ns)) readNamespaces.push(ns);
1967
1952
  }
1953
+ assertWriteNamespaceAllowed(writeNamespace);
1968
1954
  return {
1969
1955
  principal,
1970
1956
  baseNamespace,
@@ -1179,6 +1179,13 @@ test('parseConfig localLlmDisableThinking "0"/"no"/"off" all coerce to false', (
1179
1179
  assert.equal(parseConfig({ localLlmDisableThinking: "off" }).localLlmDisableThinking, false);
1180
1180
  });
1181
1181
 
1182
+ test("parseConfig localLlmThinkingThresholdChars defaults conservatively and accepts zero to disable (#1997)", () => {
1183
+ assert.equal(parseConfig({}).localLlmThinkingThresholdChars, 3_000);
1184
+ assert.equal(parseConfig({ localLlmThinkingThresholdChars: 0 }).localLlmThinkingThresholdChars, 0);
1185
+ assert.equal(parseConfig({ localLlmThinkingThresholdChars: "3000" }).localLlmThinkingThresholdChars, 3_000);
1186
+ assert.equal(parseConfig({ localLlmThinkingThresholdChars: 3_000 }).localLlmThinkingThresholdChars, 3_000);
1187
+ });
1188
+
1182
1189
  test("parseConfig procedural numeric fields coerce from CLI-style strings (issue #519)", () => {
1183
1190
  const result = parseConfig({
1184
1191
  openaiApiKey: "sk-test",
package/src/config.ts CHANGED
@@ -2856,6 +2856,12 @@ export function parseConfig(
2856
2856
  ["", "none", "low", "medium", "high", "max"].includes(cfg.localLlmReasoningEffort)
2857
2857
  ? cfg.localLlmReasoningEffort
2858
2858
  : "none",
2859
+ localLlmThinkingThresholdChars: (() => {
2860
+ const threshold = coerceNumber(cfg.localLlmThinkingThresholdChars);
2861
+ return threshold !== undefined && Number.isInteger(threshold) && threshold >= 0
2862
+ ? threshold
2863
+ : 3_000;
2864
+ })(),
2859
2865
  // Extraction retry/backoff + circuit breaker (extraction hot-loop hardening)
2860
2866
  extractionRetryEnabled: coerceBooleanLike(cfg.extractionRetryEnabled) ?? true,
2861
2867
  extractionRetryScheduleMs:
@@ -0,0 +1,44 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ import { shouldEnableLocalExtractionThinking } from "./extraction.js";
5
+ import type { PluginConfig } from "./types.js";
6
+
7
+ function config(overrides: Partial<PluginConfig> = {}): PluginConfig {
8
+ return {
9
+ localLlmDisableThinking: true,
10
+ localLlmThinkingThresholdChars: 3_000,
11
+ ...overrides,
12
+ } as PluginConfig;
13
+ }
14
+
15
+ test("short local extraction enables thinking when configured (#1997)", () => {
16
+ assert.equal(shouldEnableLocalExtractionThinking(config(), 2_999), true);
17
+ });
18
+
19
+ test("length-aware local thinking stays disabled at the threshold and above (#1997)", () => {
20
+ assert.equal(shouldEnableLocalExtractionThinking(config(), 3_000), false);
21
+ assert.equal(shouldEnableLocalExtractionThinking(config(), 3_001), false);
22
+ });
23
+
24
+ test("disabled threshold and explicit global opt-out preserve existing behavior (#1997)", () => {
25
+ assert.equal(shouldEnableLocalExtractionThinking(config({ localLlmThinkingThresholdChars: 0 }), 1), false);
26
+ assert.equal(shouldEnableLocalExtractionThinking(config({ localLlmDisableThinking: false }), 1), false);
27
+ });
28
+
29
+ test("four-transcript selection matrix keeps short sparse cases in thinking mode (#1997)", () => {
30
+ const cases = [
31
+ { name: "sparse commitment", transcript: "A".repeat(750), thinking: true },
32
+ { name: "sparse correction", transcript: "B".repeat(1_600), thinking: true },
33
+ { name: "dense technical discussion", transcript: "C".repeat(3_000), thinking: false },
34
+ { name: "dense multi-turn discussion", transcript: "D".repeat(6_000), thinking: false },
35
+ ];
36
+
37
+ for (const scenario of cases) {
38
+ assert.equal(
39
+ shouldEnableLocalExtractionThinking(config(), scenario.transcript.length),
40
+ scenario.thinking,
41
+ scenario.name,
42
+ );
43
+ }
44
+ });
package/src/extraction.ts CHANGED
@@ -147,6 +147,15 @@ function normalizeProfileUpdateKey(update: string): string {
147
147
  return update.trim().toLowerCase();
148
148
  }
149
149
 
150
+ export function shouldEnableLocalExtractionThinking(
151
+ config: Pick<PluginConfig, "localLlmDisableThinking" | "localLlmThinkingThresholdChars">,
152
+ conversationChars: number,
153
+ ): boolean {
154
+ return config.localLlmDisableThinking &&
155
+ config.localLlmThinkingThresholdChars > 0 &&
156
+ conversationChars < config.localLlmThinkingThresholdChars;
157
+ }
158
+
150
159
  export class ExtractionEngine {
151
160
  private client: OpenAI | null;
152
161
  private localLlm: LocalLlmClient;
@@ -1523,6 +1532,9 @@ ${truncatedConversation}`;
1523
1532
  temperature: 0.1,
1524
1533
  maxTokens: contextSizes.maxOutputTokens,
1525
1534
  operation: "extraction",
1535
+ disableThinking: shouldEnableLocalExtractionThinking(this.config, conversation.length)
1536
+ ? false
1537
+ : undefined,
1526
1538
  priority: "background",
1527
1539
  },
1528
1540
  );
@@ -83,7 +83,7 @@ function captureFetchBodies(): {
83
83
  async function runOneChatCompletion(
84
84
  client: LocalLlmClient,
85
85
  operation: string | null = "extraction",
86
- options: { forceDisableThinking?: boolean } = {},
86
+ options: { forceDisableThinking?: boolean; disableThinking?: boolean } = {},
87
87
  ): Promise<void> {
88
88
  await client.chatCompletion(
89
89
  [{ role: "user", content: "hello" }],
@@ -344,3 +344,15 @@ test("disableThinking=false never injects chat_template_kwargs, regardless of ba
344
344
  }
345
345
  assert.equal("chat_template_kwargs" in (bodies[0] ?? {}), false);
346
346
  });
347
+
348
+ test("request-level thinking override leaves short extraction thinking enabled (#1997)", async () => {
349
+ const client = new LocalLlmClient(createConfig());
350
+ primeClient(client, { thinking: true, detected: "ollama" });
351
+ const { restore, bodies } = captureFetchBodies();
352
+ try {
353
+ await runOneChatCompletion(client, "extraction", { disableThinking: false });
354
+ } finally {
355
+ restore();
356
+ }
357
+ assert.equal("reasoning_effort" in (bodies[0] ?? {}), false);
358
+ });
package/src/local-llm.ts CHANGED
@@ -220,6 +220,7 @@ interface LocalLlmChatCompletionOptions {
220
220
  timeoutMs?: number;
221
221
  operation?: string;
222
222
  forceDisableThinking?: boolean;
223
+ disableThinking?: boolean;
223
224
  priority?: LocalLlmRequestPriority;
224
225
  }
225
226
 
@@ -989,7 +990,7 @@ export class LocalLlmClient {
989
990
  // backend hasn't been positively identified as thinking-capable.
990
991
  const shouldSuppressThinking =
991
992
  options.forceDisableThinking === true ||
992
- (this._disableThinking &&
993
+ ((options.disableThinking ?? this._disableThinking) &&
993
994
  THINKING_SUPPRESSED_OPERATIONS.has(operation));
994
995
  if (
995
996
  shouldSuppressThinking &&
@@ -0,0 +1,103 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+
7
+ import { parseConfig } from "../config.js";
8
+ import { StorageManager } from "../index.js";
9
+ import {
10
+ QmdResultResolver,
11
+ qmdResultPathCandidates,
12
+ } from "./qmd-result-resolver.js";
13
+
14
+ test("qmdResultPathCandidates probes the facts/ fallback for relative date paths", () => {
15
+ const root = path.join(os.tmpdir(), "remnic-resolver-rel");
16
+ const candidates = qmdResultPathCandidates(root, "2026-07-21/fact-x.md");
17
+ assert.deepEqual(
18
+ candidates.sort(),
19
+ [
20
+ path.join(root, "2026-07-21", "fact-x.md"),
21
+ path.join(root, "facts", "2026-07-21", "fact-x.md"),
22
+ ].sort(),
23
+ "relative date paths probe both the literal and the facts/ location",
24
+ );
25
+ });
26
+
27
+ test("qmdResultPathCandidates probes the facts/ fallback for absolute date paths inside the storage root (issue #2111)", () => {
28
+ const root = path.join(os.tmpdir(), "remnic-resolver-abs");
29
+ const absolute = path.join(root, "2026-07-21", "fact-x.md");
30
+ const candidates = qmdResultPathCandidates(root, absolute);
31
+ assert.deepEqual(
32
+ candidates.sort(),
33
+ [absolute, path.join(root, "facts", "2026-07-21", "fact-x.md")].sort(),
34
+ "pre-absolutized date paths must probe the facts/ location too",
35
+ );
36
+ });
37
+
38
+ test("qmdResultPathCandidates keeps non-date absolute paths literal", () => {
39
+ const root = path.join(os.tmpdir(), "remnic-resolver-abs-nondate");
40
+ const absolute = path.join(root, "entities", "person-x.md");
41
+ assert.deepEqual(
42
+ qmdResultPathCandidates(root, absolute),
43
+ [absolute],
44
+ "non-date absolute paths must not grow a facts/ variant",
45
+ );
46
+ });
47
+
48
+ test("qmdResultPathCandidates rejects absolute paths outside the storage root", () => {
49
+ const root = path.join(os.tmpdir(), "remnic-resolver-abs-outside");
50
+ const outside = path.join(os.tmpdir(), "elsewhere", "2026-07-21", "fact-x.md");
51
+ assert.deepEqual(
52
+ qmdResultPathCandidates(root, outside),
53
+ [],
54
+ "containment must drop escaping paths, including their facts/ variant",
55
+ );
56
+ });
57
+
58
+ test("readQmdResultMemory resolves an absolute date path whose file lives under facts/ (issue #2111)", async () => {
59
+ const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-resolver-e2e-"));
60
+ try {
61
+ const storage = new StorageManager(dir);
62
+ await storage.ensureDirectories();
63
+ const factDir = path.join(dir, "facts", "2026-07-21");
64
+ await mkdir(factDir, { recursive: true });
65
+ const factPath = path.join(factDir, "fact-cookie-note.md");
66
+ await writeFile(
67
+ factPath,
68
+ [
69
+ "---",
70
+ "id: fact-cookie-note",
71
+ "category: fact",
72
+ "created: 2026-07-21T00:00:00.000Z",
73
+ "updated: 2026-07-21T00:00:00.000Z",
74
+ "status: active",
75
+ "---",
76
+ "",
77
+ "The storefront manages a uniqueId cookie with a 90-day expiration.",
78
+ "",
79
+ ].join("\n"),
80
+ "utf8",
81
+ );
82
+
83
+ const config = parseConfig({ memoryDir: dir });
84
+ const resolver = new QmdResultResolver({
85
+ getConfig: () => config,
86
+ storageFor: async () => storage,
87
+ storageDirNamespace: () => config.defaultNamespace,
88
+ qmdCollectionNamespaceFromPrefix: () => null,
89
+ namespaceFromPath: () => config.defaultNamespace,
90
+ });
91
+
92
+ // Daemon-mode shape: the result path is already absolutized against the
93
+ // storage root but is missing the facts/ segment because the hot-facts
94
+ // collection was registered at the facts/ subtree.
95
+ const preAbsolutized = path.join(dir, "2026-07-21", "fact-cookie-note.md");
96
+ const memory = await resolver.readQmdResultMemory(preAbsolutized, storage);
97
+ assert.ok(memory, "the memory must resolve via the facts/ fallback");
98
+ assert.equal(memory.frontmatter.id, "fact-cookie-note");
99
+ assert.equal(path.resolve(memory.path), path.resolve(factPath));
100
+ } finally {
101
+ await rm(dir, { recursive: true, force: true });
102
+ }
103
+ });
@@ -84,6 +84,17 @@ export function qmdResultPathCandidates(
84
84
 
85
85
  if (path.isAbsolute(resultPath)) {
86
86
  addCandidate(resultPath);
87
+ // Daemon-mode results can arrive pre-absolutized against the storage
88
+ // root while the file lives under facts/<date>/ (hot-facts collection
89
+ // registered at the facts/ subtree — issue #2111). Mirror the relative
90
+ // branch's facts/ fallback; addCandidate re-checks containment.
91
+ const relative = path.relative(storageRoot, path.resolve(resultPath));
92
+ if (relative && !relative.startsWith("..") && !path.isAbsolute(relative)) {
93
+ const normalized = relative.split(path.sep).join("/");
94
+ if (/^\d{4}-\d{2}-\d{2}\//.test(normalized)) {
95
+ addCandidate(path.join(storageRoot, "facts", normalized));
96
+ }
97
+ }
87
98
  } else {
88
99
  addRelativeCandidates(resultPath);
89
100
  }
@@ -489,6 +489,72 @@ export function resolveWritableNamespaceValue(
489
489
  return { ok: true, namespace: resolved };
490
490
  }
491
491
 
492
+ /**
493
+ * Inputs already derived by the access-service's read-only coding-context
494
+ * resolver. Keeping context discovery outside this pure function lets writes
495
+ * and preflight checks apply identical namespace and ACL rules.
496
+ */
497
+ export interface ScopedWritableNamespaceInput {
498
+ readonly namespace?: string;
499
+ readonly sessionKey?: string;
500
+ readonly authenticatedPrincipal?: string;
501
+ readonly principal: string | undefined;
502
+ readonly codingOverlay: CodingNamespaceOverlay | null;
503
+ readonly scopeProfile: ResolvedScopeProfilePlan | null;
504
+ readonly config: PluginConfig;
505
+ }
506
+
507
+ /**
508
+ * Resolve the namespace an explicit write or implicit coding-scoped write
509
+ * would use. The caller supplies the same derived coding inputs for the real
510
+ * write and the read-only preflight.
511
+ */
512
+ export function resolveScopedWritableNamespaceValue(
513
+ input: ScopedWritableNamespaceInput,
514
+ ): WritableNamespaceResult {
515
+ const requested = input.namespace?.trim();
516
+ if (requested) {
517
+ return resolveWritableNamespaceValue(
518
+ requested,
519
+ input.sessionKey,
520
+ input.authenticatedPrincipal,
521
+ input.config,
522
+ );
523
+ }
524
+ if (input.scopeProfile) {
525
+ const selectedLayer = input.scopeProfile.layers.find(
526
+ (layer) => layer.id === input.scopeProfile?.writeLayer,
527
+ );
528
+ const writeNamespaceReadable =
529
+ input.scopeProfile.writeNamespace.length > 0 &&
530
+ input.scopeProfile.readNamespaces.includes(input.scopeProfile.writeNamespace);
531
+ if (!selectedLayer?.writable || !writeNamespaceReadable) {
532
+ return {
533
+ ok: false,
534
+ reason: "not_writable",
535
+ namespace: input.scopeProfile.writeNamespace,
536
+ };
537
+ }
538
+ return { ok: true, namespace: input.scopeProfile.writeNamespace };
539
+ }
540
+ if (!input.codingOverlay) {
541
+ return resolveWritableNamespaceValue(
542
+ undefined,
543
+ input.sessionKey,
544
+ input.authenticatedPrincipal,
545
+ input.config,
546
+ );
547
+ }
548
+ const baseNamespace = defaultNamespaceForPrincipal(input.principal, input.config);
549
+ if (!canWriteNamespace(input.principal, baseNamespace, input.config)) {
550
+ return { ok: false, reason: "not_writable", namespace: baseNamespace };
551
+ }
552
+ return {
553
+ ok: true,
554
+ namespace: combineNamespaces(baseNamespace, input.codingOverlay.namespace),
555
+ };
556
+ }
557
+
492
558
  /**
493
559
  * Namespace preflight (issue #1888 part 3): would a write to `namespace` by a
494
560
  * caller carrying `caps` succeed? Combines the token's write-op scope, its
package/src/types.ts CHANGED
@@ -1624,6 +1624,12 @@ export interface PluginConfig extends BoundedJsonlStateConfig {
1624
1624
  * `chat_template_kwargs`, so this is the only think-off dialect it honors.
1625
1625
  * Issue #1996. */
1626
1626
  localLlmReasoningEffort: string;
1627
+ /**
1628
+ * Maximum transcript length that re-enables thinking for local extraction.
1629
+ * Set to `0` to keep thinking suppressed for every extraction. Default:
1630
+ * `3000`. Consolidation is unaffected.
1631
+ */
1632
+ localLlmThinkingThresholdChars: number;
1627
1633
  // Extraction retry/backoff + circuit breaker (extraction hot-loop hardening)
1628
1634
  /** Master gate. When false, restores pre-change behavior (extractor called on every triggered observe; no gate). */
1629
1635
  extractionRetryEnabled: boolean;