@remnic/core 10.0.83 → 10.0.85

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 (413) hide show
  1. package/dist/access-admin-ops-surface.js +67 -66
  2. package/dist/access-authorization-probe.js +68 -67
  3. package/dist/access-boundary.js +67 -66
  4. package/dist/access-cli.js +148 -146
  5. package/dist/access-cli.js.map +1 -1
  6. package/dist/access-extraction-force-flush.js +67 -66
  7. package/dist/access-http-briefing.js +68 -67
  8. package/dist/access-http-query.js +69 -68
  9. package/dist/access-http.js +91 -89
  10. package/dist/access-identity-continuity-surface.js +67 -66
  11. package/dist/access-lcm-surface.js +67 -66
  12. package/dist/access-mcp-frames.d.ts +29 -0
  13. package/dist/access-mcp-frames.d.ts.map +1 -0
  14. package/dist/access-mcp-frames.js +10 -0
  15. package/dist/access-mcp.d.ts +1 -1
  16. package/dist/access-mcp.d.ts.map +1 -1
  17. package/dist/access-mcp.js +82 -80
  18. package/dist/access-namespace-preflight.js +67 -66
  19. package/dist/access-observe-write-category.js +9 -9
  20. package/dist/access-observe-write-surface.d.ts.map +1 -1
  21. package/dist/access-observe-write-surface.js +67 -66
  22. package/dist/access-offline-manifest.js +3 -3
  23. package/dist/access-operations-batch.js +71 -70
  24. package/dist/access-operations.d.ts +1 -1
  25. package/dist/access-operations.js +78 -77
  26. package/dist/access-recall-concurrency.js +67 -66
  27. package/dist/access-recall-response.js +67 -66
  28. package/dist/access-recall-surface.js +67 -66
  29. package/dist/access-schema.js +4 -4
  30. package/dist/access-service.js +67 -66
  31. package/dist/access-surface-catalog.js +69 -68
  32. package/dist/access-surface-catalog.js.map +1 -1
  33. package/dist/active-recall.js +31 -31
  34. package/dist/{auto-sync-C7E6G7Y2.js → auto-sync-3AZW7MXI.js} +6 -6
  35. package/dist/briefing.js +25 -25
  36. package/dist/buffer-persistence.d.ts +8 -4
  37. package/dist/buffer-persistence.d.ts.map +1 -1
  38. package/dist/buffer-persistence.js +1 -1
  39. package/dist/buffer-turn-helpers.d.ts +5 -0
  40. package/dist/buffer-turn-helpers.d.ts.map +1 -1
  41. package/dist/buffer-turn-helpers.js +1 -1
  42. package/dist/buffer.d.ts +4 -1
  43. package/dist/buffer.d.ts.map +1 -1
  44. package/dist/buffer.js +9 -9
  45. package/dist/calibration.js +2 -2
  46. package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-GWVG7LGC.js} +2 -2
  47. package/dist/capsule-gunzip-KGBDGF7P.js +11 -0
  48. package/dist/{capsule-merge-XVTQJJ6R.js → capsule-merge-2IIXFXN5.js} +5 -11
  49. package/dist/capsule-merge-2IIXFXN5.js.map +1 -0
  50. package/dist/causal-behavior.js +2 -2
  51. package/dist/causal-chain.js +2 -2
  52. package/dist/causal-consolidation.js +32 -32
  53. package/dist/causal-retrieval.js +2 -2
  54. package/dist/causal-trajectory-graph.js +2 -2
  55. package/dist/causal-trajectory.js +1 -1
  56. package/dist/{chunk-T6T2RMWW.js → chunk-23B4HLWG.js} +5 -5
  57. package/dist/{chunk-LECSS7EE.js → chunk-2ASEDFOA.js} +2 -2
  58. package/dist/{chunk-TPX7XXY4.js → chunk-2JAT4S7N.js} +2 -2
  59. package/dist/{chunk-XRBHIR7Q.js → chunk-2URKYLMK.js} +2 -2
  60. package/dist/{chunk-IN4OFAHX.js → chunk-2XYDL2FG.js} +2 -2
  61. package/dist/{chunk-HQGATKG2.js → chunk-3KGCHTTK.js} +2 -2
  62. package/dist/{chunk-YAUHSNPB.js → chunk-3LHPTBWG.js} +2 -2
  63. package/dist/{chunk-7PMOCQOL.js → chunk-3ODZLCHC.js} +192 -63
  64. package/dist/chunk-3ODZLCHC.js.map +1 -0
  65. package/dist/{chunk-XT45WCKX.js → chunk-3VU2FDTU.js} +8 -8
  66. package/dist/{chunk-CIIHIAJ2.js → chunk-433EXTC4.js} +3 -3
  67. package/dist/{chunk-QZSIDSB2.js → chunk-44FQCC5D.js} +2 -2
  68. package/dist/{chunk-YUTT4ZTI.js → chunk-45VUHDV2.js} +2 -2
  69. package/dist/{chunk-54FDG7K7.js → chunk-4DPLCYEK.js} +2 -2
  70. package/dist/{chunk-KO3YBHOV.js → chunk-4IWEPQEV.js} +2 -2
  71. package/dist/{chunk-H7BZBSP6.js → chunk-52II7PB6.js} +4 -4
  72. package/dist/{chunk-K6RTQZA4.js → chunk-6DANGCMO.js} +2 -2
  73. package/dist/{chunk-2IW5PT7U.js → chunk-6KFFRMPQ.js} +2 -2
  74. package/dist/{chunk-MSIRVXQ3.js → chunk-73YVMZ7D.js} +4 -4
  75. package/dist/{chunk-A7BM2JTH.js → chunk-AJHNXIQU.js} +2 -2
  76. package/dist/{chunk-2D7BTSDW.js → chunk-ANZZLRUX.js} +2 -2
  77. package/dist/{chunk-YOEYL6CH.js → chunk-AP3TSV6S.js} +2 -2
  78. package/dist/{chunk-GQZSGXR6.js → chunk-BATPQNRG.js} +2 -2
  79. package/dist/{chunk-D5SSBCYY.js → chunk-BLGQUZFB.js} +2 -2
  80. package/dist/{chunk-BDN3TDGV.js → chunk-BLMTOIBK.js} +2 -2
  81. package/dist/{chunk-B74NPUHT.js → chunk-BMIM6ESC.js} +43 -43
  82. package/dist/chunk-BMIM6ESC.js.map +1 -0
  83. package/dist/{chunk-R45L4TV6.js → chunk-BUKK5SWA.js} +6 -6
  84. package/dist/{chunk-TFLPDNQV.js → chunk-CCU7URRP.js} +2 -2
  85. package/dist/{chunk-2XJZLSXE.js → chunk-CMRHXPLQ.js} +20 -20
  86. package/dist/{chunk-BK4FBHZ3.js → chunk-D6THW7PA.js} +3 -3
  87. package/dist/{chunk-BFBS7OFQ.js → chunk-DC55RIEZ.js} +4 -4
  88. package/dist/{chunk-VKDAJJQP.js → chunk-DI5ET2IE.js} +5 -5
  89. package/dist/{chunk-QZBTIYKD.js → chunk-DM4RRTN7.js} +3 -3
  90. package/dist/{chunk-S57QBPTA.js → chunk-DPPLNZ3A.js} +4 -6
  91. package/dist/chunk-DPPLNZ3A.js.map +1 -0
  92. package/dist/{chunk-EBOHFZI4.js → chunk-E5QEF3JO.js} +2 -2
  93. package/dist/{chunk-DD6OIFDG.js → chunk-E7V5AK7I.js} +3 -3
  94. package/dist/{chunk-WAD32CZG.js → chunk-ELWI2R6H.js} +26 -13
  95. package/dist/chunk-ELWI2R6H.js.map +1 -0
  96. package/dist/{chunk-BV2BRHD4.js → chunk-FHGWKODN.js} +2 -2
  97. package/dist/{chunk-HPFVZPRH.js → chunk-FK4WC6VK.js} +3 -3
  98. package/dist/{chunk-VLMBSGQF.js → chunk-FRM4UTDR.js} +6 -6
  99. package/dist/{chunk-LTDLJCMQ.js → chunk-FZPDRCOB.js} +2 -2
  100. package/dist/{chunk-ZJJFUEPO.js → chunk-GBOYOL5L.js} +2 -2
  101. package/dist/{chunk-YUTG35M4.js → chunk-GJVGFKOU.js} +2 -2
  102. package/dist/{chunk-77R7BQZ2.js → chunk-GKYIRTNX.js} +33 -11
  103. package/dist/{chunk-77R7BQZ2.js.map → chunk-GKYIRTNX.js.map} +1 -1
  104. package/dist/{chunk-K36RMINQ.js → chunk-GOZXQNIM.js} +3 -3
  105. package/dist/{chunk-HWHNQVRV.js → chunk-GYNRNKMW.js} +2 -2
  106. package/dist/{chunk-LU66I56Q.js → chunk-H34INI3P.js} +29 -3
  107. package/dist/chunk-H34INI3P.js.map +1 -0
  108. package/dist/{chunk-AYTDCMEL.js → chunk-H4D5YURJ.js} +80 -94
  109. package/dist/chunk-H4D5YURJ.js.map +1 -0
  110. package/dist/{chunk-6LCWKS62.js → chunk-HVFX2N2G.js} +60 -59
  111. package/dist/chunk-HVFX2N2G.js.map +1 -0
  112. package/dist/chunk-IGLJNHOX.js +62 -0
  113. package/dist/chunk-IGLJNHOX.js.map +1 -0
  114. package/dist/{chunk-KFLD7ZZG.js → chunk-IUKYFTGW.js} +3 -3
  115. package/dist/{chunk-YK7GOPIE.js → chunk-JFH6JAGY.js} +6 -4
  116. package/dist/chunk-JFH6JAGY.js.map +1 -0
  117. package/dist/{chunk-BNQJKWWZ.js → chunk-K3FH3LAQ.js} +4 -4
  118. package/dist/{chunk-FJ2VJTGA.js → chunk-KHZVAISH.js} +2 -2
  119. package/dist/{chunk-WHQXWFH7.js → chunk-LT3CMO65.js} +2 -2
  120. package/dist/{chunk-NUSAAN75.js → chunk-MHSBOEH7.js} +2 -2
  121. package/dist/{chunk-KJCL2FZO.js → chunk-MNYQVYJ4.js} +2 -2
  122. package/dist/{chunk-RZH5RVJC.js → chunk-MTTYIXSU.js} +2 -2
  123. package/dist/{chunk-FVRTCYZ3.js → chunk-MVOJDLXS.js} +2 -2
  124. package/dist/{chunk-KESJ5XX3.js → chunk-MYCCO6AA.js} +2 -2
  125. package/dist/{chunk-66JOLMWS.js → chunk-MZCGHPIJ.js} +2 -2
  126. package/dist/{chunk-B4ZU34JQ.js → chunk-N6II66E5.js} +3 -3
  127. package/dist/{chunk-BK7AJUWB.js → chunk-NIV7RPWQ.js} +6 -6
  128. package/dist/{chunk-TLHF75OR.js → chunk-O55AGDTI.js} +10 -10
  129. package/dist/{chunk-GGJFRVRD.js → chunk-OMYRPMQC.js} +2 -2
  130. package/dist/{chunk-SVCHO337.js → chunk-ONN2E5QD.js} +32 -23
  131. package/dist/chunk-ONN2E5QD.js.map +1 -0
  132. package/dist/{chunk-XHGYZRVW.js → chunk-OSTFDWZJ.js} +4 -4
  133. package/dist/{chunk-BXLOS5AJ.js → chunk-OWHERGF2.js} +2 -2
  134. package/dist/{chunk-WC475JOG.js → chunk-P225W4RQ.js} +6 -6
  135. package/dist/{chunk-TFA6HPOA.js → chunk-QCP75JGO.js} +5 -5
  136. package/dist/{chunk-JRVMCZE3.js → chunk-QEYTRFR3.js} +2 -2
  137. package/dist/chunk-QV2VZKD5.js +31 -0
  138. package/dist/chunk-QV2VZKD5.js.map +1 -0
  139. package/dist/{chunk-IZJQNDGI.js → chunk-R6HMAIKM.js} +2 -2
  140. package/dist/{chunk-VUROWXFL.js → chunk-RNGDKFY2.js} +2 -2
  141. package/dist/{chunk-FF6N7BXC.js → chunk-S45INSV3.js} +4 -4
  142. package/dist/{chunk-2RUTN7PR.js → chunk-S7GJNA3K.js} +2 -2
  143. package/dist/{chunk-XYP5WBDO.js → chunk-SGHV6LZ7.js} +13 -13
  144. package/dist/chunk-SGHV6LZ7.js.map +1 -0
  145. package/dist/{chunk-RJWL3RHB.js → chunk-TFEHSPGQ.js} +2 -2
  146. package/dist/{chunk-T77AX6DG.js → chunk-TQVECGUQ.js} +4 -4
  147. package/dist/{chunk-OQSSQOKQ.js → chunk-TV65NR7L.js} +2 -2
  148. package/dist/{chunk-KQUSP6LB.js → chunk-UDKWFDV2.js} +1 -1
  149. package/dist/chunk-UDKWFDV2.js.map +1 -0
  150. package/dist/{chunk-HQPFACXO.js → chunk-UH3FPX3L.js} +2 -2
  151. package/dist/{chunk-4EACCIPO.js → chunk-UHPHH74F.js} +2 -2
  152. package/dist/{chunk-DQEMWVMT.js → chunk-UVYI6VIX.js} +1 -1
  153. package/dist/{chunk-6QYPL6NI.js → chunk-V45TEVDA.js} +3 -3
  154. package/dist/{chunk-GCAQ3VUJ.js → chunk-VCVEMQJK.js} +2 -2
  155. package/dist/{chunk-6L63IN3M.js → chunk-VEFGHRKV.js} +1 -1
  156. package/dist/{chunk-E33UJHY3.js → chunk-WFDWLWDK.js} +2 -2
  157. package/dist/{chunk-4KLQI3L2.js → chunk-WLNWFHX3.js} +1 -1
  158. package/dist/chunk-WLNWFHX3.js.map +1 -0
  159. package/dist/{chunk-KQLBXUUQ.js → chunk-WYG5UNDY.js} +2 -2
  160. package/dist/{chunk-MPGLM2VU.js → chunk-X7REO4CH.js} +2 -2
  161. package/dist/{chunk-MPDLLLOG.js → chunk-XO23OKMK.js} +9 -5
  162. package/dist/chunk-XO23OKMK.js.map +1 -0
  163. package/dist/{chunk-Z3DDQXM4.js → chunk-XSFQN7TP.js} +35 -36
  164. package/dist/chunk-XSFQN7TP.js.map +1 -0
  165. package/dist/{chunk-FZVROZKC.js → chunk-XVZA6VXC.js} +4 -4
  166. package/dist/{chunk-WV254W4V.js → chunk-Y3IYKNBY.js} +2 -2
  167. package/dist/{chunk-FUOAIJKQ.js → chunk-Y43X3E24.js} +2 -2
  168. package/dist/{chunk-3T3VHXUH.js → chunk-YAAKVTZA.js} +2 -2
  169. package/dist/{chunk-VPEIWMUT.js → chunk-YLTU2DC4.js} +2 -2
  170. package/dist/{chunk-65SKM4BF.js → chunk-YNBMBL4C.js} +2 -2
  171. package/dist/{chunk-PJYK7HH2.js → chunk-ZWTHVUT5.js} +2 -2
  172. package/dist/cli.js +110 -108
  173. package/dist/coding/export-okf-codegraph.js +25 -25
  174. package/dist/coding/pre-action-gate.js +2 -2
  175. package/dist/compounding/engine.js +27 -27
  176. package/dist/config.js +28 -28
  177. package/dist/connectors/codex-materialize-runner.js +25 -25
  178. package/dist/connectors/index.js +25 -25
  179. package/dist/contradiction/index.js +4 -4
  180. package/dist/convergence-refresh.js +27 -27
  181. package/dist/conversation-index/backend.js +2 -2
  182. package/dist/corpus-watermark.js +27 -27
  183. package/dist/deep-recall-http-glue.js +5 -5
  184. package/dist/entity-mention-index-cache.d.ts.map +1 -1
  185. package/dist/entity-mention-index-cache.js +2 -1
  186. package/dist/entity-retrieval.js +27 -26
  187. package/dist/event-order-recall.js +2 -2
  188. package/dist/explicit-capture.js +5 -5
  189. package/dist/external-wiki-access.js +68 -67
  190. package/dist/extraction-evidence-class.js +2 -2
  191. package/dist/extraction-quote-grounding.d.ts.map +1 -1
  192. package/dist/extraction-quote-grounding.js +1 -1
  193. package/dist/extraction-source-grounding-rules.js +2 -2
  194. package/dist/extraction-source-grounding.js +5 -5
  195. package/dist/extraction-span-materialize.js +2 -2
  196. package/dist/extraction.js +40 -40
  197. package/dist/{first-start-migration-QVD22WWS.js → first-start-migration-A6PHIBUQ.js} +4 -4
  198. package/dist/{graph-edge-decay-CXTNJ7IQ.js → graph-edge-decay-EKWXRBWF.js} +5 -5
  199. package/dist/graph-edge-decay-EKWXRBWF.js.map +1 -0
  200. package/dist/graph-jsonl.js +3 -3
  201. package/dist/graph-snapshot.js +3 -3
  202. package/dist/graph.js +2 -2
  203. package/dist/harmonic-retrieval.js +25 -25
  204. package/dist/index.js +205 -203
  205. package/dist/lcm/engine.js +2 -2
  206. package/dist/lcm/index.js +2 -2
  207. package/dist/local-llm.js +2 -2
  208. package/dist/location/index.js +28 -28
  209. package/dist/maintenance/memory-governance.js +25 -25
  210. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +25 -25
  211. package/dist/maintenance/rebuild-memory-projection-runner.js +27 -27
  212. package/dist/maintenance/rebuild-memory-projection.js +26 -26
  213. package/dist/memory-browse-operations.js +68 -67
  214. package/dist/memory-subject.js +2 -2
  215. package/dist/namespaces/migrate.js +26 -26
  216. package/dist/namespaces/search.d.ts +8 -0
  217. package/dist/namespaces/search.d.ts.map +1 -1
  218. package/dist/namespaces/search.js +10 -6
  219. package/dist/namespaces/storage.js +25 -25
  220. package/dist/operator-doctor-corpus.js +28 -28
  221. package/dist/operator-toolkit.js +39 -39
  222. package/dist/orchestration/backlog-scheduler.d.ts +3 -2
  223. package/dist/orchestration/backlog-scheduler.d.ts.map +1 -1
  224. package/dist/orchestration/backlog-scheduler.js +159 -157
  225. package/dist/orchestration/backlog-scheduler.js.map +1 -1
  226. package/dist/orchestration/buffer-drain-runner.d.ts +6 -1
  227. package/dist/orchestration/buffer-drain-runner.d.ts.map +1 -1
  228. package/dist/orchestration/buffer-drain-runner.js +149 -147
  229. package/dist/orchestration/extraction-persist.d.ts.map +1 -1
  230. package/dist/orchestration/fact-dedup-window.d.ts +1 -4
  231. package/dist/orchestration/fact-dedup-window.d.ts.map +1 -1
  232. package/dist/orchestration/maintenance.js +39 -39
  233. package/dist/orchestrator.js +148 -146
  234. package/dist/provenance.js +2 -2
  235. package/dist/recall-navigation-operations.js +68 -67
  236. package/dist/recall-navigation.js +67 -66
  237. package/dist/reconcile/manifest.js +2 -2
  238. package/dist/{resolution-BNWE5Y25.js → resolution-23ZBDM6A.js} +5 -5
  239. package/dist/resolution-23ZBDM6A.js.map +1 -0
  240. package/dist/resume-bundles.js +29 -29
  241. package/dist/salvage-envelope.js +4 -4
  242. package/dist/search/factory.js +5 -5
  243. package/dist/search/index.js +9 -9
  244. package/dist/semantic-consolidation.js +26 -26
  245. package/dist/semantic-rule-promotion.js +25 -25
  246. package/dist/semantic-rule-verifier.js +25 -25
  247. package/dist/source-agent-qualifier.js +31 -31
  248. package/dist/standup/build.js +25 -25
  249. package/dist/storage/buffer-drain-claims.d.ts +18 -6
  250. package/dist/storage/buffer-drain-claims.d.ts.map +1 -1
  251. package/dist/storage/buffer-drain-claims.js +2 -2
  252. package/dist/storage/buffer-session-files.js +2 -2
  253. package/dist/storage/content-hash-index.d.ts +8 -0
  254. package/dist/storage/content-hash-index.d.ts.map +1 -1
  255. package/dist/storage.d.ts +10 -1
  256. package/dist/storage.d.ts.map +1 -1
  257. package/dist/storage.js +24 -24
  258. package/dist/subject-config.js +3 -3
  259. package/dist/summarizer.js +3 -3
  260. package/dist/support-passport/index.js +70 -69
  261. package/dist/transfer/autodetect.js +1 -1
  262. package/dist/transfer/backup.js +2 -2
  263. package/dist/transfer/capsule-export.js +3 -3
  264. package/dist/transfer/capsule-gunzip.d.ts +14 -0
  265. package/dist/transfer/capsule-gunzip.d.ts.map +1 -0
  266. package/dist/transfer/capsule-import.d.ts.map +1 -1
  267. package/dist/transfer/capsule-import.js +3 -2
  268. package/dist/transfer/capsule-merge.d.ts.map +1 -1
  269. package/dist/transfer/export-okf.js +25 -25
  270. package/dist/verified-recall.js +25 -25
  271. package/dist/who-knows-cli.js +26 -26
  272. package/dist/who-knows.js +25 -25
  273. package/dist/write-envelope.js +3 -3
  274. package/package.json +2 -2
  275. package/src/access-mcp-correction-tools.test.ts +45 -0
  276. package/src/access-mcp-frames.test.ts +47 -0
  277. package/src/access-mcp-frames.ts +74 -0
  278. package/src/access-mcp.test.ts +146 -0
  279. package/src/access-mcp.ts +30 -30
  280. package/src/access-observe-write-surface.ts +4 -4
  281. package/src/backlog-scheduler.test.ts +443 -3
  282. package/src/buffer-persistence.ts +15 -6
  283. package/src/buffer-turn-helpers.ts +6 -0
  284. package/src/buffer.ts +6 -6
  285. package/src/cli.ts +4 -4
  286. package/src/compounding/weekly-evidence.test.ts +237 -0
  287. package/src/entity-mention-index-cache.ts +1 -6
  288. package/src/extraction-quote-grounding.test.ts +49 -0
  289. package/src/extraction-quote-grounding.ts +50 -12
  290. package/src/fact-dedup-window.test.ts +103 -20
  291. package/src/maintenance/rebuild-memory-projection-runner.test.ts +90 -0
  292. package/src/namespaces/search.test.ts +339 -0
  293. package/src/namespaces/search.ts +54 -1
  294. package/src/orchestration/backlog-scheduler.ts +13 -12
  295. package/src/orchestration/buffer-drain-runner.ts +40 -16
  296. package/src/orchestration/extraction-persist.ts +2 -10
  297. package/src/orchestration/fact-dedup-window.ts +5 -12
  298. package/src/orchestration/full-corpus-heap-guard.test.ts +52 -0
  299. package/src/projection-rebuild-config.test.ts +79 -0
  300. package/src/storage/buffer-drain-claims.test.ts +330 -6
  301. package/src/storage/buffer-drain-claims.ts +226 -80
  302. package/src/storage/buffer-session-files.ts +2 -2
  303. package/src/storage/content-hash-index.ts +9 -0
  304. package/src/storage/entity-store-symlink.test.ts +44 -0
  305. package/src/storage.ts +15 -0
  306. package/src/transfer/capsule-gunzip.ts +39 -0
  307. package/src/transfer/capsule-import.test.ts +73 -0
  308. package/src/transfer/capsule-import.ts +2 -2
  309. package/src/transfer/capsule-merge.test.ts +34 -0
  310. package/src/transfer/capsule-merge.ts +2 -10
  311. package/src/utils/malformed-entity-record.test.ts +69 -0
  312. package/dist/capsule-merge-XVTQJJ6R.js.map +0 -1
  313. package/dist/chunk-4KLQI3L2.js.map +0 -1
  314. package/dist/chunk-6LCWKS62.js.map +0 -1
  315. package/dist/chunk-7PMOCQOL.js.map +0 -1
  316. package/dist/chunk-AYTDCMEL.js.map +0 -1
  317. package/dist/chunk-B74NPUHT.js.map +0 -1
  318. package/dist/chunk-KQUSP6LB.js.map +0 -1
  319. package/dist/chunk-LU66I56Q.js.map +0 -1
  320. package/dist/chunk-MPDLLLOG.js.map +0 -1
  321. package/dist/chunk-S57QBPTA.js.map +0 -1
  322. package/dist/chunk-SVCHO337.js.map +0 -1
  323. package/dist/chunk-WAD32CZG.js.map +0 -1
  324. package/dist/chunk-XYP5WBDO.js.map +0 -1
  325. package/dist/chunk-YK7GOPIE.js.map +0 -1
  326. package/dist/chunk-Z3DDQXM4.js.map +0 -1
  327. /package/dist/{capsule-crypto-YO5QJ6L3.js.map → access-mcp-frames.js.map} +0 -0
  328. /package/dist/{auto-sync-C7E6G7Y2.js.map → auto-sync-3AZW7MXI.js.map} +0 -0
  329. /package/dist/{graph-edge-decay-CXTNJ7IQ.js.map → capsule-crypto-GWVG7LGC.js.map} +0 -0
  330. /package/dist/{resolution-BNWE5Y25.js.map → capsule-gunzip-KGBDGF7P.js.map} +0 -0
  331. /package/dist/{chunk-T6T2RMWW.js.map → chunk-23B4HLWG.js.map} +0 -0
  332. /package/dist/{chunk-LECSS7EE.js.map → chunk-2ASEDFOA.js.map} +0 -0
  333. /package/dist/{chunk-TPX7XXY4.js.map → chunk-2JAT4S7N.js.map} +0 -0
  334. /package/dist/{chunk-XRBHIR7Q.js.map → chunk-2URKYLMK.js.map} +0 -0
  335. /package/dist/{chunk-IN4OFAHX.js.map → chunk-2XYDL2FG.js.map} +0 -0
  336. /package/dist/{chunk-HQGATKG2.js.map → chunk-3KGCHTTK.js.map} +0 -0
  337. /package/dist/{chunk-YAUHSNPB.js.map → chunk-3LHPTBWG.js.map} +0 -0
  338. /package/dist/{chunk-XT45WCKX.js.map → chunk-3VU2FDTU.js.map} +0 -0
  339. /package/dist/{chunk-CIIHIAJ2.js.map → chunk-433EXTC4.js.map} +0 -0
  340. /package/dist/{chunk-QZSIDSB2.js.map → chunk-44FQCC5D.js.map} +0 -0
  341. /package/dist/{chunk-YUTT4ZTI.js.map → chunk-45VUHDV2.js.map} +0 -0
  342. /package/dist/{chunk-54FDG7K7.js.map → chunk-4DPLCYEK.js.map} +0 -0
  343. /package/dist/{chunk-KO3YBHOV.js.map → chunk-4IWEPQEV.js.map} +0 -0
  344. /package/dist/{chunk-H7BZBSP6.js.map → chunk-52II7PB6.js.map} +0 -0
  345. /package/dist/{chunk-K6RTQZA4.js.map → chunk-6DANGCMO.js.map} +0 -0
  346. /package/dist/{chunk-2IW5PT7U.js.map → chunk-6KFFRMPQ.js.map} +0 -0
  347. /package/dist/{chunk-MSIRVXQ3.js.map → chunk-73YVMZ7D.js.map} +0 -0
  348. /package/dist/{chunk-A7BM2JTH.js.map → chunk-AJHNXIQU.js.map} +0 -0
  349. /package/dist/{chunk-2D7BTSDW.js.map → chunk-ANZZLRUX.js.map} +0 -0
  350. /package/dist/{chunk-YOEYL6CH.js.map → chunk-AP3TSV6S.js.map} +0 -0
  351. /package/dist/{chunk-GQZSGXR6.js.map → chunk-BATPQNRG.js.map} +0 -0
  352. /package/dist/{chunk-D5SSBCYY.js.map → chunk-BLGQUZFB.js.map} +0 -0
  353. /package/dist/{chunk-BDN3TDGV.js.map → chunk-BLMTOIBK.js.map} +0 -0
  354. /package/dist/{chunk-R45L4TV6.js.map → chunk-BUKK5SWA.js.map} +0 -0
  355. /package/dist/{chunk-TFLPDNQV.js.map → chunk-CCU7URRP.js.map} +0 -0
  356. /package/dist/{chunk-2XJZLSXE.js.map → chunk-CMRHXPLQ.js.map} +0 -0
  357. /package/dist/{chunk-BK4FBHZ3.js.map → chunk-D6THW7PA.js.map} +0 -0
  358. /package/dist/{chunk-BFBS7OFQ.js.map → chunk-DC55RIEZ.js.map} +0 -0
  359. /package/dist/{chunk-VKDAJJQP.js.map → chunk-DI5ET2IE.js.map} +0 -0
  360. /package/dist/{chunk-QZBTIYKD.js.map → chunk-DM4RRTN7.js.map} +0 -0
  361. /package/dist/{chunk-EBOHFZI4.js.map → chunk-E5QEF3JO.js.map} +0 -0
  362. /package/dist/{chunk-DD6OIFDG.js.map → chunk-E7V5AK7I.js.map} +0 -0
  363. /package/dist/{chunk-BV2BRHD4.js.map → chunk-FHGWKODN.js.map} +0 -0
  364. /package/dist/{chunk-HPFVZPRH.js.map → chunk-FK4WC6VK.js.map} +0 -0
  365. /package/dist/{chunk-VLMBSGQF.js.map → chunk-FRM4UTDR.js.map} +0 -0
  366. /package/dist/{chunk-LTDLJCMQ.js.map → chunk-FZPDRCOB.js.map} +0 -0
  367. /package/dist/{chunk-ZJJFUEPO.js.map → chunk-GBOYOL5L.js.map} +0 -0
  368. /package/dist/{chunk-YUTG35M4.js.map → chunk-GJVGFKOU.js.map} +0 -0
  369. /package/dist/{chunk-K36RMINQ.js.map → chunk-GOZXQNIM.js.map} +0 -0
  370. /package/dist/{chunk-HWHNQVRV.js.map → chunk-GYNRNKMW.js.map} +0 -0
  371. /package/dist/{chunk-KFLD7ZZG.js.map → chunk-IUKYFTGW.js.map} +0 -0
  372. /package/dist/{chunk-BNQJKWWZ.js.map → chunk-K3FH3LAQ.js.map} +0 -0
  373. /package/dist/{chunk-FJ2VJTGA.js.map → chunk-KHZVAISH.js.map} +0 -0
  374. /package/dist/{chunk-WHQXWFH7.js.map → chunk-LT3CMO65.js.map} +0 -0
  375. /package/dist/{chunk-NUSAAN75.js.map → chunk-MHSBOEH7.js.map} +0 -0
  376. /package/dist/{chunk-KJCL2FZO.js.map → chunk-MNYQVYJ4.js.map} +0 -0
  377. /package/dist/{chunk-RZH5RVJC.js.map → chunk-MTTYIXSU.js.map} +0 -0
  378. /package/dist/{chunk-FVRTCYZ3.js.map → chunk-MVOJDLXS.js.map} +0 -0
  379. /package/dist/{chunk-KESJ5XX3.js.map → chunk-MYCCO6AA.js.map} +0 -0
  380. /package/dist/{chunk-66JOLMWS.js.map → chunk-MZCGHPIJ.js.map} +0 -0
  381. /package/dist/{chunk-B4ZU34JQ.js.map → chunk-N6II66E5.js.map} +0 -0
  382. /package/dist/{chunk-BK7AJUWB.js.map → chunk-NIV7RPWQ.js.map} +0 -0
  383. /package/dist/{chunk-TLHF75OR.js.map → chunk-O55AGDTI.js.map} +0 -0
  384. /package/dist/{chunk-GGJFRVRD.js.map → chunk-OMYRPMQC.js.map} +0 -0
  385. /package/dist/{chunk-XHGYZRVW.js.map → chunk-OSTFDWZJ.js.map} +0 -0
  386. /package/dist/{chunk-BXLOS5AJ.js.map → chunk-OWHERGF2.js.map} +0 -0
  387. /package/dist/{chunk-WC475JOG.js.map → chunk-P225W4RQ.js.map} +0 -0
  388. /package/dist/{chunk-TFA6HPOA.js.map → chunk-QCP75JGO.js.map} +0 -0
  389. /package/dist/{chunk-JRVMCZE3.js.map → chunk-QEYTRFR3.js.map} +0 -0
  390. /package/dist/{chunk-IZJQNDGI.js.map → chunk-R6HMAIKM.js.map} +0 -0
  391. /package/dist/{chunk-VUROWXFL.js.map → chunk-RNGDKFY2.js.map} +0 -0
  392. /package/dist/{chunk-FF6N7BXC.js.map → chunk-S45INSV3.js.map} +0 -0
  393. /package/dist/{chunk-2RUTN7PR.js.map → chunk-S7GJNA3K.js.map} +0 -0
  394. /package/dist/{chunk-RJWL3RHB.js.map → chunk-TFEHSPGQ.js.map} +0 -0
  395. /package/dist/{chunk-T77AX6DG.js.map → chunk-TQVECGUQ.js.map} +0 -0
  396. /package/dist/{chunk-OQSSQOKQ.js.map → chunk-TV65NR7L.js.map} +0 -0
  397. /package/dist/{chunk-HQPFACXO.js.map → chunk-UH3FPX3L.js.map} +0 -0
  398. /package/dist/{chunk-4EACCIPO.js.map → chunk-UHPHH74F.js.map} +0 -0
  399. /package/dist/{chunk-DQEMWVMT.js.map → chunk-UVYI6VIX.js.map} +0 -0
  400. /package/dist/{chunk-6QYPL6NI.js.map → chunk-V45TEVDA.js.map} +0 -0
  401. /package/dist/{chunk-GCAQ3VUJ.js.map → chunk-VCVEMQJK.js.map} +0 -0
  402. /package/dist/{chunk-6L63IN3M.js.map → chunk-VEFGHRKV.js.map} +0 -0
  403. /package/dist/{chunk-E33UJHY3.js.map → chunk-WFDWLWDK.js.map} +0 -0
  404. /package/dist/{chunk-KQLBXUUQ.js.map → chunk-WYG5UNDY.js.map} +0 -0
  405. /package/dist/{chunk-MPGLM2VU.js.map → chunk-X7REO4CH.js.map} +0 -0
  406. /package/dist/{chunk-FZVROZKC.js.map → chunk-XVZA6VXC.js.map} +0 -0
  407. /package/dist/{chunk-WV254W4V.js.map → chunk-Y3IYKNBY.js.map} +0 -0
  408. /package/dist/{chunk-FUOAIJKQ.js.map → chunk-Y43X3E24.js.map} +0 -0
  409. /package/dist/{chunk-3T3VHXUH.js.map → chunk-YAAKVTZA.js.map} +0 -0
  410. /package/dist/{chunk-VPEIWMUT.js.map → chunk-YLTU2DC4.js.map} +0 -0
  411. /package/dist/{chunk-65SKM4BF.js.map → chunk-YNBMBL4C.js.map} +0 -0
  412. /package/dist/{chunk-PJYK7HH2.js.map → chunk-ZWTHVUT5.js.map} +0 -0
  413. /package/dist/{first-start-migration-QVD22WWS.js.map → first-start-migration-A6PHIBUQ.js.map} +0 -0
