@remnic/core 9.57.5 → 9.58.0

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 (476) hide show
  1. package/dist/access-admin-ops-surface.d.ts +12 -11
  2. package/dist/access-admin-ops-surface.js +25 -24
  3. package/dist/access-authorization-probe.d.ts +12 -11
  4. package/dist/access-authorization-probe.js +26 -25
  5. package/dist/access-boundary.d.ts +12 -11
  6. package/dist/access-boundary.js +25 -24
  7. package/dist/access-cli.js +77 -76
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-coding-context-resolution.d.ts +1 -1
  10. package/dist/access-extraction-force-flush.d.ts +12 -11
  11. package/dist/access-extraction-force-flush.js +25 -24
  12. package/dist/access-health-types.d.ts +1 -1
  13. package/dist/access-http-lcm-compaction.d.ts +12 -11
  14. package/dist/access-http-lifecycle-flush.d.ts +12 -11
  15. package/dist/access-http-offline-stream.d.ts +12 -11
  16. package/dist/access-http-query.js +25 -24
  17. package/dist/access-http.d.ts +13 -12
  18. package/dist/access-http.js +36 -35
  19. package/dist/access-identity-continuity-surface.d.ts +10 -9
  20. package/dist/access-identity-continuity-surface.js +25 -24
  21. package/dist/access-lcm-surface.d.ts +12 -11
  22. package/dist/access-lcm-surface.js +25 -24
  23. package/dist/access-mcp.d.ts +12 -11
  24. package/dist/access-mcp.js +32 -31
  25. package/dist/access-memory-search-fanout.d.ts +2 -2
  26. package/dist/{access-namespace-preflight-Bpt-SYP0.d.ts → access-namespace-preflight-TBXz-8s_.d.ts} +1 -1
  27. package/dist/access-namespace-preflight.d.ts +3 -3
  28. package/dist/access-namespace-preflight.js +25 -24
  29. package/dist/access-observe-write-surface.d.ts +12 -11
  30. package/dist/access-observe-write-surface.js +25 -24
  31. package/dist/access-offline-manifest.d.ts +10 -9
  32. package/dist/access-operations-batch.js +27 -26
  33. package/dist/access-operations.d.ts +15 -14
  34. package/dist/access-operations.js +31 -30
  35. package/dist/access-recall-concurrency.d.ts +12 -11
  36. package/dist/access-recall-concurrency.js +25 -24
  37. package/dist/access-recall-response.d.ts +12 -11
  38. package/dist/access-recall-response.js +25 -24
  39. package/dist/access-recall-surface.d.ts +12 -11
  40. package/dist/access-recall-surface.js +25 -24
  41. package/dist/access-schema.d.ts +88 -88
  42. package/dist/access-schema.js +3 -3
  43. package/dist/{access-service-D9xXmKvd.d.ts → access-service-BQkRul4d.d.ts} +71 -71
  44. package/dist/access-service-helpers.d.ts +12 -11
  45. package/dist/access-service.d.ts +12 -11
  46. package/dist/access-service.js +25 -24
  47. package/dist/access-surface-catalog.d.ts +12 -11
  48. package/dist/access-surface-catalog.js +27 -26
  49. package/dist/access-surface-catalog.js.map +1 -1
  50. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  51. package/dist/action-confidence.d.ts +1 -1
  52. package/dist/active-memory-bridge.d.ts +1 -1
  53. package/dist/active-recall.d.ts +1 -1
  54. package/dist/active-recall.js +1 -1
  55. package/dist/ambient-provenance.d.ts +1 -1
  56. package/dist/artifact-search.d.ts +1 -1
  57. package/dist/behavior-learner.d.ts +1 -1
  58. package/dist/behavior-signals.d.ts +1 -1
  59. package/dist/bootstrap.d.ts +10 -9
  60. package/dist/briefing-window.d.ts +2 -2
  61. package/dist/briefing.d.ts +2 -2
  62. package/dist/briefing.js +10 -10
  63. package/dist/buffer-surprise-report.d.ts +1 -1
  64. package/dist/buffer-surprise.js +4 -3
  65. package/dist/buffer-turn-helpers.d.ts +1 -1
  66. package/dist/buffer.d.ts +2 -2
  67. package/dist/bulk-import/index.d.ts +3 -3
  68. package/dist/calibration.d.ts +1 -1
  69. package/dist/capabilities.d.ts +1 -1
  70. package/dist/{capsule-crypto-YO5QJ6L3.js → capsule-crypto-GWVG7LGC.js} +2 -2
  71. package/dist/{catalog-BasnO3Bw.d.ts → catalog-z1UerMbh.d.ts} +1 -1
  72. package/dist/causal-behavior.d.ts +2 -1
  73. package/dist/causal-consolidation.d.ts +1 -1
  74. package/dist/causal-consolidation.js +14 -13
  75. package/dist/causal-consolidation.js.map +1 -1
  76. package/dist/causal-trajectory-graph.d.ts +1 -1
  77. package/dist/{chunk-P4BC54KI.js → chunk-2GBFKHBZ.js} +14 -38
  78. package/dist/chunk-2GBFKHBZ.js.map +1 -0
  79. package/dist/{chunk-YTZA7U6Q.js → chunk-2VHCLHZ5.js} +3 -3
  80. package/dist/{chunk-NEJQ65NV.js → chunk-4CLE2LXB.js} +2 -2
  81. package/dist/{chunk-3VFVQDZO.js → chunk-4IIKJOYM.js} +1 -1
  82. package/dist/{chunk-3VFVQDZO.js.map → chunk-4IIKJOYM.js.map} +1 -1
  83. package/dist/{chunk-JLNBQWZ2.js → chunk-5JMAGU26.js} +7 -6
  84. package/dist/{chunk-JLNBQWZ2.js.map → chunk-5JMAGU26.js.map} +1 -1
  85. package/dist/{chunk-VDX2J7OX.js → chunk-5W7CTZ2E.js} +4 -4
  86. package/dist/{chunk-CZUHNJHX.js → chunk-6C7Q6NG3.js} +13 -13
  87. package/dist/chunk-6TBIWIAG.js +201 -0
  88. package/dist/chunk-6TBIWIAG.js.map +1 -0
  89. package/dist/{chunk-4O6R3GPK.js → chunk-6W2ISYUV.js} +4 -4
  90. package/dist/{chunk-3AJOJOFP.js → chunk-77DAFTUU.js} +3 -3
  91. package/dist/{chunk-IKT6ZVO7.js → chunk-7DHFB5SG.js} +3 -3
  92. package/dist/{chunk-SFR7J2G6.js → chunk-7G34CBKS.js} +2 -2
  93. package/dist/{chunk-IT57AOMC.js → chunk-AH2NX6S7.js} +3 -3
  94. package/dist/{chunk-HYQJQGD3.js → chunk-AM4T6CHX.js} +49 -35
  95. package/dist/chunk-AM4T6CHX.js.map +1 -0
  96. package/dist/{chunk-Z54EM5YZ.js → chunk-B2QHVLJO.js} +60 -30
  97. package/dist/chunk-B2QHVLJO.js.map +1 -0
  98. package/dist/{chunk-FI3PIOOI.js → chunk-B4CSPFYN.js} +8 -8
  99. package/dist/{chunk-7PJARJS4.js → chunk-BPM6UHUL.js} +2 -2
  100. package/dist/{chunk-PPUTUOC3.js → chunk-BTHDQOF4.js} +5 -5
  101. package/dist/{chunk-AW4A4XOP.js → chunk-CZGOLAEW.js} +41 -41
  102. package/dist/{chunk-5PGYCWA7.js → chunk-DE6YCZEE.js} +2 -2
  103. package/dist/{chunk-JOA4Q765.js → chunk-EUYWQ7TS.js} +2 -2
  104. package/dist/{chunk-O5AFC5KM.js → chunk-EWL5DICB.js} +2 -2
  105. package/dist/{chunk-4YZCIK5E.js → chunk-EZXGJJXM.js} +2 -2
  106. package/dist/{chunk-GXIY65UH.js → chunk-FI5EAP4N.js} +2 -2
  107. package/dist/{chunk-YOKSRIFI.js → chunk-FUWS2MNJ.js} +4 -4
  108. package/dist/{chunk-6RK2X7BR.js → chunk-G3JFFUKR.js} +2 -2
  109. package/dist/{chunk-VANZKHTN.js → chunk-G5OB4XZX.js} +4 -4
  110. package/dist/{chunk-66SLUXKM.js → chunk-HK6KYIF6.js} +2 -2
  111. package/dist/{chunk-XBGLEOID.js → chunk-I4BLRM7X.js} +9 -9
  112. package/dist/{chunk-5ZIWRMZM.js → chunk-IVKIODHO.js} +7 -6
  113. package/dist/chunk-IVKIODHO.js.map +1 -0
  114. package/dist/{chunk-6SX4MY5Q.js → chunk-J65AKOD6.js} +2 -2
  115. package/dist/{chunk-BPWZDHFM.js → chunk-J6QIAYNR.js} +2 -2
  116. package/dist/{chunk-XL3TATMJ.js → chunk-JHMAYABJ.js} +4 -4
  117. package/dist/{chunk-F7M36OG2.js → chunk-JNWISMYG.js} +10 -10
  118. package/dist/{chunk-VYIXCMUP.js → chunk-KBIIE57I.js} +3 -3
  119. package/dist/{chunk-QKPDN325.js → chunk-KF75ANST.js} +6 -3
  120. package/dist/chunk-KF75ANST.js.map +1 -0
  121. package/dist/{chunk-24PNX2GF.js → chunk-KXYMU4IN.js} +3 -3
  122. package/dist/{chunk-FKTD7IVS.js → chunk-L3JVAM5Q.js} +2 -2
  123. package/dist/{chunk-5QHDXMXP.js → chunk-LLZKOSGM.js} +1 -1
  124. package/dist/{chunk-5QHDXMXP.js.map → chunk-LLZKOSGM.js.map} +1 -1
  125. package/dist/{chunk-LIF6DO6U.js → chunk-MG7GI4TT.js} +2 -2
  126. package/dist/{chunk-RUZM6Z52.js → chunk-MMZK2DWN.js} +1 -1
  127. package/dist/{chunk-NTJ6TY44.js → chunk-ODAE36PG.js} +3 -3
  128. package/dist/{chunk-QFN4U7AG.js → chunk-ODZKV2F7.js} +3 -3
  129. package/dist/{chunk-QFN4U7AG.js.map → chunk-ODZKV2F7.js.map} +1 -1
  130. package/dist/{chunk-YLHM5BQQ.js → chunk-OLX2HJFW.js} +4 -4
  131. package/dist/{chunk-DNC4A7RS.js → chunk-OU7RWWW6.js} +2 -2
  132. package/dist/{chunk-L3LRWDJW.js → chunk-OV36CROW.js} +3 -3
  133. package/dist/{chunk-BXLOS5AJ.js → chunk-OWHERGF2.js} +2 -2
  134. package/dist/{chunk-CSV34HIW.js → chunk-P5OYNV7B.js} +2 -2
  135. package/dist/{chunk-SNW3YRO6.js → chunk-P6GOYLHN.js} +2 -2
  136. package/dist/{chunk-C5B3CIMJ.js → chunk-PFPNUFKZ.js} +109 -59
  137. package/dist/chunk-PFPNUFKZ.js.map +1 -0
  138. package/dist/{chunk-USGKHF36.js → chunk-QUJC22CT.js} +2 -2
  139. package/dist/{chunk-BVRREV3N.js → chunk-R7IV3EUJ.js} +2 -2
  140. package/dist/{chunk-KSXJOC4F.js → chunk-RDFF2NAU.js} +18 -8
  141. package/dist/chunk-RDFF2NAU.js.map +1 -0
  142. package/dist/{chunk-D4LVHPOA.js → chunk-RXN7Z2V5.js} +3 -3
  143. package/dist/{chunk-7VSHDLJQ.js → chunk-T2VJ2EO5.js} +6 -6
  144. package/dist/chunk-TOTT6S2V.js +20 -0
  145. package/dist/chunk-TOTT6S2V.js.map +1 -0
  146. package/dist/{chunk-U7BMN33M.js → chunk-UBSM6TZP.js} +2 -2
  147. package/dist/{chunk-DQEMWVMT.js → chunk-UVYI6VIX.js} +1 -1
  148. package/dist/{chunk-U7XLOSG2.js → chunk-VIM6QH4D.js} +2 -2
  149. package/dist/{chunk-LJJWFV2Q.js → chunk-VJXSAJFW.js} +2 -2
  150. package/dist/{chunk-HZC3OECF.js → chunk-VOKK4WCG.js} +2 -2
  151. package/dist/{chunk-LTAVSOZW.js → chunk-WVP2I6C5.js} +5 -4
  152. package/dist/chunk-WVP2I6C5.js.map +1 -0
  153. package/dist/{chunk-LRDP2AC2.js → chunk-YBCZTBN2.js} +2 -2
  154. package/dist/{chunk-USAUBGBC.js → chunk-YKZFX2HQ.js} +2 -2
  155. package/dist/{chunk-I2GIYTRU.js → chunk-ZOGOOSB3.js} +2 -2
  156. package/dist/{chunk-PBGWYM3H.js → chunk-ZPUIRTIZ.js} +27 -15
  157. package/dist/chunk-ZPUIRTIZ.js.map +1 -0
  158. package/dist/chunking.d.ts +3 -1
  159. package/dist/chunking.js +8 -3
  160. package/dist/{cli-DTOkYhKI.d.ts → cli-DsyVvOFP.d.ts} +5 -5
  161. package/dist/cli.d.ts +14 -13
  162. package/dist/cli.js +57 -56
  163. package/dist/coding/pre-action-gate.d.ts +1 -1
  164. package/dist/compounding/engine.d.ts +2 -2
  165. package/dist/compounding/engine.js +10 -10
  166. package/dist/compounding/preference-consolidator.d.ts +2 -1
  167. package/dist/compression-optimizer.d.ts +1 -1
  168. package/dist/config.d.ts +1 -1
  169. package/dist/config.js +1 -1
  170. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  171. package/dist/connectors/codex-materialize-runner.js +12 -11
  172. package/dist/connectors/codex-materialize.d.ts +7 -12
  173. package/dist/connectors/codex-materialize.js +2 -1
  174. package/dist/connectors/index.d.ts +1 -1
  175. package/dist/connectors/index.js +12 -11
  176. package/dist/consolidation-provenance-check.d.ts +2 -2
  177. package/dist/consolidation-undo.d.ts +2 -2
  178. package/dist/contradiction/index.d.ts +2 -2
  179. package/dist/contradiction/index.js +4 -4
  180. package/dist/converge-config.d.ts +1 -1
  181. package/dist/convergence-refresh.d.ts +2 -2
  182. package/dist/convergence-refresh.js +12 -12
  183. package/dist/conversation-index/backend.d.ts +1 -1
  184. package/dist/conversation-index/chunker.d.ts +1 -1
  185. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  186. package/dist/conversation-index/indexer.d.ts +1 -1
  187. package/dist/conversation-index/search.d.ts +1 -1
  188. package/dist/corpus-watermark.d.ts +1 -1
  189. package/dist/corpus-watermark.js +12 -12
  190. package/dist/day-summary.d.ts +1 -1
  191. package/dist/day-summary.js +3 -2
  192. package/dist/delinearize.d.ts +1 -1
  193. package/dist/dependency-propagation-config.d.ts +1 -1
  194. package/dist/{dependency-propagation-delivery-C_K_AHcv.d.ts → dependency-propagation-delivery-DdwSc1qh.d.ts} +1 -1
  195. package/dist/direct-answer-wiring.d.ts +1 -1
  196. package/dist/direct-answer.d.ts +1 -1
  197. package/dist/embedding-fallback.d.ts +1 -1
  198. package/dist/enrichment/index.d.ts +1 -1
  199. package/dist/entity-retrieval.d.ts +2 -2
  200. package/dist/entity-retrieval.js +10 -10
  201. package/dist/entity-schema.d.ts +1 -1
  202. package/dist/explicit-capture.d.ts +10 -9
  203. package/dist/external-wiki-access.d.ts +12 -11
  204. package/dist/external-wiki-access.js +26 -25
  205. package/dist/external-wiki-collection-registration.d.ts +1 -1
  206. package/dist/external-wiki-collection.d.ts +1 -1
  207. package/dist/external-wiki-mcp-tools.d.ts +12 -11
  208. package/dist/extraction-error-classification.d.ts +1 -1
  209. package/dist/extraction-faithfulness.d.ts +1 -1
  210. package/dist/extraction-judge-telemetry.d.ts +1 -1
  211. package/dist/extraction-judge-training.d.ts +1 -1
  212. package/dist/extraction-judge.d.ts +1 -1
  213. package/dist/extraction-liveness.d.ts +1 -1
  214. package/dist/extraction-normalization.d.ts +1 -1
  215. package/dist/extraction-prompt.d.ts +1 -1
  216. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  217. package/dist/extraction-source-grounding.d.ts +1 -1
  218. package/dist/extraction.d.ts +1 -1
  219. package/dist/extraction.js +16 -15
  220. package/dist/fallback-llm.d.ts +1 -1
  221. package/dist/graph-dashboard-diff.d.ts +1 -1
  222. package/dist/graph-dashboard-key.d.ts +1 -1
  223. package/dist/graph-dashboard-parser.d.ts +1 -1
  224. package/dist/graph-edge-reinforcement.d.ts +1 -1
  225. package/dist/graph-path-reconstruction.d.ts +1 -1
  226. package/dist/graph-path-scoring.d.ts +1 -1
  227. package/dist/graph-snapshot.d.ts +1 -1
  228. package/dist/graph.d.ts +1 -1
  229. package/dist/harmonic-retrieval.js +1 -1
  230. package/dist/importance.d.ts +1 -1
  231. package/dist/importers/index.d.ts +1 -1
  232. package/dist/in-flight-reads.d.ts +1 -1
  233. package/dist/index.d.ts +698 -697
  234. package/dist/index.js +81 -80
  235. package/dist/intent.d.ts +1 -1
  236. package/dist/lcm/archive.d.ts +3 -2
  237. package/dist/lcm/archive.js +2 -1
  238. package/dist/lcm/engine.d.ts +2 -1
  239. package/dist/lcm/engine.js +5 -4
  240. package/dist/lcm/index.d.ts +2 -1
  241. package/dist/lcm/index.js +7 -6
  242. package/dist/lcm/recall.d.ts +1 -0
  243. package/dist/lcm/summarizer.d.ts +1 -0
  244. package/dist/lcm/summarizer.js +3 -2
  245. package/dist/lcm/tools.d.ts +2 -1
  246. package/dist/lifecycle.d.ts +1 -1
  247. package/dist/live-connectors-runner.d.ts +1 -1
  248. package/dist/local-llm.d.ts +2 -3
  249. package/dist/local-llm.js +2 -1
  250. package/dist/local-model-endpoint.d.ts +1 -1
  251. package/dist/maintenance/memory-governance.d.ts +1 -1
  252. package/dist/maintenance/memory-governance.js +10 -10
  253. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  254. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -10
  255. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  256. package/dist/maintenance/rebuild-memory-projection.js +11 -11
  257. package/dist/{maintenance-DdP931i9.d.ts → maintenance-DvkiF7fm.d.ts} +3 -3
  258. package/dist/mcp-memory-inspector-app.d.ts +12 -11
  259. package/dist/memory-action-policy.d.ts +1 -1
  260. package/dist/memory-cache.d.ts +1 -1
  261. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  262. package/dist/memory-projection-store.d.ts +1 -1
  263. package/dist/memory-provenance.d.ts +1 -1
  264. package/dist/memory-snapshot.d.ts +1 -1
  265. package/dist/memory-worth-outcomes.d.ts +2 -2
  266. package/dist/models-json.d.ts +1 -1
  267. package/dist/namespaces/migrate.d.ts +3 -3
  268. package/dist/namespaces/migrate.js +11 -11
  269. package/dist/namespaces/principal.d.ts +1 -1
  270. package/dist/namespaces/search.d.ts +1 -1
  271. package/dist/namespaces/search.js +7 -7
  272. package/dist/namespaces/storage.d.ts +3 -3
  273. package/dist/namespaces/storage.js +10 -10
  274. package/dist/native-knowledge.d.ts +1 -1
  275. package/dist/offline-sync-impression-drain.d.ts +1 -1
  276. package/dist/operator-doctor-corpus.d.ts +1 -1
  277. package/dist/operator-doctor-corpus.js +13 -13
  278. package/dist/operator-doctor-replica.d.ts +1 -1
  279. package/dist/operator-toolkit.d.ts +3 -3
  280. package/dist/operator-toolkit.js +18 -18
  281. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  282. package/dist/orchestration/maintenance.d.ts +4 -4
  283. package/dist/orchestration/maintenance.js +15 -15
  284. package/dist/{orchestrator-DxUWX7gs.d.ts → orchestrator-CXPIzs3D.d.ts} +9 -9
  285. package/dist/orchestrator.d.ts +10 -9
  286. package/dist/orchestrator.js +77 -76
  287. package/dist/patterns-cli.d.ts +1 -1
  288. package/dist/{pipeline-BKUMU1vU.d.ts → pipeline-BuYWU9rt.d.ts} +1 -1
  289. package/dist/policy-runtime.d.ts +1 -1
  290. package/dist/proactive-contention.d.ts +1 -1
  291. package/dist/provenance.d.ts +1 -1
  292. package/dist/{public-http-C01DLhAp.d.ts → public-http-m9x1Qyzn.d.ts} +1 -1
  293. package/dist/{qmd-DJP-GLFe.d.ts → qmd-DYnrPw-m.d.ts} +1 -1
  294. package/dist/qmd-preflight.d.ts +2 -2
  295. package/dist/qmd-recall-cache.d.ts +1 -1
  296. package/dist/qmd.d.ts +2 -2
  297. package/dist/recall-concurrency-config.d.ts +1 -1
  298. package/dist/recall-disclosure-escalation.d.ts +1 -1
  299. package/dist/recall-explain-renderer.d.ts +1 -1
  300. package/dist/recall-explain-renderer.js +4 -3
  301. package/dist/recall-memory-map.d.ts +1 -1
  302. package/dist/recall-planner-llm.d.ts +1 -1
  303. package/dist/recall-state.d.ts +1 -1
  304. package/dist/recall-tag-filter.d.ts +1 -1
  305. package/dist/recall-timings.d.ts +1 -1
  306. package/dist/recall-xray-cli.d.ts +1 -1
  307. package/dist/recall-xray-cli.js +5 -4
  308. package/dist/recall-xray-renderer.d.ts +1 -1
  309. package/dist/recall-xray-renderer.js +4 -3
  310. package/dist/recall-xray.d.ts +2 -7
  311. package/dist/recall-xray.js +3 -2
  312. package/dist/reconcile/cursor.d.ts +1 -1
  313. package/dist/reconcile/manifest.d.ts +1 -1
  314. package/dist/reconcile/plan.d.ts +1 -1
  315. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  316. package/dist/replay/normalizers/claude.d.ts +1 -1
  317. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  318. package/dist/replay/normalizers/shared.d.ts +1 -1
  319. package/dist/replay/runner.d.ts +1 -1
  320. package/dist/replay/types.d.ts +1 -1
  321. package/dist/replica-divergence.d.ts +1 -1
  322. package/dist/replica-peers-config.d.ts +1 -1
  323. package/dist/resolve-auth-token.d.ts +1 -1
  324. package/dist/resume-bundles.js +4 -3
  325. package/dist/retrieval-agents.d.ts +2 -2
  326. package/dist/retrieval-tiers.d.ts +1 -1
  327. package/dist/routing/engine.d.ts +1 -1
  328. package/dist/routing/store.d.ts +1 -1
  329. package/dist/salvage-envelope.d.ts +1 -1
  330. package/dist/schemas.d.ts +138 -138
  331. package/dist/{scope-profiles-CaKcnB-6.d.ts → scope-profiles-C1QG4Cmv.d.ts} +1 -1
  332. package/dist/search/embed-helper.d.ts +1 -1
  333. package/dist/search/factory.d.ts +1 -1
  334. package/dist/search/factory.js +6 -6
  335. package/dist/search/index.d.ts +1 -1
  336. package/dist/search/index.js +11 -11
  337. package/dist/search/lancedb-backend.d.ts +1 -1
  338. package/dist/search/lancedb-backend.js +2 -2
  339. package/dist/search/meilisearch-backend.d.ts +1 -1
  340. package/dist/search/meilisearch-backend.js +2 -2
  341. package/dist/search/noop-backend.d.ts +1 -1
  342. package/dist/search/orama-backend.d.ts +1 -1
  343. package/dist/search/orama-backend.js +2 -2
  344. package/dist/search/port.d.ts +1 -1
  345. package/dist/search/remote-backend.d.ts +1 -1
  346. package/dist/semantic-chunking.js +3 -2
  347. package/dist/{semantic-consolidation-P0eMWqh-.d.ts → semantic-consolidation-DMeX8XS0.d.ts} +1 -1
  348. package/dist/semantic-consolidation.d.ts +2 -2
  349. package/dist/semantic-consolidation.js +14 -13
  350. package/dist/semantic-rule-promotion.js +10 -10
  351. package/dist/semantic-rule-verifier.d.ts +1 -1
  352. package/dist/semantic-rule-verifier.js +10 -10
  353. package/dist/{service-D5GQLxq_.d.ts → service-CT3ENiTO.d.ts} +2 -2
  354. package/dist/session-observer-bands.d.ts +1 -1
  355. package/dist/session-observer-state.d.ts +1 -1
  356. package/dist/session-observer-state.js +1 -1
  357. package/dist/shared-context/manager.d.ts +9 -9
  358. package/dist/signal.d.ts +1 -1
  359. package/dist/source-agent-qualifier.d.ts +1 -1
  360. package/dist/source-agent-qualifier.js +12 -11
  361. package/dist/{storage-DIyil2ll.d.ts → storage-B0L76y7N.d.ts} +1 -1
  362. package/dist/storage.d.ts +2 -2
  363. package/dist/storage.js +9 -9
  364. package/dist/summarizer.d.ts +1 -1
  365. package/dist/summarizer.js +3 -2
  366. package/dist/summary-snapshot.d.ts +1 -1
  367. package/dist/support-passport/index.d.ts +15 -14
  368. package/dist/support-passport/index.js +28 -27
  369. package/dist/temporal-supersession.d.ts +2 -2
  370. package/dist/temporal-timeline-recall.d.ts +1 -1
  371. package/dist/temporal-validity.d.ts +1 -1
  372. package/dist/threading.d.ts +1 -1
  373. package/dist/tier-migration.d.ts +2 -2
  374. package/dist/tier-routing.d.ts +1 -1
  375. package/dist/token-estimate.d.ts +10 -0
  376. package/dist/token-estimate.js +8 -0
  377. package/dist/token-estimate.js.map +1 -0
  378. package/dist/topics.d.ts +1 -1
  379. package/dist/transcript.d.ts +1 -6
  380. package/dist/transcript.js +2 -1
  381. package/dist/transfer/backup.js +2 -2
  382. package/dist/transfer/capsule-export.js +2 -2
  383. package/dist/transfer/capsule-import.js +2 -2
  384. package/dist/transfer/types.d.ts +66 -66
  385. package/dist/trust-score-stage.d.ts +1 -1
  386. package/dist/trust-score.d.ts +1 -1
  387. package/dist/{types-CbXieHKr.d.ts → types-D7pB0QwO.d.ts} +1 -1
  388. package/dist/types.d.ts +1 -1
  389. package/dist/types.js +1 -1
  390. package/dist/utility-runtime.d.ts +1 -1
  391. package/dist/verified-recall.js +10 -10
  392. package/dist/write-envelope.d.ts +1 -1
  393. package/package.json +12 -2
  394. package/src/chunking.ts +124 -45
  395. package/src/config.ts +2 -0
  396. package/src/connectors/codex-materialize.ts +21 -26
  397. package/src/lcm/archive.ts +4 -5
  398. package/src/lcm/engine.ts +55 -34
  399. package/src/lcm/summarizer.ts +27 -16
  400. package/src/lcm-engine.test.ts +82 -2
  401. package/src/local-llm.ts +4 -6
  402. package/src/memory-extension-host/render-extensions-block.ts +3 -9
  403. package/src/orchestration/recall-section-coordinator.ts +93 -27
  404. package/src/recall-token-budget.test.ts +51 -0
  405. package/src/recall-xray.ts +4 -11
  406. package/src/semantic-chunking.ts +14 -59
  407. package/src/session-observer-state.ts +3 -3
  408. package/src/testing/subjects/recall-budget.test.ts +21 -5
  409. package/src/token-estimate.test.ts +38 -0
  410. package/src/token-estimate.ts +22 -0
  411. package/src/transcript.test.ts +38 -3
  412. package/src/transcript.ts +58 -59
  413. package/src/types.ts +1 -1
  414. package/dist/chunk-5ZIWRMZM.js.map +0 -1
  415. package/dist/chunk-C5B3CIMJ.js.map +0 -1
  416. package/dist/chunk-HYQJQGD3.js.map +0 -1
  417. package/dist/chunk-KSXJOC4F.js.map +0 -1
  418. package/dist/chunk-LTAVSOZW.js.map +0 -1
  419. package/dist/chunk-P4BC54KI.js.map +0 -1
  420. package/dist/chunk-PBGWYM3H.js.map +0 -1
  421. package/dist/chunk-QKPDN325.js.map +0 -1
  422. package/dist/chunk-UQ7RN5HK.js +0 -126
  423. package/dist/chunk-UQ7RN5HK.js.map +0 -1
  424. package/dist/chunk-Z54EM5YZ.js.map +0 -1
  425. /package/dist/{capsule-crypto-YO5QJ6L3.js.map → capsule-crypto-GWVG7LGC.js.map} +0 -0
  426. /package/dist/{chunk-YTZA7U6Q.js.map → chunk-2VHCLHZ5.js.map} +0 -0
  427. /package/dist/{chunk-NEJQ65NV.js.map → chunk-4CLE2LXB.js.map} +0 -0
  428. /package/dist/{chunk-VDX2J7OX.js.map → chunk-5W7CTZ2E.js.map} +0 -0
  429. /package/dist/{chunk-CZUHNJHX.js.map → chunk-6C7Q6NG3.js.map} +0 -0
  430. /package/dist/{chunk-4O6R3GPK.js.map → chunk-6W2ISYUV.js.map} +0 -0
  431. /package/dist/{chunk-3AJOJOFP.js.map → chunk-77DAFTUU.js.map} +0 -0
  432. /package/dist/{chunk-IKT6ZVO7.js.map → chunk-7DHFB5SG.js.map} +0 -0
  433. /package/dist/{chunk-SFR7J2G6.js.map → chunk-7G34CBKS.js.map} +0 -0
  434. /package/dist/{chunk-IT57AOMC.js.map → chunk-AH2NX6S7.js.map} +0 -0
  435. /package/dist/{chunk-FI3PIOOI.js.map → chunk-B4CSPFYN.js.map} +0 -0
  436. /package/dist/{chunk-7PJARJS4.js.map → chunk-BPM6UHUL.js.map} +0 -0
  437. /package/dist/{chunk-PPUTUOC3.js.map → chunk-BTHDQOF4.js.map} +0 -0
  438. /package/dist/{chunk-AW4A4XOP.js.map → chunk-CZGOLAEW.js.map} +0 -0
  439. /package/dist/{chunk-5PGYCWA7.js.map → chunk-DE6YCZEE.js.map} +0 -0
  440. /package/dist/{chunk-JOA4Q765.js.map → chunk-EUYWQ7TS.js.map} +0 -0
  441. /package/dist/{chunk-O5AFC5KM.js.map → chunk-EWL5DICB.js.map} +0 -0
  442. /package/dist/{chunk-4YZCIK5E.js.map → chunk-EZXGJJXM.js.map} +0 -0
  443. /package/dist/{chunk-GXIY65UH.js.map → chunk-FI5EAP4N.js.map} +0 -0
  444. /package/dist/{chunk-YOKSRIFI.js.map → chunk-FUWS2MNJ.js.map} +0 -0
  445. /package/dist/{chunk-6RK2X7BR.js.map → chunk-G3JFFUKR.js.map} +0 -0
  446. /package/dist/{chunk-VANZKHTN.js.map → chunk-G5OB4XZX.js.map} +0 -0
  447. /package/dist/{chunk-66SLUXKM.js.map → chunk-HK6KYIF6.js.map} +0 -0
  448. /package/dist/{chunk-XBGLEOID.js.map → chunk-I4BLRM7X.js.map} +0 -0
  449. /package/dist/{chunk-6SX4MY5Q.js.map → chunk-J65AKOD6.js.map} +0 -0
  450. /package/dist/{chunk-BPWZDHFM.js.map → chunk-J6QIAYNR.js.map} +0 -0
  451. /package/dist/{chunk-XL3TATMJ.js.map → chunk-JHMAYABJ.js.map} +0 -0
  452. /package/dist/{chunk-F7M36OG2.js.map → chunk-JNWISMYG.js.map} +0 -0
  453. /package/dist/{chunk-VYIXCMUP.js.map → chunk-KBIIE57I.js.map} +0 -0
  454. /package/dist/{chunk-24PNX2GF.js.map → chunk-KXYMU4IN.js.map} +0 -0
  455. /package/dist/{chunk-FKTD7IVS.js.map → chunk-L3JVAM5Q.js.map} +0 -0
  456. /package/dist/{chunk-LIF6DO6U.js.map → chunk-MG7GI4TT.js.map} +0 -0
  457. /package/dist/{chunk-RUZM6Z52.js.map → chunk-MMZK2DWN.js.map} +0 -0
  458. /package/dist/{chunk-NTJ6TY44.js.map → chunk-ODAE36PG.js.map} +0 -0
  459. /package/dist/{chunk-YLHM5BQQ.js.map → chunk-OLX2HJFW.js.map} +0 -0
  460. /package/dist/{chunk-DNC4A7RS.js.map → chunk-OU7RWWW6.js.map} +0 -0
  461. /package/dist/{chunk-L3LRWDJW.js.map → chunk-OV36CROW.js.map} +0 -0
  462. /package/dist/{chunk-BXLOS5AJ.js.map → chunk-OWHERGF2.js.map} +0 -0
  463. /package/dist/{chunk-CSV34HIW.js.map → chunk-P5OYNV7B.js.map} +0 -0
  464. /package/dist/{chunk-SNW3YRO6.js.map → chunk-P6GOYLHN.js.map} +0 -0
  465. /package/dist/{chunk-USGKHF36.js.map → chunk-QUJC22CT.js.map} +0 -0
  466. /package/dist/{chunk-BVRREV3N.js.map → chunk-R7IV3EUJ.js.map} +0 -0
  467. /package/dist/{chunk-D4LVHPOA.js.map → chunk-RXN7Z2V5.js.map} +0 -0
  468. /package/dist/{chunk-7VSHDLJQ.js.map → chunk-T2VJ2EO5.js.map} +0 -0
  469. /package/dist/{chunk-U7BMN33M.js.map → chunk-UBSM6TZP.js.map} +0 -0
  470. /package/dist/{chunk-DQEMWVMT.js.map → chunk-UVYI6VIX.js.map} +0 -0
  471. /package/dist/{chunk-U7XLOSG2.js.map → chunk-VIM6QH4D.js.map} +0 -0
  472. /package/dist/{chunk-LJJWFV2Q.js.map → chunk-VJXSAJFW.js.map} +0 -0
  473. /package/dist/{chunk-HZC3OECF.js.map → chunk-VOKK4WCG.js.map} +0 -0
  474. /package/dist/{chunk-LRDP2AC2.js.map → chunk-YBCZTBN2.js.map} +0 -0
  475. /package/dist/{chunk-USAUBGBC.js.map → chunk-YKZFX2HQ.js.map} +0 -0
  476. /package/dist/{chunk-I2GIYTRU.js.map → chunk-ZOGOOSB3.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  StorageManager
3
- } from "./chunk-YTZA7U6Q.js";
3
+ } from "./chunk-2VHCLHZ5.js";
4
4
  import {
5
5
  getCachedRuleMemories,
6
6
  setCachedRuleMemories
@@ -119,4 +119,4 @@ export {
119
119
  compareVerifiedSemanticRuleResults,
120
120
  searchVerifiedSemanticRules
121
121
  };
122
- //# sourceMappingURL=chunk-USGKHF36.js.map
122
+ //# sourceMappingURL=chunk-QUJC22CT.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isValidCapsuleSince
3
- } from "./chunk-VDX2J7OX.js";
3
+ } from "./chunk-5W7CTZ2E.js";
4
4
  import {
5
5
  CAPSULE_ID_PATTERN
6
6
  } from "./chunk-WEHSQBFR.js";
