@remnic/core 10.0.92 → 10.0.94

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 (501) hide show
  1. package/dist/access-admin-ops-surface.js +332 -59
  2. package/dist/access-authorization-probe.js +2 -283
  3. package/dist/access-boundary.d.ts +1 -1
  4. package/dist/access-boundary.d.ts.map +1 -1
  5. package/dist/access-boundary.js +1 -282
  6. package/dist/access-cli.js +287 -303
  7. package/dist/access-cli.js.map +1 -1
  8. package/dist/access-coding-context-resolution.js +3 -3
  9. package/dist/access-extraction-force-flush.js +332 -59
  10. package/dist/access-http-briefing.js +332 -60
  11. package/dist/access-http-query.js +332 -61
  12. package/dist/access-http.js +330 -112
  13. package/dist/access-identity-continuity-surface.js +332 -59
  14. package/dist/access-lcm-surface.js +332 -59
  15. package/dist/access-mcp-frames.d.ts +20 -6
  16. package/dist/access-mcp-frames.d.ts.map +1 -1
  17. package/dist/access-mcp-frames.js +1 -1
  18. package/dist/access-mcp.d.ts +5 -0
  19. package/dist/access-mcp.d.ts.map +1 -1
  20. package/dist/access-mcp.js +330 -87
  21. package/dist/access-namespace-preflight.js +2 -282
  22. package/dist/access-observe-transcript.js +3 -3
  23. package/dist/access-observe-write-category.js +6 -6
  24. package/dist/access-observe-write-surface.js +332 -59
  25. package/dist/access-offline-manifest.js +12 -11
  26. package/dist/access-operations-batch.js +330 -64
  27. package/dist/access-operations.js +330 -73
  28. package/dist/access-recall-concurrency.js +332 -59
  29. package/dist/access-recall-diagnostics.js +5 -4
  30. package/dist/access-recall-response.js +332 -59
  31. package/dist/access-recall-surface.js +332 -59
  32. package/dist/access-schema.js +2 -2
  33. package/dist/access-service.js +335 -62
  34. package/dist/access-surface-catalog.js +6 -283
  35. package/dist/access-surface-catalog.js.map +1 -1
  36. package/dist/active-context-transform.js +1 -1
  37. package/dist/active-memory-bridge.js +3 -2
  38. package/dist/active-recall.js +36 -37
  39. package/dist/active-recall.js.map +1 -1
  40. package/dist/activity/journal-extract.d.ts +13 -1
  41. package/dist/activity/journal-extract.d.ts.map +1 -1
  42. package/dist/{auto-sync-3AZW7MXI.js → auto-sync-BO5YZKM6.js} +13 -15
  43. package/dist/{auto-sync-3AZW7MXI.js.map → auto-sync-BO5YZKM6.js.map} +1 -1
  44. package/dist/briefing.js +20 -20
  45. package/dist/buffer.js +16 -16
  46. package/dist/calibration.js +10 -10
  47. package/dist/{capsule-merge-2IIXFXN5.js → capsule-merge-6IDAYTKG.js} +6 -6
  48. package/dist/causal-consolidation.js +23 -23
  49. package/dist/{chunk-RGUUBAT5.js → chunk-2WCLTWV2.js} +3 -3
  50. package/dist/{chunk-BQZEGOZ4.js → chunk-2YODOG2O.js} +2 -2
  51. package/dist/{chunk-WYG5UNDY.js → chunk-3AUDELZL.js} +2 -2
  52. package/dist/{chunk-MB6ZJDN6.js → chunk-3FBAEPCU.js} +2 -2
  53. package/dist/{chunk-PIITB2YZ.js → chunk-3ZS3NUEI.js} +4 -4
  54. package/dist/{chunk-ATPWZ4F7.js → chunk-4EZWSDFL.js} +5 -5
  55. package/dist/{chunk-ANZZLRUX.js → chunk-4IVRQMZW.js} +2 -2
  56. package/dist/{chunk-63E37JCN.js → chunk-4RAJT5L2.js} +4 -4
  57. package/dist/{chunk-45VUHDV2.js → chunk-5CO5G4MN.js} +2 -2
  58. package/dist/{chunk-LUJCQQ3L.js → chunk-65HWAQ4F.js} +2 -2
  59. package/dist/{chunk-T67LUYCR.js → chunk-77NTFICT.js} +5 -5
  60. package/dist/chunk-A2WFUMUN.js +86 -0
  61. package/dist/chunk-A2WFUMUN.js.map +1 -0
  62. package/dist/{chunk-UE6RRXMF.js → chunk-A4F7OIC5.js} +2 -2
  63. package/dist/chunk-AHA5VQGP.js +117 -0
  64. package/dist/chunk-AHA5VQGP.js.map +1 -0
  65. package/dist/{chunk-RRJBDXAQ.js → chunk-B377OKUP.js} +2 -2
  66. package/dist/{chunk-IUKYFTGW.js → chunk-B3DR2JBZ.js} +140 -125
  67. package/dist/chunk-B3DR2JBZ.js.map +1 -0
  68. package/dist/{chunk-Z7JIZ42P.js → chunk-BN2EBCLB.js} +3 -3
  69. package/dist/{chunk-YYOMGOHB.js → chunk-BOK6BN5M.js} +2 -2
  70. package/dist/{chunk-U6UNF5ZS.js → chunk-BPK32FRM.js} +3 -3
  71. package/dist/{chunk-OH7QLI6W.js → chunk-BPPUH5JM.js} +5 -5
  72. package/dist/{chunk-O6ZSWHVR.js → chunk-C2KE5DMD.js} +4 -4
  73. package/dist/{chunk-47F6WWLQ.js → chunk-C73N66PR.js} +2 -2
  74. package/dist/{chunk-WRT7GJ2D.js → chunk-CIWMTNHW.js} +4 -4
  75. package/dist/{chunk-HF3BKUVV.js → chunk-CL4JU3DF.js} +7 -7
  76. package/dist/{chunk-O55EKIEC.js → chunk-D3ZKHLN2.js} +2 -2
  77. package/dist/chunk-D5S6RL32.js +67137 -0
  78. package/dist/chunk-D5S6RL32.js.map +1 -0
  79. package/dist/{chunk-ETZLQOUR.js → chunk-D5XG2KPS.js} +2 -2
  80. package/dist/{chunk-CD4BCCNP.js → chunk-DJ7WVEWX.js} +2 -2
  81. package/dist/{chunk-PWXPRVLK.js → chunk-DNY63QWJ.js} +2 -2
  82. package/dist/{chunk-4CJTQHEG.js → chunk-ESLOLCD4.js} +3 -3
  83. package/dist/{chunk-VILPVT4S.js → chunk-EZ47HOJ6.js} +4 -4
  84. package/dist/{chunk-EFYN5I7Z.js → chunk-F4QFU5IZ.js} +2 -2
  85. package/dist/{chunk-T6OZW2WR.js → chunk-FA7SLQ5X.js} +7 -1
  86. package/dist/chunk-FA7SLQ5X.js.map +1 -0
  87. package/dist/{chunk-BRLXOZLM.js → chunk-FQAQ63QA.js} +729 -17
  88. package/dist/chunk-FQAQ63QA.js.map +1 -0
  89. package/dist/{chunk-FSO3G4JJ.js → chunk-FWRXW7CZ.js} +5000 -2748
  90. package/dist/chunk-FWRXW7CZ.js.map +1 -0
  91. package/dist/{chunk-XYKBWTWI.js → chunk-FZZMLGWQ.js} +2 -2
  92. package/dist/{chunk-FNXQZGUS.js → chunk-GBJUTX44.js} +2 -2
  93. package/dist/{chunk-YLXETSAH.js → chunk-GCZJ7XRI.js} +2 -2
  94. package/dist/{chunk-UDKWFDV2.js → chunk-HLUHEMN4.js} +27 -3
  95. package/dist/chunk-HLUHEMN4.js.map +1 -0
  96. package/dist/{chunk-SUSW74WU.js → chunk-IL3RHBWM.js} +56 -5
  97. package/dist/chunk-IL3RHBWM.js.map +1 -0
  98. package/dist/{chunk-JV4S6VDH.js → chunk-ILY5SSOM.js} +2 -2
  99. package/dist/{chunk-EXHXJETE.js → chunk-IQ55QGY5.js} +2 -2
  100. package/dist/{chunk-4J363OAA.js → chunk-J7BIFOYP.js} +2 -2
  101. package/dist/{chunk-QFEDITXM.js → chunk-JNDMIAJ4.js} +2 -2
  102. package/dist/chunk-JTSSSR4L.js +359 -0
  103. package/dist/chunk-JTSSSR4L.js.map +1 -0
  104. package/dist/{chunk-5KBIOI4G.js → chunk-JVBAPAWZ.js} +217 -13
  105. package/dist/chunk-JVBAPAWZ.js.map +1 -0
  106. package/dist/{chunk-E5PPE4VA.js → chunk-K2VRKCPA.js} +2 -2
  107. package/dist/{chunk-MKRYQROF.js → chunk-LGEHAQHK.js} +4 -4
  108. package/dist/{chunk-7HTUYFR3.js → chunk-LLPMMMWG.js} +27 -10
  109. package/dist/chunk-LLPMMMWG.js.map +1 -0
  110. package/dist/{chunk-XYTQJD7F.js → chunk-LMJVP5CM.js} +2 -2
  111. package/dist/{chunk-E7YZXWIS.js → chunk-LNGELD2M.js} +2 -2
  112. package/dist/{chunk-FQKBJJYB.js → chunk-LPV72KRQ.js} +2 -2
  113. package/dist/{chunk-2LCRG2YV.js → chunk-M2XR6B6V.js} +2 -2
  114. package/dist/{chunk-EQ4U73UH.js → chunk-MLAMXQAW.js} +14 -2
  115. package/dist/chunk-MLAMXQAW.js.map +1 -0
  116. package/dist/{chunk-ZU5JDLOH.js → chunk-MMRTPH3J.js} +2 -2
  117. package/dist/{chunk-TVIVY7KU.js → chunk-NED7IR7B.js} +4 -4
  118. package/dist/{chunk-6F5MJFXY.js → chunk-NHVAX7MH.js} +2 -2
  119. package/dist/{chunk-TG3R2SID.js → chunk-NMGHGTVR.js} +5 -5
  120. package/dist/{chunk-YCNIGRRF.js → chunk-NS7U4ZYU.js} +13 -117
  121. package/dist/chunk-NS7U4ZYU.js.map +1 -0
  122. package/dist/{chunk-NGHDW6UU.js → chunk-NUQEREIP.js} +2 -2
  123. package/dist/{chunk-5IIQU4JZ.js → chunk-OB72KNMF.js} +4 -4
  124. package/dist/{chunk-RIMK327Y.js → chunk-OUVYYKYU.js} +7 -7
  125. package/dist/{chunk-QJPJXCS4.js → chunk-P3WRNWWM.js} +157 -4
  126. package/dist/chunk-P3WRNWWM.js.map +1 -0
  127. package/dist/{chunk-E6M225BJ.js → chunk-PC5DRBGD.js} +18 -8
  128. package/dist/chunk-PC5DRBGD.js.map +1 -0
  129. package/dist/{chunk-RWGRSKN5.js → chunk-PT4DZDJA.js} +2 -2
  130. package/dist/{chunk-7EPY3IQL.js → chunk-PZJQ46DH.js} +2 -2
  131. package/dist/{chunk-MXHMNKWG.js → chunk-QDESY76F.js} +3 -3
  132. package/dist/{chunk-E3A7ELSG.js → chunk-QHARXWTC.js} +2 -2
  133. package/dist/{chunk-BLJT6JP2.js → chunk-QMFAMOT2.js} +2 -2
  134. package/dist/{chunk-I6QGI65T.js → chunk-QRMG4HK4.js} +3 -3
  135. package/dist/{chunk-ZU3NJNO7.js → chunk-QSF5SJAM.js} +4 -4
  136. package/dist/{chunk-5IYOKDM4.js → chunk-R23JWJD3.js} +5 -5
  137. package/dist/{chunk-RHQLIHMB.js → chunk-R4BBGPI2.js} +218 -218
  138. package/dist/chunk-R4BBGPI2.js.map +1 -0
  139. package/dist/{chunk-NT7F7WJQ.js → chunk-RFUL2ZIQ.js} +291 -93
  140. package/dist/chunk-RFUL2ZIQ.js.map +1 -0
  141. package/dist/{chunk-E4IRW2FG.js → chunk-RKABLU5M.js} +233 -40
  142. package/dist/chunk-RKABLU5M.js.map +1 -0
  143. package/dist/{chunk-P4WNBSTW.js → chunk-RNG7S3FY.js} +2 -2
  144. package/dist/{chunk-IPT2OY4B.js → chunk-RQFXZYTF.js} +35 -33
  145. package/dist/chunk-RQFXZYTF.js.map +1 -0
  146. package/dist/{chunk-5HFXGXE5.js → chunk-RUTN5MMC.js} +7 -9
  147. package/dist/{chunk-5HFXGXE5.js.map → chunk-RUTN5MMC.js.map} +1 -1
  148. package/dist/{chunk-AP6NCP3V.js → chunk-S3S72HRM.js} +8 -6
  149. package/dist/chunk-S3S72HRM.js.map +1 -0
  150. package/dist/{chunk-ZGFLIK5H.js → chunk-SPAKBUJY.js} +2 -2
  151. package/dist/{chunk-ER7XANP3.js → chunk-SQ3GEIEL.js} +4 -4
  152. package/dist/{chunk-PMJFRDJI.js → chunk-SUTEBYGI.js} +2 -2
  153. package/dist/{chunk-HVX4LPNY.js → chunk-T4KY6UYF.js} +5 -3
  154. package/dist/{chunk-HVX4LPNY.js.map → chunk-T4KY6UYF.js.map} +1 -1
  155. package/dist/{chunk-R6HMAIKM.js → chunk-TOSPNM4T.js} +2 -2
  156. package/dist/{chunk-RMXS4I66.js → chunk-TVDJEUV5.js} +2 -2
  157. package/dist/{chunk-PLCYKAWH.js → chunk-TYRWSE4B.js} +2 -2
  158. package/dist/{chunk-B4QYQFGY.js → chunk-UBEKET2V.js} +383 -36
  159. package/dist/chunk-UBEKET2V.js.map +1 -0
  160. package/dist/{chunk-IQWUACVG.js → chunk-UHMHJX5G.js} +3 -3
  161. package/dist/{chunk-YODUDA6R.js → chunk-UN4RVUG2.js} +22 -22
  162. package/dist/{chunk-E6Z4FBX6.js → chunk-V2QSNFCT.js} +2 -2
  163. package/dist/{chunk-NBH6K6G5.js → chunk-V65H7MI6.js} +345 -16
  164. package/dist/chunk-V65H7MI6.js.map +1 -0
  165. package/dist/chunk-W54Z2MOP.js +4500 -0
  166. package/dist/chunk-W54Z2MOP.js.map +1 -0
  167. package/dist/{chunk-7W3RXOIG.js → chunk-WGGRZYSQ.js} +14 -14
  168. package/dist/{chunk-RIZ5NUNN.js → chunk-WQ4XKIOX.js} +4 -4
  169. package/dist/{chunk-QEYTRFR3.js → chunk-X26YOFGS.js} +2 -2
  170. package/dist/{chunk-ITHZFHST.js → chunk-X2BVB74H.js} +2 -2
  171. package/dist/{chunk-6F42QONS.js → chunk-X5HGU2EM.js} +4 -4
  172. package/dist/{chunk-GVGAO3WV.js → chunk-XJ2S5UBF.js} +3 -3
  173. package/dist/{chunk-IBJ6U753.js → chunk-XKZBZOKV.js} +4 -4
  174. package/dist/{chunk-65AUYLU3.js → chunk-XPXHQI6N.js} +2 -2
  175. package/dist/chunk-XRWWCW4H.js +102 -0
  176. package/dist/chunk-XRWWCW4H.js.map +1 -0
  177. package/dist/{chunk-HH5LY6RR.js → chunk-YIXJSW5M.js} +5 -5
  178. package/dist/{chunk-2JSDPUKD.js → chunk-YMFPFXEX.js} +2 -2
  179. package/dist/{chunk-N4KAE2NB.js → chunk-Z3FTSHT5.js} +3 -3
  180. package/dist/{chunk-7GLJMDEQ.js → chunk-ZDV5YWID.js} +6 -6
  181. package/dist/{chunk-645WOU5I.js → chunk-ZDZJNXL6.js} +4 -4
  182. package/dist/{chunk-6TCXIRP5.js → chunk-ZKE4CO6B.js} +4 -4
  183. package/dist/cli.js +303 -185
  184. package/dist/coding/export-okf-codegraph.js +29 -29
  185. package/dist/compounding/engine.js +23 -24
  186. package/dist/config.js +36 -37
  187. package/dist/connectors/codex-materialize-runner.js +20 -20
  188. package/dist/connectors/index.js +21 -21
  189. package/dist/connectors/live/google-drive.d.ts +2 -0
  190. package/dist/connectors/live/google-drive.d.ts.map +1 -1
  191. package/dist/consolidation-provenance-check.js +4 -4
  192. package/dist/consolidation-undo.js +5 -5
  193. package/dist/contradiction/index.js +7 -6
  194. package/dist/{contradiction-scan-P2MHYFVG.js → contradiction-scan-IBPYGQZF.js} +4 -3
  195. package/dist/convergence-refresh.js +22 -22
  196. package/dist/corpus-watermark.js +23 -23
  197. package/dist/deep-recall-http-glue.js +2 -2
  198. package/dist/deep-recall-policy-llm.js +4 -4
  199. package/dist/direct-answer-wiring.js +2 -2
  200. package/dist/embedding-fallback.js +1 -1
  201. package/dist/entity-retrieval.js +21 -21
  202. package/dist/eval-trajectory-store.js +2 -2
  203. package/dist/eval-trajectory.js +2 -2
  204. package/dist/event-order-recall.js +2 -2
  205. package/dist/explicit-capture.d.ts +3 -2
  206. package/dist/explicit-capture.d.ts.map +1 -1
  207. package/dist/explicit-capture.js +530 -6
  208. package/dist/explicit-cue-recall.js +2 -2
  209. package/dist/external-wiki-access.js +2 -283
  210. package/dist/extraction-faithfulness.js +4 -4
  211. package/dist/extraction-judge.js +5 -5
  212. package/dist/extraction-normalization.js +1 -1
  213. package/dist/extraction-quote-grounding.d.ts.map +1 -1
  214. package/dist/extraction-quote-grounding.js +1 -1
  215. package/dist/extraction-source-grounding-rules.js +2 -2
  216. package/dist/extraction-source-grounding.js +3 -3
  217. package/dist/extraction.js +43 -44
  218. package/dist/fallback-llm-codex-subscription.js +2 -2
  219. package/dist/fallback-llm.js +3 -3
  220. package/dist/{first-start-migration-QFI7B5SH.js → first-start-migration-FILJH3RO.js} +6 -5
  221. package/dist/{first-start-migration-QFI7B5SH.js.map → first-start-migration-FILJH3RO.js.map} +1 -1
  222. package/dist/focused-list-recall.js +2 -2
  223. package/dist/harmonic-retrieval.js +20 -20
  224. package/dist/index.js +773 -794
  225. package/dist/lcm/index.js +2 -2
  226. package/dist/live-connectors-runner.js +2 -3
  227. package/dist/local-llm-config.js +2 -2
  228. package/dist/local-llm-helpers.d.ts +4 -0
  229. package/dist/local-llm-helpers.d.ts.map +1 -1
  230. package/dist/local-llm-helpers.js +3 -1
  231. package/dist/local-llm.d.ts +4 -1
  232. package/dist/local-llm.d.ts.map +1 -1
  233. package/dist/local-llm.js +4 -4
  234. package/dist/location/index.js +27 -29
  235. package/dist/maintenance/memory-governance.js +20 -20
  236. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +20 -20
  237. package/dist/maintenance/rebuild-memory-projection-runner.js +22 -22
  238. package/dist/maintenance/rebuild-memory-projection.js +21 -21
  239. package/dist/memory-browse-operations.js +2 -283
  240. package/dist/memory-browse.js +8 -7
  241. package/dist/memory-controller.js +2 -2
  242. package/dist/memory-subject.js +2 -2
  243. package/dist/namespaces/migrate.js +21 -21
  244. package/dist/namespaces/search.js +5 -5
  245. package/dist/namespaces/storage.js +20 -20
  246. package/dist/offline-sync-changeset-generations.js +1 -1
  247. package/dist/offline-sync-embedding-generation.js +1 -1
  248. package/dist/offline-sync-impression-drain.js +6 -6
  249. package/dist/offline-sync-snapshot-stream.js +1 -1
  250. package/dist/offline-sync.js +1 -1
  251. package/dist/operator-doctor-corpus.js +24 -24
  252. package/dist/operator-toolkit.js +58 -61
  253. package/dist/orchestration/backlog-scheduler.js +278 -294
  254. package/dist/orchestration/backlog-scheduler.js.map +1 -1
  255. package/dist/orchestration/buffer-drain-runner.js +278 -294
  256. package/dist/orchestration/extraction-run.d.ts +4 -0
  257. package/dist/orchestration/extraction-run.d.ts.map +1 -1
  258. package/dist/orchestration/fact-dedup-window.d.ts +1 -1
  259. package/dist/orchestration/fact-dedup-window.d.ts.map +1 -1
  260. package/dist/orchestration/maintenance.js +39 -42
  261. package/dist/orchestrator.d.ts +9 -11
  262. package/dist/orchestrator.d.ts.map +1 -1
  263. package/dist/orchestrator.js +290 -307
  264. package/dist/page-versioning.js +3 -3
  265. package/dist/qmd-daemon-session.js +2 -2
  266. package/dist/qmd.js +3 -3
  267. package/dist/recall-explain-renderer.js +1 -1
  268. package/dist/recall-navigation-operations.js +2 -283
  269. package/dist/recall-navigation.js +332 -59
  270. package/dist/recall-planner-llm.js +3 -3
  271. package/dist/recall-state-view-admission.js +6 -6
  272. package/dist/recall-why-service.js +10 -9
  273. package/dist/recall-why.js +4 -3
  274. package/dist/recall-xray-cli.js +2 -2
  275. package/dist/recall-xray-renderer.js +1 -1
  276. package/dist/reconcile/manifest.js +3 -3
  277. package/dist/{resolution-N7H3F2E4.js → resolution-OVVIF7ZY.js} +8 -7
  278. package/dist/response-guidance-recall.js +2 -2
  279. package/dist/resume-bundles.js +40 -41
  280. package/dist/salvage-envelope.js +4 -4
  281. package/dist/search/factory.js +4 -4
  282. package/dist/search/index.js +4 -4
  283. package/dist/semantic-consolidation.js +23 -23
  284. package/dist/semantic-rule-promotion.js +20 -20
  285. package/dist/semantic-rule-verifier.js +20 -20
  286. package/dist/shared-context/manager.js +2 -3
  287. package/dist/source-agent-qualifier.js +32 -33
  288. package/dist/standup/build.js +20 -20
  289. package/dist/storage/buffer-drain-claims.d.ts +97 -12
  290. package/dist/storage/buffer-drain-claims.d.ts.map +1 -1
  291. package/dist/storage/buffer-drain-claims.js +1 -1
  292. package/dist/storage/buffer-session-files.d.ts +4 -0
  293. package/dist/storage/buffer-session-files.d.ts.map +1 -1
  294. package/dist/storage/buffer-session-files.js +1 -1
  295. package/dist/storage/content-hash-index.d.ts +10 -0
  296. package/dist/storage/content-hash-index.d.ts.map +1 -1
  297. package/dist/storage.d.ts.map +1 -1
  298. package/dist/storage.js +19 -19
  299. package/dist/subject-config.js +3 -3
  300. package/dist/summarizer.d.ts +4 -1
  301. package/dist/summarizer.d.ts.map +1 -1
  302. package/dist/summarizer.js +6 -6
  303. package/dist/support-passport/index.js +53 -297
  304. package/dist/targeted-fact-recall.js +2 -2
  305. package/dist/tier-routing.js +3 -2
  306. package/dist/{tier-stats-FQGQSFET.js → tier-stats-FXEUJN73.js} +6 -5
  307. package/dist/{tier-stats-FQGQSFET.js.map → tier-stats-FXEUJN73.js.map} +1 -1
  308. package/dist/transcript.js +2 -2
  309. package/dist/transfer/capsule-import.js +4 -4
  310. package/dist/transfer/export-okf.js +20 -20
  311. package/dist/verified-recall.js +20 -20
  312. package/dist/wearables/memory-gen.d.ts +5 -1
  313. package/dist/wearables/memory-gen.d.ts.map +1 -1
  314. package/dist/wearables/service.d.ts.map +1 -1
  315. package/dist/who-knows-cli.js +21 -21
  316. package/dist/who-knows.js +20 -20
  317. package/dist/write-envelope.js +3 -3
  318. package/package.json +2 -2
  319. package/src/access-boundary.ts +5 -1
  320. package/src/access-category-alias.test.ts +5 -0
  321. package/src/access-mcp-frames.test.ts +60 -5
  322. package/src/access-mcp-frames.ts +72 -18
  323. package/src/access-mcp.test.ts +66 -2
  324. package/src/access-mcp.ts +19 -13
  325. package/src/access-service-coding-write.test.ts +7 -0
  326. package/src/activity/journal-extract-storage.test.ts +31 -0
  327. package/src/activity/journal-extract.test.ts +1 -0
  328. package/src/activity/journal-extract.ts +24 -3
  329. package/src/buffer-drain-handover.test.ts +5 -1
  330. package/src/connectors/live/google-drive.test.ts +39 -0
  331. package/src/connectors/live/google-drive.ts +41 -12
  332. package/src/explicit-capture.test.ts +109 -17
  333. package/src/explicit-capture.ts +90 -37
  334. package/src/extraction-quote-grounding.test.ts +20 -0
  335. package/src/extraction-quote-grounding.ts +21 -11
  336. package/src/fact-dedup-window.test.ts +37 -0
  337. package/src/local-llm-helpers.ts +12 -0
  338. package/src/local-llm-shutdown.test.ts +194 -0
  339. package/src/local-llm.ts +32 -30
  340. package/src/orchestration/extraction-run.ts +12 -3
  341. package/src/orchestration/fact-dedup-window.ts +5 -1
  342. package/src/orchestrator-connector-dedup.test.ts +9 -5
  343. package/src/orchestrator.ts +47 -50
  344. package/src/storage/buffer-drain-claims.test.ts +385 -1
  345. package/src/storage/buffer-drain-claims.ts +380 -97
  346. package/src/storage/buffer-session-files.ts +4 -0
  347. package/src/storage/content-hash-index.ts +27 -2
  348. package/src/storage-fact-hash-publish-failure.test.ts +87 -0
  349. package/src/storage.ts +5 -1
  350. package/src/summarizer-shutdown.test.ts +195 -0
  351. package/src/summarizer.ts +15 -2
  352. package/src/wearables/memory-gen.test.ts +20 -0
  353. package/src/wearables/memory-gen.ts +14 -7
  354. package/src/wearables/service.ts +14 -1
  355. package/src/wearables/storage-io.test.ts +25 -0
  356. package/dist/chunk-2FGLEF7C.js +0 -61
  357. package/dist/chunk-2FGLEF7C.js.map +0 -1
  358. package/dist/chunk-3RLK65ZK.js +0 -203
  359. package/dist/chunk-3RLK65ZK.js.map +0 -1
  360. package/dist/chunk-4WR2OD7K.js +0 -43
  361. package/dist/chunk-4WR2OD7K.js.map +0 -1
  362. package/dist/chunk-5KBIOI4G.js.map +0 -1
  363. package/dist/chunk-5M5M22GW.js +0 -346
  364. package/dist/chunk-5M5M22GW.js.map +0 -1
  365. package/dist/chunk-7HTUYFR3.js.map +0 -1
  366. package/dist/chunk-AP6NCP3V.js.map +0 -1
  367. package/dist/chunk-B4QYQFGY.js.map +0 -1
  368. package/dist/chunk-BJRTMNCB.js +0 -1919
  369. package/dist/chunk-BJRTMNCB.js.map +0 -1
  370. package/dist/chunk-BRLXOZLM.js.map +0 -1
  371. package/dist/chunk-BSACVS6R.js +0 -621
  372. package/dist/chunk-BSACVS6R.js.map +0 -1
  373. package/dist/chunk-DKAA2IHQ.js +0 -3644
  374. package/dist/chunk-DKAA2IHQ.js.map +0 -1
  375. package/dist/chunk-E4IRW2FG.js.map +0 -1
  376. package/dist/chunk-E6M225BJ.js.map +0 -1
  377. package/dist/chunk-EQ4U73UH.js.map +0 -1
  378. package/dist/chunk-ETSJD5IV.js +0 -361
  379. package/dist/chunk-ETSJD5IV.js.map +0 -1
  380. package/dist/chunk-F55YQP7N.js +0 -336
  381. package/dist/chunk-F55YQP7N.js.map +0 -1
  382. package/dist/chunk-FHGWKODN.js +0 -2300
  383. package/dist/chunk-FHGWKODN.js.map +0 -1
  384. package/dist/chunk-FLRP63GU.js +0 -32219
  385. package/dist/chunk-FLRP63GU.js.map +0 -1
  386. package/dist/chunk-FSO3G4JJ.js.map +0 -1
  387. package/dist/chunk-ID6JGIMD.js +0 -25
  388. package/dist/chunk-ID6JGIMD.js.map +0 -1
  389. package/dist/chunk-IGLJNHOX.js +0 -62
  390. package/dist/chunk-IGLJNHOX.js.map +0 -1
  391. package/dist/chunk-IPT2OY4B.js.map +0 -1
  392. package/dist/chunk-IUKYFTGW.js.map +0 -1
  393. package/dist/chunk-NBH6K6G5.js.map +0 -1
  394. package/dist/chunk-NT7F7WJQ.js.map +0 -1
  395. package/dist/chunk-NTRUKAAE.js +0 -223
  396. package/dist/chunk-NTRUKAAE.js.map +0 -1
  397. package/dist/chunk-OGXXGHW6.js +0 -223
  398. package/dist/chunk-OGXXGHW6.js.map +0 -1
  399. package/dist/chunk-PPCLZ4JU.js +0 -28
  400. package/dist/chunk-PPCLZ4JU.js.map +0 -1
  401. package/dist/chunk-QJPJXCS4.js.map +0 -1
  402. package/dist/chunk-R2LBF4HH.js +0 -729
  403. package/dist/chunk-R2LBF4HH.js.map +0 -1
  404. package/dist/chunk-RHQLIHMB.js.map +0 -1
  405. package/dist/chunk-RRTVGD3J.js +0 -792
  406. package/dist/chunk-RRTVGD3J.js.map +0 -1
  407. package/dist/chunk-SUSW74WU.js.map +0 -1
  408. package/dist/chunk-T6OZW2WR.js.map +0 -1
  409. package/dist/chunk-UDKWFDV2.js.map +0 -1
  410. package/dist/chunk-V7IZKJI3.js +0 -22
  411. package/dist/chunk-V7IZKJI3.js.map +0 -1
  412. package/dist/chunk-X562NQFA.js +0 -10144
  413. package/dist/chunk-X562NQFA.js.map +0 -1
  414. package/dist/chunk-XDSCJOH7.js +0 -3991
  415. package/dist/chunk-XDSCJOH7.js.map +0 -1
  416. package/dist/chunk-YCNIGRRF.js.map +0 -1
  417. package/dist/chunk-ZTTCDQ4I.js +0 -18796
  418. package/dist/chunk-ZTTCDQ4I.js.map +0 -1
  419. /package/dist/{capsule-merge-2IIXFXN5.js.map → capsule-merge-6IDAYTKG.js.map} +0 -0
  420. /package/dist/{chunk-RGUUBAT5.js.map → chunk-2WCLTWV2.js.map} +0 -0
  421. /package/dist/{chunk-BQZEGOZ4.js.map → chunk-2YODOG2O.js.map} +0 -0
  422. /package/dist/{chunk-WYG5UNDY.js.map → chunk-3AUDELZL.js.map} +0 -0
  423. /package/dist/{chunk-MB6ZJDN6.js.map → chunk-3FBAEPCU.js.map} +0 -0
  424. /package/dist/{chunk-PIITB2YZ.js.map → chunk-3ZS3NUEI.js.map} +0 -0
  425. /package/dist/{chunk-ATPWZ4F7.js.map → chunk-4EZWSDFL.js.map} +0 -0
  426. /package/dist/{chunk-ANZZLRUX.js.map → chunk-4IVRQMZW.js.map} +0 -0
  427. /package/dist/{chunk-63E37JCN.js.map → chunk-4RAJT5L2.js.map} +0 -0
  428. /package/dist/{chunk-45VUHDV2.js.map → chunk-5CO5G4MN.js.map} +0 -0
  429. /package/dist/{chunk-LUJCQQ3L.js.map → chunk-65HWAQ4F.js.map} +0 -0
  430. /package/dist/{chunk-T67LUYCR.js.map → chunk-77NTFICT.js.map} +0 -0
  431. /package/dist/{chunk-UE6RRXMF.js.map → chunk-A4F7OIC5.js.map} +0 -0
  432. /package/dist/{chunk-RRJBDXAQ.js.map → chunk-B377OKUP.js.map} +0 -0
  433. /package/dist/{chunk-Z7JIZ42P.js.map → chunk-BN2EBCLB.js.map} +0 -0
  434. /package/dist/{chunk-YYOMGOHB.js.map → chunk-BOK6BN5M.js.map} +0 -0
  435. /package/dist/{chunk-U6UNF5ZS.js.map → chunk-BPK32FRM.js.map} +0 -0
  436. /package/dist/{chunk-OH7QLI6W.js.map → chunk-BPPUH5JM.js.map} +0 -0
  437. /package/dist/{chunk-O6ZSWHVR.js.map → chunk-C2KE5DMD.js.map} +0 -0
  438. /package/dist/{chunk-47F6WWLQ.js.map → chunk-C73N66PR.js.map} +0 -0
  439. /package/dist/{chunk-WRT7GJ2D.js.map → chunk-CIWMTNHW.js.map} +0 -0
  440. /package/dist/{chunk-HF3BKUVV.js.map → chunk-CL4JU3DF.js.map} +0 -0
  441. /package/dist/{chunk-O55EKIEC.js.map → chunk-D3ZKHLN2.js.map} +0 -0
  442. /package/dist/{chunk-ETZLQOUR.js.map → chunk-D5XG2KPS.js.map} +0 -0
  443. /package/dist/{chunk-CD4BCCNP.js.map → chunk-DJ7WVEWX.js.map} +0 -0
  444. /package/dist/{chunk-PWXPRVLK.js.map → chunk-DNY63QWJ.js.map} +0 -0
  445. /package/dist/{chunk-4CJTQHEG.js.map → chunk-ESLOLCD4.js.map} +0 -0
  446. /package/dist/{chunk-VILPVT4S.js.map → chunk-EZ47HOJ6.js.map} +0 -0
  447. /package/dist/{chunk-EFYN5I7Z.js.map → chunk-F4QFU5IZ.js.map} +0 -0
  448. /package/dist/{chunk-XYKBWTWI.js.map → chunk-FZZMLGWQ.js.map} +0 -0
  449. /package/dist/{chunk-FNXQZGUS.js.map → chunk-GBJUTX44.js.map} +0 -0
  450. /package/dist/{chunk-YLXETSAH.js.map → chunk-GCZJ7XRI.js.map} +0 -0
  451. /package/dist/{chunk-JV4S6VDH.js.map → chunk-ILY5SSOM.js.map} +0 -0
  452. /package/dist/{chunk-EXHXJETE.js.map → chunk-IQ55QGY5.js.map} +0 -0
  453. /package/dist/{chunk-4J363OAA.js.map → chunk-J7BIFOYP.js.map} +0 -0
  454. /package/dist/{chunk-QFEDITXM.js.map → chunk-JNDMIAJ4.js.map} +0 -0
  455. /package/dist/{chunk-E5PPE4VA.js.map → chunk-K2VRKCPA.js.map} +0 -0
  456. /package/dist/{chunk-MKRYQROF.js.map → chunk-LGEHAQHK.js.map} +0 -0
  457. /package/dist/{chunk-XYTQJD7F.js.map → chunk-LMJVP5CM.js.map} +0 -0
  458. /package/dist/{chunk-E7YZXWIS.js.map → chunk-LNGELD2M.js.map} +0 -0
  459. /package/dist/{chunk-FQKBJJYB.js.map → chunk-LPV72KRQ.js.map} +0 -0
  460. /package/dist/{chunk-2LCRG2YV.js.map → chunk-M2XR6B6V.js.map} +0 -0
  461. /package/dist/{chunk-ZU5JDLOH.js.map → chunk-MMRTPH3J.js.map} +0 -0
  462. /package/dist/{chunk-TVIVY7KU.js.map → chunk-NED7IR7B.js.map} +0 -0
  463. /package/dist/{chunk-6F5MJFXY.js.map → chunk-NHVAX7MH.js.map} +0 -0
  464. /package/dist/{chunk-TG3R2SID.js.map → chunk-NMGHGTVR.js.map} +0 -0
  465. /package/dist/{chunk-NGHDW6UU.js.map → chunk-NUQEREIP.js.map} +0 -0
  466. /package/dist/{chunk-5IIQU4JZ.js.map → chunk-OB72KNMF.js.map} +0 -0
  467. /package/dist/{chunk-RIMK327Y.js.map → chunk-OUVYYKYU.js.map} +0 -0
  468. /package/dist/{chunk-RWGRSKN5.js.map → chunk-PT4DZDJA.js.map} +0 -0
  469. /package/dist/{chunk-7EPY3IQL.js.map → chunk-PZJQ46DH.js.map} +0 -0
  470. /package/dist/{chunk-MXHMNKWG.js.map → chunk-QDESY76F.js.map} +0 -0
  471. /package/dist/{chunk-E3A7ELSG.js.map → chunk-QHARXWTC.js.map} +0 -0
  472. /package/dist/{chunk-BLJT6JP2.js.map → chunk-QMFAMOT2.js.map} +0 -0
  473. /package/dist/{chunk-I6QGI65T.js.map → chunk-QRMG4HK4.js.map} +0 -0
  474. /package/dist/{chunk-ZU3NJNO7.js.map → chunk-QSF5SJAM.js.map} +0 -0
  475. /package/dist/{chunk-5IYOKDM4.js.map → chunk-R23JWJD3.js.map} +0 -0
  476. /package/dist/{chunk-P4WNBSTW.js.map → chunk-RNG7S3FY.js.map} +0 -0
  477. /package/dist/{chunk-ZGFLIK5H.js.map → chunk-SPAKBUJY.js.map} +0 -0
  478. /package/dist/{chunk-ER7XANP3.js.map → chunk-SQ3GEIEL.js.map} +0 -0
  479. /package/dist/{chunk-PMJFRDJI.js.map → chunk-SUTEBYGI.js.map} +0 -0
  480. /package/dist/{chunk-R6HMAIKM.js.map → chunk-TOSPNM4T.js.map} +0 -0
  481. /package/dist/{chunk-RMXS4I66.js.map → chunk-TVDJEUV5.js.map} +0 -0
  482. /package/dist/{chunk-PLCYKAWH.js.map → chunk-TYRWSE4B.js.map} +0 -0
  483. /package/dist/{chunk-IQWUACVG.js.map → chunk-UHMHJX5G.js.map} +0 -0
  484. /package/dist/{chunk-YODUDA6R.js.map → chunk-UN4RVUG2.js.map} +0 -0
  485. /package/dist/{chunk-E6Z4FBX6.js.map → chunk-V2QSNFCT.js.map} +0 -0
  486. /package/dist/{chunk-7W3RXOIG.js.map → chunk-WGGRZYSQ.js.map} +0 -0
  487. /package/dist/{chunk-RIZ5NUNN.js.map → chunk-WQ4XKIOX.js.map} +0 -0
  488. /package/dist/{chunk-QEYTRFR3.js.map → chunk-X26YOFGS.js.map} +0 -0
  489. /package/dist/{chunk-ITHZFHST.js.map → chunk-X2BVB74H.js.map} +0 -0
  490. /package/dist/{chunk-6F42QONS.js.map → chunk-X5HGU2EM.js.map} +0 -0
  491. /package/dist/{chunk-GVGAO3WV.js.map → chunk-XJ2S5UBF.js.map} +0 -0
  492. /package/dist/{chunk-IBJ6U753.js.map → chunk-XKZBZOKV.js.map} +0 -0
  493. /package/dist/{chunk-65AUYLU3.js.map → chunk-XPXHQI6N.js.map} +0 -0
  494. /package/dist/{chunk-HH5LY6RR.js.map → chunk-YIXJSW5M.js.map} +0 -0
  495. /package/dist/{chunk-2JSDPUKD.js.map → chunk-YMFPFXEX.js.map} +0 -0
  496. /package/dist/{chunk-N4KAE2NB.js.map → chunk-Z3FTSHT5.js.map} +0 -0
  497. /package/dist/{chunk-7GLJMDEQ.js.map → chunk-ZDV5YWID.js.map} +0 -0
  498. /package/dist/{chunk-645WOU5I.js.map → chunk-ZDZJNXL6.js.map} +0 -0
  499. /package/dist/{chunk-6TCXIRP5.js.map → chunk-ZKE4CO6B.js.map} +0 -0
  500. /package/dist/{contradiction-scan-P2MHYFVG.js.map → contradiction-scan-IBPYGQZF.js.map} +0 -0
  501. /package/dist/{resolution-N7H3F2E4.js.map → resolution-OVVIF7ZY.js.map} +0 -0
