@remnic/core 9.69.16 → 9.69.18

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 (526) hide show
  1. package/dist/access-admin-ops-surface.d.ts +11 -11
  2. package/dist/access-admin-ops-surface.js +49 -45
  3. package/dist/access-authorization-probe.d.ts +11 -11
  4. package/dist/access-authorization-probe.js +50 -46
  5. package/dist/access-boundary.d.ts +11 -11
  6. package/dist/access-boundary.js +49 -45
  7. package/dist/access-cli.js +111 -110
  8. package/dist/access-cli.js.map +1 -1
  9. package/dist/access-coding-context-resolution.d.ts +1 -1
  10. package/dist/access-extraction-force-flush.d.ts +11 -11
  11. package/dist/access-extraction-force-flush.js +49 -45
  12. package/dist/access-health-types.d.ts +1 -1
  13. package/dist/access-http-lcm-compaction.d.ts +11 -11
  14. package/dist/access-http-lifecycle-flush.d.ts +11 -11
  15. package/dist/access-http-offline-stream.d.ts +11 -11
  16. package/dist/access-http-query.d.ts +2 -2
  17. package/dist/access-http-query.js +51 -47
  18. package/dist/access-http.d.ts +12 -12
  19. package/dist/access-http.js +69 -65
  20. package/dist/access-identity-continuity-surface.d.ts +9 -9
  21. package/dist/access-identity-continuity-surface.js +49 -45
  22. package/dist/access-lcm-surface.d.ts +11 -11
  23. package/dist/access-lcm-surface.js +49 -45
  24. package/dist/access-mcp-output-schemas.js +1 -1
  25. package/dist/access-mcp.d.ts +11 -11
  26. package/dist/access-mcp.js +60 -56
  27. package/dist/access-memory-search-fanout.d.ts +2 -2
  28. package/dist/{access-namespace-preflight-Rzuo1nGR.d.ts → access-namespace-preflight-BMHhxoL9.d.ts} +1 -1
  29. package/dist/access-namespace-preflight.d.ts +3 -3
  30. package/dist/access-namespace-preflight.js +49 -45
  31. package/dist/access-observe-transcript.d.ts +147 -0
  32. package/dist/access-observe-transcript.js +16 -0
  33. package/dist/access-observe-write-surface.d.ts +12 -11
  34. package/dist/access-observe-write-surface.js +49 -45
  35. package/dist/access-offline-manifest.d.ts +9 -9
  36. package/dist/access-offline-manifest.js +6 -6
  37. package/dist/access-operations-batch.js +52 -48
  38. package/dist/access-operations.d.ts +13 -13
  39. package/dist/access-operations.js +57 -53
  40. package/dist/access-recall-concurrency.d.ts +11 -11
  41. package/dist/access-recall-concurrency.js +49 -45
  42. package/dist/access-recall-response.d.ts +11 -11
  43. package/dist/access-recall-response.js +49 -45
  44. package/dist/access-recall-surface.d.ts +11 -11
  45. package/dist/access-recall-surface.js +49 -45
  46. package/dist/access-schema.d.ts +4 -4
  47. package/dist/access-schema.js +5 -5
  48. package/dist/{access-service-tcC_jK6C.d.ts → access-service-CYdqPfpS.d.ts} +22 -13
  49. package/dist/access-service-helpers.d.ts +11 -11
  50. package/dist/access-service.d.ts +11 -11
  51. package/dist/access-service.js +49 -45
  52. package/dist/access-surface-catalog.d.ts +11 -11
  53. package/dist/access-surface-catalog.js +51 -47
  54. package/dist/access-surface-catalog.js.map +1 -1
  55. package/dist/access-wearables-meetings-surface.d.ts +3 -3
  56. package/dist/action-confidence.d.ts +1 -1
  57. package/dist/active-memory-bridge.d.ts +1 -1
  58. package/dist/active-recall.d.ts +1 -1
  59. package/dist/active-recall.js +7 -7
  60. package/dist/adapters/index.js +4 -4
  61. package/dist/adapters/registry.js +2 -2
  62. package/dist/ambient-provenance.d.ts +1 -1
  63. package/dist/artifact-search.d.ts +1 -1
  64. package/dist/{auto-sync-Q6Q2FVSC.js → auto-sync-GRUJFD2F.js} +3 -3
  65. package/dist/behavior-learner.d.ts +1 -1
  66. package/dist/behavior-signals.d.ts +1 -1
  67. package/dist/bootstrap.d.ts +9 -9
  68. package/dist/briefing-window.d.ts +2 -2
  69. package/dist/briefing.d.ts +2 -2
  70. package/dist/briefing.js +14 -14
  71. package/dist/buffer-surprise-report.d.ts +1 -1
  72. package/dist/buffer-turn-helpers.d.ts +1 -1
  73. package/dist/buffer.d.ts +2 -2
  74. package/dist/bulk-import/index.d.ts +3 -3
  75. package/dist/calibration.d.ts +1 -1
  76. package/dist/capabilities.d.ts +1 -1
  77. package/dist/{catalog-DjTLVOYp.d.ts → catalog-C1qHsGew.d.ts} +1 -1
  78. package/dist/causal-behavior.d.ts +1 -1
  79. package/dist/causal-behavior.js +2 -2
  80. package/dist/causal-chain.js +2 -2
  81. package/dist/causal-consolidation.d.ts +1 -1
  82. package/dist/causal-consolidation.js +16 -16
  83. package/dist/causal-retrieval.js +2 -2
  84. package/dist/causal-trajectory-graph.d.ts +1 -1
  85. package/dist/causal-trajectory-graph.js +2 -2
  86. package/dist/causal-trajectory.js +1 -1
  87. package/dist/{chunk-LEPOP46W.js → chunk-227UFSEQ.js} +4 -4
  88. package/dist/{chunk-RJ57OOCD.js → chunk-2J4TIFBK.js} +3 -3
  89. package/dist/{chunk-AU7Q3LSC.js → chunk-2QSZNTDO.js} +4 -4
  90. package/dist/{chunk-P6GKRT2H.js → chunk-2Z3DG5CQ.js} +1 -1
  91. package/dist/{chunk-BO4PWIJY.js → chunk-3LADWWMA.js} +3 -3
  92. package/dist/{chunk-P7LVYPIX.js → chunk-3LJPSRAN.js} +3 -3
  93. package/dist/{chunk-ZKZCJRRO.js → chunk-43HMVVOL.js} +2 -2
  94. package/dist/{chunk-3TSU662L.js → chunk-46QMN7I7.js} +5 -5
  95. package/dist/{chunk-HODFGQGT.js → chunk-4HYNMLT6.js} +2 -2
  96. package/dist/{chunk-HTOWFFAI.js → chunk-5CF2R4NS.js} +2 -2
  97. package/dist/{chunk-QVI63XSO.js → chunk-5MF4EGL5.js} +50 -50
  98. package/dist/{chunk-KLSPKMIO.js → chunk-5SGOARQJ.js} +2 -2
  99. package/dist/{chunk-JGXMA6HL.js → chunk-6FUMA6AA.js} +2 -2
  100. package/dist/chunk-6MINUTGJ.js +64 -0
  101. package/dist/chunk-6MINUTGJ.js.map +1 -0
  102. package/dist/{chunk-K2IJH4D3.js → chunk-7RRUHJPG.js} +7 -7
  103. package/dist/{chunk-I4QAH4SY.js → chunk-7TUB6JWA.js} +3 -3
  104. package/dist/{chunk-NNBZS3DY.js → chunk-AG46P24C.js} +4 -4
  105. package/dist/{chunk-B64IVEOH.js → chunk-AWF4CNYJ.js} +2 -2
  106. package/dist/{chunk-C25N5HWX.js → chunk-B2AGUKSS.js} +2 -2
  107. package/dist/{chunk-7ZMU4XQT.js → chunk-BR3OOQZQ.js} +2 -2
  108. package/dist/{chunk-TRLCMLX7.js → chunk-BZTJEILZ.js} +2 -2
  109. package/dist/{chunk-OLBZ2WGG.js → chunk-C2JCVZWX.js} +2 -2
  110. package/dist/{chunk-YWN3GYI2.js → chunk-CASWJ2HM.js} +2 -2
  111. package/dist/{chunk-S35IIP5P.js → chunk-CFKCFY4B.js} +2 -2
  112. package/dist/{chunk-S5G2LAL7.js → chunk-CHWUICVY.js} +4 -4
  113. package/dist/{chunk-7JV4JST3.js → chunk-CVJMGVEW.js} +47 -47
  114. package/dist/{chunk-BE4Y6GK6.js → chunk-D35XLYQ7.js} +11 -11
  115. package/dist/{chunk-DA4ZMCBU.js → chunk-D5ZNOKR7.js} +3 -3
  116. package/dist/{chunk-BEXFNGQ3.js → chunk-DK6GMO6D.js} +3 -3
  117. package/dist/{chunk-I6DUKBUI.js → chunk-DP4EBV7C.js} +2 -2
  118. package/dist/{chunk-W6GEMUZM.js → chunk-EFCBJDYE.js} +13 -13
  119. package/dist/{chunk-XMIAU4CO.js → chunk-EJ5RKUXW.js} +2 -2
  120. package/dist/{chunk-LF6SHWVV.js → chunk-F5UWQ4LX.js} +2 -2
  121. package/dist/{chunk-XQGFIAG7.js → chunk-FB7LAJQM.js} +2 -2
  122. package/dist/{chunk-OAKATRAN.js → chunk-G6N654ND.js} +10 -10
  123. package/dist/{chunk-2EHDPHMD.js → chunk-GGYDJJBO.js} +2 -2
  124. package/dist/{chunk-VAMZYOOV.js → chunk-HOUST5UX.js} +2 -2
  125. package/dist/{chunk-NHLEFBE2.js → chunk-I4Y6TBD7.js} +3 -3
  126. package/dist/{chunk-W272SWN7.js → chunk-I7FY43VC.js} +7 -7
  127. package/dist/{chunk-MSDIETFC.js → chunk-IZZ7Q2RJ.js} +56 -47
  128. package/dist/chunk-IZZ7Q2RJ.js.map +1 -0
  129. package/dist/{chunk-CTCGHNWN.js → chunk-J2R275FN.js} +4 -4
  130. package/dist/{chunk-XJJYSX6F.js → chunk-JCUG7AXZ.js} +4 -4
  131. package/dist/{chunk-ZRUEP4IK.js → chunk-JIM4BIOC.js} +30 -49
  132. package/dist/chunk-JIM4BIOC.js.map +1 -0
  133. package/dist/{chunk-BX6GW4KC.js → chunk-JMAG7WZ7.js} +2 -2
  134. package/dist/{chunk-NF3NMAG7.js → chunk-JOYC4RYC.js} +2 -2
  135. package/dist/{chunk-5JQV4T5Q.js → chunk-JZ6EYAVP.js} +2 -2
  136. package/dist/{chunk-QRDSXR3V.js → chunk-KA2HZCMG.js} +2 -2
  137. package/dist/{chunk-7LCGFUMB.js → chunk-KQAFEZQX.js} +4 -4
  138. package/dist/{chunk-ETZ7KKOS.js → chunk-KTVSPFCQ.js} +2 -2
  139. package/dist/{chunk-PAWIY5OQ.js → chunk-L74A6NTI.js} +6 -6
  140. package/dist/{chunk-2XJDAEAM.js → chunk-LFK623SF.js} +5 -5
  141. package/dist/chunk-LVE64P5Y.js +80 -0
  142. package/dist/chunk-LVE64P5Y.js.map +1 -0
  143. package/dist/{chunk-IEZ6CGTW.js → chunk-N3SS45OW.js} +115 -55
  144. package/dist/chunk-N3SS45OW.js.map +1 -0
  145. package/dist/{chunk-QUVWFZOU.js → chunk-N7JK2RKG.js} +2 -2
  146. package/dist/{chunk-BFDOBESV.js → chunk-NYRB7BKY.js} +2 -2
  147. package/dist/{chunk-LDOQE34V.js → chunk-NZGO2GKL.js} +2 -2
  148. package/dist/{chunk-VYD63IFH.js → chunk-OGTKQ5MJ.js} +3 -3
  149. package/dist/{chunk-BIJAWZYW.js → chunk-OLT3YTDH.js} +4 -4
  150. package/dist/{chunk-F2ERDKY2.js → chunk-PC7WNIRL.js} +17 -17
  151. package/dist/{chunk-3BS2OGDT.js → chunk-PPOT6SPR.js} +5 -5
  152. package/dist/{chunk-G7VEQEMG.js → chunk-QVSRE355.js} +65 -39
  153. package/dist/chunk-QVSRE355.js.map +1 -0
  154. package/dist/{chunk-LUDXSSTW.js → chunk-R7LY4YKF.js} +2 -2
  155. package/dist/{chunk-N37X5RU7.js → chunk-RACZB5HT.js} +4 -4
  156. package/dist/{chunk-LJAP4KSW.js → chunk-RO2X2EYM.js} +2 -2
  157. package/dist/{chunk-5YQ7RFSO.js → chunk-S37NN23M.js} +2 -2
  158. package/dist/{chunk-DDX6KIXF.js → chunk-SB4OBB7P.js} +2 -2
  159. package/dist/{chunk-JHTF22NQ.js → chunk-TA7UZZMW.js} +2 -2
  160. package/dist/{chunk-4UVDLNHQ.js → chunk-UMEOXLIZ.js} +2 -2
  161. package/dist/{chunk-63I7LMLG.js → chunk-WL5PR5YC.js} +2 -2
  162. package/dist/{chunk-H5IIBGDM.js → chunk-X33MJFD2.js} +2 -2
  163. package/dist/{chunk-SXHBZXHK.js → chunk-XJJLWTLW.js} +5 -5
  164. package/dist/{chunk-OYV6RKPM.js → chunk-XOQGUGJL.js} +2 -6
  165. package/dist/chunk-XOQGUGJL.js.map +1 -0
  166. package/dist/{chunk-GIC6BASP.js → chunk-XZBXINXZ.js} +4 -4
  167. package/dist/{chunk-APZXA4WI.js → chunk-YVLENSNS.js} +2 -2
  168. package/dist/{chunk-OUKBMQ2O.js → chunk-Z3SQEEB6.js} +2 -2
  169. package/dist/{chunk-NN5CQTAJ.js → chunk-ZEBRENA6.js} +2 -2
  170. package/dist/{chunk-5H2G5X4R.js → chunk-ZJWDWPX6.js} +3 -3
  171. package/dist/{chunk-M7DGN6JZ.js → chunk-ZL3XX5LW.js} +2 -2
  172. package/dist/{chunk-4WIKMOE3.js → chunk-ZZM476NV.js} +1 -1
  173. package/dist/{cli-BI9YYpKx.d.ts → cli-DN9LpWf0.d.ts} +5 -5
  174. package/dist/cli.d.ts +13 -13
  175. package/dist/cli.js +92 -88
  176. package/dist/coding/export-okf-codegraph.d.ts +1 -1
  177. package/dist/coding/export-okf-codegraph.js +13 -13
  178. package/dist/coding/pre-action-gate.d.ts +1 -1
  179. package/dist/coding/pre-action-gate.js +2 -2
  180. package/dist/compounding/engine.d.ts +2 -2
  181. package/dist/compounding/engine.js +13 -13
  182. package/dist/compounding/preference-consolidator.d.ts +1 -1
  183. package/dist/compression-optimizer.d.ts +1 -1
  184. package/dist/config.d.ts +1 -1
  185. package/dist/config.js +7 -7
  186. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  187. package/dist/connectors/codex-materialize-runner.js +13 -13
  188. package/dist/connectors/codex-materialize.d.ts +1 -1
  189. package/dist/connectors/index.d.ts +1 -1
  190. package/dist/connectors/index.js +13 -13
  191. package/dist/consolidation-provenance-check.d.ts +2 -2
  192. package/dist/consolidation-undo.d.ts +2 -2
  193. package/dist/contradiction/index.d.ts +3 -3
  194. package/dist/converge-config.d.ts +16 -2
  195. package/dist/converge-config.js +9 -1
  196. package/dist/convergence-refresh.d.ts +2 -2
  197. package/dist/convergence-refresh.js +15 -15
  198. package/dist/conversation-index/backend.d.ts +1 -1
  199. package/dist/conversation-index/backend.js +2 -2
  200. package/dist/conversation-index/chunker.d.ts +1 -1
  201. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  202. package/dist/conversation-index/indexer.d.ts +1 -1
  203. package/dist/conversation-index/search.d.ts +1 -1
  204. package/dist/corpus-watermark.d.ts +1 -1
  205. package/dist/corpus-watermark.js +15 -15
  206. package/dist/cross-lingual-recall.d.ts +1 -1
  207. package/dist/day-summary.d.ts +1 -1
  208. package/dist/deep-recall-http-glue.d.ts +11 -11
  209. package/dist/deep-recall-http-glue.js +6 -6
  210. package/dist/deep-recall-mcp-tools.d.ts +11 -11
  211. package/dist/deep-recall-policy-llm.d.ts +1 -1
  212. package/dist/deep-recall-seeds.d.ts +1 -1
  213. package/dist/deep-recall.js +2 -2
  214. package/dist/delinearize.d.ts +1 -1
  215. package/dist/dependency-propagation-config.d.ts +1 -1
  216. package/dist/{dependency-propagation-delivery-37JdQv_3.d.ts → dependency-propagation-delivery-DjpUlhLi.d.ts} +1 -1
  217. package/dist/direct-answer-wiring.d.ts +1 -1
  218. package/dist/direct-answer.d.ts +1 -1
  219. package/dist/embedding-fallback.d.ts +1 -1
  220. package/dist/enrichment/index.d.ts +1 -1
  221. package/dist/entity-origin-fields.d.ts +1 -1
  222. package/dist/entity-retrieval.d.ts +2 -2
  223. package/dist/entity-retrieval.js +13 -13
  224. package/dist/entity-schema.d.ts +1 -1
  225. package/dist/episodic-context.d.ts +1 -1
  226. package/dist/eval-trajectory-contracts.d.ts +1 -1
  227. package/dist/eval-trajectory-store.d.ts +1 -1
  228. package/dist/eval-trajectory.d.ts +1 -1
  229. package/dist/explicit-capture.d.ts +9 -9
  230. package/dist/external-wiki-access.d.ts +11 -11
  231. package/dist/external-wiki-access.js +50 -46
  232. package/dist/external-wiki-collection-registration.d.ts +1 -1
  233. package/dist/external-wiki-collection.d.ts +1 -1
  234. package/dist/external-wiki-mcp-tools.d.ts +11 -11
  235. package/dist/extraction-error-classification.d.ts +1 -1
  236. package/dist/extraction-faithfulness.d.ts +1 -1
  237. package/dist/extraction-judge-telemetry.d.ts +1 -1
  238. package/dist/extraction-judge-training.d.ts +1 -1
  239. package/dist/extraction-judge.d.ts +1 -1
  240. package/dist/extraction-liveness.d.ts +1 -1
  241. package/dist/extraction-normalization.d.ts +1 -1
  242. package/dist/extraction-prompt.d.ts +1 -1
  243. package/dist/extraction-source-grounding-rules.d.ts +1 -1
  244. package/dist/extraction-source-grounding.d.ts +1 -1
  245. package/dist/extraction.d.ts +1 -1
  246. package/dist/extraction.js +16 -16
  247. package/dist/fallback-llm.d.ts +1 -1
  248. package/dist/graph-dashboard-diff.d.ts +1 -1
  249. package/dist/graph-dashboard-key.d.ts +1 -1
  250. package/dist/graph-dashboard-parser.d.ts +1 -1
  251. package/dist/{graph-edge-decay-FXGELBFA.js → graph-edge-decay-DGTBFALQ.js} +4 -4
  252. package/dist/graph-edge-decay-DGTBFALQ.js.map +1 -0
  253. package/dist/graph-edge-reinforcement.d.ts +1 -1
  254. package/dist/graph-path-reconstruction.d.ts +1 -1
  255. package/dist/graph-path-scoring.d.ts +1 -1
  256. package/dist/graph-snapshot.d.ts +1 -1
  257. package/dist/graph-snapshot.js +3 -3
  258. package/dist/graph.d.ts +1 -1
  259. package/dist/graph.js +2 -2
  260. package/dist/harmonic-retrieval.js +1 -1
  261. package/dist/importance.d.ts +1 -1
  262. package/dist/importers/index.d.ts +1 -1
  263. package/dist/in-flight-reads.d.ts +1 -1
  264. package/dist/{index-DquhYqsc.d.ts → index-CsUrdMyL.d.ts} +2 -2
  265. package/dist/index.d.ts +26 -26
  266. package/dist/index.js +138 -127
  267. package/dist/intent.d.ts +1 -1
  268. package/dist/lcm/engine.d.ts +1 -1
  269. package/dist/lcm/index.d.ts +1 -1
  270. package/dist/lcm/tools.d.ts +1 -1
  271. package/dist/lifecycle.d.ts +1 -1
  272. package/dist/live-connectors-runner.d.ts +1 -1
  273. package/dist/local-llm.d.ts +1 -1
  274. package/dist/local-model-endpoint.d.ts +1 -1
  275. package/dist/location/index.d.ts +3 -3
  276. package/dist/location/index.js +15 -15
  277. package/dist/maintenance/memory-governance.d.ts +1 -1
  278. package/dist/maintenance/memory-governance.js +13 -13
  279. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
  280. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +13 -13
  281. package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
  282. package/dist/maintenance/rebuild-memory-projection.js +14 -14
  283. package/dist/{maintenance-CizZOycr.d.ts → maintenance-D1GRGLTE.d.ts} +3 -3
  284. package/dist/mcp-memory-inspector-app.d.ts +11 -11
  285. package/dist/memory-action-policy.d.ts +1 -1
  286. package/dist/memory-cache.d.ts +1 -1
  287. package/dist/memory-controller.d.ts +1 -1
  288. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  289. package/dist/memory-projection-store.d.ts +1 -1
  290. package/dist/memory-provenance.d.ts +1 -1
  291. package/dist/memory-snapshot.d.ts +1 -1
  292. package/dist/memory-subject-cli.d.ts +11 -11
  293. package/dist/memory-subject.d.ts +11 -11
  294. package/dist/memory-worth-outcomes.d.ts +2 -2
  295. package/dist/models-json.d.ts +1 -1
  296. package/dist/namespaces/migrate.d.ts +3 -3
  297. package/dist/namespaces/migrate.js +14 -14
  298. package/dist/namespaces/principal.d.ts +1 -1
  299. package/dist/namespaces/search.d.ts +1 -1
  300. package/dist/namespaces/search.js +9 -9
  301. package/dist/namespaces/storage.d.ts +3 -3
  302. package/dist/namespaces/storage.js +13 -13
  303. package/dist/native-knowledge.d.ts +1 -1
  304. package/dist/offline-sync-impression-drain.d.ts +1 -1
  305. package/dist/offline-sync.js +2 -2
  306. package/dist/operator-doctor-corpus.d.ts +1 -1
  307. package/dist/operator-doctor-corpus.js +16 -16
  308. package/dist/operator-doctor-replica.d.ts +1 -1
  309. package/dist/operator-toolkit.d.ts +3 -3
  310. package/dist/operator-toolkit.js +30 -30
  311. package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
  312. package/dist/orchestration/maintenance.d.ts +4 -4
  313. package/dist/orchestration/maintenance.js +21 -21
  314. package/dist/{orchestrator-DqLcuNMP.d.ts → orchestrator-DeqaPGT5.d.ts} +8 -8
  315. package/dist/orchestrator.d.ts +9 -9
  316. package/dist/orchestrator.js +111 -110
  317. package/dist/patterns-cli.d.ts +1 -1
  318. package/dist/{pipeline-DbJpmcRu.d.ts → pipeline-umUzU0D1.d.ts} +1 -1
  319. package/dist/policy-runtime.d.ts +1 -1
  320. package/dist/proactive-contention.d.ts +1 -1
  321. package/dist/provenance.d.ts +1 -1
  322. package/dist/{public-http-Bocro5ZU.d.ts → public-http-C1ht4oDJ.d.ts} +1 -1
  323. package/dist/{qmd-DA_7fbSz.d.ts → qmd-BasT78PP.d.ts} +1 -1
  324. package/dist/qmd-preflight.d.ts +2 -2
  325. package/dist/qmd-recall-cache.d.ts +1 -1
  326. package/dist/qmd.d.ts +2 -2
  327. package/dist/recall-concurrency-config.d.ts +1 -1
  328. package/dist/recall-disclosure-escalation.d.ts +1 -1
  329. package/dist/recall-explain-renderer.d.ts +1 -1
  330. package/dist/recall-explain-renderer.js +3 -3
  331. package/dist/recall-memory-map.d.ts +1 -1
  332. package/dist/recall-navigate-access.d.ts +1 -1
  333. package/dist/recall-navigate-access.js +2 -2
  334. package/dist/recall-navigate-disclosure.d.ts +1 -1
  335. package/dist/recall-navigate-disclosure.js +1 -1
  336. package/dist/recall-navigate.d.ts +1 -1
  337. package/dist/recall-navigate.js +2 -2
  338. package/dist/recall-planner-llm.d.ts +1 -1
  339. package/dist/recall-state.d.ts +1 -1
  340. package/dist/recall-tag-filter.d.ts +1 -1
  341. package/dist/recall-timings.d.ts +1 -1
  342. package/dist/recall-xray-cli.d.ts +1 -1
  343. package/dist/recall-xray-cli.js +4 -4
  344. package/dist/recall-xray-renderer.d.ts +1 -1
  345. package/dist/recall-xray-renderer.js +3 -3
  346. package/dist/recall-xray.d.ts +1 -1
  347. package/dist/recall-xray.js +2 -2
  348. package/dist/reconcile/cursor.d.ts +1 -1
  349. package/dist/reconcile/cursor.js +2 -2
  350. package/dist/reconcile/manifest.d.ts +1 -1
  351. package/dist/reconcile/manifest.js +3 -3
  352. package/dist/reconcile/plan.d.ts +16 -1
  353. package/dist/reconcile/plan.js +2 -2
  354. package/dist/replay/normalizers/chatgpt.d.ts +1 -1
  355. package/dist/replay/normalizers/claude.d.ts +1 -1
  356. package/dist/replay/normalizers/openclaw.d.ts +1 -1
  357. package/dist/replay/normalizers/shared.d.ts +1 -1
  358. package/dist/replay/runner.d.ts +1 -1
  359. package/dist/replay/types.d.ts +1 -1
  360. package/dist/replica-divergence.d.ts +1 -1
  361. package/dist/replica-peers-config.d.ts +1 -1
  362. package/dist/resolve-auth-token.d.ts +1 -1
  363. package/dist/resume-bundles.js +8 -8
  364. package/dist/retrieval-agents.d.ts +2 -2
  365. package/dist/retrieval-tiers.d.ts +1 -1
  366. package/dist/routing/engine.d.ts +1 -1
  367. package/dist/routing/store.d.ts +1 -1
  368. package/dist/salvage-envelope.d.ts +1 -1
  369. package/dist/schemas.d.ts +42 -42
  370. package/dist/{scope-profiles-BpiWKZzx.d.ts → scope-profiles-DXYzyOXW.d.ts} +1 -1
  371. package/dist/search/embed-helper.d.ts +1 -1
  372. package/dist/search/factory.d.ts +1 -1
  373. package/dist/search/factory.js +8 -8
  374. package/dist/search/index.d.ts +1 -1
  375. package/dist/search/index.js +13 -13
  376. package/dist/search/lancedb-backend.d.ts +1 -1
  377. package/dist/search/lancedb-backend.js +2 -2
  378. package/dist/search/meilisearch-backend.d.ts +1 -1
  379. package/dist/search/meilisearch-backend.js +2 -2
  380. package/dist/search/noop-backend.d.ts +1 -1
  381. package/dist/search/orama-backend.d.ts +1 -1
  382. package/dist/search/orama-backend.js +2 -2
  383. package/dist/search/port.d.ts +1 -1
  384. package/dist/search/remote-backend.d.ts +1 -1
  385. package/dist/{semantic-consolidation-NJpaZpkY.d.ts → semantic-consolidation-CqDeaY0U.d.ts} +1 -1
  386. package/dist/semantic-consolidation.d.ts +2 -2
  387. package/dist/semantic-consolidation.js +14 -14
  388. package/dist/semantic-rule-promotion.js +13 -13
  389. package/dist/semantic-rule-verifier.d.ts +1 -1
  390. package/dist/semantic-rule-verifier.js +13 -13
  391. package/dist/{service-DdlZjX1D.d.ts → service-BKD-DVYZ.d.ts} +2 -2
  392. package/dist/session-observer-bands.d.ts +1 -1
  393. package/dist/session-observer-state.d.ts +1 -1
  394. package/dist/shared-context/manager.d.ts +1 -1
  395. package/dist/signal.d.ts +1 -1
  396. package/dist/source-agent-qualifier.d.ts +1 -1
  397. package/dist/source-agent-qualifier.js +13 -13
  398. package/dist/standup/build.js +13 -13
  399. package/dist/{storage-C7BWrpU9.d.ts → storage-BcFd1lN_.d.ts} +1 -1
  400. package/dist/storage.d.ts +2 -2
  401. package/dist/storage.js +12 -12
  402. package/dist/subject-config.d.ts +1 -1
  403. package/dist/summarizer.d.ts +30 -4
  404. package/dist/summarizer.js +6 -4
  405. package/dist/summary-snapshot.d.ts +1 -1
  406. package/dist/support-passport/index.d.ts +14 -14
  407. package/dist/support-passport/index.js +52 -48
  408. package/dist/temporal-supersession.d.ts +2 -2
  409. package/dist/temporal-timeline-recall.d.ts +1 -1
  410. package/dist/temporal-validity.d.ts +1 -1
  411. package/dist/threading.d.ts +1 -1
  412. package/dist/tier-migration.d.ts +2 -2
  413. package/dist/tier-routing.d.ts +1 -1
  414. package/dist/topics.d.ts +1 -1
  415. package/dist/transcript.d.ts +1 -1
  416. package/dist/transfer/capsule-export.js +2 -2
  417. package/dist/transfer/capsule-import.js +2 -2
  418. package/dist/transfer/export-okf.d.ts +1 -1
  419. package/dist/transfer/export-okf.js +14 -14
  420. package/dist/transfer/types.d.ts +12 -12
  421. package/dist/trust-score-stage.d.ts +1 -1
  422. package/dist/trust-score.d.ts +1 -1
  423. package/dist/{types-Cy1l6fzp.d.ts → types-BRg3tMyp.d.ts} +2 -0
  424. package/dist/types.d.ts +1 -1
  425. package/dist/types.js +1 -1
  426. package/dist/utility-runtime.d.ts +1 -1
  427. package/dist/verified-recall.js +13 -13
  428. package/dist/who-knows-cli.d.ts +11 -11
  429. package/dist/who-knows-cli.js +14 -14
  430. package/dist/who-knows.d.ts +11 -11
  431. package/dist/who-knows.js +13 -13
  432. package/dist/write-envelope.d.ts +1 -1
  433. package/package.json +2 -2
  434. package/src/access-mcp-output-schemas.ts +60 -34
  435. package/src/access-observe-transcript-persistence.test.ts +252 -0
  436. package/src/access-observe-transcript.ts +153 -0
  437. package/src/access-observe-write-surface.ts +234 -224
  438. package/src/access-service.ts +33 -28
  439. package/src/converge-config.ts +40 -3
  440. package/src/index.ts +1 -1
  441. package/src/reconcile/plan.test.ts +118 -88
  442. package/src/reconcile/plan.ts +98 -84
  443. package/src/summarizer.ts +217 -111
  444. package/src/summary-snapshot.test.ts +8 -6
  445. package/src/types.ts +47 -44
  446. package/dist/chunk-G7VEQEMG.js.map +0 -1
  447. package/dist/chunk-HBVPYRDW.js +0 -39
  448. package/dist/chunk-HBVPYRDW.js.map +0 -1
  449. package/dist/chunk-IEZ6CGTW.js.map +0 -1
  450. package/dist/chunk-MSDIETFC.js.map +0 -1
  451. package/dist/chunk-OYV6RKPM.js.map +0 -1
  452. package/dist/chunk-ZRUEP4IK.js.map +0 -1
  453. /package/dist/{graph-edge-decay-FXGELBFA.js.map → access-observe-transcript.js.map} +0 -0
  454. /package/dist/{auto-sync-Q6Q2FVSC.js.map → auto-sync-GRUJFD2F.js.map} +0 -0
  455. /package/dist/{chunk-LEPOP46W.js.map → chunk-227UFSEQ.js.map} +0 -0
  456. /package/dist/{chunk-RJ57OOCD.js.map → chunk-2J4TIFBK.js.map} +0 -0
  457. /package/dist/{chunk-AU7Q3LSC.js.map → chunk-2QSZNTDO.js.map} +0 -0
  458. /package/dist/{chunk-P6GKRT2H.js.map → chunk-2Z3DG5CQ.js.map} +0 -0
  459. /package/dist/{chunk-BO4PWIJY.js.map → chunk-3LADWWMA.js.map} +0 -0
  460. /package/dist/{chunk-P7LVYPIX.js.map → chunk-3LJPSRAN.js.map} +0 -0
  461. /package/dist/{chunk-ZKZCJRRO.js.map → chunk-43HMVVOL.js.map} +0 -0
  462. /package/dist/{chunk-3TSU662L.js.map → chunk-46QMN7I7.js.map} +0 -0
  463. /package/dist/{chunk-HODFGQGT.js.map → chunk-4HYNMLT6.js.map} +0 -0
  464. /package/dist/{chunk-HTOWFFAI.js.map → chunk-5CF2R4NS.js.map} +0 -0
  465. /package/dist/{chunk-QVI63XSO.js.map → chunk-5MF4EGL5.js.map} +0 -0
  466. /package/dist/{chunk-KLSPKMIO.js.map → chunk-5SGOARQJ.js.map} +0 -0
  467. /package/dist/{chunk-JGXMA6HL.js.map → chunk-6FUMA6AA.js.map} +0 -0
  468. /package/dist/{chunk-K2IJH4D3.js.map → chunk-7RRUHJPG.js.map} +0 -0
  469. /package/dist/{chunk-I4QAH4SY.js.map → chunk-7TUB6JWA.js.map} +0 -0
  470. /package/dist/{chunk-NNBZS3DY.js.map → chunk-AG46P24C.js.map} +0 -0
  471. /package/dist/{chunk-B64IVEOH.js.map → chunk-AWF4CNYJ.js.map} +0 -0
  472. /package/dist/{chunk-C25N5HWX.js.map → chunk-B2AGUKSS.js.map} +0 -0
  473. /package/dist/{chunk-7ZMU4XQT.js.map → chunk-BR3OOQZQ.js.map} +0 -0
  474. /package/dist/{chunk-TRLCMLX7.js.map → chunk-BZTJEILZ.js.map} +0 -0
  475. /package/dist/{chunk-OLBZ2WGG.js.map → chunk-C2JCVZWX.js.map} +0 -0
  476. /package/dist/{chunk-YWN3GYI2.js.map → chunk-CASWJ2HM.js.map} +0 -0
  477. /package/dist/{chunk-S35IIP5P.js.map → chunk-CFKCFY4B.js.map} +0 -0
  478. /package/dist/{chunk-S5G2LAL7.js.map → chunk-CHWUICVY.js.map} +0 -0
  479. /package/dist/{chunk-7JV4JST3.js.map → chunk-CVJMGVEW.js.map} +0 -0
  480. /package/dist/{chunk-BE4Y6GK6.js.map → chunk-D35XLYQ7.js.map} +0 -0
  481. /package/dist/{chunk-DA4ZMCBU.js.map → chunk-D5ZNOKR7.js.map} +0 -0
  482. /package/dist/{chunk-BEXFNGQ3.js.map → chunk-DK6GMO6D.js.map} +0 -0
  483. /package/dist/{chunk-I6DUKBUI.js.map → chunk-DP4EBV7C.js.map} +0 -0
  484. /package/dist/{chunk-W6GEMUZM.js.map → chunk-EFCBJDYE.js.map} +0 -0
  485. /package/dist/{chunk-XMIAU4CO.js.map → chunk-EJ5RKUXW.js.map} +0 -0
  486. /package/dist/{chunk-LF6SHWVV.js.map → chunk-F5UWQ4LX.js.map} +0 -0
  487. /package/dist/{chunk-XQGFIAG7.js.map → chunk-FB7LAJQM.js.map} +0 -0
  488. /package/dist/{chunk-OAKATRAN.js.map → chunk-G6N654ND.js.map} +0 -0
  489. /package/dist/{chunk-2EHDPHMD.js.map → chunk-GGYDJJBO.js.map} +0 -0
  490. /package/dist/{chunk-VAMZYOOV.js.map → chunk-HOUST5UX.js.map} +0 -0
  491. /package/dist/{chunk-NHLEFBE2.js.map → chunk-I4Y6TBD7.js.map} +0 -0
  492. /package/dist/{chunk-W272SWN7.js.map → chunk-I7FY43VC.js.map} +0 -0
  493. /package/dist/{chunk-CTCGHNWN.js.map → chunk-J2R275FN.js.map} +0 -0
  494. /package/dist/{chunk-XJJYSX6F.js.map → chunk-JCUG7AXZ.js.map} +0 -0
  495. /package/dist/{chunk-BX6GW4KC.js.map → chunk-JMAG7WZ7.js.map} +0 -0
  496. /package/dist/{chunk-NF3NMAG7.js.map → chunk-JOYC4RYC.js.map} +0 -0
  497. /package/dist/{chunk-5JQV4T5Q.js.map → chunk-JZ6EYAVP.js.map} +0 -0
  498. /package/dist/{chunk-QRDSXR3V.js.map → chunk-KA2HZCMG.js.map} +0 -0
  499. /package/dist/{chunk-7LCGFUMB.js.map → chunk-KQAFEZQX.js.map} +0 -0
  500. /package/dist/{chunk-ETZ7KKOS.js.map → chunk-KTVSPFCQ.js.map} +0 -0
  501. /package/dist/{chunk-PAWIY5OQ.js.map → chunk-L74A6NTI.js.map} +0 -0
  502. /package/dist/{chunk-2XJDAEAM.js.map → chunk-LFK623SF.js.map} +0 -0
  503. /package/dist/{chunk-QUVWFZOU.js.map → chunk-N7JK2RKG.js.map} +0 -0
  504. /package/dist/{chunk-BFDOBESV.js.map → chunk-NYRB7BKY.js.map} +0 -0
  505. /package/dist/{chunk-LDOQE34V.js.map → chunk-NZGO2GKL.js.map} +0 -0
  506. /package/dist/{chunk-VYD63IFH.js.map → chunk-OGTKQ5MJ.js.map} +0 -0
  507. /package/dist/{chunk-BIJAWZYW.js.map → chunk-OLT3YTDH.js.map} +0 -0
  508. /package/dist/{chunk-F2ERDKY2.js.map → chunk-PC7WNIRL.js.map} +0 -0
  509. /package/dist/{chunk-3BS2OGDT.js.map → chunk-PPOT6SPR.js.map} +0 -0
  510. /package/dist/{chunk-LUDXSSTW.js.map → chunk-R7LY4YKF.js.map} +0 -0
  511. /package/dist/{chunk-N37X5RU7.js.map → chunk-RACZB5HT.js.map} +0 -0
  512. /package/dist/{chunk-LJAP4KSW.js.map → chunk-RO2X2EYM.js.map} +0 -0
  513. /package/dist/{chunk-5YQ7RFSO.js.map → chunk-S37NN23M.js.map} +0 -0
  514. /package/dist/{chunk-DDX6KIXF.js.map → chunk-SB4OBB7P.js.map} +0 -0
  515. /package/dist/{chunk-JHTF22NQ.js.map → chunk-TA7UZZMW.js.map} +0 -0
  516. /package/dist/{chunk-4UVDLNHQ.js.map → chunk-UMEOXLIZ.js.map} +0 -0
  517. /package/dist/{chunk-63I7LMLG.js.map → chunk-WL5PR5YC.js.map} +0 -0
  518. /package/dist/{chunk-H5IIBGDM.js.map → chunk-X33MJFD2.js.map} +0 -0
  519. /package/dist/{chunk-SXHBZXHK.js.map → chunk-XJJLWTLW.js.map} +0 -0
  520. /package/dist/{chunk-GIC6BASP.js.map → chunk-XZBXINXZ.js.map} +0 -0
  521. /package/dist/{chunk-APZXA4WI.js.map → chunk-YVLENSNS.js.map} +0 -0
  522. /package/dist/{chunk-OUKBMQ2O.js.map → chunk-Z3SQEEB6.js.map} +0 -0
  523. /package/dist/{chunk-NN5CQTAJ.js.map → chunk-ZEBRENA6.js.map} +0 -0
  524. /package/dist/{chunk-5H2G5X4R.js.map → chunk-ZJWDWPX6.js.map} +0 -0
  525. /package/dist/{chunk-M7DGN6JZ.js.map → chunk-ZL3XX5LW.js.map} +0 -0
  526. /package/dist/{chunk-4WIKMOE3.js.map → chunk-ZZM476NV.js.map} +0 -0