@@ -475,4 +475,4 @@ export {
475
475
  actionConfidenceRequestSchema,
476
476
  validateRequest
477
477
  };
478
- //# sourceMappingURL=chunk-BVRREV3N.js.map
478
+ //# sourceMappingURL=chunk-R7IV3EUJ.js.map
@@ -1,3 +1,6 @@
1
+ import {
2
+ estimateTokenCount
3
+ } from "./chunk-TOTT6S2V.js";
1
4
  import {
2
5
  expandTildePath
3
6
  } from "./chunk-EYIEWJNI.js";
@@ -604,17 +607,15 @@ function trimHyphenEdges(value) {
604
607
  return value.slice(start, end);
605
608
  }
606
609
  function approximateTokenCount(text) {
607
- const trimmed = text.trim();
608
- if (trimmed.length === 0) return 0;
609
- return trimmed.split(/\s+/u).length;
610
+ return estimateTokenCount(text);
610
611
  }
611
612
  function truncateToTokenBudget(text, maxTokens) {
612
613
  if (maxTokens <= 0) return "";
613
614
  if (approximateTokenCount(text) <= maxTokens) return text;
614
615
  const lineMarker = "_[truncated for summary budget]_";
615
616
  const tailMarker = "[truncated]";
617
+ if (approximateTokenCount(tailMarker) > maxTokens) return "";
616
618
  const lineMarkerTokens = approximateTokenCount(lineMarker);
617
- const tailMarkerTokens = approximateTokenCount(tailMarker);
618
619
  const lines = text.split(/\r?\n/u);
619
620
  const lineBudget = Math.max(0, maxTokens - lineMarkerTokens);
620
621
  while (lines.length > 0 && approximateTokenCount(lines.join("\n")) > lineBudget) {
@@ -623,9 +624,18 @@ function truncateToTokenBudget(text, maxTokens) {
623
624
  lines.push(lineMarker);
624
625
  let result = lines.join("\n");
625
626
  if (approximateTokenCount(result) > maxTokens) {
626
- const tokens = result.split(/\s+/u);
627
- const keep = Math.max(0, maxTokens - tailMarkerTokens);
628
- result = keep > 0 ? `${tokens.slice(0, keep).join(" ")} ${tailMarker}` : tailMarker;
627
+ const codePoints = [...result];
628
+ let low = 0;
629
+ let high = codePoints.length;
630
+ while (low < high) {
631
+ const mid = Math.ceil((low + high) / 2);
632
+ const prefix2 = codePoints.slice(0, mid).join("");
633
+ const candidate = prefix2.length > 0 ? `${prefix2} ${tailMarker}` : tailMarker;
634
+ if (approximateTokenCount(candidate) <= maxTokens) low = mid;
635
+ else high = mid - 1;
636
+ }
637
+ const prefix = codePoints.slice(0, low).join("");
638
+ result = prefix.length > 0 ? `${prefix} ${tailMarker}` : tailMarker;
629
639
  }
630
640
  return result;
631
641
  }
@@ -694,4 +704,4 @@ export {
694
704
  truncateToTokenBudget,
695
705
  describeMemoriesDir
696
706
  };
697
- //# sourceMappingURL=chunk-KSXJOC4F.js.map
707
+ //# sourceMappingURL=chunk-RDFF2NAU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/connectors/codex-materialize.ts"],"sourcesContent":["/**\n * codex-materialize.ts — Codex CLI native memory artifact materialization (#378)\n *\n * Periodically writes Remnic memories into the file layout that Codex CLI's\n * phase-2 consolidation reads directly under `<codex_home>/memories/`:\n *\n * memory_summary.md — always-loaded at session start (tight budget)\n * MEMORY.md — searchable handbook (task-group schema)\n * raw_memories.md — mechanical merge of raw memories, latest first\n * rollout_summaries/<slug>.md — per-session recaps\n *\n * Codex's own read path is agnostic to which producer wrote these files — it\n * tags reads by `memory_md` / `memory_summary` / `raw_memories` /\n * `rollout_summaries` / `skills`. By materializing Remnic content into this\n * exact layout we let Codex pick up Remnic memories without a single MCP call.\n *\n * Safety invariants\n * ─────────────────\n * - **Atomic writes.** Every file is rendered under `.remnic-tmp/` and then\n * `rename()`d into place so Codex never observes a half-written file.\n * - **Sentinel-based opt-in.** If `<codex_home>/memories/.remnic-managed` is\n * missing, we SKIP materialization entirely and log a warning. This honors\n * user hand-edits to the directory — a user who manually curated their\n * Codex memory layout will never have those edits overwritten.\n * - **Schema validation.** `MEMORY.md` content is validated against the\n * task-group schema before write. Invalid content throws and nothing is\n * written.\n * - **Idempotent no-ops.** A content hash is written into the sentinel. If\n * the re-rendered hash matches the previous run, we skip writes entirely.\n * - **Token budget.** `memory_summary.md` is truncated to fit under the\n * configured script-aware token estimate, leaving headroom under Codex's\n * 5000-token summary cap.\n *\n * Privacy\n * ───────\n * This module does not persist any user content outside `<codex_home>/memories`\n * — it only mirrors the memories that Remnic already wrote. It does not log\n * memory content to stdout; it logs file names, counts, and hashes.\n */\n\nimport {\n createHash,\n} from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\nimport { log } from \"../logger.js\";\nimport { readEnvVar, resolveHomeDir } from \"../runtime/env.js\";\nimport type { MemoryFile } from \"../types.js\";\nimport { estimateTokenCount } from \"../token-estimate.js\";\nimport { expandTildePath } from \"../utils/path.js\";\n\n// ─── Types ─────────────────────────────────────────────────────────────────\n\n/**\n * Input for {@link materializeForNamespace}. Prefer passing pre-loaded\n * `memories` so this module stays I/O-agnostic and trivially testable.\n */\nexport interface MaterializeOptions {\n /** Pre-loaded Remnic memories for this namespace (required). */\n memories: MemoryFile[];\n /** Override `<codex_home>`. Defaults to `$CODEX_HOME` or `~/.codex`. */\n codexHome?: string;\n /** Maximum estimated token size of memory_summary.md. Default 4500. */\n maxSummaryTokens?: number;\n /** Maximum age of rollout_summaries/*.md in days. Default 30. */\n rolloutRetentionDays?: number;\n /** Per-session rollout summaries to render. */\n rolloutSummaries?: RolloutSummaryInput[];\n /** Current time, injected for deterministic tests. */\n now?: Date;\n /** Optional logger override for tests. */\n logger?: { info: (msg: string) => void; warn: (msg: string) => void; debug?: (msg: string) => void };\n}\n\n/** Input describing one Codex rollout summary file. */\nexport interface RolloutSummaryInput {\n /** Stable slug for the file (becomes `<slug>.md`). */\n slug: string;\n /** Working directory used during the rollout. */\n cwd?: string;\n /** Path to the raw Codex rollout log, if known. */\n rolloutPath?: string;\n /** ISO-8601 timestamp of the last update. */\n updatedAt?: string;\n /** Opaque thread / session id. */\n threadId?: string;\n /** Markdown body for the recap. */\n body: string;\n /** Freeform keywords / search hints. */\n keywords?: string[];\n}\n\n/** Result of a materialization run. */\nexport interface MaterializeResult {\n /** Namespace that was materialized. */\n namespace: string;\n /** `<codex_home>/memories` path this run targeted. */\n memoriesDir: string;\n /** Was anything actually written (vs. skipped / idempotent no-op)? */\n wrote: boolean;\n /** True if the sentinel was missing and we skipped with a warning. */\n skippedNoSentinel: boolean;\n /** True if the hash matched the previous run and we short-circuited. */\n skippedIdempotent: boolean;\n /** Files that were written this run (relative to `memoriesDir`). */\n filesWritten: string[];\n /** Content hash computed for this run. */\n contentHash: string;\n}\n\n/** On-disk shape of the `.remnic-managed` sentinel. */\ninterface SentinelFile {\n version: number;\n namespace: string;\n updated_at: string;\n content_hash: string;\n}\n\n// ─── Constants ─────────────────────────────────────────────────────────────\n\n/** Bump when the on-disk layout or semantics change. */\nexport const MATERIALIZE_VERSION = 1;\n\n/** Sentinel file name at the root of the materialized memories dir. */\nexport const SENTINEL_FILE = \".remnic-managed\";\n\n/** Scratch directory used for atomic renames. */\nexport const TMP_DIR = \".remnic-tmp\";\n\n/** File names we own. Anything else in the directory is considered user-managed. */\nconst OWNED_FILES = new Set<string>([\n \"memory_summary.md\",\n \"MEMORY.md\",\n \"raw_memories.md\",\n]);\n\n/** Sub-directory for per-session rollout recaps. */\nconst ROLLOUT_SUBDIR = \"rollout_summaries\";\n\n// ─── Public entry points ───────────────────────────────────────────────────\n\n/**\n * Materialize a Remnic namespace into Codex's native memory layout.\n *\n * Returns a {@link MaterializeResult} describing what happened. Callers\n * should treat \"skipped\" as success — the sentinel / idempotent cases are\n * expected and intentional.\n *\n * @throws if `MEMORY.md` fails schema validation (we do not write garbage).\n */\nexport function materializeForNamespace(\n namespace: string,\n options: MaterializeOptions,\n): MaterializeResult {\n const logger = options.logger ?? {\n info: (msg) => log.info(`[codex-materialize] ${msg}`),\n warn: (msg) => log.warn(`[codex-materialize] ${msg}`),\n debug: (msg) => log.debug(`[codex-materialize] ${msg}`),\n };\n const memoriesDir = resolveCodexMemoriesDir(options.codexHome);\n const now = options.now ?? new Date();\n // Honor `0` as \"no summary budget\" — parseConfig already clamps to non-\n // negative integers, so any provided number is meaningful. Only fall back\n // to the default when the caller did not provide the option at all.\n const maxSummaryTokens =\n typeof options.maxSummaryTokens === \"number\" && options.maxSummaryTokens >= 0\n ? options.maxSummaryTokens\n : 4500;\n const rolloutRetentionDays =\n typeof options.rolloutRetentionDays === \"number\" && options.rolloutRetentionDays >= 0\n ? options.rolloutRetentionDays\n : 30;\n\n // ── Sentinel check ─────────────────────────────────────────────────────\n // We deliberately do NOT `mkdirSync(memoriesDir)` before reading the\n // sentinel: creating `~/.codex/memories/` for every user (including ones\n // who never use Codex) would make Remnic's post-consolidation hook leave\n // empty opt-in directories behind on disk. Instead we only check whether\n // the sentinel already exists — if the parent dir doesn't exist, the\n // sentinel can't exist either and we fall straight through to the skip\n // path without touching the filesystem. The `mkdirSync` for `memoriesDir`\n // happens later, only once we know we're actually going to write.\n const sentinelPath = path.join(memoriesDir, SENTINEL_FILE);\n const existingSentinel = readSentinel(sentinelPath);\n if (!existingSentinel) {\n // Log at `debug` when the entire memories dir doesn't exist — that's\n // the common \"user never opted in\" case and should not be noisy.\n // Keep the `warn` level only when the dir exists but lacks a sentinel,\n // which is the \"user hand-curated layout, don't overwrite\" case that\n // genuinely warrants attention.\n if (fs.existsSync(memoriesDir)) {\n logger.warn(\n `sentinel ${SENTINEL_FILE} missing in ${memoriesDir}; skipping materialization to preserve hand-edits`,\n );\n } else {\n logger.debug?.(\n `skipping materialization — ${memoriesDir} does not exist (user not opted in)`,\n );\n }\n return {\n namespace,\n memoriesDir,\n wrote: false,\n skippedNoSentinel: true,\n skippedIdempotent: false,\n filesWritten: [],\n contentHash: \"\",\n };\n }\n\n // Now that we know the user has opted in (sentinel exists), it's safe to\n // ensure the memories dir is present. In practice this is almost always a\n // no-op because the sentinel read above already succeeded, but a defensive\n // mkdirSync protects against a race where the dir was removed between the\n // sentinel read and the first write.\n fs.mkdirSync(memoriesDir, { recursive: true });\n\n // ── Render ─────────────────────────────────────────────────────────────\n const memories = [...options.memories];\n // Track whether the caller actually supplied a rollout set. `undefined`\n // means \"don't touch rollout_summaries/\"; an empty array is still\n // authoritative and means \"we own this dir and it should be empty\".\n const rolloutsSupplied = options.rolloutSummaries !== undefined;\n const rolloutSummaries = options.rolloutSummaries ?? [];\n\n // Prune-before-render: MEMORY.md and memory_summary.md both embed rollout\n // filenames in their body, so they must only ever see the *retained* set.\n // Running pruneRollouts after the renderers (as an earlier revision did)\n // caused MEMORY.md to list `rollout_summaries/<slug>.md` paths for rollouts\n // that were then pruned and never written — a broken link pointing at a\n // ghost file. See review feedback on PR #392.\n const retainedRollouts = pruneRollouts(rolloutSummaries, rolloutRetentionDays, now);\n\n // Deduplicate on sanitized filename. Two different slugs (\"Session 1\" and\n // \"session!!!1\") can sanitize to the same output (\"session-1\"), which would\n // otherwise make the first entry's tmp file get overwritten and cause the\n // later rename step to crash with ENOENT. For each collision slot we keep\n // the entry with the newest `updatedAt` so an unsorted input (or a caller\n // that accidentally appends older recaps after newer ones) can't have an\n // older recap clobber a newer one.\n // We do this at the retained-input level (not just at the written-file\n // level) so MEMORY.md's \"rollout_summary_files\" section lists each slot\n // exactly once and matches what actually gets written to disk.\n const dedupedRollouts: RolloutSummaryInput[] = [];\n const seenNames = new Map<string, number>();\n const parseTs = (value: string | undefined): number => {\n if (!value) return Number.NEGATIVE_INFINITY;\n const parsed = Date.parse(value);\n return Number.isFinite(parsed) ? parsed : Number.NEGATIVE_INFINITY;\n };\n for (const r of retainedRollouts) {\n const name = `${sanitizeSlug(r.slug)}.md`;\n const existingIdx = seenNames.get(name);\n if (existingIdx === undefined) {\n seenNames.set(name, dedupedRollouts.length);\n dedupedRollouts.push(r);\n continue;\n }\n // Newest-wins: only replace the existing entry if the incoming one has a\n // strictly newer timestamp. Ties keep the earlier entry (stable for\n // unsorted inputs) because overwriting on ties would flip rendering output\n // for benign call-order changes.\n const existing = dedupedRollouts[existingIdx];\n if (parseTs(r.updatedAt) > parseTs(existing.updatedAt)) {\n dedupedRollouts[existingIdx] = r;\n }\n }\n\n const memorySummary = renderMemorySummary({\n namespace,\n memories,\n rolloutSummaries: dedupedRollouts,\n maxTokens: maxSummaryTokens,\n });\n\n const memoryMd = renderMemoryMd({\n namespace,\n memories,\n rolloutSummaries: dedupedRollouts,\n });\n\n // Fail fast on schema issues — do not write garbage.\n const validation = validateMemoryMd(memoryMd);\n if (!validation.valid) {\n const reason = validation.errors.join(\"; \");\n logger.warn(`MEMORY.md failed schema validation: ${reason}`);\n throw new Error(`codex-materialize: MEMORY.md schema validation failed: ${reason}`);\n }\n\n const rawMemories = renderRawMemories({ memories });\n\n const rolloutFiles = dedupedRollouts.map((r) => ({\n name: `${sanitizeSlug(r.slug)}.md`,\n body: renderRolloutSummary(r),\n }));\n const destRolloutsDir = path.join(memoriesDir, ROLLOUT_SUBDIR);\n const retainedRolloutNames = new Set(rolloutFiles.map((r) => r.name));\n\n // ── Idempotence check ──────────────────────────────────────────────────\n const hash = computeContentHash({\n namespace,\n memorySummary,\n memoryMd,\n rawMemories,\n rolloutFiles,\n });\n\n if (existingSentinel.content_hash === hash) {\n // Idempotence early-return is only safe when the managed files we would\n // have written are still on disk. If a user or external process deleted\n // `MEMORY.md` / `memory_summary.md` / `raw_memories.md` (or any retained\n // rollout file) while the sentinel's hash stayed the same, we must fall\n // through and rewrite — otherwise Codex would be stuck with missing\n // artifacts until a memory-content change happens to flip the hash.\n const requiredFiles = [\n path.join(memoriesDir, \"memory_summary.md\"),\n path.join(memoriesDir, \"MEMORY.md\"),\n path.join(memoriesDir, \"raw_memories.md\"),\n ...rolloutFiles.map((r) => path.join(memoriesDir, ROLLOUT_SUBDIR, r.name)),\n ];\n const allPresent = requiredFiles.every((f) => fs.existsSync(f));\n const rolloutsClean =\n !rolloutsSupplied ||\n rolloutDirectoryMatchesRetainedSet(\n ensureSafeRolloutsDir(memoriesDir, destRolloutsDir),\n retainedRolloutNames,\n );\n if (allPresent && rolloutsClean) {\n logger.debug?.(`no-op materialization for namespace=${namespace} (hash unchanged)`);\n return {\n namespace,\n memoriesDir,\n wrote: false,\n skippedNoSentinel: false,\n skippedIdempotent: true,\n filesWritten: [],\n contentHash: hash,\n };\n }\n logger.debug?.(\n `hash unchanged for namespace=${namespace} but managed files need refresh — forcing rewrite`,\n );\n }\n\n // ── Atomic writes ──────────────────────────────────────────────────────\n // Use a unique, per-run staging sub-directory so two overlapping runs\n // (e.g. a session-end trigger overlapping with a consolidation post-hook)\n // can't stomp each other's tmp files mid-rename. The old \"fixed TMP_DIR,\n // wipe-on-entry\" layout meant run B would delete run A's staging area out\n // from under it, causing ENOENT on A's rename loop. Per-run uniqueness\n // turns the shared dir into an insulated workspace. See review feedback on\n // PR #392.\n const runTag = `${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n const tmpDir = path.join(memoriesDir, `${TMP_DIR}-${runTag}`);\n // Opportunistic GC for stale scratch dirs left behind by a previous\n // crashed run. We only remove entries whose mtime is older than the\n // stale-threshold below — that way we never delete another in-flight\n // run's staging area out from under it. The threshold is deliberately\n // generous (1h) because a healthy materialize completes in milliseconds\n // and there's no legitimate reason for a live staging dir to be older.\n //\n // NB: we compare against `Date.now()` (wall-clock), not against the\n // injected `options.now`. Tests and deterministic replays commonly\n // inject a non-current timestamp, but file mtimes on disk are always\n // wall-clock, so mixing the two would either false-positive delete\n // fresh dirs (test-time in the past) or false-negative skip stale ones\n // (test-time in the future).\n const TMP_STALE_MS = 60 * 60 * 1000;\n const wallClockMs = Date.now();\n try {\n for (const entry of fs.readdirSync(memoriesDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n if (!entry.name.startsWith(TMP_DIR)) continue;\n const stalePath = path.join(memoriesDir, entry.name);\n try {\n const stat = fs.statSync(stalePath);\n if (wallClockMs - stat.mtimeMs < TMP_STALE_MS) continue;\n fs.rmSync(stalePath, { recursive: true, force: true });\n } catch {\n // ignore — another concurrent run may own it, or we lack perms\n }\n }\n } catch {\n // ignore — dir may not exist yet\n }\n fs.mkdirSync(tmpDir, { recursive: true });\n fs.mkdirSync(path.join(tmpDir, ROLLOUT_SUBDIR), { recursive: true });\n\n const filesWritten: string[] = [];\n\n fs.writeFileSync(path.join(tmpDir, \"memory_summary.md\"), memorySummary);\n filesWritten.push(\"memory_summary.md\");\n\n fs.writeFileSync(path.join(tmpDir, \"MEMORY.md\"), memoryMd);\n filesWritten.push(\"MEMORY.md\");\n\n fs.writeFileSync(path.join(tmpDir, \"raw_memories.md\"), rawMemories);\n filesWritten.push(\"raw_memories.md\");\n\n for (const rollout of rolloutFiles) {\n fs.writeFileSync(path.join(tmpDir, ROLLOUT_SUBDIR, rollout.name), rollout.body);\n filesWritten.push(path.join(ROLLOUT_SUBDIR, rollout.name));\n }\n\n // Rename into place. Atomic per-file is sufficient — Codex reads each file\n // independently and tolerates an inconsistent in-between snapshot across\n // files for the duration of the rename loop (milliseconds).\n for (const rel of [\"memory_summary.md\", \"MEMORY.md\", \"raw_memories.md\"]) {\n const src = path.join(tmpDir, rel);\n const dest = path.join(memoriesDir, rel);\n fs.renameSync(src, dest);\n }\n\n const safeDestRolloutsDir = ensureSafeRolloutsDir(memoriesDir, destRolloutsDir);\n // Only garbage-collect rollout files when the caller actually supplied a\n // `rolloutSummaries` array — otherwise we'd wipe legitimately\n // user/Codex-created recap files on every session-end run, since those\n // calls typically omit the rollout set entirely. When rollouts were\n // supplied (even as an empty array — meaning \"we own this dir and it\n // should be empty\"), we clear the stale files we previously owned.\n if (rolloutsSupplied) {\n let existingRollouts: fs.Dirent[];\n try {\n existingRollouts = fs.readdirSync(safeDestRolloutsDir, { withFileTypes: true });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") throw err;\n existingRollouts = [];\n }\n for (const entry of existingRollouts) {\n if (!entry.isFile()) continue;\n if (!entry.name.endsWith(\".md\")) continue;\n if (retainedRolloutNames.has(entry.name)) continue;\n try {\n fs.unlinkSync(path.join(safeDestRolloutsDir, entry.name));\n } catch (err) {\n throw new Error(\n `codex-materialize: failed to prune stale rollout summary ${entry.name}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n }\n\n for (const rollout of rolloutFiles) {\n const src = path.join(tmpDir, ROLLOUT_SUBDIR, rollout.name);\n const dest = path.join(safeDestRolloutsDir, rollout.name);\n fs.renameSync(src, dest);\n }\n\n // Update sentinel last so a crash leaves hash mismatched → next run rewrites.\n const sentinel: SentinelFile = {\n version: MATERIALIZE_VERSION,\n namespace,\n updated_at: now.toISOString(),\n content_hash: hash,\n };\n writeSentinelAtomically(sentinelPath, sentinel);\n\n try {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n } catch {\n // ignore\n }\n\n logger.info(\n `materialized namespace=${namespace} files=${filesWritten.length} hash=${hash.slice(0, 12)}`,\n );\n\n return {\n namespace,\n memoriesDir,\n wrote: true,\n skippedNoSentinel: false,\n skippedIdempotent: false,\n filesWritten,\n contentHash: hash,\n };\n}\n\n/**\n * Create (or refresh) the `.remnic-managed` sentinel. Callers must do this\n * explicitly the first time they want Remnic to start managing a directory —\n * we never write it implicitly, because its presence is the user's opt-in.\n */\nexport function ensureSentinel(memoriesDir: string, namespace: string, now: Date = new Date()): void {\n fs.mkdirSync(memoriesDir, { recursive: true });\n const sentinelPath = path.join(memoriesDir, SENTINEL_FILE);\n if (fs.existsSync(sentinelPath)) {\n readSentinel(sentinelPath);\n return;\n }\n const sentinel: SentinelFile = {\n version: MATERIALIZE_VERSION,\n namespace,\n updated_at: now.toISOString(),\n content_hash: \"\",\n };\n writeSentinelAtomically(sentinelPath, sentinel);\n}\n\n// ─── Rendering ─────────────────────────────────────────────────────────────\n\ninterface RenderContext {\n namespace: string;\n memories: MemoryFile[];\n rolloutSummaries: RolloutSummaryInput[];\n // Historically this interface exposed a `now: Date` field, but neither\n // `renderMemoryMd` nor `renderMemorySummary` ever read it (rendered output\n // is purely a function of `namespace`, `memories`, and `rolloutSummaries`).\n // The field was flagged as dead weight in PR #392 review and removed.\n // If a future renderer needs a timestamp, re-add it here and update both\n // call sites and the schema test.\n}\n\ninterface SummaryRenderContext extends RenderContext {\n maxTokens: number;\n}\n\n/**\n * Render `memory_summary.md` — the always-loaded file.\n * Budget-capped at `maxTokens` whitespace tokens.\n */\nexport function renderMemorySummary(ctx: SummaryRenderContext): string {\n const lines: string[] = [];\n lines.push(\"# Memory Summary\");\n lines.push(\"\");\n lines.push(`_namespace: ${ctx.namespace}_`);\n lines.push(`_source: remnic_`);\n lines.push(\"\");\n\n const highValue = selectSummaryMemories(ctx.memories, 12);\n if (highValue.length > 0) {\n lines.push(\"## Top memories\");\n lines.push(\"\");\n for (const mem of highValue) {\n lines.push(`- ${oneLineSummary(mem)}`);\n }\n lines.push(\"\");\n }\n\n if (ctx.rolloutSummaries.length > 0) {\n lines.push(\"## Recent rollouts\");\n lines.push(\"\");\n const sorted = [...ctx.rolloutSummaries]\n .sort((a, b) => (b.updatedAt ?? \"\").localeCompare(a.updatedAt ?? \"\"))\n .slice(0, 5);\n for (const r of sorted) {\n const when = r.updatedAt ? ` (${r.updatedAt})` : \"\";\n lines.push(`- ${r.slug}${when}`);\n }\n lines.push(\"\");\n }\n\n // Collapse trailing newlines to one without the anchored /\\n+$/ quantifier,\n // which backtracks polynomially (CodeQL js/polynomial-redos).\n const joined = lines.join(\"\\n\");\n let joinedEnd = joined.length;\n while (joinedEnd > 0 && joined[joinedEnd - 1] === \"\\n\") joinedEnd--;\n const full = joinedEnd === joined.length ? joined : `${joined.slice(0, joinedEnd)}\\n`;\n return truncateToTokenBudget(full, ctx.maxTokens);\n}\n\n/**\n * Render `MEMORY.md` — the searchable handbook in Codex's task-group schema.\n */\nexport function renderMemoryMd(ctx: RenderContext): string {\n const lines: string[] = [];\n lines.push(`# Task Group: ${ctx.namespace}`);\n lines.push(`scope: ${ctx.namespace}`);\n lines.push(`applies_to: cwd=*; reuse_rule=namespace-match`);\n lines.push(\"\");\n\n // One \"task\" per top-level topic cluster. For the first cut we group by\n // memory category so the schema validator always sees at least one task.\n const byCategory = groupMemoriesByCategory(ctx.memories);\n let taskIndex = 1;\n if (byCategory.size === 0) {\n lines.push(`## Task ${taskIndex}: baseline — no memories yet`);\n lines.push(\"\");\n lines.push(\"### rollout_summary_files\");\n for (const r of ctx.rolloutSummaries) {\n lines.push(\n `- rollout_summaries/${sanitizeSlug(r.slug)}.md (cwd=${r.cwd ?? \"*\"}, rollout_path=${r.rolloutPath ?? \"\"}, updated_at=${r.updatedAt ?? \"\"}, thread_id=${r.threadId ?? \"\"})`,\n );\n }\n if (ctx.rolloutSummaries.length === 0) {\n lines.push(\"- (none)\");\n }\n lines.push(\"\");\n lines.push(\"### keywords\");\n lines.push(`- ${ctx.namespace}`);\n lines.push(\"\");\n taskIndex += 1;\n } else {\n for (const [category, mems] of byCategory) {\n lines.push(`## Task ${taskIndex}: ${category} memories, outcome=surface-to-codex`);\n lines.push(\"\");\n lines.push(\"### rollout_summary_files\");\n const relevantRollouts = ctx.rolloutSummaries.slice(0, 5);\n if (relevantRollouts.length === 0) {\n lines.push(\"- (none)\");\n } else {\n for (const r of relevantRollouts) {\n lines.push(\n `- rollout_summaries/${sanitizeSlug(r.slug)}.md (cwd=${r.cwd ?? \"*\"}, rollout_path=${r.rolloutPath ?? \"\"}, updated_at=${r.updatedAt ?? \"\"}, thread_id=${r.threadId ?? \"\"})`,\n );\n }\n }\n lines.push(\"\");\n lines.push(\"### keywords\");\n const keywords = collectKeywords(mems, category, ctx.namespace);\n lines.push(`- ${keywords.join(\", \")}`);\n lines.push(\"\");\n taskIndex += 1;\n }\n }\n\n lines.push(\"## User preferences\");\n const prefs = pickCategory(ctx.memories, [\"preference\"]);\n if (prefs.length === 0) {\n lines.push(\"- (none recorded)\");\n } else {\n for (const pref of prefs.slice(0, 20)) {\n lines.push(`- ${oneLineSummary(pref)}`);\n }\n }\n lines.push(\"\");\n\n lines.push(\"## Reusable knowledge\");\n const knowledge = pickCategory(ctx.memories, [\"fact\", \"decision\", \"principle\", \"rule\", \"skill\"]);\n if (knowledge.length === 0) {\n lines.push(\"- (none recorded)\");\n } else {\n for (const mem of knowledge.slice(0, 30)) {\n lines.push(`- ${oneLineSummary(mem)}`);\n }\n }\n lines.push(\"\");\n\n lines.push(\"## Failures and how to do differently\");\n const corrections = pickCategory(ctx.memories, [\"correction\"]);\n if (corrections.length === 0) {\n lines.push(\"- (none recorded)\");\n } else {\n for (const mem of corrections.slice(0, 20)) {\n lines.push(`- ${oneLineSummary(mem)}`);\n }\n }\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\n/** Render `raw_memories.md` — mechanical dump, latest first. */\nexport function renderRawMemories(ctx: { memories: MemoryFile[] }): string {\n const sorted = [...ctx.memories].sort((a, b) => {\n const aUpdated = a.frontmatter.updated ?? a.frontmatter.created ?? \"\";\n const bUpdated = b.frontmatter.updated ?? b.frontmatter.created ?? \"\";\n return bUpdated.localeCompare(aUpdated);\n });\n\n const lines: string[] = [\"# Raw Memories\", \"\", \"_source: remnic — latest first_\", \"\"];\n for (const mem of sorted) {\n const fm = mem.frontmatter;\n const id = fm.id ?? \"unknown\";\n const category = fm.category ?? \"unknown\";\n const updated = fm.updated ?? fm.created ?? \"\";\n lines.push(`## ${id} (${category}, updated=${updated})`);\n lines.push(\"\");\n lines.push(mem.content.trim());\n lines.push(\"\");\n }\n return lines.join(\"\\n\");\n}\n\n/** Render a single rollout summary file. */\nexport function renderRolloutSummary(input: RolloutSummaryInput): string {\n const lines: string[] = [];\n lines.push(`# Rollout Summary: ${input.slug}`);\n lines.push(\"\");\n const meta: string[] = [];\n if (input.cwd) meta.push(`cwd=${input.cwd}`);\n if (input.rolloutPath) meta.push(`rollout_path=${input.rolloutPath}`);\n if (input.updatedAt) meta.push(`updated_at=${input.updatedAt}`);\n if (input.threadId) meta.push(`thread_id=${input.threadId}`);\n if (meta.length > 0) {\n lines.push(`_${meta.join(\"; \")}_`);\n lines.push(\"\");\n }\n if (input.keywords && input.keywords.length > 0) {\n lines.push(`**keywords:** ${input.keywords.join(\", \")}`);\n lines.push(\"\");\n }\n lines.push(input.body.trim());\n lines.push(\"\");\n return lines.join(\"\\n\");\n}\n\n// ─── Schema validation ─────────────────────────────────────────────────────\n\nexport interface MemoryMdValidation {\n valid: boolean;\n errors: string[];\n}\n\n/**\n * Validate that a rendered `MEMORY.md` matches Codex's task-group schema.\n * We enforce the minimum set of structural requirements called out in #378:\n *\n * - one `# Task Group:` header\n * - `scope:` and `applies_to:` lines directly beneath it\n * - at least one `## Task N:` section\n * - each task section has `### rollout_summary_files` and `### keywords`\n * - `## User preferences`, `## Reusable knowledge`,\n * `## Failures and how to do differently` sections all present\n */\nexport function validateMemoryMd(content: string): MemoryMdValidation {\n const errors: string[] = [];\n const lines = content.split(/\\r?\\n/u);\n\n const taskGroupIndex = lines.findIndex((l) => /^#\\s+Task Group:\\s+\\S+/u.test(l));\n if (taskGroupIndex === -1) {\n errors.push(\"missing `# Task Group:` header\");\n } else {\n const tail = lines.slice(taskGroupIndex + 1, taskGroupIndex + 5);\n if (!tail.some((l) => /^scope:\\s*\\S+/u.test(l))) {\n errors.push(\"missing `scope:` line under Task Group header\");\n }\n if (!tail.some((l) => /^applies_to:\\s*\\S+/u.test(l))) {\n errors.push(\"missing `applies_to:` line under Task Group header\");\n }\n }\n\n const taskHeaders = lines.filter((l) => /^##\\s+Task\\s+\\d+:/u.test(l));\n if (taskHeaders.length === 0) {\n errors.push(\"at least one `## Task N:` section is required\");\n }\n\n // For every task section, make sure we have rollout_summary_files + keywords\n // before the next `##` header at the same level.\n const sectionRegex = /^##\\s+/u;\n for (let i = 0; i < lines.length; i++) {\n if (!/^##\\s+Task\\s+\\d+:/u.test(lines[i])) continue;\n let hasRollout = false;\n let hasKeywords = false;\n for (let j = i + 1; j < lines.length; j++) {\n if (sectionRegex.test(lines[j])) break;\n if (/^###\\s+rollout_summary_files\\s*$/u.test(lines[j])) hasRollout = true;\n if (/^###\\s+keywords\\s*$/u.test(lines[j])) hasKeywords = true;\n }\n if (!hasRollout) errors.push(`task block at line ${i + 1} missing \\`### rollout_summary_files\\``);\n if (!hasKeywords) errors.push(`task block at line ${i + 1} missing \\`### keywords\\``);\n }\n\n const requiredSections = [\n /^##\\s+User preferences\\s*$/u,\n /^##\\s+Reusable knowledge\\s*$/u,\n /^##\\s+Failures and how to do differently\\s*$/u,\n ];\n for (const re of requiredSections) {\n if (!lines.some((l) => re.test(l))) {\n errors.push(`missing required section: ${re.source}`);\n }\n }\n\n return { valid: errors.length === 0, errors };\n}\n\n// ─── Helpers ───────────────────────────────────────────────────────────────\n\nfunction resolveCodexHome(override?: string): string {\n if (override && override.trim().length > 0) {\n return path.resolve(expandTildePath(override.trim()));\n }\n const fromEnv = readEnvVar(\"CODEX_HOME\");\n if (fromEnv && fromEnv.trim().length > 0) {\n return path.resolve(expandTildePath(fromEnv.trim()));\n }\n return path.resolve(resolveHomeDir(), \".codex\");\n}\n\nexport function resolveCodexMemoriesDir(codexHome?: string): string {\n return path.join(resolveCodexHome(codexHome), \"memories\");\n}\n\nexport function hasCodexMaterializeSentinel(codexHome?: string): boolean {\n return readSentinel(path.join(resolveCodexMemoriesDir(codexHome), SENTINEL_FILE)) !== null;\n}\n\nfunction rolloutDirectoryMatchesRetainedSet(\n rolloutsDir: string,\n retainedNames: Set<string>,\n): boolean {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(rolloutsDir, { withFileTypes: true });\n } catch {\n return retainedNames.size === 0;\n }\n for (const entry of entries) {\n if (!entry.isFile()) continue;\n if (!entry.name.endsWith(\".md\")) continue;\n if (!retainedNames.has(entry.name)) return false;\n }\n return true;\n}\n\nfunction isPathInside(parent: string, child: string): boolean {\n const relative = path.relative(parent, child);\n return relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative));\n}\n\nfunction ensureSafeRolloutsDir(memoriesDir: string, rolloutsDir: string): string {\n const memoriesReal = fs.realpathSync(memoriesDir);\n\n try {\n const stat = fs.lstatSync(rolloutsDir);\n if (stat.isSymbolicLink()) {\n throw new Error(\"is a symbolic link\");\n }\n if (!stat.isDirectory()) {\n throw new Error(\"is not a directory\");\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw new Error(\n `codex-materialize: unsafe ${ROLLOUT_SUBDIR} directory at ${rolloutsDir}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n fs.mkdirSync(rolloutsDir, { recursive: true });\n }\n\n const rolloutsReal = fs.realpathSync(rolloutsDir);\n if (!isPathInside(memoriesReal, rolloutsReal)) {\n throw new Error(\n `codex-materialize: unsafe ${ROLLOUT_SUBDIR} directory at ${rolloutsDir}: resolves outside ${memoriesDir}`,\n );\n }\n\n return rolloutsDir;\n}\n\nfunction readSentinel(sentinelPath: string): SentinelFile | null {\n if (!fs.existsSync(sentinelPath)) return null;\n try {\n const raw = fs.readFileSync(sentinelPath, \"utf-8\");\n const parsed = JSON.parse(raw) as Partial<SentinelFile>;\n if (\n typeof parsed !== \"object\" ||\n parsed === null ||\n typeof parsed.version !== \"number\" ||\n typeof parsed.namespace !== \"string\" ||\n typeof parsed.updated_at !== \"string\" ||\n typeof parsed.content_hash !== \"string\"\n ) {\n throw new Error(\"invalid sentinel schema\");\n }\n return {\n version: parsed.version,\n namespace: parsed.namespace,\n updated_at: parsed.updated_at,\n content_hash: parsed.content_hash,\n };\n } catch (err) {\n throw new Error(\n `codex-materialize: corrupt ${SENTINEL_FILE} sentinel at ${sentinelPath}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n}\n\nfunction writeSentinelAtomically(\n sentinelPath: string,\n sentinel: SentinelFile,\n): void {\n const tmpPath = `${sentinelPath}.${process.pid}.${Date.now()}.${Math.random()\n .toString(16)\n .slice(2)}.tmp`;\n try {\n fs.writeFileSync(tmpPath, `${JSON.stringify(sentinel, null, 2)}\\n`, {\n flag: \"wx\",\n });\n fs.renameSync(tmpPath, sentinelPath);\n } catch (err) {\n try {\n fs.rmSync(tmpPath, { force: true });\n } catch {\n // ignore cleanup failures; preserve the original write/rename error\n }\n throw err;\n }\n}\n\nfunction selectSummaryMemories(memories: MemoryFile[], limit: number): MemoryFile[] {\n const scored = memories\n .filter((m) => !m.frontmatter.status || m.frontmatter.status === \"active\")\n .map((m) => {\n const confidence = typeof m.frontmatter.confidence === \"number\" ? m.frontmatter.confidence : 0;\n const importance =\n typeof m.frontmatter.importance === \"object\" &&\n m.frontmatter.importance !== null &&\n typeof (m.frontmatter.importance as { score?: number }).score === \"number\"\n ? ((m.frontmatter.importance as { score: number }).score ?? 0)\n : 0;\n const updated = m.frontmatter.updated ?? m.frontmatter.created ?? \"\";\n return { memory: m, score: importance * 2 + confidence, updated };\n });\n\n scored.sort((a, b) => {\n if (b.score !== a.score) return b.score - a.score;\n return b.updated.localeCompare(a.updated);\n });\n\n return scored.slice(0, limit).map((s) => s.memory);\n}\n\nfunction oneLineSummary(memory: MemoryFile): string {\n const raw = memory.content.replace(/\\s+/gu, \" \").trim();\n if (raw.length <= 160) return raw;\n return `${raw.slice(0, 157)}...`;\n}\n\nfunction groupMemoriesByCategory(memories: MemoryFile[]): Map<string, MemoryFile[]> {\n const map = new Map<string, MemoryFile[]>();\n for (const memory of memories) {\n if (memory.frontmatter.status && memory.frontmatter.status !== \"active\") continue;\n const category = memory.frontmatter.category ?? \"unknown\";\n const list = map.get(category) ?? [];\n list.push(memory);\n map.set(category, list);\n }\n return map;\n}\n\nfunction pickCategory(memories: MemoryFile[], categories: string[]): MemoryFile[] {\n const allowed = new Set(categories);\n return memories.filter(\n (m) =>\n (!m.frontmatter.status || m.frontmatter.status === \"active\") &&\n allowed.has(m.frontmatter.category ?? \"\"),\n );\n}\n\nfunction collectKeywords(memories: MemoryFile[], category: string, namespace: string): string[] {\n const keywords = new Set<string>();\n keywords.add(category);\n keywords.add(namespace);\n for (const mem of memories.slice(0, 10)) {\n for (const tag of mem.frontmatter.tags ?? []) {\n if (typeof tag === \"string\" && tag.trim().length > 0) keywords.add(tag.trim());\n }\n }\n return [...keywords].slice(0, 16);\n}\n\nfunction pruneRollouts(\n rollouts: RolloutSummaryInput[],\n retentionDays: number,\n now: Date,\n): RolloutSummaryInput[] {\n // Negative retention → \"infinite retention\" escape hatch. `parseConfig`\n // clamps the knob to >= 0, so in practice only callers passing a negative\n // value intentionally get the all-pass behavior.\n if (retentionDays < 0) return rollouts;\n // retentionDays === 0 → cutoff is exactly `now`, which prunes every\n // rollout whose `updatedAt` is in the past (i.e. all of them in practice).\n // This matches the documented semantics of \"retain for 0 days\".\n const cutoffMs = now.getTime() - retentionDays * 24 * 60 * 60 * 1000;\n return rollouts.filter((r) => {\n if (!r.updatedAt) return true;\n const t = Date.parse(r.updatedAt);\n if (!Number.isFinite(t)) return true;\n return t >= cutoffMs;\n });\n}\n\nfunction sanitizeSlug(slug: string): string {\n const sanitized = slug\n .toLowerCase()\n .replace(/[^a-z0-9._-]+/gu, \"-\")\n .slice(0, 96);\n const trimmed = trimHyphenEdges(sanitized);\n return trimmed || \"rollout\";\n}\n\nfunction trimHyphenEdges(value: string): string {\n let start = 0;\n let end = value.length;\n while (start < end && value[start] === \"-\") start += 1;\n while (end > start && value[end - 1] === \"-\") end -= 1;\n return value.slice(start, end);\n}\n/** Shared script-aware approximation used by the budget check. */\nexport function approximateTokenCount(text: string): number {\n return estimateTokenCount(text);\n}\n\n/**\n * Truncate `text` so it fits under `maxTokens`. We drop trailing lines until\n * under budget, then append a marker so readers can see that truncation occurred.\n */\nexport function truncateToTokenBudget(text: string, maxTokens: number): string {\n if (maxTokens <= 0) return \"\";\n if (approximateTokenCount(text) <= maxTokens) return text;\n\n const lineMarker = \"_[truncated for summary budget]_\";\n const tailMarker = \"[truncated]\";\n if (approximateTokenCount(tailMarker) > maxTokens) return \"\";\n const lineMarkerTokens = approximateTokenCount(lineMarker);\n\n const lines = text.split(/\\r?\\n/u);\n const lineBudget = Math.max(0, maxTokens - lineMarkerTokens);\n while (lines.length > 0 && approximateTokenCount(lines.join(\"\\n\")) > lineBudget) {\n lines.pop();\n }\n lines.push(lineMarker);\n let result = lines.join(\"\\n\");\n\n if (approximateTokenCount(result) > maxTokens) {\n const codePoints = [...result];\n let low = 0;\n let high = codePoints.length;\n while (low < high) {\n const mid = Math.ceil((low + high) / 2);\n const prefix = codePoints.slice(0, mid).join(\"\");\n const candidate = prefix.length > 0 ? `${prefix} ${tailMarker}` : tailMarker;\n if (approximateTokenCount(candidate) <= maxTokens) low = mid;\n else high = mid - 1;\n }\n const prefix = codePoints.slice(0, low).join(\"\");\n result = prefix.length > 0 ? `${prefix} ${tailMarker}` : tailMarker;\n }\n return result;\n}\n\nfunction computeContentHash(input: {\n namespace: string;\n memorySummary: string;\n memoryMd: string;\n rawMemories: string;\n rolloutFiles: Array<{ name: string; body: string }>;\n}): string {\n const hash = createHash(\"sha256\");\n hash.update(`v${MATERIALIZE_VERSION}\\n`);\n hash.update(`namespace=${input.namespace}\\n`);\n hash.update(\"---memory_summary---\\n\");\n hash.update(input.memorySummary);\n hash.update(\"\\n---memory_md---\\n\");\n hash.update(input.memoryMd);\n hash.update(\"\\n---raw_memories---\\n\");\n hash.update(input.rawMemories);\n const sortedRollouts = [...input.rolloutFiles].sort((a, b) => a.name.localeCompare(b.name));\n for (const r of sortedRollouts) {\n hash.update(`\\n---rollout:${r.name}---\\n`);\n hash.update(r.body);\n }\n return hash.digest(\"hex\");\n}\n\n// ─── Stat helper for tests / debugging ─────────────────────────────────────\n\n/**\n * Return basic stats about a materialized memories dir. Useful for tests and\n * debug CLI output. Returns `null` if the dir does not exist.\n */\nexport function describeMemoriesDir(memoriesDir: string): {\n exists: boolean;\n hasSentinel: boolean;\n files: string[];\n sentinel: SentinelFile | null;\n} | null {\n if (!fs.existsSync(memoriesDir)) return null;\n const sentinelPath = path.join(memoriesDir, SENTINEL_FILE);\n const sentinel = readSentinel(sentinelPath);\n const files: string[] = [];\n for (const entry of fs.readdirSync(memoriesDir, { withFileTypes: true })) {\n if (entry.isFile() && OWNED_FILES.has(entry.name)) files.push(entry.name);\n }\n const rolloutsDir = path.join(memoriesDir, ROLLOUT_SUBDIR);\n if (fs.existsSync(rolloutsDir)) {\n try {\n for (const entry of fs.readdirSync(rolloutsDir, { withFileTypes: true })) {\n if (entry.isFile() && entry.name.endsWith(\".md\")) {\n files.push(path.join(ROLLOUT_SUBDIR, entry.name));\n }\n }\n } catch {\n // ignore\n }\n }\n return {\n exists: true,\n hasSentinel: sentinel !== null,\n files: files.sort(),\n sentinel,\n };\n}\n"],"mappings":"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","names":["prefix"]}
@@ -4,14 +4,14 @@ import {
4
4
  } from "./chunk-WT6UL3UA.js";
5
5
  import {
6
6
  TranscriptManager
7
- } from "./chunk-HYQJQGD3.js";
7
+ } from "./chunk-AM4T6CHX.js";
8
8
  import {
9
9
  resolveCommitmentLedgerDir,
10
10
  validateCommitmentLedgerEntry
11
11
  } from "./chunk-NOB2T2FC.js";
12
12
  import {
13
13
  parseConfig
14
- } from "./chunk-3VFVQDZO.js";
14
+ } from "./chunk-4IIKJOYM.js";
15
15
  import {
16
16
  resolveObjectiveStateStoreDir,
17
17
  validateObjectiveStateSnapshot
@@ -268,4 +268,4 @@ export {
268
268
  recordResumeBundle,
269
269
  getResumeBundleStatus
270
270
  };
271
- //# sourceMappingURL=chunk-D4LVHPOA.js.map
271
+ //# sourceMappingURL=chunk-RXN7Z2V5.js.map
@@ -4,13 +4,13 @@ import {
4
4
  import {
5
5
  normalizeDreamsStatusWindowHours
6
6
  } from "./chunk-EQWEIIKQ.js";
7
- import {
8
- runContradictionScan
9
- } from "./chunk-7BY7V4YX.js";
10
7
  import {
11
8
  executeResolution,
12
9
  isValidResolutionVerb
13
10
  } from "./chunk-MDVBCPOS.js";
11
+ import {
12
+ runContradictionScan
13
+ } from "./chunk-7BY7V4YX.js";
14
14
  import {
15
15
  isDefaultReviewNamespace,
16
16
  listPairs,
@@ -28,10 +28,10 @@ import {
28
28
  defineOperation,
29
29
  parseNamespacePreflightWriteOp,
30
30
  resolveAuthorizedNamespaceWritablePreflight
31
- } from "./chunk-CZUHNJHX.js";
31
+ } from "./chunk-6C7Q6NG3.js";
32
32
  import {
33
33
  validateBriefingFormat
34
- } from "./chunk-CSV34HIW.js";
34
+ } from "./chunk-P5OYNV7B.js";
35
35
  import {
36
36
  enforceNamespaceAllowList,
37
37
  tokenCapabilityStore
@@ -494,4 +494,4 @@ defineOperation({ name: "graph_events", description: "SSE graph events.", schema
494
494
  defineOperation({ name: "chat_message", description: "Chat message.", schema: strictSchema({ message: S.str, chatSessionId: S.str }), handler: async (_i, _ctx) => ({ result: { ok: true } }) });
495
495
  defineOperation({ name: "chat_events", description: "SSE chat events.", schema: strictSchema({}), handler: async (_i, _ctx) => ({ result: { stream: "sse" } }) });
496
496
  defineOperation({ name: "adapters_status", description: "Adapter registry metadata (issue #1850 round 5). Marker op: the HTTP transport builds the response from its own adapterRegistry, but the op still must be registered so it appears in listRegisteredOperations and enforceTokenOp can gate it for scoped tokens.", schema: strictSchema({}), handler: async (_i, _ctx) => ({ result: { ok: true } }) });
497
- //# sourceMappingURL=chunk-7VSHDLJQ.js.map
497
+ //# sourceMappingURL=chunk-T2VJ2EO5.js.map
@@ -0,0 +1,20 @@
1
+ // src/token-estimate.ts
2
+ var NARROW_LETTER = /[\p{Script=Latin}\p{Script=Greek}\p{Script=Cyrillic}]/u;
3
+ function estimateTokenCount(text) {
4
+ let wideTokens = 0;
5
+ let narrowCodePoints = 0;
6
+ for (const char of text.normalize("NFC")) {
7
+ const codePoint = char.codePointAt(0) ?? 0;
8
+ if (codePoint <= 127 || NARROW_LETTER.test(char)) {
9
+ narrowCodePoints++;
10
+ } else {
11
+ wideTokens++;
12
+ }
13
+ }
14
+ return wideTokens + Math.ceil(narrowCodePoints / 4);
15
+ }
16
+
17
+ export {
18
+ estimateTokenCount
19
+ };
20
+ //# sourceMappingURL=chunk-TOTT6S2V.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/token-estimate.ts"],"sourcesContent":["const NARROW_LETTER = /[\\p{Script=Latin}\\p{Script=Greek}\\p{Script=Cyrillic}]/u;\n\n/**\n * Estimate model tokens without a tokenizer.\n *\n * Wide-script code points approximate one token each. Latin, Greek, Cyrillic,\n * punctuation, and symbols use the established four-code-point heuristic.\n * Unknown letters count conservatively as wide-script code points.\n */\nexport function estimateTokenCount(text: string): number {\n let wideTokens = 0;\n let narrowCodePoints = 0;\n for (const char of text.normalize(\"NFC\")) {\n const codePoint = char.codePointAt(0) ?? 0;\n if (codePoint <= 0x7f || NARROW_LETTER.test(char)) {\n narrowCodePoints++;\n } else {\n wideTokens++;\n }\n }\n return wideTokens + Math.ceil(narrowCodePoints / 4);\n}\n"],"mappings":";AAAA,IAAM,gBAAgB;AASf,SAAS,mBAAmB,MAAsB;AACvD,MAAI,aAAa;AACjB,MAAI,mBAAmB;AACvB,aAAW,QAAQ,KAAK,UAAU,KAAK,GAAG;AACxC,UAAM,YAAY,KAAK,YAAY,CAAC,KAAK;AACzC,QAAI,aAAa,OAAQ,cAAc,KAAK,IAAI,GAAG;AACjD;AAAA,IACF,OAAO;AACL;AAAA,IACF;AAAA,EACF;AACA,SAAO,aAAa,KAAK,KAAK,mBAAmB,CAAC;AACpD;","names":[]}
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-SOBJ6NEY.js";
4
4
  import {
5
5
  summarizeDisclosureTokens
6
- } from "./chunk-QKPDN325.js";
6
+ } from "./chunk-KF75ANST.js";
7
7
  import {
8
8
  summarizeRetrievedMemoryProvenance
9
9
  } from "./chunk-I4WBNM3M.js";
@@ -606,4 +606,4 @@ export {
606
606
  renderRecallExplain,
607
607
  parseRecallExplainFormat
608
608
  };
609
- //# sourceMappingURL=chunk-U7BMN33M.js.map
609
+ //# sourceMappingURL=chunk-UBSM6TZP.js.map
@@ -246,4 +246,4 @@ export {
246
246
  decryptCapsuleFile,
247
247
  decryptCapsuleFileInMemory
248
248
  };
249
- //# sourceMappingURL=chunk-DQEMWVMT.js.map
249
+ //# sourceMappingURL=chunk-UVYI6VIX.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SUPPORT_PASSPORT_DRAFT_MAX_CONTENT_CHARACTERS,
3
3
  SUPPORT_PASSPORT_DRAFT_MAX_MEMORIES
4
- } from "./chunk-CZUHNJHX.js";
4
+ } from "./chunk-6C7Q6NG3.js";
5
5
  import {
6
6
  SUPPORT_PASSPORT_SOURCE_MEMORY_ID_MAX_LENGTH
7
7
  } from "./chunk-XDL5CYZN.js";
@@ -343,4 +343,4 @@ export {
343
343
  parseSupportPassportModelJob,
344
344
  SupportPassportModelBridge
345
345
  };
346
- //# sourceMappingURL=chunk-U7XLOSG2.js.map
346
+ //# sourceMappingURL=chunk-VIM6QH4D.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  listNamespaces
3
- } from "./chunk-L3LRWDJW.js";
3
+ } from "./chunk-OV36CROW.js";
4
4
  import {
5
5
  capabilityAllowsNamespace
6
6
  } from "./chunk-MZWSOLMT.js";