@@ -10,12 +10,16 @@ import assert from "node:assert/strict";
10
10
  import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
11
11
  import os from "node:os";
12
12
  import path from "node:path";
13
+ import { PassThrough } from "node:stream";
13
14
  import test from "node:test";
14
15
 
15
16
  import { EngramMcpServer } from "./access-mcp.js";
17
+ import { MCP_STDIO_MAX_FRAME_BYTES } from "./access-mcp-frames.js";
18
+ import { EngramAccessForbiddenError } from "./access-errors.js";
16
19
  import { tokenCapabilityStore } from "./access-token-capabilities.js";
17
20
  import { EngramAccessInputError, type EngramAccessService } from "./access-service.js";
18
21
  import { parseConfig } from "./config.js";
22
+ import { initLogger, resetLogger } from "./logger.js";
19
23
  import { readPair, writePair } from "./contradiction/contradiction-review.js";
20
24
  import type { StorageManager } from "./storage.js";
21
25
 
@@ -1451,3 +1455,145 @@ test("MCP external_wiki_search rejects an empty query before service dispatch",
1451
1455
  assert.equal(readMcpResult(response).isError, true);
1452
1456
  assert.equal(configRead, false);
1453
1457
  });
1458
+
1459
+ // ===========================================================================
1460
+ // Issue #3225 C5 — tools/call catch-all must not leak unexpected Error.message
1461
+ // (paths from fs/backend). Intended typed access errors stay readable.
1462
+ // ===========================================================================
1463
+
1464
+ function serviceWithRecallThrow(error: Error): EngramAccessService {
1465
+ const service = makeMockService();
1466
+ service.recall = async () => {
1467
+ throw error;
1468
+ };
1469
+ return service;
1470
+ }
1471
+
1472
+ test("MCP tools/call hides unexpected Error.message paths behind internal error", async () => {
1473
+ const secretPath = "/home/secret/vault/token.pem";
1474
+ const service = serviceWithRecallThrow(
1475
+ new Error(`ENOENT: no such file or directory, open '${secretPath}'`),
1476
+ );
1477
+
1478
+ const logLines: string[] = [];
1479
+ initLogger(
1480
+ {
1481
+ info() {},
1482
+ warn() {},
1483
+ error(msg: string) {
1484
+ logLines.push(msg);
1485
+ },
1486
+ },
1487
+ false,
1488
+ { timestamps: false },
1489
+ );
1490
+ try {
1491
+ const server = new EngramMcpServer(service);
1492
+ const outcome = readCallToolOutcome(
1493
+ await server.handleRequest(makeToolRequest("engram.recall", { query: "anything" })),
1494
+ );
1495
+ assert.equal(outcome.isError, true);
1496
+ assert.equal(outcome.text, "internal error");
1497
+ assert.equal(outcome.text.includes(secretPath), false);
1498
+ assert.ok(
1499
+ logLines.some((line) => line.includes(secretPath)),
1500
+ "server log must retain the unexpected detail",
1501
+ );
1502
+ } finally {
1503
+ resetLogger();
1504
+ }
1505
+ });
1506
+
1507
+ test("MCP tools/call keeps intended EngramAccessInputError and ForbiddenError messages", async () => {
1508
+ const inputOutcome = readCallToolOutcome(
1509
+ await new EngramMcpServer(serviceWithRecallThrow(new EngramAccessInputError("memory not found: mem-42"))).handleRequest(
1510
+ makeToolRequest("engram.recall", { query: "anything" }),
1511
+ ),
1512
+ );
1513
+ assert.equal(inputOutcome.isError, true);
1514
+ assert.equal(inputOutcome.text, "memory not found: mem-42");
1515
+
1516
+ const forbiddenOutcome = readCallToolOutcome(
1517
+ await new EngramMcpServer(
1518
+ serviceWithRecallThrow(new EngramAccessForbiddenError("token is not permitted to call operation: recall")),
1519
+ ).handleRequest(makeToolRequest("engram.recall", { query: "anything" })),
1520
+ );
1521
+ assert.equal(forbiddenOutcome.isError, true);
1522
+ assert.equal(forbiddenOutcome.text, "token is not permitted to call operation: recall");
1523
+ });
1524
+
1525
+ // ===========================================================================
1526
+ // Issue #3225 N1 — stdio framing is bounded, refuses an oversized frame,
1527
+ // and keeps answering the frames that follow it.
1528
+ // ===========================================================================
1529
+
1530
+ type StdioMessage = { id?: number | null; result?: object; error?: { message: string } };
1531
+ type StdioRequest = { jsonrpc: "2.0"; id: number; method: string };
1532
+
1533
+ function stdioFrame(payload: StdioRequest): string {
1534
+ const body = JSON.stringify(payload);
1535
+ return `Content-Length: ${Buffer.byteLength(body, "utf-8")}\r\n\r\n${body}`;
1536
+ }
1537
+
1538
+ function readStdioMessages(raw: string): StdioMessage[] {
1539
+ const messages: StdioMessage[] = [];
1540
+ let rest = raw;
1541
+ while (rest.length > 0) {
1542
+ const headerEnd = rest.indexOf("\r\n\r\n");
1543
+ assert.ok(headerEnd >= 0, "server output must be Content-Length framed");
1544
+ const length = Number.parseInt(rest.slice(0, headerEnd).split(":")[1] ?? "", 10);
1545
+ const message: StdioMessage = JSON.parse(rest.slice(headerEnd + 4, headerEnd + 4 + length));
1546
+ messages.push(message);
1547
+ rest = rest.slice(headerEnd + 4 + length);
1548
+ }
1549
+ return messages;
1550
+ }
1551
+
1552
+ /** Feeds each chunk in its own tick so the server sees separate data events. */
1553
+ async function runStdioChunks(chunks: string[]): Promise<StdioMessage[]> {
1554
+ const input = new PassThrough();
1555
+ const output = new PassThrough();
1556
+ output.setEncoding("utf8");
1557
+ let raw = "";
1558
+ output.on("data", (chunk: string) => {
1559
+ raw += chunk;
1560
+ });
1561
+ const running = new EngramMcpServer(makeMockService()).runStdio(input, output);
1562
+ for (const chunk of chunks) {
1563
+ input.write(chunk);
1564
+ await new Promise<void>((resolve) => setImmediate(resolve));
1565
+ }
1566
+ input.end();
1567
+ await running;
1568
+ return readStdioMessages(raw);
1569
+ }
1570
+
1571
+ const stdioPing = (id: number) => stdioFrame({ jsonrpc: "2.0", id, method: "ping" });
1572
+
1573
+ test("MCP stdio refuses an oversized Content-Length, discards its body, and answers the next frame", async () => {
1574
+ const declared = MCP_STDIO_MAX_FRAME_BYTES + 1;
1575
+ const messages = await runStdioChunks([
1576
+ `Content-Length: ${declared}\r\n\r\n`,
1577
+ "x".repeat(1000),
1578
+ "x".repeat(declared - 1000),
1579
+ stdioPing(7),
1580
+ ]);
1581
+ assert.equal(messages.length, 2);
1582
+ assert.match(messages[0]?.error?.message ?? "", /frame too large/);
1583
+ assert.equal(messages[1]?.id, 7);
1584
+ assert.ok(messages[1]?.result, "the frame after the refused one is answered normally");
1585
+ });
1586
+
1587
+ test("MCP stdio refuses a header that never terminates and answers the next frame", async () => {
1588
+ const messages = await runStdioChunks(["A".repeat(MCP_STDIO_MAX_FRAME_BYTES + 1), stdioPing(8)]);
1589
+ assert.equal(messages.length, 2);
1590
+ assert.match(messages[0]?.error?.message ?? "", /frame too large/);
1591
+ assert.equal(messages[1]?.id, 8);
1592
+ });
1593
+
1594
+ test("MCP stdio reassembles a frame split inside its header and inside its body", async () => {
1595
+ const frame = stdioPing(9);
1596
+ const messages = await runStdioChunks([frame.slice(0, 6), frame.slice(6, frame.length - 4), frame.slice(frame.length - 4)]);
1597
+ assert.equal(messages.length, 1);
1598
+ assert.equal(messages[0]?.id, 9);
1599
+ });
package/src/access-mcp.ts CHANGED
@@ -30,7 +30,9 @@ import {
30
30
  validateRequest,
31
31
  } from "./access-schema.js";
