@remnic/core 10.0.49 → 10.0.50

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 (338) hide show
  1. package/dist/access-admin-ops-surface.js +41 -40
  2. package/dist/access-authorization-probe.js +42 -41
  3. package/dist/access-boundary.js +41 -40
  4. package/dist/access-cli.js +107 -106
  5. package/dist/access-cli.js.map +1 -1
  6. package/dist/access-extraction-force-flush.js +41 -40
  7. package/dist/access-http-briefing.d.ts +2 -0
  8. package/dist/access-http-briefing.d.ts.map +1 -1
  9. package/dist/access-http-briefing.js +42 -41
  10. package/dist/access-http-query.js +43 -42
  11. package/dist/access-http.d.ts.map +1 -1
  12. package/dist/access-http.js +59 -58
  13. package/dist/access-identity-continuity-surface.js +41 -40
  14. package/dist/access-lcm-surface.js +41 -40
  15. package/dist/access-mcp.js +51 -50
  16. package/dist/access-namespace-preflight.js +41 -40
  17. package/dist/access-observe-write-category.d.ts +1 -1
  18. package/dist/access-observe-write-category.d.ts.map +1 -1
  19. package/dist/access-observe-write-category.js +10 -10
  20. package/dist/access-observe-write-surface.d.ts.map +1 -1
  21. package/dist/access-observe-write-surface.js +41 -40
  22. package/dist/access-offline-manifest.js +4 -4
  23. package/dist/access-operations-batch.js +42 -41
  24. package/dist/access-operations.js +49 -48
  25. package/dist/access-recall-concurrency.js +41 -40
  26. package/dist/access-recall-response.js +41 -40
  27. package/dist/access-recall-surface.js +41 -40
  28. package/dist/access-schema.js +6 -6
  29. package/dist/access-service.d.ts +5 -0
  30. package/dist/access-service.d.ts.map +1 -1
  31. package/dist/access-service.js +41 -40
  32. package/dist/access-surface-catalog.js +43 -42
  33. package/dist/access-surface-catalog.js.map +1 -1
  34. package/dist/active-recall.js +14 -14
  35. package/dist/{auto-sync-BNCBMU6H.js → auto-sync-UQQ6YJSB.js} +3 -3
  36. package/dist/briefing-deadline.d.ts +7 -0
  37. package/dist/briefing-deadline.d.ts.map +1 -0
  38. package/dist/briefing-deadline.js +13 -0
  39. package/dist/briefing-window.d.ts +12 -4
  40. package/dist/briefing-window.d.ts.map +1 -1
  41. package/dist/briefing-window.js +3 -1
  42. package/dist/briefing.d.ts +2 -0
  43. package/dist/briefing.d.ts.map +1 -1
  44. package/dist/briefing.js +12 -11
  45. package/dist/buffer.js +3 -3
  46. package/dist/calibration.js +2 -2
  47. package/dist/{capsule-merge-RNQUP2VL.js → capsule-merge-D4BTIJGK.js} +3 -3
  48. package/dist/causal-consolidation.js +11 -11
  49. package/dist/{chunk-ESDOQEJM.js → chunk-2AKIVSHP.js} +2 -2
  50. package/dist/{chunk-MCS4LIXP.js → chunk-43TUWQNR.js} +2 -2
  51. package/dist/{chunk-2NLCDNGA.js → chunk-564YP3DW.js} +2 -2
  52. package/dist/{chunk-PBWJVRKE.js → chunk-5FUDSK6Z.js} +2 -2
  53. package/dist/{chunk-V4GPFCJ7.js → chunk-5G53JSRO.js} +2 -2
  54. package/dist/{chunk-WJCAAVZX.js → chunk-5X2H3X4J.js} +2 -2
  55. package/dist/{chunk-CPBYKOTC.js → chunk-6ZQX3R66.js} +2 -2
  56. package/dist/{chunk-AF4UIHON.js → chunk-74AY3S7U.js} +9 -9
  57. package/dist/{chunk-XSJL62LE.js → chunk-7J6A5MV2.js} +2 -2
  58. package/dist/{chunk-A3WXV7YU.js → chunk-7SAE6T36.js} +2 -2
  59. package/dist/{chunk-BWF3KNSQ.js → chunk-7YVER7ZO.js} +2 -2
  60. package/dist/{chunk-5IDQVE4U.js → chunk-A3UFV4K3.js} +6 -6
  61. package/dist/{chunk-LWRIGKFM.js → chunk-A5L5KGDI.js} +19 -1
  62. package/dist/chunk-A5L5KGDI.js.map +1 -0
  63. package/dist/{chunk-6TIVVOVU.js → chunk-BNJAVRNJ.js} +9 -9
  64. package/dist/{chunk-CMOYD5CA.js → chunk-CCL2OXFO.js} +2 -2
  65. package/dist/{chunk-7XFQSQYS.js → chunk-CRN3EPE2.js} +4 -3
  66. package/dist/chunk-CRN3EPE2.js.map +1 -0
  67. package/dist/{chunk-3NYIXVCT.js → chunk-DMKTOCC7.js} +2 -2
  68. package/dist/chunk-DMKTOCC7.js.map +1 -0
  69. package/dist/{chunk-FRXS6SC7.js → chunk-EKUI7I2X.js} +20 -4
  70. package/dist/chunk-EKUI7I2X.js.map +1 -0
  71. package/dist/{chunk-N6EM7ESC.js → chunk-EKYWZYZJ.js} +22 -14
  72. package/dist/chunk-EKYWZYZJ.js.map +1 -0
  73. package/dist/{chunk-FOKTW6GY.js → chunk-EWBXMGXR.js} +2 -2
  74. package/dist/{chunk-YNDLCWXS.js → chunk-EZ25VE3G.js} +4 -4
  75. package/dist/{chunk-6W3QH3QW.js → chunk-GQIYL7OD.js} +388 -292
  76. package/dist/chunk-GQIYL7OD.js.map +1 -0
  77. package/dist/{chunk-E47UQBYW.js → chunk-GXVXBYRA.js} +3 -3
  78. package/dist/{chunk-RZDDNH63.js → chunk-HKOMHP6D.js} +27 -15
  79. package/dist/chunk-HKOMHP6D.js.map +1 -0
  80. package/dist/{chunk-AGCEJDG2.js → chunk-HPNXS6W6.js} +2 -2
  81. package/dist/{chunk-O4CA53UY.js → chunk-IMKOJVD4.js} +69 -63
  82. package/dist/chunk-IMKOJVD4.js.map +1 -0
  83. package/dist/{chunk-N5PISU26.js → chunk-IN6U2BS5.js} +2 -2
  84. package/dist/{chunk-HI53EK3Y.js → chunk-IUYXCTA7.js} +2 -2
  85. package/dist/{chunk-VGRBKEBH.js → chunk-JBWD3J5U.js} +3 -3
  86. package/dist/{chunk-YB3WN6XA.js → chunk-K5QQXVG6.js} +12 -12
  87. package/dist/{chunk-7LCGFUMB.js → chunk-KQAFEZQX.js} +4 -4
  88. package/dist/{chunk-HDT3DMUF.js → chunk-KW5YZELC.js} +2 -2
  89. package/dist/{chunk-DM6SOROF.js → chunk-LIBVANOF.js} +2 -2
  90. package/dist/{chunk-VKUMKVEU.js → chunk-LMMBV7QC.js} +4 -4
  91. package/dist/{chunk-NMOEOQV4.js → chunk-M2DOJBH7.js} +2 -2
  92. package/dist/{chunk-3INLTKTW.js → chunk-M4HRYLOA.js} +2 -2
  93. package/dist/{chunk-YY6PWFUC.js → chunk-M6TP6UYD.js} +3 -3
  94. package/dist/{chunk-BJTFLP3J.js → chunk-MLNXATFG.js} +2 -2
  95. package/dist/{chunk-C7WDWD35.js → chunk-MWURUSRE.js} +5 -5
  96. package/dist/{chunk-WIBWONL4.js → chunk-N74WJ7B2.js} +2 -2
  97. package/dist/{chunk-LCHFINL4.js → chunk-N7FNCE7F.js} +2 -2
  98. package/dist/{chunk-QZK6HG4J.js → chunk-NPLM7AFU.js} +2 -2
  99. package/dist/{chunk-CRJX4OMN.js → chunk-NSP5PIQH.js} +2 -2
  100. package/dist/{chunk-X52SXKVC.js → chunk-P7OVFGMU.js} +2 -2
  101. package/dist/{chunk-2J6BIOVN.js → chunk-PJCVI44H.js} +2 -2
  102. package/dist/{chunk-Q6PYCPHO.js → chunk-Q3PNQYAC.js} +2 -2
  103. package/dist/{chunk-D76AHITY.js → chunk-QS765SBL.js} +2 -2
  104. package/dist/{chunk-KNCR7APE.js → chunk-QTDZ2NYC.js} +7 -7
  105. package/dist/{chunk-YFXRLRKP.js → chunk-S4OZKPBS.js} +7 -11
  106. package/dist/{chunk-YFXRLRKP.js.map → chunk-S4OZKPBS.js.map} +1 -1
  107. package/dist/{chunk-HCPVL6SF.js → chunk-SJTSWG2Z.js} +3 -3
  108. package/dist/{chunk-SA6P2KS3.js → chunk-TEH5MDX5.js} +33 -17
  109. package/dist/chunk-TEH5MDX5.js.map +1 -0
  110. package/dist/{chunk-XFND63OB.js → chunk-TFWJXWL6.js} +2 -2
  111. package/dist/{chunk-SVJ5JVZO.js → chunk-TXKQBQYW.js} +3 -3
  112. package/dist/{chunk-WQFHHJWK.js → chunk-UALXWWGN.js} +2 -2
  113. package/dist/{chunk-3PVKV3XL.js → chunk-UNOAVHV4.js} +2 -2
  114. package/dist/{chunk-FYZXZUGU.js → chunk-UQBOPCDK.js} +2 -2
  115. package/dist/{chunk-SUKPM6DV.js → chunk-UWMZT2TY.js} +47 -4
  116. package/dist/chunk-UWMZT2TY.js.map +1 -0
  117. package/dist/{chunk-OD7ZXCUF.js → chunk-UXGXJUZ5.js} +7 -7
  118. package/dist/{chunk-NH37SP6V.js → chunk-UZVQFGAY.js} +81 -78
  119. package/dist/chunk-UZVQFGAY.js.map +1 -0
  120. package/dist/{chunk-2BY56HE6.js → chunk-VCOMACR6.js} +35 -35
  121. package/dist/{chunk-5FNZ3G6X.js → chunk-VKQI47DJ.js} +4 -4
  122. package/dist/{chunk-MPJDQC4G.js → chunk-WJCXUE2J.js} +2 -2
  123. package/dist/{chunk-C3HRYVGD.js → chunk-WV4UYDP6.js} +2 -2
  124. package/dist/{chunk-E3DL3CAL.js → chunk-WXJC2L66.js} +2 -2
  125. package/dist/chunk-X2KO4FK5.js +40 -0
  126. package/dist/chunk-X2KO4FK5.js.map +1 -0
  127. package/dist/{chunk-O7GNSHFF.js → chunk-XC3H7KON.js} +2 -2
  128. package/dist/{chunk-OOOX5C4X.js → chunk-XL2EE5W3.js} +4 -4
  129. package/dist/{chunk-NUK5XU3P.js → chunk-XTXWR6KQ.js} +25 -10
  130. package/dist/chunk-XTXWR6KQ.js.map +1 -0
  131. package/dist/{chunk-CZVNOTLR.js → chunk-XXR4A33N.js} +2 -2
  132. package/dist/{chunk-2AV2U2SZ.js → chunk-YDIOMDBW.js} +2 -2
  133. package/dist/{chunk-QFTNWDJ6.js → chunk-YECEEJUU.js} +2 -2
  134. package/dist/{chunk-BMG3SAXA.js → chunk-Z5277JWF.js} +3 -3
  135. package/dist/{chunk-SW3WHVKN.js → chunk-ZFNXJEUG.js} +2 -2
  136. package/dist/{chunk-VY6BD5KB.js → chunk-ZMO2S5RT.js} +12 -10
  137. package/dist/chunk-ZMO2S5RT.js.map +1 -0
  138. package/dist/{chunk-KMTMMBEB.js → chunk-ZNRTHYYW.js} +6 -6
  139. package/dist/{chunk-VCBS5GRQ.js → chunk-ZSMA67FV.js} +2 -2
  140. package/dist/cli.js +80 -79
  141. package/dist/coding/export-okf-codegraph.js +9 -9
  142. package/dist/compounding/engine.js +11 -11
  143. package/dist/config.js +14 -14
  144. package/dist/connectors/codex-materialize-runner.js +10 -10
  145. package/dist/connectors/index.js +10 -10
  146. package/dist/consolidation-provenance-check.js +4 -4
  147. package/dist/consolidation-undo.js +2 -2
  148. package/dist/convergence-refresh.js +12 -12
  149. package/dist/corpus-watermark.js +12 -12
  150. package/dist/correction/passive-correction-notifications.d.ts +1 -1
  151. package/dist/correction/passive-correction-notifications.d.ts.map +1 -1
  152. package/dist/dashboard-runtime.js +2 -2
  153. package/dist/deep-recall-http-glue.js +7 -7
  154. package/dist/{entity-canonical-id-migration-2YOLMOFC.js → entity-canonical-id-migration-ZBNRGUNV.js} +3 -3
  155. package/dist/entity-canonical-id-migration-ZBNRGUNV.js.map +1 -0
  156. package/dist/entity-retrieval.js +11 -11
  157. package/dist/explicit-capture.js +2 -2
  158. package/dist/external-wiki-access.js +42 -41
  159. package/dist/extraction.js +16 -16
  160. package/dist/{first-start-migration-QVD22WWS.js → first-start-migration-A6PHIBUQ.js} +4 -4
  161. package/dist/harmonic-retrieval.js +10 -10
  162. package/dist/index.d.ts +1 -0
  163. package/dist/index.d.ts.map +1 -1
  164. package/dist/index.js +130 -122
  165. package/dist/lcm/engine.js +2 -2
  166. package/dist/lcm/index.js +5 -5
  167. package/dist/local-llm.js +2 -2
  168. package/dist/location/index.js +15 -15
  169. package/dist/location/tagging.d.ts +7 -5
  170. package/dist/location/tagging.d.ts.map +1 -1
  171. package/dist/maintenance/memory-governance.js +10 -10
  172. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -10
  173. package/dist/maintenance/rebuild-memory-projection-runner.js +12 -12
  174. package/dist/maintenance/rebuild-memory-projection.js +11 -11
  175. package/dist/memory-browse-operations.js +42 -41
  176. package/dist/namespaces/migrate.js +11 -11
  177. package/dist/namespaces/storage.js +10 -10
  178. package/dist/offline-sync-file-io.d.ts +15 -0
  179. package/dist/offline-sync-file-io.d.ts.map +1 -1
  180. package/dist/offline-sync-file-io.js +9 -1
  181. package/dist/offline-sync-snapshot-stream.js +4 -4
  182. package/dist/offline-sync-upload-staging.js +2 -2
  183. package/dist/offline-sync.d.ts.map +1 -1
  184. package/dist/offline-sync.js +3 -3
  185. package/dist/operator-doctor-corpus.js +13 -13
  186. package/dist/operator-toolkit.js +24 -24
  187. package/dist/orchestration/maintenance.js +23 -23
  188. package/dist/orchestrator.d.ts +1 -0
  189. package/dist/orchestrator.d.ts.map +1 -1
  190. package/dist/orchestrator.js +109 -108
  191. package/dist/page-versioning.js +2 -2
  192. package/dist/recall-navigation-operations.js +42 -41
  193. package/dist/recall-navigation.js +41 -40
  194. package/dist/resume-bundles.js +15 -15
  195. package/dist/semantic-consolidation.js +15 -15
  196. package/dist/semantic-rule-promotion.js +10 -10
  197. package/dist/semantic-rule-verifier.js +10 -10
  198. package/dist/source-agent-qualifier.js +13 -13
  199. package/dist/standup/build.js +10 -10
  200. package/dist/storage/entity-canonical-id-migration-adapter.d.ts +1 -0
  201. package/dist/storage/entity-canonical-id-migration-adapter.d.ts.map +1 -1
  202. package/dist/storage/entity-canonical-id-migration.d.ts +7 -0
  203. package/dist/storage/entity-canonical-id-migration.d.ts.map +1 -1
  204. package/dist/storage/entity-canonical-id-references.d.ts +2 -0
  205. package/dist/storage/entity-canonical-id-references.d.ts.map +1 -1
  206. package/dist/storage/entity-migration-completion-cache.d.ts +46 -0
  207. package/dist/storage/entity-migration-completion-cache.d.ts.map +1 -0
  208. package/dist/storage/entity-store.d.ts +1 -8
  209. package/dist/storage/entity-store.d.ts.map +1 -1
  210. package/dist/storage/memory-read-store.d.ts +3 -2
  211. package/dist/storage/memory-read-store.d.ts.map +1 -1
  212. package/dist/storage/windowed-memory-read.d.ts +6 -0
  213. package/dist/storage/windowed-memory-read.d.ts.map +1 -1
  214. package/dist/storage.d.ts +2 -0
  215. package/dist/storage.d.ts.map +1 -1
  216. package/dist/storage.js +9 -9
  217. package/dist/summarizer.js +3 -3
  218. package/dist/support-passport/index.js +44 -43
  219. package/dist/transfer/capsule-export.js +2 -2
  220. package/dist/transfer/capsule-import.js +4 -4
  221. package/dist/transfer/export-okf.js +10 -10
  222. package/dist/verified-recall.js +10 -10
  223. package/dist/who-knows-cli.js +11 -11
  224. package/dist/who-knows.js +10 -10
  225. package/package.json +2 -2
  226. package/src/access-http-briefing.ts +4 -0
  227. package/src/access-http.test.ts +40 -11
  228. package/src/access-http.ts +6 -0
  229. package/src/access-observe-write-category.ts +1 -1
  230. package/src/access-observe-write-surface.ts +24 -19
  231. package/src/access-operations-batch.ts +18 -2
  232. package/src/access-service.ts +5 -0
  233. package/src/briefing-abort.test.ts +173 -0
  234. package/src/briefing-deadline.test.ts +84 -0
  235. package/src/briefing-deadline.ts +33 -0
  236. package/src/briefing-window-abort.test.ts +47 -0
  237. package/src/briefing-window.ts +33 -4
  238. package/src/briefing.ts +23 -16
  239. package/src/correction/passive-correction-notifications-abort.test.ts +42 -0
  240. package/src/correction/passive-correction-notifications.ts +4 -0
  241. package/src/entity-lazy-compatibility.test.ts +229 -0
  242. package/src/entity-migration-completion-notification.test.ts +148 -0
  243. package/src/index.ts +1 -1
  244. package/src/location/tagging.ts +14 -12
  245. package/src/offline-sync-file-io.ts +61 -2
  246. package/src/offline-sync.test.ts +313 -20
  247. package/src/offline-sync.ts +43 -21
  248. package/src/orchestrator-init.test.ts +49 -1
  249. package/src/orchestrator.ts +9 -8
  250. package/src/storage/entity-canonical-id-migration-adapter.ts +16 -1
  251. package/src/storage/entity-canonical-id-migration.ts +17 -8
  252. package/src/storage/entity-canonical-id-references.ts +24 -0
  253. package/src/storage/entity-migration-completion-cache.nofollow.test.ts +223 -0
  254. package/src/storage/entity-migration-completion-cache.ts +153 -0
  255. package/src/storage/entity-store.ts +58 -86
  256. package/src/storage/memory-read-store.ts +9 -3
  257. package/src/storage/windowed-memory-read.ts +8 -0
  258. package/src/storage-startup-nonblocking-migration.test.ts +183 -0
  259. package/src/storage.ts +7 -2
  260. package/src/testing/subjects/entity-migration-completion-cache.test.ts +90 -0
  261. package/dist/chunk-3NYIXVCT.js.map +0 -1
  262. package/dist/chunk-6W3QH3QW.js.map +0 -1
  263. package/dist/chunk-7XFQSQYS.js.map +0 -1
  264. package/dist/chunk-FRXS6SC7.js.map +0 -1
  265. package/dist/chunk-LWRIGKFM.js.map +0 -1
  266. package/dist/chunk-N6EM7ESC.js.map +0 -1
  267. package/dist/chunk-NH37SP6V.js.map +0 -1
  268. package/dist/chunk-NUK5XU3P.js.map +0 -1
  269. package/dist/chunk-O4CA53UY.js.map +0 -1
  270. package/dist/chunk-RZDDNH63.js.map +0 -1
  271. package/dist/chunk-SA6P2KS3.js.map +0 -1
  272. package/dist/chunk-SUKPM6DV.js.map +0 -1
  273. package/dist/chunk-VY6BD5KB.js.map +0 -1
  274. /package/dist/{auto-sync-BNCBMU6H.js.map → auto-sync-UQQ6YJSB.js.map} +0 -0
  275. /package/dist/{entity-canonical-id-migration-2YOLMOFC.js.map → briefing-deadline.js.map} +0 -0
  276. /package/dist/{capsule-merge-RNQUP2VL.js.map → capsule-merge-D4BTIJGK.js.map} +0 -0
  277. /package/dist/{chunk-ESDOQEJM.js.map → chunk-2AKIVSHP.js.map} +0 -0
  278. /package/dist/{chunk-MCS4LIXP.js.map → chunk-43TUWQNR.js.map} +0 -0
  279. /package/dist/{chunk-2NLCDNGA.js.map → chunk-564YP3DW.js.map} +0 -0
  280. /package/dist/{chunk-PBWJVRKE.js.map → chunk-5FUDSK6Z.js.map} +0 -0
  281. /package/dist/{chunk-V4GPFCJ7.js.map → chunk-5G53JSRO.js.map} +0 -0
  282. /package/dist/{chunk-WJCAAVZX.js.map → chunk-5X2H3X4J.js.map} +0 -0
  283. /package/dist/{chunk-CPBYKOTC.js.map → chunk-6ZQX3R66.js.map} +0 -0
  284. /package/dist/{chunk-AF4UIHON.js.map → chunk-74AY3S7U.js.map} +0 -0
  285. /package/dist/{chunk-XSJL62LE.js.map → chunk-7J6A5MV2.js.map} +0 -0
  286. /package/dist/{chunk-A3WXV7YU.js.map → chunk-7SAE6T36.js.map} +0 -0
  287. /package/dist/{chunk-BWF3KNSQ.js.map → chunk-7YVER7ZO.js.map} +0 -0
  288. /package/dist/{chunk-5IDQVE4U.js.map → chunk-A3UFV4K3.js.map} +0 -0
  289. /package/dist/{chunk-6TIVVOVU.js.map → chunk-BNJAVRNJ.js.map} +0 -0
  290. /package/dist/{chunk-CMOYD5CA.js.map → chunk-CCL2OXFO.js.map} +0 -0
  291. /package/dist/{chunk-FOKTW6GY.js.map → chunk-EWBXMGXR.js.map} +0 -0
  292. /package/dist/{chunk-YNDLCWXS.js.map → chunk-EZ25VE3G.js.map} +0 -0
  293. /package/dist/{chunk-E47UQBYW.js.map → chunk-GXVXBYRA.js.map} +0 -0
  294. /package/dist/{chunk-AGCEJDG2.js.map → chunk-HPNXS6W6.js.map} +0 -0
  295. /package/dist/{chunk-N5PISU26.js.map → chunk-IN6U2BS5.js.map} +0 -0
  296. /package/dist/{chunk-HI53EK3Y.js.map → chunk-IUYXCTA7.js.map} +0 -0
  297. /package/dist/{chunk-VGRBKEBH.js.map → chunk-JBWD3J5U.js.map} +0 -0
  298. /package/dist/{chunk-YB3WN6XA.js.map → chunk-K5QQXVG6.js.map} +0 -0
  299. /package/dist/{chunk-7LCGFUMB.js.map → chunk-KQAFEZQX.js.map} +0 -0
  300. /package/dist/{chunk-HDT3DMUF.js.map → chunk-KW5YZELC.js.map} +0 -0
  301. /package/dist/{chunk-DM6SOROF.js.map → chunk-LIBVANOF.js.map} +0 -0
  302. /package/dist/{chunk-VKUMKVEU.js.map → chunk-LMMBV7QC.js.map} +0 -0
  303. /package/dist/{chunk-NMOEOQV4.js.map → chunk-M2DOJBH7.js.map} +0 -0
  304. /package/dist/{chunk-3INLTKTW.js.map → chunk-M4HRYLOA.js.map} +0 -0
  305. /package/dist/{chunk-YY6PWFUC.js.map → chunk-M6TP6UYD.js.map} +0 -0
  306. /package/dist/{chunk-BJTFLP3J.js.map → chunk-MLNXATFG.js.map} +0 -0
  307. /package/dist/{chunk-C7WDWD35.js.map → chunk-MWURUSRE.js.map} +0 -0
  308. /package/dist/{chunk-WIBWONL4.js.map → chunk-N74WJ7B2.js.map} +0 -0
  309. /package/dist/{chunk-LCHFINL4.js.map → chunk-N7FNCE7F.js.map} +0 -0
  310. /package/dist/{chunk-QZK6HG4J.js.map → chunk-NPLM7AFU.js.map} +0 -0
  311. /package/dist/{chunk-CRJX4OMN.js.map → chunk-NSP5PIQH.js.map} +0 -0
  312. /package/dist/{chunk-X52SXKVC.js.map → chunk-P7OVFGMU.js.map} +0 -0
  313. /package/dist/{chunk-2J6BIOVN.js.map → chunk-PJCVI44H.js.map} +0 -0
  314. /package/dist/{chunk-Q6PYCPHO.js.map → chunk-Q3PNQYAC.js.map} +0 -0
  315. /package/dist/{chunk-D76AHITY.js.map → chunk-QS765SBL.js.map} +0 -0
  316. /package/dist/{chunk-KNCR7APE.js.map → chunk-QTDZ2NYC.js.map} +0 -0
  317. /package/dist/{chunk-HCPVL6SF.js.map → chunk-SJTSWG2Z.js.map} +0 -0
  318. /package/dist/{chunk-XFND63OB.js.map → chunk-TFWJXWL6.js.map} +0 -0
  319. /package/dist/{chunk-SVJ5JVZO.js.map → chunk-TXKQBQYW.js.map} +0 -0
  320. /package/dist/{chunk-WQFHHJWK.js.map → chunk-UALXWWGN.js.map} +0 -0
  321. /package/dist/{chunk-3PVKV3XL.js.map → chunk-UNOAVHV4.js.map} +0 -0
  322. /package/dist/{chunk-FYZXZUGU.js.map → chunk-UQBOPCDK.js.map} +0 -0
  323. /package/dist/{chunk-OD7ZXCUF.js.map → chunk-UXGXJUZ5.js.map} +0 -0
  324. /package/dist/{chunk-2BY56HE6.js.map → chunk-VCOMACR6.js.map} +0 -0
  325. /package/dist/{chunk-5FNZ3G6X.js.map → chunk-VKQI47DJ.js.map} +0 -0
  326. /package/dist/{chunk-MPJDQC4G.js.map → chunk-WJCXUE2J.js.map} +0 -0
  327. /package/dist/{chunk-C3HRYVGD.js.map → chunk-WV4UYDP6.js.map} +0 -0
  328. /package/dist/{chunk-E3DL3CAL.js.map → chunk-WXJC2L66.js.map} +0 -0
  329. /package/dist/{chunk-O7GNSHFF.js.map → chunk-XC3H7KON.js.map} +0 -0
  330. /package/dist/{chunk-OOOX5C4X.js.map → chunk-XL2EE5W3.js.map} +0 -0
  331. /package/dist/{chunk-CZVNOTLR.js.map → chunk-XXR4A33N.js.map} +0 -0
  332. /package/dist/{chunk-2AV2U2SZ.js.map → chunk-YDIOMDBW.js.map} +0 -0
  333. /package/dist/{chunk-QFTNWDJ6.js.map → chunk-YECEEJUU.js.map} +0 -0
  334. /package/dist/{chunk-BMG3SAXA.js.map → chunk-Z5277JWF.js.map} +0 -0
  335. /package/dist/{chunk-SW3WHVKN.js.map → chunk-ZFNXJEUG.js.map} +0 -0
  336. /package/dist/{chunk-KMTMMBEB.js.map → chunk-ZNRTHYYW.js.map} +0 -0
  337. /package/dist/{chunk-VCBS5GRQ.js.map → chunk-ZSMA67FV.js.map} +0 -0
  338. /package/dist/{first-start-migration-QVD22WWS.js.map → first-start-migration-A6PHIBUQ.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/briefing.ts","../src/correction/passive-correction-notifications.ts"],"sourcesContent":["/**\n * Daily Context Briefing (Issue #370)\n *\n * Produces a focused \"here is what matters right now\" briefing by\n * cross-referencing active entities, recent facts, open commitments,\n * LLM-generated follow-ups, and an optional calendar source.\n *\n * The module exposes:\n * - `parseBriefingWindow(token)` — CLI-friendly window parser.\n * - `buildBriefing(options)` — core builder that returns markdown + JSON.\n * - `FileCalendarSource` — stub CalendarSource implementation that reads\n * a local ICS or JSON file.\n *\n * ALL OpenAI usage in this module goes through the Responses API. Chat\n * Completions is never used.\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { log } from \"./logger.js\";\nimport { withBriefingFollowupTimeout } from \"./briefing-followup-timeout.js\";\nimport { extractJsonCandidates } from \"./json-extract.js\";\nimport { drainPassiveCorrectionNotifications } from \"./correction/passive-correction-notifications.js\";\nimport { excludeSupportPassportPrivateMemories } from \"./support-passport/card-projection.js\";\nimport { normalizeEntityName, StorageManager } from \"./storage.js\";\nimport { safeReadMemories } from \"./briefing-window.js\";\nimport { readEnvVar, resolveHomeDir } from \"./runtime/env.js\";\nimport type {\n BriefingActiveThread,\n BriefingCalendarSourceError,\n BriefingFocus,\n BriefingFollowup,\n BriefingOpenCommitment,\n BriefingRecentEntity,\n BriefingResult,\n BriefingSections,\n CalendarEvent,\n CalendarSource,\n EntityFile,\n MemoryFile,\n} from \"./types.js\";\n\n// ──────────────────────────────────────────────────────────────────────────\n// Window parsing\n// ──────────────────────────────────────────────────────────────────────────\n\n/** Allowed values for the briefing format flag/field. */\nexport const BRIEFING_FORMAT_ALLOWED = [\"markdown\", \"json\"] as const;\n\n/**\n * Default model used for the Responses API follow-up generation call.\n * Mirrors the extraction engine default in config.ts — keep in sync.\n */\nexport const BRIEFING_FOLLOWUP_DEFAULT_MODEL = \"gpt-5.5\";\nexport type BriefingFormatValue = typeof BRIEFING_FORMAT_ALLOWED[number];\n\n/**\n * Validate a user-supplied `--format` flag value.\n * Returns `null` when the value is valid (or `undefined`, meaning the flag\n * was not supplied and the caller should fall back to the configured default).\n * Returns an error message string when the value is explicitly invalid.\n */\nexport function validateBriefingFormat(value: string | undefined): string | null {\n if (value === undefined) return null;\n if ((BRIEFING_FORMAT_ALLOWED as readonly string[]).includes(value)) return null;\n return `Invalid --format value: \"${value}\". Accepted: ${BRIEFING_FORMAT_ALLOWED.join(\", \")}.`;\n}\n\n/** Parsed briefing lookback window. */\nexport interface ParsedBriefingWindow {\n /** Start of the window (inclusive). */\n from: Date;\n /** End of the window (exclusive). */\n to: Date;\n /** Human-readable label. */\n label: string;\n}\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Maximum allowed lookback offset in milliseconds (100 years).\n * Anything beyond this is almost certainly a typo or abuse — and would\n * overflow to `Invalid Date` for sufficiently large values anyway.\n */\nconst MAX_WINDOW_MS = 100 * 365 * DAY_MS;\n\n/**\n * Parse a CLI-friendly window token into a concrete date range.\n *\n * Accepted forms (case-insensitive):\n * - `yesterday` — the previous UTC calendar day.\n * - `today` — the current UTC calendar day so far.\n * - `NNh` — last N hours (e.g. `24h`, `48h`).\n * - `NNd` — last N calendar days (e.g. `3d`, `7d`).\n * - `NNw` — last N weeks (e.g. `1w`, `2w`).\n *\n * Returns `null` for invalid tokens so callers can surface a clean error.\n */\nexport function parseBriefingWindow(\n token: string,\n now: Date = new Date(),\n): ParsedBriefingWindow | null {\n const raw = typeof token === \"string\" ? token.trim().toLowerCase() : \"\";\n if (raw.length === 0) return null;\n\n if (raw === \"yesterday\") {\n const startOfToday = startOfUtcDay(now);\n const from = new Date(startOfToday.getTime() - DAY_MS);\n return { from, to: startOfToday, label: \"yesterday\" };\n }\n\n if (raw === \"today\") {\n return { from: startOfUtcDay(now), to: now, label: \"today\" };\n }\n\n const match = raw.match(/^(\\d+)\\s*(h|d|w)$/);\n if (!match) return null;\n const value = parseInt(match[1], 10);\n if (!Number.isFinite(value) || value <= 0) return null;\n const unit = match[2];\n let ms = 0;\n if (unit === \"h\") ms = value * 60 * 60 * 1000;\n else if (unit === \"d\") ms = value * DAY_MS;\n else if (unit === \"w\") ms = value * 7 * DAY_MS;\n if (ms === 0) return null;\n // Reject values that exceed the 100-year cap or would overflow to Invalid Date.\n if (ms > MAX_WINDOW_MS || !Number.isFinite(ms)) return null;\n const from = new Date(now.getTime() - ms);\n if (!Number.isFinite(from.getTime())) return null;\n return {\n from,\n to: now,\n label: `last ${value}${unit}`,\n };\n}\n\nfunction startOfUtcDay(date: Date): Date {\n const d = new Date(date.getTime());\n d.setUTCHours(0, 0, 0, 0);\n return d;\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Focus filter\n// ──────────────────────────────────────────────────────────────────────────\n\n/**\n * Parse a CLI `--focus` string into a structured focus filter.\n *\n * Accepted forms:\n * - `person:Jane Doe`\n * - `project:remnic-core`\n * - `topic:retrieval`\n *\n * If no prefix is supplied, falls back to `topic:<value>`.\n */\nexport function parseBriefingFocus(token: string | undefined): BriefingFocus | null {\n if (typeof token !== \"string\") return null;\n const trimmed = token.trim();\n if (trimmed.length === 0) return null;\n const [maybeType, ...rest] = trimmed.split(\":\");\n if (rest.length === 0) {\n return { type: \"topic\", value: maybeType };\n }\n const rawType = maybeType.toLowerCase();\n if (rawType === \"person\" || rawType === \"project\" || rawType === \"topic\") {\n const value = rest.join(\":\").trim();\n if (value.length === 0) return null;\n return { type: rawType, value };\n }\n return { type: \"topic\", value: trimmed };\n}\n\n/**\n * Decide whether a memory/entity matches the given focus filter.\n * Purely deterministic — no LLM, case-insensitive substring match across\n * the most useful surfaces.\n *\n * For typed focus (`person:`, `project:`, `entity:`) we attribute via the\n * canonical-id path below to avoid the substring leak fixed in #682 PR 2/3\n * R-10 (`Alice-Test` substring-hitting `person-alice-test-a1`).\n *\n * For untyped (`topic`) focus there is no type to canonicalize against, so\n * we keep `entityRef` in the raw haystack — otherwise memories that link to\n * an entity only via `frontmatter.entityRef` (no body / tag mention) would\n * silently drop out of an untyped focus filter (codex P2 review on #695).\n */\nexport function focusMatchesMemory(\n memory: MemoryFile,\n focus: BriefingFocus,\n entityAliases?: Readonly<Record<string, string>>,\n): boolean {\n const needle = focus.value.toLowerCase();\n const entityRef = (memory.frontmatter.entityRef ?? \"\").toLowerCase();\n\n // Raw substring match across content and tags. For untyped (`topic`)\n // focus, also include the entityRef so memories linked only via the\n // frontmatter ref still match. For typed focus we deliberately\n // exclude entityRef here and route through the canonical-id path\n // below (see comment above).\n const rawHaystackParts = [\n memory.content,\n ...(memory.frontmatter.tags ?? []),\n ];\n if (focus.type === \"topic\" && entityRef) {\n rawHaystackParts.push(entityRef);\n }\n const rawHaystack = rawHaystackParts.join(\" \").toLowerCase();\n if (rawHaystack.includes(needle)) return true;\n\n // Canonical-id match (#682 PR 2/3 R-10). Normalize BOTH sides through\n // `normalizeEntityName` so:\n // - `entityRef === slug` exact comparison no longer fails when the\n // stored ref is in a non-canonical form (e.g. `person:Alice-Test`\n // vs. `person-alice-test`) — both normalize to the same canonical id.\n // - `entityRef.includes(slug)` substring matching is replaced by\n // equality, so similarly-prefixed entities like\n // `person-alice-test-a1` no longer match a focus on\n // `person:Alice-Test`.\n // This also handles the type-prefix-in-name case the cursor reviewer\n // flagged: `normalizeEntityName` strips a duplicate type prefix so\n // `Project-Alpha` of type `project` canonicalizes to `project-alpha`,\n // and a focus on `project:Project-Alpha` does the same.\n if (!entityRef) return false;\n const focusCanonical = normalizeEntityName(focus.value, focus.type, entityAliases);\n // Strip a leading `<type><delimiter>` prefix from a non-canonical\n // entityRef before normalizing — `normalizeEntityName` only strips\n // `<type>-` so other valid verbatim formats (`person:Alice-Test`,\n // `person/alice-test`, `person_alice_test`, `person Alice Test`)\n // would otherwise double up the type prefix and miss the canonical\n // comparison. Codex P2 review on #695: memory writes persist\n // entityRef strings as provided, so any non-alphanumeric delimiter\n // after the type token must be tolerated here.\n let refForNormalize = entityRef;\n const typeDelimMatch = refForNormalize.match(\n new RegExp(`^${focus.type}[^a-z0-9]+`, \"i\"),\n );\n if (typeDelimMatch) {\n refForNormalize = refForNormalize.slice(typeDelimMatch[0].length);\n }\n const refCanonical = normalizeEntityName(refForNormalize, focus.type, entityAliases);\n return refCanonical === focusCanonical;\n}\n\nexport function focusMatchesEntity(entity: EntityFile, focus: BriefingFocus): boolean {\n const needle = focus.value.toLowerCase();\n if (focus.type === \"person\" && entity.type.toLowerCase() !== \"person\") return false;\n if (focus.type === \"project\" && entity.type.toLowerCase() !== \"project\") return false;\n const haystack = [\n entity.name,\n entity.synthesis || entity.summary || \"\",\n ...entity.facts,\n ...(entity.aliases ?? []),\n ...(entity.structuredSections ?? []).flatMap((section) => [section.title, ...section.facts]),\n ]\n .join(\" \")\n .toLowerCase();\n return haystack.includes(needle);\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Calendar source\n// ──────────────────────────────────────────────────────────────────────────\n\n/**\n * Stub `CalendarSource` backed by a single local file. Supports:\n * - JSON files containing an array of `CalendarEvent` records, OR a wrapper\n * `{ events: CalendarEvent[] }` object.\n * - Minimal ICS (`.ics`) files — extracts `VEVENT` blocks with `SUMMARY`,\n * `DTSTART`, `DTEND`, `LOCATION`, `DESCRIPTION`, `UID`.\n *\n * Real calendar integrations (Google, iCloud, Microsoft) can plug into the\n * same `CalendarSource` interface later.\n */\nexport class FileCalendarSource implements CalendarSource {\n constructor(private readonly filePath: string) {}\n\n async eventsForDate(dateIso: string): Promise<CalendarEvent[]> {\n let raw: string;\n try {\n raw = await readFile(this.filePath, \"utf-8\");\n } catch (err) {\n log.warn(`briefing: calendar source unreadable at ${this.filePath}: ${err}`);\n return [];\n }\n\n const events = this.filePath.toLowerCase().endsWith(\".ics\")\n ? parseIcsEvents(raw)\n : parseJsonEvents(raw);\n\n return events.filter((event) => eventFallsOnDate(event, dateIso));\n }\n}\n\nfunction parseJsonEvents(raw: string): CalendarEvent[] {\n try {\n const parsed = JSON.parse(raw) as unknown;\n const arr = Array.isArray(parsed)\n ? parsed\n : parsed && typeof parsed === \"object\" && Array.isArray((parsed as { events?: unknown }).events)\n ? ((parsed as { events: unknown[] }).events)\n : [];\n const events: CalendarEvent[] = [];\n for (const entry of arr) {\n if (!entry || typeof entry !== \"object\") continue;\n const e = entry as Record<string, unknown>;\n const id = typeof e.id === \"string\" ? e.id : typeof e.uid === \"string\" ? e.uid : cryptoRandomId();\n const title = typeof e.title === \"string\" ? e.title : typeof e.summary === \"string\" ? e.summary : \"\";\n const start = typeof e.start === \"string\" ? e.start : typeof e.dtstart === \"string\" ? e.dtstart : \"\";\n if (!title || !start) continue;\n events.push({\n id,\n title,\n start,\n end: typeof e.end === \"string\" ? e.end : typeof e.dtend === \"string\" ? e.dtend : undefined,\n location: typeof e.location === \"string\" ? e.location : undefined,\n notes: typeof e.notes === \"string\" ? e.notes : typeof e.description === \"string\" ? e.description : undefined,\n });\n }\n return events;\n } catch (err) {\n log.warn(`briefing: calendar JSON parse failed: ${err}`);\n return [];\n }\n}\n\ninterface IcsParsedLine {\n property: string;\n params: Record<string, string>;\n value: string;\n}\n\n/**\n * Parse a single ICS content line into its property, parameters, and value.\n * Returns null if the line is not a well-formed property line.\n *\n * Example:\n * `DTSTART;TZID=America/New_York:20260411T233000`\n * → { property: \"DTSTART\", params: { TZID: \"America/New_York\" }, value: \"20260411T233000\" }\n */\nfunction parseIcsLine(line: string): IcsParsedLine | null {\n // Find the first `:` outside of any parameter value. Per RFC 5545 parameter\n // values may be quoted, but the minimal-parser use case here only needs to\n // handle unquoted TZID values.\n const colonIdx = line.indexOf(\":\");\n if (colonIdx <= 0) return null;\n const head = line.slice(0, colonIdx);\n const value = line.slice(colonIdx + 1).trim();\n // Head is of the form `PROPERTY[;PARAM=val[;PARAM=val]]`.\n const headParts = head.split(\";\");\n const property = headParts[0]!.toUpperCase();\n if (!/^[A-Z0-9-]+$/.test(property)) return null;\n const params: Record<string, string> = {};\n for (let i = 1; i < headParts.length; i++) {\n const segment = headParts[i]!;\n const eqIdx = segment.indexOf(\"=\");\n if (eqIdx <= 0) continue;\n const name = segment.slice(0, eqIdx).toUpperCase();\n let val = segment.slice(eqIdx + 1);\n // Strip surrounding quotes if present (RFC 5545 §3.1).\n if (val.startsWith('\"') && val.endsWith('\"') && val.length >= 2) {\n val = val.slice(1, -1);\n }\n params[name] = val;\n }\n return { property, params, value };\n}\n\ninterface IcsDateField {\n raw: string;\n params: Record<string, string>;\n}\n\n/** @internal — exported for testing only. */\nexport function parseIcsEvents(raw: string): CalendarEvent[] {\n const events: CalendarEvent[] = [];\n // RFC 5545 §3.1 line unfolding: a CRLF (now \\n) followed by a single\n // whitespace character (space or tab) is a fold — remove both characters\n // to join the continuation onto the preceding logical line. This MUST\n // happen after normalising CRLF → \\n and BEFORE splitting on \\n.\n const normalized = raw.replace(/\\r\\n/g, \"\\n\").replace(/\\n[ \\t]/g, \"\");\n const blocks = normalized.split(/BEGIN:VEVENT/i).slice(1);\n for (const block of blocks) {\n const endIdx = block.search(/END:VEVENT/i);\n const body = endIdx === -1 ? block : block.slice(0, endIdx);\n const simpleFields: Record<string, string> = {};\n const dateFields: Record<string, IcsDateField> = {};\n for (const line of body.split(\"\\n\")) {\n const parsed = parseIcsLine(line);\n if (!parsed) continue;\n const { property, params, value } = parsed;\n if (property === \"DTSTART\" || property === \"DTEND\") {\n if (dateFields[property] === undefined) {\n dateFields[property] = { raw: value, params };\n }\n } else if (simpleFields[property] === undefined) {\n simpleFields[property] = value;\n }\n }\n const title = simpleFields.SUMMARY;\n const dtstart = dateFields.DTSTART;\n if (!title || !dtstart) continue;\n const dtend = dateFields.DTEND;\n events.push({\n id: simpleFields.UID ?? cryptoRandomId(),\n title,\n start: normalizeIcsDate(dtstart.raw, dtstart.params),\n end: dtend ? normalizeIcsDate(dtend.raw, dtend.params) : undefined,\n location: simpleFields.LOCATION,\n notes: simpleFields.DESCRIPTION,\n });\n }\n return events;\n}\n\n/**\n * Normalise an ICS date/datetime value (optionally with a `TZID` parameter)\n * into an ISO 8601 string that downstream code can compare unambiguously.\n *\n * Behaviour:\n * - `20260411T150000Z` → `2026-04-11T15:00:00Z`\n * - `20260411` → `2026-04-11T00:00:00Z` (date-only events are day-boundaries)\n * - `20260411T150000` (floating, no Z, no TZID) → `2026-04-11T15:00:00` (floating)\n * - `20260411T233000` with `TZID=America/New_York` → `2026-04-12T03:30:00Z`\n * (applies the zone offset at that wallclock time; DST-aware via Intl)\n * - Unknown TZID falls back to UTC with a logged warning (conservative:\n * the event still appears, but on the UTC date).\n */\nfunction normalizeIcsDate(value: string, params: Record<string, string> = {}): string {\n // Date-time with explicit Z suffix (UTC).\n if (/^\\d{8}T\\d{6}Z$/.test(value)) {\n const y = value.slice(0, 4);\n const m = value.slice(4, 6);\n const d = value.slice(6, 8);\n const hh = value.slice(9, 11);\n const mm = value.slice(11, 13);\n const ss = value.slice(13, 15);\n return `${y}-${m}-${d}T${hh}:${mm}:${ss}Z`;\n }\n // Date-time without Z: may be floating or zoned via TZID.\n if (/^\\d{8}T\\d{6}$/.test(value)) {\n const y = value.slice(0, 4);\n const m = value.slice(4, 6);\n const d = value.slice(6, 8);\n const hh = value.slice(9, 11);\n const mm = value.slice(11, 13);\n const ss = value.slice(13, 15);\n const local = `${y}-${m}-${d}T${hh}:${mm}:${ss}`;\n const tzid = params.TZID;\n if (tzid) {\n const utcIso = icsWallclockToUtc(local, tzid);\n if (utcIso) return utcIso;\n log.warn(\n `briefing: unsupported TZID \"${tzid}\" — treating as UTC for ${local}`,\n );\n return `${local}Z`;\n }\n // No TZID → floating. Downstream compares the date slice directly.\n return local;\n }\n // Date-only (all-day event). Date-only values carry no TZID per RFC 5545.\n if (/^\\d{8}$/.test(value)) {\n return `${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}T00:00:00Z`;\n }\n return value;\n}\n\n/**\n * Convert a wallclock local datetime in a named IANA timezone to a UTC ISO\n * string. Returns null if the timezone is unsupported by the runtime.\n *\n * Implementation note: this is the standard \"invert the formatter\" technique.\n * We treat the local wallclock as though it were UTC, ask the runtime what\n * time that instant shows in the target zone, and the delta is the zone's\n * offset at that wallclock moment (DST-aware).\n */\nfunction icsWallclockToUtc(local: string, tzid: string): string | null {\n const match = local.match(/^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})$/);\n if (!match) return null;\n const [, y, mo, d, hh, mm, ss] = match;\n // Treat the wallclock as UTC for the first probe.\n const naiveUtcMs = Date.UTC(\n Number(y),\n Number(mo) - 1,\n Number(d),\n Number(hh),\n Number(mm),\n Number(ss),\n );\n if (!Number.isFinite(naiveUtcMs)) return null;\n\n let formatter: Intl.DateTimeFormat;\n try {\n formatter = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: tzid,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n hour12: false,\n });\n } catch {\n return null;\n }\n\n const zonedMs = zonedFormatToMs(formatter, new Date(naiveUtcMs));\n if (zonedMs === null) return null;\n // Offset = naiveUtc − zonedAtNaiveUtc (positive for zones east of UTC).\n const offsetMs = naiveUtcMs - zonedMs;\n // Apply the offset once to land on the real UTC instant.\n const realUtcMs = naiveUtcMs + offsetMs;\n // Second pass: offsets can differ when the wallclock crosses a DST boundary.\n const zonedMs2 = zonedFormatToMs(formatter, new Date(realUtcMs));\n if (zonedMs2 !== null) {\n const offsetMs2 = realUtcMs - zonedMs2;\n if (offsetMs2 !== offsetMs) {\n return new Date(naiveUtcMs + offsetMs2).toISOString();\n }\n }\n return new Date(realUtcMs).toISOString();\n}\n\n/**\n * Format a Date in the given timezone and return the absolute ms timestamp\n * of that wallclock time interpreted as if it were UTC. Used only by\n * `icsWallclockToUtc` to compute zone offsets.\n */\nfunction zonedFormatToMs(formatter: Intl.DateTimeFormat, date: Date): number | null {\n const parts = formatter.formatToParts(date);\n const get = (type: string): string | undefined =>\n parts.find((p) => p.type === type)?.value;\n const y = get(\"year\");\n const mo = get(\"month\");\n const d = get(\"day\");\n const hh = get(\"hour\");\n const mm = get(\"minute\");\n const ss = get(\"second\");\n if (!y || !mo || !d || !hh || !mm || !ss) return null;\n // RFC 5545 / Intl edge-case: some runtimes return `hour: \"24\"` for midnight\n // while keeping the same calendar day (instead of returning hour=0 with the\n // next day). Passing 24 straight to Date.UTC would roll the date forward by\n // one day, producing a 24-hour-skewed offset in icsWallclockToUtc and\n // shifting TZID midnight events to the wrong briefing day. Normalise to 0\n // and leave the date component unchanged.\n const normalizedHour = Number(hh) === 24 ? 0 : Number(hh);\n const ms = Date.UTC(Number(y), Number(mo) - 1, Number(d), normalizedHour, Number(mm), Number(ss));\n return Number.isFinite(ms) ? ms : null;\n}\n\n/**\n * Returns true when `isoStr` has an explicit UTC or numeric offset suffix\n * (Z, ±HH:MM, or ±HHMM). Floating datetimes produced by `normalizeIcsDate`\n * have no such suffix.\n */\nfunction isoHasTimezone(isoStr: string): boolean {\n return /(Z|[+-]\\d{2}:?\\d{2})$/.test(isoStr);\n}\n\n/**\n * Parse an ISO datetime string (UTC-aware or floating) to milliseconds since\n * epoch, or `null` if the string is not a valid datetime.\n *\n * - UTC / offset-aware strings are passed directly to `new Date()`.\n * - Floating strings (no timezone suffix) are interpreted as UTC so that\n * interval arithmetic uses the same epoch base as UTC-aware strings.\n * The caller is responsible for using the correct date-boundary constants.\n */\nfunction isoToMs(isoStr: string): number | null {\n if (!isoStr) return null;\n let src = isoStr;\n if (!isoHasTimezone(src)) {\n // Treat floating time as UTC for interval math (append Z).\n src = src + \"Z\";\n }\n const ms = new Date(src).getTime();\n return Number.isFinite(ms) ? ms : null;\n}\n\n/** @internal — exported for testing only. */\nexport function eventFallsOnDate(event: CalendarEvent, dateIso: string): boolean {\n const target = dateIso.slice(0, 10);\n const start = event.start;\n\n // Floating ICS datetime (no Z, no offset): `normalizeIcsDate` produces\n // \"YYYY-MM-DDTHH:MM:SS\" with no timezone. Passing this to `new Date()`\n // causes ECMAScript to parse it as local time, which then round-trips\n // through UTC via `toISOString()` and can shift the calendar date.\n // For floating times we compare date portions directly (no epoch arithmetic).\n const startIsFloating = !isoHasTimezone(start);\n\n if (startIsFloating) {\n // Validate the start timestamp with the same rigour applied to end:\n // 1. Shape check — must match the ISO-8601 date or datetime pattern.\n // 2. Real-date check — round-trip through UTC to reject impossible dates\n // like \"2026-02-30\" that JavaScript silently auto-corrects.\n // 3. Time-component check — reject out-of-range hours/minutes/seconds\n // (e.g. \"2026-04-11T25:99:00\") that JavaScript rolls over to a\n // different day, which would cause the event to be matched against\n // unrelated calendar dates.\n // If start fails any check we skip the event entirely — there is no usable\n // start date to fall back on.\n const startShapeOk =\n typeof start === \"string\" &&\n /^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}(:\\d{2}(\\.\\d+)?)?)?$/.test(start);\n if (!startShapeOk) {\n log.debug(`briefing: skipping calendar event with invalid start value: ${JSON.stringify(start)}`);\n return false;\n }\n const startDateStr = start.slice(0, 10);\n const startDateProbe = new Date(startDateStr + \"T00:00:00Z\");\n if (\n Number.isNaN(startDateProbe.getTime()) ||\n startDateProbe.toISOString().slice(0, 10) !== startDateStr\n ) {\n log.warn(\n `briefing: skipping calendar event \"${event.title}\" with impossible start date ${JSON.stringify(startDateStr)}`,\n );\n return false;\n }\n const startRawTime = start.indexOf(\"T\") !== -1 ? start.slice(start.indexOf(\"T\") + 1) : \"\";\n if (startRawTime !== \"\") {\n const startTimeParts = startRawTime.split(\":\").map(Number);\n const shh = startTimeParts[0] ?? 0;\n const smm = startTimeParts[1] ?? 0;\n const sss = Math.floor(startTimeParts[2] ?? 0);\n if (shh > 23 || smm > 59 || sss > 59) {\n log.warn(\n `briefing: skipping calendar event \"${event.title}\" with out-of-range start time ${JSON.stringify(startRawTime)}`,\n );\n return false;\n }\n }\n\n const startDate = startDateStr;\n const end = event.end;\n\n // Point event (no end) — simple date prefix comparison.\n if (!end) return startDate === target;\n\n // Validate that end is a recognisable ISO-8601 date/datetime string before\n // slicing it for lexicographic comparison. A malformed end (e.g. a JSON\n // feed emitting \"end\": \"invalid\") would otherwise produce a non-date prefix\n // from `end.slice(0, 10)` and cause the event to appear on unrelated days.\n // Fallback: treat the event as a single-day event starting on startDate.\n const endIsValid =\n typeof end === \"string\" &&\n /^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}(:\\d{2}(\\.\\d+)?)?)?$/.test(end);\n if (!endIsValid) {\n log.warn(\n `briefing: event \"${event.title}\" has malformed end timestamp ${JSON.stringify(end)}; treating as single-day event at ${startDate}`,\n );\n // Render the event but only on its start date.\n return startDate === target;\n }\n\n // UhLh: Reject impossible calendar dates that pass the regex (e.g. \"2026-99-99\").\n // The regex only validates the *shape* of the string — it accepts month 99 and\n // day 99. We must additionally verify the date is real by constructing a UTC\n // Date and checking that the ISO round-trip matches the input prefix. If the\n // date is impossible, Date will auto-correct it (e.g. \"2026-01-99\" becomes some\n // later date), so the round-trip will differ. Fall back to single-day semantics.\n const endDate = end.slice(0, 10);\n const endDateProbe = new Date(endDate + \"T00:00:00Z\");\n if (\n Number.isNaN(endDateProbe.getTime()) ||\n endDateProbe.toISOString().slice(0, 10) !== endDate\n ) {\n log.warn(\n `briefing: event \"${event.title}\" has impossible end date ${JSON.stringify(endDate)}; treating as single-day event at ${startDate}`,\n );\n return startDate === target;\n }\n\n // Validate the time components of the end timestamp when present.\n // The regex above only checks the shape (e.g. two digits for hour) but does\n // not enforce numeric ranges. A value like \"2026-04-11T25:99:99\" passes the\n // regex and the date-round-trip check above yet carries an impossible time.\n // JavaScript's Date constructor silently rolls such values over to a later\n // date, which would make the event bleed into unrelated days. Extract the\n // individual time fields and reject anything outside the valid range.\n const rawTime = end.indexOf(\"T\") !== -1 ? end.slice(end.indexOf(\"T\") + 1) : \"\";\n if (rawTime !== \"\") {\n const timeParts = rawTime.split(\":\").map(Number);\n const hh = timeParts[0] ?? 0;\n const mm = timeParts[1] ?? 0;\n // Seconds may carry a fractional component; floor to get the integer part.\n const ss = Math.floor(timeParts[2] ?? 0);\n const timeIsValid = hh <= 23 && mm <= 59 && ss <= 59;\n if (!timeIsValid) {\n log.warn(\n `briefing: event \"${event.title}\" has out-of-range end time ${JSON.stringify(rawTime)}; treating as single-day event at ${startDate}`,\n );\n return startDate === target;\n }\n }\n\n // Span event: include if [start, end) overlaps the target calendar day.\n //\n // We can't use pure YYYY-MM-DD lexicographic comparison because a\n // same-day event (`start=2026-04-11T14:30`, `end=2026-04-11T15:00`)\n // has `startDate === endDate === \"2026-04-11\"`, and a `target < endDate`\n // check would wrongly exclude it. A cross-day event ending at\n // `2026-04-12T00:00:00` (exact midnight) also needs the end day to be\n // treated as exclusive per half-open `[start, end)` semantics.\n //\n // Decide whether the end day is still active on the end date by looking\n // at the time portion: if the end time is strictly after midnight, the\n // event is still running at the start of the end day and should include\n // it; if the end time is exactly midnight, the event ends precisely at\n // the boundary and the end day is excluded. Within-day spans always\n // have a non-zero end time and so correctly include their own date.\n //\n // UhLg: A date-only end value (no \"T\" separator) produces an empty\n // endTime string. The regex above does not match empty string, so\n // endAtExactMidnight would be false and the event would incorrectly\n // appear on the end date. Date-only end values carry [start, end)\n // semantics (the end date is exclusive), so we treat them as midnight.\n const endTime = end.slice(11); // \"HH:MM\", \"HH:MM:SS\", \"HH:MM:SS.mmm\", or \"\" (date-only)\n // Treat any end time that is exactly midnight — or absent (date-only) — as\n // day-exclusive per [start, end) semantics.\n // Cases covered:\n // \"\" — date-only end (UhLg fix: exclusive like midnight)\n // \"00:00\" — HH:MM form (valid floating-time ISO value, no seconds)\n // \"00:00:00\" — HH:MM:SS form\n // \"00:00:00.000...\" — with fractional seconds (any number of trailing zeros)\n // A bare `>` string comparison incorrectly treats \"00:00:00.000\" as > \"00:00:00\"\n // because the fractional suffix makes the string lexicographically longer.\n const endIsDateOnly = endTime === \"\";\n const endAtExactMidnight = endIsDateOnly || /^00(:00){1,2}(\\.0+)?$/.test(endTime);\n const endActiveOnEndDay = !endAtExactMidnight;\n if (endActiveOnEndDay) {\n return startDate <= target && target <= endDate;\n }\n return startDate <= target && target < endDate;\n }\n\n // UTC or offset-aware ISO string: parse and normalise to UTC milliseconds,\n // then check whether the event's [start, end) interval overlaps the target\n // UTC day [dayStart, dayEnd).\n const startMs = isoToMs(start);\n if (startMs === null) {\n log.debug(`briefing: skipping calendar event with invalid start value: ${JSON.stringify(start)}`);\n return false;\n }\n\n // Boundaries of the target UTC day (half-open: [dayStart, dayEnd)).\n const dayStart = Date.UTC(\n Number(target.slice(0, 4)),\n Number(target.slice(5, 7)) - 1,\n Number(target.slice(8, 10)),\n );\n const dayEnd = dayStart + 86_400_000; // +24 h\n\n const end = event.end;\n if (!end) {\n // Point event: included iff start falls within [dayStart, dayEnd).\n return startMs >= dayStart && startMs < dayEnd;\n }\n\n const endMs = isoToMs(end);\n if (endMs === null) {\n // Unparseable end — fall back to point-event semantics.\n return startMs >= dayStart && startMs < dayEnd;\n }\n\n // Interval event: overlaps day iff start < dayEnd AND end > dayStart.\n // Using strict > for end so that an event ending exactly at midnight\n // (dayEnd of previous day) is NOT counted on the next day.\n return startMs < dayEnd && endMs > dayStart;\n}\n\nfunction cryptoRandomId(): string {\n // Keep dependency-free: Math.random is fine for synthetic fixture IDs.\n return `evt-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// buildBriefing\n// ──────────────────────────────────────────────────────────────────────────\n\n/** Dependency-injection hook for LLM follow-up generation (used in tests). */\nexport type BriefingFollowupGenerator = (\n prompt: {\n sections: BriefingSections;\n windowLabel: string;\n maxFollowups: number;\n },\n) => Promise<BriefingFollowup[]>;\n\n/** Options accepted by `buildBriefing`. */\nexport interface BuildBriefingOptions {\n /** Workspace-scoped storage. Tests pass a temp dir. */\n storage: StorageManager;\n /** Parsed window. If omitted, a default 1-day window is used. */\n window?: ParsedBriefingWindow;\n /** Optional focus filter. */\n focus?: BriefingFocus | null;\n /** Optional namespace hint for logging. */\n namespace?: string;\n /** Calendar source. Section omitted entirely when undefined. */\n calendarSource?: CalendarSource;\n /** Maximum LLM follow-ups (0 to disable the section). */\n maxFollowups?: number;\n /** Whether the module is allowed to invoke the Responses API. */\n allowLlm?: boolean;\n /** OpenAI API key. If absent the follow-up section is gracefully omitted. */\n openaiApiKey?: string;\n /** OpenAI-compatible base URL (for Azure or proxied endpoints). */\n openaiBaseUrl?: string;\n /** Model id for the Responses call. */\n model?: string;\n /** Injected follow-up generator. Overrides real LLM call (tests). */\n followupGenerator?: BriefingFollowupGenerator;\n /** Injected \"now\" — makes tests deterministic. */\n now?: Date;\n}\n\nconst MAX_ACTIVE_THREADS = 8;\nconst MAX_RECENT_ENTITIES = 8;\nconst MAX_OPEN_COMMITMENTS = 8;\n\n/**\n * Build the daily context briefing.\n *\n * Never throws on LLM failures — the suggested follow-ups section is simply\n * omitted and `followupsUnavailableReason` is set.\n */\nexport async function buildBriefing(options: BuildBriefingOptions): Promise<BriefingResult> {\n const now = options.now ?? new Date();\n const window = options.window ?? defaultWindow(now);\n const maxFollowups = clampFollowups(options.maxFollowups);\n const focus = options.focus ?? null;\n\n const [allMemories, allEntities] = await Promise.all([\n safeReadMemories(options.storage, window).then(excludeSupportPassportPrivateMemories),\n safeReadEntities(options.storage),\n ]);\n\n const memoriesInWindow = filterMemoriesByWindow(allMemories, window);\n const focusedMemories = focus\n ? memoriesInWindow.filter((m) => focusMatchesMemory(m, focus, options.storage.entityAliases))\n : memoriesInWindow;\n\n const activeThreads = buildActiveThreads(focusedMemories);\n const recentEntities = buildRecentEntities(allEntities, window, focus);\n const openCommitments = buildOpenCommitments(focusedMemories);\n\n const calendarLoadResult = options.calendarSource\n ? await loadTodayCalendar(options.calendarSource, now)\n : undefined;\n\n const calendarSourceErrors: BriefingCalendarSourceError[] =\n calendarLoadResult?.error ? [calendarLoadResult.error] : [];\n\n const sectionsBase: BriefingSections = {\n activeThreads,\n recentEntities,\n openCommitments,\n suggestedFollowups: [],\n todayCalendar: calendarLoadResult?.events,\n };\n\n let followups: BriefingFollowup[] = [];\n let followupsUnavailableReason: string | undefined;\n\n if (maxFollowups === 0 || options.allowLlm === false) {\n followupsUnavailableReason = \"LLM follow-ups disabled by configuration\";\n } else if (!options.openaiApiKey && !options.followupGenerator) {\n followupsUnavailableReason =\n 'no LLM configured for follow-ups (set OPENAI_API_KEY, enable a local LLM, or use modelSource \"gateway\")';\n } else {\n try {\n const generator = options.followupGenerator ?? buildOpenAiFollowupGenerator({\n apiKey: options.openaiApiKey!,\n model: options.model ?? BRIEFING_FOLLOWUP_DEFAULT_MODEL,\n baseURL: options.openaiBaseUrl,\n });\n const generated = await withBriefingFollowupTimeout(\n generator({\n sections: sectionsBase,\n windowLabel: window.label,\n maxFollowups,\n }),\n );\n followups = generated.slice(0, maxFollowups);\n } catch (err) {\n const errMsg = stringifyError(err);\n const modelName = options.model ?? BRIEFING_FOLLOWUP_DEFAULT_MODEL;\n // Detect \"model not found / invalid\" errors from the Responses API and\n // produce a user-friendly message that surfaces the problematic identifier.\n if (\n /model/i.test(errMsg) &&\n (/not found/i.test(errMsg) || /does not exist/i.test(errMsg) || /invalid/i.test(errMsg))\n ) {\n followupsUnavailableReason =\n `configured follow-up model '${modelName}' is not available in the Responses API`;\n } else {\n followupsUnavailableReason = `LLM follow-ups failed: ${errMsg}`;\n }\n log.warn(`briefing: ${followupsUnavailableReason}`);\n }\n }\n\n const sections: BriefingSections = {\n ...sectionsBase,\n suggestedFollowups: followups,\n };\n\n // Drain auto-applied passive-correction notifications (issue #1581). The\n // queue is cleared on read, so each notification surfaces in exactly one\n // briefing. Fail-open: a drain error never blocks the briefing.\n let correctionNotifications: BriefingResult[\"correctionNotifications\"];\n try {\n const drained = await drainPassiveCorrectionNotifications(options.storage.dir);\n if (drained.length > 0) {\n correctionNotifications = drained.map((n) => ({\n planId: n.planId,\n summary: n.summary,\n undoCommand: n.undoCommand,\n createdAt: n.createdAt,\n }));\n }\n } catch (err) {\n log.debug(`briefing: correction notification drain failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);\n }\n\n const windowIso = { from: window.from.toISOString(), to: window.to.toISOString() };\n const markdown = renderBriefingMarkdown({\n sections,\n windowLabel: window.label,\n focus,\n followupsUnavailableReason,\n generatedAt: now,\n namespace: options.namespace,\n correctionNotifications,\n });\n\n const json: Record<string, unknown> = {\n generatedAt: now.toISOString(),\n window: windowIso,\n focus,\n namespace: options.namespace ?? null,\n correctionNotifications: correctionNotifications ?? null,\n sections,\n followupsUnavailableReason: followupsUnavailableReason ?? null,\n calendarSourceErrors: calendarSourceErrors.length > 0 ? calendarSourceErrors : null,\n };\n\n const result: BriefingResult = {\n markdown,\n json,\n sections,\n followupsUnavailableReason,\n window: windowIso,\n ...(correctionNotifications ? { correctionNotifications } : {}),\n };\n\n if (calendarSourceErrors.length > 0) {\n result.calendarSourceErrors = calendarSourceErrors;\n }\n\n return result;\n}\n\nfunction clampFollowups(value: number | undefined): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return 5;\n return Math.max(0, Math.min(10, Math.floor(value)));\n}\n\nfunction defaultWindow(now: Date): ParsedBriefingWindow {\n const parsed = parseBriefingWindow(\"yesterday\", now);\n if (parsed) return parsed;\n return { from: new Date(now.getTime() - DAY_MS), to: now, label: \"yesterday\" };\n}\n\nasync function safeReadEntities(storage: StorageManager): Promise<EntityFile[]> {\n try {\n return await storage.readAllEntityFiles();\n } catch (err) {\n log.warn(`briefing: readAllEntityFiles failed: ${err}`);\n return [];\n }\n}\n\nfunction memoryTimestamp(memory: MemoryFile): number {\n const raw = memory.frontmatter.updated || memory.frontmatter.created;\n if (!raw) return 0;\n const t = Date.parse(raw);\n return Number.isFinite(t) ? t : 0;\n}\n\n/** @internal — exported for testing only. */\nexport function filterMemoriesByWindow(memories: MemoryFile[], window: ParsedBriefingWindow): MemoryFile[] {\n const fromMs = window.from.getTime();\n const toMs = window.to.getTime();\n return memories.filter((m) => {\n // Exclude explicitly retired statuses so commitments overridden within the\n // window don't appear as open. In addition to `superseded` / `archived`\n // (temporal retirement), also exclude `rejected` and `quarantined`, which\n // come from governance/disposition workflows: those memories have been\n // explicitly marked unsafe or invalid and must NOT flow into active\n // threads, open commitments, or follow-up generation, even if they\n // fall within the briefing window. Surfacing them would reintroduce\n // quarantined content into downstream automation as actionable context.\n //\n // `pending_review` memories are awaiting human review — not invalidated —\n // and must be included so reviewers see them in the briefing.\n const status = m.frontmatter.status;\n if (\n status === \"superseded\" ||\n status === \"archived\" ||\n status === \"rejected\" ||\n status === \"quarantined\" ||\n status === \"forgotten\"\n ) {\n return false;\n }\n const ts = memoryTimestamp(m);\n return ts >= fromMs && ts < toMs;\n });\n}\n\n/** @internal — exported for testing only. */\nexport function buildActiveThreads(memories: MemoryFile[]): BriefingActiveThread[] {\n const buckets = new Map<string, BriefingActiveThread>();\n for (const memory of memories) {\n const threadKey = extractThreadKey(memory);\n const updatedAt = memory.frontmatter.updated || memory.frontmatter.created || \"\";\n const existing = buckets.get(threadKey);\n if (!existing || updatedAt > existing.updatedAt) {\n buckets.set(threadKey, {\n id: threadKey,\n title: summarizeContentTitle(memory),\n updatedAt,\n // Always derive reason from the newest memory so the description\n // reflects the most-recent activity type, not the first memory seen.\n reason: describeReason(memory),\n });\n }\n }\n return Array.from(buckets.values())\n .sort((a, b) => {\n if (a.updatedAt > b.updatedAt) return -1;\n if (a.updatedAt < b.updatedAt) return 1;\n // Tiebreaker: lexicographic order by id ensures a deterministic, stable\n // result when multiple threads share the same updatedAt timestamp (e.g.\n // after a batch extraction run).\n return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;\n })\n .slice(0, MAX_ACTIVE_THREADS);\n}\n\nfunction extractThreadKey(memory: MemoryFile): string {\n const entityRef = memory.frontmatter.entityRef?.trim();\n if (entityRef) return `entity:${entityRef}`;\n const tags = memory.frontmatter.tags ?? [];\n const topicTag = tags.find((t) => t.startsWith(\"topic:\"));\n if (topicTag) return topicTag;\n if (tags.length > 0) return `tag:${tags[0]}`;\n return `memory:${memory.frontmatter.id}`;\n}\n\nfunction summarizeContentTitle(memory: MemoryFile): string {\n const firstLine = (memory.content || \"\").split(\"\\n\").find((line) => line.trim().length > 0) ?? \"\";\n const trimmed = firstLine.trim();\n if (trimmed.length === 0) return memory.frontmatter.id;\n return trimmed.length > 120 ? `${trimmed.slice(0, 117)}...` : trimmed;\n}\n\nfunction describeReason(memory: MemoryFile): string {\n const cat = memory.frontmatter.category;\n if (cat === \"commitment\") return \"open commitment\";\n if (cat === \"decision\") return \"recent decision\";\n if (cat === \"correction\") return \"recent correction\";\n return \"recent activity\";\n}\n\n/** @internal — exported for testing only. */\nexport function buildRecentEntities(\n entities: EntityFile[],\n window: ParsedBriefingWindow,\n focus: BriefingFocus | null,\n): BriefingRecentEntity[] {\n const fromMs = window.from.getTime();\n const scored: BriefingRecentEntity[] = [];\n const now = window.to;\n for (const entity of entities) {\n if (focus && !focusMatchesEntity(entity, focus)) continue;\n const toMs = window.to.getTime();\n const updatedMs = entity.updated ? Date.parse(entity.updated) : 0;\n if (!Number.isFinite(updatedMs) || updatedMs < fromMs || updatedMs >= toMs) continue;\n const score = StorageManager.scoreEntity(entity, now);\n scored.push({\n name: entity.name,\n type: entity.type,\n updatedAt: entity.updated,\n score: Number(score.toFixed(4)),\n summary: entity.synthesis || entity.summary,\n });\n }\n return scored\n .sort((a, b) => {\n const scoreDiff = b.score - a.score;\n if (scoreDiff !== 0) return scoreDiff;\n if (a.updatedAt > b.updatedAt) return -1;\n if (a.updatedAt < b.updatedAt) return 1;\n return 0;\n })\n .slice(0, MAX_RECENT_ENTITIES);\n}\n\n/** @internal — exported for testing only. */\nexport function buildOpenCommitments(memories: MemoryFile[]): BriefingOpenCommitment[] {\n const commitments: BriefingOpenCommitment[] = [];\n\n for (const memory of memories) {\n const tags = memory.frontmatter.tags ?? [];\n const isPending = tags.some((t) => t.toLowerCase() === \"pending\");\n const isCommitment = memory.frontmatter.category === \"commitment\";\n const isUnresolvedQuestion = /(?:[??؟]$|\\bfollow[- ]up\\b|\\btodo\\b)/i.test(memory.content);\n\n if (isPending || isCommitment || isUnresolvedQuestion) {\n const kind: BriefingOpenCommitment[\"kind\"] = isCommitment\n ? \"commitment\"\n : isUnresolvedQuestion\n ? \"question\"\n : \"pending_memory\";\n commitments.push({\n id: memory.frontmatter.id,\n kind,\n text: summarizeContentTitle(memory),\n source: memory.frontmatter.source,\n createdAt: memory.frontmatter.created,\n });\n }\n }\n\n return commitments\n .sort((a, b) => {\n // Missing timestamps sort last (highest comparator value).\n if (!a.createdAt && !b.createdAt) return 0;\n if (!a.createdAt) return 1;\n if (!b.createdAt) return -1;\n if (a.createdAt > b.createdAt) return -1;\n if (a.createdAt < b.createdAt) return 1;\n return 0;\n })\n .slice(0, MAX_OPEN_COMMITMENTS);\n}\n\ninterface CalendarLoadResult {\n events: CalendarEvent[] | undefined;\n error: BriefingCalendarSourceError | undefined;\n}\n\nasync function loadTodayCalendar(\n source: CalendarSource,\n now: Date,\n): Promise<CalendarLoadResult> {\n const sourceLabel = (source as { filePath?: string }).filePath ?? \"calendar\";\n try {\n const dateIso = now.toISOString().slice(0, 10);\n const events = await source.eventsForDate(dateIso);\n // Return the events array (possibly empty for a legitimately empty calendar).\n // An empty array is distinct from `undefined`: empty means \"source responded\n // with no events today\"; undefined means \"source failed\".\n return { events, error: undefined };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n log.warn(`briefing: calendar source error (${sourceLabel}): ${message}`);\n // Return undefined events (not []) to signal an error so callers can\n // distinguish \"no events today\" from \"the calendar source threw\".\n return {\n events: undefined,\n error: { source: sourceLabel, error: message },\n };\n }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Follow-ups (Responses API)\n// ──────────────────────────────────────────────────────────────────────────\n\nfunction buildOpenAiFollowupGenerator(cfg: {\n apiKey: string;\n model: string;\n baseURL?: string;\n}): BriefingFollowupGenerator {\n return async ({ sections, windowLabel, maxFollowups }) => {\n // Lazy import keeps the module dependency-free when LLM path is unused.\n const { OpenAI } = (await import(\"openai\")) as {\n OpenAI: new (opts: { apiKey: string; baseURL?: string }) => unknown;\n };\n const clientOpts: { apiKey: string; baseURL?: string } = { apiKey: cfg.apiKey };\n if (cfg.baseURL) clientOpts.baseURL = cfg.baseURL;\n const client = new OpenAI(clientOpts) as {\n responses: {\n create: (args: {\n model: string;\n instructions: string;\n input: string;\n max_output_tokens?: number;\n }) => Promise<{ output_text?: string }>;\n };\n };\n\n const prompt = buildFollowupPrompt(sections, windowLabel, maxFollowups);\n const response = await client.responses.create({\n model: cfg.model,\n instructions: FOLLOWUP_INSTRUCTIONS,\n input: prompt,\n max_output_tokens: 512,\n });\n\n const text = typeof response.output_text === \"string\" ? response.output_text : \"\";\n return parseFollowupResponse(text, maxFollowups);\n };\n}\n\n/**\n * Minimal chat-completion surface shared by `FallbackLlmClient` (gateway\n * model chain) and `LocalLlmClient` (Ollama / OpenAI-compatible local\n * endpoints). Matches `Orchestrator.fastLlmForRerank` so briefing\n * follow-ups can ride the same routing as other fast-tier operations.\n */\nexport interface BriefingChainLlmClient {\n chatCompletion(\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options?: {\n temperature?: number;\n maxTokens?: number;\n timeoutMs?: number;\n operation?: string;\n priority?: \"background\" | \"recall-critical\";\n },\n ): Promise<{ content: string } | null>;\n}\n\n/**\n * Build a follow-up generator backed by the configured LLM chain\n * (gateway model source or local LLM) instead of a direct OpenAI key.\n *\n * Local models frequently wrap JSON in code fences or prose, so the\n * response is run through `extractJsonCandidates` and the first candidate\n * that parses into a valid `{ followups: [...] }` shape wins. Throws when\n * the chain returns nothing or no candidate parses — `buildBriefing`\n * catches and surfaces the message via `followupsUnavailableReason`.\n */\nexport function buildChainFollowupGenerator(\n client: BriefingChainLlmClient,\n): BriefingFollowupGenerator {\n return async ({ sections, windowLabel, maxFollowups }) => {\n const prompt = buildFollowupPrompt(sections, windowLabel, maxFollowups);\n const response = await client.chatCompletion(\n [\n { role: \"system\", content: FOLLOWUP_INSTRUCTIONS },\n { role: \"user\", content: prompt },\n ],\n {\n temperature: 0.2,\n maxTokens: 512,\n operation: \"briefing-followups\",\n priority: \"background\",\n },\n );\n if (!response?.content) {\n throw new Error(\"LLM chain returned no response\");\n }\n const candidates = extractJsonCandidates(response.content);\n let lastError: unknown;\n for (const candidate of candidates) {\n try {\n return parseFollowupResponse(candidate, maxFollowups);\n } catch (err) {\n lastError = err;\n }\n }\n throw new Error(\n `LLM chain response contained no valid followups JSON: ${stringifyError(lastError ?? \"no JSON candidates found\")}`,\n );\n };\n}\n\nconst FOLLOWUP_INSTRUCTIONS = `You suggest short follow-up prompts for a daily context briefing.\nReturn strict JSON of the form { \"followups\": [{ \"text\": \"...\", \"rationale\": \"...\" }] }.\nRules:\n- Never invent facts absent from the input.\n- Keep each \"text\" under 140 characters.\n- Prefer concrete, action-oriented phrasing.\n- Omit duplicates. Avoid filler.`;\n\nfunction buildFollowupPrompt(\n sections: BriefingSections,\n windowLabel: string,\n maxFollowups: number,\n): string {\n const lines: string[] = [];\n lines.push(`Window: ${windowLabel}`);\n lines.push(`Desired follow-ups: ${maxFollowups}`);\n lines.push(\"\");\n lines.push(\"Active threads:\");\n for (const t of sections.activeThreads) lines.push(`- ${t.title} (${t.reason})`);\n lines.push(\"\");\n lines.push(\"Recent entities:\");\n for (const e of sections.recentEntities) lines.push(`- ${e.name} [${e.type}]`);\n lines.push(\"\");\n lines.push(\"Open commitments:\");\n for (const c of sections.openCommitments) lines.push(`- [${c.kind}] ${c.text}`);\n return lines.join(\"\\n\");\n}\n\nfunction parseFollowupResponse(raw: string, max: number): BriefingFollowup[] {\n // JSON.parse throws on invalid JSON — let the caller catch it so the outer\n // try/catch in buildBriefing can set followupsUnavailableReason rather than\n // silently returning an empty array that masks the parse failure.\n const candidates = extractJsonCandidates(raw);\n let lastError: unknown;\n for (const candidate of candidates) {\n try {\n const parsed = JSON.parse(candidate) as unknown;\n if (!parsed || typeof parsed !== \"object\") {\n throw new Error(`LLM returned non-object JSON: ${typeof parsed}`);\n }\n const arr = (parsed as { followups?: unknown }).followups;\n if (!Array.isArray(arr)) {\n throw new Error(`LLM response missing \"followups\" array`);\n }\n const out: BriefingFollowup[] = [];\n for (const entry of arr) {\n if (!entry || typeof entry !== \"object\") continue;\n const text = (entry as Record<string, unknown>).text;\n if (typeof text !== \"string\" || text.trim().length === 0) continue;\n const rationale = (entry as Record<string, unknown>).rationale;\n out.push({\n text: text.trim(),\n rationale: typeof rationale === \"string\" ? rationale.trim() : undefined,\n });\n if (out.length >= max) break;\n }\n return out;\n } catch (err) {\n lastError = err;\n }\n }\n if (lastError) throw lastError;\n throw new Error(\"LLM response contained no JSON candidates\");\n}\n\nfunction stringifyError(err: unknown): string {\n if (err instanceof Error) return err.message;\n return String(err);\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Markdown rendering\n// ──────────────────────────────────────────────────────────────────────────\n\ninterface RenderContext {\n sections: BriefingSections;\n windowLabel: string;\n focus: BriefingFocus | null;\n followupsUnavailableReason?: string;\n generatedAt: Date;\n namespace?: string;\n /** Auto-applied passive corrections drained for this briefing (#1581). */\n correctionNotifications?: BriefingResult[\"correctionNotifications\"];\n}\n\nexport function renderBriefingMarkdown(ctx: RenderContext): string {\n const lines: string[] = [];\n lines.push(`# Daily Context Briefing`);\n lines.push(\"\");\n lines.push(`_Generated ${ctx.generatedAt.toISOString()} (window: ${ctx.windowLabel})_`);\n if (ctx.focus) {\n lines.push(`_Focus: ${ctx.focus.type}:${ctx.focus.value}_`);\n }\n if (ctx.namespace) {\n lines.push(`_Namespace: ${ctx.namespace}_`);\n }\n lines.push(\"\");\n\n if (ctx.correctionNotifications && ctx.correctionNotifications.length > 0) {\n lines.push(`## Memory updates`);\n for (const n of ctx.correctionNotifications) {\n lines.push(`- ✎ ${n.summary} (undo: ${n.undoCommand})`);\n }\n lines.push(\"\");\n }\n\n lines.push(`## Active threads`);\n if (ctx.sections.activeThreads.length === 0) {\n lines.push(`_No active threads in window._`);\n } else {\n for (const t of ctx.sections.activeThreads) {\n lines.push(`- **${t.title}** — ${t.reason} (updated ${t.updatedAt})`);\n }\n }\n lines.push(\"\");\n\n lines.push(`## Recent entities`);\n if (ctx.sections.recentEntities.length === 0) {\n lines.push(`_No entities updated in window._`);\n } else {\n for (const e of ctx.sections.recentEntities) {\n const summary = e.summary ? ` — ${e.summary}` : \"\";\n lines.push(`- **${e.name}** (${e.type}, score ${e.score})${summary}`);\n }\n }\n lines.push(\"\");\n\n lines.push(`## Open commitments`);\n if (ctx.sections.openCommitments.length === 0) {\n lines.push(`_No open commitments detected._`);\n } else {\n for (const c of ctx.sections.openCommitments) {\n lines.push(`- [${c.kind}] ${c.text}`);\n }\n }\n lines.push(\"\");\n\n lines.push(`## Suggested follow-ups`);\n if (ctx.followupsUnavailableReason) {\n lines.push(`_Unavailable: ${ctx.followupsUnavailableReason}_`);\n } else if (ctx.sections.suggestedFollowups.length === 0) {\n lines.push(`_No follow-ups suggested._`);\n } else {\n for (const f of ctx.sections.suggestedFollowups) {\n const rationale = f.rationale ? ` _(${f.rationale})_` : \"\";\n lines.push(`- ${f.text}${rationale}`);\n }\n }\n lines.push(\"\");\n\n if (ctx.sections.todayCalendar !== undefined) {\n lines.push(`## Today's calendar`);\n if (ctx.sections.todayCalendar.length === 0) {\n lines.push(`_No events on the calendar today._`);\n } else {\n for (const ev of ctx.sections.todayCalendar) {\n const end = ev.end ? ` → ${ev.end}` : \"\";\n const loc = ev.location ? ` @ ${ev.location}` : \"\";\n lines.push(`- **${ev.title}** (${ev.start}${end})${loc}`);\n }\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\").trimEnd() + \"\\n\";\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Save helpers\n// ──────────────────────────────────────────────────────────────────────────\n\n/**\n * Resolve the directory where `--save` writes dated briefings.\n * Respects the following precedence:\n * 1. explicit `configOverride` argument\n * 2. `$REMNIC_HOME/briefings/`\n * 3. `$HOME/.remnic/briefings/`\n */\nexport function resolveBriefingSaveDir(\n configOverride: string | null | undefined,\n env?: NodeJS.ProcessEnv,\n): string {\n if (typeof configOverride === \"string\" && configOverride.trim().length > 0) {\n return path.resolve(configOverride.trim());\n }\n const remnicHome = (env === undefined ? readEnvVar(\"REMNIC_HOME\") : env.REMNIC_HOME)?.trim();\n if (remnicHome && remnicHome.length > 0) {\n return path.join(remnicHome, \"briefings\");\n }\n const home = env === undefined\n ? resolveHomeDir()\n : env.HOME ?? env.USERPROFILE ?? os.homedir();\n return path.join(home, \".remnic\", \"briefings\");\n}\n\n/** Format the dated filename for a given briefing. */\nexport function briefingFilename(date: Date, format: \"markdown\" | \"json\" = \"markdown\"): string {\n const day = date.toISOString().slice(0, 10);\n return format === \"json\" ? `${day}.json` : `${day}.md`;\n}\n","/**\n * correction/passive-correction-notifications.ts — JSONL notification queue\n * for auto-applied passive corrections (issue #1581).\n *\n * When passive capture auto-applies a correction, it enqueues a one-line\n * notification here: `✎ Memory updated: <summary> (auto-applied (plan <planId>))`.\n * The plan id is referenced (not a revert command) because `remnic correct`\n * has no `--revert` flag — corrections are page-versioned for manual revert.\n * The next session-start briefing drains the queue ONCE (temp-file-then-rename,\n * rule 54) and clears it, so a notification is shown exactly once.\n *\n * File location: `<storageDir>/state/corrections/notifications.jsonl`\n */\n\nimport { mkdir, readFile, rename, writeFile, unlink } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { serializeMutations } from \"../utils/serialize-mutations.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface PassiveCorrectionNotification {\n planId: string;\n /** One-line human-readable summary of what changed. */\n summary: string;\n /** Undo command the user can run. */\n undoCommand: string;\n createdAt: string;\n}\n\n// ---------------------------------------------------------------------------\n// Path\n// ---------------------------------------------------------------------------\n\nfunction notificationsPath(storageDir: string): string {\n return path.join(storageDir, \"state\", \"corrections\", \"notifications.jsonl\");\n}\n\n// ---------------------------------------------------------------------------\n// Enqueue\n// ---------------------------------------------------------------------------\n\n/**\n * Append a notification line to the JSONL queue. Atomic (rule 54): the line\n * is written to a temp file then renamed over the real file. Multiple\n * notifications accumulate across calls — the queue is drained, not replaced.\n */\nexport async function enqueuePassiveCorrectionNotification(\n storageDir: string,\n notification: PassiveCorrectionNotification,\n): Promise<void> {\n const filePath = notificationsPath(storageDir);\n await serializeMutations(`passive-notification:${filePath}`, async () => {\n // Read existing content (if any) so we accumulate rather than overwrite.\n let existing = \"\";\n try {\n existing = await readFile(filePath, \"utf-8\");\n } catch (err) {\n const code = (err as NodeJS.ErrnoException)?.code;\n if (code !== \"ENOENT\") throw err;\n }\n\n await mkdir(path.dirname(filePath), { recursive: true });\n const line = `${JSON.stringify(notification)}\\n`;\n const content = existing + line;\n\n const tmp = `${filePath}.${process.pid}.${Date.now().toString(36)}.tmp`;\n await writeFile(tmp, content, \"utf-8\");\n await rename(tmp, filePath);\n });\n}\n\n// ---------------------------------------------------------------------------\n// Drain (read + clear — exactly once)\n// ---------------------------------------------------------------------------\n\n/**\n * Read all pending notifications and atomically clear the file. Returns the\n * notifications in insertion order. If the file does not exist, returns [].\n *\n * Drain-once semantics: the file is deleted after reading, so calling this\n * twice in a row returns notifications only the first time.\n */\nexport async function drainPassiveCorrectionNotifications(\n storageDir: string,\n): Promise<PassiveCorrectionNotification[]> {\n const filePath = notificationsPath(storageDir);\n return serializeMutations(`passive-notification:${filePath}`, async () => {\n let raw: string;\n try {\n raw = await readFile(filePath, \"utf-8\");\n } catch (err) {\n const code = (err as NodeJS.ErrnoException)?.code;\n if (code === \"ENOENT\") return [];\n throw err;\n }\n\n const notifications: PassiveCorrectionNotification[] = [];\n for (const line of raw.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n notifications.push(JSON.parse(trimmed) as PassiveCorrectionNotification);\n } catch {\n // Skip malformed lines (rule 34 — best-effort, never crash a briefing).\n continue;\n }\n }\n\n // Clear the file atomically (delete is atomic enough for this use case —\n // the worst case is a duplicate notification, never a lost one, because\n // the read already captured the content).\n try {\n await unlink(filePath);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException)?.code;\n if (code !== \"ENOENT\") throw err;\n }\n\n return notifications;\n });\n}\n"],"mappings":"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","names":["readFile","path","from","readFile","end","path"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/offline-sync.ts"],"sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport {\n lstat,\n mkdir,\n open,\n readdir,\n readFile,\n rename,\n rm,\n stat,\n unlink,\n utimes,\n writeFile,\n} from \"node:fs/promises\";\nimport type { Stats } from \"node:fs\";\nimport path from \"node:path\";\nimport {\n DEFAULT_TRANSFER_EXCLUDE_DIRS,\n} from \"./transfer/exclusions.js\";\nimport {\n prepareSafeArchiveRoot,\n resolveSafeArchiveTarget,\n sha256Bytes,\n validateArchiveRelativePath,\n type SafeArchiveRoot,\n} from \"./transfer/fs-utils.js\";\nimport { parseFlexibleIsoTimestamp } from \"./utils/iso-timestamp.js\";\nimport { EmbeddingIndexStorageError } from \"./embedding-index-storage.js\";\nimport { isEmbeddingGenerationMarkerPath, matchesOfflineSyncDefaultExclude } from \"./offline-sync-exclude-globs.js\";\nimport { isNotFoundError } from \"./utils/errno.js\";\nimport { isMacOsReplicationJunkBasename } from \"./utils/macos-replication-junk.js\";\nimport {\n applyIncomingEmbeddingGenerations,\n assertEmbeddingGenerationStillIncluded,\n advanceEmbeddingGenerationMarker,\n computeOmittedEmbeddingGenerationPaths,\n divergedEmbeddingGenerationDeferrals,\n embeddingGenerationMembership,\n isEmbeddingGenerationDirPath,\n isPathInOmittedEmbeddingGeneration,\n} from \"./offline-sync-embedding-generation.js\";\nimport {\n applyChangesetEmbeddingGenerations,\n normalizeChangesetGenerations,\n type OfflineSyncChangesetGeneration,\n} from \"./offline-sync-changeset-generations.js\";\nimport { withEmbeddingGenerationLock, withEmbeddingGenerationLockIter } from \"./embedding-generation-lock.js\";\nimport {\n isCanonicalRuntimeStatePath,\n shouldDeleteAbsentIncomingOfflineRuntimeFile,\n shouldPreferIncomingOfflineRuntimeFile,\n} from \"./offline-sync-runtime-state.js\";\nexport { shouldPreferIncomingOfflineRuntimeFile } from \"./offline-sync-runtime-state.js\";\nexport { computeOmittedEmbeddingGenerationPaths } from \"./offline-sync-embedding-generation.js\";\nexport type { OfflineSyncChangesetGeneration } from \"./offline-sync-changeset-generations.js\";\nexport {\n compileOfflineSyncExcludeGlobs,\n globToRegExp,\n parseOfflineSyncExcludes,\n} from \"./offline-sync-exclude-globs.js\";\nimport {\n isEncryptedOfflineSyncFile,\n readPlainOfflineSyncFileChunk,\n sha256OfflineSyncFile,\n shouldExcludeOfflineSyncFile,\n type OfflineSyncExcludeFile,\n type OfflineSyncFileTarget,\n plainFileDigest,\n SYNC_INTERNAL_DIR,\n setSafeFileMtime,\n assertNonNegativeFinite,\n assertOfflineSyncMtimeMs,\n OFFLINE_SYNC_FAST_BASE_MTIME_TOLERANCE_MS,\n} from \"./offline-sync-file-io.js\";\nimport { CENSUS_MAX_MTIME_MS, isSha256Hex } from \"./census-validation.js\";\nimport {\n cleanupOfflineUpload,\n digestOfflineUploadStagingContent,\n pruneOfflineUploadStaging,\n writeOfflineUploadChunk,\n writeSafeFileFromUpload,\n hashText,\n type OfflineUploadStaging,\n} from \"./offline-sync-upload-staging.js\";\nexport type { OfflineSyncExcludeFile, OfflineSyncFileTarget } from \"./offline-sync-file-io.js\";\n\nexport const OFFLINE_SYNC_SNAPSHOT_FORMAT = \"remnic.offline-sync.snapshot.v1\";\nexport const OFFLINE_SYNC_CHANGESET_FORMAT = \"remnic.offline-sync.changeset.v1\";\nexport const OFFLINE_SYNC_STATE_VERSION = 1;\nexport const OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES = 64 * 1024 * 1024;\nexport const OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES = 8 * 1024 * 1024;\nexport const OFFLINE_SYNC_APPLY_MAX_BODY_BYTES = 16 * 1024 * 1024;\nexport const OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES = 64 * 1024 * 1024;\nexport const OFFLINE_SYNC_MAX_MTIME_MS = CENSUS_MAX_MTIME_MS;\n\nexport interface OfflineSyncFileState {\n path: string;\n sha256: string;\n /** Byte length of the transferable content, after any readFile hook such as secure-store decryption. */\n bytes: number;\n mtimeMs: number;\n}\n\nexport interface OfflineSyncFileRecord extends OfflineSyncFileState {\n contentBase64?: string;\n}\n\nexport interface OfflineSyncFileDigest {\n sha256: string;\n bytes: number;\n}\n\nexport interface OfflineSyncDeletionRevision {\n path: string;\n mtimeMs: number;\n}\n\nexport interface OfflineSyncSnapshot {\n format: typeof OFFLINE_SYNC_SNAPSHOT_FORMAT;\n schemaVersion: 1;\n createdAt: string;\n sourceId: string;\n includeTranscripts: boolean;\n files: OfflineSyncFileRecord[];\n deletions?: OfflineSyncDeletionRevision[];\n /**\n * Embedding generation dirs whose on-disk members were ALL omitted from\n * `files` because a push filter excluded at least one member (PR #3148\n * round 4). Their absence here is NOT a delete instruction: a receiver\n * keeps its local copy and its base entries until the generation is\n * pushed unfiltered or genuinely deleted with deletion metadata.\n */\n omittedEmbeddingGenerationDirs?: string[];\n}\n\nexport type OfflineSyncChange =\n | {\n type: \"upsert\";\n path: string;\n baseSha256?: string;\n file: OfflineSyncFileRecord & { contentBase64: string };\n }\n | {\n type: \"delete\";\n path: string;\n baseSha256: string;\n mtimeMs?: number;\n };\n\nexport interface OfflineSyncChangeset {\n format: typeof OFFLINE_SYNC_CHANGESET_FORMAT;\n schemaVersion: 1;\n createdAt: string;\n sourceId: string;\n includeTranscripts: boolean;\n changes: OfflineSyncChange[];\n /**\n * Complete post-change membership of every embedding generation the\n * changeset touches (issue #3150). Absent on legacy senders: receivers\n * defer manifest-less shard upserts as conflicts instead of publishing a\n * mixed generation.\n */\n embeddingGenerations?: OfflineSyncChangesetGeneration[];\n}\n\nexport interface OfflineSyncState {\n version: typeof OFFLINE_SYNC_STATE_VERSION;\n remoteId: string;\n namespace?: string;\n includeTranscripts: boolean;\n lastSyncedAt: string;\n baseFiles: OfflineSyncFileState[];\n}\n\nexport interface OfflineSyncConflict {\n path: string;\n reason:\n | \"both_modified\"\n | \"local_deleted_remote_modified\"\n | \"local_modified_remote_deleted\"\n | \"remote_exists_for_local_create\"\n | \"remote_changed_for_local_update\"\n | \"remote_deleted_for_local_update\"\n | \"remote_changed_for_local_delete\"\n // Changeset generation deferrals (#3150): the receiver refused a whole\n // embedding generation; surfaced as conflicts so the push side never\n // checkpoints it as applied.\n | \"embedding_generation_diverged\"\n | \"embedding_generation_manifest_required\";\n baseSha256?: string;\n localSha256?: string;\n incomingSha256?: string;\n conflictPath?: string;\n}\n\nexport interface OfflineSyncApplySnapshotResult {\n upserted: number;\n deleted: number;\n skipped: number;\n pendingLocal: number;\n conflicts: OfflineSyncConflict[];\n nextBaseFiles: OfflineSyncFileState[];\n}\n\nexport interface OfflineSyncApplyChangesetResult {\n appliedUpserts: number;\n appliedDeletes: number;\n skipped: number;\n conflicts: OfflineSyncConflict[];\n currentFiles: OfflineSyncFileState[];\n currentFilesComplete?: boolean;\n}\n\nexport interface OfflineSyncChangesetSummary {\n upserts: number;\n deletes: number;\n total: number;\n}\n\nexport interface OfflineSyncFileDeleteTarget extends OfflineSyncFileTarget {\n mtimeMs?: number;\n}\n\nexport type OfflineSyncRecordDeletionRevision = (\n target: OfflineSyncFileDeleteTarget & { mtimeMs: number },\n) => Promise<void>;\n\nexport interface OfflineSyncFileWriteTarget extends OfflineSyncFileTarget {\n content: Buffer;\n}\n\nexport interface OfflineSyncFileWriteChunksTarget extends OfflineSyncFileTarget {\n chunks: AsyncIterable<Buffer>;\n}\n\nexport interface OfflineSyncFileStagingWriteTarget extends OfflineSyncFileWriteTarget {\n /**\n * ABSOLUTE final path whose canonical AAD the staged ciphertext binds\n * (secure-store deployments): the offline-sync embedding generation\n * transaction stages under a staging dir and publishes by rename, so the\n * ciphertext must decrypt at the FINAL path. The AAD derives through the\n * same filePathAad logic as ordinary reads (platform-consistent).\n */\n finalAadFilePath?: string;\n}\n\nexport interface OfflineSyncFileStagingReadTarget extends OfflineSyncFileTarget {\n /** See {@link OfflineSyncFileStagingWriteTarget.finalAadFilePath}. */\n finalAadFilePath?: string;\n}\n\nexport interface OfflineSyncFileContentChunk extends Omit<OfflineSyncFileState, \"sha256\"> {\n sha256?: string;\n offset: number;\n chunkBytes: number;\n content: Buffer;\n}\n\nexport interface OfflineSyncApplyFileContentChunkResult {\n path: string;\n sha256: string;\n bytes: number;\n mtimeMs: number;\n offset: number;\n chunkBytes: number;\n done: boolean;\n applied: boolean;\n skipped: boolean;\n conflict?: OfflineSyncConflict;\n currentFile?: OfflineSyncFileState;\n}\n\ninterface OfflineSyncFileRecordOptions {\n root: SafeArchiveRoot;\n relPath: string;\n filePath: string;\n includeContent: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n signal?: AbortSignal;\n}\n\nconst OFFLINE_SYNC_FAST_BASE_CTIME_TOLERANCE_MS = 1;\nconst EXCLUDED_FILE_NAMES = new Set([\n \".sync-state.json\",\n]);\n\nconst EXCLUDED_FILE_PREFIXES = [\n \".remnic-sync.\",\n \".remnic-sync-state.\",\n];\n\n/**\n * Convert a tiny subset of glob syntax (`*`, `**`, `?`, literal text) into a\n * regular expression anchored at the start and end of the input. The matcher\n * is intentionally narrow — it is only used for operator-supplied\n * `offlineSyncExcludes` entries, not for full shell-style globbing.\n * `*` and `?` match within a single path segment. `**` is cross-segment\n * wherever it appears: a `star-star-slash` prefix (leading or embedded)\n * matches zero or more whole segments, and a trailing `dir/star-star`\n * matches everything under `dir/` at any depth.\n */\n\n\nfunction sha256Buffer(buffer: Buffer): { sha256: string; bytes: number } {\n return sha256Bytes(buffer);\n}\n\nfunction throwIfOfflineSyncAborted(signal: AbortSignal | undefined): void {\n if (!signal?.aborted) return;\n throw new Error(\"offline sync request aborted\");\n}\n\nfunction compareByPath<T extends { path: string }>(left: T, right: T): number {\n return left.path.localeCompare(right.path);\n}\n\nfunction assertSha256(value: unknown, field: string): string {\n if (!isSha256Hex(value)) {\n throw new Error(`${field} must be a 64-character sha256 hex string`);\n }\n return value.toLowerCase();\n}\n\nfunction assertNonNegativeInteger(value: unknown, field: string): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value) ||\n !Number.isInteger(value) ||\n value < 0\n ) {\n throw new Error(`${field} must be a non-negative integer`);\n }\n return value;\n}\n\n\n\nfunction assertBoolean(value: unknown, field: string): boolean {\n if (typeof value !== \"boolean\") {\n throw new Error(`${field} must be a boolean`);\n }\n return value;\n}\n\nfunction normalizeSourceId(value: unknown, field: string): string {\n if (typeof value !== \"string\" || value.trim().length === 0 || value.length > 512) {\n throw new Error(`${field} must be a non-empty string no longer than 512 characters`);\n }\n return value.trim();\n}\n\nfunction normalizeFileState(input: unknown, fieldPrefix: string): OfflineSyncFileState {\n if (!input || typeof input !== \"object\" || Array.isArray(input)) {\n throw new Error(`${fieldPrefix} must be an object`);\n }\n const obj = input as Record<string, unknown>;\n const relPath = normalizeRelativePath(obj.path, `${fieldPrefix}.path`);\n return {\n path: relPath,\n sha256: assertSha256(obj.sha256, `${fieldPrefix}.sha256`),\n bytes: assertNonNegativeInteger(obj.bytes, `${fieldPrefix}.bytes`),\n mtimeMs: assertOfflineSyncMtimeMs(obj.mtimeMs, `${fieldPrefix}.mtimeMs`),\n };\n}\n\nfunction normalizeFileRecord(\n input: unknown,\n fieldPrefix: string,\n requireContent: boolean,\n): OfflineSyncFileRecord {\n const state = normalizeFileState(input, fieldPrefix);\n const obj = input as Record<string, unknown>;\n const contentBase64 = obj.contentBase64;\n if (requireContent && typeof contentBase64 !== \"string\") {\n throw new Error(`${fieldPrefix}.contentBase64 is required`);\n }\n if (contentBase64 !== undefined && typeof contentBase64 !== \"string\") {\n throw new Error(`${fieldPrefix}.contentBase64 must be a base64 string`);\n }\n return {\n ...state,\n ...(contentBase64 !== undefined ? { contentBase64 } : {}),\n };\n}\n\nfunction normalizeFileStates(input: readonly unknown[] | undefined): OfflineSyncFileState[] {\n if (!input) return [];\n if (!Array.isArray(input)) {\n throw new Error(\"baseFiles must be an array\");\n }\n return input.map((entry, index) => normalizeFileState(entry, `baseFiles[${index}]`));\n}\n\nfunction normalizeDeletionRevisions(\n input: unknown,\n fieldPrefix: string,\n): OfflineSyncDeletionRevision[] | undefined {\n if (input === undefined) return undefined;\n if (!Array.isArray(input)) {\n throw new Error(`${fieldPrefix} must be an array`);\n }\n const deletions = input.map((entry, index): OfflineSyncDeletionRevision => {\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) {\n throw new Error(`${fieldPrefix}[${index}] must be an object`);\n }\n const obj = entry as Record<string, unknown>;\n return {\n path: normalizeRelativePath(obj.path, `${fieldPrefix}[${index}].path`),\n mtimeMs: assertOfflineSyncMtimeMs(obj.mtimeMs, `${fieldPrefix}[${index}].mtimeMs`),\n };\n });\n assertUniquePaths(deletions, fieldPrefix);\n return deletions.sort(compareByPath);\n}\n\nfunction snapshotBuilderDeletions(options: {\n deletions?: readonly OfflineSyncDeletionRevision[];\n files: readonly OfflineSyncFileState[];\n paths?: readonly string[];\n includeTranscripts: boolean;\n excludeNodeLocalState?: boolean;\n userExcludeRegexps?: readonly RegExp[];\n /** Generation dirs omitted by the push enumeration (PR #3148): revisions\n * for ANY member — including already-absent ones — are suppressed, so a\n * filtered generation can never be announced as deleted. */\n omittedGenerationDirs?: ReadonlySet<string>;\n}): OfflineSyncDeletionRevision[] | undefined {\n const deletions = normalizeDeletionRevisions(options.deletions, \"deletions\");\n if (deletions === undefined) return undefined;\n if (deletions.length === 0) return deletions;\n const presentPaths = new Set(options.files.map((file) => file.path.toLowerCase()));\n const scopedPaths = options.paths\n ? new Set(options.paths.map((relPath) => relPath.toLowerCase()))\n : undefined;\n return deletions.filter((deletion) =>\n (scopedPaths === undefined || scopedPaths.has(deletion.path.toLowerCase())) &&\n !presentPaths.has(deletion.path.toLowerCase()) &&\n !isDeletionInOmittedGeneration(deletion.path, options.omittedGenerationDirs) &&\n !(options.excludeNodeLocalState === false\n ? shouldExcludeRelPath(deletion.path, options.includeTranscripts)\n : shouldExcludePushRelPath(\n deletion.path,\n options.includeTranscripts,\n options.userExcludeRegexps,\n )));\n}\n\nfunction isDeletionInOmittedGeneration(\n relPath: string,\n omittedGenerationDirs: ReadonlySet<string> | undefined,\n): boolean {\n if (!omittedGenerationDirs || omittedGenerationDirs.size === 0) return false;\n const membership = embeddingGenerationMembership(relPath);\n return membership !== null && omittedGenerationDirs.has(membership.shardDir);\n}\n\nexport async function filterOfflineSyncDeletionRevisions(options: {\n root: string;\n deletions: readonly OfflineSyncDeletionRevision[];\n includeTranscripts?: boolean;\n userExcludeRegexps?: readonly RegExp[];\n excludeFile?: OfflineSyncExcludeFile;\n}): Promise<OfflineSyncDeletionRevision[]> {\n const deletions = normalizeDeletionRevisions(options.deletions, \"deletions\");\n if (deletions === undefined) throw new Error(\"deletions must be an array\");\n if (deletions.length === 0) return deletions;\n const root = await prepareSafeArchiveRoot(\n path.resolve(options.root),\n \"filterOfflineSyncDeletionRevisions\",\n \"root\",\n );\n const includeTranscripts = options.includeTranscripts !== false;\n const omission = await computeOmittedEmbeddingGenerationPaths({\n rootAbs: root.abs,\n userExcludeRegexps: options.userExcludeRegexps,\n excludeFile: options.excludeFile,\n isExcludedRelPath: (relPath) =>\n shouldExcludePushRelPath(relPath, includeTranscripts, options.userExcludeRegexps),\n });\n const omittedDirs = new Set(omission.omittedDirs);\n const filtered: OfflineSyncDeletionRevision[] = [];\n for (const deletion of deletions) {\n if (\n shouldExcludePushRelPath(deletion.path, includeTranscripts, options.userExcludeRegexps) ||\n isDeletionInOmittedGeneration(deletion.path, omittedDirs)\n ) {\n continue;\n }\n const filePath = path.join(root.abs, ...deletion.path.split(\"/\"));\n const present = await lstat(filePath).then(\n () => true,\n (error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw error;\n },\n );\n if (!present) filtered.push(deletion);\n }\n return filtered;\n}\n\nexport function normalizeOfflineSyncSnapshot(\n input: unknown,\n options: { requireContent?: boolean } = {},\n): OfflineSyncSnapshot {\n if (!input || typeof input !== \"object\" || Array.isArray(input)) {\n throw new Error(\"offline sync snapshot must be an object\");\n }\n const obj = input as Record<string, unknown>;\n if (obj.format !== OFFLINE_SYNC_SNAPSHOT_FORMAT) {\n throw new Error(`offline sync snapshot format must be ${OFFLINE_SYNC_SNAPSHOT_FORMAT}`);\n }\n if (obj.schemaVersion !== 1) {\n throw new Error(\"offline sync snapshot schemaVersion must be 1\");\n }\n const createdAt = normalizeIsoString(obj.createdAt, \"createdAt\");\n const sourceId = normalizeSourceId(obj.sourceId, \"sourceId\");\n const includeTranscripts = assertBoolean(obj.includeTranscripts, \"includeTranscripts\");\n if (!Array.isArray(obj.files)) {\n throw new Error(\"offline sync snapshot files must be an array\");\n }\n const files = obj.files\n .map((entry, index) =>\n normalizeFileRecord(entry, `files[${index}]`, options.requireContent === true))\n .filter((file) => !shouldIgnoreIncomingRuntimePath(file.path))\n .sort(compareByPath);\n const deletions = normalizeDeletionRevisions(obj.deletions, \"deletions\")\n ?.filter((deletion) => !shouldIgnoreIncomingRuntimePath(deletion.path));\n const entries = deletions && deletions.length > 0 ? [...files, ...deletions] : files;\n assertUniquePaths(entries, \"offline sync snapshot\");\n if (!includeTranscripts) {\n const transcriptPath = entries\n .find((entry) => entry.path.split(\"/\")[0] === \"transcripts\")?.path;\n if (transcriptPath) {\n throw new Error(\n `offline sync snapshot includeTranscripts is false but contains transcript path: ${transcriptPath}`,\n );\n }\n }\n const excludedPath = entries\n .find((entry) => shouldExcludeRelPath(entry.path, true))?.path;\n if (excludedPath) {\n throw new Error(`offline sync snapshot contains excluded path: ${excludedPath}`);\n }\n let omittedEmbeddingGenerationDirs: string[] | undefined;\n if (obj.omittedEmbeddingGenerationDirs !== undefined) {\n if (!Array.isArray(obj.omittedEmbeddingGenerationDirs)) {\n throw new Error(\"offline sync snapshot omittedEmbeddingGenerationDirs must be an array\");\n }\n const seenDirs = new Set<string>();\n for (const [index, entry] of obj.omittedEmbeddingGenerationDirs.entries()) {\n if (\n typeof entry !== \"string\" ||\n !isEmbeddingGenerationDirPath(entry) ||\n seenDirs.has(entry)\n ) {\n throw new Error(\n `omittedEmbeddingGenerationDirs[${index}] must be a unique canonical embeddings generation dir`,\n );\n }\n seenDirs.add(entry);\n }\n omittedEmbeddingGenerationDirs = [...seenDirs].sort((left, right) => left.localeCompare(right));\n }\n return {\n format: OFFLINE_SYNC_SNAPSHOT_FORMAT,\n schemaVersion: 1,\n createdAt,\n sourceId,\n includeTranscripts,\n files,\n ...(deletions === undefined ? {} : { deletions }),\n ...(omittedEmbeddingGenerationDirs === undefined ? {} : { omittedEmbeddingGenerationDirs }),\n };\n}\n\nexport function normalizeOfflineSyncChangeset(\n input: unknown,\n): OfflineSyncChangeset {\n if (!input || typeof input !== \"object\" || Array.isArray(input)) {\n throw new Error(\"offline sync changeset must be an object\");\n }\n const obj = input as Record<string, unknown>;\n if (obj.format !== OFFLINE_SYNC_CHANGESET_FORMAT) {\n throw new Error(`offline sync changeset format must be ${OFFLINE_SYNC_CHANGESET_FORMAT}`);\n }\n if (obj.schemaVersion !== 1) {\n throw new Error(\"offline sync changeset schemaVersion must be 1\");\n }\n const createdAt = normalizeIsoString(obj.createdAt, \"createdAt\");\n const sourceId = normalizeSourceId(obj.sourceId, \"sourceId\");\n const includeTranscripts = assertBoolean(obj.includeTranscripts, \"includeTranscripts\");\n if (!Array.isArray(obj.changes)) {\n throw new Error(\"offline sync changeset changes must be an array\");\n }\n const changes = obj.changes.map((entry, index): OfflineSyncChange => {\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) {\n throw new Error(`changes[${index}] must be an object`);\n }\n const change = entry as Record<string, unknown>;\n const type = change.type;\n const relPath = normalizeRelativePath(change.path, `changes[${index}].path`);\n if (type === \"upsert\") {\n const file = normalizeFileRecord(\n change.file,\n `changes[${index}].file`,\n true,\n ) as OfflineSyncFileRecord & { contentBase64: string };\n if (file.path !== relPath) {\n throw new Error(`changes[${index}].file.path must match changes[${index}].path`);\n }\n const baseSha256 =\n change.baseSha256 === undefined\n ? undefined\n : assertSha256(change.baseSha256, `changes[${index}].baseSha256`);\n return {\n type: \"upsert\",\n path: relPath,\n ...(baseSha256 ? { baseSha256 } : {}),\n file,\n };\n }\n if (type === \"delete\") {\n const mtimeMs = change.mtimeMs === undefined\n ? undefined\n : assertOfflineSyncMtimeMs(change.mtimeMs, `changes[${index}].mtimeMs`);\n return {\n type: \"delete\",\n path: relPath,\n baseSha256: assertSha256(change.baseSha256, `changes[${index}].baseSha256`),\n ...(mtimeMs === undefined ? {} : { mtimeMs }),\n };\n }\n throw new Error(`changes[${index}].type must be \"upsert\" or \"delete\"`);\n }).filter((change) => !shouldIgnoreIncomingRuntimePath(change.path));\n assertUniquePaths(changes, \"offline sync changeset\");\n if (!includeTranscripts) {\n const transcriptPath = changes.find((change) => change.path.split(\"/\")[0] === \"transcripts\")?.path;\n if (transcriptPath) {\n throw new Error(\n `offline sync changeset includeTranscripts is false but contains transcript path: ${transcriptPath}`,\n );\n }\n }\n const excludedPath = changes.find((change) => shouldExcludeRelPath(change.path, true))?.path;\n if (excludedPath) {\n throw new Error(`offline sync changeset contains excluded path: ${excludedPath}`);\n }\n const embeddingGenerations = normalizeChangesetGenerations(obj.embeddingGenerations, changes);\n return {\n format: OFFLINE_SYNC_CHANGESET_FORMAT,\n schemaVersion: 1,\n createdAt,\n sourceId,\n includeTranscripts,\n changes: changes.sort(compareByPath),\n ...(embeddingGenerations === undefined ? {} : { embeddingGenerations }),\n };\n}\n\nfunction normalizeIsoString(input: unknown, field: string): string {\n if (typeof input !== \"string\" || input.trim().length === 0) {\n throw new Error(`${field} must be an ISO timestamp string`);\n }\n const parsed = parseFlexibleIsoTimestamp(input.trim());\n if (parsed === null) {\n throw new Error(`${field} must be a parseable ISO timestamp`);\n }\n return new Date(parsed).toISOString();\n}\n\nfunction normalizeRelativePath(input: unknown, field: string): string {\n if (typeof input !== \"string\") {\n throw new Error(`${field} must be a POSIX relative path string`);\n }\n return validateArchiveRelativePath(input, field);\n}\n\nfunction assertUniquePaths(entries: readonly { path: string }[], context: string): void {\n const seen = new Set<string>();\n for (const entry of entries) {\n const key = entry.path.toLowerCase();\n if (seen.has(key)) {\n throw new Error(`${context} contains duplicate path: ${entry.path}`);\n }\n seen.add(key);\n }\n}\n\nexport function isInternalRemnicStatePath(relPosix: string): boolean {\n const normalized = relPosix.includes(\"\\\\\") ? relPosix.replaceAll(\"\\\\\", \"/\") : relPosix;\n return normalized === \".remnic\"\n || normalized.startsWith(\".remnic/\")\n || normalized.endsWith(\"/.remnic\")\n || normalized.includes(\"/.remnic/\");\n}\n\nfunction shouldExcludeRelPath(relPosix: string, includeTranscripts: boolean): boolean {\n if (isInternalRemnicStatePath(relPosix)) return true;\n const parts = relPosix.split(\"/\");\n if (parts.some((part) => DEFAULT_TRANSFER_EXCLUDE_DIRS.has(part))) return true;\n if (parts.some((part) => part === SYNC_INTERNAL_DIR)) return true;\n if (!includeTranscripts && parts[0] === \"transcripts\") return true;\n const basename = parts[parts.length - 1] ?? \"\";\n if (parts.some((part) => isMacOsReplicationJunkBasename(part))) return true;\n if (isCanonicalRuntimeStatePath(parts) && basename.includes(\".tmp-\")) return true;\n if (EXCLUDED_FILE_NAMES.has(basename)) return true;\n if (EXCLUDED_FILE_PREFIXES.some((prefix) => basename.startsWith(prefix))) return true;\n return false;\n}\n\n/**\n * Push-side variant of `shouldExcludeRelPath` for issue #1786. Combines the\n * legacy structural exclude (private dirs, sync internal, tmp runtime state,\n * excluded file names/prefixes) with the new push-only exclusion layers:\n * - the `state/*.sqlite`, `state/index_tags.json`, etc. defaults that\n * describe node-local runtime state each node rebuilds from synced\n * records, and\n * - operator-supplied `offlineSyncExcludes` regexps.\n *\n * Used ONLY by push-side enumeration/validation paths. Apply-side callers\n * must use the legacy `shouldExcludeRelPath` so a remote snapshot containing\n * `state/lcm.sqlite` can still be accepted on first sync -- the remote's\n * view is authoritative for that file until the local LCM is bootstrapped.\n */\nfunction shouldExcludePushRelPath(\n relPosix: string,\n includeTranscripts: boolean,\n userExcludeRegexps?: readonly RegExp[],\n): boolean {\n if (shouldExcludeRelPath(relPosix, includeTranscripts)) return true;\n // Issue #1786: node-local runtime state (live sqlite, derived indexes,\n // per-node governance run logs) is rebuilt by each node, never synced.\n if (matchesOfflineSyncDefaultExclude(relPosix)) return true;\n if (userExcludeRegexps && userExcludeRegexps.some((re) => re.test(relPosix))) return true;\n return false;\n}\n\n// Precompiled once at module load — this check sits on the hot\n// enumeration path for every walked file (Kilo review, PR #1793).\n\n\n/**\n * Compile operator-supplied `offlineSyncExcludes` glob strings into a\n * pre-validated array of regular expressions. Empty input is allowed and\n * returns an empty list. Throws on any invalid entry — callers should treat\n * a thrown error as a fatal configuration mistake and refuse to start the\n * sync run rather than silently dropping the bad entry.\n */\n\nfunction shouldIgnoreIncomingRuntimePath(relPosix: string): boolean {\n if (isInternalRemnicStatePath(relPosix)) return true;\n const parts = relPosix.split(\"/\");\n const basename = parts[parts.length - 1] ?? \"\";\n // Drop Finder metadata before the structural-exclude throw. An older\n // peer snapshot that still lists `._*` or `.DS_Store` — including a file\n // nested under a junk directory — must not fail the whole pull; those\n // paths are never written.\n if (parts.some((part) => isMacOsReplicationJunkBasename(part))) return true;\n return isCanonicalRuntimeStatePath(parts) && basename.includes(\".tmp-\");\n}\n\nfunction filterBaseFilesForMode(\n files: readonly OfflineSyncFileState[],\n includeTranscripts: boolean,\n): OfflineSyncFileState[] {\n return files.filter((file) => !shouldExcludeRelPath(file.path, includeTranscripts));\n}\n\nfunction canReuseFastBaseFileState(\n baseEntry: OfflineSyncFileState,\n st: { size: number; mtimeMs: number; ctimeMs: number },\n baseCapturedAtMs: number | null,\n): boolean {\n if (baseEntry.bytes !== st.size) return false;\n if (Math.abs(baseEntry.mtimeMs - st.mtimeMs) > OFFLINE_SYNC_FAST_BASE_MTIME_TOLERANCE_MS) {\n return false;\n }\n if (baseCapturedAtMs === null) return false;\n // Node reports stat times as fractional milliseconds while Date snapshots are\n // whole milliseconds, so allow only a tiny precision window around capture.\n return st.ctimeMs - baseCapturedAtMs <= OFFLINE_SYNC_FAST_BASE_CTIME_TOLERANCE_MS;\n}\n\nasync function canReuseFastBaseFileStateFromDisk(\n baseEntry: OfflineSyncFileState,\n st: { size: number; mtimeMs: number; ctimeMs: number },\n baseCapturedAtMs: number | null,\n): Promise<boolean> {\n return canReuseFastBaseFileState(baseEntry, st, baseCapturedAtMs);\n}\n\nasync function readOfflineSyncFileRecord(\n options: OfflineSyncFileRecordOptions,\n): Promise<OfflineSyncFileRecord | null> {\n try {\n return await readPresentOfflineSyncFileRecord(options);\n } catch (error) {\n // A file removed between readdir and stat/hash is a race, not a corrupt corpus.\n if (isNotFoundError(error)) return null;\n throw error;\n }\n}\n\n// A vanished path may only be omitted when nothing can misread the gap:\n// embedding generations travel and replace as one unit (issue #3148), and a\n// base-known file omitted here would fabricate a delete in\n// buildOfflineSyncChangesetFromSnapshot.\nfunction assertSnapshotVanishIsSafe(relPath: string, base: ReadonlyMap<string, unknown> | undefined): void {\n if (embeddingGenerationMembership(relPath) !== null) {\n throw new Error(`offline sync embedding generation member vanished during snapshot walk: ${relPath}`);\n }\n if (base?.has(relPath)) {\n throw new Error(`offline sync snapshot base file vanished during walk: ${relPath}`);\n }\n}\n\nasync function readPresentOfflineSyncFileRecord(\n options: OfflineSyncFileRecordOptions,\n): Promise<OfflineSyncFileRecord> {\n throwIfOfflineSyncAborted(options.signal);\n const relPath = validateArchiveRelativePath(options.relPath, \"offlineSyncFile.path\");\n let content: Buffer | null = null;\n let digest: OfflineSyncFileDigest;\n if (options.includeContent) {\n content = options.readFile\n ? await options.readFile({ root: options.root.abs, path: relPath, filePath: options.filePath })\n : await readFile(options.filePath);\n throwIfOfflineSyncAborted(options.signal);\n digest = sha256Buffer(content);\n } else if (options.readFileDigest) {\n digest = await options.readFileDigest({ root: options.root.abs, path: relPath, filePath: options.filePath });\n throwIfOfflineSyncAborted(options.signal);\n } else if (options.readFile) {\n content = await options.readFile({ root: options.root.abs, path: relPath, filePath: options.filePath });\n throwIfOfflineSyncAborted(options.signal);\n digest = sha256Buffer(content);\n content = null;\n } else {\n digest = await sha256OfflineSyncFile(options.filePath, options.signal);\n }\n throwIfOfflineSyncAborted(options.signal);\n const st = await stat(options.filePath);\n return {\n path: relPath,\n sha256: digest.sha256,\n bytes: digest.bytes,\n mtimeMs: st.mtimeMs,\n ...(content ? { contentBase64: content.toString(\"base64\") } : {}),\n };\n}\n\nexport async function* iterateOfflineSyncSnapshotFileRecords(options: {\n root: string;\n includeContent?: boolean;\n includeTranscripts?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n excludeFile?: OfflineSyncExcludeFile;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * Precomputed whole-generation omission set (PR #3148 round 4): paths the\n * walk must skip because their embedding generation lost ANY member to a\n * push filter. When omitted and push excludes are active, the set is\n * computed here so streaming census consumers get the same semantics.\n */\n skipEmbeddingGenerationPaths?: ReadonlySet<string>;\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n signal?: AbortSignal;\n}): AsyncIterable<OfflineSyncFileRecord> {\n throwIfOfflineSyncAborted(options.signal);\n const rootAbs = path.resolve(options.root);\n const root = await prepareSafeArchiveRoot(rootAbs, \"iterateOfflineSyncSnapshotFileRecords\", \"root\");\n const includeTranscripts = options.includeTranscripts !== false;\n const pushExcludes = options.excludeNodeLocalState !== false;\n const skipGenerationPaths = options.skipEmbeddingGenerationPaths ??\n (pushExcludes\n ? (await computeOmittedEmbeddingGenerationPaths({\n rootAbs: root.abs,\n userExcludeRegexps: options.userExcludeRegexps,\n excludeFile: options.excludeFile,\n isExcludedRelPath: (relPath) =>\n shouldExcludePushRelPath(relPath, includeTranscripts, options.userExcludeRegexps),\n })).omittedPaths\n : undefined);\n\n async function* walk(dirAbs: string, includeContent = options.includeContent === true): AsyncIterable<OfflineSyncFileRecord> {\n throwIfOfflineSyncAborted(options.signal);\n let entries = await readdir(dirAbs, { withFileTypes: true });\n entries = entries.sort((left, right) => left.name.localeCompare(right.name));\n for (const entry of entries) {\n const abs = path.join(dirAbs, entry.name);\n const relPosix = path.relative(root.abs, abs).split(path.sep).join(\"/\");\n if (\n options.excludeNodeLocalState === false\n ? shouldExcludeRelPath(relPosix, includeTranscripts)\n : shouldExcludePushRelPath(relPosix, includeTranscripts, options.userExcludeRegexps)\n ) continue;\n if (skipGenerationPaths?.has(relPosix)) continue;\n if (entry.isSymbolicLink()) continue;\n if (entry.isDirectory()) {\n if (isEmbeddingGenerationDirPath(relPosix)) {\n yield* withEmbeddingGenerationLockIter(path.dirname(abs), (content) => walk(abs, content), includeContent,\n () => assertEmbeddingGenerationStillIncluded(root.abs, relPosix, options.excludeFile,\n (rel) => shouldExcludePushRelPath(rel, includeTranscripts, options.userExcludeRegexps),\n []));\n continue;\n }\n yield* walk(abs, includeContent);\n continue;\n }\n if (!entry.isFile()) continue;\n if (await shouldExcludeOfflineSyncFile(options.excludeFile, {\n root: root.abs,\n path: relPosix,\n filePath: abs,\n })) continue;\n const record = await readOfflineSyncFileRecord({\n root,\n relPath: relPosix,\n filePath: abs,\n includeContent,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n signal: options.signal,\n });\n if (record) yield record;\n else assertSnapshotVanishIsSafe(relPosix, undefined);\n }\n }\n\n yield* walk(root.abs);\n}\n\nexport async function buildOfflineSyncSnapshot(options: {\n root: string;\n sourceId: string;\n includeContent?: boolean;\n deletions?: readonly OfflineSyncDeletionRevision[];\n includeTranscripts?: boolean;\n now?: Date;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n excludeFile?: OfflineSyncExcludeFile;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n signal?: AbortSignal;\n}): Promise<OfflineSyncSnapshot> {\n throwIfOfflineSyncAborted(options.signal);\n const includeTranscripts = options.includeTranscripts !== false;\n const pushExcludes = options.excludeNodeLocalState !== false;\n const normalizedDeletions = normalizeDeletionRevisions(options.deletions, \"deletions\");\n const omission = pushExcludes\n ? await computeOmittedEmbeddingGenerationPaths({\n rootAbs: path.resolve(options.root),\n userExcludeRegexps: options.userExcludeRegexps,\n excludeFile: options.excludeFile,\n tombstonedPaths: (normalizedDeletions ?? []).map((deletion) => deletion.path),\n isExcludedRelPath: (relPath) =>\n shouldExcludePushRelPath(relPath, includeTranscripts, options.userExcludeRegexps),\n })\n : undefined;\n const files: OfflineSyncFileRecord[] = [];\n for await (const file of iterateOfflineSyncSnapshotFileRecords({\n ...options,\n skipEmbeddingGenerationPaths: omission?.omittedPaths,\n })) files.push(file);\n throwIfOfflineSyncAborted(options.signal);\n\n const sortedFiles = files.sort(compareByPath);\n const deletions = snapshotBuilderDeletions({\n deletions: options.deletions,\n files: sortedFiles,\n includeTranscripts,\n excludeNodeLocalState: options.excludeNodeLocalState,\n userExcludeRegexps: options.userExcludeRegexps,\n omittedGenerationDirs: omission && omission.omittedDirs.length > 0\n ? new Set(omission.omittedDirs)\n : undefined,\n });\n return {\n format: OFFLINE_SYNC_SNAPSHOT_FORMAT,\n schemaVersion: 1,\n createdAt: (options.now ?? new Date()).toISOString(),\n sourceId: normalizeSourceId(options.sourceId, \"sourceId\"),\n includeTranscripts,\n files: sortedFiles,\n ...(deletions === undefined ? {} : { deletions }),\n ...(omission && omission.omittedDirs.length > 0\n ? { omittedEmbeddingGenerationDirs: omission.omittedDirs }\n : {}),\n };\n}\n\nexport async function buildOfflineSyncSnapshotFromBase(options: {\n root: string;\n sourceId: string;\n baseFiles?: readonly OfflineSyncFileState[];\n deletions?: readonly OfflineSyncDeletionRevision[];\n baseCapturedAt?: Date;\n includeContent?: boolean;\n includeTranscripts?: boolean;\n now?: Date;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n excludeFile?: OfflineSyncExcludeFile;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n signal?: AbortSignal;\n}): Promise<OfflineSyncSnapshot> {\n throwIfOfflineSyncAborted(options.signal);\n const rootAbs = path.resolve(options.root);\n const root = await prepareSafeArchiveRoot(rootAbs, \"buildOfflineSyncSnapshotFromBase\", \"root\");\n const includeTranscripts = options.includeTranscripts !== false;\n const base = byPath(filterBaseFilesForMode(\n normalizeFileStates(options.baseFiles),\n includeTranscripts,\n ));\n const rawBaseCapturedAtMs = options.baseCapturedAt?.getTime();\n const baseCapturedAtMs = rawBaseCapturedAtMs !== undefined && Number.isFinite(rawBaseCapturedAtMs)\n ? rawBaseCapturedAtMs\n : null;\n const pushExcludes = options.excludeNodeLocalState !== false;\n const normalizedDeletions = normalizeDeletionRevisions(options.deletions, \"deletions\");\n const omission = pushExcludes\n ? await computeOmittedEmbeddingGenerationPaths({\n rootAbs: root.abs,\n userExcludeRegexps: options.userExcludeRegexps,\n excludeFile: options.excludeFile,\n tombstonedPaths: (normalizedDeletions ?? []).map((deletion) => deletion.path),\n isExcludedRelPath: (relPath) =>\n shouldExcludePushRelPath(relPath, includeTranscripts, options.userExcludeRegexps),\n })\n : undefined;\n const files: OfflineSyncFileRecord[] = [];\n\n async function walk(dirAbs: string): Promise<void> {\n throwIfOfflineSyncAborted(options.signal);\n let entries = await readdir(dirAbs, { withFileTypes: true });\n entries = entries.sort((left, right) => left.name.localeCompare(right.name));\n for (const entry of entries) {\n throwIfOfflineSyncAborted(options.signal);\n const abs = path.join(dirAbs, entry.name);\n const relPosix = path.relative(root.abs, abs).split(path.sep).join(\"/\");\n if (\n options.excludeNodeLocalState === false\n ? shouldExcludeRelPath(relPosix, includeTranscripts)\n : shouldExcludePushRelPath(relPosix, includeTranscripts, options.userExcludeRegexps)\n ) continue;\n if (omission?.omittedPaths.has(relPosix)) continue;\n if (entry.isSymbolicLink()) continue;\n if (entry.isDirectory()) {\n if (isEmbeddingGenerationDirPath(relPosix)) {\n await withEmbeddingGenerationLock(path.dirname(abs), async () => {\n await assertEmbeddingGenerationStillIncluded(root.abs, relPosix, options.excludeFile,\n (rel) => shouldExcludePushRelPath(rel, includeTranscripts, options.userExcludeRegexps),\n (normalizedDeletions ?? []).map((deletion) => deletion.path));\n await walk(abs);\n });\n continue;\n }\n await walk(abs);\n continue;\n }\n if (!entry.isFile()) continue;\n if (await shouldExcludeOfflineSyncFile(options.excludeFile, {\n root: root.abs,\n path: relPosix,\n filePath: abs,\n })) continue;\n let st: Stats;\n try {\n st = await stat(abs);\n } catch (error) {\n // Same race readOfflineSyncFileRecord tolerates, unless omitting the\n // path could fabricate a delete or downgrade a generation.\n if (isNotFoundError(error)) {\n assertSnapshotVanishIsSafe(relPosix, base);\n continue;\n }\n throw error;\n }\n const baseEntry = base.get(relPosix);\n if (\n options.includeContent !== true &&\n baseEntry &&\n baseCapturedAtMs !== null &&\n await canReuseFastBaseFileStateFromDisk(baseEntry, st, baseCapturedAtMs)\n ) {\n files.push(baseEntry);\n continue;\n }\n const record = await readOfflineSyncFileRecord({\n root,\n relPath: relPosix,\n filePath: abs,\n includeContent: options.includeContent === true,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n signal: options.signal,\n });\n if (record) files.push(record);\n else assertSnapshotVanishIsSafe(relPosix, base);\n }\n }\n\n await walk(root.abs);\n throwIfOfflineSyncAborted(options.signal);\n\n const sortedFiles = files.sort(compareByPath);\n const deletions = snapshotBuilderDeletions({\n deletions: options.deletions,\n files: sortedFiles,\n includeTranscripts,\n excludeNodeLocalState: options.excludeNodeLocalState,\n userExcludeRegexps: options.userExcludeRegexps,\n omittedGenerationDirs: omission && omission.omittedDirs.length > 0\n ? new Set(omission.omittedDirs)\n : undefined,\n });\n return {\n format: OFFLINE_SYNC_SNAPSHOT_FORMAT,\n schemaVersion: 1,\n createdAt: (options.now ?? new Date()).toISOString(),\n sourceId: normalizeSourceId(options.sourceId, \"sourceId\"),\n includeTranscripts,\n files: sortedFiles,\n ...(deletions === undefined ? {} : { deletions }),\n ...(omission && omission.omittedDirs.length > 0\n ? { omittedEmbeddingGenerationDirs: omission.omittedDirs }\n : {}),\n };\n}\n\nexport async function buildOfflineSyncSnapshotForPaths(options: {\n root: string;\n sourceId: string;\n paths: readonly string[];\n deletions?: readonly OfflineSyncDeletionRevision[];\n includeContent?: boolean;\n includeTranscripts?: boolean;\n now?: Date;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n excludeFile?: OfflineSyncExcludeFile;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n signal?: AbortSignal;\n}): Promise<OfflineSyncSnapshot> {\n throwIfOfflineSyncAborted(options.signal);\n const rootAbs = path.resolve(options.root);\n const root = await prepareSafeArchiveRoot(rootAbs, \"buildOfflineSyncSnapshotForPaths\", \"root\");\n const includeTranscripts = options.includeTranscripts !== false;\n const files: OfflineSyncFileRecord[] = [];\n const seen = new Set<string>();\n\n for (const rawPath of options.paths) {\n throwIfOfflineSyncAborted(options.signal);\n const relPath = normalizeRelativePath(rawPath, \"paths[]\");\n if (seen.has(relPath)) continue;\n seen.add(relPath);\n if (\n options.excludeNodeLocalState === false\n ? shouldExcludeRelPath(relPath, includeTranscripts)\n : shouldExcludePushRelPath(relPath, includeTranscripts, options.userExcludeRegexps)\n ) {\n throw new Error(`offline sync snapshot path is excluded: ${relPath}`);\n }\n const filePath = await resolveSafeArchiveTarget(root, relPath);\n const st = await lstat(filePath).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (!st || st.isSymbolicLink() || !st.isFile()) continue;\n if (await shouldExcludeOfflineSyncFile(options.excludeFile, {\n root: root.abs,\n path: relPath,\n filePath,\n })) {\n throw new Error(`offline sync snapshot path is excluded: ${relPath}`);\n }\n const record = await readOfflineSyncFileRecord({\n root,\n relPath,\n filePath,\n includeContent: options.includeContent === true,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n signal: options.signal,\n });\n if (record) files.push(record);\n else assertSnapshotVanishIsSafe(relPath, undefined);\n }\n throwIfOfflineSyncAborted(options.signal);\n\n const sortedFiles = files.sort(compareByPath);\n const deletions = snapshotBuilderDeletions({\n deletions: options.deletions,\n files: sortedFiles,\n paths: [...seen],\n includeTranscripts,\n excludeNodeLocalState: options.excludeNodeLocalState,\n userExcludeRegexps: options.userExcludeRegexps,\n });\n return {\n format: OFFLINE_SYNC_SNAPSHOT_FORMAT,\n schemaVersion: 1,\n createdAt: (options.now ?? new Date()).toISOString(),\n sourceId: normalizeSourceId(options.sourceId, \"sourceId\"),\n includeTranscripts,\n files: sortedFiles,\n ...(deletions === undefined ? {} : { deletions }),\n };\n}\n\nexport async function readOfflineSyncFileContentChunk(options: {\n root: string;\n path: string;\n offset?: number;\n length?: number;\n includeTranscripts?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n excludeFile?: OfflineSyncExcludeFile;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n}): Promise<OfflineSyncFileContentChunk> {\n const rootAbs = path.resolve(options.root);\n const root = await prepareSafeArchiveRoot(rootAbs, \"readOfflineSyncFileContentChunk\", \"root\");\n const includeTranscripts = options.includeTranscripts !== false;\n const relPath = normalizeRelativePath(options.path, \"path\");\n if (\n options.excludeNodeLocalState === false\n ? shouldExcludeRelPath(relPath, includeTranscripts)\n : shouldExcludePushRelPath(relPath, includeTranscripts, options.userExcludeRegexps)\n ) {\n throw new Error(`offline sync file content path is excluded: ${relPath}`);\n }\n const offset = options.offset === undefined\n ? 0\n : assertNonNegativeInteger(options.offset, \"offset\");\n const requestedLength = options.length === undefined\n ? OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES\n : assertNonNegativeInteger(options.length, \"length\");\n if (requestedLength < 1 || requestedLength > OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES) {\n throw new Error(\n `length must be an integer from 1 to ${OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES}`,\n );\n }\n const filePath = await resolveSafeArchiveTarget(root, relPath);\n const st = await lstat(filePath).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (!st || st.isSymbolicLink() || !st.isFile()) {\n throw new Error(`offline sync file content path not found: ${relPath}`);\n }\n if (await shouldExcludeOfflineSyncFile(options.excludeFile, {\n root: root.abs,\n path: relPath,\n filePath,\n })) {\n throw new Error(`offline sync file content path is excluded: ${relPath}`);\n }\n const encrypted = await isEncryptedOfflineSyncFile(filePath);\n if (!encrypted) {\n if (offset > st.size) {\n throw new Error(`offset must be <= file size for ${relPath}`);\n }\n // Plain files need the whole-file sha256 for the response contract\n // (x-remnic-file-sha256; peer transports reject chunks without it), but\n // must stay memory-bounded for large files: the digest is computed by a\n // streamed hash pass (never buffering the file) and cached by\n // (path, bytes, mtimeMs) so per-chunk requests after the first are O(1).\n const chunk = await readPlainOfflineSyncFileChunk({\n filePath,\n offset,\n length: requestedLength,\n bytes: st.size,\n });\n const digest = await plainFileDigest(filePath);\n return {\n path: relPath,\n sha256: digest,\n bytes: st.size,\n mtimeMs: st.mtimeMs,\n offset,\n chunkBytes: chunk.length,\n content: chunk,\n };\n }\n if (!options.readFile) {\n throw new Error(`offline sync file content requires a secure-store read hook: ${relPath}`);\n }\n const content = await options.readFile({ root: root.abs, path: relPath, filePath });\n if (offset > content.length) {\n throw new Error(`offset must be <= file size for ${relPath}`);\n }\n const digest = sha256Buffer(content);\n const end = Math.min(content.length, offset + requestedLength);\n const chunk = content.subarray(offset, end);\n return {\n path: relPath,\n sha256: digest.sha256,\n bytes: digest.bytes,\n mtimeMs: st.mtimeMs,\n offset,\n chunkBytes: chunk.length,\n content: Buffer.from(chunk),\n };\n}\n\nexport async function buildOfflineSyncChangeset(options: {\n root: string;\n sourceId: string;\n baseFiles?: readonly OfflineSyncFileState[];\n deletions?: readonly OfflineSyncDeletionRevision[];\n baseCapturedAt?: Date;\n excludePaths?: readonly string[];\n includeTranscripts?: boolean;\n now?: Date;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n}): Promise<OfflineSyncChangeset> {\n const includeTranscripts = options.includeTranscripts !== false;\n const current = await buildOfflineSyncSnapshotFromBase({\n root: options.root,\n sourceId: options.sourceId,\n baseFiles: options.baseFiles,\n deletions: options.deletions,\n baseCapturedAt: options.baseCapturedAt,\n includeContent: false,\n includeTranscripts,\n now: options.now,\n userExcludeRegexps: options.userExcludeRegexps,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n });\n return buildOfflineSyncChangesetFromSnapshot({\n root: options.root,\n sourceId: options.sourceId,\n baseFiles: options.baseFiles,\n currentFiles: current.files,\n deletions: current.deletions,\n excludePaths: options.excludePaths,\n includeTranscripts,\n now: options.now,\n userExcludeRegexps: options.userExcludeRegexps,\n readFile: options.readFile,\n });\n}\n\nexport async function buildOfflineSyncChangesetFromSnapshot(options: {\n root: string;\n sourceId: string;\n currentFiles: readonly OfflineSyncFileState[];\n baseFiles?: readonly OfflineSyncFileState[];\n deletions?: readonly OfflineSyncDeletionRevision[];\n excludePaths?: readonly string[];\n includeTranscripts?: boolean;\n now?: Date;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n}): Promise<OfflineSyncChangeset> {\n const includeTranscripts = options.includeTranscripts !== false;\n const excludedPaths = new Set(\n (options.excludePaths ?? []).map((relPath) => normalizeRelativePath(relPath, \"excludePaths[]\")),\n );\n const base = byPath(filterBaseFilesForMode(\n normalizeFileStates(options.baseFiles),\n includeTranscripts,\n ));\n const currentMap = byPath(filterBaseFilesForMode(\n normalizeFileStates(options.currentFiles),\n includeTranscripts,\n ));\n const deletions = normalizeDeletionRevisions(options.deletions, \"deletions\");\n const deletionMtimeByPath = deletions === undefined\n ? undefined\n : new Map(deletions.map((deletion) => [deletion.path, deletion.mtimeMs] as const));\n const changes: OfflineSyncChange[] = [];\n\n for (const relPath of unionPaths(base, currentMap)) {\n if (excludedPaths.has(relPath)) continue;\n // Issue #1786: node-local runtime state must never appear in a push-side\n // changeset — each node rebuilds it from synced records.\n if (shouldExcludePushRelPath(relPath, includeTranscripts, options.userExcludeRegexps)) continue;\n // Runtime state is remote-authoritative in offline sync: local edits and\n // deletes are not pushed; the pull phase restores or removes these files\n // from the remote snapshot.\n if (shouldPreferIncomingOfflineRuntimeFile(relPath)) continue;\n const baseEntry = base.get(relPath);\n const currentEntry = currentMap.get(relPath);\n if (currentEntry && currentEntry.sha256 !== baseEntry?.sha256) {\n const file = await buildOfflineSyncSnapshotForPaths({\n root: options.root,\n sourceId: options.sourceId,\n paths: [relPath],\n includeContent: true,\n includeTranscripts,\n now: options.now,\n userExcludeRegexps: options.userExcludeRegexps,\n readFile: options.readFile,\n });\n const record = file.files[0];\n if (!record || typeof record.contentBase64 !== \"string\" || record.sha256 !== currentEntry.sha256) {\n throw new Error(`offline sync file changed while building changeset: ${relPath}`);\n }\n changes.push({\n type: \"upsert\",\n path: relPath,\n ...(baseEntry ? { baseSha256: baseEntry.sha256 } : {}),\n file: record as OfflineSyncFileRecord & { contentBase64: string },\n });\n continue;\n }\n if (!currentEntry && baseEntry) {\n const mtimeMs = deletionMtimeByPath?.get(relPath);\n changes.push({\n type: \"delete\",\n path: relPath,\n baseSha256: baseEntry.sha256,\n ...(mtimeMs === undefined ? {} : { mtimeMs }),\n });\n }\n }\n\n return {\n format: OFFLINE_SYNC_CHANGESET_FORMAT,\n schemaVersion: 1,\n createdAt: (options.now ?? new Date()).toISOString(),\n sourceId: normalizeSourceId(options.sourceId, \"sourceId\"),\n includeTranscripts,\n changes: changes.sort(compareByPath),\n };\n}\n\nexport function summarizeOfflineSyncChangeset(\n changeset: OfflineSyncChangeset,\n): OfflineSyncChangesetSummary {\n const upserts = changeset.changes.filter((change) => change.type === \"upsert\").length;\n const deletes = changeset.changes.filter((change) => change.type === \"delete\").length;\n return {\n upserts,\n deletes,\n total: changeset.changes.length,\n };\n}\n\nexport async function summarizeOfflineSyncPendingChanges(options: {\n root: string;\n sourceId: string;\n baseFiles?: readonly OfflineSyncFileState[];\n baseCapturedAt?: Date;\n includeTranscripts?: boolean;\n now?: Date;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n}): Promise<OfflineSyncChangesetSummary> {\n const includeTranscripts = options.includeTranscripts !== false;\n const current = await buildOfflineSyncSnapshotFromBase({\n root: options.root,\n sourceId: options.sourceId,\n baseFiles: options.baseFiles,\n baseCapturedAt: options.baseCapturedAt,\n includeContent: false,\n includeTranscripts,\n now: options.now,\n userExcludeRegexps: options.userExcludeRegexps,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n });\n return summarizeOfflineSyncPendingFiles({\n baseFiles: options.baseFiles,\n currentFiles: current.files,\n includeTranscripts,\n userExcludeRegexps: options.userExcludeRegexps,\n });\n}\n\nexport function summarizeOfflineSyncPendingFiles(options: {\n baseFiles?: readonly OfflineSyncFileState[];\n currentFiles: readonly OfflineSyncFileState[];\n includeTranscripts?: boolean;\n userExcludeRegexps?: readonly RegExp[];\n /**\n * When false, enumeration uses only the legacy structural excludes —\n * the apply/pull-side view of local files. Push-side callers keep the\n * default (true): built-in node-local state excludes + user excludes.\n * (Cursor review on PR #1793: apply-side local enumeration must see\n * files like state/lcm.sqlite or merges misclassify them.)\n */\n excludeNodeLocalState?: boolean;\n}): OfflineSyncChangesetSummary {\n const includeTranscripts = options.includeTranscripts !== false;\n const base = byPath(filterBaseFilesForMode(\n normalizeFileStates(options.baseFiles),\n includeTranscripts,\n ));\n const currentMap = byPath(filterBaseFilesForMode(\n normalizeFileStates(options.currentFiles),\n includeTranscripts,\n ));\n let upserts = 0;\n let deletes = 0;\n for (const relPath of unionPaths(base, currentMap)) {\n if (shouldPreferIncomingOfflineRuntimeFile(relPath)) continue;\n if (shouldExcludePushRelPath(relPath, includeTranscripts, options.userExcludeRegexps)) continue;\n const baseEntry = base.get(relPath);\n const currentEntry = currentMap.get(relPath);\n if (currentEntry && currentEntry.sha256 !== baseEntry?.sha256) {\n upserts += 1;\n continue;\n }\n if (!currentEntry && baseEntry) {\n deletes += 1;\n }\n }\n\n return {\n upserts,\n deletes,\n total: upserts + deletes,\n };\n}\n\nexport async function applyOfflineSyncSnapshot(options: {\n root: string;\n snapshot: unknown;\n baseFiles?: readonly OfflineSyncFileState[];\n currentFiles?: readonly OfflineSyncFileState[];\n deferredPaths?: readonly string[];\n allowMissingConflictContent?: boolean;\n /**\n * Explicit INCOMING content source for snapshot records without inline\n * `contentBase64` (oversized generation members the client fetched\n * chunk-wise into a private staging root). Consulted only for such\n * records; return null to keep the metadata-only behavior (the local\n * file must hash-match the record). Returned buffers are digest-verified\n * against the incoming record before anything is published.\n */\n readIncomingFile?: (target: { path: string; sha256: string; bytes: number }) => Promise<Buffer | null>;\n writeConflictCopies?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n writeFile?: (target: OfflineSyncFileWriteTarget) => Promise<void>;\n writeStagingFile?: (target: OfflineSyncFileStagingWriteTarget) => Promise<void>;\n readStagingFile?: (target: OfflineSyncFileStagingReadTarget) => Promise<Buffer>;\n deleteFile?: (target: OfflineSyncFileDeleteTarget) => Promise<void>;\n recordDeletionRevision?: OfflineSyncRecordDeletionRevision;\n}): Promise<OfflineSyncApplySnapshotResult> {\n const snapshot = normalizeOfflineSyncSnapshot(options.snapshot);\n const baseMap = byPath(filterBaseFilesForMode(\n normalizeFileStates(options.baseFiles),\n snapshot.includeTranscripts,\n ));\n const incomingMap = byPath(snapshot.files);\n const deletionMtimeByPath = snapshot.deletions === undefined\n ? undefined\n : new Map(snapshot.deletions.map((deletion) => [deletion.path, deletion.mtimeMs] as const));\n const incomingBuffers = await verifyRecordContents(snapshot.files, \"offline sync snapshot\", {\n requireContent: false,\n readIncomingFile: options.readIncomingFile,\n });\n const root = await ensureSyncRoot(options.root, \"applyOfflineSyncSnapshot\");\n const currentFiles = options.currentFiles\n ? filterBaseFilesForMode(normalizeFileStates(options.currentFiles), snapshot.includeTranscripts).sort(compareByPath)\n : (await buildOfflineSyncSnapshot({\n root: root.abs,\n sourceId: \"local\",\n includeContent: false,\n includeTranscripts: snapshot.includeTranscripts,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n excludeNodeLocalState: false,\n })).files;\n const currentMap = byPath(currentFiles);\n const deferredPaths = new Set([...(options.deferredPaths ?? []),\n ...divergedEmbeddingGenerationDeferrals({\n incomingFiles: snapshot.files, baseFiles: [...baseMap.values()], currentFiles,\n }),\n ]);\n const omittedGenerationDirs = new Set(snapshot.omittedEmbeddingGenerationDirs ?? []);\n if (deletionMtimeByPath && options.recordDeletionRevision) {\n for (const [relPath, mtimeMs] of deletionMtimeByPath) {\n if (\n currentMap.has(relPath) ||\n deferredPaths.has(relPath) ||\n (omittedGenerationDirs.size > 0 &&\n isPathInOmittedEmbeddingGeneration(relPath, omittedGenerationDirs)) ||\n matchesOfflineSyncDefaultExclude(relPath)\n ) {\n continue;\n }\n await options.recordDeletionRevision({\n root: root.abs,\n path: relPath,\n filePath: await resolveSafeArchiveTarget(root, relPath),\n mtimeMs,\n });\n }\n }\n const nextBase = new Map(baseMap);\n const conflicts: OfflineSyncConflict[] = [];\n let upserted = 0;\n let deleted = 0;\n let skipped = 0;\n let pendingLocal = 0;\n const conflictIncomingBuffer = (relPath: string): Buffer | undefined => {\n if (options.writeConflictCopies === false) return undefined;\n const buffer = incomingBuffers.get(relPath);\n if (buffer || options.allowMissingConflictContent === true) return buffer;\n return requiredBuffer(incomingBuffers, relPath);\n };\n\n // Embedding generations travel and replace as ONE unit (issue #3148):\n // atomic replacement, cross-layout marker conversion, whole-generation\n // removal on tombstones — all extracted to the generation module (issue\n // #3150) so the changeset path can share it without growing this file.\n const { transactionResults, deferredGenerationDirs } = await applyIncomingEmbeddingGenerations({\n root,\n incomingMap,\n incomingBuffers,\n baseMap,\n currentMap,\n deferredPaths,\n omittedGenerationDirs,\n deletionMtimeByPath,\n io: {\n readFile: options.readFile,\n writeStagingFile: options.writeStagingFile,\n readStagingFile: options.readStagingFile,\n deleteFile: options.deleteFile,\n },\n customIoPresent: Boolean(options.writeFile || options.readFile || options.readFileDigest || options.deleteFile),\n now: Date.now(),\n });\n\n const transactionHandled = new Set<string>();\n let generationUpserted = 0;\n let generationDeleted = 0;\n for (const result of transactionResults) {\n if (result.deferredLocalDivergence) {\n for (const relPath of result.handledPaths) deferredPaths.add(relPath);\n deferredGenerationDirs.add(result.shardDirRel);\n continue;\n }\n generationUpserted += result.upserted;\n generationDeleted += result.deleted;\n for (const relPath of result.handledPaths) transactionHandled.add(relPath);\n // Record converted shard paths directly; they may not be in any input map.\n for (const [relPath, state] of result.writtenStates) {\n nextBase.set(relPath, state);\n transactionHandled.add(relPath);\n }\n for (const relPath of result.removedPaths) {\n nextBase.delete(relPath);\n transactionHandled.add(relPath);\n }\n }\n\n for (const relPath of unionPaths(baseMap, incomingMap, currentMap)) {\n const base = baseMap.get(relPath);\n const incoming = incomingMap.get(relPath);\n const currentEntry = currentMap.get(relPath);\n\n if (deferredPaths.has(relPath)) {\n if (base) nextBase.set(relPath, base);\n else nextBase.delete(relPath);\n skipped += 1;\n continue;\n }\n\n // The generation transaction already published or removed this path and\n // applied its nextBase bookkeeping above; nothing left to do.\n if (transactionHandled.has(relPath)) continue;\n\n // A deferral anywhere in a generation defers the WHOLE generation: no\n // partial replacement in either direction, local files and base entries\n // stay exactly as they are.\n const membership = embeddingGenerationMembership(relPath);\n if (membership && deferredGenerationDirs.has(membership.shardDir)) {\n if (base) nextBase.set(relPath, base);\n else nextBase.delete(relPath);\n skipped += 1;\n continue;\n }\n\n if (incoming) {\n // The generation marker (PR #3176) is node-local on BOTH sides: an\n // incoming copy — old or hostile — never overwrites the local file\n // and never enters the base set. Other default excludes stay\n // apply-accepted (#1786: first-sync LCM sqlite bootstrapping).\n if (isEmbeddingGenerationMarkerPath(relPath)) {\n nextBase.delete(relPath);\n skipped += 1;\n continue;\n }\n if (currentEntry?.sha256 === incoming.sha256) {\n if (await setSafeFileMtime(root, relPath, incoming.mtimeMs)) {\n nextBase.set(relPath, toFileState(incoming));\n } else {\n if (base) nextBase.set(relPath, base);\n else nextBase.delete(relPath);\n pendingLocal += 1;\n }\n skipped += 1;\n continue;\n }\n // Remote unchanged from the shared base while the local file drifted:\n // keep the local copy (no content is needed to make that decision).\n // Members of a replaced generation never reach this branch — the\n // generation transaction or the deferral guard handled them above.\n if (\n shouldPreferIncomingOfflineRuntimeFile(relPath) &&\n currentEntry && base && incoming.sha256 === base.sha256\n ) {\n nextBase.set(relPath, base);\n skipped += 1;\n continue;\n }\n if (shouldPreferIncomingOfflineRuntimeFile(relPath)) {\n await writeSafeFile(root, relPath, requiredBuffer(incomingBuffers, relPath), options.writeFile, incoming.mtimeMs);\n nextBase.set(relPath, toFileState(incoming));\n upserted += 1;\n continue;\n }\n if (!currentEntry && base && incoming.sha256 === base.sha256) {\n nextBase.set(relPath, base);\n pendingLocal += 1;\n skipped += 1;\n continue;\n }\n if (!currentEntry && base && incoming.sha256 !== base.sha256) {\n conflicts.push(await recordConflict({\n root,\n relPath,\n reason: \"local_deleted_remote_modified\",\n baseSha256: base.sha256,\n incomingSha256: incoming.sha256,\n incomingBuffer: conflictIncomingBuffer(relPath),\n writeConflictCopies: options.writeConflictCopies !== false,\n sourceId: snapshot.sourceId,\n writeFile: options.writeFile,\n }));\n nextBase.set(relPath, base);\n continue;\n }\n if (!currentEntry && !base) {\n await writeSafeFile(root, relPath, requiredBuffer(incomingBuffers, relPath), options.writeFile, incoming.mtimeMs);\n nextBase.set(relPath, toFileState(incoming));\n upserted += 1;\n continue;\n }\n if (base && currentEntry && currentEntry.sha256 === base.sha256) {\n await writeSafeFile(root, relPath, requiredBuffer(incomingBuffers, relPath), options.writeFile, incoming.mtimeMs);\n nextBase.set(relPath, toFileState(incoming));\n upserted += 1;\n continue;\n }\n if (base && incoming.sha256 === base.sha256) {\n nextBase.set(relPath, base);\n pendingLocal += 1;\n skipped += 1;\n continue;\n }\n conflicts.push(await recordConflict({\n root,\n relPath,\n reason: base ? \"both_modified\" : \"remote_exists_for_local_create\",\n baseSha256: base?.sha256,\n localSha256: currentEntry?.sha256,\n incomingSha256: incoming.sha256,\n incomingBuffer: conflictIncomingBuffer(relPath),\n writeConflictCopies: options.writeConflictCopies !== false,\n sourceId: snapshot.sourceId,\n writeFile: options.writeFile,\n }));\n if (base) nextBase.set(relPath, base);\n continue;\n }\n\n // Node-local runtime state (#1786): a push-filtered remote snapshot\n // never carries these paths, so their absence is NOT a delete\n // instruction. Drop any stale base entry (pre-#1786 state files still\n // carry them) and leave the local file untouched — deleting a live\n // sqlite WAL/SHM here would corrupt the local LCM store.\n if (matchesOfflineSyncDefaultExclude(relPath)) {\n nextBase.delete(relPath);\n skipped += 1;\n continue;\n }\n if (!currentEntry) {\n nextBase.delete(relPath);\n skipped += 1;\n continue;\n }\n if (\n shouldPreferIncomingOfflineRuntimeFile(relPath) &&\n membership !== null && omittedGenerationDirs.has(membership.shardDir)\n ) {\n // The push omitted this whole generation because a filter excluded at\n // least one member (snapshot.omittedEmbeddingGenerationDirs): absence\n // is NOT a deletion — keep the local generation and its base entries\n // until it is pushed unfiltered or deleted with deletion metadata.\n pendingLocal += 1;\n skipped += 1;\n continue;\n }\n if (\n shouldPreferIncomingOfflineRuntimeFile(relPath) &&\n (base || shouldDeleteAbsentIncomingOfflineRuntimeFile(relPath))\n ) {\n await deleteSafeFile(\n root,\n relPath,\n options.deleteFile,\n deletionMtimeByPath?.get(relPath),\n );\n nextBase.delete(relPath);\n deleted += 1;\n continue;\n }\n if (shouldPreferIncomingOfflineRuntimeFile(relPath)) {\n pendingLocal += 1;\n skipped += 1;\n continue;\n }\n if (base && currentEntry.sha256 === base.sha256) {\n await deleteSafeFile(\n root,\n relPath,\n options.deleteFile,\n deletionMtimeByPath?.get(relPath),\n );\n nextBase.delete(relPath);\n deleted += 1;\n continue;\n }\n if (base) {\n conflicts.push({\n path: relPath,\n reason: \"local_modified_remote_deleted\",\n baseSha256: base.sha256,\n localSha256: currentEntry.sha256,\n });\n nextBase.set(relPath, base);\n continue;\n }\n pendingLocal += 1;\n skipped += 1;\n }\n\n return {\n upserted: upserted + generationUpserted,\n deleted: deleted + generationDeleted,\n skipped,\n pendingLocal,\n conflicts,\n nextBaseFiles: [...nextBase.values()].sort(compareByPath),\n };\n}\n\nexport async function applyOfflineSyncChangeset(options: {\n root: string;\n changeset: unknown;\n currentFiles?: readonly OfflineSyncFileState[];\n returnCurrentFiles?: boolean;\n writeConflictCopies?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n writeFile?: (target: OfflineSyncFileWriteTarget) => Promise<void>;\n writeStagingFile?: (target: OfflineSyncFileStagingWriteTarget) => Promise<void>;\n readStagingFile?: (target: OfflineSyncFileStagingReadTarget) => Promise<Buffer>;\n deleteFile?: (target: OfflineSyncFileDeleteTarget) => Promise<void>;\n recordDeletionRevision?: OfflineSyncRecordDeletionRevision;\n}): Promise<OfflineSyncApplyChangesetResult> {\n let changeset: OfflineSyncChangeset;\n try {\n changeset = normalizeOfflineSyncChangeset(options.changeset);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n message.startsWith(\"offline sync\")\n ? message\n : `offline sync changeset invalid: ${message}`,\n );\n }\n const root = await ensureSyncRoot(options.root, \"applyOfflineSyncChangeset\");\n const records = changeset.changes\n .filter((change): change is Extract<OfflineSyncChange, { type: \"upsert\" }> => change.type === \"upsert\")\n .map((change) => change.file);\n const incomingBuffers = await verifyRecordContents(records, \"offline sync changeset\");\n const currentFiles = options.currentFiles\n ? filterBaseFilesForMode(normalizeFileStates(options.currentFiles), changeset.includeTranscripts).sort(compareByPath)\n : (await buildOfflineSyncSnapshotForPaths({\n root: root.abs,\n sourceId: \"local\",\n paths: changeset.changes.map((change) => change.path),\n includeContent: false,\n includeTranscripts: changeset.includeTranscripts,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n excludeNodeLocalState: false,\n })).files;\n const currentMap = byPath(currentFiles);\n const conflicts: OfflineSyncConflict[] = [];\n let appliedUpserts = 0;\n let appliedDeletes = 0;\n let skipped = 0;\n\n // Embedding generations apply as ONE unit through the shared locked\n // transaction (issue #3150). Deferred generations surface as conflicts so\n // the push side never checkpoints them as applied.\n const generationRouting = await applyChangesetEmbeddingGenerations({\n root,\n changeset,\n incomingBuffers,\n currentMap,\n io: {\n readFile: options.readFile,\n writeStagingFile: options.writeStagingFile,\n readStagingFile: options.readStagingFile,\n deleteFile: options.deleteFile,\n },\n customIoPresent: Boolean(options.writeFile || options.readFile || options.readFileDigest || options.deleteFile),\n now: Date.now(),\n });\n appliedUpserts += generationRouting.appliedUpserts;\n appliedDeletes += generationRouting.appliedDeletes;\n conflicts.push(...generationRouting.conflicts);\n\n for (const change of changeset.changes) {\n if (generationRouting.conflictedPaths.has(change.path)) continue;\n if (generationRouting.transactionHandled.has(change.path)) continue;\n if (isEmbeddingGenerationMarkerPath(change.path)) {\n skipped += 1;\n continue;\n }\n const currentEntry = currentMap.get(change.path);\n if (change.type === \"upsert\") {\n if (currentEntry?.sha256 === change.file.sha256) {\n if (await setSafeFileMtime(root, change.path, change.file.mtimeMs)) {\n skipped += 1;\n } else {\n await writeSafeFile(root, change.path, requiredBuffer(incomingBuffers, change.path), options.writeFile, change.file.mtimeMs);\n currentMap.set(change.path, toFileState(change.file));\n appliedUpserts += 1;\n }\n continue;\n }\n if (!change.baseSha256) {\n if (!currentEntry) {\n await writeSafeFile(root, change.path, requiredBuffer(incomingBuffers, change.path), options.writeFile, change.file.mtimeMs);\n currentMap.set(change.path, toFileState(change.file));\n appliedUpserts += 1;\n continue;\n }\n conflicts.push(await recordConflict({\n root,\n relPath: change.path,\n reason: \"remote_exists_for_local_create\",\n localSha256: currentEntry.sha256,\n incomingSha256: change.file.sha256,\n incomingBuffer: incomingBuffers.get(change.path),\n writeConflictCopies: options.writeConflictCopies !== false,\n sourceId: changeset.sourceId,\n writeFile: options.writeFile,\n }));\n continue;\n }\n if (currentEntry?.sha256 === change.baseSha256) {\n await writeSafeFile(root, change.path, requiredBuffer(incomingBuffers, change.path), options.writeFile, change.file.mtimeMs);\n currentMap.set(change.path, toFileState(change.file));\n appliedUpserts += 1;\n continue;\n }\n conflicts.push(await recordConflict({\n root,\n relPath: change.path,\n reason: currentEntry ? \"remote_changed_for_local_update\" : \"remote_deleted_for_local_update\",\n baseSha256: change.baseSha256,\n localSha256: currentEntry?.sha256,\n incomingSha256: change.file.sha256,\n incomingBuffer: incomingBuffers.get(change.path),\n writeConflictCopies: options.writeConflictCopies !== false,\n sourceId: changeset.sourceId,\n writeFile: options.writeFile,\n }));\n continue;\n }\n\n if (!currentEntry) {\n if (change.mtimeMs !== undefined && options.recordDeletionRevision) {\n await options.recordDeletionRevision({\n root: root.abs,\n path: change.path,\n filePath: await resolveSafeArchiveTarget(root, change.path),\n mtimeMs: change.mtimeMs,\n });\n }\n skipped += 1;\n continue;\n }\n if (currentEntry.sha256 === change.baseSha256) {\n await deleteSafeFile(root, change.path, options.deleteFile, change.mtimeMs);\n currentMap.delete(change.path);\n appliedDeletes += 1;\n continue;\n }\n conflicts.push({\n path: change.path,\n reason: \"remote_changed_for_local_delete\",\n baseSha256: change.baseSha256,\n localSha256: currentEntry.sha256,\n });\n }\n\n // Generation transactions bypassed the per-file loop; fold their published\n // and removed members into the partial result map (returnCurrentFiles ===\n // false consumers) so it reflects the post-apply generation exactly.\n for (const [relPath, state] of generationRouting.writtenStates) currentMap.set(relPath, state);\n for (const relPath of generationRouting.removedPaths) currentMap.delete(relPath);\n\n return {\n appliedUpserts,\n appliedDeletes,\n skipped,\n conflicts,\n currentFiles: options.returnCurrentFiles === false\n ? [...currentMap.values()].sort(compareByPath)\n : (await buildOfflineSyncSnapshot({\n root: root.abs,\n sourceId: \"local\",\n includeContent: false,\n includeTranscripts: changeset.includeTranscripts,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n excludeNodeLocalState: false,\n })).files,\n ...(options.returnCurrentFiles === false ? { currentFilesComplete: false } : {}),\n };\n}\n\nasync function verifyRecordContents(\n records: readonly OfflineSyncFileRecord[],\n context: string,\n options: {\n requireContent?: boolean;\n readIncomingFile?: (target: { path: string; sha256: string; bytes: number }) => Promise<Buffer | null>;\n } = {},\n): Promise<Map<string, Buffer>> {\n const buffers = new Map<string, Buffer>();\n for (const record of records) {\n if (typeof record.contentBase64 !== \"string\") {\n if (options.readIncomingFile) {\n // Explicit INCOMING content source for records whose bytes travel\n // out-of-band (chunked fetch into the client's private staging\n // root). Never the local current-state file: the buffer is\n // digest-verified against the incoming record before anything is\n // published. null keeps the metadata-only behavior below.\n const incoming = await options.readIncomingFile({\n path: record.path,\n sha256: record.sha256,\n bytes: record.bytes,\n });\n if (incoming) {\n const digest = sha256Buffer(incoming);\n if (digest.sha256 !== record.sha256 || digest.bytes !== record.bytes) {\n throw new Error(`${context}: incoming content checksum mismatch for ${record.path}`);\n }\n buffers.set(record.path, incoming);\n continue;\n }\n }\n if (options.requireContent === false) continue;\n throw new Error(`${context}: contentBase64 is required for ${record.path}`);\n }\n const buffer = Buffer.from(record.contentBase64, \"base64\");\n const digest = sha256Buffer(buffer);\n if (digest.sha256 !== record.sha256 || digest.bytes !== record.bytes) {\n throw new Error(\n `${context}: content checksum mismatch for ${record.path}`,\n );\n }\n buffers.set(record.path, buffer);\n }\n return buffers;\n}\n\nfunction requiredBuffer(buffers: Map<string, Buffer>, relPath: string): Buffer {\n const buffer = buffers.get(relPath);\n if (!buffer) {\n throw new Error(`missing decoded content for ${relPath}`);\n }\n return buffer;\n}\n\nasync function ensureSyncRoot(rootPath: string, errorPrefix: string): Promise<SafeArchiveRoot> {\n const rootAbs = path.resolve(rootPath);\n await mkdir(rootAbs, { recursive: true });\n return prepareSafeArchiveRoot(rootAbs, errorPrefix, \"root\");\n}\n\nfunction byPath<T extends OfflineSyncFileState>(files: readonly T[]): Map<string, T> {\n const out = new Map<string, T>();\n for (const file of files) {\n out.set(validateArchiveRelativePath(file.path, \"offlineSync\"), file);\n }\n return out;\n}\n\nfunction unionPaths(...maps: Array<Map<string, unknown>>): string[] {\n const paths = new Set<string>();\n for (const map of maps) {\n for (const key of map.keys()) paths.add(key);\n }\n return [...paths].sort();\n}\n\nfunction toFileState(file: OfflineSyncFileState): OfflineSyncFileState {\n return {\n path: file.path,\n sha256: file.sha256,\n bytes: file.bytes,\n mtimeMs: file.mtimeMs,\n };\n}\n\nasync function writeSafeFile(\n root: SafeArchiveRoot,\n relPath: string,\n content: Buffer,\n writeFileHook?: (target: OfflineSyncFileWriteTarget) => Promise<void>,\n mtimeMs?: number,\n): Promise<void> {\n const target = await resolveSafeArchiveTarget(root, relPath);\n if (writeFileHook) {\n await writeFileHook({ root: root.abs, path: relPath, filePath: target, content });\n await setSafeFileMtime(root, relPath, mtimeMs);\n return;\n }\n await mkdir(path.dirname(target), { recursive: true });\n const tmp = path.join(\n path.dirname(target),\n `.remnic-sync.${process.pid}.${randomUUID()}.tmp`,\n );\n await writeFile(tmp, content);\n try {\n const targetStat = await lstat(target).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (targetStat?.isSymbolicLink()) {\n throw new Error(`offline sync target is a symlink: ${relPath}`);\n }\n await rename(tmp, target);\n await setSafeFileMtime(root, relPath, mtimeMs);\n } catch (error) {\n await unlink(tmp).catch(() => {});\n throw error;\n }\n}\n\n\n/**\n * Read the local file digest for a single relative path without applying\n * push-side exclude rules. Used by apply-side helpers that need to check\n * the current local state of a path that the push-side exclude would\n * reject (e.g. `state/lcm.sqlite`). Returns `null` if the file does not\n * exist, is not a regular file, or is a symlink.\n */\nasync function readLocalFileState(options: {\n rootAbs: string;\n relPath: string;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n signal?: AbortSignal;\n}): Promise<OfflineSyncFileState | null> {\n const filePath = await resolveSafeArchiveTarget(\n await prepareSafeArchiveRoot(options.rootAbs, \"readLocalFileState\", \"rootAbs\"),\n options.relPath,\n );\n const st = await lstat(filePath).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (!st || st.isSymbolicLink() || !st.isFile()) return null;\n throwIfOfflineSyncAborted(options.signal);\n let digest: OfflineSyncFileDigest;\n if (options.readFileDigest) {\n digest = await options.readFileDigest({ root: options.rootAbs, path: options.relPath, filePath });\n } else if (options.readFile) {\n const content = await options.readFile({ root: options.rootAbs, path: options.relPath, filePath });\n digest = sha256Buffer(content);\n } else {\n digest = await sha256OfflineSyncFile(filePath, options.signal);\n }\n throwIfOfflineSyncAborted(options.signal);\n return {\n path: options.relPath,\n sha256: digest.sha256,\n bytes: digest.bytes,\n mtimeMs: st.mtimeMs,\n };\n}\n\nexport async function applyOfflineSyncFileContentChunk(options: {\n root: string;\n sourceId: string;\n path: string;\n sha256: string;\n bytes: number;\n mtimeMs: number;\n offset?: number;\n content: Buffer;\n baseSha256?: string;\n includeTranscripts?: boolean;\n readFile?: (target: OfflineSyncFileTarget) => Promise<Buffer>;\n readFileDigest?: (target: OfflineSyncFileTarget) => Promise<OfflineSyncFileDigest>;\n writeFile?: (target: OfflineSyncFileWriteTarget) => Promise<void>;\n writeStagingFile?: (target: OfflineSyncFileStagingWriteTarget) => Promise<void>;\n writeFileChunks?: (target: OfflineSyncFileWriteChunksTarget) => Promise<void>;\n}): Promise<OfflineSyncApplyFileContentChunkResult> {\n const root = await ensureSyncRoot(options.root, \"applyOfflineSyncFileContentChunk\");\n const sourceId = normalizeSourceId(options.sourceId, \"sourceId\");\n const relPath = normalizeRelativePath(options.path, \"path\");\n const includeTranscripts = options.includeTranscripts !== false;\n if (shouldExcludeRelPath(relPath, includeTranscripts)) {\n throw new Error(`offline sync file content path is excluded: ${relPath}`);\n }\n if (isEmbeddingGenerationMarkerPath(relPath)) {\n throw new Error(`offline sync file content path is node-local: ${relPath}`);\n }\n const sha256 = assertSha256(options.sha256, \"sha256\");\n const bytes = assertNonNegativeInteger(options.bytes, \"bytes\");\n const mtimeMs = assertOfflineSyncMtimeMs(options.mtimeMs, \"mtimeMs\");\n const offset = options.offset === undefined\n ? 0\n : assertNonNegativeInteger(options.offset, \"offset\");\n const baseSha256 = options.baseSha256 === undefined\n ? undefined\n : assertSha256(options.baseSha256, \"baseSha256\");\n const preferIncomingRuntimeFile = shouldPreferIncomingOfflineRuntimeFile(relPath);\n if (!Buffer.isBuffer(options.content)) {\n throw new Error(\"content must be a Buffer\");\n }\n if (options.content.length > OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES) {\n throw new Error(\n `content chunk must be ${OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES} bytes or fewer`,\n );\n }\n if (bytes > 0 && options.content.length === 0) {\n throw new Error(\"content chunk must be non-empty before EOF\");\n }\n if (offset > bytes || offset + options.content.length > bytes) {\n throw new Error(`content chunk range exceeds declared file size for ${relPath}`);\n }\n if (options.writeFile && !options.writeFileChunks) {\n throw new Error(\"offline sync upload storage hooks require writeFileChunks\");\n }\n if (options.writeFile && !options.writeStagingFile) {\n throw new Error(\"offline sync upload storage hooks require writeStagingFile\");\n }\n const baseResult = {\n path: relPath,\n sha256,\n bytes,\n mtimeMs,\n offset,\n chunkBytes: options.content.length,\n done: offset + options.content.length === bytes,\n };\n const currentFileConflict = async (\n currentFile: OfflineSyncFileState | undefined,\n ): Promise<{ conflict: OfflineSyncConflict; currentFile?: OfflineSyncFileState } | null> => {\n if (!baseSha256 && currentFile && !preferIncomingRuntimeFile) {\n const conflict = await recordConflict({\n root,\n relPath,\n reason: \"remote_exists_for_local_create\",\n localSha256: currentFile.sha256,\n incomingSha256: sha256,\n writeConflictCopies: false,\n sourceId,\n writeFile: options.writeFile,\n });\n return {\n conflict,\n currentFile,\n };\n }\n if (baseSha256 && currentFile?.sha256 !== baseSha256 && !preferIncomingRuntimeFile) {\n const conflict = await recordConflict({\n root,\n relPath,\n reason: currentFile ? \"remote_changed_for_local_update\" : \"remote_deleted_for_local_update\",\n baseSha256,\n localSha256: currentFile?.sha256,\n incomingSha256: sha256,\n writeConflictCopies: false,\n sourceId,\n writeFile: options.writeFile,\n });\n return {\n conflict,\n ...(currentFile ? { currentFile } : {}),\n };\n }\n return null;\n };\n if (offset === 0) {\n await pruneOfflineUploadStaging(root);\n const currentFile = await readLocalFileState({\n rootAbs: root.abs,\n relPath,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n });\n if (currentFile && currentFile.sha256 === sha256) {\n await setSafeFileMtime(root, relPath, mtimeMs);\n return {\n ...baseResult,\n done: true,\n chunkBytes: 0,\n applied: false,\n skipped: true,\n currentFile: toFileState(currentFile),\n };\n }\n const conflictResult = await currentFileConflict(currentFile ? toFileState(currentFile) : undefined);\n if (conflictResult) {\n return {\n ...baseResult,\n done: true,\n chunkBytes: 0,\n applied: false,\n skipped: false,\n ...conflictResult,\n };\n }\n }\n\n const upload = await writeOfflineUploadChunk({\n root,\n sourceId,\n relPath,\n sha256,\n bytes,\n offset,\n content: options.content,\n readFile: options.readFile,\n writeFile: options.writeFile,\n writeStagingFile: options.writeStagingFile,\n });\n const done = baseResult.done;\n if (!done) {\n return {\n ...baseResult,\n applied: false,\n skipped: false,\n };\n }\n\n const digest = await digestOfflineUploadStagingContent({\n root,\n upload,\n readFile: options.readFile,\n });\n if (digest.sha256 !== sha256 || digest.bytes !== bytes) {\n await cleanupOfflineUpload(upload).catch(() => {});\n throw new Error(`offline sync upload checksum mismatch for ${relPath}`);\n }\n\n const currentFile = await readLocalFileState({\n rootAbs: root.abs,\n relPath,\n readFile: options.readFile,\n readFileDigest: options.readFileDigest,\n });\n const uploadedState: OfflineSyncFileState = {\n path: relPath,\n sha256,\n bytes,\n mtimeMs,\n };\n\n try {\n if (currentFile && currentFile.sha256 === sha256) {\n await setSafeFileMtime(root, relPath, mtimeMs);\n return {\n ...baseResult,\n applied: false,\n skipped: true,\n currentFile: uploadedState,\n };\n }\n\n const conflictResult = await currentFileConflict(currentFile ? toFileState(currentFile) : undefined);\n if (conflictResult) {\n return {\n ...baseResult,\n applied: false,\n skipped: false,\n ...conflictResult,\n };\n }\n\n await advanceEmbeddingGenerationMarker(root.abs, embeddingGenerationMembership(relPath), () =>\n writeSafeFileFromUpload(root, relPath, upload, options.readFile, options.writeFileChunks, mtimeMs),\n );\n return {\n ...baseResult,\n applied: true,\n skipped: false,\n currentFile: uploadedState,\n };\n } finally {\n await cleanupOfflineUpload(upload).catch(() => {});\n }\n}\n\n\nasync function deleteSafeFile(\n root: SafeArchiveRoot,\n relPath: string,\n deleteFile?: (target: OfflineSyncFileDeleteTarget) => Promise<void>,\n mtimeMs?: number,\n): Promise<void> {\n const target = await resolveSafeArchiveTarget(root, relPath);\n if (deleteFile) {\n await deleteFile({\n root: root.abs,\n path: relPath,\n filePath: target,\n ...(mtimeMs === undefined ? {} : { mtimeMs }),\n });\n return;\n }\n await unlink(target).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw error;\n });\n}\n\nasync function recordConflict(options: {\n root: SafeArchiveRoot;\n relPath: string;\n reason: OfflineSyncConflict[\"reason\"];\n baseSha256?: string;\n localSha256?: string;\n incomingSha256?: string;\n incomingBuffer?: Buffer;\n writeConflictCopies: boolean;\n sourceId: string;\n writeFile?: (target: OfflineSyncFileWriteTarget) => Promise<void>;\n}): Promise<OfflineSyncConflict> {\n let conflictPath: string | undefined;\n if (options.writeConflictCopies && options.incomingBuffer) {\n const sourceHash = hashText(options.sourceId).slice(0, 12);\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n conflictPath = `${SYNC_INTERNAL_DIR}/conflicts/${stamp}-${sourceHash}/${options.relPath}`;\n await writeSafeFile(options.root, conflictPath, options.incomingBuffer, options.writeFile);\n }\n return {\n path: options.relPath,\n reason: options.reason,\n baseSha256: options.baseSha256,\n localSha256: options.localSha256,\n incomingSha256: options.incomingSha256,\n ...(conflictPath ? { conflictPath } : {}),\n };\n}\n\nexport function defaultOfflineSyncStatePath(\n memoryDir: string,\n remoteId: string,\n namespace?: string,\n): string {\n const key = hashText(`${remoteId}\\0${namespace ?? \"\"}`).slice(0, 16);\n return path.join(path.resolve(memoryDir), SYNC_INTERNAL_DIR, \"state\", `${key}.json`);\n}\n\nexport async function readOfflineSyncState(\n statePath: string,\n): Promise<OfflineSyncState | null> {\n let raw: string;\n try {\n raw = await readFile(path.resolve(statePath), \"utf-8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n }\n const parsed = JSON.parse(raw) as unknown;\n return normalizeOfflineSyncState(parsed);\n}\n\nexport async function writeOfflineSyncState(\n statePath: string,\n state: OfflineSyncState,\n): Promise<void> {\n const normalized = normalizeOfflineSyncState(state);\n const target = path.resolve(statePath);\n await mkdir(path.dirname(target), { recursive: true });\n const tmp = path.join(\n path.dirname(target),\n `.remnic-sync-state.${process.pid}.${randomUUID()}.tmp`,\n );\n await writeFile(tmp, JSON.stringify(normalized, null, 2) + \"\\n\", \"utf-8\");\n try {\n await rename(tmp, target);\n } catch (error) {\n await unlink(tmp).catch(() => {});\n throw error;\n }\n}\n\nexport function offlineSyncStateFromSnapshot(options: {\n remoteId: string;\n namespace?: string;\n snapshot: OfflineSyncSnapshot;\n baseFiles?: readonly OfflineSyncFileState[];\n}): OfflineSyncState {\n const snapshot = normalizeOfflineSyncSnapshot(options.snapshot);\n return normalizeOfflineSyncState({\n version: OFFLINE_SYNC_STATE_VERSION,\n remoteId: options.remoteId,\n namespace: options.namespace,\n includeTranscripts: snapshot.includeTranscripts,\n lastSyncedAt: new Date().toISOString(),\n baseFiles: options.baseFiles ?? snapshot.files.map(toFileState),\n });\n}\n\nexport function normalizeOfflineSyncState(input: unknown): OfflineSyncState {\n if (!input || typeof input !== \"object\" || Array.isArray(input)) {\n throw new Error(\"offline sync state must be an object\");\n }\n const obj = input as Record<string, unknown>;\n if (obj.version !== OFFLINE_SYNC_STATE_VERSION) {\n throw new Error(`offline sync state version must be ${OFFLINE_SYNC_STATE_VERSION}`);\n }\n const namespace =\n typeof obj.namespace === \"string\" && obj.namespace.trim().length > 0\n ? obj.namespace.trim()\n : undefined;\n const baseFiles = normalizeFileStates(obj.baseFiles as readonly unknown[] | undefined)\n .sort(compareByPath);\n assertUniquePaths(baseFiles, \"offline sync state\");\n return {\n version: OFFLINE_SYNC_STATE_VERSION,\n remoteId: normalizeSourceId(obj.remoteId, \"remoteId\"),\n ...(namespace ? { namespace } : {}),\n includeTranscripts: assertBoolean(obj.includeTranscripts, \"includeTranscripts\"),\n lastSyncedAt: normalizeIsoString(obj.lastSyncedAt, \"lastSyncedAt\"),\n baseFiles,\n };\n}\n\nexport function fileStatesFromSnapshot(snapshot: OfflineSyncSnapshot): OfflineSyncFileState[] {\n return normalizeOfflineSyncSnapshot(snapshot).files.map(toFileState).sort(compareByPath);\n}\n"],"mappings":"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","names":["chunk","digest","currentFile"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/offline-sync-file-io.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { createReadStream } from \"node:fs\";\nimport { open } from \"node:fs/promises\";\nimport { throwIfAborted } from \"./abort-error.js\";\nimport { MAGIC_HEADER_SIZE, isEncryptedFile } from \"./secure-store/secure-fs.js\";\n\nexport interface OfflineSyncFileTarget {\n root: string;\n path: string;\n filePath: string;\n}\n\nexport type OfflineSyncExcludeFile = (target: OfflineSyncFileTarget) => boolean | Promise<boolean>;\nexport async function shouldExcludeOfflineSyncFile(\n excludeFile: OfflineSyncExcludeFile | undefined,\n target: OfflineSyncFileTarget\n): Promise<boolean> {\n return excludeFile ? await excludeFile(target) : false;\n}\n\nexport async function sha256OfflineSyncFile(\n filePath: string,\n signal?: AbortSignal\n): Promise<{ sha256: string; bytes: number }> {\n const hash = createHash(\"sha256\");\n let bytes = 0;\n for await (const chunk of createReadStream(filePath)) {\n throwIfAborted(signal, \"offline sync request aborted\");\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n hash.update(buffer);\n bytes += buffer.length;\n }\n throwIfAborted(signal, \"offline sync request aborted\");\n return { sha256: hash.digest(\"hex\"), bytes };\n}\n\nexport async function isEncryptedOfflineSyncFile(filePath: string): Promise<boolean> {\n const handle = await open(filePath, \"r\");\n try {\n const header = Buffer.alloc(MAGIC_HEADER_SIZE);\n const { bytesRead } = await handle.read(header, 0, header.length, 0);\n return bytesRead >= MAGIC_HEADER_SIZE && isEncryptedFile(header);\n } finally {\n await handle.close();\n }\n}\n\nexport async function readPlainOfflineSyncFileChunk(options: {\n filePath: string;\n offset: number;\n length: number;\n bytes: number;\n}): Promise<Buffer> {\n const chunkBytes = Math.min(options.length, options.bytes - options.offset);\n const chunk = Buffer.alloc(chunkBytes);\n if (chunkBytes === 0) return chunk;\n const handle = await open(options.filePath, \"r\");\n try {\n const { bytesRead } = await handle.read(chunk, 0, chunk.length, options.offset);\n return bytesRead === chunk.length ? chunk : chunk.subarray(0, bytesRead);\n } finally {\n await handle.close();\n }\n}\n\n/** Streamed whole-file sha256 for plain-file chunk reads — the value the\n * file-content response contract exposes as x-remnic-file-sha256. Deliberately\n * UNCACHED: identity keys like (path, size, mtimeMs) are spoofable (a rewrite\n * that preserves size and mtime would serve a stale digest, defeating the\n * uploader's verify-before-idempotent-skip check). One bounded-memory hash\n * pass per chunk request; content reads stay windowed. */\nexport async function plainFileDigest(filePath: string): Promise<string> {\n const hash = createHash(\"sha256\");\n for await (const piece of createReadStream(filePath)) {\n hash.update(piece as Buffer);\n }\n return hash.digest(\"hex\");\n}\n\nimport { lstat, utimes } from \"node:fs/promises\";\nimport { isCensusMtimeMs } from \"./census-validation.js\";\nimport { resolveSafeArchiveTarget, type SafeArchiveRoot } from \"./transfer/fs-utils.js\";\n\n/** Sync-internal directory spooling partial uploads and coordination state. */\nexport const SYNC_INTERNAL_DIR = \".offline-sync\";\n\nexport const OFFLINE_SYNC_FAST_BASE_MTIME_TOLERANCE_MS = 1_000;\n\nexport function assertNonNegativeFinite(value: unknown, field: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n throw new Error(`${field} must be a non-negative finite number`);\n }\n return value;\n}\n\nexport function assertOfflineSyncMtimeMs(value: unknown, field: string): number {\n const mtimeMs = assertNonNegativeFinite(value, field);\n if (!isCensusMtimeMs(mtimeMs)) {\n throw new Error(`${field} must be within JavaScript Date range`);\n }\n return mtimeMs;\n}\n\nexport async function setSafeFileMtime(\n root: SafeArchiveRoot,\n relPath: string,\n mtimeMs: number | undefined,\n): Promise<boolean> {\n if (mtimeMs === undefined) return true;\n const target = await resolveSafeArchiveTarget(root, relPath);\n const targetStat = await lstat(target).catch((error: unknown) => {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw error;\n });\n if (!targetStat) return false;\n if (targetStat.isSymbolicLink()) {\n throw new Error(`offline sync target is a symlink: ${relPath}`);\n }\n const targetMtimeMs = assertOfflineSyncMtimeMs(mtimeMs, \"mtimeMs\");\n if (Math.abs(targetStat.mtimeMs - targetMtimeMs) <= OFFLINE_SYNC_FAST_BASE_MTIME_TOLERANCE_MS) {\n return true;\n }\n const mtime = new Date(targetMtimeMs);\n await utimes(target, mtime, mtime);\n return true;\n}\n"],"mappings":"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","names":[]}