@@ -282,4 +282,4 @@ export {
282
282
  computeServiceCorpusWatermarks,
283
283
  computeServiceCorpusCensus
284
284
  };
285
- //# sourceMappingURL=chunk-LJJWFV2Q.js.map
285
+ //# sourceMappingURL=chunk-VJXSAJFW.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-7T4TOGMS.js";
4
4
  import {
5
5
  defineOperation
6
- } from "./chunk-CZUHNJHX.js";
6
+ } from "./chunk-6C7Q6NG3.js";
7
7
 
8
8
  // src/external-wiki-access.ts
9
9
  import { z } from "zod";
@@ -26,4 +26,4 @@ var externalWikiSearchOperation = defineOperation({
26
26
  export {
27
27
  externalWikiSearchOperation
28
28
  };
29
- //# sourceMappingURL=chunk-HZC3OECF.js.map
29
+ //# sourceMappingURL=chunk-VOKK4WCG.js.map
@@ -1,14 +1,15 @@
1
1
  import {
2
2
  parseMessageParts
3
3
  } from "./chunk-AQEJKOKI.js";
4
+ import {
5
+ estimateTokenCount
6
+ } from "./chunk-TOTT6S2V.js";
4
7
  import {
5
8
  log
6
9
  } from "./chunk-3WCASNQZ.js";
7
10
 
8
11
  // src/lcm/archive.ts
9
- function estimateTokens(text) {
10
- return Math.ceil(text.length / 4);
11
- }
12
+ var estimateTokens = estimateTokenCount;
12
13
  var PUBLIC_LCM_SEARCH_LIMIT = 100;
13
14
  function normalizeSearchLimit(limit, fallback = 10, max = PUBLIC_LCM_SEARCH_LIMIT) {
14
15
  if (typeof limit !== "number" || !Number.isFinite(limit)) return fallback;
@@ -546,4 +547,4 @@ export {
546
547
  estimateTokens,
547
548
  LcmArchive
548
549
  };
549
- //# sourceMappingURL=chunk-LTAVSOZW.js.map
550
+ //# sourceMappingURL=chunk-WVP2I6C5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lcm/archive.ts"],"sourcesContent":["import type Database from \"better-sqlite3\";\nimport { log } from \"../logger.js\";\nimport {\n type LcmMessagePartInput,\n type MessagePartSourceFormat,\n parseMessageParts,\n} from \"../message-parts/index.js\";\nimport { estimateTokenCount } from \"../token-estimate.js\";\n\nexport interface LcmMessage {\n id: number;\n session_id: string;\n turn_index: number;\n role: string;\n content: string;\n token_count: number;\n created_at: string;\n metadata: string | null;\n}\n\nexport interface LcmSearchResult {\n turn_index: number;\n role: string;\n snippet: string;\n session_id: string;\n score: number;\n}\n\nexport interface LcmSearchWithContentResult {\n id: number;\n turn_index: number;\n role: string;\n content: string;\n session_id: string;\n score: number;\n}\n\nexport interface LcmStructuredRecallMatch {\n part_id: number;\n message_id: number;\n turn_index: number;\n role: string;\n content: string;\n session_id: string;\n kind: string;\n tool_name: string | null;\n file_path: string | null;\n payload: string;\n score: number;\n}\n\n/** Shared script-aware token estimate used by LCM accounting. */\nexport const estimateTokens = estimateTokenCount;\n\nconst PUBLIC_LCM_SEARCH_LIMIT = 100;\n\nfunction normalizeSearchLimit(limit: number, fallback = 10, max = PUBLIC_LCM_SEARCH_LIMIT): number {\n if (typeof limit !== \"number\" || !Number.isFinite(limit)) return fallback;\n const normalized = Math.floor(limit);\n if (normalized <= 0) return 0;\n return Math.min(max, normalized);\n}\n\nfunction escapeSqlLike(value: string): string {\n return value.replace(/[\\\\%_]/g, (match) => `\\\\${match}`);\n}\n\nexport class LcmArchive {\n constructor(private readonly db: Database.Database) {}\n\n /** Append a message to the archive. Returns the row id. */\n appendMessage(\n sessionId: string,\n turnIndex: number,\n role: string,\n content: string,\n metadata?: Record<string, unknown>,\n parts?: LcmMessagePartInput[],\n ): number {\n const tokenCount = estimateTokens(content);\n const now = new Date().toISOString();\n const metaJson = metadata ? JSON.stringify(metadata) : null;\n\n const stmt = this.db.prepare(`\n INSERT INTO lcm_messages (session_id, turn_index, role, content, token_count, created_at, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n const result = stmt.run(sessionId, turnIndex, role, content, tokenCount, now, metaJson);\n const rowId = Number(result.lastInsertRowid);\n\n // Keep FTS in sync\n this.db\n .prepare(\"INSERT INTO lcm_messages_fts (rowid, content) VALUES (?, ?)\")\n .run(rowId, content);\n\n if (parts && parts.length > 0) {\n this.insertMessageParts(rowId, parts, now);\n }\n\n return rowId;\n }\n\n /** Append multiple messages in a single transaction. */\n appendMessages(\n sessionId: string,\n messages: Array<{\n turnIndex: number;\n role: string;\n content: string;\n metadata?: Record<string, unknown>;\n parts?: LcmMessagePartInput[];\n rawContent?: unknown;\n sourceFormat?: MessagePartSourceFormat;\n }>,\n options: { messagePartsEnabled?: boolean } = {},\n ): void {\n if (messages.length === 0) return;\n const captureMessageParts = options.messagePartsEnabled !== false;\n\n const txn = this.db.transaction(() => {\n for (const msg of messages) {\n const explicitParts =\n msg.parts && msg.parts.length > 0 ? msg.parts : undefined;\n const rawContent = msg.rawContent ?? msg.content;\n const parts =\n captureMessageParts\n ? explicitParts ??\n parseMessageParts(rawContent, {\n sourceFormat: msg.sourceFormat,\n renderedContent: msg.content,\n })\n : undefined;\n this.appendMessage(\n sessionId,\n msg.turnIndex,\n msg.role,\n msg.content,\n msg.metadata,\n parts,\n );\n }\n });\n txn();\n }\n\n insertMessageParts(\n messageId: number,\n parts: LcmMessagePartInput[],\n fallbackCreatedAt: string,\n ): void {\n if (parts.length === 0) return;\n const stmt = this.db.prepare(`\n INSERT INTO lcm_message_parts (message_id, ordinal, kind, payload, tool_name, file_path, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n for (let index = 0; index < parts.length; index += 1) {\n const part = parts[index]!;\n const rawPart = part as unknown as Record<string, unknown>;\n const toolName = part.toolName ?? asNullableString(rawPart.tool_name);\n const filePath = part.filePath ?? asNullableString(rawPart.file_path);\n const createdAt = part.createdAt ?? asNullableString(rawPart.created_at);\n stmt.run(\n messageId,\n part.ordinal ?? index,\n part.kind,\n JSON.stringify(part.payload ?? {}),\n toolName ?? null,\n filePath ?? null,\n createdAt ?? fallbackCreatedAt,\n );\n }\n }\n\n /** Get the highest turn_index for a session, or -1 if none. */\n getMaxTurnIndex(sessionId: string): number {\n const row = this.db\n .prepare(\"SELECT MAX(turn_index) as max_turn FROM lcm_messages WHERE session_id = ?\")\n .get(sessionId) as { max_turn: number | null } | undefined;\n return row?.max_turn ?? -1;\n }\n\n /** Retrieve messages in a turn range (inclusive). */\n getMessages(sessionId: string, fromTurn: number, toTurn: number): LcmMessage[] {\n return this.db\n .prepare(\n \"SELECT * FROM lcm_messages WHERE session_id = ? AND turn_index >= ? AND turn_index <= ? ORDER BY turn_index\",\n )\n .all(sessionId, fromTurn, toTurn) as LcmMessage[];\n }\n\n /** Retrieve unsummarized messages (after last leaf summary). */\n getUnsummarizedMessages(sessionId: string): LcmMessage[] {\n const lastLeafEnd = this.db\n .prepare(\n \"SELECT MAX(msg_end) as last_end FROM lcm_summary_nodes WHERE session_id = ? AND depth = 0\",\n )\n .get(sessionId) as { last_end: number | null } | undefined;\n\n const lastSummarized = lastLeafEnd?.last_end ?? -1;\n return this.db\n .prepare(\n \"SELECT * FROM lcm_messages WHERE session_id = ? AND turn_index > ? ORDER BY turn_index\",\n )\n .all(sessionId, lastSummarized) as LcmMessage[];\n }\n\n /** Full-text search across all messages. */\n search(query: string, limit: number, sessionId?: string, sessionPrefix?: string): LcmSearchResult[] {\n try {\n const ftsQuery = sanitizeFtsQuery(query);\n if (!ftsQuery) return [];\n const cappedLimit = normalizeSearchLimit(limit);\n if (cappedLimit === 0) return [];\n\n let sql: string;\n const params: unknown[] = [ftsQuery];\n\n if (sessionId) {\n sql = `\n SELECT m.turn_index, m.role, snippet(lcm_messages_fts, 0, '>>>', '<<<', '...', 48) as snippet,\n m.session_id, rank\n FROM lcm_messages_fts f\n JOIN lcm_messages m ON m.id = f.rowid\n WHERE lcm_messages_fts MATCH ?\n AND m.session_id = ?\n ORDER BY rank\n LIMIT ?\n `;\n params.push(sessionId, cappedLimit);\n } else if (sessionPrefix) {\n sql = `\n SELECT m.turn_index, m.role, snippet(lcm_messages_fts, 0, '>>>', '<<<', '...', 48) as snippet,\n m.session_id, rank\n FROM lcm_messages_fts f\n JOIN lcm_messages m ON m.id = f.rowid\n WHERE lcm_messages_fts MATCH ?\n AND m.session_id LIKE ? ESCAPE '\\\\'\n ORDER BY rank\n LIMIT ?\n `;\n params.push(`${escapeSqlLike(sessionPrefix)}%`, cappedLimit);\n } else {\n sql = `\n SELECT m.turn_index, m.role, snippet(lcm_messages_fts, 0, '>>>', '<<<', '...', 48) as snippet,\n m.session_id, rank\n FROM lcm_messages_fts f\n JOIN lcm_messages m ON m.id = f.rowid\n WHERE lcm_messages_fts MATCH ?\n ORDER BY rank\n LIMIT ?\n `;\n params.push(cappedLimit);\n }\n\n const rows = this.db.prepare(sql).all(...params) as Array<{\n turn_index: number;\n role: string;\n snippet: string;\n session_id: string;\n rank: number;\n }>;\n\n return rows.map((r) => ({\n turn_index: r.turn_index,\n role: r.role,\n snippet: r.snippet,\n session_id: r.session_id,\n score: -r.rank, // FTS5 rank is negative; negate for ascending score\n }));\n } catch (err) {\n log.debug(`LCM FTS search error: ${err}`);\n return [];\n }\n }\n\n /**\n * Full-text search returning focused excerpts around matching terms.\n * Returns ~1000-char windows centered on query term matches.\n * Deduplicates by message id and returns results sorted by FTS rank.\n */\n searchWithContent(query: string, limit: number, sessionId?: string, excerptChars = 1000, sessionPrefix?: string): LcmSearchWithContentResult[] {\n try {\n const ftsQuery = sanitizeFtsQuery(query);\n if (!ftsQuery) return [];\n const cappedLimit = normalizeSearchLimit(limit);\n if (cappedLimit === 0) return [];\n\n // Extract content words from query for excerpt windowing\n const queryWords = query\n .replace(/[^\\w\\s]/g, \" \")\n .split(/\\s+/)\n .filter((w) => w.length > 1 && !STOPWORDS.has(w.toLowerCase()))\n .map((w) => w.toLowerCase());\n\n let sql: string;\n const params: unknown[] = [ftsQuery];\n\n if (sessionId) {\n sql = `\n SELECT m.id, m.turn_index, m.role, m.content, m.session_id, rank\n FROM lcm_messages_fts f\n JOIN lcm_messages m ON m.id = f.rowid\n WHERE lcm_messages_fts MATCH ?\n AND m.session_id = ?\n ORDER BY rank\n LIMIT ?\n `;\n params.push(sessionId, cappedLimit);\n } else if (sessionPrefix) {\n sql = `\n SELECT m.id, m.turn_index, m.role, m.content, m.session_id, rank\n FROM lcm_messages_fts f\n JOIN lcm_messages m ON m.id = f.rowid\n WHERE lcm_messages_fts MATCH ?\n AND m.session_id LIKE ? ESCAPE '\\\\'\n ORDER BY rank\n LIMIT ?\n `;\n params.push(`${escapeSqlLike(sessionPrefix)}%`, cappedLimit);\n } else {\n sql = `\n SELECT m.id, m.turn_index, m.role, m.content, m.session_id, rank\n FROM lcm_messages_fts f\n JOIN lcm_messages m ON m.id = f.rowid\n WHERE lcm_messages_fts MATCH ?\n ORDER BY rank\n LIMIT ?\n `;\n params.push(cappedLimit);\n }\n\n const rows = this.db.prepare(sql).all(...params) as Array<{\n id: number;\n turn_index: number;\n role: string;\n content: string;\n session_id: string;\n rank: number;\n }>;\n\n // Deduplicate by message id (same message may match multiple terms)\n const seen = new Set<number>();\n const results: LcmSearchWithContentResult[] = [];\n for (const r of rows) {\n if (seen.has(r.id)) continue;\n seen.add(r.id);\n results.push({\n id: r.id,\n turn_index: r.turn_index,\n role: r.role,\n content: extractExcerpt(r.content, queryWords, excerptChars),\n session_id: r.session_id,\n score: -r.rank,\n });\n }\n return results;\n } catch (err) {\n log.debug(`LCM FTS searchWithContent error: ${err}`);\n return [];\n }\n }\n\n searchStructuredParts(\n query: string,\n limit: number,\n sessionId?: string,\n ): LcmStructuredRecallMatch[] {\n const cappedLimit = Math.max(0, Math.min(20, Math.floor(limit)));\n if (cappedLimit === 0) return [];\n\n const fileTerms = extractStructuredFileTerms(query);\n const toolTerms = extractStructuredToolTerms(query);\n if (fileTerms.length === 0 && toolTerms.length === 0) return [];\n\n const matchWhere: string[] = [];\n const whereParams: unknown[] = [];\n for (const term of fileTerms) {\n matchWhere.push(\"(p.file_path = ? OR p.file_path LIKE ? ESCAPE '\\\\')\");\n whereParams.push(term, `%${escapeLike(term)}%`);\n }\n for (const term of toolTerms) {\n matchWhere.push(\"p.tool_name LIKE ? ESCAPE '\\\\'\");\n whereParams.push(`%${escapeLike(term)}%`);\n }\n const where = [`(${matchWhere.join(\" OR \")})`];\n if (sessionId) {\n where.push(\"m.session_id = ?\");\n whereParams.push(sessionId);\n }\n const exactFileScoreParams = [...fileTerms];\n const sqlParams = [...exactFileScoreParams, ...whereParams, cappedLimit];\n\n const rows = this.db.prepare(`\n SELECT\n p.id AS part_id,\n p.message_id AS message_id,\n m.turn_index AS turn_index,\n m.role AS role,\n m.content AS content,\n m.session_id AS session_id,\n p.kind AS kind,\n p.tool_name AS tool_name,\n p.file_path AS file_path,\n p.payload AS payload,\n CASE\n WHEN p.file_path IN (${fileTerms.map(() => \"?\").join(\",\") || \"NULL\"}) THEN 3\n WHEN p.file_path IS NOT NULL THEN 2\n WHEN p.tool_name IS NOT NULL THEN 1\n ELSE 0\n END AS score\n FROM lcm_message_parts p\n JOIN lcm_messages m ON m.id = p.message_id\n WHERE ${where.join(\" AND \")}\n ORDER BY score DESC, m.turn_index DESC, p.ordinal ASC\n LIMIT ?\n `).all(...sqlParams) as LcmStructuredRecallMatch[];\n\n return rows;\n }\n\n /** Get total message count for a session. */\n getMessageCount(sessionId: string): number {\n const row = this.db\n .prepare(\"SELECT COUNT(*) as cnt FROM lcm_messages WHERE session_id = ?\")\n .get(sessionId) as { cnt: number };\n return row.cnt;\n }\n\n /** Get total message count across all sessions. */\n getTotalMessageCount(): number {\n const row = this.db\n .prepare(\"SELECT COUNT(*) as cnt FROM lcm_messages\")\n .get() as { cnt: number };\n return row.cnt;\n }\n\n /** Delete all archived messages for one session. */\n deleteSession(sessionId: string): number {\n const txn = this.db.transaction(() => {\n this.db\n .prepare(\n \"DELETE FROM lcm_messages_fts WHERE rowid IN (SELECT id FROM lcm_messages WHERE session_id = ?)\",\n )\n .run(sessionId);\n this.db\n .prepare(\n \"DELETE FROM lcm_message_parts WHERE message_id IN (SELECT id FROM lcm_messages WHERE session_id = ?)\",\n )\n .run(sessionId);\n const result = this.db\n .prepare(\"DELETE FROM lcm_messages WHERE session_id = ?\")\n .run(sessionId);\n return result.changes;\n });\n return txn();\n }\n\n /** Delete all archived messages. */\n deleteAll(): number {\n const txn = this.db.transaction(() => {\n this.db.prepare(\"DELETE FROM lcm_messages_fts\").run();\n this.db.prepare(\"DELETE FROM lcm_message_parts\").run();\n const result = this.db.prepare(\"DELETE FROM lcm_messages\").run();\n return result.changes;\n });\n return txn();\n }\n\n /** Prune messages older than retentionDays. */\n pruneOldMessages(retentionDays: number): number {\n const cutoff = new Date(Date.now() - retentionDays * 86400_000).toISOString();\n\n const txn = this.db.transaction(() => {\n // Delete from FTS and child tables first. Some handles may not have\n // foreign_keys enabled, so do not rely on ON DELETE CASCADE for parts.\n this.db\n .prepare(\n \"DELETE FROM lcm_messages_fts WHERE rowid IN (SELECT id FROM lcm_messages WHERE created_at < ?)\",\n )\n .run(cutoff);\n this.db\n .prepare(\n \"DELETE FROM lcm_message_parts WHERE message_id IN (SELECT id FROM lcm_messages WHERE created_at < ?)\",\n )\n .run(cutoff);\n\n const result = this.db\n .prepare(\"DELETE FROM lcm_messages WHERE created_at < ?\")\n .run(cutoff);\n return result.changes;\n });\n return txn();\n }\n}\n\n/**\n * Extract a focused excerpt from content centered on query term matches.\n * Returns a window of ~excerptChars around the first matching term.\n * If content is shorter than excerptChars, returns the full content.\n */\nfunction extractExcerpt(content: string, queryWords: string[], excerptChars: number): string {\n if (content.length <= excerptChars) return content;\n\n // Find the earliest position of any query word in the content\n const contentLower = content.toLowerCase();\n let bestPos = -1;\n for (const word of queryWords) {\n const pos = contentLower.indexOf(word);\n if (pos !== -1 && (bestPos === -1 || pos < bestPos)) {\n bestPos = pos;\n }\n }\n\n // If no match found (shouldn't happen for FTS results), return start\n if (bestPos === -1) {\n return content.slice(0, excerptChars) + \"...\";\n }\n\n // Center the window around the match\n const halfWindow = Math.floor(excerptChars / 2);\n let start = Math.max(0, bestPos - halfWindow);\n let end = Math.min(content.length, start + excerptChars);\n\n // Adjust start if we hit the end\n if (end === content.length) {\n start = Math.max(0, end - excerptChars);\n }\n\n // Extend to sentence boundaries if possible\n if (start > 0) {\n const sentenceStart = content.lastIndexOf(\". \", start);\n if (sentenceStart !== -1 && start - sentenceStart < 200) {\n start = sentenceStart + 2;\n }\n }\n if (end < content.length) {\n const sentenceEnd = content.indexOf(\". \", end - 1);\n if (sentenceEnd !== -1 && sentenceEnd - end < 200) {\n end = sentenceEnd + 1;\n }\n }\n\n const prefix = start > 0 ? \"...\" : \"\";\n const suffix = end < content.length ? \"...\" : \"\";\n return prefix + content.slice(start, end) + suffix;\n}\n\nconst STOPWORDS = new Set([\n \"a\", \"an\", \"the\", \"is\", \"are\", \"was\", \"were\", \"be\", \"been\", \"being\",\n \"have\", \"has\", \"had\", \"do\", \"does\", \"did\", \"will\", \"would\", \"could\",\n \"should\", \"may\", \"might\", \"shall\", \"can\", \"to\", \"of\", \"in\", \"for\",\n \"on\", \"with\", \"at\", \"by\", \"from\", \"as\", \"into\", \"about\", \"between\",\n \"through\", \"during\", \"before\", \"after\", \"and\", \"but\", \"or\", \"nor\",\n \"not\", \"so\", \"if\", \"then\", \"than\", \"that\", \"this\", \"it\", \"its\",\n \"what\", \"which\", \"who\", \"whom\", \"how\", \"when\", \"where\", \"why\",\n \"all\", \"each\", \"every\", \"both\", \"few\", \"more\", \"most\", \"other\",\n \"some\", \"such\", \"no\", \"only\", \"own\", \"same\", \"just\", \"very\",\n \"my\", \"your\", \"his\", \"her\", \"our\", \"their\", \"me\", \"him\", \"us\", \"them\",\n \"i\", \"you\", \"he\", \"she\", \"we\", \"they\",\n]);\n\nfunction extractStructuredFileTerms(query: string): string[] {\n const terms = new Set<string>();\n for (const raw of splitQueryTerms(query)) {\n const cleaned = trimStructuredQueryTerm(raw);\n if (\n cleaned.includes(\"/\") ||\n hasStructuredFileExtension(cleaned)\n ) {\n terms.add(cleaned);\n const basename = cleaned.split(\"/\").pop();\n if (basename && basename !== cleaned) terms.add(basename);\n }\n }\n return [...terms].filter((term) => term.length > 1).slice(0, 12);\n}\n\nfunction splitQueryTerms(query: string): string[] {\n const terms: string[] = [];\n let term = \"\";\n for (const char of query.slice(0, 20_000)) {\n if (char === \" \" || char === \"\\n\" || char === \"\\r\" || char === \"\\t\") {\n if (term.length > 0) terms.push(term);\n term = \"\";\n continue;\n }\n term += char;\n if (term.length > 512) {\n terms.push(term);\n term = \"\";\n }\n }\n if (term.length > 0) terms.push(term);\n return terms;\n}\n\nfunction trimStructuredQueryTerm(raw: string): string {\n const leading = new Set([\"`\", \"'\", \"\\\"\", \"(\", \"[\", \"{\"]);\n const trailing = new Set([\"`\", \"'\", \"\\\"\", \",\", \".\", \"?\", \"!\", \":\", \";\", \")\", \"]\", \"}\"]);\n let start = 0;\n let end = raw.length;\n while (start < end && leading.has(raw[start]!)) start += 1;\n while (end > start && trailing.has(raw[end - 1]!)) end -= 1;\n return raw.slice(start, end);\n}\n\nfunction hasStructuredFileExtension(value: string): boolean {\n const slash = value.lastIndexOf(\"/\");\n const basename = value.slice(slash + 1);\n const dot = basename.lastIndexOf(\".\");\n if (dot <= 0 || dot === basename.length - 1) return false;\n const ext = basename.slice(dot + 1);\n if (ext.length < 1 || ext.length > 12) return false;\n for (const char of ext) {\n const code = char.charCodeAt(0);\n const valid =\n (code >= 48 && code <= 57) ||\n (code >= 65 && code <= 90) ||\n (code >= 97 && code <= 122) ||\n char === \"_\" ||\n char === \"+\" ||\n char === \"-\";\n if (!valid) return false;\n }\n return true;\n}\n\nfunction extractStructuredToolTerms(query: string): string[] {\n const lower = query.toLowerCase();\n if (!/\\b(tool|command|invocation|called|used|ran|read|write|patch|edit|grep|search)\\b/.test(lower)) {\n return [];\n }\n return query\n .replace(/[^\\w.-]/g, \" \")\n .split(/\\s+/)\n .filter((term) => term.length > 2 && !STOPWORDS.has(term.toLowerCase()))\n .slice(0, 8);\n}\n\nfunction escapeLike(value: string): string {\n return value.replace(/[\\\\%_]/g, (char) => `\\\\${char}`);\n}\n\nfunction asNullableString(value: unknown): string | null {\n return typeof value === \"string\" && value.trim().length > 0 ? value : null;\n}\n\n/**\n * Sanitize a query for FTS5 MATCH.\n * Uses OR logic so partial matches rank higher than no matches.\n * Filters stopwords to focus on content words.\n */\nfunction sanitizeFtsQuery(raw: string): string {\n const words = raw\n .replace(/[^\\w\\s]/g, \" \")\n .split(/\\s+/)\n .filter((w) => w.length > 1 && !STOPWORDS.has(w.toLowerCase()));\n if (words.length === 0) {\n // If all words were stopwords, fall back to using all words\n const allWords = raw.replace(/[^\\w\\s]/g, \" \").split(/\\s+/).filter((w) => w.length > 1);\n if (allWords.length === 0) return \"\";\n return allWords.map((w) => `\"${w}\"`).join(\" OR \");\n }\n return words.map((w) => `\"${w}\"`).join(\" OR \");\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SupportPassportError,
3
3
  getOperation
4
- } from "./chunk-CZUHNJHX.js";
4
+ } from "./chunk-6C7Q6NG3.js";
5
5
  import {
6
6
  abortError,
7
7
  isAbortError
@@ -499,4 +499,4 @@ export {
499
499
  buildSupportPassportPublicRequestHandler,
500
500
  composeSupportPassportExternalRequestHandlers
501
501
  };
502
- //# sourceMappingURL=chunk-LRDP2AC2.js.map
502
+ //# sourceMappingURL=chunk-YBCZTBN2.js.map
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  computeCorpusWatermarks,
6
6
  resolveCorpusNamespaceRoots
7
- } from "./chunk-LJJWFV2Q.js";
7
+ } from "./chunk-VJXSAJFW.js";
8
8
 