32
32
  import { EngramAccessInputError, type EngramAccessRecallResponse, type EngramAccessService } from "./access-service.js";
33
- import { unknownToolError } from "./access-errors.js";
33
+ import { EngramAccessForbiddenError, unknownToolError } from "./access-errors.js";
34
+ import { log } from "./logger.js";
35
+ import { McpFrameReader } from "./access-mcp-frames.js";
34
36
  import "./access-operations.js";
35
37
  import { validateBriefingFormat } from "./briefing.js";
36
38
  import { processChatMessage } from "./chat/chat-factory.js";
@@ -88,6 +90,19 @@ function throwMcpAbort(signal: AbortSignal | undefined, message: string): void {
88
90
  throw abortError(message);
89
91
  }
90
92
 
93
+ /**
94
+ * Map tools/call failures to a client-safe message. Unexpected backend/fs
95
+ * errors become a stable generic string; detail stays in the server log.
96
+ * Intended EngramAccessInputError / EngramAccessForbiddenError stay readable.
97
+ */
98
+ function mcpToolErrorMessage(err: Error): string {
99
+ if (err instanceof EngramAccessInputError || err instanceof EngramAccessForbiddenError) {
100
+ return err.message;
101
+ }
102
+ log.error("engram MCP tools/call internal error", err);
103
+ return "internal error";
104
+ }
105
+
91
106
  type McpRequestOptions = {
92
107
  principalOverride?: string;
93
108
  namespaceOverride?: string;
@@ -406,7 +421,7 @@ function parseMcpRequest<N extends SchemaName>(schemaName: N, args: Record<strin
406
421
  function optionalNonEmptyString(value: unknown, label: string): string | undefined {
407
422
  if (value === undefined || value === null || value === "") return undefined;
408
423
  if (typeof value !== "string") {
409
- throw new Error(`${label} expects a string; got ${JSON.stringify(value)}`);
424
+ throw new EngramAccessInputError(`${label} expects a string; got ${JSON.stringify(value)}`);
410
425
  }
411
426
  return value;
412
427
  }
@@ -420,11 +435,11 @@ function optionalNonEmptyString(value: unknown, label: string): string | undefin
420
435
  function optionalPositiveInteger(value: unknown, label: string): number | undefined {
421
436
  if (value === undefined || value === null || value === "") return undefined;
422
437
  if (typeof value !== "number" && typeof value !== "string") {
423
- throw new Error(`${label} expects a positive integer; got ${JSON.stringify(value)}`);
438
+ throw new EngramAccessInputError(`${label} expects a positive integer; got ${JSON.stringify(value)}`);
424
439
  }
425
440
  const parsed = typeof value === "number" ? value : Number(value);
426
441
  if (!Number.isFinite(parsed) || parsed <= 0 || !Number.isInteger(parsed)) {
427
- throw new Error(`${label} expects a positive integer; got ${JSON.stringify(value)}`);
442
+ throw new EngramAccessInputError(`${label} expects a positive integer; got ${JSON.stringify(value)}`);
428
443
  }
429
444
  return parsed;
430
445
  }
@@ -447,7 +462,7 @@ async function getMcpServerVersion(): Promise<string> {
447
462
  }
448
463
 
449
464
  export class EngramMcpServer {
450
- private buffer = Buffer.alloc(0);
465
+ private readonly frames = new McpFrameReader();
451
466
  private flushTask: Promise<void> | null = null;
452
467
  private readonly tools: McpTool[];
453
468
  private readonly resources: McpResource[];
@@ -2402,7 +2417,7 @@ export class EngramMcpServer {
2402
2417
  // Cancellation is transport control flow, not a JSON-RPC tool error.
2403
2418
  // Preserve the original AbortError so HTTP can silently end a dead socket.
2404
2419
  if (isAbortError(err)) throw err;
2405
- const message = err instanceof Error ? err.message : String(err);
2420
+ const message = mcpToolErrorMessage(err instanceof Error ? err : new Error(String(err)));
2406
2421
  return {
2407
2422
  jsonrpc: "2.0",
2408
2423
  id,
@@ -2426,7 +2441,7 @@ export class EngramMcpServer {
2426
2441
 
2427
2442
  async runStdio(input: Readable, output: Writable): Promise<void> {
2428
2443
  input.on("data", (chunk) => {
2429
- this.buffer = Buffer.concat([this.buffer, Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)]);
2444
+ this.frames.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
2430
2445
  this.scheduleFlush(output);
2431
2446
  });
2432
2447
  await new Promise<void>((resolve, reject) => {
@@ -2455,7 +2470,7 @@ export class EngramMcpServer {
2455
2470
  if (this.flushTask === task) {
2456
2471
  this.flushTask = null;
2457
2472
  }
2458
- if (this.buffer.length > 0) {
2473
+ if (this.frames.hasUnread()) {
2459
2474
  this.scheduleFlush(output);
2460
2475
  }
2461
2476
  });
@@ -2463,30 +2478,15 @@ export class EngramMcpServer {
2463
2478
  }
2464
2479
 
2465
2480
  private async flushBuffer(output: Writable): Promise<void> {
2466
- while (true) {
2467
- const headerEnd = this.buffer.indexOf("\r\n\r\n");
2468
- if (headerEnd < 0) return;
2469
- const headerText = this.buffer.slice(0, headerEnd).toString("utf-8");
2470
- const headers = headerText.split("\r\n");
2471
- const contentLengthHeader = headers.find((line) => line.toLowerCase().startsWith("content-length:"));
2472
- if (!contentLengthHeader) {
2473
- this.buffer = Buffer.alloc(0);
2474
- return;
2475
- }
2476
- const contentLength = Number.parseInt(contentLengthHeader.split(":")[1]?.trim() ?? "0", 10);
2477
- if (!Number.isFinite(contentLength) || contentLength < 0) {
2478
- this.buffer = Buffer.alloc(0);
2479
- return;
2481
+ for (let frame = this.frames.next(); frame; frame = this.frames.next()) {
2482
+ if (frame.kind === "too-large") {
2483
+ this.writeMessage(output, { jsonrpc: "2.0", id: null, error: { code: -32600, message: "frame too large" } });
2484
+ continue;
2480
2485
  }
2481
- const messageStart = headerEnd + 4;
2482
- const messageEnd = messageStart + contentLength;
2483
- if (this.buffer.length < messageEnd) return;
2484
- const body = this.buffer.slice(messageStart, messageEnd).toString("utf-8");
2485
- this.buffer = this.buffer.slice(messageEnd);
2486
-
2487
2486
  let parsed: JsonRpcRequest;
2488
2487
  try {
2489
- parsed = JSON.parse(body) as JsonRpcRequest;
2488
+ // SAFETY: handleRequest defaults missing fields; a non-object body throws and scheduleFlush answers -32700.
2489
+ parsed = JSON.parse(frame.text) as JsonRpcRequest;
2490
2490
  } catch {
2491
2491
  this.writeMessage(output, {
2492
2492
  jsonrpc: "2.0",
@@ -2620,7 +2620,7 @@ export class EngramMcpServer {
2620
2620
  caps?.ops === undefined || capabilityAllowsOp(caps, MCP_MIGRATED_OPERATIONS[toLegacyToolName(t.name)] ?? "")
2621
2621
  )
2622
2622
  .map((t) => t.name);
2623
- throw new Error(unknownToolError(name, visible));
2623
+ throw new EngramAccessInputError(unknownToolError(name, visible));
2624
2624
  }
2625
2625
  const op = getOperation(migrated);
2626
2626
  if (!op) {
@@ -51,6 +51,7 @@ import {
51
51
  queueExplicitCaptureForReview,
52
52
  } from "./explicit-capture.js";
53
53
  import { log } from "./logger.js";
54
+ import { embeddingBacklogExceeds, isSearchHealthDegraded } from "./namespaces/search.js";
54
55
  import { recordObjectiveStateSnapshotsFromObservedMessages } from "./objective-state-writers.js";
55
56
  import type { Orchestrator } from "./orchestrator.js";
56
57
  import { displayErrorDetail } from "./runtime/better-sqlite.js";
@@ -289,7 +290,7 @@ export class AccessObserveWriteSurface {
289
290
  /* status probe failed — non-fatal */
290
291
  }
291
292
  }
292
- if (threshold > 0 && pendingEmbeddings !== null && pendingEmbeddings > threshold) {
293
+ if (embeddingBacklogExceeds(pendingEmbeddings, threshold)) {
293
294
  degraded = true;
294
295
  degradedReason = `embedding-backlog: ${pendingEmbeddings} pending > threshold ${threshold}`;
295
296
  }
@@ -355,14 +356,13 @@ export class AccessObserveWriteSurface {
355
356
  const pending = health.pendingEmbeddings ?? null;
356
357
  const oldest = health.oldestPendingAgeMs ?? null;
357
358
  const threshold = this.deps.orchestrator.config.qmdEmbeddingBacklogThreshold;
358
- const backlogDegraded = threshold > 0 && pending !== null && pending > threshold;
359
- const degraded = !active || health.collectionState === "unknown" || backlogDegraded;
359
+ const backlogDegraded = embeddingBacklogExceeds(pending, threshold);
360
360
  const mode = !active ? "fallback" : health.daemonMode === true ? "daemon" : "cli";
361
361
 
362
362
  return {
363
363
  enabled: true,
364
364
  active,
365
- degraded,
365
+ degraded: isSearchHealthDegraded({ ...health, pendingEmbeddings: pending }, threshold),
366
366
  mode,
367
367
  collection: health.collection || fallbackCollection,
368
368
  collectionState: health.collectionState,