@remnic/core 9.69.40 → 9.69.42

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 (688) hide show
  1. package/dist/access-admin-ops-surface.d.ts +14 -13
  2. package/dist/access-admin-ops-surface.js +79 -78
  3. package/dist/access-audit.js +2 -2
  4. package/dist/access-authorization-probe.d.ts +14 -13
  5. package/dist/access-authorization-probe.js +80 -79
  6. package/dist/access-boundary.d.ts +14 -13
  7. package/dist/access-boundary.js +79 -78
  8. package/dist/access-cli.js +170 -168
  9. package/dist/access-cli.js.map +1 -1
  10. package/dist/access-coding-context-resolution.d.ts +1 -1
  11. package/dist/access-extraction-force-flush.d.ts +14 -13
  12. package/dist/access-extraction-force-flush.js +79 -78
  13. package/dist/access-health-types.d.ts +1 -1
  14. package/dist/access-http-briefing.d.ts +14 -13
  15. package/dist/access-http-briefing.js +80 -79
  16. package/dist/access-http-lcm-compaction.d.ts +14 -13
  17. package/dist/access-http-lifecycle-flush.d.ts +14 -13
  18. package/dist/access-http-offline-stream.d.ts +14 -13
  19. package/dist/access-http-query.d.ts +2 -2
  20. package/dist/access-http-query.js +81 -80
  21. package/dist/access-http.d.ts +15 -14
  22. package/dist/access-http.js +100 -97
  23. package/dist/access-identity-continuity-surface.d.ts +11 -11
  24. package/dist/access-identity-continuity-surface.js +79 -78
  25. package/dist/access-lcm-surface.d.ts +14 -13
  26. package/dist/access-lcm-surface.js +79 -78
  27. package/dist/access-mcp-shared-context-tools.d.ts +157 -0
  28. package/dist/access-mcp-shared-context-tools.js +8 -0
  29. package/dist/access-mcp.d.ts +14 -13
  30. package/dist/access-mcp.js +91 -88
  31. package/dist/access-memory-search-fanout.d.ts +2 -2
  32. package/dist/{access-namespace-preflight-CKBumJ8W.d.ts → access-namespace-preflight-ShnAJ9uL.d.ts} +1 -1
  33. package/dist/access-namespace-preflight.d.ts +3 -3
  34. package/dist/access-namespace-preflight.js +79 -78
  35. package/dist/access-observe-transcript.d.ts +11 -11
  36. package/dist/access-observe-write-category.d.ts +17 -1
  37. package/dist/access-observe-write-category.js +21 -4
  38. package/dist/access-observe-write-surface.d.ts +14 -13
  39. package/dist/access-observe-write-surface.js +79 -78
  40. package/dist/access-offline-manifest.d.ts +11 -11
  41. package/dist/access-offline-manifest.js +14 -14
  42. package/dist/access-operations-batch.js +84 -82
  43. package/dist/access-operations.d.ts +14 -13
  44. package/dist/access-operations.js +89 -87
  45. package/dist/access-recall-concurrency.d.ts +14 -13
  46. package/dist/access-recall-concurrency.js +79 -78
  47. package/dist/access-recall-response.d.ts +14 -13
  48. package/dist/access-recall-response.js +79 -78
  49. package/dist/access-recall-surface.d.ts +14 -13
  50. package/dist/access-recall-surface.js +79 -78
  51. package/dist/access-schema.d.ts +117 -114
  52. package/dist/access-schema.js +3 -3
  53. package/dist/{access-service-DJ3qogNt.d.ts → access-service-DjG_e2cM.d.ts} +81 -75
  54. package/dist/access-service-helpers.d.ts +14 -13
  55. package/dist/access-service.d.ts +14 -13
  56. package/dist/access-service.js +79 -78
  57. package/dist/access-surface-catalog.d.ts +14 -13
  58. package/dist/access-surface-catalog.js +81 -80
  59. package/dist/access-surface-catalog.js.map +1 -1
  60. package/dist/access-wearables-meetings-surface.d.ts +4 -4
  61. package/dist/action-confidence.d.ts +1 -1
  62. package/dist/active-memory-bridge.d.ts +1 -1
  63. package/dist/active-memory-bridge.js +3 -3
  64. package/dist/active-recall.d.ts +1 -1
  65. package/dist/active-recall.js +10 -10
  66. package/dist/activity/digest.d.ts +1 -1
  67. package/dist/ambient-provenance.d.ts +1 -1
  68. package/dist/artifact-search.d.ts +1 -1
  69. package/dist/{auto-sync-D6BAPIJV.js → auto-sync-QZD4RD6H.js} +14 -10
  70. package/dist/{auto-sync-D6BAPIJV.js.map → auto-sync-QZD4RD6H.js.map} +1 -1
  71. package/dist/background-generation.d.ts +1 -1
  72. package/dist/behavior-learner.d.ts +1 -1
  73. package/dist/behavior-signals.d.ts +1 -1
  74. package/dist/bootstrap.d.ts +11 -11
  75. package/dist/briefing-window.d.ts +2 -2
  76. package/dist/briefing.d.ts +2 -2
  77. package/dist/briefing.js +22 -22
  78. package/dist/buffer-surprise-report.d.ts +1 -1
  79. package/dist/buffer-turn-helpers.d.ts +1 -1
  80. package/dist/buffer.d.ts +2 -2
  81. package/dist/buffer.js +9 -9
  82. package/dist/bulk-import/index.d.ts +3 -3
  83. package/dist/calibration.d.ts +1 -1
  84. package/dist/calibration.js +2 -2
  85. package/dist/capabilities.d.ts +1 -1
  86. package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-YO5QJ6L3.js} +2 -2
  87. package/dist/{capsule-merge-IPG4IOFP.js → capsule-merge-3MNURAQ3.js} +2 -2
  88. package/dist/{catalog-BHXkBVhg.d.ts → catalog-BhuXaQHx.d.ts} +1 -1
  89. package/dist/causal-behavior.d.ts +1 -1
  90. package/dist/causal-consolidation.d.ts +1 -1
  91. package/dist/causal-consolidation.js +25 -25
  92. package/dist/causal-trajectory-graph.d.ts +1 -1
  93. package/dist/{chunk-M6RORUO5.js → chunk-2EYZ32LH.js} +24 -2
  94. package/dist/{chunk-M6RORUO5.js.map → chunk-2EYZ32LH.js.map} +1 -1
  95. package/dist/{chunk-JAJIMTFB.js → chunk-2PDMIPMP.js} +9 -9
  96. package/dist/{chunk-5LYSEZOF.js → chunk-2UINSKQC.js} +12 -11
  97. package/dist/chunk-2UINSKQC.js.map +1 -0
  98. package/dist/{chunk-6L2II3KS.js → chunk-3D75XIYO.js} +2 -2
  99. package/dist/{chunk-XCPNH2MG.js → chunk-3KJTSCSX.js} +5 -5
  100. package/dist/{chunk-YTZN2UZO.js → chunk-3RLWUW7G.js} +2 -2
  101. package/dist/{chunk-J272ODKJ.js → chunk-42DJ235G.js} +2 -2
  102. package/dist/{chunk-NVVZPBKI.js → chunk-46FVFU7S.js} +2 -2
  103. package/dist/{chunk-JUDT33RX.js → chunk-4AX5OYKC.js} +2 -2
  104. package/dist/{chunk-GSSDHAYH.js → chunk-4IGOLIWM.js} +2 -2
  105. package/dist/{chunk-23HFXQ5J.js → chunk-6EGIQEKC.js} +4 -4
  106. package/dist/{chunk-TVVEYCNW.js → chunk-7K5Q6COX.js} +4 -4
  107. package/dist/{chunk-GO5LOHCD.js → chunk-7L54ARML.js} +2 -2
  108. package/dist/{chunk-TEMKBSV6.js → chunk-7PSRCGWT.js} +3 -3
  109. package/dist/{chunk-ICNJ6J46.js → chunk-AAAFZW3U.js} +2 -2
  110. package/dist/{chunk-K4JKAXMO.js → chunk-AAX22E4K.js} +3 -3
  111. package/dist/{chunk-UZ6JYPJ6.js → chunk-ADARR5KF.js} +232 -171
  112. package/dist/chunk-ADARR5KF.js.map +1 -0
  113. package/dist/{chunk-KY236SP5.js → chunk-AHHFBJX7.js} +3 -3
  114. package/dist/{chunk-TZ44E732.js → chunk-AIVRD66I.js} +2 -2
  115. package/dist/{chunk-OEDW4ER7.js → chunk-AJBWVDRV.js} +2 -1
  116. package/dist/chunk-AJBWVDRV.js.map +1 -0
  117. package/dist/{chunk-YRIFXXMI.js → chunk-AOGICQMH.js} +6 -6
  118. package/dist/{chunk-KOTG3RXE.js → chunk-AUSRUOMQ.js} +2 -2
  119. package/dist/{chunk-C5R73BON.js → chunk-BIANISES.js} +2 -2
  120. package/dist/{chunk-IMBQFHRV.js → chunk-BPXJINHW.js} +8 -8
  121. package/dist/{chunk-2NLLXCJG.js → chunk-BXLOS5AJ.js} +2 -2
  122. package/dist/{chunk-2J3V5QEO.js → chunk-C3QXITIP.js} +4 -4
  123. package/dist/{chunk-2SNCQHJZ.js → chunk-CQ4BTPX6.js} +6 -6
  124. package/dist/{chunk-3QEVOQF5.js → chunk-CTETTVDN.js} +2 -2
  125. package/dist/{chunk-DFVSJFHK.js → chunk-DBB5JPSL.js} +2 -2
  126. package/dist/{chunk-W23JARAQ.js → chunk-DLPMOSNH.js} +2 -2
  127. package/dist/{chunk-BGRTZOJB.js → chunk-DMTSKY4W.js} +8 -8
  128. package/dist/{chunk-X7Y7WX73.js → chunk-DQEMWVMT.js} +1 -1
  129. package/dist/{chunk-QS5Q5RBV.js → chunk-E4FRR4MA.js} +8 -8
  130. package/dist/{chunk-NETQXOPY.js → chunk-EH3HNCAM.js} +12 -7
  131. package/dist/{chunk-NETQXOPY.js.map → chunk-EH3HNCAM.js.map} +1 -1
  132. package/dist/{chunk-RJQAP333.js → chunk-ETE3SGAH.js} +2 -2
  133. package/dist/{chunk-YNDLCWXS.js → chunk-EZ25VE3G.js} +4 -4
  134. package/dist/{chunk-RLU2Y5GV.js → chunk-F2FJTOV6.js} +4 -4
  135. package/dist/{chunk-V2ZA4YWE.js → chunk-F5H6YG5P.js} +2 -2
  136. package/dist/{chunk-K75A5XWU.js → chunk-F6PTJLEM.js} +4 -4
  137. package/dist/chunk-F6PTJLEM.js.map +1 -0
  138. package/dist/{chunk-4CMXI55L.js → chunk-FSUFKIFS.js} +2 -2
  139. package/dist/{chunk-ZAEPD4C2.js → chunk-G3NTZZWT.js} +2 -2
  140. package/dist/{chunk-ZMWSYUUL.js → chunk-GCBIXUPT.js} +2 -2
  141. package/dist/{chunk-WZYHPAG5.js → chunk-GIM2AGFL.js} +3 -3
  142. package/dist/{chunk-VKWFNPBH.js → chunk-GR76OKET.js} +14 -5
  143. package/dist/{chunk-VKWFNPBH.js.map → chunk-GR76OKET.js.map} +1 -1
  144. package/dist/{chunk-J7FVMLBR.js → chunk-GWEZNCGA.js} +2 -2
  145. package/dist/{chunk-LFVZD5EC.js → chunk-GWNSKQDA.js} +3 -3
  146. package/dist/{chunk-MJC7UKH7.js → chunk-H2N6SLTR.js} +2 -2
  147. package/dist/{chunk-J4WGTN2N.js → chunk-HK44SV6K.js} +4 -4
  148. package/dist/{chunk-JDX2OA4R.js → chunk-HNHIHXSD.js} +2 -2
  149. package/dist/{chunk-IS2IDFJP.js → chunk-HO2P3FAX.js} +22 -22
  150. package/dist/chunk-HO2P3FAX.js.map +1 -0
  151. package/dist/{chunk-VQYWKCDR.js → chunk-HPMCKAET.js} +3 -3
  152. package/dist/{chunk-ROEFLU37.js → chunk-HSJU6JFT.js} +16 -86
  153. package/dist/chunk-HSJU6JFT.js.map +1 -0
  154. package/dist/{chunk-MVG3KXON.js → chunk-I65KB36L.js} +25 -25
  155. package/dist/chunk-IFBSZGW3.js +42 -0
  156. package/dist/chunk-IFBSZGW3.js.map +1 -0
  157. package/dist/{chunk-SFHLQPBF.js → chunk-IUTYNDFS.js} +118 -112
  158. package/dist/chunk-IUTYNDFS.js.map +1 -0
  159. package/dist/{chunk-AEOOGXMQ.js → chunk-J2MGTGKC.js} +4 -4
  160. package/dist/chunk-JATHBCAV.js +94 -0
  161. package/dist/chunk-JATHBCAV.js.map +1 -0
  162. package/dist/{chunk-PKUJNICO.js → chunk-JC2OBYYD.js} +2 -2
  163. package/dist/{chunk-5U7K4W6K.js → chunk-JDOBQPJY.js} +3 -3
  164. package/dist/{chunk-TG3FAM2S.js → chunk-JL4TQYM5.js} +48 -1
  165. package/dist/{chunk-TG3FAM2S.js.map → chunk-JL4TQYM5.js.map} +1 -1
  166. package/dist/{chunk-VQWBUPSJ.js → chunk-JMAP6L6Q.js} +2 -2
  167. package/dist/{chunk-7Z54NXVS.js → chunk-K27INAPR.js} +2 -2
  168. package/dist/{chunk-YTK5MVNF.js → chunk-KCKXOS4Y.js} +14 -13
  169. package/dist/chunk-KCKXOS4Y.js.map +1 -0
  170. package/dist/{chunk-7D6SER6A.js → chunk-KJQ4Y2PY.js} +14 -14
  171. package/dist/{chunk-DAZANIYU.js → chunk-L732NBPR.js} +87 -88
  172. package/dist/{chunk-DAZANIYU.js.map → chunk-L732NBPR.js.map} +1 -1
  173. package/dist/{chunk-QPVNK2VE.js → chunk-LCVYO3ON.js} +2 -2
  174. package/dist/{chunk-HIP6DKJJ.js → chunk-LQVXSRAJ.js} +2 -2
  175. package/dist/{chunk-A7GQBJP5.js → chunk-LVFI5LG7.js} +7 -7
  176. package/dist/{chunk-TO36VPZI.js → chunk-LWF6GOII.js} +2 -2
  177. package/dist/{chunk-62HFZNCJ.js → chunk-N7B6V7SG.js} +13 -12
  178. package/dist/{chunk-62HFZNCJ.js.map → chunk-N7B6V7SG.js.map} +1 -1
  179. package/dist/{chunk-ES5BUPYB.js → chunk-OCWFKD5Q.js} +2 -2
  180. package/dist/{chunk-IOPIGX7Y.js → chunk-OP722LOG.js} +2 -2
  181. package/dist/{chunk-62D2PAAM.js → chunk-PAAJWQH5.js} +4 -4
  182. package/dist/{chunk-V6EGNVUT.js → chunk-PIWFNPQT.js} +4 -4
  183. package/dist/{chunk-JOP7W24J.js → chunk-PLJ2MQFT.js} +4 -4
  184. package/dist/{chunk-37CAEC7E.js → chunk-PWPIERBM.js} +4 -4
  185. package/dist/{chunk-BXIJSPCL.js → chunk-Q62GA5U2.js} +2 -2
  186. package/dist/{chunk-CC37E3QM.js → chunk-QKCXRS5A.js} +16 -1
  187. package/dist/chunk-QKCXRS5A.js.map +1 -0
  188. package/dist/{chunk-I3H5LFOI.js → chunk-QNJQCLI6.js} +4 -4
  189. package/dist/{chunk-BYQX4IOG.js → chunk-R45VFSEV.js} +2 -2
  190. package/dist/{chunk-XVDZFTN5.js → chunk-RFIJH2OE.js} +5 -5
  191. package/dist/{chunk-K4A6UVPB.js → chunk-RJ7Z7YXK.js} +11 -11
  192. package/dist/{chunk-ZZCR2QYL.js → chunk-RSSLDMFX.js} +2 -2
  193. package/dist/{chunk-ZZCR2QYL.js.map → chunk-RSSLDMFX.js.map} +1 -1
  194. package/dist/{chunk-QE6YVNP5.js → chunk-RTXHUVOD.js} +53 -19
  195. package/dist/chunk-RTXHUVOD.js.map +1 -0
  196. package/dist/{chunk-HJUP3K6L.js → chunk-RXYO6NA6.js} +2 -2
  197. package/dist/{chunk-TBXAY2SS.js → chunk-SGHGCFVV.js} +5 -5
  198. package/dist/{chunk-THTF2W7M.js → chunk-TRTLWUDD.js} +19 -18
  199. package/dist/chunk-TRTLWUDD.js.map +1 -0
  200. package/dist/{chunk-2SKMZUOW.js → chunk-U26LB4WA.js} +7 -7
  201. package/dist/{chunk-6P4REYKL.js → chunk-UDAUULK2.js} +28 -2
  202. package/dist/{chunk-6P4REYKL.js.map → chunk-UDAUULK2.js.map} +1 -1
  203. package/dist/{chunk-KTOXQMW3.js → chunk-UHSOPTNB.js} +14 -4
  204. package/dist/chunk-UHSOPTNB.js.map +1 -0
  205. package/dist/{chunk-VHKXRYQN.js → chunk-VBK6SRNE.js} +2 -2
  206. package/dist/{chunk-KQAFEZQX.js → chunk-VDX2J7OX.js} +2 -2
  207. package/dist/{chunk-Z4GUX2M6.js → chunk-VSN2DMQK.js} +2 -2
  208. package/dist/{chunk-ZHXSOMYH.js → chunk-VVX5PZFS.js} +2 -2
  209. package/dist/{chunk-G2XZFGYN.js → chunk-WGZHSQDV.js} +4 -4
  210. package/dist/{chunk-H3TKENU4.js → chunk-WIKO4SCR.js} +5 -5
  211. package/dist/{chunk-MDIEES23.js → chunk-WN2OXGGH.js} +1 -1
  212. package/dist/chunk-WN2OXGGH.js.map +1 -0
  213. package/dist/{chunk-LKFVVN7R.js → chunk-WNPRRBOE.js} +2 -2
  214. package/dist/{chunk-SV4Z2S67.js → chunk-WUUGE7QC.js} +54 -21
  215. package/dist/chunk-WUUGE7QC.js.map +1 -0
  216. package/dist/{chunk-ZZUVBZL2.js → chunk-X2QPKLPL.js} +2 -2
  217. package/dist/{chunk-RDLPFM7I.js → chunk-XJLTQTAO.js} +2 -2
  218. package/dist/{chunk-ZRMMXWYI.js → chunk-YR5QT4SR.js} +32 -9
  219. package/dist/chunk-YR5QT4SR.js.map +1 -0
  220. package/dist/{chunk-CARRTDKC.js → chunk-Z22M4JCY.js} +4 -3
  221. package/dist/chunk-Z22M4JCY.js.map +1 -0
  222. package/dist/{chunk-XM46Y66S.js → chunk-ZFU6QNRN.js} +7 -7
  223. package/dist/{chunk-SUEOG2S4.js → chunk-ZGXHTV5Y.js} +2 -2
  224. package/dist/{chunk-ZX3AYNNV.js → chunk-ZOGKZ2XT.js} +3 -2
  225. package/dist/chunk-ZOGKZ2XT.js.map +1 -0
  226. package/dist/{chunk-46Z3VGWF.js → chunk-ZYRAY5FL.js} +3 -3
  227. package/dist/{chunk-3XPN7AVY.js → chunk-ZYSOT6HD.js} +2 -2
  228. package/dist/{cli-BWri5-am.d.ts → cli-Cx9s_VRn.d.ts} +5 -5
  229. package/dist/cli.d.ts +16 -15
  230. package/dist/cli.js +129 -127
  231. package/dist/coding/export-okf-codegraph.d.ts +1 -1
  232. package/dist/coding/export-okf-codegraph.js +22 -22
  233. package/dist/coding/pre-action-gate.d.ts +1 -1
  234. package/dist/compounding/engine.d.ts +2 -2
  235. package/dist/compounding/engine.js +24 -24
  236. package/dist/compounding/preference-consolidator.d.ts +1 -1
  237. package/dist/compression-optimizer.d.ts +1 -1
  238. package/dist/config.d.ts +1 -1
  239. package/dist/config.js +10 -10
  240. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  241. package/dist/connectors/codex-materialize-runner.js +24 -24
  242. package/dist/connectors/codex-materialize.d.ts +1 -1
  243. package/dist/connectors/codex-materialize.js +2 -2
  244. package/dist/connectors/index.d.ts +1 -1
  245. package/dist/connectors/index.js +25 -25
  246. package/dist/consolidation-provenance-check.d.ts +2 -2
  247. package/dist/consolidation-undo.d.ts +2 -2
  248. package/dist/contradiction/index.d.ts +4 -4
  249. package/dist/contradiction/index.js +7 -7
  250. package/dist/{contradiction-scan-BSGKZHYJ.js → contradiction-scan-GVD4JJ7B.js} +4 -4
  251. package/dist/converge-config.d.ts +1 -1
  252. package/dist/convergence-refresh.d.ts +2 -2
  253. package/dist/convergence-refresh.js +26 -26
  254. package/dist/conversation-index/backend.d.ts +1 -1
  255. package/dist/conversation-index/chunker.d.ts +1 -1
  256. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  257. package/dist/conversation-index/indexer.d.ts +1 -1
  258. package/dist/conversation-index/search.d.ts +1 -1
  259. package/dist/corpus-watermark.d.ts +1 -1
  260. package/dist/corpus-watermark.js +25 -25
  261. package/dist/cross-lingual-recall.d.ts +1 -1
  262. package/dist/dashboard-runtime.js +2 -2
  263. package/dist/day-summary.d.ts +1 -1
  264. package/dist/deep-recall-config.d.ts +12 -1
  265. package/dist/deep-recall-config.js +5 -3
  266. package/dist/deep-recall-http-glue.d.ts +17 -14
  267. package/dist/deep-recall-http-glue.js +7 -4
  268. package/dist/deep-recall-mcp-tools.d.ts +14 -13
  269. package/dist/deep-recall-policy-llm.d.ts +12 -2
  270. package/dist/deep-recall-policy-llm.js +3 -3
  271. package/dist/deep-recall-seeds.d.ts +4 -1
  272. package/dist/deep-recall-seeds.js +1 -1
  273. package/dist/deep-recall.d.ts +12 -1
  274. package/dist/deep-recall.js +3 -2
  275. package/dist/delinearize.d.ts +1 -1
  276. package/dist/dependency-propagation-config.d.ts +1 -1
  277. package/dist/{dependency-propagation-delivery-ueZlKTQB.d.ts → dependency-propagation-delivery-C2QFQ97b.d.ts} +1 -1
  278. package/dist/direct-answer-wiring.d.ts +1 -1
  279. package/dist/direct-answer.d.ts +1 -1
  280. package/dist/embedding-fallback.d.ts +1 -1
  281. package/dist/enrichment/index.d.ts +1 -1
  282. package/dist/entity-origin-fields.d.ts +1 -1
  283. package/dist/entity-retrieval.d.ts +2 -2
  284. package/dist/entity-retrieval.js +23 -23
  285. package/dist/entity-schema.d.ts +1 -1
  286. package/dist/episodic-context.d.ts +1 -1
  287. package/dist/eval-trajectory-contracts.d.ts +1 -1
  288. package/dist/eval-trajectory-store.d.ts +1 -1
  289. package/dist/eval-trajectory.d.ts +1 -1
  290. package/dist/explicit-capture.d.ts +11 -11
  291. package/dist/explicit-capture.js +6 -6
  292. package/dist/external-wiki-access.d.ts +14 -13
  293. package/dist/external-wiki-access.js +80 -79
  294. package/dist/external-wiki-collection-registration.d.ts +1 -1
  295. package/dist/external-wiki-collection.d.ts +1 -1
  296. package/dist/external-wiki-mcp-tools.d.ts +14 -13
  297. package/dist/extraction-error-classification.d.ts +1 -1
  298. package/dist/extraction-faithfulness.d.ts +2 -2
  299. package/dist/extraction-faithfulness.js +3 -3
  300. package/dist/extraction-judge-telemetry.d.ts +2 -2
  301. package/dist/extraction-judge-training.d.ts +2 -2
  302. package/dist/extraction-judge.d.ts +2 -2
  303. package/dist/extraction-judge.js +3 -3
  304. package/dist/extraction-liveness.d.ts +1 -1
  305. package/dist/extraction-normalization.d.ts +1 -1
  306. package/dist/extraction-prompt.d.ts +1 -1
  307. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  308. package/dist/extraction-source-grounding.d.ts +1 -1
  309. package/dist/extraction-span-config.d.ts +1 -1
  310. package/dist/extraction-span-materialize.d.ts +1 -1
  311. package/dist/extraction.d.ts +2 -2
  312. package/dist/extraction.js +38 -38
  313. package/dist/fallback-llm-codex-subscription.d.ts +15 -5
  314. package/dist/fallback-llm-codex-subscription.js +3 -1
  315. package/dist/fallback-llm.d.ts +1 -1
  316. package/dist/fallback-llm.js +2 -2
  317. package/dist/{first-start-migration-ZWMV5CX4.js → first-start-migration-L3UFX5CU.js} +4 -4
  318. package/dist/{generic-recall-paths-CpyVmA88.d.ts → generic-recall-paths-CeKQsQEn.d.ts} +1 -1
  319. package/dist/graph-append-error.d.ts +1 -1
  320. package/dist/graph-dashboard-diff.d.ts +1 -1
  321. package/dist/graph-dashboard-key.d.ts +1 -1
  322. package/dist/graph-dashboard-parser.d.ts +1 -1
  323. package/dist/graph-edge-reinforcement.d.ts +1 -1
  324. package/dist/graph-jsonl.d.ts +1 -1
  325. package/dist/graph-path-reconstruction.d.ts +1 -1
  326. package/dist/graph-path-scoring.d.ts +1 -1
  327. package/dist/graph-snapshot.d.ts +1 -1
  328. package/dist/graph.d.ts +1 -1
  329. package/dist/harmonic-retrieval.js +3 -3
  330. package/dist/importance.d.ts +1 -1
  331. package/dist/importers/index.d.ts +1 -1
  332. package/dist/importers/test-utils.d.ts +1 -1
  333. package/dist/in-flight-reads.d.ts +1 -1
  334. package/dist/{index-BvUA4S7M.d.ts → index-Bau-Wl0H.d.ts} +3 -3
  335. package/dist/index.d.ts +703 -702
  336. package/dist/index.js +331 -327
  337. package/dist/intent.d.ts +1 -1
  338. package/dist/lcm/engine.d.ts +1 -1
  339. package/dist/lcm/engine.js +3 -3
  340. package/dist/lcm/index.d.ts +1 -1
  341. package/dist/lcm/index.js +8 -8
  342. package/dist/lcm/tools.d.ts +1 -1
  343. package/dist/lifecycle.d.ts +1 -1
  344. package/dist/live-connectors-runner.d.ts +1 -1
  345. package/dist/{local-llm-BsJGulur.d.ts → local-llm-Bj-m01Ro.d.ts} +1 -1
  346. package/dist/local-llm-helpers.d.ts +2 -2
  347. package/dist/local-llm.d.ts +2 -2
  348. package/dist/local-llm.js +2 -2
  349. package/dist/local-model-endpoint.d.ts +1 -1
  350. package/dist/location/index.d.ts +6 -209
  351. package/dist/location/index.js +77 -71
  352. package/dist/maintenance/memory-governance.d.ts +1 -1
  353. package/dist/maintenance/memory-governance.js +23 -23
  354. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  355. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +23 -23
  356. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  357. package/dist/maintenance/rebuild-memory-projection.js +25 -25
  358. package/dist/{maintenance-CYubtIRr.d.ts → maintenance-Ye-y-c7f.d.ts} +7 -6
  359. package/dist/mcp-memory-inspector-app.d.ts +14 -13
  360. package/dist/memory-action-policy.d.ts +1 -1
  361. package/dist/memory-cache.d.ts +1 -1
  362. package/dist/memory-controller.d.ts +1 -1
  363. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  364. package/dist/memory-projection-store.d.ts +1 -1
  365. package/dist/memory-provenance.d.ts +1 -1
  366. package/dist/memory-snapshot.d.ts +1 -1
  367. package/dist/memory-subject-cli.d.ts +14 -13
  368. package/dist/memory-subject.d.ts +14 -13
  369. package/dist/memory-worth-outcomes.d.ts +2 -2
  370. package/dist/models-json.d.ts +1 -1
  371. package/dist/namespaces/migrate.d.ts +3 -3
  372. package/dist/namespaces/migrate.js +23 -23
  373. package/dist/namespaces/principal.d.ts +1 -1
  374. package/dist/namespaces/search.d.ts +1 -1
  375. package/dist/namespaces/search.js +3 -3
  376. package/dist/namespaces/storage.d.ts +3 -3
  377. package/dist/namespaces/storage.js +22 -22
  378. package/dist/native-knowledge.d.ts +1 -1
  379. package/dist/offline-sync-impression-drain.d.ts +1 -1
  380. package/dist/offline-sync-impression-drain.js +5 -5
  381. package/dist/operator-doctor-corpus.d.ts +1 -1
  382. package/dist/operator-doctor-corpus.js +26 -26
  383. package/dist/operator-doctor-replica.d.ts +1 -1
  384. package/dist/operator-toolkit.d.ts +3 -3
  385. package/dist/operator-toolkit.js +44 -44
  386. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  387. package/dist/orchestration/maintenance.d.ts +4 -4
  388. package/dist/orchestration/maintenance.js +39 -39
  389. package/dist/{orchestrator-BWDRJ_0d.d.ts → orchestrator-fFDDYUUV.d.ts} +20 -10
  390. package/dist/orchestrator.d.ts +11 -11
  391. package/dist/orchestrator.js +170 -168
  392. package/dist/patterns-cli.d.ts +1 -1
  393. package/dist/{pipeline-7JMn2yMH.d.ts → pipeline-D_j5n_Ih.d.ts} +1 -1
  394. package/dist/policy-runtime.d.ts +1 -1
  395. package/dist/proactive-contention.d.ts +2 -2
  396. package/dist/provenance.d.ts +1 -1
  397. package/dist/{public-http-CJWs3mo9.d.ts → public-http-CjiSqxUx.d.ts} +1 -1
  398. package/dist/{qmd-CxCH9G9m.d.ts → qmd-CnxVjKrv.d.ts} +1 -1
  399. package/dist/qmd-preflight.d.ts +2 -2
  400. package/dist/qmd-recall-cache.d.ts +1 -1
  401. package/dist/qmd.d.ts +2 -2
  402. package/dist/recall-concurrency-config.d.ts +1 -1
  403. package/dist/recall-disclosure-escalation.d.ts +1 -1
  404. package/dist/recall-explain-renderer.d.ts +1 -1
  405. package/dist/recall-explain-renderer.js +3 -3
  406. package/dist/recall-memory-map.d.ts +1 -1
  407. package/dist/recall-navigate-access.d.ts +1 -1
  408. package/dist/recall-navigate-access.js +2 -2
  409. package/dist/recall-navigate-disclosure.d.ts +1 -1
  410. package/dist/recall-navigate-disclosure.js +1 -1
  411. package/dist/recall-navigate.d.ts +1 -1
  412. package/dist/recall-navigate.js +2 -2
  413. package/dist/recall-planner-llm.d.ts +1 -1
  414. package/dist/recall-planner-llm.js +2 -2
  415. package/dist/recall-state-view-admission.d.ts +2 -2
  416. package/dist/recall-state-view-admission.js +8 -8
  417. package/dist/recall-state-view-anchors.d.ts +1 -1
  418. package/dist/recall-state-view-anchors.js +2 -2
  419. package/dist/recall-state-view-inject.js +2 -2
  420. package/dist/recall-state-view-render.js +2 -2
  421. package/dist/recall-state-view-widen.js +2 -2
  422. package/dist/recall-state-view-wire.js +3 -3
  423. package/dist/recall-state-view.d.ts +9 -1
  424. package/dist/recall-state-view.js +5 -3
  425. package/dist/recall-state.d.ts +1 -1
  426. package/dist/recall-tag-filter.d.ts +1 -1
  427. package/dist/recall-timings.d.ts +1 -1
  428. package/dist/recall-xray-cli.d.ts +1 -1
  429. package/dist/recall-xray-cli.js +4 -4
  430. package/dist/recall-xray-renderer.d.ts +1 -1
  431. package/dist/recall-xray-renderer.js +3 -3
  432. package/dist/recall-xray.d.ts +1 -1
  433. package/dist/recall-xray.js +2 -2
  434. package/dist/reconcile/cursor.d.ts +1 -1
  435. package/dist/reconcile/cursor.js +2 -2
  436. package/dist/reconcile/manifest.d.ts +1 -1
  437. package/dist/reconcile/manifest.js +4 -4
  438. package/dist/reconcile/plan.d.ts +1 -1
  439. package/dist/reconcile/plan.js +2 -2
  440. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  441. package/dist/replay/normalizers/claude.d.ts +1 -1
  442. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  443. package/dist/replay/normalizers/shared.d.ts +1 -1
  444. package/dist/replay/runner.d.ts +1 -1
  445. package/dist/replay/types.d.ts +1 -1
  446. package/dist/replica-divergence.d.ts +1 -1
  447. package/dist/replica-peers-config.d.ts +1 -1
  448. package/dist/{resolution-4GG3QZRJ.js → resolution-LXFQQ4AE.js} +8 -8
  449. package/dist/resolution-LXFQQ4AE.js.map +1 -0
  450. package/dist/resolve-auth-token.d.ts +1 -1
  451. package/dist/resume-bundles.js +12 -12
  452. package/dist/retrieval-agents.d.ts +2 -2
  453. package/dist/retrieval-tiers.d.ts +1 -1
  454. package/dist/routing/engine.d.ts +1 -1
  455. package/dist/routing/store.d.ts +1 -1
  456. package/dist/salvage-envelope.d.ts +1 -1
  457. package/dist/schemas.d.ts +160 -160
  458. package/dist/{scope-profiles-BGAUqhBR.d.ts → scope-profiles-BajH5zAT.d.ts} +1 -1
  459. package/dist/search/embed-helper.d.ts +1 -1
  460. package/dist/search/factory.d.ts +1 -1
  461. package/dist/search/factory.js +2 -2
  462. package/dist/search/index.d.ts +1 -1
  463. package/dist/search/index.js +4 -4
  464. package/dist/search/lancedb-backend.d.ts +1 -1
  465. package/dist/search/meilisearch-backend.d.ts +1 -1
  466. package/dist/search/noop-backend.d.ts +1 -1
  467. package/dist/search/orama-backend.d.ts +1 -1
  468. package/dist/search/port.d.ts +1 -1
  469. package/dist/search/remote-backend.d.ts +1 -1
  470. package/dist/{semantic-consolidation-CCeRD9pV.d.ts → semantic-consolidation-Bu6d3O7R.d.ts} +1 -1
  471. package/dist/semantic-consolidation.d.ts +2 -2
  472. package/dist/semantic-consolidation.js +25 -25
  473. package/dist/semantic-rule-promotion.js +22 -22
  474. package/dist/semantic-rule-verifier.d.ts +1 -1
  475. package/dist/semantic-rule-verifier.js +22 -22
  476. package/dist/{service-BwpzRduk.d.ts → service-ChFwWtLS.d.ts} +13 -2
  477. package/dist/session-observer-bands.d.ts +1 -1
  478. package/dist/session-observer-state.d.ts +1 -1
  479. package/dist/shared-context/manager.d.ts +7 -7
  480. package/dist/shared-context/manager.js +2 -2
  481. package/dist/shared-context/write-output-controls.d.ts +34 -0
  482. package/dist/shared-context/write-output-controls.js +10 -0
  483. package/dist/shared-context/write-output-controls.js.map +1 -0
  484. package/dist/signal.d.ts +1 -1
  485. package/dist/source-agent-qualifier.d.ts +1 -1
  486. package/dist/source-agent-qualifier.js +33 -33
  487. package/dist/source-attribution.d.ts +23 -1
  488. package/dist/source-attribution.js +13 -3
  489. package/dist/standup/build.js +23 -23
  490. package/dist/{storage-BprAGBG0.d.ts → storage-BDKQdsmB.d.ts} +1 -1
  491. package/dist/storage.d.ts +2 -2
  492. package/dist/storage.js +21 -21
  493. package/dist/subject-config.d.ts +1 -1
  494. package/dist/subject-config.js +2 -2
  495. package/dist/summarizer.d.ts +1 -1
  496. package/dist/summarizer.js +6 -6
  497. package/dist/summary-snapshot.d.ts +1 -1
  498. package/dist/support-passport/index.d.ts +17 -16
  499. package/dist/support-passport/index.js +82 -81
  500. package/dist/tagging-CwK6um2q.d.ts +240 -0
  501. package/dist/temporal-supersession.d.ts +2 -2
  502. package/dist/temporal-timeline-recall.d.ts +1 -1
  503. package/dist/temporal-validity.d.ts +1 -1
  504. package/dist/threading.d.ts +1 -1
  505. package/dist/tier-migration.d.ts +2 -2
  506. package/dist/tier-routing.d.ts +1 -1
  507. package/dist/tier-routing.js +3 -3
  508. package/dist/{tier-stats-LUSUUNU6.js → tier-stats-VK5PCO2L.js} +4 -4
  509. package/dist/topics.d.ts +1 -1
  510. package/dist/transcript.d.ts +1 -1
  511. package/dist/transfer/backup.js +2 -2
  512. package/dist/transfer/capsule-export.js +2 -2
  513. package/dist/transfer/capsule-import.js +3 -3
  514. package/dist/transfer/export-okf.d.ts +1 -1
  515. package/dist/transfer/export-okf.js +22 -22
  516. package/dist/transfer/types.d.ts +78 -78
  517. package/dist/trust-score-stage.d.ts +1 -1
  518. package/dist/trust-score.d.ts +1 -1
  519. package/dist/{types-nJV23pa3.d.ts → types-B65IoepH.d.ts} +6 -1
  520. package/dist/types.d.ts +1 -1
  521. package/dist/types.js +1 -1
  522. package/dist/utility-runtime.d.ts +1 -1
  523. package/dist/verified-recall.js +22 -22
  524. package/dist/who-knows-cli.d.ts +14 -13
  525. package/dist/who-knows-cli.js +23 -23
  526. package/dist/who-knows.d.ts +14 -13
  527. package/dist/who-knows.js +22 -22
  528. package/dist/write-envelope.d.ts +1 -1
  529. package/package.json +12 -2
  530. package/src/access-http.test.ts +1 -0
  531. package/src/access-http.ts +1 -1
  532. package/src/access-mcp-shared-context-tools.ts +103 -0
  533. package/src/access-mcp.ts +7 -80
  534. package/src/access-observe-write-category.ts +1 -0
  535. package/src/access-observe-write-surface.ts +3 -3
  536. package/src/access-operations-batch.ts +47 -4
  537. package/src/access-schema.ts +1 -0
  538. package/src/access-service.ts +18 -12
  539. package/src/activity/timeline/regenerate.test.ts +48 -0
  540. package/src/activity/timeline/regenerate.ts +7 -5
  541. package/src/cli/deep-recall-commands.ts +22 -10
  542. package/src/config.ts +5 -0
  543. package/src/dedup/merge.test.ts +283 -0
  544. package/src/deep-recall-boundary.test.ts +66 -0
  545. package/src/deep-recall-cli.test.ts +82 -0
  546. package/src/deep-recall-config.test.ts +56 -0
  547. package/src/deep-recall-config.ts +32 -0
  548. package/src/deep-recall-http-glue.ts +10 -10
  549. package/src/deep-recall-policy-llm.test.ts +242 -0
  550. package/src/deep-recall-policy-llm.ts +37 -7
  551. package/src/deep-recall-seeds.test.ts +53 -0
  552. package/src/deep-recall-seeds.ts +7 -1
  553. package/src/deep-recall-surface.test.ts +93 -0
  554. package/src/deep-recall.test.ts +121 -0
  555. package/src/deep-recall.ts +88 -28
  556. package/src/fallback-llm-codex-subscription.ts +27 -5
  557. package/src/fallback-llm.test.ts +120 -0
  558. package/src/fallback-llm.ts +17 -16
  559. package/src/location/phase5-wiring.test.ts +408 -0
  560. package/src/location/tagging.ts +58 -0
  561. package/src/meetings/config.test.ts +58 -0
  562. package/src/orchestration/extraction-persist.ts +1 -1
  563. package/src/orchestration/orchestrator-helpers.ts +2 -0
  564. package/src/orchestration/recall-entry.ts +15 -1
  565. package/src/orchestration/recall-internal.ts +1 -0
  566. package/src/orchestration/recall-section-coordinator.ts +65 -28
  567. package/src/orchestration/recall-state-view-pipeline.test.ts +8 -2
  568. package/src/orchestration/semantic-merge-commit-effects.ts +45 -16
  569. package/src/orchestration/semantic-merge-persist.ts +23 -36
  570. package/src/orchestration/workspace-ops.ts +14 -0
  571. package/src/providers/codex-subscription.test.ts +127 -0
  572. package/src/providers/codex-subscription.ts +1 -1
  573. package/src/recall-state-view-budget.test.ts +424 -0
  574. package/src/recall-state-view.ts +30 -16
  575. package/src/shared-context/envelope-io.ts +25 -0
  576. package/src/shared-context/envelope-wiring.test.ts +4 -2
  577. package/src/shared-context/manager.ts +1 -0
  578. package/src/shared-context/write-output-controls.test.ts +192 -0
  579. package/src/shared-context/write-output-controls.ts +72 -0
  580. package/src/source-attribution.test.ts +39 -0
  581. package/src/source-attribution.ts +72 -0
  582. package/src/types.ts +5 -0
  583. package/src/wearables/pipeline.ts +19 -0
  584. package/src/wearables/service.ts +8 -0
  585. package/dist/chunk-5LYSEZOF.js.map +0 -1
  586. package/dist/chunk-CARRTDKC.js.map +0 -1
  587. package/dist/chunk-CC37E3QM.js.map +0 -1
  588. package/dist/chunk-IS2IDFJP.js.map +0 -1
  589. package/dist/chunk-K75A5XWU.js.map +0 -1
  590. package/dist/chunk-KTOXQMW3.js.map +0 -1
  591. package/dist/chunk-MDIEES23.js.map +0 -1
  592. package/dist/chunk-OEDW4ER7.js.map +0 -1
  593. package/dist/chunk-QE6YVNP5.js.map +0 -1
  594. package/dist/chunk-ROEFLU37.js.map +0 -1
  595. package/dist/chunk-SFHLQPBF.js.map +0 -1
  596. package/dist/chunk-SV4Z2S67.js.map +0 -1
  597. package/dist/chunk-THTF2W7M.js.map +0 -1
  598. package/dist/chunk-UZ6JYPJ6.js.map +0 -1
  599. package/dist/chunk-YTK5MVNF.js.map +0 -1
  600. package/dist/chunk-ZRMMXWYI.js.map +0 -1
  601. package/dist/chunk-ZX3AYNNV.js.map +0 -1
  602. /package/dist/{capsule-crypto-7FJQINUR.js.map → access-mcp-shared-context-tools.js.map} +0 -0
  603. /package/dist/{contradiction-scan-BSGKZHYJ.js.map → capsule-crypto-YO5QJ6L3.js.map} +0 -0
  604. /package/dist/{capsule-merge-IPG4IOFP.js.map → capsule-merge-3MNURAQ3.js.map} +0 -0
  605. /package/dist/{chunk-JAJIMTFB.js.map → chunk-2PDMIPMP.js.map} +0 -0
  606. /package/dist/{chunk-6L2II3KS.js.map → chunk-3D75XIYO.js.map} +0 -0
  607. /package/dist/{chunk-XCPNH2MG.js.map → chunk-3KJTSCSX.js.map} +0 -0
  608. /package/dist/{chunk-YTZN2UZO.js.map → chunk-3RLWUW7G.js.map} +0 -0
  609. /package/dist/{chunk-J272ODKJ.js.map → chunk-42DJ235G.js.map} +0 -0
  610. /package/dist/{chunk-NVVZPBKI.js.map → chunk-46FVFU7S.js.map} +0 -0
  611. /package/dist/{chunk-JUDT33RX.js.map → chunk-4AX5OYKC.js.map} +0 -0
  612. /package/dist/{chunk-GSSDHAYH.js.map → chunk-4IGOLIWM.js.map} +0 -0
  613. /package/dist/{chunk-23HFXQ5J.js.map → chunk-6EGIQEKC.js.map} +0 -0
  614. /package/dist/{chunk-TVVEYCNW.js.map → chunk-7K5Q6COX.js.map} +0 -0
  615. /package/dist/{chunk-GO5LOHCD.js.map → chunk-7L54ARML.js.map} +0 -0
  616. /package/dist/{chunk-TEMKBSV6.js.map → chunk-7PSRCGWT.js.map} +0 -0
  617. /package/dist/{chunk-ICNJ6J46.js.map → chunk-AAAFZW3U.js.map} +0 -0
  618. /package/dist/{chunk-K4JKAXMO.js.map → chunk-AAX22E4K.js.map} +0 -0
  619. /package/dist/{chunk-KY236SP5.js.map → chunk-AHHFBJX7.js.map} +0 -0
  620. /package/dist/{chunk-TZ44E732.js.map → chunk-AIVRD66I.js.map} +0 -0
  621. /package/dist/{chunk-YRIFXXMI.js.map → chunk-AOGICQMH.js.map} +0 -0
  622. /package/dist/{chunk-KOTG3RXE.js.map → chunk-AUSRUOMQ.js.map} +0 -0
  623. /package/dist/{chunk-C5R73BON.js.map → chunk-BIANISES.js.map} +0 -0
  624. /package/dist/{chunk-IMBQFHRV.js.map → chunk-BPXJINHW.js.map} +0 -0
  625. /package/dist/{chunk-2NLLXCJG.js.map → chunk-BXLOS5AJ.js.map} +0 -0
  626. /package/dist/{chunk-2J3V5QEO.js.map → chunk-C3QXITIP.js.map} +0 -0
  627. /package/dist/{chunk-2SNCQHJZ.js.map → chunk-CQ4BTPX6.js.map} +0 -0
  628. /package/dist/{chunk-3QEVOQF5.js.map → chunk-CTETTVDN.js.map} +0 -0
  629. /package/dist/{chunk-DFVSJFHK.js.map → chunk-DBB5JPSL.js.map} +0 -0
  630. /package/dist/{chunk-W23JARAQ.js.map → chunk-DLPMOSNH.js.map} +0 -0
  631. /package/dist/{chunk-BGRTZOJB.js.map → chunk-DMTSKY4W.js.map} +0 -0
  632. /package/dist/{chunk-X7Y7WX73.js.map → chunk-DQEMWVMT.js.map} +0 -0
  633. /package/dist/{chunk-QS5Q5RBV.js.map → chunk-E4FRR4MA.js.map} +0 -0
  634. /package/dist/{chunk-RJQAP333.js.map → chunk-ETE3SGAH.js.map} +0 -0
  635. /package/dist/{chunk-YNDLCWXS.js.map → chunk-EZ25VE3G.js.map} +0 -0
  636. /package/dist/{chunk-RLU2Y5GV.js.map → chunk-F2FJTOV6.js.map} +0 -0
  637. /package/dist/{chunk-V2ZA4YWE.js.map → chunk-F5H6YG5P.js.map} +0 -0
  638. /package/dist/{chunk-4CMXI55L.js.map → chunk-FSUFKIFS.js.map} +0 -0
  639. /package/dist/{chunk-ZAEPD4C2.js.map → chunk-G3NTZZWT.js.map} +0 -0
  640. /package/dist/{chunk-ZMWSYUUL.js.map → chunk-GCBIXUPT.js.map} +0 -0
  641. /package/dist/{chunk-WZYHPAG5.js.map → chunk-GIM2AGFL.js.map} +0 -0
  642. /package/dist/{chunk-J7FVMLBR.js.map → chunk-GWEZNCGA.js.map} +0 -0
  643. /package/dist/{chunk-LFVZD5EC.js.map → chunk-GWNSKQDA.js.map} +0 -0
  644. /package/dist/{chunk-MJC7UKH7.js.map → chunk-H2N6SLTR.js.map} +0 -0
  645. /package/dist/{chunk-J4WGTN2N.js.map → chunk-HK44SV6K.js.map} +0 -0
  646. /package/dist/{chunk-JDX2OA4R.js.map → chunk-HNHIHXSD.js.map} +0 -0
  647. /package/dist/{chunk-VQYWKCDR.js.map → chunk-HPMCKAET.js.map} +0 -0
  648. /package/dist/{chunk-MVG3KXON.js.map → chunk-I65KB36L.js.map} +0 -0
  649. /package/dist/{chunk-AEOOGXMQ.js.map → chunk-J2MGTGKC.js.map} +0 -0
  650. /package/dist/{chunk-PKUJNICO.js.map → chunk-JC2OBYYD.js.map} +0 -0
  651. /package/dist/{chunk-5U7K4W6K.js.map → chunk-JDOBQPJY.js.map} +0 -0
  652. /package/dist/{chunk-VQWBUPSJ.js.map → chunk-JMAP6L6Q.js.map} +0 -0
  653. /package/dist/{chunk-7Z54NXVS.js.map → chunk-K27INAPR.js.map} +0 -0
  654. /package/dist/{chunk-7D6SER6A.js.map → chunk-KJQ4Y2PY.js.map} +0 -0
  655. /package/dist/{chunk-QPVNK2VE.js.map → chunk-LCVYO3ON.js.map} +0 -0
  656. /package/dist/{chunk-HIP6DKJJ.js.map → chunk-LQVXSRAJ.js.map} +0 -0
  657. /package/dist/{chunk-A7GQBJP5.js.map → chunk-LVFI5LG7.js.map} +0 -0
  658. /package/dist/{chunk-TO36VPZI.js.map → chunk-LWF6GOII.js.map} +0 -0
  659. /package/dist/{chunk-ES5BUPYB.js.map → chunk-OCWFKD5Q.js.map} +0 -0
  660. /package/dist/{chunk-IOPIGX7Y.js.map → chunk-OP722LOG.js.map} +0 -0
  661. /package/dist/{chunk-62D2PAAM.js.map → chunk-PAAJWQH5.js.map} +0 -0
  662. /package/dist/{chunk-V6EGNVUT.js.map → chunk-PIWFNPQT.js.map} +0 -0
  663. /package/dist/{chunk-JOP7W24J.js.map → chunk-PLJ2MQFT.js.map} +0 -0
  664. /package/dist/{chunk-37CAEC7E.js.map → chunk-PWPIERBM.js.map} +0 -0
  665. /package/dist/{chunk-BXIJSPCL.js.map → chunk-Q62GA5U2.js.map} +0 -0
  666. /package/dist/{chunk-I3H5LFOI.js.map → chunk-QNJQCLI6.js.map} +0 -0
  667. /package/dist/{chunk-BYQX4IOG.js.map → chunk-R45VFSEV.js.map} +0 -0
  668. /package/dist/{chunk-XVDZFTN5.js.map → chunk-RFIJH2OE.js.map} +0 -0
  669. /package/dist/{chunk-K4A6UVPB.js.map → chunk-RJ7Z7YXK.js.map} +0 -0
  670. /package/dist/{chunk-HJUP3K6L.js.map → chunk-RXYO6NA6.js.map} +0 -0
  671. /package/dist/{chunk-TBXAY2SS.js.map → chunk-SGHGCFVV.js.map} +0 -0
  672. /package/dist/{chunk-2SKMZUOW.js.map → chunk-U26LB4WA.js.map} +0 -0
  673. /package/dist/{chunk-VHKXRYQN.js.map → chunk-VBK6SRNE.js.map} +0 -0
  674. /package/dist/{chunk-KQAFEZQX.js.map → chunk-VDX2J7OX.js.map} +0 -0
  675. /package/dist/{chunk-Z4GUX2M6.js.map → chunk-VSN2DMQK.js.map} +0 -0
  676. /package/dist/{chunk-ZHXSOMYH.js.map → chunk-VVX5PZFS.js.map} +0 -0
  677. /package/dist/{chunk-G2XZFGYN.js.map → chunk-WGZHSQDV.js.map} +0 -0
  678. /package/dist/{chunk-H3TKENU4.js.map → chunk-WIKO4SCR.js.map} +0 -0
  679. /package/dist/{chunk-LKFVVN7R.js.map → chunk-WNPRRBOE.js.map} +0 -0
  680. /package/dist/{chunk-ZZUVBZL2.js.map → chunk-X2QPKLPL.js.map} +0 -0
  681. /package/dist/{chunk-RDLPFM7I.js.map → chunk-XJLTQTAO.js.map} +0 -0
  682. /package/dist/{chunk-XM46Y66S.js.map → chunk-ZFU6QNRN.js.map} +0 -0
  683. /package/dist/{chunk-SUEOG2S4.js.map → chunk-ZGXHTV5Y.js.map} +0 -0
  684. /package/dist/{chunk-46Z3VGWF.js.map → chunk-ZYRAY5FL.js.map} +0 -0
  685. /package/dist/{chunk-3XPN7AVY.js.map → chunk-ZYSOT6HD.js.map} +0 -0
  686. /package/dist/{resolution-4GG3QZRJ.js.map → contradiction-scan-GVD4JJ7B.js.map} +0 -0
  687. /package/dist/{first-start-migration-ZWMV5CX4.js.map → first-start-migration-L3UFX5CU.js.map} +0 -0
  688. /package/dist/{tier-stats-LUSUUNU6.js.map → tier-stats-VK5PCO2L.js.map} +0 -0