@@ -13,13 +13,13 @@ import {
13
13
  requestEntityCanonicalIdReconcile,
14
14
  withRawEntityPageMutation
15
15
  } from "./chunk-NNZFPYYX.js";
16
+ import {
17
+ parseExportBundle
18
+ } from "./chunk-WEHSQBFR.js";
16
19
  import {
17
20
  decryptCapsuleFileInMemory,
18
21
  isEncryptedCapsuleFile
19
22
  } from "./chunk-X7Y7WX73.js";
20
- import {
21
- parseExportBundle
22
- } from "./chunk-WEHSQBFR.js";
23
23
  import {
24
24
  assertIsDirectoryNotSymlink,
25
25
  assertRealpathInsideRoot,
@@ -294,4 +294,4 @@ function mintForkId(capsuleId, originalId, now) {
294
294
  export {
295
295
  importCapsule
296
296
  };
297
- //# sourceMappingURL=chunk-CTCGHNWN.js.map
297
+ //# sourceMappingURL=chunk-J2R275FN.js.map
@@ -7,15 +7,15 @@ import {
7
7
  sha256Bytes,
8
8
  validateArchiveRelativePath
9
9
  } from "./chunk-GCGJW34D.js";
10
- import {
11
- DEFAULT_OFFLINE_SYNC_EXCLUDE_GLOBS
12
- } from "./chunk-AREGMX2J.js";
13
10
  import {
14
11
  isEncryptedOfflineSyncFile,
15
12
  readPlainOfflineSyncFileChunk,
16
13
  sha256OfflineSyncFile,
17
14
  shouldExcludeOfflineSyncFile
18
15
  } from "./chunk-NBP4EX5N.js";
16
+ import {
17
+ DEFAULT_OFFLINE_SYNC_EXCLUDE_GLOBS
18
+ } from "./chunk-AREGMX2J.js";
19
19
  import {
20
20
  CENSUS_MAX_MTIME_MS,
21
21
  isCensusMtimeMs,
@@ -1894,4 +1894,4 @@ export {
1894
1894
  normalizeOfflineSyncState,
1895
1895
  fileStatesFromSnapshot
1896
1896
  };
1897
- //# sourceMappingURL=chunk-XJJYSX6F.js.map
1897
+ //# sourceMappingURL=chunk-JCUG7AXZ.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  CONVERGE_CONFLICT_POLICIES,
3
3
  DEFAULT_CONVERGE_CONFLICT_POLICY
4
- } from "./chunk-HBVPYRDW.js";
4
+ } from "./chunk-6MINUTGJ.js";
5
5
  import {
6
6
  validateArchiveRelativePath
7
7
  } from "./chunk-GCGJW34D.js";
@@ -21,7 +21,7 @@ var ReconcilePlanInputError = class extends Error {
21
21
  this.name = "ReconcilePlanInputError";
22
22
  }
23
23
  };