9
9
  // src/operator-doctor-corpus.ts
10
10
  var DIGEST_PREFIX_LENGTH = 12;
@@ -78,4 +78,4 @@ export {
78
78
  corpusWatermarksFromCheck,
79
79
  summarizeCorpusAndReplica
80
80
  };
81
- //# sourceMappingURL=chunk-USAUBGBC.js.map
81
+ //# sourceMappingURL=chunk-YKZFX2HQ.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  StorageManager
3
- } from "./chunk-YTZA7U6Q.js";
3
+ } from "./chunk-2VHCLHZ5.js";
4
4
  import {
5
5
  composeMemoryEnvelope
6
6
  } from "./chunk-LCU5R6TQ.js";
@@ -546,4 +546,4 @@ export {
546
546
  setSemanticRulePromotionTestHooks,
547
547
  promoteSemanticRuleFromMemory
548
548
  };
549
- //# sourceMappingURL=chunk-I2GIYTRU.js.map
549
+ //# sourceMappingURL=chunk-ZOGOOSB3.js.map
@@ -1,9 +1,12 @@
1
1
  import {
2
2
  estimateTokens
3
- } from "./chunk-LTAVSOZW.js";
3
+ } from "./chunk-WVP2I6C5.js";
4
4
  import {
5
5
  looksLikeMechanicalTelemetryTranscript
6
6
  } from "./chunk-4RA3C3EV.js";