@@ -11,14 +11,14 @@ import {
11
11
  } from "./chunk-WLZYGLJ4.js";
12
12
  import {
13
13
  LocalLlmClient
14
- } from "./chunk-G2XZFGYN.js";
14
+ } from "./chunk-WGZHSQDV.js";
15
15
  import {
16
16
  FallbackLlmClient,
17
17
  gatewayTaskChainOptions
18
- } from "./chunk-THTF2W7M.js";
18
+ } from "./chunk-TRTLWUDD.js";
19
19
  import {
20
20
  fallbackLlmRuntimeContextFromConfig
21
- } from "./chunk-KTOXQMW3.js";
21
+ } from "./chunk-UHSOPTNB.js";
22
22
  import {
23
23
  completeBackgroundGeneration,
24
24
  parseBackgroundGenerationJson
@@ -781,4 +781,4 @@ export {
781
781
  summarizeHourlyStatus,
782
782
  HourlySummarizer
783
783
  };
784
- //# sourceMappingURL=chunk-AEOOGXMQ.js.map
784
+ //# sourceMappingURL=chunk-J2MGTGKC.js.map
@@ -0,0 +1,94 @@
1
+ // src/access-mcp-shared-context-tools.ts
2
+ var sharedContextMcpTools = [
3
+ {
4
+ name: "engram.shared_context_write_output",
5
+ description: "Write agent work product into shared-context directory for cross-agent coordination.",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ agentId: { type: "string", description: "Agent ID producing this output." },
10
+ title: { type: "string", description: "Short title for the output." },
11
+ content: { type: "string", description: "Markdown content to write." },
12
+ authority: {
13
+ type: "string",
14
+ enum: ["informational", "advisory", "binding"],
15
+ description: "Envelope authority class. `binding` additionally requires the operator config `sharedContextAllowBindingAuthority: true`."
16
+ },
17
+ expiresAt: {
18
+ type: "string",
19
+ description: "ISO-8601 instant strictly after the write time and at most 10 years out. Past, invalid, or over-bound values are rejected."
20
+ },
21
+ supersedes: {
22
+ type: "string",
23
+ description: "Id of the shared item this output supersedes (non-empty, single line)."
24
+ }
25
+ },
26
+ required: ["agentId", "title", "content"],
27
+ additionalProperties: false
28
+ }
29
+ },
30
+ {
31
+ name: "engram.shared_feedback_record",
32
+ description: "Append approval/rejection decision into shared-context feedback inbox for compounding learning.",
33
+ inputSchema: {
34
+ type: "object",
35
+ properties: {
36
+ agent: { type: "string", description: "Agent name that produced the output." },
37
+ decision: { type: "string", enum: ["approved", "approved_with_feedback", "rejected"] },
38
+ reason: { type: "string" },
39
+ date: { type: "string", description: "ISO timestamp. Defaults to now." },
40
+ learning: { type: "string" },
41
+ outcome: { type: "string" },
42
+ severity: { type: "string", enum: ["low", "medium", "high"] },
43
+ confidence: { type: "number", description: "Confidence 0-1." },
44
+ workflow: { type: "string" },
45
+ tags: { type: "array", items: { type: "string" } },
46
+ evidenceWindowStart: { type: "string" },
47
+ evidenceWindowEnd: { type: "string" },
48
+ refs: { type: "array", items: { type: "string" } }
49
+ },
50
+ required: ["agent", "decision", "reason"],
51
+ additionalProperties: false
52
+ }
53
+ },
54
+ {
55
+ name: "engram.shared_priorities_append",
56
+ description: "Append priorities text into shared-context inbox for curator merge.",
57
+ inputSchema: {
58
+ type: "object",
59
+ properties: {
60
+ agentId: { type: "string" },
61
+ text: { type: "string", description: "Priority notes (markdown)." }
62
+ },
63
+ required: ["agentId", "text"],
64
+ additionalProperties: false
65
+ }
66
+ },
67
+ {
68
+ name: "engram.shared_context_cross_signals_run",
69
+ description: "Generate cross-signal markdown + JSON artifacts from agent outputs and feedback.",
70
+ inputSchema: {
71
+ type: "object",
72
+ properties: {
73
+ date: { type: "string", description: "YYYY-MM-DD. Defaults to today." }
74
+ },
75
+ additionalProperties: false
76
+ }
77
+ },
78
+ {
79
+ name: "engram.shared_context_curate_daily",
80
+ description: "Generate daily roundtable summary (deterministic baseline aggregation).",
81
+ inputSchema: {
82
+ type: "object",
83
+ properties: {
84
+ date: { type: "string", description: "YYYY-MM-DD. Defaults to today." }
85
+ },
86
+ additionalProperties: false
87
+ }
88
+ }
89
+ ];
90
+
91
+ export {
92
+ sharedContextMcpTools
93
+ };
94
+ //# sourceMappingURL=chunk-JATHBCAV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/access-mcp-shared-context-tools.ts"],"sourcesContent":["/**\n * Shared-context MCP tool descriptors (issue #2920).\n *\n * Extracted from access-mcp.ts (at its fileSizeGrandfather ceiling) so the\n * write-output tool could gain the governed envelope controls without\n * growing the god file. Content is identical to the previously inline\n * entries except for the new `authority`/`expiresAt`/`supersedes` properties\n * on `engram.shared_context_write_output`, which mirror the canonical\n * validation in shared-context/write-output-controls.ts and\n * composeWriteEnvelope.\n */\nimport type { McpTool } from \"./access-mcp.js\";\n\nexport const sharedContextMcpTools: McpTool[] = [\n {\n name: \"engram.shared_context_write_output\",\n description: \"Write agent work product into shared-context directory for cross-agent coordination.\",\n inputSchema: {\n type: \"object\",\n properties: {\n agentId: { type: \"string\", description: \"Agent ID producing this output.\" },\n title: { type: \"string\", description: \"Short title for the output.\" },\n content: { type: \"string\", description: \"Markdown content to write.\" },\n authority: {\n type: \"string\",\n enum: [\"informational\", \"advisory\", \"binding\"],\n description:\n \"Envelope authority class. `binding` additionally requires the operator config `sharedContextAllowBindingAuthority: true`.\",\n },\n expiresAt: {\n type: \"string\",\n description:\n \"ISO-8601 instant strictly after the write time and at most 10 years out. Past, invalid, or over-bound values are rejected.\",\n },\n supersedes: {\n type: \"string\",\n description: \"Id of the shared item this output supersedes (non-empty, single line).\",\n },\n },\n required: [\"agentId\", \"title\", \"content\"],\n additionalProperties: false,\n },\n },\n {\n name: \"engram.shared_feedback_record\",\n description: \"Append approval/rejection decision into shared-context feedback inbox for compounding learning.\",\n inputSchema: {\n type: \"object\",\n properties: {\n agent: { type: \"string\", description: \"Agent name that produced the output.\" },\n decision: { type: \"string\", enum: [\"approved\", \"approved_with_feedback\", \"rejected\"] },\n reason: { type: \"string\" },\n date: { type: \"string\", description: \"ISO timestamp. Defaults to now.\" },\n learning: { type: \"string\" },\n outcome: { type: \"string\" },\n severity: { type: \"string\", enum: [\"low\", \"medium\", \"high\"] },\n confidence: { type: \"number\", description: \"Confidence 0-1.\" },\n workflow: { type: \"string\" },\n tags: { type: \"array\", items: { type: \"string\" } },\n evidenceWindowStart: { type: \"string\" },\n evidenceWindowEnd: { type: \"string\" },\n refs: { type: \"array\", items: { type: \"string\" } },\n },\n required: [\"agent\", \"decision\", \"reason\"],\n additionalProperties: false,\n },\n },\n {\n name: \"engram.shared_priorities_append\",\n description: \"Append priorities text into shared-context inbox for curator merge.\",\n inputSchema: {\n type: \"object\",\n properties: {\n agentId: { type: \"string\" },\n text: { type: \"string\", description: \"Priority notes (markdown).\" },\n },\n required: [\"agentId\", \"text\"],\n additionalProperties: false,\n },\n },\n {\n name: \"engram.shared_context_cross_signals_run\",\n description: \"Generate cross-signal markdown + JSON artifacts from agent outputs and feedback.\",\n inputSchema: {\n type: \"object\",\n properties: {\n date: { type: \"string\", description: \"YYYY-MM-DD. Defaults to today.\" },\n },\n additionalProperties: false,\n },\n },\n {\n name: \"engram.shared_context_curate_daily\",\n description: \"Generate daily roundtable summary (deterministic baseline aggregation).\",\n inputSchema: {\n type: \"object\",\n properties: {\n date: { type: \"string\", description: \"YYYY-MM-DD. Defaults to today.\" },\n },\n additionalProperties: false,\n },\n },\n];\n"],"mappings":";AAaO,IAAM,wBAAmC;AAAA,EAC9C;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,UAAU,aAAa,kCAAkC;AAAA,QAC1E,OAAO,EAAE,MAAM,UAAU,aAAa,8BAA8B;AAAA,QACpE,SAAS,EAAE,MAAM,UAAU,aAAa,6BAA6B;AAAA,QACrE,WAAW;AAAA,UACT,MAAM;AAAA,UACN,MAAM,CAAC,iBAAiB,YAAY,SAAS;AAAA,UAC7C,aACE;AAAA,QACJ;AAAA,QACA,WAAW;AAAA,UACT,MAAM;AAAA,UACN,aACE;AAAA,QACJ;AAAA,QACA,YAAY;AAAA,UACV,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,MACF;AAAA,MACA,UAAU,CAAC,WAAW,SAAS,SAAS;AAAA,MACxC,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,OAAO,EAAE,MAAM,UAAU,aAAa,uCAAuC;AAAA,QAC7E,UAAU,EAAE,MAAM,UAAU,MAAM,CAAC,YAAY,0BAA0B,UAAU,EAAE;AAAA,QACrF,QAAQ,EAAE,MAAM,SAAS;AAAA,QACzB,MAAM,EAAE,MAAM,UAAU,aAAa,kCAAkC;AAAA,QACvE,UAAU,EAAE,MAAM,SAAS;AAAA,QAC3B,SAAS,EAAE,MAAM,SAAS;AAAA,QAC1B,UAAU,EAAE,MAAM,UAAU,MAAM,CAAC,OAAO,UAAU,MAAM,EAAE;AAAA,QAC5D,YAAY,EAAE,MAAM,UAAU,aAAa,kBAAkB;AAAA,QAC7D,UAAU,EAAE,MAAM,SAAS;AAAA,QAC3B,MAAM,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,EAAE;AAAA,QACjD,qBAAqB,EAAE,MAAM,SAAS;AAAA,QACtC,mBAAmB,EAAE,MAAM,SAAS;AAAA,QACpC,MAAM,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,EAAE;AAAA,MACnD;AAAA,MACA,UAAU,CAAC,SAAS,YAAY,QAAQ;AAAA,MACxC,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,SAAS;AAAA,QAC1B,MAAM,EAAE,MAAM,UAAU,aAAa,6BAA6B;AAAA,MACpE;AAAA,MACA,UAAU,CAAC,WAAW,MAAM;AAAA,MAC5B,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,MAAM,EAAE,MAAM,UAAU,aAAa,iCAAiC;AAAA,MACxE;AAAA,MACA,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,MAAM,EAAE,MAAM,UAAU,aAAa,iCAAiC;AAAA,MACxE;AAAA,MACA,sBAAsB;AAAA,IACxB;AAAA,EACF;AACF;","names":[]}
@@ -14,7 +14,7 @@ import {
14
14
  } from "./chunk-3UXOZBHV.js";