@@ -0,0 +1,194 @@
1
+ // Shutdown-signal behavioral tests for LocalLlmClient: a daemon stop must
2
+ // abort in-flight chat requests at once (the abort reaches the transport),
3
+ // must not start another attempt once aborted, and must not sit out the
4
+ // retry backoff after abort. Uses the globalThis.fetch seam from
5
+ // local-llm-qos.test.ts with a hanging transport so the real retry loop is
6
+ // exercised, not a mock of it.
7
+ import assert from "node:assert/strict";
8
+ import test from "node:test";
9
+
10
+ import { parseConfig } from "./config.js";
11
+ import { LocalLlmClient } from "./local-llm.js";
12
+ import { initLogger, resetLogger, type LoggerBackend } from "./logger.js";
13
+
14
+ /** Captured log lines with the logger's "remnic: " prefix stripped. */
15
+ interface CapturedLog {
16
+ lines: string[];
17
+ }
18
+
19
+ function createConfig(memoryDir: string) {
20
+ return parseConfig({
21
+ openaiApiKey: "sk-test",
22
+ memoryDir,
23
+ workspaceDir: `${memoryDir}/workspace`,
24
+ localLlmEnabled: true,
25
+ localLlmModel: "test-local-model",
26
+ localLlmUrl: "http://127.0.0.1:9",
27
+ // Mirror the production daemon: a 10-minute budget with 2 attempts, so
28
+ // an unhonored abort would outlive any sane test deadline.
29
+ localLlmTimeoutMs: 600_000,
30
+ localLlmRetry5xxCount: 1,
31
+ localLlmRetryBackoffMs: 30_000,
32
+ localLlmHeaders: {},
33
+ localLlm400TripThreshold: 3,
34
+ localLlm400CooldownMs: 60_000,
35
+ localLlmReasoningEffort: "none",
36
+ debug: false,
37
+ });
38
+ }
39
+
40
+ interface HangingFetchSpec {
41
+ calls: { signal: AbortSignal | undefined }[];
42
+ sawAbort: boolean;
43
+ /** Reject with AbortError after delayMs (timeout simulation); default hangs forever. */
44
+ timeoutAfterMs?: number;
45
+ /** Resolves when the transport stub is entered (request is in flight). */
46
+ entered: Promise<void>;
47
+ }
48
+
49
+ function installHangingFetch(spec: HangingFetchSpec): () => void {
50
+ const { promise: entered, resolve: markEntered } = Promise.withResolvers<void>();
51
+ spec.entered = entered;
52
+ const originalFetch = globalThis.fetch;
53
+ // SAFETY: the transport passes a string URL and an init with a signal;
54
+ // this async stub matches that call shape exactly.
55
+ globalThis.fetch = (async (url: string, init?: { signal?: AbortSignal }) => {
56
+ void url;
57
+ const signal = init?.signal;
58
+ spec.calls.push({ signal });
59
+ markEntered();
60
+ const { promise, reject } = Promise.withResolvers<Response>();
61
+ // A real transport rejects with AbortError when its signal aborts
62
+ // (undici behavior); the stub must honor it the same way or the client
63
+ // loop cannot observe the abort.
64
+ const onAbort = (): void => {
65
+ spec.sawAbort = true;
66
+ reject(new DOMException("This operation was aborted", "AbortError"));
67
+ };
68
+ if (signal) {
69
+ if (signal.aborted) onAbort();
70
+ else signal.addEventListener("abort", onAbort, { once: true });
71
+ }
72
+ if (spec.timeoutAfterMs !== undefined) {
73
+ const timer = setTimeout(() => {
74
+ signal?.removeEventListener("abort", onAbort);
75
+ reject(new DOMException("This operation was aborted", "AbortError"));
76
+ }, spec.timeoutAfterMs);
77
+ timer.unref?.();
78
+ }
79
+ return await promise;
80
+ }) as typeof fetch;
81
+ return () => {
82
+ globalThis.fetch = originalFetch;
83
+ };
84
+ }
85
+
86
+ /** Polls a real runtime condition (a log line, a stub entry) instead of a
87
+ * guessed fixed sleep: the condition, not a duration, gates progress. */
88
+ async function waitFor(
89
+ predicate: () => boolean,
90
+ description: string,
91
+ timeoutMs = 5_000,
92
+ ): Promise<void> {
93
+ const deadline = Date.now() + timeoutMs;
94
+ while (!predicate()) {
95
+ if (Date.now() > deadline) throw new Error(`condition not met: ${description}`);
96
+ await new Promise((resolve) => setTimeout(resolve, 10));
97
+ }
98
+ }
99
+
100
+ async function withTestDeadline<T>(promise: Promise<T>, timeoutMs: number, label: string): Promise<T> {
101
+ const { promise: deadline, reject } = Promise.withResolvers<never>();
102
+ const timer = setTimeout(() => reject(new Error(`${label}: test deadline exceeded (${timeoutMs}ms)`)), timeoutMs);
103
+ timer.unref?.();
104
+ try {
105
+ return await Promise.race([promise, deadline]);
106
+ } finally {
107
+ clearTimeout(timer);
108
+ }
109
+ }
110
+
111
+ function installRecordingLogger(): CapturedLog {
112
+ const lines: string[] = [];
113
+ const body = (msg: string) => msg.replace(/^remnic: /, "");
114
+ const backend: LoggerBackend = {
115
+ info: (msg) => lines.push(body(msg)),
116
+ warn: (msg) => lines.push(body(msg)),
117
+ error: (msg) => lines.push(body(msg)),
118
+ };
119
+ initLogger(backend, false, { timestamps: false });
120
+ return { lines };
121
+ }
122
+
123
+ function quietLogger(): void {
124
+ initLogger({ info() {}, warn() {}, error() {}, debug() {} }, false);
125
+ }
126
+
127
+ test("aborting the client shutdown signal aborts an in-flight request and reaches the transport stub", async () => {
128
+ quietLogger();
129
+ const spec: HangingFetchSpec = { calls: [], sawAbort: false, entered: Promise.resolve() };
130
+ const restoreFetch = installHangingFetch(spec);
131
+ try {
132
+ const controller = new AbortController();
133
+ const client = new LocalLlmClient(createConfig("/tmp/remnic-llm-shutdown-inflight"), undefined, controller.signal);
134
+ // SAFETY: availability is stubbed at the established field seam (same as
135
+ // local-llm-qos.test.ts) so the retry loop, not the network probe, runs.
136
+ const seams = client as any;
137
+ seams.isAvailable = true;
138
+ seams.lastHealthCheck = Date.now();
139
+
140
+ const pending = client.chatCompletion(
141
+ [{ role: "user", content: "shutdown abort in flight" }],
142
+ { operation: "extraction" },
143
+ );
144
+
145
+ await spec.entered;
146
+ controller.abort();
147
+
148
+ const result = await withTestDeadline(pending, 2_000, "in-flight abort");
149
+ assert.equal(result, null);
150
+ assert.equal(spec.calls.length, 1, "no second attempt may start after abort");
151
+ assert.equal(spec.sawAbort, true, "the abort signal must reach the transport stub");
152
+ assert.equal(spec.calls[0]?.signal?.aborted, true);
153
+ } finally {
154
+ restoreFetch();
155
+ resetLogger();
156
+ }
157
+ });
158
+
159
+ test("an abort during retry backoff ends the loop without sleeping it out or starting another attempt", async () => {
160
+ const { lines } = installRecordingLogger();
161
+ const spec: HangingFetchSpec = { calls: [], sawAbort: false, timeoutAfterMs: 20, entered: Promise.resolve() };
162
+ const restoreFetch = installHangingFetch(spec);
163
+ try {
164
+ const controller = new AbortController();
165
+ const client = new LocalLlmClient(createConfig("/tmp/remnic-llm-shutdown-backoff"), undefined, controller.signal);
166
+ // SAFETY: availability is stubbed at the established field seam (same as
167
+ // local-llm-qos.test.ts) so the retry loop, not the network probe, runs.
168
+ const seams = client as any;
169
+ seams.isAvailable = true;
170
+ seams.lastHealthCheck = Date.now();
171
+
172
+ const pending = client.chatCompletion(
173
+ [{ role: "user", content: "shutdown abort during backoff" }],
174
+ { operation: "extraction" },
175
+ );
176
+
177
+ // Sync point: the retry loop is in its 30s backoff when the backoff
178
+ // warn line lands; abort there.
179
+ await waitFor(
180
+ () => lines.some((line) => line.includes("retrying after 30000ms")),
181
+ "attempt 1 to fail and backoff to start",
182
+ );
183
+ controller.abort();
184
+
185
+ const startedAtMs = Date.now();
186
+ const result = await withTestDeadline(pending, 2_000, "backoff abort");
187
+ assert.equal(result, null);
188
+ assert.ok(Date.now() - startedAtMs < 1_500, "backoff must not be slept out after abort");
189
+ assert.equal(spec.calls.length, 1, "no second attempt may start after abort");
190
+ } finally {
191
+ restoreFetch();
192
+ resetLogger();
193
+ }
194
+ });
package/src/local-llm.ts CHANGED
@@ -20,6 +20,7 @@ import {
20
20
  type ProbeFetchResult,
21
21
  normalizeBackendTripReason,
22
22
  waitForRetryBackoff,
23
+ combineClientAbortSignals,
23
24
  SingleFlightProbe,
24
25
  type LocalLlmChatCompletionOptions,
25
26
  type LocalLlmChatCompletionResult,
@@ -201,10 +202,14 @@ export class LocalLlmClient {
201
202
  private static readonly HEALTH_CHECK_INTERVAL_MS = 60000; // 1 minute
202
203
  private static readonly LMS_CACHE_INTERVAL_MS = 30000; // 30 seconds
203
204
  private readonly chatTransport = new ChatTransport();
205
+ /** Orchestrator-owned stop signal: aborts every in-flight and queued
206
+ * request (and their retry backoffs) the moment teardown begins. */
207
+ private readonly shutdownSignal: AbortSignal | undefined;
204
208
 
205
- constructor(config: PluginConfig, modelRegistry?: ModelRegistry) {
209
+ constructor(config: PluginConfig, modelRegistry?: ModelRegistry, shutdownSignal?: AbortSignal) {
206
210
  this.config = config;
207
211
  this.modelRegistry = modelRegistry;
212
+ this.shutdownSignal = shutdownSignal;
208
213
  }
209
214
 
210
215
  /**
@@ -829,7 +834,7 @@ export class LocalLlmClient {
829
834
 
830
835
  private async runQueuedRequest(next: LocalLlmQueuedRequest): Promise<void> {
831
836
  try {
832
- if (next.options.signal?.aborted) {
837
+ if (combineClientAbortSignals(next.options.signal, this.shutdownSignal)?.aborted) {
833
838
  next.resolve(null);
834
839
  return;
835
840
  }
@@ -879,8 +884,9 @@ export class LocalLlmClient {
879
884
  }
880
885
 
881
886
  try {
882
- if (options.signal?.aborted) return null;
883
- const isAvailable = await this.checkAvailability(options.signal);
887
+ const signal = combineClientAbortSignals(options.signal, this.shutdownSignal);
888
+ if (signal?.aborted) return null;
889
+ const isAvailable = await this.checkAvailability(signal);
884
890
  if (!isAvailable) {
885
891
  log.debug(
886
892
  `local LLM: checkAvailability returned false for ${this.config.localLlmUrl}`,
@@ -977,7 +983,7 @@ export class LocalLlmClient {
977
983
  response = null;
978
984
  responseBody = "";
979
985
  // Wait out the shared endpoint backoff, then take a concurrency slot.
980
- const gate = await rateLimit.beforeAttempt(options.signal);
986
+ const gate = await rateLimit.beforeAttempt(signal);
981
987
  if (gate.kind === "skip") {
982
988
  log.warn(gate.reason === "queue"
983
989
  ? `local LLM concurrency queue exceeded the ${effectiveTimeoutMs}ms request budget; skipping request (op=${operation})`
@@ -989,24 +995,25 @@ export class LocalLlmClient {
989
995
  if (gate.kind === "aborted") return null;
990
996
  const attemptAbort = new AbortController();
991
997
  const onCallerAbort = (): void => {
992
- attemptAbort.abort(options.signal?.reason);
998
+ attemptAbort.abort(signal?.reason);
993
999
  };
994
- if (options.signal) {
995
- if (options.signal.aborted) {
1000
+ if (signal) {
1001
+ if (signal.aborted) {
996
1002
  onCallerAbort();
997
1003
  } else {
998
- options.signal.addEventListener("abort", onCallerAbort, { once: true });
1004
+ signal.addEventListener("abort", onCallerAbort, { once: true });
999
1005
  }
1000
1006
  }
1001
1007
  const attemptTimeout = setTimeout(() => attemptAbort.abort(), effectiveTimeoutMs);
1008
+ const postAttempt = (bodyJson: string): Promise<Response> => this.chatTransport.post({
1009
+ url: chatUrl,
1010
+ headers: this.buildRequestHeaders({ "Content-Type": "application/json" }),
1011
+ body: bodyJson,
1012
+ signal: attemptAbort.signal,
1013
+ budgetMs: this.config.localLlmTimeoutMs,
1014
+ });
1002
1015
  try {
1003
- response = await this.chatTransport.post({
1004
- url: chatUrl,
1005
- headers: this.buildRequestHeaders({ "Content-Type": "application/json" }),
1006
- body: requestBodyJson,
1007
- signal: attemptAbort.signal,
1008
- budgetMs: this.config.localLlmTimeoutMs,
1009
- });
1016
+ response = await postAttempt(requestBodyJson);
1010
1017
  responseBody = await response.text();
1011
1018
  if (
1012
1019
  response.status === 400 &&
@@ -1019,18 +1026,12 @@ export class LocalLlmClient {
1019
1026
  requestBodyJson = JSON.stringify(requestBody);
1020
1027
  log.debug("local LLM rejected native JSON schema; retrying without it");
1021
1028
  response = null;
1022
- response = await this.chatTransport.post({
1023
- url: chatUrl,
1024
- headers: this.buildRequestHeaders({ "Content-Type": "application/json" }),
1025
- body: requestBodyJson,
1026
- signal: attemptAbort.signal,
1027
- budgetMs: this.config.localLlmTimeoutMs,
1028
- });
1029
+ response = await postAttempt(requestBodyJson);
1029
1030
  responseBody = await response.text();
1030
1031
  }
1031
1032
  } catch (err) {
1032
1033
  const error = err instanceof Error ? err : new Error(String(err));
1033
- if (options.signal?.aborted) {
1034
+ if (signal?.aborted) {
1034
1035
  response = null;
1035
1036
  lastAbortError = error;
1036
1037
  break;
@@ -1046,12 +1047,12 @@ export class LocalLlmClient {
1046
1047
  log.warn(
1047
1048
  `local LLM request aborted: op=${operation} attempt=${attempt}/${maxAttempts} timeoutMs=${effectiveTimeoutMs} model=${this.config.localLlmModel}; retrying after ${backoffMs}ms`,
1048
1049
  );
1049
- if (!(await waitForRetryBackoff(backoffMs, options.signal))) return null;
1050
+ if (!(await waitForRetryBackoff(backoffMs, signal))) return null;
1050
1051
  continue;
1051
1052
  }
1052
1053
  } finally {
1053
1054
  clearTimeout(attemptTimeout);
1054
- options.signal?.removeEventListener("abort", onCallerAbort);
1055
+ signal?.removeEventListener("abort", onCallerAbort);
1055
1056
  gate.release();
1056
1057
  }
1057
1058
 
@@ -1085,7 +1086,7 @@ export class LocalLlmClient {
1085
1086
  log.warn(
1086
1087
  `local LLM request got ${response.status}; retrying (attempt ${attempt + 1}/${maxAttempts}) after ${backoffMs}ms`,
1087
1088
  );
1088
- if (!(await waitForRetryBackoff(backoffMs, options.signal))) return null;
1089
+ if (!(await waitForRetryBackoff(backoffMs, signal))) return null;
1089
1090
  }
1090
1091
  log.debug(
1091
1092
  `local LLM: received response, status=${response?.status}, ok=${response?.ok}`,
@@ -1401,13 +1402,14 @@ export class LocalLlmClient {
1401
1402
  }
1402
1403
  if (options.priority) {
1403
1404
  const priority = options.priority;
1405
+ const signal = combineClientAbortSignals(options.signal, this.shutdownSignal);
1404
1406
  return await new Promise<LocalLlmChatCompletionResult | null>((resolve) => {
1405
1407
  let settled = false;
1406
1408
  let onAbort: (() => void) | undefined;
1407
1409
  const finish = (value: LocalLlmChatCompletionResult | null): void => {
1408
1410
  if (settled) return;
1409
1411
  settled = true;
1410
- if (onAbort) options.signal?.removeEventListener("abort", onAbort);
1412
+ if (onAbort) signal?.removeEventListener("abort", onAbort);
1411
1413
  resolve(value);
1412
1414
  };
1413
1415
  const queued: LocalLlmQueuedRequest = {
@@ -1424,8 +1426,8 @@ export class LocalLlmClient {
1424
1426
  finish(null);
1425
1427
  };
1426
1428
  this.requestQueues[priority].push(queued);
1427
- if (options.signal?.aborted) onAbort();
1428
- else if (options.signal) options.signal.addEventListener("abort", onAbort, { once: true });
1429
+ if (signal?.aborted) onAbort();
1430
+ else if (signal) signal.addEventListener("abort", onAbort, { once: true });
1429
1431
  this.scheduleQueueDrain();
1430
1432
  });
1431
1433
  }
@@ -113,6 +113,10 @@ export interface ExtractionRunCoordinatorDeps {
113
113
  * threshold and honors a foreground-opened breaker (review round).
114
114
  */
115
115
  providerBreaker?: ProviderCircuitBreaker;
116
+ /** Orchestrator-owned stop signal, combined into every extraction run's
117
+ * abort signal: queued tasks never start and in-flight runs abort the
118
+ * moment destroy() begins. Absent for standalone coordinators (tests). */
119
+ shutdownSignal?: AbortSignal;
116
120
  }
117
121
 
118
122
  // Recall/extraction abort helpers live in orchestrator-helpers.ts since
@@ -692,11 +696,16 @@ export class ExtractionRunCoordinator {
692
696
  typeof deadlineMs === "number" && Number.isFinite(deadlineMs)
693
697
  ? new AbortController()
694
698
  : undefined;
699
+ const shutdownSignal = this.deps.shutdownSignal;
700
+ const callerAbortSignal =
701
+ options.abortSignal && shutdownSignal
702
+ ? AbortSignal.any([options.abortSignal, shutdownSignal])
703
+ : (options.abortSignal ?? shutdownSignal);
695
704
  const extractionAbortSignal = extractionDeadlineController
696
- ? options.abortSignal
697
- ? AbortSignal.any([options.abortSignal, extractionDeadlineController.signal])
705
+ ? callerAbortSignal
706
+ ? AbortSignal.any([callerAbortSignal, extractionDeadlineController.signal])
698
707
  : extractionDeadlineController.signal
699
- : options.abortSignal;
708
+ : callerAbortSignal;
700
709
  let extractionDeadlineTimer: NodeJS.Timeout | undefined;
701
710
  const clearExtractionDeadlineTimer = (): void => {
702
711
  if (extractionDeadlineTimer) {
@@ -1,6 +1,10 @@
1
1
  import path from "node:path";
2
2
  import { serializeMutations, withHeldFileLock } from "../utils/serialize-mutations.js";
3
- import { ContentHashIndex, type StorageManager } from "../index.js";
3
+ // Import from the real modules, NOT the ../index.js barrel: a barrel edge
4
+ // from orchestration code that explicit-capture.ts imports re-orders module
5
+ // initialization and leaves access-boundary's registry in TDZ (#3354).
6
+ import { ContentHashIndex } from "../storage/content-hash-index.js";
7
+ import type { StorageManager } from "../storage.js";
4
8
  import type { MemoryFile } from "../types.js";
5
9
  import { normalizeStoredHashSource } from "./extraction-persist-citation.js";
6
10
  import { stripAttributesSuffix } from "../structured-attributes.js";
@@ -1331,8 +1331,10 @@ test("#1909 round 11: the restart rebuild reflects the current corpus (archived
1331
1331
  test("#1909 round 11 finding 2: destroy() flushes the debounced buffer BEFORE catalog touches", async () => {
1332
1332
  // The buffer save fires a coalesced namespace-catalog touch; if catalog touches
1333
1333
  // were flushed first, that shutdown-time touch would queue after and be lost.
1334
- // destroy() must flush the buffer first so its touch folds into the catalog
1335
- // flush and both settle before destroy() returns.
1334
+ // destroy() flushes the buffer before the extraction drain and again after it
1335
+ // (post-drain removals); every buffer flush must run before the one catalog
1336
+ // flush so each shutdown-time touch folds into it and settles before destroy()
1337
+ // returns.
1336
1338
  const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-destroy-order-"));
1337
1339
  const config = parseConfig({
1338
1340
  openaiApiKey: "sk-test",
@@ -1363,10 +1365,12 @@ test("#1909 round 11 finding 2: destroy() flushes the debounced buffer BEFORE ca
1363
1365
 
1364
1366
  await priv.destroy();
1365
1367
  assert.deepEqual(
1366
- order,
1367
- ["buffer", "catalog"],
1368
- "buffer flush must run before the catalog-touch flush on shutdown",
1368
+ order.filter((step) => step === "catalog"),
1369
+ ["catalog"],
1370
+ "the catalog-touch flush runs exactly once",
1369
1371
  );
1372
+ assert.equal(order.at(-1), "catalog", "no buffer flush may run after the catalog-touch flush");
1373
+ assert.ok(order.includes("buffer"), "destroy() flushes the buffer");
1370
1374
  });
1371
1375
  test("#1909 round 14: destroy() surfaces a buffer flush failure and still completes teardown", async () => {
1372
1376
  // Graceful-shutdown durability contract: a failed shutdown buffer flush must
@@ -739,6 +739,9 @@ export class Orchestrator {
739
739
  private _dependencyPropagationRecovery: Promise<void> | null = null;
740
740
  private destroyed = false;
741
741
  private acceptingEntityMigrationMaintenance = true;
742
+ /** Aborted at the start of destroy(); stops every local-LLM client and extraction task at once. */
743
+ private readonly shutdownController = new AbortController();
744
+ readonly shutdownSignal: AbortSignal = this.shutdownController.signal;
742
745
 
743
746
  private get dependencyPropagationDelivery(): DependencyPropagationDelivery {
744
747
  if (this.destroyed) throw new Error("orchestrator has been destroyed");
@@ -770,9 +773,8 @@ export class Orchestrator {
770
773
  return this._providerBreaker;
771
774
  }
772
775
 
773
- /** The run-coordinator deps bundle, parameterized by its buffer accessor so
774
- * an isolated claim-backed drain can bind its own SmartBuffer (the daemon
775
- * backlog scheduler) while live extraction keeps `this.buffer`. */
776
+ /** The run-coordinator deps bundle, parameterized by its buffer accessor:
777
+ * an isolated claim-backed drain binds its own SmartBuffer (backlog scheduler). */
776
778
  private extractionRunDeps(getBuffer: () => SmartBuffer): ExtractionRunCoordinatorDeps {
777
779
  return {
778
780
  config: this.config,
@@ -795,9 +797,26 @@ export class Orchestrator {
795
797
  runTierMigrationCycle: (storage, trigger, options) => this.runTierMigrationCycle(storage, trigger, options),
796
798
  recordProcessedExtractionFingerprint: (storage, fingerprint, preloadedMeta) =>
797
799
  this.recordProcessedExtractionFingerprint(storage, fingerprint, preloadedMeta),
800
+ shutdownSignal: this.shutdownSignal,
798
801
  };
799
802
  }
800
803
 
804
+ /** Fast-tier client: low latency at all costs, thinking always suppressed. */
805
+ private buildFastLlm(config: PluginConfig): LocalLlmClient {
806
+ const client = new LocalLlmClient(
807
+ {
808
+ ...config,
809
+ localLlmModel: config.localLlmFastModel || config.localLlmModel,
810
+ localLlmUrl: config.localLlmFastUrl,
811
+ localLlmTimeoutMs: config.localLlmFastTimeoutMs,
812
+ },
813
+ this.modelRegistry,
814
+ this.shutdownSignal,
815
+ );
816
+ client.disableThinking = true;
817
+ return client;
818
+ }
819
+
801
820
  private get extractionRunCoordinator(): ExtractionRunCoordinator {
802
821
  if (!this._extractionRunCoordinator) {
803
822
  this._extractionRunCoordinator = new ExtractionRunCoordinator(this.extractionRunDeps(() => this.buffer));
@@ -983,6 +1002,8 @@ export class Orchestrator {
983
1002
  * commands should call it before returning to let Node exit naturally.
984
1003
  */
985
1004
  async destroy(): Promise<void> {
1005
+ // First, always: every client and extraction task holds this signal.
1006
+ this.shutdownController.abort();
986
1007
  this.acceptingEntityMigrationMaintenance = false;
987
1008
  this._orchestratorInitCoordinator?.retireStartupEpoch();
988
1009
  this.abortDeferredInit();
@@ -996,23 +1017,29 @@ export class Orchestrator {
996
1017
  await this.maintenanceScheduler.dispose();
997
1018
  await this._dependencyPropagationRecovery;
998
1019
  this._dependencyPropagationRecovery = null;
1020
+ // Persist unsent turns BEFORE the extraction drain: buffered turns must
1021
+ // already be on disk when shutdown abandons or bounds the drain's wait.
1022
+ let bufferFlushError: unknown;
1023
+ try {
1024
+ await this.buffer.flushPendingSave({ throwOnFailure: true });
1025
+ } catch (err) {
1026
+ bufferFlushError = err;
1027
+ }
999
1028
  const extractionDrainError = await drainExtractionAndShutdownDependencyPropagation(
1000
1029
  this.extractionQueueCoordinator,
1001
1030
  this._dependencyPropagationDelivery,
1002
1031
  );
1032
+ // After the drain, never before: an extraction already in its persist
1033
+ // stage reads dependencyPropagationDelivery, and this flag gates that
1034
+ // getter ("orchestrator has been destroyed").
1003
1035
  this.destroyed = true;
1004
1036
  this._dependencyPropagationDelivery = undefined;
1037
+ // Persist post-drain removals; a failed write stays pending for next boot.
1038
+ await this.buffer.flushPendingSave().catch(() => undefined);
1005
1039
  await drainRecallWrites(this);
1006
1040
  await this.persistenceIndexCoordinator
1007
1041
  .drainContentHashReconcileRetries()
1008
1042
  .catch((err) => log.warn(`content-hash reconcile drain failed during destroy: ${err}`));
1009
- // Save buffered turns before catalog flush; rethrow save failures after teardown.
1010
- let bufferFlushError: unknown;
1011
- try {
1012
- await this.buffer.flushPendingSave({ throwOnFailure: true });
1013
- } catch (err) {
1014
- bufferFlushError = err;
1015
- }
1016
1043
  try {
1017
1044
  // Flush catalog touches before backend disposal.
1018
1045
  await this.namespaceCatalog.flushPendingTouches().catch(() => undefined);
@@ -1668,35 +1695,16 @@ export class Orchestrator {
1668
1695
  config.gatewayConfig,
1669
1696
  this.modelRegistry,
1670
1697
  this.transcript,
1698
+ this.shutdownSignal,
1671
1699
  );
1672
1700
  this.judgeVerdictCache = createVerdictCache();
1673
1701
  this.judgeDeferCounts = createDeferCountMap();
1674
- this.localLlm = new LocalLlmClient(config, this.modelRegistry);
1675
- // Issue #548: the main local-LLM client is used by extraction,
1676
- // consolidation, and other structured-output tasks that gain
1677
- // nothing from chain-of-thought reasoning. Apply the operator's
1678
- // configured preference (default true) so thinking-capable models
1679
- // skip reasoning tokens and avoid the common 60s extraction
1680
- // timeout. Operators can set `localLlmDisableThinking: false`
1681
- // when they want thinking enabled for narrative paths.
1702
+ this.localLlm = new LocalLlmClient(config, this.modelRegistry, this.shutdownSignal);
1703
+ // Operator-controlled thinking suppression for structured-output ops;
1704
+ // full rationale on THINKING_SUPPRESSED_OPERATIONS in local-llm.ts (issue #548).
1682
1705
  this.localLlm.disableThinking = config.localLlmDisableThinking;
1683
1706
  this.fastLlm = resolvePipelineProcessingCapabilities(this.config).localLlmFast
1684
- ? (() => {
1685
- const client = new LocalLlmClient(
1686
- {
1687
- ...config,
1688
- localLlmModel: config.localLlmFastModel || config.localLlmModel,
1689
- localLlmUrl: config.localLlmFastUrl,
1690
- localLlmTimeoutMs: config.localLlmFastTimeoutMs,
1691
- },
1692
- this.modelRegistry,
1693
- );
1694
- // Fast-tier always suppresses thinking — the contract of
1695
- // `fastLlm` is "low latency at all costs" and that is
1696
- // independent of the main-client config.
1697
- client.disableThinking = true;
1698
- return client;
1699
- })()
1707
+ ? this.buildFastLlm(config)
1700
1708
  : this.localLlm;
1701
1709
  this.semanticConsolidationCoordinator = new SemanticConsolidationCoordinator({
1702
1710
  config,
@@ -1715,11 +1723,7 @@ export class Orchestrator {
1715
1723
  )
1716
1724
  : null;
1717
1725
  if (config.modelSource === "gateway") {
1718
- log.debug(
1719
- `orchestrator: gateway model source active` +
1720
- (config.gatewayAgentId ? ` (primary: ${config.gatewayAgentId})` : "") +
1721
- (config.fastGatewayAgentId ? ` (fast: ${config.fastGatewayAgentId})` : ""),
1722
- );
1726
+ log.debug(`orchestrator: gateway model source active (primary: ${config.gatewayAgentId ?? "none"}, fast: ${config.fastGatewayAgentId ?? "none"})`);
1723
1727
  }
1724
1728
  this.extraction = new ExtractionEngine(
1725
1729
  config,
@@ -1973,18 +1977,11 @@ export class Orchestrator {
1973
1977
  };
1974
1978
  }
1975
1979
 
1976
- /**
1977
- * Build a briefing follow-up generator backed by the configured LLM chain
1978
- * (gateway model source or local LLM). Returns `undefined` when no chain
1979
- * is available so `buildBriefing` can surface a clear unavailable reason
1980
- * instead of failing at call time. Used by the access service and CLI as
1981
- * the fallback when no direct `openaiApiKey` is configured, so briefing
1982
- * follow-ups ride the same routing as every other fast-tier LLM feature.
1983
- */
1980
+ /** Briefing follow-up generator over the configured LLM chain, or
1981
+ * `undefined` when no chain is available (see buildBriefing). */
1984
1982
  get briefingChainFollowupGenerator(): BriefingFollowupGenerator | undefined {
1985
- // Plugin mode gates on `localLlmEnabled` alone: `LocalLlmClient.chatCompletion`
1986
- // returns null when the master switch is off, so `localLlmFastEnabled` by
1987
- // itself cannot serve requests (Cursor review on PR #1463).
1983
+ // Plugin mode gates on `localLlmEnabled` alone: chatCompletion returns
1984
+ // null when the master switch is off (Cursor review on PR #1463).
1988
1985
  const chainAvailable =
1989
1986
  this.config.modelSource === "gateway"
1990
1987
  ? this._fastGatewayLlm?.isAvailable(