7
+ import {
8
+ estimateTokenCount
9
+ } from "./chunk-TOTT6S2V.js";
7
10
  import {
8
11
  log
9
12
  } from "./chunk-3WCASNQZ.js";
@@ -140,26 +143,35 @@ var LcmSummarizer = class {
140
143
  }
141
144
  };
142
145
  function deterministicTruncate(text, maxTokens) {
143
- const maxChars = maxTokens * 4;
144
- if (text.length <= maxChars) return text;
146
+ if (maxTokens <= 0 || estimateTokenCount(text) <= maxTokens) return text;
145
147
  const sentences = text.split(/(?<=[.!?])\s+/).filter((s) => s.length > 0);
146
- if (sentences.length <= 2) {
147
- return text.slice(0, maxChars);
148
- }
148
+ if (sentences.length <= 2) return clampToTokenBudget(text, maxTokens);
149
149
  const first = sentences[0];
150
150
  const last = sentences[sentences.length - 1];
151
- const budget = maxChars - first.length - last.length - 20;
152
- if (budget <= 0) {
153
- return text.slice(0, maxChars);
154
- }
151
+ const render = (middle2, truncated2) => `${first} ${middle2.join(" ")}${truncated2 ? " [...] " : " "}${last}`;
152
+ const base = render([], false);
153
+ if (estimateTokenCount(base) > maxTokens) return clampToTokenBudget(text, maxTokens);
154
+ if (estimateTokenCount(render([], true)) > maxTokens) return base;
155
155
  const middle = [];
156
- let used = 0;
157
156
  for (let i = 1; i < sentences.length - 1; i++) {
158
- if (used + sentences[i].length > budget) break;
157
+ const candidate = [...middle, sentences[i]];
158
+ const truncated2 = i < sentences.length - 2;
159
+ if (estimateTokenCount(render(candidate, truncated2)) > maxTokens) break;
159
160
  middle.push(sentences[i]);
160
- used += sentences[i].length;
161
161
  }
162
- return `${first} ${middle.join(" ")}${middle.length < sentences.length - 2 ? " [...] " : " "}${last}`;
162
+ const truncated = middle.length < sentences.length - 2;
163
+ return clampToTokenBudget(render(middle, truncated), maxTokens);
164
+ }
165
+ function clampToTokenBudget(text, maxTokens) {
166
+ const codePoints = [...text];
167
+ let low = 0;
168
+ let high = codePoints.length;
169
+ while (low < high) {
170
+ const mid = Math.ceil((low + high) / 2);
171
+ if (estimateTokenCount(codePoints.slice(0, mid).join("")) <= maxTokens) low = mid;
172
+ else high = mid - 1;
173
+ }
174
+ return codePoints.slice(0, low).join("");
163
175
  }
164
176
  function chunkArray(arr, size) {
165
177
  const chunks = [];
@@ -172,4 +184,4 @@ function chunkArray(arr, size) {
172
184
  export {
173
185
  LcmSummarizer
174
186
  };
175
- //# sourceMappingURL=chunk-PBGWYM3H.js.map
187
+ //# sourceMappingURL=chunk-ZPUIRTIZ.js.map