15
15
  import {
16
16
  StorageManager
17
- } from "./chunk-MVG3KXON.js";
17
+ } from "./chunk-I65KB36L.js";
18
18
  import {
19
19
  OKF_PROFILE_TYPE,
20
20
  okfTypeForMemory
@@ -272,4 +272,4 @@ export {
272
272
  exportOkfBundle,
273
273
  firstHeading
274
274
  };
275
- //# sourceMappingURL=chunk-PKUJNICO.js.map
275
+ //# sourceMappingURL=chunk-JC2OBYYD.js.map
@@ -2,11 +2,11 @@ import {
2
2
  compareReconcilePlanEntries,
3
3
  semanticAgreementKey,
4
4
  summarizeReconcilePlan
5
- } from "./chunk-62D2PAAM.js";
5
+ } from "./chunk-PAAJWQH5.js";
6
6
  import {
7
7
  DEFAULT_CITATION_FORMAT,
8
8
  stripCitationForTemplate
9
- } from "./chunk-TG3FAM2S.js";
9
+ } from "./chunk-JL4TQYM5.js";
10
10
  import {
11
11
  inferMemoryStatus
12
12
  } from "./chunk-7RJUVTVF.js";
@@ -347,4 +347,4 @@ export {
347
347
  buildReconcileManifest,
348
348
  collapseActiveFactDuplicates
349
349
  };