24
- function assertCensusRecord(file, side, namespace) {
24
+ function assertCensusRecord(file, side, namespace, platforms) {
25
25
  const path = file?.path;
26
26
  if (typeof path !== "string" || path.length === 0) {
27
27
  throw new ReconcilePlanInputError(
@@ -33,7 +33,7 @@ function assertCensusRecord(file, side, namespace) {
33
33
  } catch (err) {
34
34
  throw new ReconcilePlanInputError(err instanceof Error ? err.message : String(err));
35
35
  }
36
- assertPortablePathSegments(path, side, namespace);
36
+ assertPortablePathSegments(path, side, namespace, platforms);
37
37
  return {
38
38
  ...file,
39
39
  path,
@@ -51,9 +51,7 @@ function assertMtimeMs(value, context) {
51
51
  }
52
52
  function assertDigest(value, context) {
53
53
  if (!isSha256Hex(value)) {
54
- throw new ReconcilePlanInputError(
55
- `reconcile: ${context} must carry a 64-character sha256 hex digest`
56
- );
54
+ throw new ReconcilePlanInputError(`reconcile: ${context} must carry a 64-character sha256 hex digest`);
57
55
  }
58
56
  return value.toLowerCase();
59
57
  }
@@ -87,10 +85,11 @@ function assertIterable(value, side, namespace) {
87
85
  var WIN32_INVALID_CHARS = /[<>:"|?*\u0000-\u001f]/;
88
86
  var LONE_SURROGATE = /[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/;
89
87
  var WIN32_RESERVED_NAMES = /^(con|prn|aux|nul|(com|lpt)[1-9\u00b9\u00b2\u00b3])$/i;
90
- function assertPortablePathSegments(path, side, namespace) {
88
+ function assertPortablePathSegments(path, side, namespace, platforms) {
89
+ const isWindows = platforms.some((candidate) => candidate === "win32");
91
90
  for (const segment of path.split("/")) {
92
91
  if (segment.length === 0) continue;
93
- if (segment.endsWith(".") || segment.endsWith(" ")) {
92
+ if (isWindows && (segment.endsWith(".") || segment.endsWith(" "))) {
94
93
  throw new ReconcilePlanInputError(
95
94
  `reconcile: ${side} census for namespace ${namespace} path ${path} has a segment ending in a dot or space; Windows strips those and would alias it onto another file`
96
95
  );
@@ -100,12 +99,12 @@ function assertPortablePathSegments(path, side, namespace) {
100
99
  `reconcile: ${side} census for namespace ${namespace} path ${path} contains an unpaired surrogate`
101
100
  );
102
101
  }
103
- if (WIN32_INVALID_CHARS.test(segment)) {
102
+ if (isWindows && WIN32_INVALID_CHARS.test(segment)) {
104
103
  throw new ReconcilePlanInputError(
105
104
  `reconcile: ${side} census for namespace ${namespace} path ${path} contains a character Windows cannot store`
106
105
  );
107
106
  }
108
- if (WIN32_RESERVED_NAMES.test(segment.split(".")[0] ?? "")) {
107
+ if (isWindows && WIN32_RESERVED_NAMES.test(segment.split(".")[0] ?? "")) {
109
108
  throw new ReconcilePlanInputError(
110
109
  `reconcile: ${side} census for namespace ${namespace} path ${path} uses a reserved Windows device name`
111
110
  );
@@ -136,10 +135,10 @@ function rejectConflictingDuplicate(existing, incoming, path, side, namespace) {
136
135
  }
137
136
  return true;
138
137
  }
139
- function indexByPath(files, side, namespace) {
138
+ function indexByPath(files, side, namespace, platforms) {
140
139
  const index = /* @__PURE__ */ new Map();
141
140
  for (const raw of files) {
142
- const file = assertCensusRecord(raw, side, namespace);
141
+ const file = assertCensusRecord(raw, side, namespace, platforms);
143
142
  if (rejectConflictingDuplicate(index.get(file.path), file, file.path, side, namespace)) continue;
144
143
  index.set(file.path, file);
145
144
  }
@@ -163,10 +162,10 @@ function parseTombstonedDigests(value, namespace, field = "tombstonedFileSha256"
163
162
  }
164
163
  return digests;
165
164
  }
166
- function indexDigestsByPath(files, side, namespace) {
165
+ function indexDigestsByPath(files, side, namespace, platforms) {
167
166
  const index = /* @__PURE__ */ new Map();
168
167
  for (const raw of files) {
169
- const file = assertCensusRecord(raw, side, namespace);
168
+ const file = assertCensusRecord(raw, side, namespace, platforms);
170
169
  const existing = index.get(file.path);
171
170
  if (existing !== void 0) {
172
171
  if (existing !== file.sha256) {
@@ -204,12 +203,10 @@ function resolveConflict(policy, localMtimeMs, peerMtimeMs, missingTimestampReso
204
203
  }
205
204
  return localMtimeMs > peerMtimeMs ? "local-wins" : "peer-wins";
206
205
  }
207
- function parseDeletionMtimes(value, side, namespace) {
206
+ function parseDeletionMtimes(value, side, namespace, platforms) {
208
207
  if (value === void 0) return /* @__PURE__ */ new Map();
209
208
  if (!(value instanceof Map)) {
210
- throw new ReconcilePlanInputError(
211
- `reconcile: ${side} deletion mtimes for namespace ${namespace} must be a Map`
212
- );
209
+ throw new ReconcilePlanInputError(`reconcile: ${side} deletion mtimes for namespace ${namespace} must be a Map`);
213
210
  }
214
211
  const parsed = /* @__PURE__ */ new Map();
215
212
  for (const [path, mtimeMs] of value) {
@@ -218,7 +215,7 @@ function parseDeletionMtimes(value, side, namespace) {
218
215
  } catch (err) {
219
216
  throw new ReconcilePlanInputError(err instanceof Error ? err.message : String(err));
220
217
  }
221
- assertPortablePathSegments(path, side, namespace);
218
+ assertPortablePathSegments(path, side, namespace, platforms);
222
219
  parsed.set(path, assertMtimeMs(mtimeMs, `${side} deletion for namespace ${namespace} entry ${path}`));
223
220
  }
224
221
  return parsed;
@@ -234,21 +231,18 @@ function planNamespaceReconciliation(input, options = {}) {
234
231
  const policy = assertConflictPolicy(options.conflictPolicy);
235
232
  const localCensus = assertIterable(input.local, "local", namespace);
236
233
  const caseFold = /* @__PURE__ */ new Map();
237
- const peer = indexByPath(assertIterable(input.peer, "peer", namespace), "peer", namespace);
238
- const base = input.base === void 0 ? null : indexDigestsByPath(assertIterable(input.base, "base", namespace), "base", namespace);
234
+ const effectivePlatforms = [options.localPlatform ?? process.platform, options.peerPlatform];
235
+ const peer = indexByPath(assertIterable(input.peer, "peer", namespace), "peer", namespace, effectivePlatforms);
236
+ const base = input.base === void 0 ? null : indexDigestsByPath(assertIterable(input.base, "base", namespace), "base", namespace, effectivePlatforms);
239
237
  const tombstoned = parseTombstonedDigests(input.tombstonedFileSha256, namespace);
240
- const peerTombstoned = parseTombstonedDigests(
241
- input.peerTombstonedFileSha256,
242
- namespace,
243
- "peerTombstonedFileSha256"
244
- );
245
- const localDeletionMtimeMs = parseDeletionMtimes(input.localDeletionMtimeMs, "local", namespace);
246
- const peerDeletionMtimeMs = parseDeletionMtimes(input.peerDeletionMtimeMs, "peer", namespace);
238
+ const peerTombstoned = parseTombstonedDigests(input.peerTombstonedFileSha256, namespace, "peerTombstonedFileSha256");
239
+ const localDeletionMtimeMs = parseDeletionMtimes(input.localDeletionMtimeMs, "local", namespace, effectivePlatforms);
240
+ const peerDeletionMtimeMs = parseDeletionMtimes(input.peerDeletionMtimeMs, "peer", namespace, effectivePlatforms);
247
241
  const entries = [];
248
242
  if (base) for (const basePath of base.keys()) assertNoPathAlias(caseFold, basePath, namespace);
249
243
  const seenLocal = /* @__PURE__ */ new Map();
250
244
  for (const rawLocal of localCensus) {
251
- const localFile = assertCensusRecord(rawLocal, "local", namespace);
245
+ const localFile = assertCensusRecord(rawLocal, "local", namespace, effectivePlatforms);
252
246
  const path = localFile.path;
253
247
  assertNoPathAlias(caseFold, path, namespace);
254
248
  const seen = seenLocal.get(path);
@@ -277,12 +271,7 @@ function planNamespaceReconciliation(input, options = {}) {
277
271
  if (!peerFile) {
278
272
  if (baseSha256 !== void 0) {
279
273
  const peerDeletionMtime = peerDeletionMtimeMs.get(path);
280
- const resolution2 = baseSha256 === localFile.sha256 ? "unresolved" : resolveConflict(
281
- policy,
282
- localFile.mtimeMs,
283
- peerDeletionMtime,
284
- "unresolved"
285
- );
274
+ const resolution2 = baseSha256 === localFile.sha256 ? "unresolved" : resolveConflict(policy, localFile.mtimeMs, peerDeletionMtime, "unresolved");
286
275
  entries.push({
287
276
  path,
288
277
  namespace,
@@ -340,12 +329,7 @@ function planNamespaceReconciliation(input, options = {}) {
340
329
  });
341
330
  continue;
342
331
  }
343
- const resolution = resolveConflict(
344
- policy,
345
- localFile.mtimeMs,
346
- peerFile.mtimeMs,
347
- "supersede-link"
348
- );
332
+ const resolution = resolveConflict(policy, localFile.mtimeMs, peerFile.mtimeMs, "supersede-link");
349
333
  entries.push({
350
334
  path,
351
335
  namespace,
@@ -374,12 +358,7 @@ function planNamespaceReconciliation(input, options = {}) {
374
358
  }
375
359
  if (baseSha256 !== void 0) {
376
360
  const localDeletionMtime = localDeletionMtimeMs.get(path);
377
- const resolution = baseSha256 === peerFile.sha256 ? "unresolved" : resolveConflict(
378
- policy,
379
- localDeletionMtime,
380
- peerFile.mtimeMs,
381
- "unresolved"
382
- );
361
+ const resolution = baseSha256 === peerFile.sha256 ? "unresolved" : resolveConflict(policy, localDeletionMtime, peerFile.mtimeMs, "unresolved");
383
362
  entries.push({
384
363
  path,
385
364
  namespace,
@@ -414,7 +393,9 @@ function summarizeReconcilePlan(entries) {
414
393
  const needsOperator = entry.resolution === "unresolved" || entry.resolution === "supersede-link";
415
394
  if (entry.action === "conflict" && needsOperator) report.unresolved += 1;
416
395
  }
417
- return [...byNamespace.values()].sort((a, b) => a.namespace === b.namespace ? 0 : a.namespace < b.namespace ? -1 : 1);
396
+ return [...byNamespace.values()].sort(
397
+ (a, b) => a.namespace === b.namespace ? 0 : a.namespace < b.namespace ? -1 : 1
398
+ );
418
399
  }
419
400
  function planReconciliation(namespaces, options = {}) {
420
401
  if (!Array.isArray(namespaces)) {
@@ -452,4 +433,4 @@ export {
452
433
  summarizeReconcilePlan,
453
434
  planReconciliation
454
435
  };
455
- //# sourceMappingURL=chunk-ZRUEP4IK.js.map
436
+ //# sourceMappingURL=chunk-JIM4BIOC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/reconcile/plan.ts"],"sourcesContent":["import { CENSUS_MAX_MTIME_MS, isCensusMtimeMs, isSha256Hex } from \"../census-validation.js\";\nimport { normalizeNamespaceIdentity } from \"../namespaces/identity.js\";\nimport { validateArchiveRelativePath } from \"../transfer/fs-utils.js\";\nimport type { OfflineSyncFileState } from \"../offline-sync.js\";\nimport { CONVERGE_CONFLICT_POLICIES, DEFAULT_CONVERGE_CONFLICT_POLICY } from \"../converge-config.js\";\nimport type { ConvergeConflictPolicy } from \"../types.js\";\nexport type ReconcileConflictPolicy = ConvergeConflictPolicy;\n\n/**\n * Bootstrap reconciliation planner for two peer daemons whose corpora have\n * already diverged (issue #2150).\n *\n * The offline-sync protocol assumes a satellite that shares a common base with\n * one daemon: every path it does not know about is a pull, and a conflict is\n * rare. Two long-lived daemons are the opposite case — each side holds months\n * of history the other never saw, both sides are authoritative, and there is\n * NO common base on the first run. That is a different decision problem, so it\n * gets its own planner rather than another mode flag inside `applyOfflineSync*`.\n *\n * This module is deliberately pure: it takes two file censuses and returns what\n * to do. No I/O, no transport, no clock. Everything that makes reconciliation\n * risky — which side wins, what counts as converged, what is reported — is\n * decided here where it can be exhaustively tested, and the transport layer is\n * left to carry out an already-settled plan.\n */\n\n/** Which way a path must move for the two corpora to agree. */\nexport type ReconcileAction = \"pull\" | \"push\" | \"identical\" | \"conflict\" | \"suppress\";\n\n/**\n * What the planner decided for a conflicting path.\n * `supersede-link` records that both revisions need durable preservation when\n * timestamps cannot safely select a winner. Apply must stop until transport\n * can assign distinct durable identities to both revisions.\n */\nexport type ReconcileResolution = \"local-wins\" | \"peer-wins\" | \"supersede-link\" | \"unresolved\";\n\nexport interface ReconcileSemanticFileState {\n path: string;\n sha256: string;\n}\n\nexport interface ReconcileSemanticAgreement {\n local: ReconcileSemanticFileState;\n peer: ReconcileSemanticFileState;\n}\n\nexport type ReconcileSemanticChange = \"unchanged\" | \"local_changed\" | \"peer_changed\" | \"both_modified\";\n\nexport interface ReconcilePlanEntry {\n path: string;\n namespace: string;\n action: ReconcileAction;\n /** Stable machine-readable cause, safe to assert on and to aggregate. */\n reason: ReconcileReason;\n localSha256?: string;\n peerSha256?: string;\n /** Present only when a prior converged run left a cursor covering this path. */\n baseSha256?: string;\n /** Set only when `action` is `conflict`. */\n resolution?: ReconcileResolution;\n /** Original revision time when conflict resolution propagates a deletion. */\n deletionMtimeMs?: number;\n /**\n * Which side holds the retracted revision. Set only when `action` is\n * `suppress`: with different digests on each side and only one retracted,\n * the entry would otherwise be identical either way and transport could\n * delete the live copy instead of the retracted one.\n */\n suppressSide?: \"local\" | \"peer\" | \"both\";\n /**\n * Real per-side identities for a cross-path semantic agreement. Synthetic\n * rows omit the top-level side digests because `path` cannot name both files.\n */\n semanticAgreement?: ReconcileSemanticAgreement;\n /** Each side's current digest compared with its own prior semantic digest. */\n semanticChange?: ReconcileSemanticChange;\n}\n\nexport type ReconcileReason =\n | \"peer_only\"\n | \"local_only\"\n /** Cursor showed only that side moved since agreement; both still hold the path. */\n | \"peer_changed\"\n | \"local_changed\"\n | \"same_content\"\n | \"semantic_duplicate\"\n | \"both_modified\"\n | \"peer_deleted\"\n | \"local_deleted\"\n /** Peer deleted it while this side edited it — the offline-sync delete/modify pair. */\n | \"local_modified_peer_deleted\"\n | \"local_deleted_peer_modified\"\n | \"tombstoned\";\n\nexport interface ReconcileNamespaceReport {\n namespace: string;\n pull: number;\n push: number;\n identical: number;\n conflict: number;\n /** Local retractions the peer must be told about before the pair agrees. */\n suppress: number;\n /**\n * Conflicts still needing an operator: those the policy declined to settle,\n * plus supersede links whose direction could not be determined.\n */\n unresolved: number;\n}\n\nexport interface ReconcilePlan {\n entries: ReconcilePlanEntry[];\n byNamespace: ReconcileNamespaceReport[];\n /**\n * True when the two corpora already agree — every shared path matches and\n * neither side holds a path the other lacks.\n *\n * This is the idempotency contract from #2150: running reconciliation against\n * an already-converged peer must be a no-op, and a caller can skip the whole\n * transfer phase on this flag alone.\n */\n converged: boolean;\n}\n\n/** Minimal shape the planner needs; `OfflineSyncFileState` satisfies it. */\nexport type ReconcileFileState = Pick<OfflineSyncFileState, \"path\" | \"sha256\"> &\n Partial<Pick<OfflineSyncFileState, \"mtimeMs\" | \"bytes\">>;\n\nexport interface ReconcileNamespaceInput {\n namespace: string;\n local: Iterable<ReconcileFileState>;\n peer: Iterable<ReconcileFileState>;\n /**\n * File states agreed at the end of the last converged run with THIS peer.\n * Absent on a bootstrap merge, which is why a path missing from one side is\n * read as \"never seen\" rather than \"deleted\".\n */\n base?: Iterable<ReconcileFileState>;\n /**\n * Revision timestamps for paths deleted locally since the base cursor.\n * A deletion is a revision and must carry a comparable time for\n * `newest-wins`; absence alone has no timestamp.\n */\n localDeletionMtimeMs?: ReadonlyMap<string, number>;\n /** Revision timestamps for paths deleted by the peer since the base cursor. */\n peerDeletionMtimeMs?: ReadonlyMap<string, number>;\n /**\n * Digests of FILES this side has retracted, in the same form as\n * `ReconcileFileState.sha256` — a hash of the serialized file.\n *\n * Deliberately NOT `TombstoneEntry.contentHash`, which hashes the canonical\n * raw fact text and therefore never equals a file digest (§13: one content\n * form, everywhere). Mapping retracted fact hashes onto the file digests that\n * carry them is the caller's job, because only the caller can read its own\n * corpus; handing this the wrong form would silently plan `pull` and\n * resurrect every retracted fact, so the parameter name states the form.\n */\n tombstonedFileSha256?: Iterable<string>;\n /**\n * Digests the PEER has retracted, same form.\n *\n * Without this a bootstrap merge cannot tell \"the peer never had it\" from\n * \"the peer deliberately retracted it\": the peer census simply omits both,\n * so a file we still hold is planned `push` and the peer's retraction is\n * undone. Reconciliation is symmetric, so retraction has to be too.\n *\n * SCOPE: these sets decide what happens to files that still EXIST on one\n * side. Sharing the retraction records themselves is not modelled here -\n * tombstones are corpus files (`state/tombstones.jsonl`), so they reconcile\n * as ordinary paths through this same plan. A digest both censuses have\n * already dropped therefore produces no entry, by design: there is no file\n * left to act on, and synthesizing a path-less entry would hand transport\n * something it cannot apply.\n */\n peerTombstonedFileSha256?: Iterable<string>;\n}\n\nexport interface ReconcileOptions {\n conflictPolicy?: ConvergeConflictPolicy;\n /**\n * Platform whose filesystem constraints the portability gates enforce\n * (trailing dot/space, Windows-invalid characters, reserved device names).\n * Defaults to the local platform: a POSIX planner may reason about\n * POSIX-origin paths that carry characters Windows cannot store, because\n * that plan will never be applied on a Windows participant. Injectable so\n * the Windows branches stay testable from any platform.\n */\n localPlatform?: NodeJS.Platform;\n /**\n * Platform of the PEER participant when known (advertised via the\n * offline-sync capabilities route). Push entries materialize on the peer,\n * so Windows path hazards apply when EITHER participant is win32.\n */\n peerPlatform?: string;\n}\n\n/**\n * A census the planner refuses to reason about.\n *\n * Dropping a malformed or contradictory record would let the planner return\n * `converged: true` for a corpus it could not actually read, and transport is\n * invited to skip everything on that flag — so bad input fails loudly instead\n * (§1/§39).\n */\nexport class ReconcilePlanInputError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ReconcilePlanInputError\";\n }\n}\n\n/** Shared with offline-sync's census validation (issue #2477): one acceptance set. */\n\n/**\n * Validate a census record's identity fields.\n *\n * The digest matters as much as the path: two records that both omit `sha256`\n * compare `undefined === undefined` and plan as `identical`, converging a\n * corpus the planner never actually read.\n */\nfunction assertCensusRecord(\n file: ReconcileFileState | undefined,\n side: string,\n namespace: string,\n platforms: readonly (string | undefined)[]\n): ReconcileFileState {\n const path = file?.path;\n if (typeof path !== \"string\" || path.length === 0) {\n throw new ReconcilePlanInputError(\n `reconcile: ${side} census for namespace ${namespace} contains a record with no path`\n );\n }\n // Same boundary offline-sync applies to this field: a peer census is\n // untrusted input, and an absolute or traversal path would otherwise become\n // a transfer instruction pointing outside the corpus root.\n try {\n validateArchiveRelativePath(path, `reconcile: ${side} census for namespace ${namespace}`);\n } catch (err) {\n throw new ReconcilePlanInputError(err instanceof Error ? err.message : String(err));\n }\n assertPortablePathSegments(path, side, namespace, platforms);\n return {\n ...file,\n path,\n sha256: assertDigest(file?.sha256, `${side} census for namespace ${namespace} entry ${path}`),\n ...(file?.mtimeMs === undefined\n ? {}\n : { mtimeMs: assertMtimeMs(file.mtimeMs, `${side} census for namespace ${namespace} entry ${path}`) }),\n };\n}\n\n/**\n * `newest-wins` decides which corpus keeps its history from this number, so a\n * NaN, an Infinity or a value past the Date range must not pick the winner.\n *\n * Fractional values ARE valid: `fs.stat()` reports sub-millisecond mtimes on\n * common filesystems and offline-sync forwards them unrounded, so this matches\n * its `assertOfflineSyncMtimeMs` — non-negative finite within Date range — and\n * deliberately does not require an integer.\n */\nfunction assertMtimeMs(value: unknown, context: string): number {\n if (!isCensusMtimeMs(value)) {\n throw new ReconcilePlanInputError(\n `reconcile: ${context} has an out-of-range mtimeMs; expected a finite value between 0 and ${CENSUS_MAX_MTIME_MS}`\n );\n }\n return value;\n}\n\n/**\n * Digests are canonicalized to lowercase, exactly as offline-sync's\n * `assertSha256` does. Keeping the caller's spelling would make two forms of\n * one digest compare unequal, so identical files would plan `both_modified`\n * and tombstone lookups would silently miss.\n */\nfunction assertDigest(value: unknown, context: string): string {\n if (!isSha256Hex(value)) {\n throw new ReconcilePlanInputError(`reconcile: ${context} must carry a 64-character sha256 hex digest`);\n }\n return value.toLowerCase();\n}\n\nfunction isPlainObject(value: unknown): boolean {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return false;\n const proto: unknown = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nfunction assertNamespace(namespace: unknown): string {\n if (typeof namespace !== \"string\" || namespace.length === 0) {\n throw new ReconcilePlanInputError(\"reconcile: every namespace input needs a non-empty namespace\");\n }\n // `team` and ` team ` are one namespace to the rest of core, so accepting\n // both here would slip two inputs past the duplicate check and let them plan\n // contradictory actions for the same path. Rejected rather than silently\n // rewritten, so the namespace on every entry is the caller's own string.\n if (LONE_SURROGATE.test(namespace)) {\n // `namespaceIdentityToken()` encodes through TextEncoder, so a lone\n // surrogate and a literal U+FFFD collapse to ONE storage identity while\n // comparing as two here - slipping both past the duplicate-namespace guard.\n throw new ReconcilePlanInputError(\n \"reconcile: namespace contains an unpaired surrogate; it would collide with another namespace on disk\"\n );\n }\n if (normalizeNamespaceIdentity(namespace) !== namespace) {\n throw new ReconcilePlanInputError(\n `reconcile: namespace ${JSON.stringify(namespace)} is not canonical; pass ${JSON.stringify(normalizeNamespaceIdentity(namespace))}`\n );\n }\n return namespace;\n}\n\nfunction assertIterable(value: unknown, side: string, namespace: string): Iterable<ReconcileFileState> {\n if (\n value === null ||\n typeof value !== \"object\" ||\n typeof (value as Iterable<ReconcileFileState>)[Symbol.iterator] !== \"function\"\n ) {\n throw new ReconcilePlanInputError(`reconcile: ${side} census for namespace ${namespace} must be iterable`);\n }\n return value as Iterable<ReconcileFileState>;\n}\n\n/**\n * Two paths that a participant's filesystem resolves to ONE file must not draw\n * separate push/pull work, or application order decides which revision\n * survives. Remnic is explicitly multi-platform, so all three aliasing rules\n * are folded together and a collision is rejected rather than raced:\n * case (macOS, Windows), Unicode normalization (macOS stores decomposed and\n * compares canonically), and Win32 trailing dots/spaces, which the Windows API\n * strips before touching disk.\n */\n// eslint-disable-next-line no-control-regex -- control characters are exactly what this rejects\nconst WIN32_INVALID_CHARS = /[<>:\"|?*\\u0000-\\u001f]/;\n// Windows treats the superscripts as their digits in COM/LPT device names.\nconst LONE_SURROGATE = /[\\ud800-\\udbff](?![\\udc00-\\udfff])|(?<![\\ud800-\\udbff])[\\udc00-\\udfff]/;\nconst WIN32_RESERVED_NAMES = /^(con|prn|aux|nul|(com|lpt)[1-9\\u00b9\\u00b2\\u00b3])$/i;\n\nfunction assertPortablePathSegments(\n path: string,\n side: string,\n namespace: string,\n platforms: readonly (string | undefined)[]\n): void {\n // Windows-only hazards (trailing dot/space stripping, invalid characters\n // like `:`, reserved device names) only constrain a plan whose LOCAL\n // participant would materialize those paths on Windows. POSIX-origin\n // corpora legitimately contain `:` (e.g. sqlite sidecar names), so the\n // gates are skipped for non-win32 planners. The lone-surrogate check is\n // UNCONDITIONAL: Node mangles unpaired surrogates identically everywhere,\n // which corrupts cross-platform path comparison itself.\n const isWindows = platforms.some((candidate) => candidate === \"win32\");\n for (const segment of path.split(\"/\")) {\n if (segment.length === 0) continue;\n if (isWindows && (segment.endsWith(\".\") || segment.endsWith(\" \"))) {\n throw new ReconcilePlanInputError(\n `reconcile: ${side} census for namespace ${namespace} path ${path} has a segment ending in a dot or space; ` +\n \"Windows strips those and would alias it onto another file\"\n );\n }\n // `:` opens an alternate data stream, the rest cannot be created at all,\n // and a reserved device name resolves to hardware. A plan containing any of\n // them cannot be applied on a Windows participant.\n if (LONE_SURROGATE.test(segment)) {\n // Node encodes an unpaired surrogate as U+FFFD, so this path and a\n // literal U+FFFD path are one file on disk while comparing as distinct.\n throw new ReconcilePlanInputError(\n `reconcile: ${side} census for namespace ${namespace} path ${path} contains an unpaired surrogate`\n );\n }\n if (isWindows && WIN32_INVALID_CHARS.test(segment)) {\n throw new ReconcilePlanInputError(\n `reconcile: ${side} census for namespace ${namespace} path ${path} contains a character Windows cannot store`\n );\n }\n if (isWindows && WIN32_RESERVED_NAMES.test(segment.split(\".\")[0] ?? \"\")) {\n throw new ReconcilePlanInputError(\n `reconcile: ${side} census for namespace ${namespace} path ${path} uses a reserved Windows device name`\n );\n }\n }\n}\n\nfunction assertNoPathAlias(seen: Map<string, string>, path: string, namespace: string): void {\n // NFC first: macOS stores decomposed names and compares canonically, so\n // `é` (U+00E9) and `é` (e + U+0301) are ONE file there. Then a FULL caseless\n // fold - upper-then-lower, which collapses forms a bare toLowerCase() keeps\n // apart, such as final sigma `ς` against `σ`. Lowercasing alone would leave\n // those distinct and the planner would emit both a push and a pull.\n // `ß` upper-folds to `ss` while `ẞ` folds to `ß`, so one more pass equalizes\n // the pair that a single upper-then-lower still leaves apart.\n const folded = path\n .normalize(\"NFC\")\n .toUpperCase()\n .toLowerCase()\n .replace(/\\u00df/g, \"ss\");\n const existing = seen.get(folded);\n if (existing !== undefined && existing !== path) {\n throw new ReconcilePlanInputError(\n `reconcile: namespace ${namespace} has aliasing paths (${existing}, ${path}); ` +\n \"they resolve to one file on a case-insensitive or Unicode-normalizing peer\"\n );\n }\n seen.set(folded, path);\n}\n\n/**\n * Duplicate paths are accepted only when they agree. Two digests for one path\n * make the plan depend on which record arrived last, which would break the\n * byte-stable ordering the convergence report relies on.\n */\nfunction rejectConflictingDuplicate(\n existing: { sha256: string; mtimeMs?: number } | undefined,\n incoming: { sha256: string; mtimeMs?: number },\n path: string,\n side: string,\n namespace: string\n): boolean {\n if (!existing) return false;\n if (existing.sha256 !== incoming.sha256) {\n throw new ReconcilePlanInputError(\n `reconcile: ${side} census for namespace ${namespace} lists ${path} twice with different digests`\n );\n }\n // Same bytes but a different mtime is still ambiguous: `newest-wins` reads\n // that timestamp, so accepting the first arrival would let input order decide\n // the winner.\n if (existing.mtimeMs !== incoming.mtimeMs) {\n throw new ReconcilePlanInputError(\n `reconcile: ${side} census for namespace ${namespace} lists ${path} twice with different mtimeMs`\n );\n }\n return true;\n}\n\nfunction indexByPath(\n files: Iterable<ReconcileFileState>,\n side: string,\n namespace: string,\n platforms: readonly (string | undefined)[]\n): Map<string, ReconcileFileState> {\n const index = new Map<string, ReconcileFileState>();\n for (const raw of files) {\n const file = assertCensusRecord(raw, side, namespace, platforms);\n if (rejectConflictingDuplicate(index.get(file.path), file, file.path, side, namespace)) continue;\n index.set(file.path, file);\n }\n return index;\n}\n\n/**\n * A bare string satisfies `Iterable<string>`, and `new Set(\"abc…\")` would split\n * it into 64 one-character members — every membership test then misses and each\n * retracted file is planned as `pull` and resurrected. Reject the scalar and\n * canonicalize every member.\n */\nfunction parseTombstonedDigests(\n value: Iterable<string> | undefined,\n namespace: string,\n field = \"tombstonedFileSha256\"\n): Set<string> {\n if (value === undefined) return new Set();\n if (typeof value === \"string\") {\n throw new ReconcilePlanInputError(\n `reconcile: ${field} for namespace ${namespace} must be a collection of digests, not a single string`\n );\n }\n if (value === null || typeof value !== \"object\" || typeof value[Symbol.iterator] !== \"function\") {\n // Otherwise the for...of below throws a raw TypeError and a caller handling\n // ReconcilePlanInputError cannot tell a bad request from a planner bug.\n throw new ReconcilePlanInputError(\n `reconcile: ${field} for namespace ${namespace} must be an iterable collection of digests`\n );\n }\n const digests = new Set<string>();\n for (const entry of value) {\n digests.add(assertDigest(entry, `${field} for namespace ${namespace}`));\n }\n return digests;\n}\n\n/**\n * Validate a census while keeping ONLY path -> digest.\n *\n * The base cursor is read for digests alone, so indexing full records and\n * compacting afterwards would hold a corpus-sized record map and its copy at\n * once - the peak this avoids.\n */\nfunction indexDigestsByPath(\n files: Iterable<ReconcileFileState>,\n side: string,\n namespace: string,\n platforms: readonly (string | undefined)[]\n): Map<string, string> {\n const index = new Map<string, string>();\n for (const raw of files) {\n const file = assertCensusRecord(raw, side, namespace, platforms);\n const existing = index.get(file.path);\n // One map, not a parallel `seen`: the base's own mtimeMs is never a\n // decision input (only the local and peer timestamps order a conflict), so\n // a duplicate that agrees on the digest is unambiguous here regardless of\n // its timestamp, and the digest alone is enough to detect a real clash.\n if (existing !== undefined) {\n if (existing !== file.sha256) {\n throw new ReconcilePlanInputError(\n `reconcile: ${side} census for namespace ${namespace} lists ${file.path} twice with different digests`\n );\n }\n continue;\n }\n index.set(file.path, file.sha256);\n }\n return index;\n}\n\nfunction assertConflictPolicy(value: ConvergeConflictPolicy | undefined): ConvergeConflictPolicy {\n if (value === undefined) return DEFAULT_CONVERGE_CONFLICT_POLICY;\n if (!CONVERGE_CONFLICT_POLICIES.includes(value)) {\n throw new ReconcilePlanInputError(\n `reconcile: unknown conflictPolicy ${JSON.stringify(value)}; expected one of ${CONVERGE_CONFLICT_POLICIES.join(\", \")}`\n );\n }\n return value;\n}\n\n/**\n * Total ordering for plan entries (§12): namespace, then path. Both are unique\n * per entry, so equal keys are impossible and the comparator never has to\n * return 0 for distinct rows — the output is byte-identical across runs, which\n * is what makes a convergence report diffable. Cursor and manifest sort with\n * this same export; a local copy on either side is how ordering drifts (§2477).\n */\nexport function compareReconcilePlanEntries(a: ReconcilePlanEntry, b: ReconcilePlanEntry): number {\n if (a.namespace !== b.namespace) return a.namespace < b.namespace ? -1 : 1;\n if (a.path !== b.path) return a.path < b.path ? -1 : 1;\n return 0;\n}\n\n/**\n * Identity of a semantic-duplicate pair: the ordered (local, peer) path pair.\n * Cursor derivation and manifest collapse must key prior agreements with this\n * same export or a stored cursor stops matching the plan that wrote it.\n */\nexport function semanticAgreementKey(agreement: ReconcileSemanticAgreement): string {\n return `${agreement.local.path}\\0${agreement.peer.path}`;\n}\n\nfunction resolveConflict(\n policy: ConvergeConflictPolicy,\n localMtimeMs: number | undefined,\n peerMtimeMs: number | undefined,\n missingTimestampResolution: ReconcileResolution\n): ReconcileResolution {\n if (policy !== \"newest-wins\") return \"unresolved\";\n if (localMtimeMs === undefined || peerMtimeMs === undefined || localMtimeMs === peerMtimeMs) {\n return missingTimestampResolution;\n }\n return localMtimeMs > peerMtimeMs ? \"local-wins\" : \"peer-wins\";\n}\n\nfunction parseDeletionMtimes(\n value: ReadonlyMap<string, number> | undefined,\n side: string,\n namespace: string,\n platforms: readonly (string | undefined)[]\n): ReadonlyMap<string, number> {\n if (value === undefined) return new Map();\n if (!(value instanceof Map)) {\n throw new ReconcilePlanInputError(`reconcile: ${side} deletion mtimes for namespace ${namespace} must be a Map`);\n }\n const parsed = new Map<string, number>();\n for (const [path, mtimeMs] of value) {\n try {\n validateArchiveRelativePath(path, `reconcile: ${side} deletion mtimes for namespace ${namespace}`);\n } catch (err) {\n throw new ReconcilePlanInputError(err instanceof Error ? err.message : String(err));\n }\n assertPortablePathSegments(path, side, namespace, platforms);\n parsed.set(path, assertMtimeMs(mtimeMs, `${side} deletion for namespace ${namespace} entry ${path}`));\n }\n return parsed;\n}\n\n/**\n * Plan one namespace. Exposed for callers that stream namespaces one at a time.\n *\n * Residency is one peer index + a set of local paths + the entry list. The\n * local census is consumed as a stream and never materialized, so a 100k-file\n * corpus does not hold two full censuses at once — but this is NOT constant\n * memory, and a caller holding its own census arrays adds to that.\n */\nexport function planNamespaceReconciliation(\n input: ReconcileNamespaceInput,\n options: ReconcileOptions = {}\n): ReconcilePlanEntry[] {\n if (!isPlainObject(input)) {\n throw new ReconcilePlanInputError(\"reconcile: namespace input must be a plain object\");\n }\n if (!isPlainObject(options)) {\n // A Date, Map or RegExp passes a bare typeof check, exposes no\n // `conflictPolicy`, and would silently take the default policy - hiding a\n // malformed request behind `manual`.\n throw new ReconcilePlanInputError(\"reconcile: options must be a plain object\");\n }\n const namespace = assertNamespace(input.namespace);\n const policy = assertConflictPolicy(options.conflictPolicy);\n const localCensus = assertIterable(input.local, \"local\", namespace);\n const caseFold = new Map<string, string>();\n // Index the peer census only, then stream the local one against it, removing\n // each match as it is consumed. Peak residency is one index plus the entry\n // list rather than two full censuses (round 2, codex P2).\n const effectivePlatforms = [options.localPlatform ?? process.platform, options.peerPlatform];\n const peer = indexByPath(assertIterable(input.peer, \"peer\", namespace), \"peer\", namespace, effectivePlatforms);\n // Only `base.sha256` is ever read, so the base is compacted to path -> digest\n // instead of a second full record index (round 7, codex P2).\n // Only an ABSENT base means bootstrap. A null/invalid cursor silently read as\n // \"no prior agreement\" would turn a peer-side deletion into a push and\n // resurrect it.\n const base =\n input.base === undefined\n ? null\n : indexDigestsByPath(assertIterable(input.base, \"base\", namespace), \"base\", namespace, effectivePlatforms);\n const tombstoned = parseTombstonedDigests(input.tombstonedFileSha256, namespace);\n const peerTombstoned = parseTombstonedDigests(input.peerTombstonedFileSha256, namespace, \"peerTombstonedFileSha256\");\n const localDeletionMtimeMs = parseDeletionMtimes(input.localDeletionMtimeMs, \"local\", namespace, effectivePlatforms);\n const peerDeletionMtimeMs = parseDeletionMtimes(input.peerDeletionMtimeMs, \"peer\", namespace, effectivePlatforms);\n const entries: ReconcilePlanEntry[] = [];\n\n // Path -> digest only, never the file objects: enough to make the stream\n // idempotent and to catch contradictory duplicates without materializing the\n // second census.\n // Base paths participate in the collision check: a base `Facts/A.md` against\n // a local `facts/a.md` is the same delete/change ambiguity on a\n // case-insensitive participant.\n if (base) for (const basePath of base.keys()) assertNoPathAlias(caseFold, basePath, namespace);\n // Path -> decision-relevant fields only, never the whole record: enough to\n // make the stream idempotent and to catch contradictory duplicates without\n // materializing the second census.\n const seenLocal = new Map<string, { sha256: string; mtimeMs?: number }>();\n for (const rawLocal of localCensus) {\n const localFile = assertCensusRecord(rawLocal, \"local\", namespace, effectivePlatforms);\n const path = localFile.path;\n assertNoPathAlias(caseFold, path, namespace);\n const seen = seenLocal.get(path);\n if (seen !== undefined) {\n // Same rule the indexed censuses get: mtimeMs is decision-relevant under\n // `newest-wins`, so a duplicate that disagrees on it is ambiguous too.\n if (rejectConflictingDuplicate(seen, localFile, path, \"local\", namespace)) continue;\n }\n seenLocal.set(path, { sha256: localFile.sha256, mtimeMs: localFile.mtimeMs });\n const peerFile = peer.get(path);\n // Consumed: whatever remains in the index afterwards is peer-only.\n peer.delete(path);\n const baseSha256 = base?.get(path);\n // Retraction outranks every other decision for this path, on EITHER side.\n // Checked before hash comparison and conflict resolution: a retracted peer\n // revision reaching the conflict ladder can win under `newest-wins`, and a\n // retracted LOCAL revision would otherwise be pushed - which is also how a\n // suppression undoes itself on the next run, since the local copy survives\n // the peer-side delete (round 4).\n // Either side's retraction removes the copy that carries the digest, so a\n // peer retraction of something we still hold suppresses OUR copy rather\n // than pushing it back.\n const localRetracted = tombstoned.has(localFile.sha256) || peerTombstoned.has(localFile.sha256);\n const peerRetracted =\n peerFile !== undefined && (tombstoned.has(peerFile.sha256) || peerTombstoned.has(peerFile.sha256));\n if (localRetracted || peerRetracted) {\n entries.push({\n path,\n namespace,\n action: \"suppress\",\n reason: \"tombstoned\",\n localSha256: localFile.sha256,\n ...(peerFile ? { peerSha256: peerFile.sha256 } : {}),\n ...(baseSha256 === undefined ? {} : { baseSha256 }),\n suppressSide: localRetracted && peerRetracted ? \"both\" : localRetracted ? \"local\" : \"peer\",\n });\n continue;\n }\n if (!peerFile) {\n // Base PRESENCE is what proves a deletion, not equality with whatever the\n // surviving side now holds. If we also edited since the base, this is\n // delete-versus-modify: still a conflict, and pushing it would resurrect\n // a deliberate deletion. Without a base the peer simply never saw the\n // path, and a bootstrap merge must push — both sides hold unique data.\n if (baseSha256 !== undefined) {\n const peerDeletionMtime = peerDeletionMtimeMs.get(path);\n const resolution =\n baseSha256 === localFile.sha256\n ? \"unresolved\"\n : resolveConflict(policy, localFile.mtimeMs, peerDeletionMtime, \"unresolved\");\n entries.push({\n path,\n namespace,\n action: \"conflict\",\n reason: baseSha256 === localFile.sha256 ? \"peer_deleted\" : \"local_modified_peer_deleted\",\n localSha256: localFile.sha256,\n baseSha256,\n resolution,\n ...(resolution === \"peer-wins\" && peerDeletionMtime !== undefined\n ? { deletionMtimeMs: peerDeletionMtime }\n : {}),\n });\n continue;\n }\n entries.push({\n path,\n namespace,\n action: \"push\",\n reason: \"local_only\",\n localSha256: localFile.sha256,\n });\n continue;\n }\n if (peerFile.sha256 === localFile.sha256) {\n entries.push({\n path,\n namespace,\n action: \"identical\",\n reason: \"same_content\",\n localSha256: localFile.sha256,\n peerSha256: peerFile.sha256,\n ...(baseSha256 === undefined ? {} : { baseSha256 }),\n });\n continue;\n }\n // A base that matches one side turns a \"conflict\" into an ordinary\n // one-sided change: that side is the only one that moved since agreement.\n if (baseSha256 !== undefined && baseSha256 === localFile.sha256) {\n entries.push({\n path,\n namespace,\n action: \"pull\",\n reason: \"peer_changed\",\n localSha256: localFile.sha256,\n peerSha256: peerFile.sha256,\n baseSha256,\n });\n continue;\n }\n if (baseSha256 !== undefined && baseSha256 === peerFile.sha256) {\n entries.push({\n path,\n namespace,\n action: \"push\",\n reason: \"local_changed\",\n localSha256: localFile.sha256,\n peerSha256: peerFile.sha256,\n baseSha256,\n });\n continue;\n }\n const resolution = resolveConflict(policy, localFile.mtimeMs, peerFile.mtimeMs, \"supersede-link\");\n entries.push({\n path,\n namespace,\n action: \"conflict\",\n reason: \"both_modified\",\n localSha256: localFile.sha256,\n peerSha256: peerFile.sha256,\n ...(baseSha256 === undefined ? {} : { baseSha256 }),\n resolution,\n });\n }\n\n for (const [path, peerFile] of peer) {\n assertNoPathAlias(caseFold, path, namespace);\n const baseSha256 = base?.get(path);\n if (tombstoned.has(peerFile.sha256) || peerTombstoned.has(peerFile.sha256)) {\n // Retracted here on purpose, and the peer still serves it. Pulling it\n // back would undo the retraction; calling it `identical` would be worse,\n // because a converged plan lets transport skip everything and the peer\n // keeps serving the retracted fact forever. It is work: propagate the\n // tombstone.\n entries.push({\n path,\n namespace,\n action: \"suppress\",\n reason: \"tombstoned\",\n peerSha256: peerFile.sha256,\n ...(baseSha256 === undefined ? {} : { baseSha256 }),\n suppressSide: \"peer\",\n });\n continue;\n }\n if (baseSha256 !== undefined) {\n const localDeletionMtime = localDeletionMtimeMs.get(path);\n const resolution =\n baseSha256 === peerFile.sha256\n ? \"unresolved\"\n : resolveConflict(policy, localDeletionMtime, peerFile.mtimeMs, \"unresolved\");\n entries.push({\n path,\n namespace,\n action: \"conflict\",\n reason: baseSha256 === peerFile.sha256 ? \"local_deleted\" : \"local_deleted_peer_modified\",\n peerSha256: peerFile.sha256,\n baseSha256,\n resolution,\n ...(resolution === \"local-wins\" && localDeletionMtime !== undefined\n ? { deletionMtimeMs: localDeletionMtime }\n : {}),\n });\n continue;\n }\n entries.push({\n path,\n namespace,\n action: \"pull\",\n reason: \"peer_only\",\n peerSha256: peerFile.sha256,\n });\n }\n\n return entries.sort(compareReconcilePlanEntries);\n}\n\n/** Aggregate entries into the per-namespace convergence report (#2150). */\nexport function summarizeReconcilePlan(entries: readonly ReconcilePlanEntry[]): ReconcileNamespaceReport[] {\n const byNamespace = new Map<string, ReconcileNamespaceReport>();\n for (const entry of entries) {\n let report = byNamespace.get(entry.namespace);\n if (!report) {\n report = { namespace: entry.namespace, pull: 0, push: 0, identical: 0, conflict: 0, suppress: 0, unresolved: 0 };\n byNamespace.set(entry.namespace, report);\n }\n report[entry.action] += 1;\n const needsOperator = entry.resolution === \"unresolved\" || entry.resolution === \"supersede-link\";\n if (entry.action === \"conflict\" && needsOperator) report.unresolved += 1;\n }\n return [...byNamespace.values()].sort((a, b) =>\n a.namespace === b.namespace ? 0 : a.namespace < b.namespace ? -1 : 1\n );\n}\n\n/**\n * Plan a full reconciliation across namespaces.\n *\n * `converged` is an affirmative claim that nothing needs to move, so it is\n * derived from the entries rather than tracked alongside them: any action other\n * than `identical` disproves it.\n */\nexport function planReconciliation(\n namespaces: readonly ReconcileNamespaceInput[],\n options: ReconcileOptions = {}\n): ReconcilePlan {\n if (!Array.isArray(namespaces)) {\n throw new ReconcilePlanInputError(\"reconcile: planReconciliation expects an array of namespace inputs\");\n }\n // Validated here too: with an empty array the per-namespace path never runs,\n // and a malformed options envelope would return `converged` instead of\n // raising - the same call failing or succeeding based on list length.\n if (!isPlainObject(options)) {\n throw new ReconcilePlanInputError(\"reconcile: options must be a plain object\");\n }\n assertConflictPolicy(options.conflictPolicy);\n const entries: ReconcilePlanEntry[] = [];\n // Two inputs for one namespace are planned independently, so the same\n // (namespace, path) can draw contradictory actions - and because those\n // entries also sort equal, batch order would decide which revision survives.\n const seenNamespaces = new Set<string>();\n for (const namespace of namespaces) {\n const name = assertNamespace(namespace?.namespace);\n if (seenNamespaces.has(name)) {\n throw new ReconcilePlanInputError(\n `reconcile: namespace ${name} appears twice; merge its censuses before planning`\n );\n }\n seenNamespaces.add(name);\n entries.push(...planNamespaceReconciliation(namespace, options));\n }\n entries.sort(compareReconcilePlanEntries);\n return {\n entries,\n byNamespace: summarizeReconcilePlan(entries),\n converged: entries.every((entry) => entry.action === \"identical\"),\n };\n}\n"],"mappings":"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","names":["resolution"]}
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-B7RWBZXW.js";
4
4
  import {
5
5
  resolveCausalTrajectoryStoreDir
6
- } from "./chunk-P6GKRT2H.js";
6
+ } from "./chunk-2Z3DG5CQ.js";
7
7
  import {
8
8
  normalizeRecallTokens
9
9
  } from "./chunk-YCVB7X56.js";
@@ -339,4 +339,4 @@ export {
339
339
  scoreStitchCandidate,
340
340
  stitchCausalChain
341
341
  };
342
- //# sourceMappingURL=chunk-BX6GW4KC.js.map
342
+ //# sourceMappingURL=chunk-JMAG7WZ7.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isRecallDisclosure
3
- } from "./chunk-OYV6RKPM.js";
3
+ } from "./chunk-XOQGUGJL.js";
4
4
  import {
5
5
  estimateTokenCount
6
6
  } from "./chunk-TOTT6S2V.js";
@@ -304,4 +304,4 @@ export {
304
304
  RecallXrayBuilder,
305
305
  summarizeDisclosureTokens
306
306
  };
307
- //# sourceMappingURL=chunk-NF3NMAG7.js.map
307
+ //# sourceMappingURL=chunk-JOYC4RYC.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SupportPassportError,
3
3
  getOperation
4
- } from "./chunk-MSDIETFC.js";
4
+ } from "./chunk-IZZ7Q2RJ.js";
5
5
  import {
6
6
  abortError,
7
7
  isAbortError
@@ -499,4 +499,4 @@ export {
499
499
  buildSupportPassportPublicRequestHandler,
500
500
  composeSupportPassportExternalRequestHandlers
501
501
  };
502
- //# sourceMappingURL=chunk-5JQV4T5Q.js.map
502
+ //# sourceMappingURL=chunk-JZ6EYAVP.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  rebuildMemoryProjection
3
- } from "./chunk-BEXFNGQ3.js";
3
+ } from "./chunk-DK6GMO6D.js";
4
4
 
5
5
  // src/convergence-refresh.ts
6
6
  async function refreshConvergedNamespaces(namespaces, namespaceSearchRouter, getStorage, searchEnabled) {
@@ -32,4 +32,4 @@ async function refreshConvergedNamespaces(namespaces, namespaceSearchRouter, get
32
32
  export {
33
33
  refreshConvergedNamespaces
34
34
  };
35
- //# sourceMappingURL=chunk-QRDSXR3V.js.map
35
+ //# sourceMappingURL=chunk-KA2HZCMG.js.map
@@ -1,12 +1,12 @@
1
- import {
2
- encryptCapsuleFile
3
- } from "./chunk-X7Y7WX73.js";
4
1
  import {
5
2
  CAPSULE_ID_PATTERN,
6
3
  CapsuleBlockSchema,
7
4
  ExportBundleV2Schema,
8
5
  ExportManifestV2Schema
9
6
  } from "./chunk-WEHSQBFR.js";
7
+ import {
8
+ encryptCapsuleFile
9
+ } from "./chunk-X7Y7WX73.js";
10
10
  import {
11
11
  CAPSULE_SCHEMA_VERSION,
12
12
  EXPORT_FORMAT
@@ -261,4 +261,4 @@ export {
261
261
  exportCapsule,
262
262
  isValidCapsuleSince
263
263
  };
264
- //# sourceMappingURL=chunk-7LCGFUMB.js.map
264
+ //# sourceMappingURL=chunk-KQAFEZQX.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-SOBJ6NEY.js";
4
4
  import {
5
5
  summarizeDisclosureTokens
6
- } from "./chunk-NF3NMAG7.js";
6
+ } from "./chunk-JOYC4RYC.js";
7
7
  import {
8
8
  summarizeRetrievedMemoryProvenance
9
9
  } from "./chunk-I4WBNM3M.js";
@@ -606,4 +606,4 @@ export {
606
606
  renderRecallExplain,
607
607
  parseRecallExplainFormat
608
608
  };
609
- //# sourceMappingURL=chunk-ETZ7KKOS.js.map
609
+ //# sourceMappingURL=chunk-KTVSPFCQ.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  buildStandup,
3
3
  parseStandupDate
4
- } from "./chunk-VAMZYOOV.js";
4
+ } from "./chunk-HOUST5UX.js";
5
5
  import {
6
6
  backfillMemoryStorage,
7
7
  runLocationBackfill,
@@ -9,20 +9,20 @@ import {
9
9
  runLocationDay,
10
10
  runLocationStatus,
11
11
  runLocationSync
12
- } from "./chunk-5H2G5X4R.js";
12
+ } from "./chunk-ZJWDWPX6.js";
13
13
  import {
14
14
  externalWikiSearchOperation
15
- } from "./chunk-C25N5HWX.js";
15
+ } from "./chunk-B2AGUKSS.js";
16
16
  import {
17
17
  memoryStoreRequestSchema
18
- } from "./chunk-NHLEFBE2.js";
18
+ } from "./chunk-I4Y6TBD7.js";
19
19
  import {
20
20
  CorrectionContractError,
21
21
  DECISION_SUBCOMMANDS,
22
22
  DELTA_SUBCOMMANDS,
23
23
  defineOperation,
24
24
  isCodegraphToolName
25
- } from "./chunk-MSDIETFC.js";
25
+ } from "./chunk-IZZ7Q2RJ.js";
26
26
  import {
27
27
  serializeMutations,
28
28
  withHeldFileLock
@@ -1909,4 +1909,4 @@ export {
1909
1909
  codegraphIngestTracesOperation,
1910
1910
  REGISTERED_OPERATIONS
1911
1911
  };
1912
- //# sourceMappingURL=chunk-PAWIY5OQ.js.map
1912
+ //# sourceMappingURL=chunk-L74A6NTI.js.map
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  StorageManager
3
- } from "./chunk-VYD63IFH.js";
3
+ } from "./chunk-OGTKQ5MJ.js";
4
4
  import {
5
5
  normalizeEntityName
6
6
  } from "./chunk-YXZG5TVN.js";
7
- import {
8
- extractJsonCandidates
9
- } from "./chunk-RGMVMVMF.js";
10
7
  import {
11
8
  safeReadMemories
12
9
  } from "./chunk-UBCBDJOB.js";
10
+ import {
11
+ extractJsonCandidates
12
+ } from "./chunk-RGMVMVMF.js";
13
13
  import {
14
14
  excludeSupportPassportPrivateMemories
15
15
  } from "./chunk-EEOUMG3J.js";
@@ -957,4 +957,4 @@ export {
957
957
  resolveBriefingSaveDir,
958
958
  briefingFilename
959
959
  };
960
- //# sourceMappingURL=chunk-2XJDAEAM.js.map
960
+ //# sourceMappingURL=chunk-LFK623SF.js.map
@@ -0,0 +1,80 @@
1
+ import {
2
+ lcmSessionKeyForNamespace
3
+ } from "./chunk-QBC33MPY.js";
4
+ import {
5
+ log
6
+ } from "./chunk-3WCASNQZ.js";
7
+
8
+ // src/access-observe-transcript.ts
9
+ import { createHash, randomUUID } from "crypto";
10
+ var OBSERVE_TRANSCRIPT_DEDUPE_MAX_ENTRIES = 8192;
11
+ var OBSERVE_TRANSCRIPT_MIN_CONTENT_CHARS = 10;
12
+ var OBSERVE_TRANSCRIPT_DEDUPE_TTL_MS = 10 * 60 * 1e3;
13
+ function observeTranscriptSessionKey(sessionKey, writeNamespace, config) {
14
+ return lcmSessionKeyForNamespace(writeNamespace, sessionKey, config.defaultNamespace) ?? sessionKey;
15
+ }
16
+ var ObserveTranscriptPersister = class {
17
+ seenFingerprintsAt = /* @__PURE__ */ new Map();
18
+ /** In-flight appends by fingerprint: an overlapping identical observe waits for the first append instead of double-writing. */
19
+ inflightAppends = /* @__PURE__ */ new Map();
20
+ /**
21
+ * Append every eligible message of an observe payload to the per-session
22
+ * transcript store. Best-effort: a failing append logs and does not fail
23
+ * the observe. Returns true when at least one turn was appended.
24
+ */
25
+ async persist(orchestrator, sessionKey, messages, rawSessionKey) {
26
+ let persisted = false;
27
+ const { channelType } = orchestrator.transcript.getTranscriptPath(rawSessionKey ?? sessionKey);
28
+ if (orchestrator.config.transcriptSkipChannelTypes.includes(channelType)) {
29
+ return false;
30
+ }
31
+ for (const message of messages) {
32
+ if (message.content.length < OBSERVE_TRANSCRIPT_MIN_CONTENT_CHARS) continue;
33
+ const fingerprint = createHash("sha256").update(`${sessionKey}\0${message.role}\0${message.content}`).digest("hex");
34
+ for (let attempt = 0; attempt < 2; attempt++) {
35
+ const seenAt = this.seenFingerprintsAt.get(fingerprint);
36
+ if (seenAt !== void 0 && Date.now() - seenAt < OBSERVE_TRANSCRIPT_DEDUPE_TTL_MS) {
37
+ break;
38
+ }
39
+ const inflight = this.inflightAppends.get(fingerprint);
40
+ if (inflight) {
41
+ await inflight;
42
+ continue;
43
+ }
44
+ const entry = {
45
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
46
+ role: message.role,
47
+ content: message.content,
48
+ sessionKey,
49
+ turnId: randomUUID()
50
+ };
51
+ const appendPromise = orchestrator.transcript.append(entry).then(() => {
52
+ this.remember(fingerprint);
53
+ persisted = true;
54
+ }).catch((err) => {
55
+ log.error(`access-observe transcript append failed: ${err}`);
56
+ }).finally(() => {
57
+ this.inflightAppends.delete(fingerprint);
58
+ });
59
+ this.inflightAppends.set(fingerprint, appendPromise);
60
+ await appendPromise;
61
+ break;
62
+ }
63
+ }
64
+ return persisted;
65
+ }
66
+ remember(fingerprint) {
67
+ this.seenFingerprintsAt.delete(fingerprint);
68
+ this.seenFingerprintsAt.set(fingerprint, Date.now());
69
+ if (this.seenFingerprintsAt.size > OBSERVE_TRANSCRIPT_DEDUPE_MAX_ENTRIES) {
70
+ const oldest = this.seenFingerprintsAt.keys().next().value;
71
+ if (typeof oldest === "string") this.seenFingerprintsAt.delete(oldest);
72
+ }
73
+ }
74
+ };
75
+
76
+ export {
77
+ observeTranscriptSessionKey,
78
+ ObserveTranscriptPersister
79
+ };
80
+ //# sourceMappingURL=chunk-LVE64P5Y.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/access-observe-transcript.ts"],"sourcesContent":["/**\n * Observe-derived transcript persistence (issue #2783).\n *\n * Delegate-mode gateways POST every turn to `/observe`; without a transcript\n * append in the daemon's observe path the transcript store never grows and\n * the hourly summarizer starves silently while every run reports ok. This\n * module is that append: it mirrors the embedded runtime's `agent_end`\n * handler (src/index.ts) — same `TranscriptManager`, same entry shape, same\n * `transcriptEnabled` presentation gate, same 10-char noise floor.\n *\n * Turns are deduped against a bounded process-lifetime (session, role,\n * content) fingerprint — the daemon-side equivalent of the embedded\n * runtime's `observedInboundContentFingerprints`, extended to both roles\n * because an un-keyed client re-POST always carries the whole turn — so a\n * retry cannot double-write it.\n */\n\nimport { createHash, randomUUID } from \"node:crypto\";\nimport { lcmSessionKeyForNamespace } from \"./coding/coding-namespace.js\";\nimport type { PluginConfig } from \"./types.js\";\nimport { log } from \"./logger.js\";\nimport type { Orchestrator } from \"./orchestrator.js\";\nimport type { TranscriptEntry } from \"./types.js\";\n\nconst OBSERVE_TRANSCRIPT_DEDUPE_MAX_ENTRIES = 8192;\nconst OBSERVE_TRANSCRIPT_MIN_CONTENT_CHARS = 10;\n/**\n * A fingerprint only suppresses re-POSTs inside this window. A client retry\n * lands seconds later; a session LEGITIMATELY repeating the same >10-char\n * turn usually does so minutes or hours later, and that repeat is a real\n * conversation event the transcripts must keep (review: preserve legitimate\n * repeated turns).\n */\nconst OBSERVE_TRANSCRIPT_DEDUPE_TTL_MS = 10 * 60 * 1000;\n\n/**\n * The transcript-side session identity for an observe payload (issue #2783\n * review: namespace scoping). Two authenticated principals can submit the\n * same client-controlled sessionKey while resolving to different effective\n * write namespaces; persisting through the raw key would let one\n * principal's transcript-derived summaries surface under the other's\n * session. Mirror the LCM archive's answer (rule 42 parity): prefix the\n * key with the effective write namespace whenever it diverges from the\n * default store. The summarizer lists sessions from the store itself, so\n * reads self-consistently follow the same prefixed keys.\n */\nexport function observeTranscriptSessionKey(\n sessionKey: string,\n writeNamespace: string,\n config: Pick<PluginConfig, \"defaultNamespace\">\n): string {\n return lcmSessionKeyForNamespace(writeNamespace, sessionKey, config.defaultNamespace) ?? sessionKey;\n}\n\n/** Bounded FIFO of seen fingerprints; insertion order is the eviction order. */\nexport class ObserveTranscriptPersister {\n private readonly seenFingerprintsAt = new Map<string, number>();\n /** In-flight appends by fingerprint: an overlapping identical observe waits for the first append instead of double-writing. */\n private readonly inflightAppends = new Map<string, Promise<void>>();\n\n /**\n * Append every eligible message of an observe payload to the per-session\n * transcript store. Best-effort: a failing append logs and does not fail\n * the observe. Returns true when at least one turn was appended.\n */\n async persist(\n orchestrator: Orchestrator,\n sessionKey: string,\n messages: ReadonlyArray<{ role: string; content: string }>,\n rawSessionKey?: string\n ): Promise<boolean> {\n let persisted = false;\n // TranscriptManager.append silently no-ops for skip-listed channel types\n // (cron by default) — check BEFORE appending so the response's\n // transcriptPersisted stays truthful (review: report skipped appends).\n // The channel identity must derive from the RAW session key: the legacy\n // parser requires the key to start with \"agent:\", so a namespace-prefixed\n // transcript identity would always classify as \"session\" and the skip\n // list would silently not apply to namespaced cron sessions (review r4).\n const { channelType } = orchestrator.transcript.getTranscriptPath(rawSessionKey ?? sessionKey);\n if (orchestrator.config.transcriptSkipChannelTypes.includes(channelType)) {\n return false;\n }\n for (const message of messages) {\n if (message.content.length < OBSERVE_TRANSCRIPT_MIN_CONTENT_CHARS) continue;\n // Fixed-size digest, never the raw content: 8192 retained entries of\n // full turn text is an avoidable heap-exhaustion surface on a daemon\n // that accepts arbitrary observe payloads (review round 2).\n const fingerprint = createHash(\"sha256\")\n .update(`${sessionKey}\\0${message.role}\\0${message.content}`)\n .digest(\"hex\");\n // Two identical observes can overlap before either records its\n // fingerprint; both would then append and the transcript would carry\n // the turn twice. The attempt loop serializes per fingerprint: a caller\n // that finds an in-flight append awaits it and RE-RUNS BOTH checks — on\n // success the completed-set check skips the message; on failure (no\n // fingerprint recorded) exactly ONE waiter proceeds to retry, because\n // the check-then-register sequence has no await between its steps and\n // is therefore atomic on the event loop (review r4).\n for (let attempt = 0; attempt < 2; attempt++) {\n const seenAt = this.seenFingerprintsAt.get(fingerprint);\n if (seenAt !== undefined && Date.now() - seenAt < OBSERVE_TRANSCRIPT_DEDUPE_TTL_MS) {\n break; // duplicate within the retry window — skip the message\n }\n const inflight = this.inflightAppends.get(fingerprint);\n if (inflight) {\n await inflight;\n continue; // re-run both checks with the append's outcome visible\n }\n const entry: TranscriptEntry = {\n timestamp: new Date().toISOString(),\n role: message.role as TranscriptEntry[\"role\"],\n content: message.content,\n sessionKey,\n turnId: randomUUID(),\n };\n const appendPromise = orchestrator.transcript\n .append(entry)\n .then(() => {\n // Remember only after a successful append: a transient failure\n // must not permanently swallow the turn — the client's retry has\n // to be able to re-append it (review round 2).\n this.remember(fingerprint);\n persisted = true;\n })\n .catch((err) => {\n // Same policy as the LCM enqueue in the observe path: transcript\n // persistence must never fail the observe itself.\n log.error(`access-observe transcript append failed: ${err}`);\n })\n .finally(() => {\n this.inflightAppends.delete(fingerprint);\n });\n this.inflightAppends.set(fingerprint, appendPromise);\n await appendPromise;\n break;\n }\n }\n return persisted;\n }\n\n private remember(fingerprint: string): void {\n // Map.set keeps an existing key at its ORIGINAL insertion position, so a\n // TTL-refreshed fingerprint could still be the FIFO-oldest and get\n // evicted immediately — delete first to move it to the end (review r4).\n this.seenFingerprintsAt.delete(fingerprint);\n this.seenFingerprintsAt.set(fingerprint, Date.now());\n if (this.seenFingerprintsAt.size > OBSERVE_TRANSCRIPT_DEDUPE_MAX_ENTRIES) {\n const oldest = this.seenFingerprintsAt.keys().next().value;\n if (typeof oldest === \"string\") this.seenFingerprintsAt.delete(oldest);\n }\n }\n}\n"],"mappings":";;;;;;;;AAiBA,SAAS,YAAY,kBAAkB;AAOvC,IAAM,wCAAwC;AAC9C,IAAM,uCAAuC;AAQ7C,IAAM,mCAAmC,KAAK,KAAK;AAa5C,SAAS,4BACd,YACA,gBACA,QACQ;AACR,SAAO,0BAA0B,gBAAgB,YAAY,OAAO,gBAAgB,KAAK;AAC3F;AAGO,IAAM,6BAAN,MAAiC;AAAA,EACrB,qBAAqB,oBAAI,IAAoB;AAAA;AAAA,EAE7C,kBAAkB,oBAAI,IAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOlE,MAAM,QACJ,cACA,YACA,UACA,eACkB;AAClB,QAAI,YAAY;AAQhB,UAAM,EAAE,YAAY,IAAI,aAAa,WAAW,kBAAkB,iBAAiB,UAAU;AAC7F,QAAI,aAAa,OAAO,2BAA2B,SAAS,WAAW,GAAG;AACxE,aAAO;AAAA,IACT;AACA,eAAW,WAAW,UAAU;AAC9B,UAAI,QAAQ,QAAQ,SAAS,qCAAsC;AAInE,YAAM,cAAc,WAAW,QAAQ,EACpC,OAAO,GAAG,UAAU,KAAK,QAAQ,IAAI,KAAK,QAAQ,OAAO,EAAE,EAC3D,OAAO,KAAK;AASf,eAAS,UAAU,GAAG,UAAU,GAAG,WAAW;AAC5C,cAAM,SAAS,KAAK,mBAAmB,IAAI,WAAW;AACtD,YAAI,WAAW,UAAa,KAAK,IAAI,IAAI,SAAS,kCAAkC;AAClF;AAAA,QACF;AACA,cAAM,WAAW,KAAK,gBAAgB,IAAI,WAAW;AACrD,YAAI,UAAU;AACZ,gBAAM;AACN;AAAA,QACF;AACA,cAAM,QAAyB;AAAA,UAC7B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,UAClC,MAAM,QAAQ;AAAA,UACd,SAAS,QAAQ;AAAA,UACjB;AAAA,UACA,QAAQ,WAAW;AAAA,QACrB;AACA,cAAM,gBAAgB,aAAa,WAChC,OAAO,KAAK,EACZ,KAAK,MAAM;AAIV,eAAK,SAAS,WAAW;AACzB,sBAAY;AAAA,QACd,CAAC,EACA,MAAM,CAAC,QAAQ;AAGd,cAAI,MAAM,4CAA4C,GAAG,EAAE;AAAA,QAC7D,CAAC,EACA,QAAQ,MAAM;AACb,eAAK,gBAAgB,OAAO,WAAW;AAAA,QACzC,CAAC;AACH,aAAK,gBAAgB,IAAI,aAAa,aAAa;AACnD,cAAM;AACN;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,SAAS,aAA2B;AAI1C,SAAK,mBAAmB,OAAO,WAAW;AAC1C,SAAK,mBAAmB,IAAI,aAAa,KAAK,IAAI,CAAC;AACnD,QAAI,KAAK,mBAAmB,OAAO,uCAAuC;AACxE,YAAM,SAAS,KAAK,mBAAmB,KAAK,EAAE,KAAK,EAAE;AACrD,UAAI,OAAO,WAAW,SAAU,MAAK,mBAAmB,OAAO,MAAM;AAAA,IACvE;AAAA,EACF;AACF;","names":[]}