350
- //# sourceMappingURL=chunk-5U7K4W6K.js.map
350
+ //# sourceMappingURL=chunk-JDOBQPJY.js.map
@@ -137,6 +137,48 @@ function lastCitationMarkerForTemplate(text, template = DEFAULT_CITATION_FORMAT)
137
137
  }
138
138
  return last;
139
139
  }
140
+ function citationTemplateIsDetectable(template) {
141
+ if (typeof template !== "string" || template.length === 0) return false;
142
+ if (template === DEFAULT_CITATION_FORMAT) return true;
143
+ PLACEHOLDER_REGEX.lastIndex = 0;
144
+ if (!PLACEHOLDER_REGEX.test(template)) {
145
+ PLACEHOLDER_REGEX.lastIndex = 0;
146
+ return true;
147
+ }
148
+ PLACEHOLDER_REGEX.lastIndex = 0;
149
+ return templateMatcher(template) !== null;
150
+ }
151
+ function citationTemplatesToRecognize(primary, extra = []) {
152
+ const out = [];
153
+ const add = (template) => {
154
+ if (typeof template !== "string" || template.length === 0) return;
155
+ if (!citationTemplateIsDetectable(template)) return;
156
+ if (!out.includes(template)) out.push(template);
157
+ };
158
+ add(DEFAULT_CITATION_FORMAT);
159
+ add(primary);
160
+ for (const template of extra) add(template);
161
+ return out;
162
+ }
163
+ function citationTemplatesForMerge(config) {
164
+ const raw = config.inlineSourceAttributionFormatHistory;
165
+ const extra = Array.isArray(raw) ? raw.filter((value) => typeof value === "string" && value.length > 0) : [];
166
+ return citationTemplatesToRecognize(config.inlineSourceAttributionFormat, extra);
167
+ }
168
+ function lastRecognizedCitationMarker(text, templates) {
169
+ for (const template of templates) {
170
+ const marker = lastCitationMarkerForTemplate(text, template);
171
+ if (marker) return marker;
172
+ }
173
+ return null;
174
+ }
175
+ function stripRecognizedCitations(text, templates) {
176
+ let out = text;
177
+ for (const template of templates) {
178
+ out = stripCitationForTemplate(out, template);
179
+ }
180
+ return out;
181
+ }
140
182
  function attachCitation(text, ctx, template = DEFAULT_CITATION_FORMAT) {
141
183
  if (typeof text !== "string") return text;
142
184
  if (hasCitationForTemplate(text, template)) return text;
@@ -259,10 +301,15 @@ export {
259
301
  hasCitation,
260
302
  hasCitationForTemplate,
261
303
  lastCitationMarkerForTemplate,
304
+ citationTemplateIsDetectable,
305
+ citationTemplatesToRecognize,
306
+ citationTemplatesForMerge,
307
+ lastRecognizedCitationMarker,
308
+ stripRecognizedCitations,
262
309
  attachCitation,
263
310
  parseCitation,
264
311
  parseAllCitations,
265
312
  stripCitation,
266
313
  stripCitationForTemplate
267
314
  };
268
- //# sourceMappingURL=chunk-TG3FAM2S.js.map
315
+ //# sourceMappingURL=chunk-JL4TQYM5.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/source-attribution.ts"],"sourcesContent":["/**\n * Inline Source Attribution Protocol (issue #369)\n *\n * Extracted facts carry provenance inline inside the fact body, so the\n * citation survives hostile memory text, copy/paste, and LLM quoting. This\n * complements — never replaces — the YAML frontmatter provenance stored on\n * disk.\n *\n * Default format (matches issue #369 proposal):\n *\n * The foo service uses Redis for rate limiting. [Source: agent=planner, session=abc123, ts=2026-04-10T14:25:07Z]\n *\n * Key properties:\n * - Inline (part of the body, not metadata).\n * - Compact (typically <80 chars of overhead per fact).\n * - Machine-parseable by a single regex.\n * - Opt-in via `inlineSourceAttributionEnabled` config flag (default off\n * for backwards compatibility with existing downstream consumers).\n * - Legacy facts without a citation remain fully readable.\n *\n * The format template is configurable via `inlineSourceAttributionFormat`\n * with supported placeholders:\n *\n * {agent} — principal / agent identifier\n * {session} — full session key (colon-delimited)\n * {sessionId} — short stable session id (trailing component)\n * {ts} — extraction timestamp (ISO 8601)\n * {date} — extraction date (YYYY-MM-DD)\n *\n * Any privacy-sensitive identifiers should be normalized before being passed\n * to `formatCitation` — the helper treats them as opaque strings.\n */\n\n/** Default citation format template (matches issue #369). */\nexport const DEFAULT_CITATION_FORMAT =\n \"[Source: agent={agent}, session={sessionId}, ts={ts}]\";\n\n/** Sentinel value used when a provenance field is missing. */\nexport const CITATION_UNKNOWN = \"unknown\";\n\nexport interface CitationContext {\n /** Principal / agent identifier (e.g. resolved via resolvePrincipal). */\n agent?: string;\n /** Full session key (e.g. \"agent:planner:main\"). */\n session?: string;\n /**\n * Opaque short session id. Derived from the trailing component of the\n * session key when not provided explicitly. Use this for compact formats\n * that do not need the full colon-delimited session key.\n */\n sessionId?: string;\n /** Extraction timestamp as an ISO 8601 string. */\n ts?: string;\n}\n\nexport interface ParsedCitation {\n /** Agent identifier parsed from the citation (never crashes on malformed input). */\n agent?: string;\n /** Session identifier parsed from the citation. */\n session?: string;\n /** Extraction timestamp parsed from the citation. */\n ts?: string;\n /** The full matched citation substring. */\n raw: string;\n}\n\n/**\n * Regex that matches the default `[Source: agent=X, session=Y, ts=Z]` shape\n * as well as human-edited variants (extra whitespace, reordered fields,\n * subset of fields). Matches non-greedily so it can be anchored anywhere in\n * the text. Kept as a getter factory so callers do not share regex state.\n */\nfunction defaultCitationMatcher(): RegExp {\n // Bounded repetition {1,1024} instead of + so the match cannot backtrack\n // polynomially over hostile memory text (CodeQL js/polynomial-redos). A real\n // citation is far shorter than 1024 chars, so this is behavior-preserving for\n // any genuine [Source: …] block; only pathological/oversized input is excluded.\n return /\\[Source:([^\\]\\n]{1,1024})\\]/gi;\n}\n\n// Linear trailing-whitespace trim. Replaces text.replace(/\\s+$/u, \"\"), whose\n// anchored quantifier backtracks polynomially on long inputs (CodeQL\n// js/polynomial-redos). Matches the exact \\s (with u flag) semantics one char\n// at a time, so the trailing-content preservation logic in attachCitation is\n// unaffected.\nfunction trimTrailingWhitespace(text: string): string {\n let end = text.length;\n while (end > 0 && /\\s/u.test(text[end - 1]!)) end--;\n return text.slice(0, end);\n}\n\n/**\n * Derive a short session id from a full session key.\n * Falls back to the raw session string if no colon is present.\n */\nexport function deriveSessionId(session: string | undefined): string | undefined {\n if (!session) return undefined;\n const trimmed = session.trim();\n if (trimmed.length === 0) return undefined;\n const parts = trimmed.split(\":\").filter((p) => p.length > 0);\n if (parts.length === 0) return trimmed;\n return parts[parts.length - 1];\n}\n\n/**\n * Format an inline citation tag using the provided template.\n *\n * Missing context fields fall back to {@link CITATION_UNKNOWN} — the caller\n * should always get a non-empty, parseable tag.\n *\n * Uses a single-pass substitution so that values which themselves contain\n * placeholder syntax (e.g. an agent literally named `\"{ts}\"`) cannot be\n * re-interpreted by subsequent replacement steps. Each placeholder slot\n * receives exactly one lookup and the substituted value is treated as\n * terminal text, not template source.\n */\nexport function formatCitation(\n ctx: CitationContext,\n template: string = DEFAULT_CITATION_FORMAT,\n): string {\n const session = ctx.session ?? \"\";\n const sessionId = ctx.sessionId ?? deriveSessionId(session) ?? CITATION_UNKNOWN;\n const ts = ctx.ts ?? CITATION_UNKNOWN;\n const agent = ctx.agent && ctx.agent.trim().length > 0 ? ctx.agent : CITATION_UNKNOWN;\n const date = ts && ts !== CITATION_UNKNOWN ? ts.slice(0, 10) : CITATION_UNKNOWN;\n const sessionForTemplate = session.trim().length > 0 ? session : CITATION_UNKNOWN;\n\n // Map from recognised placeholder names to their resolved value. Unknown\n // placeholder names are left intact (returning the original `{name}`).\n const values: Record<string, string> = {\n agent,\n session: sessionForTemplate,\n sessionId,\n ts,\n date,\n };\n\n // Single-pass scan: replace every recognised `{name}` in one sweep so that\n // substituted values cannot themselves be treated as template source on a\n // subsequent pass. The replacer-function form also guarantees that `$` /\n // `$&` / `$1` sequences inside values are emitted literally.\n return template.replace(/\\{([a-zA-Z_][\\w]*)\\}/g, (match, name: string) => {\n return Object.prototype.hasOwnProperty.call(values, name)\n ? values[name]!\n : match;\n });\n}\n\n/**\n * Returns true if the text already carries at least one citation marker.\n * Safe to call on any string — never throws.\n */\nexport function hasCitation(text: string): boolean {\n if (typeof text !== \"string\" || text.length === 0) return false;\n return defaultCitationMatcher().test(text);\n}\n\n/**\n * Escape a string for use as a regex literal.\n */\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Escape a single character for use INSIDE a character class `[...]`.\n * Special chars inside character classes: `]`, `\\`, `^`, `-`.\n */\nfunction escapeRegExpCharClass(ch: string): string {\n if (ch === \"]\") return \"\\\\]\";\n if (ch === \"\\\\\") return \"\\\\\\\\\";\n if (ch === \"^\") return \"\\\\^\";\n if (ch === \"-\") return \"\\\\-\";\n // Other regex meta chars are NOT special inside [...] but escaping them is safe.\n return escapeRegExp(ch);\n}\n\n/**\n * Build a per-placeholder token pattern that excludes newlines, whitespace,\n * and any punctuation characters used as inner separators in the template.\n *\n * This prevents a placeholder span from consuming separator bytes and\n * matching strings that cross separator boundaries in user-supplied content.\n *\n * @param nonWordSepChars - Set of non-word (non-alphanumeric, non-`_`) chars\n * extracted from the inner separator literals of the template.\n */\nfunction buildTokenPattern(nonWordSepChars: Set<string>): string {\n // Always exclude newlines and whitespace.\n const base = \"\\\\n\\\\s\";\n if (nonWordSepChars.size === 0) {\n // No inner separator punctuation — the placeholder spans the full space\n // between prefix and suffix. Fall back to a generous no-newline match.\n return `[^\\\\n]+?`;\n }\n const escaped = [...nonWordSepChars].map(escapeRegExpCharClass).join(\"\");\n return `[^${base}${escaped}]+?`;\n}\n\n/** Regex that matches a `{placeholder}` token inside a template string. */\nconst PLACEHOLDER_REGEX = /\\{[a-zA-Z_][\\w]*\\}/g;\n\n/**\n * Build a regex that matches a citation produced by the given template.\n *\n * The approach depends on the shape of the template:\n *\n * - **Normal case (non-empty literal prefix or suffix).** Anchor the match\n * on the outer literal frame and reconstruct the interior as\n * `interToken + sep + interToken + sep + ... + sep + lastToken`.\n * All **intermediate** per-placeholder tokens exclude the combined set of\n * non-word separator characters used between any two adjacent placeholders,\n * preventing a value from consuming a separator and crossing placeholder\n * boundaries. The **last** token is only required to avoid newlines because\n * it is terminated by the literal suffix anchor — this lets placeholder\n * values that legitimately contain a separator character be recognised (e.g.\n * an ISO-8601 timestamp `2026-04-10T14:25:07Z` in `[src:{agent}:{ts}]`\n * where `:` is the inter-placeholder separator). A template like\n * `[src:{agent}/{sessionId}@{date}]` emits\n * `\\[src:[^\\n\\s/@]+?\\/[^\\n\\s/@]+?@[^\\n]+?\\]` so that `[src:foo/bar]`\n * is NOT matched (wrong separator count), `[src:foo/bar/extra@2026]`\n * is NOT matched (intermediate token crosses a `/` boundary), and\n * `[src:planner/main@2026-04-10]` IS matched correctly.\n *\n * - **Placeholder-bounded with whitespace separator.** Both prefix and\n * suffix are empty and the separator literal(s) between placeholders\n * contain at least one whitespace character (e.g. `{source}: {content}`,\n * `{agent} {sessionId}`). A whitespace-containing separator produces\n * output that is visually indistinguishable from ordinary prose, so the\n * safe strategy is to require a **hard bracket/paren/angle delimiter** on\n * both sides of the reconstructed match. Prose almost never places\n * `[...]` / `(...)` / `<...>` around a phrase, so this yields clean\n * false-positive rejection.\n *\n * - **Placeholder-bounded with compact (non-whitespace) separator.** Both\n * prefix and suffix are empty and the separator literal(s) contain NO\n * whitespace (e.g. `{agent}:{sessionId}`, `{agent}/{sessionId}`).\n * `formatCitation` emits a compact token like `planner:main` with no\n * surrounding delimiters, so the bracket strategy cannot detect it.\n * Instead, the pattern requires that the entire token is bordered by\n * whitespace or a bracket/paren/angle on each side:\n *\n * `(?:(?<=[\\[\\(\\<])|(?<!\\S))[\\w.-]+<sep>[\\w.-]+(?:(?=[\\]\\)\\>])|(?!\\S))`\n *\n * This accepts `planner:main` when it appears standalone or inside a\n * bracket-wrapped token, and rejects `host:80` embedded inside a URL like\n * `http://host:80` because `host` is immediately preceded by `/`\n * (non-whitespace, non-bracket).\n *\n * - **All-placeholder case (no literals between placeholders either).** No\n * reliable regex can be built — a template like `{agent}{sessionId}`\n * contains no anchor characters. Returns `null`; {@link\n * hasCitationForTemplate} treats this as \"cannot detect\" and returns\n * false, falling back on explicit sentinel/format detection only for the\n * default `[Source: ...]` shape.\n *\n * Returns `null` when the template has no placeholders (fully-literal\n * citation, handled by the string-equality fast path in {@link\n * hasCitationForTemplate}) **or** when the template is entirely placeholder-\n * only with no literal content whatsoever.\n */\nfunction templateMatcher(template: string): RegExp | null {\n // Split around all {placeholder} tokens.\n const parts = template.split(PLACEHOLDER_REGEX);\n if (parts.length <= 1) return null;\n\n const prefix = parts[0] ?? \"\";\n const suffix = parts[parts.length - 1] ?? \"\";\n\n // Normal case: at least one literal frame on the outside.\n // Tighten the per-placeholder token so it cannot consume separator\n // characters and match strings that cross separator boundaries\n // (Finding 3 — Uru3).\n if (prefix.length > 0 || suffix.length > 0) {\n const escapedPrefix = escapeRegExp(prefix);\n const escapedSuffix = escapeRegExp(suffix);\n\n // Inner parts: literal separators that sit between adjacent placeholders.\n // For `[src:{agent}/{sessionId}@{date}]`, parts = [\"[src:\", \"/\", \"@\", \"]\"]\n // so innerParts = [\"/\", \"@\"].\n const innerParts = parts.slice(1, -1);\n\n // Collect only the non-word (punctuation/symbol) characters from each\n // inner separator so alphabetic separator text (unlikely but valid) does\n // not exclude letters from the per-placeholder token pattern.\n const nonWordSepChars = new Set<string>();\n for (const sep of innerParts) {\n for (const ch of sep) {\n if (!/\\w/.test(ch)) {\n nonWordSepChars.add(ch);\n }\n }\n }\n\n // All intermediate tokens (every placeholder except the last) use the\n // combined exclusion so they cannot cross placeholder boundaries.\n //\n // The LAST token is different: it is terminated by the literal suffix anchor\n // (e.g. `\\]`), so it does not need to exclude inner-separator characters.\n // Dropping that restriction lets placeholder values that legitimately contain\n // a separator character (e.g. an ISO-8601 timestamp `2026-04-10T14:25:07Z`\n // in template `[src:{agent}:{ts}]`) be recognised correctly instead of\n // producing false-negative misses that trigger duplicate citation injection.\n //\n // Only the LAST token is relaxed. Intermediate tokens keep the combined\n // exclusion so that cross-boundary false positives are still rejected\n // (e.g. `[src:foo/bar/extra@2026-04-11]` for `[src:{a}/{b}@{c}]`).\n const interToken = buildTokenPattern(nonWordSepChars);\n // Last token: terminated by suffix anchor — exclude only newlines.\n const lastToken = buildTokenPattern(new Set<string>());\n\n // Reconstruct the interior: interToken sep interToken sep ... sep lastToken\n // (or just lastToken when there are no inner separators at all).\n const middle =\n innerParts.length === 0\n ? lastToken\n : interToken +\n innerParts\n .slice(0, -1)\n .map((sep) => escapeRegExp(sep) + interToken)\n .join(\"\") +\n escapeRegExp(innerParts[innerParts.length - 1]!) +\n lastToken;\n\n const pattern = escapedPrefix + middle + escapedSuffix;\n return new RegExp(pattern, \"i\");\n }\n\n // Placeholder-bounded case: prefix and suffix are both empty.\n const middleLiterals = parts.slice(1, -1);\n const hasNonEmptyMiddle = middleLiterals.some((p) => p.length > 0);\n if (!hasNonEmptyMiddle) {\n // All-placeholder template with no literal content. Impossible to anchor\n // reliably without sentinel markers; signal the caller.\n return null;\n }\n\n // Identifier token: one or more word chars, dots, dashes, or colons.\n // Colons are included to allow timestamp values like \"10:30\" or session\n // keys like \"agent:planner:main\" inside compact placeholder-bounded\n // templates. URL-like fragments (`http://host:80`) are still rejected\n // because the lead anchor requires whitespace or a bracket immediately\n // before the first id-token group (`http` is preceded by `/`).\n const idToken = \"[\\\\w.:-]+\";\n const body =\n idToken +\n middleLiterals.map((lit) => escapeRegExp(lit) + idToken).join(\"\");\n\n const separatorText = middleLiterals.join(\"\");\n if (/\\s/.test(separatorText)) {\n // Separator contains whitespace: the emitted citation looks like ordinary\n // prose (e.g. `planner main`). Require a hard bracket/paren/angle\n // delimiter on both sides to prevent false matches on English text.\n const opener = \"[\\\\[\\\\(\\\\<]\";\n const closer = \"[\\\\]\\\\)\\\\>]\";\n return new RegExp(opener + body + closer, \"i\");\n }\n\n // Separator is compact (no whitespace): `formatCitation` emits a token like\n // `planner:main` without surrounding delimiters. The challenge is that the\n // same token shape also matches ordinary hyphenated or slashed prose words\n // (e.g. `long-term`, `docs/setup`), causing `hasCitationForTemplate` to\n // return true on uncited fact bodies and silently suppress citation injection\n // from `attachCitation`.\n //\n // Fix (Finding 1): tighten the trail anchor so a bare compact token is only\n // accepted when it sits at the very end of the string (possibly followed by\n // optional trailing whitespace or a newline). Since `attachCitation` always\n // appends the citation at the trimmed end of the fact body, a real citation\n // token will always appear at the tail. Prose like `\"long-term solution\"`\n // has `long-term` in the middle of the string (followed by ` solution`), so\n // the end-of-string anchor rejects it — no false positive, no silent drop.\n //\n // The lead anchor still accepts either a bracket opener or a whitespace\n // boundary (or start of string), so `\"Fact. planner:main\"` and standalone\n // `\"planner:main\"` are both detected after the first attachment pass.\n //\n // Bracket-wrapped form (e.g. `[planner:main]`) is also accepted via the\n // opener/closer pair — bracket still takes precedence over end-of-string.\n //\n // Example — why `http://host:80` does NOT match:\n // Trying to match `host:80`: the char before `h` is `/` (non-whitespace,\n // non-bracket), so `(?<=[\\[\\(\\<])` and `(?<!\\S)` both fail ⟹ no match.\n // Trying to match `http:...`: after `http:` the next chars are `//` which\n // are not `[\\w.-]+`, so the second id-token group fails ⟹ no match.\n const leadAnchor = \"(?:(?<=[\\\\[\\\\(\\\\<])|(?<!\\\\S))\";\n // Trail: either a bracket closer (for `[token]` shape) or end-of-string\n // optionally preceded by whitespace. The `(?!\\S)` is deliberately removed\n // so that a compact token in the MIDDLE of a sentence does not match.\n const trailAnchor = \"(?:(?=[\\\\]\\\\)\\\\>])|(?=\\\\s*$))\";\n return new RegExp(leadAnchor + body + trailAnchor, \"i\");\n}\n\n/**\n * Returns true if `text` already carries a citation produced by `template`\n * **or** by the default `[Source: ...]` format (for facts that were tagged\n * before a config change).\n *\n * Use this instead of {@link hasCitation} whenever the caller has access to\n * the configured `inlineSourceAttributionFormat`.\n *\n * All-placeholder templates such as `{agent}{sessionId}` have no literal\n * content to anchor on and therefore cannot be reliably detected without\n * dedicated sentinel markers. In that case the function returns `false` —\n * callers that need idempotent dedup for such templates should either adopt\n * a template with literal delimiters (recommended) or rely on the default\n * `[Source: ...]` marker detection which is always available via\n * {@link hasCitation}.\n */\nexport function hasCitationForTemplate(text: string, template: string): boolean {\n if (typeof text !== \"string\" || text.length === 0) return false;\n // Always accept the default format as a fallback so facts tagged before a\n // configuration change are not double-tagged on reprocessing.\n if (hasCitation(text)) return true;\n // If the configured template matches the default, we're done.\n //\n // Known limitation (Thread 2 — Codex P2): this fast path exits without\n // checking whether the content carries a citation from a DIFFERENT custom\n // template that was active before the config was changed back to the default.\n // Such a fact would be detected by `hasCitation` above only if the prior\n // custom template happened to match the default `[Source: ...]` pattern.\n // In practice, template changes mid-stream are rare, and the false-negative\n // (missing an old custom citation) produces a benign duplicate citation rather\n // than data loss. A full fix would require storing the citation template used\n // at write time in the frontmatter and checking that here.\n if (template === DEFAULT_CITATION_FORMAT) return false;\n\n // Fully-literal template (no placeholders): exact inclusion check.\n if (!PLACEHOLDER_REGEX.test(template)) {\n // Reset lastIndex because PLACEHOLDER_REGEX is declared with /g.\n PLACEHOLDER_REGEX.lastIndex = 0;\n return text.includes(template);\n }\n // Reset lastIndex after the .test() probe above.\n PLACEHOLDER_REGEX.lastIndex = 0;\n\n const matcher = templateMatcher(template);\n if (!matcher) {\n // All-placeholder template: cannot build a reliable matcher. See the\n // docstring — callers should not rely on dedup for this shape.\n return false;\n }\n return matcher.test(text);\n}\n\n/**\n * Return the LAST citation marker in `text` for the given template (or the\n * default `[Source: ...]` shape). `attachCitation` always appends at the\n * trimmed end, so the last occurrence is the most recently attached marker —\n * callers use this to lift a just-attached citation off a cited body and\n * re-attach it to a derived body (the merged-target commit path). Returns\n * null when the text carries no marker of this template (including\n * all-placeholder templates that cannot be matched reliably).\n */\nexport function lastCitationMarkerForTemplate(\n text: string,\n template: string = DEFAULT_CITATION_FORMAT,\n): string | null {\n if (typeof text !== \"string\" || text.length === 0) return null;\n let matcher: RegExp | null;\n if (template === DEFAULT_CITATION_FORMAT) {\n matcher = defaultCitationMatcher();\n } else if (!PLACEHOLDER_REGEX.test(template)) {\n // Fully-literal template: presence is exact inclusion (no placeholders\n // to widen the match).\n PLACEHOLDER_REGEX.lastIndex = 0;\n return text.includes(template) ? template : null;\n } else {\n PLACEHOLDER_REGEX.lastIndex = 0;\n matcher = templateMatcher(template);\n }\n if (!matcher) return null;\n const global = new RegExp(\n matcher.source,\n matcher.flags.includes(\"g\") ? matcher.flags : matcher.flags + \"g\",\n );\n let last: string | null = null;\n for (let match = global.exec(text); match !== null; match = global.exec(text)) {\n last = match[0];\n if (match[0].length === 0) global.lastIndex++;\n }\n return last;\n}\n\n/**\n * Attach an inline citation to fact text.\n *\n * If the text already has a citation — either the default `[Source: ...]`\n * marker or one produced by the configured template — it is returned unchanged.\n * Existing provenance is respected and never overwritten. Otherwise the\n * citation is appended to the trimmed text with a single space separator,\n * which keeps the marker visually adjacent to the fact body.\n */\nexport function attachCitation(\n text: string,\n ctx: CitationContext,\n template: string = DEFAULT_CITATION_FORMAT,\n): string {\n if (typeof text !== \"string\") return text as unknown as string;\n if (hasCitationForTemplate(text, template)) return text;\n const trimmedEnd = trimTrailingWhitespace(text);\n if (trimmedEnd.length === 0) return text;\n const citation = formatCitation(ctx, template);\n // Preserve any trailing newline that callers rely on for markdown rendering.\n const trailing = text.slice(trimmedEnd.length);\n return `${trimmedEnd} ${citation}${trailing}`;\n}\n\n/**\n * Parse a single inline citation from a piece of text. Returns the first\n * citation encountered or `null` when none is present. Malformed citations\n * do not throw — fields that cannot be parsed simply remain `undefined`.\n */\nexport function parseCitation(text: string): ParsedCitation | null {\n if (typeof text !== \"string\" || text.length === 0) return null;\n const matcher = defaultCitationMatcher();\n const match = matcher.exec(text);\n if (!match) return null;\n\n const body = match[1] ?? \"\";\n const raw = match[0] ?? \"\";\n const parsed: ParsedCitation = { raw };\n\n const fields = body\n .split(\",\")\n .map((segment) => segment.trim())\n .filter((segment) => segment.length > 0);\n\n for (const field of fields) {\n const eqIdx = field.indexOf(\"=\");\n if (eqIdx <= 0) continue;\n const key = field.slice(0, eqIdx).trim().toLowerCase();\n const value = field.slice(eqIdx + 1).trim();\n if (value.length === 0) continue;\n switch (key) {\n case \"agent\":\n parsed.agent = value;\n break;\n case \"session\":\n case \"sessionid\":\n parsed.session = value;\n break;\n case \"ts\":\n case \"timestamp\":\n parsed.ts = value;\n break;\n default:\n // Unknown fields are ignored defensively so human edits never crash.\n break;\n }\n }\n\n return parsed;\n}\n\n/**\n * Parse every citation embedded in the text. Always returns an array; empty\n * when none are present.\n */\nexport function parseAllCitations(text: string): ParsedCitation[] {\n if (typeof text !== \"string\" || text.length === 0) return [];\n const matcher = defaultCitationMatcher();\n const results: ParsedCitation[] = [];\n let match: RegExpExecArray | null;\n while ((match = matcher.exec(text)) !== null) {\n const parsed = parseCitation(match[0]);\n if (parsed) results.push(parsed);\n }\n return results;\n}\n\n/**\n * Remove all inline citations from a piece of text.\n *\n * Callers that want the raw fact body (for dedup hashing, display, or\n * comparison) should use this helper instead of hand-rolled regexes so the\n * whole codebase agrees on the citation syntax.\n *\n * Finding 2 fix: when the input contains no citation marker, the input is\n * returned byte-for-byte unchanged. When a citation IS removed, whitespace\n * normalization is applied only at each join seam (the single space between\n * the preceding text and where the citation was), rather than across the\n * entire string. This preserves markdown hard-break spacing, aligned text,\n * and code-like snippets in fact bodies that happen to carry a citation.\n *\n * Implementation: each citation match is replaced by its \"seam fix\" — the\n * content before the match has its trailing whitespace trimmed and then a\n * single space is appended if any text remains, collapsing only the gap\n * left by the removed marker. Whitespace elsewhere in the body is untouched.\n */\nexport function stripCitation(text: string): string {\n if (typeof text !== \"string\" || text.length === 0) return text;\n // Early exit: no citation marker present — return the input unchanged so\n // that callers never lose formatting fidelity on uncited strings.\n if (!hasCitation(text)) return text;\n\n // Walk through all citations and slice them out one by one so that we can\n // normalise ONLY the whitespace at each seam rather than the entire string.\n const matcher = defaultCitationMatcher();\n let result = \"\";\n let lastIndex = 0;\n\n let match: RegExpExecArray | null;\n while ((match = matcher.exec(text)) !== null) {\n // Text before this citation. Trim trailing spaces/tabs at the seam only.\n const before = text.slice(lastIndex, match.index).replace(/[ \\t]+$/, \"\");\n result += before;\n lastIndex = match.index + match[0].length;\n }\n\n // Append any trailing text after the last citation. Trim leading\n // spaces/tabs and trailing whitespace at the join seam.\n const after = text.slice(lastIndex).replace(/^[ \\t]+/, \"\");\n if (after.length > 0) {\n if (result.length > 0) result += \" \";\n result += after;\n }\n\n return result.trimEnd();\n}\n\n/**\n * Strip an inline citation from text using a specific template regex.\n *\n * This is the template-aware counterpart to {@link stripCitation}. When the\n * caller holds the configured `inlineSourceAttributionFormat`, use this\n * function to strip citations produced by that template — including custom\n * templates that differ from the default `[Source: ...]` pattern.\n *\n * Behaviour:\n * - If the text has a **default-format** citation, strips it first\n * (always safe).\n * - Then, if the result has a **custom-template** citation detected by\n * `hasCitationForTemplate`, builds the template regex and removes every\n * occurrence. BOTH passes run when a body carries both forms — a target\n * written under the default format can carry the default marker plus a\n * custom marker appended after a config change; returning after the\n * default pass alone left the custom marker inside hash inputs (#2330).\n * - All-placeholder templates (no literal prefix/suffix/separator) cannot\n * produce a reliable matcher. `hasCitationForTemplate` already returns\n * `false` for such templates, so this function never attempts to strip an\n * undetectable citation. The text is returned unchanged when no citation\n * is detected.\n * - If no citation is detected for the given template, returns the text\n * unchanged.\n *\n * @returns The stripped text (or the original text when no citation is found).\n */\nexport function stripCitationForTemplate(\n text: string,\n template: string,\n): string {\n if (typeof text !== \"string\" || text.length === 0) return text;\n\n // First pass: the default-format marker, if any. A second pass below still\n // runs — a body can carry the default marker AND the custom template's\n // marker, and canonicalization must remove every recognized form.\n const afterDefault = hasCitation(text) ? stripCitation(text) : text;\n\n if (!hasCitationForTemplate(afterDefault, template)) return afterDefault;\n\n // Build the template matcher. hasCitationForTemplate already returned true,\n // which means templateMatcher produced a non-null result. The null branch\n // here is a defensive fallback only — the default pass already ran.\n const matcher = templateMatcher(template);\n if (!matcher) return afterDefault;\n\n // The matcher regex was built without the global flag; add it for exec loop.\n const globalMatcher = new RegExp(\n matcher.source,\n matcher.flags.includes(\"g\") ? matcher.flags : matcher.flags + \"g\",\n );\n let result = \"\";\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = globalMatcher.exec(afterDefault)) !== null) {\n const matchEnd = match.index + match[0].length;\n const enclosure = enclosingDelimiterRange(afterDefault, match.index, matchEnd);\n const removalStart = enclosure?.start ?? match.index;\n const removalEnd = enclosure?.end ?? matchEnd;\n const before = afterDefault.slice(lastIndex, removalStart).replace(/[ \\t]+$/, \"\");\n result += before;\n lastIndex = removalEnd;\n // Guard against zero-width matches causing an infinite loop.\n if (match[0].length === 0) {\n globalMatcher.lastIndex++;\n }\n }\n\n const after = afterDefault.slice(lastIndex).replace(/^[ \\t]+/, \"\");\n if (after.length > 0) {\n if (result.length > 0) result += \" \";\n result += after;\n }\n\n return result.trimEnd();\n}\n\nfunction enclosingDelimiterRange(\n text: string,\n start: number,\n end: number,\n): { start: number; end: number } | undefined {\n if (start <= 0 || end >= text.length) return undefined;\n const opener = text[start - 1];\n const closer = text[end];\n if (\n (opener === \"[\" && closer === \"]\") ||\n (opener === \"(\" && closer === \")\") ||\n (opener === \"<\" && closer === \">\")\n ) {\n return { start: start - 1, end: end + 1 };\n }\n return undefined;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/source-attribution.ts"],"sourcesContent":["/**\n * Inline Source Attribution Protocol (issue #369)\n *\n * Extracted facts carry provenance inline inside the fact body, so the\n * citation survives hostile memory text, copy/paste, and LLM quoting. This\n * complements — never replaces — the YAML frontmatter provenance stored on\n * disk.\n *\n * Default format (matches issue #369 proposal):\n *\n * The foo service uses Redis for rate limiting. [Source: agent=planner, session=abc123, ts=2026-04-10T14:25:07Z]\n *\n * Key properties:\n * - Inline (part of the body, not metadata).\n * - Compact (typically <80 chars of overhead per fact).\n * - Machine-parseable by a single regex.\n * - Opt-in via `inlineSourceAttributionEnabled` config flag (default off\n * for backwards compatibility with existing downstream consumers).\n * - Legacy facts without a citation remain fully readable.\n *\n * The format template is configurable via `inlineSourceAttributionFormat`\n * with supported placeholders:\n *\n * {agent} — principal / agent identifier\n * {session} — full session key (colon-delimited)\n * {sessionId} — short stable session id (trailing component)\n * {ts} — extraction timestamp (ISO 8601)\n * {date} — extraction date (YYYY-MM-DD)\n *\n * Any privacy-sensitive identifiers should be normalized before being passed\n * to `formatCitation` — the helper treats them as opaque strings.\n */\n\n/** Default citation format template (matches issue #369). */\nexport const DEFAULT_CITATION_FORMAT =\n \"[Source: agent={agent}, session={sessionId}, ts={ts}]\";\n\n/** Sentinel value used when a provenance field is missing. */\nexport const CITATION_UNKNOWN = \"unknown\";\n\nexport interface CitationContext {\n /** Principal / agent identifier (e.g. resolved via resolvePrincipal). */\n agent?: string;\n /** Full session key (e.g. \"agent:planner:main\"). */\n session?: string;\n /**\n * Opaque short session id. Derived from the trailing component of the\n * session key when not provided explicitly. Use this for compact formats\n * that do not need the full colon-delimited session key.\n */\n sessionId?: string;\n /** Extraction timestamp as an ISO 8601 string. */\n ts?: string;\n}\n\nexport interface ParsedCitation {\n /** Agent identifier parsed from the citation (never crashes on malformed input). */\n agent?: string;\n /** Session identifier parsed from the citation. */\n session?: string;\n /** Extraction timestamp parsed from the citation. */\n ts?: string;\n /** The full matched citation substring. */\n raw: string;\n}\n\n/**\n * Regex that matches the default `[Source: agent=X, session=Y, ts=Z]` shape\n * as well as human-edited variants (extra whitespace, reordered fields,\n * subset of fields). Matches non-greedily so it can be anchored anywhere in\n * the text. Kept as a getter factory so callers do not share regex state.\n */\nfunction defaultCitationMatcher(): RegExp {\n // Bounded repetition {1,1024} instead of + so the match cannot backtrack\n // polynomially over hostile memory text (CodeQL js/polynomial-redos). A real\n // citation is far shorter than 1024 chars, so this is behavior-preserving for\n // any genuine [Source: …] block; only pathological/oversized input is excluded.\n return /\\[Source:([^\\]\\n]{1,1024})\\]/gi;\n}\n\n// Linear trailing-whitespace trim. Replaces text.replace(/\\s+$/u, \"\"), whose\n// anchored quantifier backtracks polynomially on long inputs (CodeQL\n// js/polynomial-redos). Matches the exact \\s (with u flag) semantics one char\n// at a time, so the trailing-content preservation logic in attachCitation is\n// unaffected.\nfunction trimTrailingWhitespace(text: string): string {\n let end = text.length;\n while (end > 0 && /\\s/u.test(text[end - 1]!)) end--;\n return text.slice(0, end);\n}\n\n/**\n * Derive a short session id from a full session key.\n * Falls back to the raw session string if no colon is present.\n */\nexport function deriveSessionId(session: string | undefined): string | undefined {\n if (!session) return undefined;\n const trimmed = session.trim();\n if (trimmed.length === 0) return undefined;\n const parts = trimmed.split(\":\").filter((p) => p.length > 0);\n if (parts.length === 0) return trimmed;\n return parts[parts.length - 1];\n}\n\n/**\n * Format an inline citation tag using the provided template.\n *\n * Missing context fields fall back to {@link CITATION_UNKNOWN} — the caller\n * should always get a non-empty, parseable tag.\n *\n * Uses a single-pass substitution so that values which themselves contain\n * placeholder syntax (e.g. an agent literally named `\"{ts}\"`) cannot be\n * re-interpreted by subsequent replacement steps. Each placeholder slot\n * receives exactly one lookup and the substituted value is treated as\n * terminal text, not template source.\n */\nexport function formatCitation(\n ctx: CitationContext,\n template: string = DEFAULT_CITATION_FORMAT,\n): string {\n const session = ctx.session ?? \"\";\n const sessionId = ctx.sessionId ?? deriveSessionId(session) ?? CITATION_UNKNOWN;\n const ts = ctx.ts ?? CITATION_UNKNOWN;\n const agent = ctx.agent && ctx.agent.trim().length > 0 ? ctx.agent : CITATION_UNKNOWN;\n const date = ts && ts !== CITATION_UNKNOWN ? ts.slice(0, 10) : CITATION_UNKNOWN;\n const sessionForTemplate = session.trim().length > 0 ? session : CITATION_UNKNOWN;\n\n // Map from recognised placeholder names to their resolved value. Unknown\n // placeholder names are left intact (returning the original `{name}`).\n const values: Record<string, string> = {\n agent,\n session: sessionForTemplate,\n sessionId,\n ts,\n date,\n };\n\n // Single-pass scan: replace every recognised `{name}` in one sweep so that\n // substituted values cannot themselves be treated as template source on a\n // subsequent pass. The replacer-function form also guarantees that `$` /\n // `$&` / `$1` sequences inside values are emitted literally.\n return template.replace(/\\{([a-zA-Z_][\\w]*)\\}/g, (match, name: string) => {\n return Object.prototype.hasOwnProperty.call(values, name)\n ? values[name]!\n : match;\n });\n}\n\n/**\n * Returns true if the text already carries at least one citation marker.\n * Safe to call on any string — never throws.\n */\nexport function hasCitation(text: string): boolean {\n if (typeof text !== \"string\" || text.length === 0) return false;\n return defaultCitationMatcher().test(text);\n}\n\n/**\n * Escape a string for use as a regex literal.\n */\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Escape a single character for use INSIDE a character class `[...]`.\n * Special chars inside character classes: `]`, `\\`, `^`, `-`.\n */\nfunction escapeRegExpCharClass(ch: string): string {\n if (ch === \"]\") return \"\\\\]\";\n if (ch === \"\\\\\") return \"\\\\\\\\\";\n if (ch === \"^\") return \"\\\\^\";\n if (ch === \"-\") return \"\\\\-\";\n // Other regex meta chars are NOT special inside [...] but escaping them is safe.\n return escapeRegExp(ch);\n}\n\n/**\n * Build a per-placeholder token pattern that excludes newlines, whitespace,\n * and any punctuation characters used as inner separators in the template.\n *\n * This prevents a placeholder span from consuming separator bytes and\n * matching strings that cross separator boundaries in user-supplied content.\n *\n * @param nonWordSepChars - Set of non-word (non-alphanumeric, non-`_`) chars\n * extracted from the inner separator literals of the template.\n */\nfunction buildTokenPattern(nonWordSepChars: Set<string>): string {\n // Always exclude newlines and whitespace.\n const base = \"\\\\n\\\\s\";\n if (nonWordSepChars.size === 0) {\n // No inner separator punctuation — the placeholder spans the full space\n // between prefix and suffix. Fall back to a generous no-newline match.\n return `[^\\\\n]+?`;\n }\n const escaped = [...nonWordSepChars].map(escapeRegExpCharClass).join(\"\");\n return `[^${base}${escaped}]+?`;\n}\n\n/** Regex that matches a `{placeholder}` token inside a template string. */\nconst PLACEHOLDER_REGEX = /\\{[a-zA-Z_][\\w]*\\}/g;\n\n/**\n * Build a regex that matches a citation produced by the given template.\n *\n * The approach depends on the shape of the template:\n *\n * - **Normal case (non-empty literal prefix or suffix).** Anchor the match\n * on the outer literal frame and reconstruct the interior as\n * `interToken + sep + interToken + sep + ... + sep + lastToken`.\n * All **intermediate** per-placeholder tokens exclude the combined set of\n * non-word separator characters used between any two adjacent placeholders,\n * preventing a value from consuming a separator and crossing placeholder\n * boundaries. The **last** token is only required to avoid newlines because\n * it is terminated by the literal suffix anchor — this lets placeholder\n * values that legitimately contain a separator character be recognised (e.g.\n * an ISO-8601 timestamp `2026-04-10T14:25:07Z` in `[src:{agent}:{ts}]`\n * where `:` is the inter-placeholder separator). A template like\n * `[src:{agent}/{sessionId}@{date}]` emits\n * `\\[src:[^\\n\\s/@]+?\\/[^\\n\\s/@]+?@[^\\n]+?\\]` so that `[src:foo/bar]`\n * is NOT matched (wrong separator count), `[src:foo/bar/extra@2026]`\n * is NOT matched (intermediate token crosses a `/` boundary), and\n * `[src:planner/main@2026-04-10]` IS matched correctly.\n *\n * - **Placeholder-bounded with whitespace separator.** Both prefix and\n * suffix are empty and the separator literal(s) between placeholders\n * contain at least one whitespace character (e.g. `{source}: {content}`,\n * `{agent} {sessionId}`). A whitespace-containing separator produces\n * output that is visually indistinguishable from ordinary prose, so the\n * safe strategy is to require a **hard bracket/paren/angle delimiter** on\n * both sides of the reconstructed match. Prose almost never places\n * `[...]` / `(...)` / `<...>` around a phrase, so this yields clean\n * false-positive rejection.\n *\n * - **Placeholder-bounded with compact (non-whitespace) separator.** Both\n * prefix and suffix are empty and the separator literal(s) contain NO\n * whitespace (e.g. `{agent}:{sessionId}`, `{agent}/{sessionId}`).\n * `formatCitation` emits a compact token like `planner:main` with no\n * surrounding delimiters, so the bracket strategy cannot detect it.\n * Instead, the pattern requires that the entire token is bordered by\n * whitespace or a bracket/paren/angle on each side:\n *\n * `(?:(?<=[\\[\\(\\<])|(?<!\\S))[\\w.-]+<sep>[\\w.-]+(?:(?=[\\]\\)\\>])|(?!\\S))`\n *\n * This accepts `planner:main` when it appears standalone or inside a\n * bracket-wrapped token, and rejects `host:80` embedded inside a URL like\n * `http://host:80` because `host` is immediately preceded by `/`\n * (non-whitespace, non-bracket).\n *\n * - **All-placeholder case (no literals between placeholders either).** No\n * reliable regex can be built — a template like `{agent}{sessionId}`\n * contains no anchor characters. Returns `null`; {@link\n * hasCitationForTemplate} treats this as \"cannot detect\" and returns\n * false, falling back on explicit sentinel/format detection only for the\n * default `[Source: ...]` shape.\n *\n * Returns `null` when the template has no placeholders (fully-literal\n * citation, handled by the string-equality fast path in {@link\n * hasCitationForTemplate}) **or** when the template is entirely placeholder-\n * only with no literal content whatsoever.\n */\nfunction templateMatcher(template: string): RegExp | null {\n // Split around all {placeholder} tokens.\n const parts = template.split(PLACEHOLDER_REGEX);\n if (parts.length <= 1) return null;\n\n const prefix = parts[0] ?? \"\";\n const suffix = parts[parts.length - 1] ?? \"\";\n\n // Normal case: at least one literal frame on the outside.\n // Tighten the per-placeholder token so it cannot consume separator\n // characters and match strings that cross separator boundaries\n // (Finding 3 — Uru3).\n if (prefix.length > 0 || suffix.length > 0) {\n const escapedPrefix = escapeRegExp(prefix);\n const escapedSuffix = escapeRegExp(suffix);\n\n // Inner parts: literal separators that sit between adjacent placeholders.\n // For `[src:{agent}/{sessionId}@{date}]`, parts = [\"[src:\", \"/\", \"@\", \"]\"]\n // so innerParts = [\"/\", \"@\"].\n const innerParts = parts.slice(1, -1);\n\n // Collect only the non-word (punctuation/symbol) characters from each\n // inner separator so alphabetic separator text (unlikely but valid) does\n // not exclude letters from the per-placeholder token pattern.\n const nonWordSepChars = new Set<string>();\n for (const sep of innerParts) {\n for (const ch of sep) {\n if (!/\\w/.test(ch)) {\n nonWordSepChars.add(ch);\n }\n }\n }\n\n // All intermediate tokens (every placeholder except the last) use the\n // combined exclusion so they cannot cross placeholder boundaries.\n //\n // The LAST token is different: it is terminated by the literal suffix anchor\n // (e.g. `\\]`), so it does not need to exclude inner-separator characters.\n // Dropping that restriction lets placeholder values that legitimately contain\n // a separator character (e.g. an ISO-8601 timestamp `2026-04-10T14:25:07Z`\n // in template `[src:{agent}:{ts}]`) be recognised correctly instead of\n // producing false-negative misses that trigger duplicate citation injection.\n //\n // Only the LAST token is relaxed. Intermediate tokens keep the combined\n // exclusion so that cross-boundary false positives are still rejected\n // (e.g. `[src:foo/bar/extra@2026-04-11]` for `[src:{a}/{b}@{c}]`).\n const interToken = buildTokenPattern(nonWordSepChars);\n // Last token: terminated by suffix anchor — exclude only newlines.\n const lastToken = buildTokenPattern(new Set<string>());\n\n // Reconstruct the interior: interToken sep interToken sep ... sep lastToken\n // (or just lastToken when there are no inner separators at all).\n const middle =\n innerParts.length === 0\n ? lastToken\n : interToken +\n innerParts\n .slice(0, -1)\n .map((sep) => escapeRegExp(sep) + interToken)\n .join(\"\") +\n escapeRegExp(innerParts[innerParts.length - 1]!) +\n lastToken;\n\n const pattern = escapedPrefix + middle + escapedSuffix;\n return new RegExp(pattern, \"i\");\n }\n\n // Placeholder-bounded case: prefix and suffix are both empty.\n const middleLiterals = parts.slice(1, -1);\n const hasNonEmptyMiddle = middleLiterals.some((p) => p.length > 0);\n if (!hasNonEmptyMiddle) {\n // All-placeholder template with no literal content. Impossible to anchor\n // reliably without sentinel markers; signal the caller.\n return null;\n }\n\n // Identifier token: one or more word chars, dots, dashes, or colons.\n // Colons are included to allow timestamp values like \"10:30\" or session\n // keys like \"agent:planner:main\" inside compact placeholder-bounded\n // templates. URL-like fragments (`http://host:80`) are still rejected\n // because the lead anchor requires whitespace or a bracket immediately\n // before the first id-token group (`http` is preceded by `/`).\n const idToken = \"[\\\\w.:-]+\";\n const body =\n idToken +\n middleLiterals.map((lit) => escapeRegExp(lit) + idToken).join(\"\");\n\n const separatorText = middleLiterals.join(\"\");\n if (/\\s/.test(separatorText)) {\n // Separator contains whitespace: the emitted citation looks like ordinary\n // prose (e.g. `planner main`). Require a hard bracket/paren/angle\n // delimiter on both sides to prevent false matches on English text.\n const opener = \"[\\\\[\\\\(\\\\<]\";\n const closer = \"[\\\\]\\\\)\\\\>]\";\n return new RegExp(opener + body + closer, \"i\");\n }\n\n // Separator is compact (no whitespace): `formatCitation` emits a token like\n // `planner:main` without surrounding delimiters. The challenge is that the\n // same token shape also matches ordinary hyphenated or slashed prose words\n // (e.g. `long-term`, `docs/setup`), causing `hasCitationForTemplate` to\n // return true on uncited fact bodies and silently suppress citation injection\n // from `attachCitation`.\n //\n // Fix (Finding 1): tighten the trail anchor so a bare compact token is only\n // accepted when it sits at the very end of the string (possibly followed by\n // optional trailing whitespace or a newline). Since `attachCitation` always\n // appends the citation at the trimmed end of the fact body, a real citation\n // token will always appear at the tail. Prose like `\"long-term solution\"`\n // has `long-term` in the middle of the string (followed by ` solution`), so\n // the end-of-string anchor rejects it — no false positive, no silent drop.\n //\n // The lead anchor still accepts either a bracket opener or a whitespace\n // boundary (or start of string), so `\"Fact. planner:main\"` and standalone\n // `\"planner:main\"` are both detected after the first attachment pass.\n //\n // Bracket-wrapped form (e.g. `[planner:main]`) is also accepted via the\n // opener/closer pair — bracket still takes precedence over end-of-string.\n //\n // Example — why `http://host:80` does NOT match:\n // Trying to match `host:80`: the char before `h` is `/` (non-whitespace,\n // non-bracket), so `(?<=[\\[\\(\\<])` and `(?<!\\S)` both fail ⟹ no match.\n // Trying to match `http:...`: after `http:` the next chars are `//` which\n // are not `[\\w.-]+`, so the second id-token group fails ⟹ no match.\n const leadAnchor = \"(?:(?<=[\\\\[\\\\(\\\\<])|(?<!\\\\S))\";\n // Trail: either a bracket closer (for `[token]` shape) or end-of-string\n // optionally preceded by whitespace. The `(?!\\S)` is deliberately removed\n // so that a compact token in the MIDDLE of a sentence does not match.\n const trailAnchor = \"(?:(?=[\\\\]\\\\)\\\\>])|(?=\\\\s*$))\";\n return new RegExp(leadAnchor + body + trailAnchor, \"i\");\n}\n\n/**\n * Returns true if `text` already carries a citation produced by `template`\n * **or** by the default `[Source: ...]` format (for facts that were tagged\n * before a config change).\n *\n * Use this instead of {@link hasCitation} whenever the caller has access to\n * the configured `inlineSourceAttributionFormat`.\n *\n * All-placeholder templates such as `{agent}{sessionId}` have no literal\n * content to anchor on and therefore cannot be reliably detected without\n * dedicated sentinel markers. In that case the function returns `false` —\n * callers that need idempotent dedup for such templates should either adopt\n * a template with literal delimiters (recommended) or rely on the default\n * `[Source: ...]` marker detection which is always available via\n * {@link hasCitation}.\n */\nexport function hasCitationForTemplate(text: string, template: string): boolean {\n if (typeof text !== \"string\" || text.length === 0) return false;\n // Always accept the default format as a fallback so facts tagged before a\n // configuration change are not double-tagged on reprocessing.\n if (hasCitation(text)) return true;\n // If the configured template matches the default, we're done.\n //\n // Known limitation (Thread 2 — Codex P2): this fast path exits without\n // checking whether the content carries a citation from a DIFFERENT custom\n // template that was active before the config was changed back to the default.\n // Such a fact would be detected by `hasCitation` above only if the prior\n // custom template happened to match the default `[Source: ...]` pattern.\n // In practice, template changes mid-stream are rare, and the false-negative\n // (missing an old custom citation) produces a benign duplicate citation rather\n // than data loss. A full fix would require storing the citation template used\n // at write time in the frontmatter and checking that here.\n if (template === DEFAULT_CITATION_FORMAT) return false;\n\n // Fully-literal template (no placeholders): exact inclusion check.\n if (!PLACEHOLDER_REGEX.test(template)) {\n // Reset lastIndex because PLACEHOLDER_REGEX is declared with /g.\n PLACEHOLDER_REGEX.lastIndex = 0;\n return text.includes(template);\n }\n // Reset lastIndex after the .test() probe above.\n PLACEHOLDER_REGEX.lastIndex = 0;\n\n const matcher = templateMatcher(template);\n if (!matcher) {\n // All-placeholder template: cannot build a reliable matcher. See the\n // docstring — callers should not rely on dedup for this shape.\n return false;\n }\n return matcher.test(text);\n}\n\n/**\n * Return the LAST citation marker in `text` for the given template (or the\n * default `[Source: ...]` shape). `attachCitation` always appends at the\n * trimmed end, so the last occurrence is the most recently attached marker —\n * callers use this to lift a just-attached citation off a cited body and\n * re-attach it to a derived body (the merged-target commit path). Returns\n * null when the text carries no marker of this template (including\n * all-placeholder templates that cannot be matched reliably).\n */\nexport function lastCitationMarkerForTemplate(\n text: string,\n template: string = DEFAULT_CITATION_FORMAT,\n): string | null {\n if (typeof text !== \"string\" || text.length === 0) return null;\n let matcher: RegExp | null;\n if (template === DEFAULT_CITATION_FORMAT) {\n matcher = defaultCitationMatcher();\n } else if (!PLACEHOLDER_REGEX.test(template)) {\n // Fully-literal template: presence is exact inclusion (no placeholders\n // to widen the match).\n PLACEHOLDER_REGEX.lastIndex = 0;\n return text.includes(template) ? template : null;\n } else {\n PLACEHOLDER_REGEX.lastIndex = 0;\n matcher = templateMatcher(template);\n }\n if (!matcher) return null;\n const global = new RegExp(\n matcher.source,\n matcher.flags.includes(\"g\") ? matcher.flags : matcher.flags + \"g\",\n );\n let last: string | null = null;\n for (let match = global.exec(text); match !== null; match = global.exec(text)) {\n last = match[0];\n if (match[0].length === 0) global.lastIndex++;\n }\n return last;\n}\n\n/**\n * True when a template can be matched and stripped later. All-placeholder\n * templates such as `{agent}{sessionId}` have no literal anchors.\n */\nexport function citationTemplateIsDetectable(template: string): boolean {\n if (typeof template !== \"string\" || template.length === 0) return false;\n if (template === DEFAULT_CITATION_FORMAT) return true;\n PLACEHOLDER_REGEX.lastIndex = 0;\n if (!PLACEHOLDER_REGEX.test(template)) {\n PLACEHOLDER_REGEX.lastIndex = 0;\n return true;\n }\n PLACEHOLDER_REGEX.lastIndex = 0;\n return templateMatcher(template) !== null;\n}\n\n/**\n * Templates the merge path may lift, preserve, or strip: the default\n * format, the current format when it is detectable, then any prior\n * configured formats the caller still holds. Undetectable shapes are\n * dropped so we never hash or attach a marker we cannot re-match.\n */\nexport function citationTemplatesToRecognize(\n primary: string | undefined,\n extra: readonly string[] = [],\n): string[] {\n const out: string[] = [];\n const add = (template: string | undefined): void => {\n if (typeof template !== \"string\" || template.length === 0) return;\n if (!citationTemplateIsDetectable(template)) return;\n if (!out.includes(template)) out.push(template);\n };\n add(DEFAULT_CITATION_FORMAT);\n add(primary);\n for (const template of extra) add(template);\n return out;\n}\n\n/**\n * Prior formats the caller still holds, if any. Absent or malformed\n * history is ignored — fail safe, do not invent templates.\n */\nexport function citationTemplatesForMerge(config: {\n inlineSourceAttributionFormat?: string;\n inlineSourceAttributionFormatHistory?: unknown;\n}): string[] {\n const raw = config.inlineSourceAttributionFormatHistory;\n const extra = Array.isArray(raw)\n ? raw.filter((value): value is string => typeof value === \"string\" && value.length > 0)\n : [];\n return citationTemplatesToRecognize(config.inlineSourceAttributionFormat, extra);\n}\n\nexport function lastRecognizedCitationMarker(\n text: string,\n templates: readonly string[],\n): string | null {\n for (const template of templates) {\n const marker = lastCitationMarkerForTemplate(text, template);\n if (marker) return marker;\n }\n return null;\n}\n\nexport function stripRecognizedCitations(text: string, templates: readonly string[]): string {\n let out = text;\n for (const template of templates) {\n out = stripCitationForTemplate(out, template);\n }\n return out;\n}\n\n/**\n * Attach an inline citation to fact text.\n *\n * If the text already has a citation — either the default `[Source: ...]`\n * marker or one produced by the configured template — it is returned unchanged.\n * Existing provenance is respected and never overwritten. Otherwise the\n * citation is appended to the trimmed text with a single space separator,\n * which keeps the marker visually adjacent to the fact body.\n */\nexport function attachCitation(\n text: string,\n ctx: CitationContext,\n template: string = DEFAULT_CITATION_FORMAT,\n): string {\n if (typeof text !== \"string\") return text as unknown as string;\n if (hasCitationForTemplate(text, template)) return text;\n const trimmedEnd = trimTrailingWhitespace(text);\n if (trimmedEnd.length === 0) return text;\n const citation = formatCitation(ctx, template);\n // Preserve any trailing newline that callers rely on for markdown rendering.\n const trailing = text.slice(trimmedEnd.length);\n return `${trimmedEnd} ${citation}${trailing}`;\n}\n\n/**\n * Parse a single inline citation from a piece of text. Returns the first\n * citation encountered or `null` when none is present. Malformed citations\n * do not throw — fields that cannot be parsed simply remain `undefined`.\n */\nexport function parseCitation(text: string): ParsedCitation | null {\n if (typeof text !== \"string\" || text.length === 0) return null;\n const matcher = defaultCitationMatcher();\n const match = matcher.exec(text);\n if (!match) return null;\n\n const body = match[1] ?? \"\";\n const raw = match[0] ?? \"\";\n const parsed: ParsedCitation = { raw };\n\n const fields = body\n .split(\",\")\n .map((segment) => segment.trim())\n .filter((segment) => segment.length > 0);\n\n for (const field of fields) {\n const eqIdx = field.indexOf(\"=\");\n if (eqIdx <= 0) continue;\n const key = field.slice(0, eqIdx).trim().toLowerCase();\n const value = field.slice(eqIdx + 1).trim();\n if (value.length === 0) continue;\n switch (key) {\n case \"agent\":\n parsed.agent = value;\n break;\n case \"session\":\n case \"sessionid\":\n parsed.session = value;\n break;\n case \"ts\":\n case \"timestamp\":\n parsed.ts = value;\n break;\n default:\n // Unknown fields are ignored defensively so human edits never crash.\n break;\n }\n }\n\n return parsed;\n}\n\n/**\n * Parse every citation embedded in the text. Always returns an array; empty\n * when none are present.\n */\nexport function parseAllCitations(text: string): ParsedCitation[] {\n if (typeof text !== \"string\" || text.length === 0) return [];\n const matcher = defaultCitationMatcher();\n const results: ParsedCitation[] = [];\n let match: RegExpExecArray | null;\n while ((match = matcher.exec(text)) !== null) {\n const parsed = parseCitation(match[0]);\n if (parsed) results.push(parsed);\n }\n return results;\n}\n\n/**\n * Remove all inline citations from a piece of text.\n *\n * Callers that want the raw fact body (for dedup hashing, display, or\n * comparison) should use this helper instead of hand-rolled regexes so the\n * whole codebase agrees on the citation syntax.\n *\n * Finding 2 fix: when the input contains no citation marker, the input is\n * returned byte-for-byte unchanged. When a citation IS removed, whitespace\n * normalization is applied only at each join seam (the single space between\n * the preceding text and where the citation was), rather than across the\n * entire string. This preserves markdown hard-break spacing, aligned text,\n * and code-like snippets in fact bodies that happen to carry a citation.\n *\n * Implementation: each citation match is replaced by its \"seam fix\" — the\n * content before the match has its trailing whitespace trimmed and then a\n * single space is appended if any text remains, collapsing only the gap\n * left by the removed marker. Whitespace elsewhere in the body is untouched.\n */\nexport function stripCitation(text: string): string {\n if (typeof text !== \"string\" || text.length === 0) return text;\n // Early exit: no citation marker present — return the input unchanged so\n // that callers never lose formatting fidelity on uncited strings.\n if (!hasCitation(text)) return text;\n\n // Walk through all citations and slice them out one by one so that we can\n // normalise ONLY the whitespace at each seam rather than the entire string.\n const matcher = defaultCitationMatcher();\n let result = \"\";\n let lastIndex = 0;\n\n let match: RegExpExecArray | null;\n while ((match = matcher.exec(text)) !== null) {\n // Text before this citation. Trim trailing spaces/tabs at the seam only.\n const before = text.slice(lastIndex, match.index).replace(/[ \\t]+$/, \"\");\n result += before;\n lastIndex = match.index + match[0].length;\n }\n\n // Append any trailing text after the last citation. Trim leading\n // spaces/tabs and trailing whitespace at the join seam.\n const after = text.slice(lastIndex).replace(/^[ \\t]+/, \"\");\n if (after.length > 0) {\n if (result.length > 0) result += \" \";\n result += after;\n }\n\n return result.trimEnd();\n}\n\n/**\n * Strip an inline citation from text using a specific template regex.\n *\n * This is the template-aware counterpart to {@link stripCitation}. When the\n * caller holds the configured `inlineSourceAttributionFormat`, use this\n * function to strip citations produced by that template — including custom\n * templates that differ from the default `[Source: ...]` pattern.\n *\n * Behaviour:\n * - If the text has a **default-format** citation, strips it first\n * (always safe).\n * - Then, if the result has a **custom-template** citation detected by\n * `hasCitationForTemplate`, builds the template regex and removes every\n * occurrence. BOTH passes run when a body carries both forms — a target\n * written under the default format can carry the default marker plus a\n * custom marker appended after a config change; returning after the\n * default pass alone left the custom marker inside hash inputs (#2330).\n * - All-placeholder templates (no literal prefix/suffix/separator) cannot\n * produce a reliable matcher. `hasCitationForTemplate` already returns\n * `false` for such templates, so this function never attempts to strip an\n * undetectable citation. The text is returned unchanged when no citation\n * is detected.\n * - If no citation is detected for the given template, returns the text\n * unchanged.\n *\n * @returns The stripped text (or the original text when no citation is found).\n */\nexport function stripCitationForTemplate(\n text: string,\n template: string,\n): string {\n if (typeof text !== \"string\" || text.length === 0) return text;\n\n // First pass: the default-format marker, if any. A second pass below still\n // runs — a body can carry the default marker AND the custom template's\n // marker, and canonicalization must remove every recognized form.\n const afterDefault = hasCitation(text) ? stripCitation(text) : text;\n\n if (!hasCitationForTemplate(afterDefault, template)) return afterDefault;\n\n // Build the template matcher. hasCitationForTemplate already returned true,\n // which means templateMatcher produced a non-null result. The null branch\n // here is a defensive fallback only — the default pass already ran.\n const matcher = templateMatcher(template);\n if (!matcher) return afterDefault;\n\n // The matcher regex was built without the global flag; add it for exec loop.\n const globalMatcher = new RegExp(\n matcher.source,\n matcher.flags.includes(\"g\") ? matcher.flags : matcher.flags + \"g\",\n );\n let result = \"\";\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = globalMatcher.exec(afterDefault)) !== null) {\n const matchEnd = match.index + match[0].length;\n const enclosure = enclosingDelimiterRange(afterDefault, match.index, matchEnd);\n const removalStart = enclosure?.start ?? match.index;\n const removalEnd = enclosure?.end ?? matchEnd;\n const before = afterDefault.slice(lastIndex, removalStart).replace(/[ \\t]+$/, \"\");\n result += before;\n lastIndex = removalEnd;\n // Guard against zero-width matches causing an infinite loop.\n if (match[0].length === 0) {\n globalMatcher.lastIndex++;\n }\n }\n\n const after = afterDefault.slice(lastIndex).replace(/^[ \\t]+/, \"\");\n if (after.length > 0) {\n if (result.length > 0) result += \" \";\n result += after;\n }\n\n return result.trimEnd();\n}\n\nfunction enclosingDelimiterRange(\n text: string,\n start: number,\n end: number,\n): { start: number; end: number } | undefined {\n if (start <= 0 || end >= text.length) return undefined;\n const opener = text[start - 1];\n const closer = text[end];\n if (\n (opener === \"[\" && closer === \"]\") ||\n (opener === \"(\" && closer === \")\") ||\n (opener === \"<\" && closer === \">\")\n ) {\n return { start: start - 1, end: end + 1 };\n }\n return undefined;\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  listNamespaces
3
- } from "./chunk-KY236SP5.js";
3
+ } from "./chunk-AHHFBJX7.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-VQWBUPSJ.js.map
285
+ //# sourceMappingURL=chunk-JMAP6L6Q.js.map
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-NHLLKEKK.js";
12
12
  import {
13
13
  parseConfig
14
- } from "./chunk-5LYSEZOF.js";
14
+ } from "./chunk-2UINSKQC.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-7Z54NXVS.js.map
271
+ //# sourceMappingURL=chunk-K27INAPR.js.map
@@ -1,20 +1,15 @@
1
+ import {
2
+ parseDeepRecallMaxSteps
3
+ } from "./chunk-2EYZ32LH.js";
1
4
  import {
2
5
  deepRecallRequestSchema
3
- } from "./chunk-ZX3AYNNV.js";
6
+ } from "./chunk-ZOGKZ2XT.js";
4
7
  import {
5
8
  EngramAccessInputError
6
9
  } from "./chunk-2Z24E5W2.js";
7
10
 
8
11
  // src/deep-recall-http-glue.ts
9
- function coerceMaxSteps(raw) {
10
- if (raw === void 0 || raw === null) return void 0;
11
- const value = typeof raw === "string" ? Number(raw) : raw;
12
- if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value < 0) {
13
- throw new EngramAccessInputError("maxSteps must be a non-negative integer");
14
- }
15
- return value;
16
- }
17
- async function respondDeepRecall(req, res, respondJson, readJsonBody, service, scopeFor) {
12
+ async function respondDeepRecall(req, res, respondJson, readJsonBody, service, scopeFor, abortSignal) {
18
13
  const parsed = deepRecallRequestSchema.safeParse(await readJsonBody(req));
19
14
  if (!parsed.success) {
20
15
  respondJson(
@@ -24,14 +19,20 @@ async function respondDeepRecall(req, res, respondJson, readJsonBody, service, s
24
19
  );
25
20
  return;
26
21
  }
27
- const maxSteps = coerceMaxSteps(parsed.data.maxSteps);
22
+ let maxSteps;
23
+ try {
24
+ maxSteps = parseDeepRecallMaxSteps(parsed.data.maxSteps);
25
+ } catch (err) {
26
+ throw new EngramAccessInputError(err instanceof Error ? err.message : String(err));
27
+ }
28
28
  const scope = scopeFor(parsed.data.namespace, parsed.data.sessionKey);
29
29
  const result = await service.deepRecall({
30
30
  query: parsed.data.query,
31
31
  ...maxSteps !== void 0 ? { maxSteps } : {},
32
32
  namespace: scope.namespace,
33
33
  sessionKey: scope.sessionKey,
34
- authenticatedPrincipal: scope.authenticatedPrincipal
34
+ authenticatedPrincipal: scope.authenticatedPrincipal,
35
+ ...abortSignal ? { abortSignal } : {}
35
36
  });
36
37
  respondJson(res, 200, result);
37
38
  }
@@ -39,4 +40,4 @@ async function respondDeepRecall(req, res, respondJson, readJsonBody, service, s
39
40
  export {
40
41
  respondDeepRecall
41
42
  };
42
- //# sourceMappingURL=chunk-YTK5MVNF.js.map
43
+ //# sourceMappingURL=chunk-KCKXOS4Y.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/deep-recall-http-glue.ts"],"sourcesContent":["/**\n * Deep-recall HTTP glue (issue #2332) — route body lives here so\n * access-http.ts stays at its structural ceiling (same seam as\n * meetings/http-glue.ts and location/http-glue.ts).\n *\n * Input errors map to 400; everything else rethrows so backend faults keep\n * flowing to the global 500 handler. `deepRecall.enabled` gating lives in\n * EngramAccessService — this module only translates transport shape.\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { deepRecallRequestSchema } from \"./access-schema.js\";\nimport { EngramAccessInputError } from \"./access-errors.js\";\nimport type { EngramAccessService } from \"./access-service.js\";\nimport { parseDeepRecallMaxSteps } from \"./deep-recall-config.js\";\n\ntype RespondJson = (res: ServerResponse, status: number, payload: unknown) => void;\ntype ReadJsonBody = (req: IncomingMessage) => Promise<unknown>;\n\nexport async function respondDeepRecall(\n req: IncomingMessage,\n res: ServerResponse,\n respondJson: RespondJson,\n readJsonBody: ReadJsonBody,\n service: EngramAccessService,\n /**\n * Resolve the caller scope for a body-supplied namespace/sessionKey. The\n * body `namespace` is user-controlled, so it MUST flow through the SAME\n * effective-namespace allow-list gate as the query-string value (issue\n * #1850 finding 2 / #2332 review): a scoped bearer that passes an allowed\n * `?namespace=` while setting a different `namespace` in the body would\n * otherwise read another tenant. access-http supplies the gate and applies\n * the query-string fallback, so this module never selects a namespace of\n * its own. Throws 403 when the effective namespace is not permitted.\n *\n * `authenticatedPrincipal` is the identity the transport authenticated, and\n * it MUST reach the service: authorization and the audit trail derive from\n * the presenting principal, never from the client-supplied `sessionKey`.\n * Dropping it let a crafted key matching another principal rule read that\n * principal's namespaces, and made a legitimate namespace-enabled request\n * with no session key fail as unauthenticated.\n */\n scopeFor: (\n bodyNamespace?: string,\n bodySessionKey?: string,\n ) => { namespace?: string; sessionKey?: string; authenticatedPrincipal?: string },\n /** Transport cancellation (issue #2915): aborts seed search, graph reads, policy calls. */\n abortSignal?: AbortSignal,\n): Promise<void> {\n const parsed = deepRecallRequestSchema.safeParse(await readJsonBody(req));\n if (!parsed.success) {\n respondJson(\n res,\n 400,\n { error: \"invalid_request\", detail: parsed.error.issues.map((i) => `${i.path.join(\".\")}: ${i.message}`).join(\"; \") },\n );\n return;\n }\n let maxSteps: number | undefined;\n try {\n maxSteps = parseDeepRecallMaxSteps(parsed.data.maxSteps);\n } catch (err) {\n throw new EngramAccessInputError(err instanceof Error ? err.message : String(err));\n }\n const scope = scopeFor(parsed.data.namespace, parsed.data.sessionKey);\n const result = await service.deepRecall({\n query: parsed.data.query,\n ...(maxSteps !== undefined ? { maxSteps } : {}),\n namespace: scope.namespace,\n sessionKey: scope.sessionKey,\n authenticatedPrincipal: scope.authenticatedPrincipal,\n ...(abortSignal ? { abortSignal } : {}),\n });\n respondJson(res, 200, result);\n}\n"],"mappings":";;;;;;;;;;;AAmBA,eAAsB,kBACpB,KACA,KACA,aACA,cACA,SAkBA,UAKA,aACe;AACf,QAAM,SAAS,wBAAwB,UAAU,MAAM,aAAa,GAAG,CAAC;AACxE,MAAI,CAAC,OAAO,SAAS;AACnB;AAAA,MACE;AAAA,MACA;AAAA,MACA,EAAE,OAAO,mBAAmB,QAAQ,OAAO,MAAM,OAAO,IAAI,CAAC,MAAM,GAAG,EAAE,KAAK,KAAK,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,IAAI,EAAE;AAAA,IACrH;AACA;AAAA,EACF;AACA,MAAI;AACJ,MAAI;AACF,eAAW,wBAAwB,OAAO,KAAK,QAAQ;AAAA,EACzD,SAAS,KAAK;AACZ,UAAM,IAAI,uBAAuB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,EACnF;AACA,QAAM,QAAQ,SAAS,OAAO,KAAK,WAAW,OAAO,KAAK,UAAU;AACpE,QAAM,SAAS,MAAM,QAAQ,WAAW;AAAA,IACtC,OAAO,OAAO,KAAK;AAAA,IACnB,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;AAAA,IAC7C,WAAW,MAAM;AAAA,IACjB,YAAY,MAAM;AAAA,IAClB,wBAAwB,MAAM;AAAA,IAC9B,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;AAAA,EACvC,CAAC;AACD,cAAY,KAAK,KAAK,MAAM;AAC9B;","names":[]}
@@ -3,7 +3,7 @@ import {
3
3
  readNamespaceMaintenanceLastRanStatuses,
4
4
  readNamespaceMaintenanceStatuses,
5
5
  runNamespaceMaintenancePlan
6
- } from "./chunk-WZYHPAG5.js";
6
+ } from "./chunk-GIM2AGFL.js";
7
7
  import {
8
8
  analyzeSessionIntegrity,
9
9
  applySessionRepair,
@@ -14,7 +14,7 @@ import {
14
14
  } from "./chunk-CMTINOFS.js";
15
15
  import {
16
16
  summarizeCorpusAndReplica
17
- } from "./chunk-BYQX4IOG.js";
17
+ } from "./chunk-R45VFSEV.js";
18
18
  import {
19
19
  readJudgeVerdictStats
20
20
  } from "./chunk-OZKOPQCM.js";
@@ -25,36 +25,36 @@ import {
25
25
  runEvalBenchmarkCiGate,
26
26
  validateEvalBenchmarkPack
27
27
  } from "./chunk-4IHBN6WU.js";
28
- import {
29
- runConsolidationProvenanceCheck
30
- } from "./chunk-2SGLMP2E.js";
31
28
  import {
32
29
  resolveCuratedIncludeFilesStatePath,
33
30
  resolveNativeKnowledgeStatePath,
34
31
  resolveOpenClawWorkspaceStatePath
35
32
  } from "./chunk-2DQ2XREU.js";
33
+ import {
34
+ runConsolidationProvenanceCheck
35
+ } from "./chunk-2SGLMP2E.js";
36
36
  import {
37
37
  reportBufferSurpriseDistribution
38
38
  } from "./chunk-YBPYIAA5.js";
39
39
  import {
40
40
  parseConfig
41
- } from "./chunk-5LYSEZOF.js";
41
+ } from "./chunk-2UINSKQC.js";
42
42
  import {
43
43
  readAggregateExtractionWatermark
44
- } from "./chunk-LKFVVN7R.js";
45
- import {
46
- listNamespaces
47
- } from "./chunk-KY236SP5.js";
44
+ } from "./chunk-WNPRRBOE.js";
48
45
  import {
49
46
  listMemoryGovernanceRuns,
50
47
  readMemoryGovernanceRunArtifact
51
- } from "./chunk-2SKMZUOW.js";
48
+ } from "./chunk-U26LB4WA.js";
49
+ import {
50
+ listNamespaces
51
+ } from "./chunk-AHHFBJX7.js";
52
52
  import {
53
53
  analyzeGraphHealth
54
54
  } from "./chunk-5FAGCOZD.js";
55
55
  import {
56
56
  StorageManager
57
- } from "./chunk-MVG3KXON.js";
57
+ } from "./chunk-I65KB36L.js";
58
58
  import {
59
59
  lintWorkspaceFiles
60
60
  } from "./chunk-DM2T26WE.js";
@@ -1109,7 +1109,7 @@ async function summarizeGraphEdgeDecayStatus(config) {
1109
1109
  }
1110
1110
  async function summarizeTierDistribution(storage) {
1111
1111
  try {
1112
- const { summarizeTiers } = await import("./tier-stats-LUSUUNU6.js");
1112
+ const { summarizeTiers } = await import("./tier-stats-VK5PCO2L.js");
1113
1113
  const summary = await summarizeTiers(storage);
1114
1114
  const storageDir = storage.dir ?? "";
1115
1115
  const journalPath = storageDir.length > 0 ? path.join(storageDir, "state", "tier-migration-journal.jsonl") : null;
@@ -1683,4 +1683,4 @@ export {
1683
1683
  runBenchmarkRecall,
1684
1684
  runOperatorRepair
1685
1685
  };
1686
- //# sourceMappingURL=chunk-7D6SER6A.js.map
1686
+ //# sourceMappingURL=chunk-KJQ4Y2PY.js.map