@remnic/core 1.1.12 → 1.1.14

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 (1324) hide show
  1. package/dist/access-cli.d.ts +2 -1
  2. package/dist/access-cli.js +263 -82
  3. package/dist/access-cli.js.map +1 -1
  4. package/dist/access-http.d.ts +26 -60
  5. package/dist/access-http.js +43 -29
  6. package/dist/access-mcp.d.ts +24 -6
  7. package/dist/access-mcp.js +35 -28
  8. package/dist/access-schema.d.ts +9 -6
  9. package/dist/access-schema.js +7 -5
  10. package/dist/access-service-DcCDmNYC.d.ts +1542 -0
  11. package/dist/access-service.d.ts +25 -7
  12. package/dist/access-service.js +33 -26
  13. package/dist/active-memory-bridge.js +2 -2
  14. package/dist/active-recall.js +11 -3
  15. package/dist/active-recall.js.map +1 -1
  16. package/dist/adapters/claude-code.d.ts +24 -0
  17. package/dist/adapters/claude-code.js +9 -0
  18. package/dist/adapters/codex.d.ts +25 -0
  19. package/dist/adapters/codex.js +9 -0
  20. package/dist/adapters/hermes.d.ts +35 -0
  21. package/dist/adapters/hermes.js +9 -0
  22. package/dist/adapters/index.d.ts +6 -0
  23. package/dist/adapters/index.js +26 -0
  24. package/dist/adapters/registry.d.ts +20 -0
  25. package/dist/adapters/registry.js +13 -0
  26. package/dist/adapters/replit.d.ts +28 -0
  27. package/dist/adapters/replit.js +9 -0
  28. package/dist/adapters/types.d.ts +43 -0
  29. package/dist/adapters/types.js +8 -0
  30. package/dist/bootstrap.d.ts +20 -5
  31. package/dist/boxes.d.ts +7 -0
  32. package/dist/boxes.js +1 -1
  33. package/dist/briefing.d.ts +5 -3
  34. package/dist/briefing.js +9 -6
  35. package/dist/buffer-surprise-report.js +1 -1
  36. package/dist/buffer.d.ts +18 -4
  37. package/dist/buffer.js +1 -1
  38. package/dist/calibration.js +4 -4
  39. package/dist/capsule-cli.d.ts +4 -4
  40. package/dist/capsule-cli.js +1 -1
  41. package/dist/capsule-crypto-5CYAGVC5.js +18 -0
  42. package/dist/capsule-merge-4MGKE7C5.js +189 -0
  43. package/dist/causal-behavior.d.ts +8 -28
  44. package/dist/causal-behavior.js +6 -3
  45. package/dist/causal-behavior.js.map +1 -1
  46. package/dist/causal-chain.js +3 -2
  47. package/dist/causal-consolidation.d.ts +1 -1
  48. package/dist/causal-consolidation.js +24 -13
  49. package/dist/causal-consolidation.js.map +1 -1
  50. package/dist/causal-retrieval.js +3 -3
  51. package/dist/causal-trajectory.js +1 -1
  52. package/dist/chunk-25MQ7IHJ.js +427 -0
  53. package/dist/chunk-25MQ7IHJ.js.map +1 -0
  54. package/dist/chunk-2F2W355T.js +256 -0
  55. package/dist/chunk-2F2W355T.js.map +1 -0
  56. package/dist/chunk-2KI4QFHU.js +228 -0
  57. package/dist/chunk-2KI4QFHU.js.map +1 -0
  58. package/dist/chunk-2PRQG7PV.js +86 -0
  59. package/dist/chunk-2PRQG7PV.js.map +1 -0
  60. package/dist/chunk-2QR3XXIC.js +2272 -0
  61. package/dist/chunk-2QR3XXIC.js.map +1 -0
  62. package/dist/chunk-2WWLHTZY.js +121 -0
  63. package/dist/chunk-326G7DJK.js +2185 -0
  64. package/dist/chunk-326G7DJK.js.map +1 -0
  65. package/dist/chunk-34DQE4KF.js +174 -0
  66. package/dist/chunk-34DQE4KF.js.map +1 -0
  67. package/dist/chunk-3APJ5EVB.js +601 -0
  68. package/dist/chunk-3APJ5EVB.js.map +1 -0
  69. package/dist/chunk-3HPAPHUK.js +51 -0
  70. package/dist/chunk-3HPAPHUK.js.map +1 -0
  71. package/dist/chunk-3JXBXXM2.js +69 -0
  72. package/dist/chunk-3JXBXXM2.js.map +1 -0
  73. package/dist/chunk-3KW65B36.js +681 -0
  74. package/dist/chunk-3KW65B36.js.map +1 -0
  75. package/dist/chunk-3UXOZBHV.js +20 -0
  76. package/dist/chunk-3UXOZBHV.js.map +1 -0
  77. package/dist/chunk-3VAL7ZL2.js +266 -0
  78. package/dist/chunk-3VAL7ZL2.js.map +1 -0
  79. package/dist/chunk-3Y4P7RXM.js +31 -0
  80. package/dist/chunk-3Y4P7RXM.js.map +1 -0
  81. package/dist/chunk-47VWKCAF.js +273 -0
  82. package/dist/chunk-47VWKCAF.js.map +1 -0
  83. package/dist/chunk-4CRG46BG.js +271 -0
  84. package/dist/chunk-5375UYTQ.js +914 -0
  85. package/dist/chunk-5375UYTQ.js.map +1 -0
  86. package/dist/chunk-56K5QLHX.js +506 -0
  87. package/dist/chunk-56K5QLHX.js.map +1 -0
  88. package/dist/chunk-5RGLBDQF.js +596 -0
  89. package/dist/chunk-5RGLBDQF.js.map +1 -0
  90. package/dist/chunk-5UZXUTVO.js +9 -0
  91. package/dist/chunk-5UZXUTVO.js.map +1 -0
  92. package/dist/chunk-65PG43EQ.js +105 -0
  93. package/dist/chunk-65PG43EQ.js.map +1 -0
  94. package/dist/chunk-66DHUKLO.js +57 -0
  95. package/dist/chunk-66DHUKLO.js.map +1 -0
  96. package/dist/chunk-6FC5EGNV.js +46 -0
  97. package/dist/chunk-6FC5EGNV.js.map +1 -0
  98. package/dist/chunk-6H2TESSP.js +62 -0
  99. package/dist/chunk-6H2TESSP.js.map +1 -0
  100. package/dist/chunk-6LVVDPJ4.js +32 -0
  101. package/dist/chunk-6LVVDPJ4.js.map +1 -0
  102. package/dist/chunk-6RVI47ZR.js +159 -0
  103. package/dist/chunk-6RVI47ZR.js.map +1 -0
  104. package/dist/chunk-7AAT6G4Q.js +5117 -0
  105. package/dist/chunk-7AAT6G4Q.js.map +1 -0
  106. package/dist/chunk-7DTASS5T.js +29 -0
  107. package/dist/chunk-7DTASS5T.js.map +1 -0
  108. package/dist/chunk-7IASACLB.js +596 -0
  109. package/dist/chunk-7MNMYOFP.js +32 -0
  110. package/dist/chunk-7MNMYOFP.js.map +1 -0
  111. package/dist/chunk-7N4KAIGN.js +133 -0
  112. package/dist/chunk-7N4KAIGN.js.map +1 -0
  113. package/dist/chunk-7OZ53EXP.js +101 -0
  114. package/dist/chunk-7OZ53EXP.js.map +1 -0
  115. package/dist/chunk-7XYTQGCC.js +134 -0
  116. package/dist/chunk-7XYTQGCC.js.map +1 -0
  117. package/dist/chunk-A2XUIMJ3.js +341 -0
  118. package/dist/chunk-A2XUIMJ3.js.map +1 -0
  119. package/dist/chunk-AGZQD76C.js +201 -0
  120. package/dist/chunk-AGZQD76C.js.map +1 -0
  121. package/dist/chunk-APO3DCMU.js +361 -0
  122. package/dist/chunk-APO3DCMU.js.map +1 -0
  123. package/dist/chunk-BFBF3XEF.js +283 -0
  124. package/dist/chunk-BFBF3XEF.js.map +1 -0
  125. package/dist/chunk-BJ3KMYTB.js +1974 -0
  126. package/dist/chunk-BJ3KMYTB.js.map +1 -0
  127. package/dist/chunk-CHEL3SKB.js +6758 -0
  128. package/dist/chunk-CHEL3SKB.js.map +1 -0
  129. package/dist/chunk-CQZRLNMV.js +1491 -0
  130. package/dist/chunk-CQZRLNMV.js.map +1 -0
  131. package/dist/chunk-D46YSIYX.js +892 -0
  132. package/dist/chunk-D46YSIYX.js.map +1 -0
  133. package/dist/chunk-DINWEURR.js +648 -0
  134. package/dist/chunk-DINWEURR.js.map +1 -0
  135. package/dist/chunk-DK5LDEQM.js +530 -0
  136. package/dist/chunk-DK5LDEQM.js.map +1 -0
  137. package/dist/chunk-DOM4GKSW.js +34 -0
  138. package/dist/chunk-DOM4GKSW.js.map +1 -0
  139. package/dist/chunk-EDTHC6UD.js +1075 -0
  140. package/dist/chunk-EFJ3MQ4V.js +721 -0
  141. package/dist/chunk-EHRTFRWW.js +89 -0
  142. package/dist/chunk-EHRTFRWW.js.map +1 -0
  143. package/dist/chunk-FAJ7FZYM.js +11 -0
  144. package/dist/chunk-FAJ7FZYM.js.map +1 -0
  145. package/dist/chunk-FBYESMQ2.js +570 -0
  146. package/dist/chunk-FDU6HUUL.js +147 -0
  147. package/dist/chunk-FF4KLI5W.js +99 -0
  148. package/dist/chunk-FF4KLI5W.js.map +1 -0
  149. package/dist/chunk-FIT6DMX6.js +310 -0
  150. package/dist/chunk-FIT6DMX6.js.map +1 -0
  151. package/dist/chunk-FJ43PRLT.js +272 -0
  152. package/dist/chunk-FJ43PRLT.js.map +1 -0
  153. package/dist/chunk-FKFMOY3N.js +32 -0
  154. package/dist/chunk-FKFMOY3N.js.map +1 -0
  155. package/dist/chunk-FLTNHQK6.js +262 -0
  156. package/dist/chunk-FLTNHQK6.js.map +1 -0
  157. package/dist/chunk-GA454ALV.js +12436 -0
  158. package/dist/chunk-GA454ALV.js.map +1 -0
  159. package/dist/chunk-GGKRUQOO.js +228 -0
  160. package/dist/chunk-GIF42EW3.js +63 -0
  161. package/dist/chunk-GIF42EW3.js.map +1 -0
  162. package/dist/chunk-GL6I6MEQ.js +647 -0
  163. package/dist/chunk-H3ME6L6D.js +709 -0
  164. package/dist/chunk-H3ME6L6D.js.map +1 -0
  165. package/dist/chunk-HHLLAQGZ.js +1 -0
  166. package/dist/chunk-HXXBL2KD.js +2040 -0
  167. package/dist/chunk-I5V2VDIW.js +219 -0
  168. package/dist/chunk-I5V2VDIW.js.map +1 -0
  169. package/dist/chunk-I6K5FBRQ.js +35 -0
  170. package/dist/chunk-I6K5FBRQ.js.map +1 -0
  171. package/dist/chunk-ICRIXAP2.js +121 -0
  172. package/dist/chunk-ICRIXAP2.js.map +1 -0
  173. package/dist/chunk-J4EB7DNW.js +11 -0
  174. package/dist/chunk-J4EB7DNW.js.map +1 -0
  175. package/dist/chunk-JLFA7DQG.js +62 -0
  176. package/dist/chunk-JLFA7DQG.js.map +1 -0
  177. package/dist/chunk-KJTKLXTH.js +9 -0
  178. package/dist/chunk-KJTKLXTH.js.map +1 -0
  179. package/dist/chunk-KLAO5DGL.js +917 -0
  180. package/dist/chunk-KLAO5DGL.js.map +1 -0
  181. package/dist/chunk-KNKUID7G.js +183 -0
  182. package/dist/chunk-KOSORCJG.js +624 -0
  183. package/dist/chunk-KOSORCJG.js.map +1 -0
  184. package/dist/chunk-KUJVMMZQ.js +1262 -0
  185. package/dist/chunk-KUJVMMZQ.js.map +1 -0
  186. package/dist/chunk-LCR46JY5.js +123 -0
  187. package/dist/chunk-LCR46JY5.js.map +1 -0
  188. package/dist/chunk-LLQ2LLWF.js +148 -0
  189. package/dist/chunk-LLQ2LLWF.js.map +1 -0
  190. package/dist/chunk-LPMVBPA3.js +236 -0
  191. package/dist/chunk-LT3NLYSI.js +50 -0
  192. package/dist/chunk-LT3NLYSI.js.map +1 -0
  193. package/dist/chunk-LUDTDZLK.js +287 -0
  194. package/dist/chunk-LUDTDZLK.js.map +1 -0
  195. package/dist/chunk-M23FSH32.js +3963 -0
  196. package/dist/chunk-M23FSH32.js.map +1 -0
  197. package/dist/chunk-MC26UJIM.js +118 -0
  198. package/dist/chunk-ME6ESPZU.js +119 -0
  199. package/dist/chunk-ME6ESPZU.js.map +1 -0
  200. package/dist/chunk-MGKYQQYF.js +272 -0
  201. package/dist/chunk-MJFNCJXV.js +66 -0
  202. package/dist/chunk-MJFNCJXV.js.map +1 -0
  203. package/dist/chunk-MSWG7JI6.js +237 -0
  204. package/dist/chunk-MSWG7JI6.js.map +1 -0
  205. package/dist/chunk-MT25YHYH.js +141 -0
  206. package/dist/chunk-MT25YHYH.js.map +1 -0
  207. package/dist/chunk-MT4HVDUZ.js +53 -0
  208. package/dist/chunk-MY6TPVXW.js +219 -0
  209. package/dist/chunk-N2D6GXBM.js +267 -0
  210. package/dist/chunk-N2D6GXBM.js.map +1 -0
  211. package/dist/chunk-NJ3MJQZX.js +46 -0
  212. package/dist/chunk-NJ3MJQZX.js.map +1 -0
  213. package/dist/chunk-NMZY542O.js +335 -0
  214. package/dist/chunk-NMZY542O.js.map +1 -0
  215. package/dist/chunk-NNVTUXEB.js +23 -0
  216. package/dist/chunk-NZL6GGQE.js +375 -0
  217. package/dist/chunk-NZL6GGQE.js.map +1 -0
  218. package/dist/chunk-P4NEIHUT.js +108 -0
  219. package/dist/chunk-P7FMDTKL.js +103 -0
  220. package/dist/chunk-P7FMDTKL.js.map +1 -0
  221. package/dist/chunk-PHK3HARR.js +32 -0
  222. package/dist/chunk-PHK3HARR.js.map +1 -0
  223. package/dist/chunk-PIRJPV5T.js +98 -0
  224. package/dist/chunk-PIRJPV5T.js.map +1 -0
  225. package/dist/chunk-PK7H5L6Y.js +159 -0
  226. package/dist/chunk-PK7H5L6Y.js.map +1 -0
  227. package/dist/chunk-PR5FBTFU.js +233 -0
  228. package/dist/chunk-PR5FBTFU.js.map +1 -0
  229. package/dist/chunk-PU63GXWS.js +174 -0
  230. package/dist/chunk-PU63GXWS.js.map +1 -0
  231. package/dist/chunk-PZIAX57I.js +124 -0
  232. package/dist/chunk-PZIAX57I.js.map +1 -0
  233. package/dist/chunk-Q7P4WJDP.js +26 -0
  234. package/dist/chunk-Q7P4WJDP.js.map +1 -0
  235. package/dist/chunk-QQUAB63I.js +63 -0
  236. package/dist/chunk-QQUAB63I.js.map +1 -0
  237. package/dist/chunk-QRNI5JBH.js +18 -0
  238. package/dist/chunk-RHY3HH7P.js +601 -0
  239. package/dist/chunk-RHY3HH7P.js.map +1 -0
  240. package/dist/chunk-RRF5UOBJ.js +91 -0
  241. package/dist/chunk-RXDLTSWT.js +124 -0
  242. package/dist/chunk-RXDLTSWT.js.map +1 -0
  243. package/dist/chunk-RYED3SPJ.js +42 -0
  244. package/dist/chunk-RYED3SPJ.js.map +1 -0
  245. package/dist/chunk-S7KDBTWT.js +106 -0
  246. package/dist/chunk-S7KDBTWT.js.map +1 -0
  247. package/dist/chunk-SEDEKFYQ.js +1 -0
  248. package/dist/chunk-TECVW3JP.js +36 -0
  249. package/dist/chunk-TECVW3JP.js.map +1 -0
  250. package/dist/chunk-TFO23QT4.js +88 -0
  251. package/dist/chunk-TFO23QT4.js.map +1 -0
  252. package/dist/chunk-TK4UEOSK.js +76 -0
  253. package/dist/chunk-TK4UEOSK.js.map +1 -0
  254. package/dist/chunk-TKWGAOLV.js +122 -0
  255. package/dist/chunk-TKWGAOLV.js.map +1 -0
  256. package/dist/chunk-TMM4S4IJ.js +597 -0
  257. package/dist/chunk-TMM4S4IJ.js.map +1 -0
  258. package/dist/chunk-TMQLARTH.js +188 -0
  259. package/dist/chunk-TMQLARTH.js.map +1 -0
  260. package/dist/chunk-TPDBFYEG.js +130 -0
  261. package/dist/chunk-TPDBFYEG.js.map +1 -0
  262. package/dist/chunk-TPMQ3G6Z.js +145 -0
  263. package/dist/chunk-TPMQ3G6Z.js.map +1 -0
  264. package/dist/chunk-TZOLIGIG.js +61 -0
  265. package/dist/chunk-TZOLIGIG.js.map +1 -0
  266. package/dist/chunk-U3PN77QT.js +113 -0
  267. package/dist/chunk-U3WSW6PZ.js +277 -0
  268. package/dist/chunk-U4SCL7B7.js +640 -0
  269. package/dist/chunk-U4SCL7B7.js.map +1 -0
  270. package/dist/chunk-UWK5OXUJ.js +156 -0
  271. package/dist/chunk-UWK5OXUJ.js.map +1 -0
  272. package/dist/chunk-UWVJF25J.js +74 -0
  273. package/dist/chunk-UXHQAFNA.js +1317 -0
  274. package/dist/chunk-UXHQAFNA.js.map +1 -0
  275. package/dist/chunk-V5OCT34X.js +1 -0
  276. package/dist/chunk-VLXA6PI2.js +304 -0
  277. package/dist/chunk-VLXA6PI2.js.map +1 -0
  278. package/dist/chunk-VNO6ZJ35.js +500 -0
  279. package/dist/chunk-VNO6ZJ35.js.map +1 -0
  280. package/dist/chunk-VW676BEI.js +827 -0
  281. package/dist/chunk-VW676BEI.js.map +1 -0
  282. package/dist/chunk-W3LR522O.js +2296 -0
  283. package/dist/chunk-W4L6CZKA.js +96 -0
  284. package/dist/chunk-W4L6CZKA.js.map +1 -0
  285. package/dist/chunk-W4RVMTHR.js +372 -0
  286. package/dist/chunk-W4RVMTHR.js.map +1 -0
  287. package/dist/chunk-WEHSQBFR.js +188 -0
  288. package/dist/chunk-WEHSQBFR.js.map +1 -0
  289. package/dist/chunk-WELDCG6C.js +380 -0
  290. package/dist/chunk-WELDCG6C.js.map +1 -0
  291. package/dist/chunk-WZYKANL3.js +2800 -0
  292. package/dist/chunk-WZYKANL3.js.map +1 -0
  293. package/dist/chunk-XIG5PDM7.js +48 -0
  294. package/dist/chunk-XJNBEDFE.js +193 -0
  295. package/dist/chunk-XJNBEDFE.js.map +1 -0
  296. package/dist/chunk-XVVIG67A.js +291 -0
  297. package/dist/chunk-XVVIG67A.js.map +1 -0
  298. package/dist/chunk-XVZ7B3HG.js +135 -0
  299. package/dist/chunk-YBPYIAA5.js +73 -0
  300. package/dist/chunk-YBPYIAA5.js.map +1 -0
  301. package/dist/chunk-Z734BLO3.js +21 -0
  302. package/dist/chunk-Z734BLO3.js.map +1 -0
  303. package/dist/chunk-ZKSK55RC.js +269 -0
  304. package/dist/chunk-ZKSK55RC.js.map +1 -0
  305. package/dist/chunk-ZTFCYYEZ.js +69 -0
  306. package/dist/chunk-ZTFCYYEZ.js.map +1 -0
  307. package/dist/chunk-ZY2MNJR6.js +329 -0
  308. package/dist/chunk-ZY2MNJR6.js.map +1 -0
  309. package/dist/cli-D3VpkVwB.d.ts +1136 -0
  310. package/dist/cli.d.ts +39 -10
  311. package/dist/cli.js +108 -49
  312. package/dist/commitment-ledger.js +1 -1
  313. package/dist/compat/checks.d.ts +5 -0
  314. package/dist/compat/checks.js +11 -0
  315. package/dist/compat/checks.js.map +1 -0
  316. package/dist/compat/types.d.ts +30 -0
  317. package/dist/compat/types.js +1 -0
  318. package/dist/compat/types.js.map +1 -0
  319. package/dist/compounding/engine.d.ts +221 -0
  320. package/dist/compounding/engine.js +32 -0
  321. package/dist/compounding/engine.js.map +1 -0
  322. package/dist/compounding/preference-consolidator.d.ts +92 -0
  323. package/dist/compounding/preference-consolidator.js +553 -0
  324. package/dist/compounding/preference-consolidator.js.map +1 -0
  325. package/dist/config.d.ts +4 -2
  326. package/dist/config.js +9 -4
  327. package/dist/conflict-policy-DyJ2wd-h.d.ts +4 -0
  328. package/dist/connectors/codex-materialize-runner.d.ts +64 -0
  329. package/dist/connectors/codex-materialize-runner.js +33 -0
  330. package/dist/connectors/codex-materialize-runner.js.map +1 -0
  331. package/dist/connectors/codex-materialize.d.ts +195 -0
  332. package/dist/connectors/codex-materialize.js +38 -0
  333. package/dist/connectors/codex-materialize.js.map +1 -0
  334. package/dist/connectors/index.d.ts +444 -0
  335. package/dist/connectors/index.js +115 -0
  336. package/dist/connectors/index.js.map +1 -0
  337. package/dist/connectors-cli-CwbyjGR7.d.ts +257 -0
  338. package/dist/connectors-cli.d.ts +1 -1
  339. package/dist/consolidation-provenance-check.d.ts +3 -1
  340. package/dist/consolidation-undo.d.ts +3 -1
  341. package/dist/contradiction/index.d.ts +258 -0
  342. package/dist/contradiction/index.js +43 -0
  343. package/dist/contradiction/index.js.map +1 -0
  344. package/dist/contradiction-review-ATP4S6IC.js +30 -0
  345. package/dist/contradiction-review-ATP4S6IC.js.map +1 -0
  346. package/dist/contradiction-scan-5A4IDZV5.js +13 -0
  347. package/dist/contradiction-scan-5A4IDZV5.js.map +1 -0
  348. package/dist/conversation-index/backend.d.ts +97 -0
  349. package/dist/conversation-index/backend.js +13 -0
  350. package/dist/conversation-index/backend.js.map +1 -0
  351. package/dist/conversation-index/chunker.d.ts +16 -0
  352. package/dist/conversation-index/chunker.js +8 -0
  353. package/dist/conversation-index/chunker.js.map +1 -0
  354. package/dist/conversation-index/cleanup.d.ts +11 -0
  355. package/dist/conversation-index/cleanup.js +9 -0
  356. package/dist/conversation-index/cleanup.js.map +1 -0
  357. package/dist/conversation-index/faiss-adapter.d.ts +6 -0
  358. package/dist/conversation-index/faiss-adapter.js +16 -0
  359. package/dist/conversation-index/faiss-adapter.js.map +1 -0
  360. package/dist/conversation-index/indexer.d.ts +23 -0
  361. package/dist/conversation-index/indexer.js +15 -0
  362. package/dist/conversation-index/indexer.js.map +1 -0
  363. package/dist/conversation-index/search.d.ts +6 -0
  364. package/dist/conversation-index/search.js +11 -0
  365. package/dist/conversation-index/search.js.map +1 -0
  366. package/dist/embedding-fallback.js +2 -2
  367. package/dist/enrichment/index.d.ts +163 -0
  368. package/dist/enrichment/index.js +18 -0
  369. package/dist/enrichment/index.js.map +1 -0
  370. package/dist/entity-retrieval.d.ts +4 -2
  371. package/dist/entity-retrieval.js +8 -5
  372. package/dist/evals.js +1 -1
  373. package/dist/explicit-capture.d.ts +20 -5
  374. package/dist/explicit-capture.js +2 -2
  375. package/dist/extraction-judge-training.js +1 -1
  376. package/dist/extraction.js +8 -8
  377. package/dist/faiss-adapter-CzPghc4C.d.ts +70 -0
  378. package/dist/fallback-llm.d.ts +2 -0
  379. package/dist/fallback-llm.js +4 -4
  380. package/dist/graph-edge-decay-5DI5GUNL.js +207 -0
  381. package/dist/index.d.ts +66 -711
  382. package/dist/index.js +556 -2680
  383. package/dist/index.js.map +1 -1
  384. package/dist/lcm/archive.d.ts +89 -0
  385. package/dist/lcm/archive.js +12 -0
  386. package/dist/lcm/archive.js.map +1 -0
  387. package/dist/lcm/dag.d.ts +48 -0
  388. package/dist/lcm/dag.js +8 -0
  389. package/dist/lcm/dag.js.map +1 -0
  390. package/dist/lcm/engine.d.ts +116 -0
  391. package/dist/lcm/engine.js +20 -0
  392. package/dist/lcm/engine.js.map +1 -0
  393. package/dist/lcm/index.d.ts +12 -0
  394. package/dist/lcm/index.js +44 -0
  395. package/dist/lcm/index.js.map +1 -0
  396. package/dist/lcm/queue.d.ts +62 -0
  397. package/dist/lcm/queue.js +8 -0
  398. package/dist/lcm/queue.js.map +1 -0
  399. package/dist/lcm/recall.d.ts +20 -0
  400. package/dist/lcm/recall.js +8 -0
  401. package/dist/lcm/recall.js.map +1 -0
  402. package/dist/lcm/schema.d.ts +16 -0
  403. package/dist/lcm/schema.js +14 -0
  404. package/dist/lcm/schema.js.map +1 -0
  405. package/dist/lcm/summarizer.d.ts +38 -0
  406. package/dist/lcm/summarizer.js +12 -0
  407. package/dist/lcm/summarizer.js.map +1 -0
  408. package/dist/lcm/tools.d.ts +29 -0
  409. package/dist/lcm/tools.js +8 -0
  410. package/dist/lcm/tools.js.map +1 -0
  411. package/dist/live-connectors-runner.js +5 -5
  412. package/dist/local-llm.js +3 -3
  413. package/dist/maintenance/archive-observations.d.ts +18 -0
  414. package/dist/maintenance/archive-observations.js +8 -0
  415. package/dist/maintenance/archive-observations.js.map +1 -0
  416. package/dist/maintenance/backup-stamp.d.ts +3 -0
  417. package/dist/maintenance/backup-stamp.js +8 -0
  418. package/dist/maintenance/backup-stamp.js.map +1 -0
  419. package/dist/maintenance/memory-governance-cron.d.ts +85 -0
  420. package/dist/maintenance/memory-governance-cron.js +22 -0
  421. package/dist/maintenance/memory-governance-cron.js.map +1 -0
  422. package/dist/maintenance/memory-governance.d.ts +137 -0
  423. package/dist/maintenance/memory-governance.js +40 -0
  424. package/dist/maintenance/memory-governance.js.map +1 -0
  425. package/dist/maintenance/migrate-observations.d.ts +18 -0
  426. package/dist/maintenance/migrate-observations.js +9 -0
  427. package/dist/maintenance/migrate-observations.js.map +1 -0
  428. package/dist/maintenance/observation-ledger-utils.d.ts +10 -0
  429. package/dist/maintenance/observation-ledger-utils.js +10 -0
  430. package/dist/maintenance/observation-ledger-utils.js.map +1 -0
  431. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +15 -0
  432. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +28 -0
  433. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js.map +1 -0
  434. package/dist/maintenance/rebuild-memory-projection.d.ts +77 -0
  435. package/dist/maintenance/rebuild-memory-projection.js +35 -0
  436. package/dist/maintenance/rebuild-memory-projection.js.map +1 -0
  437. package/dist/maintenance/rebuild-observations.d.ts +17 -0
  438. package/dist/maintenance/rebuild-observations.js +9 -0
  439. package/dist/maintenance/rebuild-observations.js.map +1 -0
  440. package/dist/mcp-memory-inspector-app.d.ts +24 -6
  441. package/dist/memory-projection-store.d.ts +108 -3
  442. package/dist/memory-projection-store.js +2 -1
  443. package/dist/memory-worth-outcomes.d.ts +4 -2
  444. package/dist/migrate/from-engram.d.ts +24 -0
  445. package/dist/migrate/from-engram.js +12 -0
  446. package/dist/migrate/from-engram.js.map +1 -0
  447. package/dist/namespaces/migrate.d.ts +50 -0
  448. package/dist/namespaces/migrate.js +50 -0
  449. package/dist/namespaces/migrate.js.map +1 -0
  450. package/dist/namespaces/principal.d.ts +17 -0
  451. package/dist/namespaces/principal.js +16 -0
  452. package/dist/namespaces/principal.js.map +1 -0
  453. package/dist/namespaces/search.d.ts +46 -0
  454. package/dist/namespaces/search.js +28 -0
  455. package/dist/namespaces/search.js.map +1 -0
  456. package/dist/namespaces/storage.d.ts +32 -0
  457. package/dist/namespaces/storage.js +28 -0
  458. package/dist/namespaces/storage.js.map +1 -0
  459. package/dist/network/tailscale.d.ts +41 -0
  460. package/dist/network/tailscale.js +9 -0
  461. package/dist/network/tailscale.js.map +1 -0
  462. package/dist/network/webdav.d.ts +39 -0
  463. package/dist/network/webdav.js +10 -0
  464. package/dist/network/webdav.js.map +1 -0
  465. package/dist/objective-state-writers.js +2 -2
  466. package/dist/operator-toolkit.d.ts +4 -2
  467. package/dist/operator-toolkit.js +32 -14
  468. package/dist/opik-exporter.js +2 -2
  469. package/dist/opik-exporter.js.map +1 -1
  470. package/dist/orchestrator-DuWl9Hwx.d.ts +1244 -0
  471. package/dist/orchestrator.d.ts +22 -7
  472. package/dist/orchestrator.js +79 -44
  473. package/dist/path-MR5JPYOP.js +9 -0
  474. package/dist/path-MR5JPYOP.js.map +1 -0
  475. package/dist/qmd-recall-cache.d.ts +1 -1
  476. package/dist/qmd.d.ts +102 -3
  477. package/dist/qmd.js +23 -5
  478. package/dist/recall-explain-renderer.js +3 -3
  479. package/dist/recall-xray-cli.js +4 -4
  480. package/dist/recall-xray-renderer.js +3 -3
  481. package/dist/recall-xray.js +2 -2
  482. package/dist/replay/normalizers/chatgpt.d.ts +6 -0
  483. package/dist/replay/normalizers/chatgpt.js +11 -0
  484. package/dist/replay/normalizers/chatgpt.js.map +1 -0
  485. package/dist/replay/normalizers/claude.d.ts +6 -0
  486. package/dist/replay/normalizers/claude.js +11 -0
  487. package/dist/replay/normalizers/claude.js.map +1 -0
  488. package/dist/replay/normalizers/openclaw.d.ts +6 -0
  489. package/dist/replay/normalizers/openclaw.js +11 -0
  490. package/dist/replay/normalizers/openclaw.js.map +1 -0
  491. package/dist/replay/normalizers/shared.d.ts +16 -0
  492. package/dist/replay/normalizers/shared.js +14 -0
  493. package/dist/replay/normalizers/shared.js.map +1 -0
  494. package/dist/replay/runner.d.ts +35 -0
  495. package/dist/replay/runner.js +16 -0
  496. package/dist/replay/runner.js.map +1 -0
  497. package/dist/replay/types.d.ts +57 -0
  498. package/dist/replay/types.js +19 -0
  499. package/dist/replay/types.js.map +1 -0
  500. package/dist/resolution-B7FNQSSP.js +12 -0
  501. package/dist/resolution-B7FNQSSP.js.map +1 -0
  502. package/dist/resolve-provider-secret.js +2 -2
  503. package/dist/resume-bundles.js +8 -6
  504. package/dist/retrieval-agents.d.ts +1 -1
  505. package/dist/routing/engine.d.ts +35 -0
  506. package/dist/routing/engine.js +16 -0
  507. package/dist/routing/engine.js.map +1 -0
  508. package/dist/routing/store.d.ts +27 -0
  509. package/dist/routing/store.js +10 -0
  510. package/dist/routing/store.js.map +1 -0
  511. package/dist/runtime/better-sqlite.d.ts +8 -0
  512. package/dist/runtime/better-sqlite.js +10 -0
  513. package/dist/runtime/better-sqlite.js.map +1 -0
  514. package/dist/runtime/child-process.d.ts +32 -0
  515. package/dist/runtime/child-process.js +10 -0
  516. package/dist/runtime/child-process.js.map +1 -0
  517. package/dist/runtime/env.d.ts +5 -0
  518. package/dist/runtime/env.js +12 -0
  519. package/dist/runtime/env.js.map +1 -0
  520. package/dist/schemas.d.ts +22 -22
  521. package/dist/sdk-compat.js +1 -1
  522. package/dist/search/document-scanner.d.ts +22 -0
  523. package/dist/search/document-scanner.js +8 -0
  524. package/dist/search/document-scanner.js.map +1 -0
  525. package/dist/search/embed-helper.d.ts +35 -0
  526. package/dist/search/embed-helper.js +9 -0
  527. package/dist/search/embed-helper.js.map +1 -0
  528. package/dist/search/factory.d.ts +32 -0
  529. package/dist/search/factory.js +29 -0
  530. package/dist/search/factory.js.map +1 -0
  531. package/dist/search/index.d.ts +15 -0
  532. package/dist/search/index.js +50 -0
  533. package/dist/search/index.js.map +1 -0
  534. package/dist/search/lancedb-backend.d.ts +51 -0
  535. package/dist/search/lancedb-backend.js +10 -0
  536. package/dist/search/lancedb-backend.js.map +1 -0
  537. package/dist/search/meilisearch-backend.d.ts +48 -0
  538. package/dist/search/meilisearch-backend.js +10 -0
  539. package/dist/search/meilisearch-backend.js.map +1 -0
  540. package/dist/search/noop-backend.d.ts +26 -0
  541. package/dist/search/noop-backend.js +8 -0
  542. package/dist/search/noop-backend.js.map +1 -0
  543. package/dist/search/orama-backend.d.ts +53 -0
  544. package/dist/search/orama-backend.js +10 -0
  545. package/dist/search/orama-backend.js.map +1 -0
  546. package/dist/search/port.d.ts +61 -0
  547. package/dist/search/port.js +1 -0
  548. package/dist/search/port.js.map +1 -0
  549. package/dist/search/remote-backend.d.ts +39 -0
  550. package/dist/search/remote-backend.js +9 -0
  551. package/dist/search/remote-backend.js.map +1 -0
  552. package/dist/secure-store/index.d.ts +890 -0
  553. package/dist/secure-store/index.js +156 -0
  554. package/dist/secure-store/index.js.map +1 -0
  555. package/dist/semantic-VwGI14Ok.d.ts +69 -0
  556. package/dist/semantic-consolidation-4HkHWgeI.d.ts +180 -0
  557. package/dist/semantic-consolidation.d.ts +2 -2
  558. package/dist/semantic-consolidation.js +13 -6
  559. package/dist/semantic-rule-promotion.js +8 -5
  560. package/dist/semantic-rule-verifier.js +8 -5
  561. package/dist/shared-context/manager.d.ts +131 -0
  562. package/dist/shared-context/manager.js +15 -0
  563. package/dist/shared-context/manager.js.map +1 -0
  564. package/dist/skills-registry.js +13 -1
  565. package/dist/skills-registry.js.map +1 -1
  566. package/dist/state-store-VZU2IA53.js +16 -0
  567. package/dist/state-store-VZU2IA53.js.map +1 -0
  568. package/dist/storage-paths.d.ts +9 -0
  569. package/dist/storage-paths.js +20 -0
  570. package/dist/storage-paths.js.map +1 -0
  571. package/dist/storage.d.ts +3 -1
  572. package/dist/storage.js +7 -4
  573. package/dist/summarizer.d.ts +5 -0
  574. package/dist/summarizer.js +9 -8
  575. package/dist/summary-snapshot.js +2 -1
  576. package/dist/surfaces/dreams.d.ts +16 -0
  577. package/dist/surfaces/dreams.js +282 -0
  578. package/dist/surfaces/dreams.js.map +1 -0
  579. package/dist/surfaces/heartbeat.d.ts +17 -0
  580. package/dist/surfaces/heartbeat.js +265 -0
  581. package/dist/surfaces/heartbeat.js.map +1 -0
  582. package/dist/temporal-supersession.d.ts +3 -1
  583. package/dist/threading.d.ts +5 -0
  584. package/dist/threading.js +2 -1
  585. package/dist/tier-migration.d.ts +4 -2
  586. package/dist/tokens.js +2 -2
  587. package/dist/transcript.d.ts +15 -1
  588. package/dist/transcript.js +2 -1
  589. package/dist/transfer/autodetect.d.ts +4 -0
  590. package/dist/transfer/autodetect.js +15 -0
  591. package/dist/transfer/autodetect.js.map +1 -0
  592. package/dist/transfer/backup.d.ts +21 -0
  593. package/dist/transfer/backup.js +17 -0
  594. package/dist/transfer/backup.js.map +1 -0
  595. package/dist/transfer/capsule-export.d.ts +113 -0
  596. package/dist/transfer/capsule-export.js +19 -0
  597. package/dist/transfer/capsule-export.js.map +1 -0
  598. package/dist/transfer/capsule-import.d.ts +124 -0
  599. package/dist/transfer/capsule-import.js +16 -0
  600. package/dist/transfer/capsule-import.js.map +1 -0
  601. package/dist/transfer/constants.d.ts +13 -0
  602. package/dist/transfer/constants.js +12 -0
  603. package/dist/transfer/constants.js.map +1 -0
  604. package/dist/transfer/export-json.d.ts +11 -0
  605. package/dist/transfer/export-json.js +11 -0
  606. package/dist/transfer/export-json.js.map +1 -0
  607. package/dist/transfer/export-md.d.ts +10 -0
  608. package/dist/transfer/export-md.js +13 -0
  609. package/dist/transfer/export-md.js.map +1 -0
  610. package/dist/transfer/export-sqlite.d.ts +9 -0
  611. package/dist/transfer/export-sqlite.js +12 -0
  612. package/dist/transfer/export-sqlite.js.map +1 -0
  613. package/dist/transfer/fs-utils.d.ts +61 -0
  614. package/dist/transfer/fs-utils.js +40 -0
  615. package/dist/transfer/fs-utils.js.map +1 -0
  616. package/dist/transfer/import-json.d.ts +16 -0
  617. package/dist/transfer/import-json.js +13 -0
  618. package/dist/transfer/import-json.js.map +1 -0
  619. package/dist/transfer/import-md.d.ts +14 -0
  620. package/dist/transfer/import-md.js +11 -0
  621. package/dist/transfer/import-md.js.map +1 -0
  622. package/dist/transfer/import-sqlite.d.ts +14 -0
  623. package/dist/transfer/import-sqlite.js +12 -0
  624. package/dist/transfer/import-sqlite.js.map +1 -0
  625. package/dist/transfer/sqlite-schema.d.ts +4 -0
  626. package/dist/transfer/sqlite-schema.js +10 -0
  627. package/dist/transfer/sqlite-schema.js.map +1 -0
  628. package/dist/transfer/types.d.ts +916 -0
  629. package/dist/transfer/types.js +30 -0
  630. package/dist/transfer/types.js.map +1 -0
  631. package/dist/types.d.ts +28 -1
  632. package/dist/types.js +1 -1
  633. package/dist/verified-recall.js +9 -6
  634. package/dist/work/board.d.ts +43 -0
  635. package/dist/work/board.js +14 -0
  636. package/dist/work/board.js.map +1 -0
  637. package/dist/work/boundary.d.ts +8 -0
  638. package/dist/work/boundary.js +14 -0
  639. package/dist/work/boundary.js.map +1 -0
  640. package/dist/work/storage.d.ts +39 -0
  641. package/dist/work/storage.js +11 -0
  642. package/dist/work/storage.js.map +1 -0
  643. package/dist/work/types.d.ts +75 -0
  644. package/dist/work/types.js +1 -0
  645. package/dist/work/types.js.map +1 -0
  646. package/package.json +2767 -6
  647. package/scripts/faiss_index.py +816 -0
  648. package/scripts/faiss_requirements.txt +3 -0
  649. package/skills/remnic-entities/SKILL.md +51 -0
  650. package/skills/remnic-memory-workflow/SKILL.md +61 -0
  651. package/skills/remnic-recall/SKILL.md +51 -0
  652. package/skills/remnic-remember/SKILL.md +56 -0
  653. package/skills/remnic-search/SKILL.md +51 -0
  654. package/skills/remnic-status/SKILL.md +51 -0
  655. package/src/abort-error.test.ts +49 -0
  656. package/src/abort-error.ts +46 -0
  657. package/src/abstraction-nodes.ts +162 -0
  658. package/src/access-audit.test.ts +178 -0
  659. package/src/access-audit.ts +125 -0
  660. package/src/access-cli.test.ts +439 -0
  661. package/src/access-cli.ts +438 -0
  662. package/src/access-http.test.ts +225 -0
  663. package/src/access-http.ts +1899 -0
  664. package/src/access-idempotency.ts +232 -0
  665. package/src/access-mcp.test.ts +568 -0
  666. package/src/access-mcp.ts +3056 -0
  667. package/src/access-schema-pi.test.ts +60 -0
  668. package/src/access-schema.ts +522 -0
  669. package/src/access-service-namespace.test.ts +123 -0
  670. package/src/access-service.ts +5629 -0
  671. package/src/action-confidence.test.ts +206 -0
  672. package/src/action-confidence.ts +466 -0
  673. package/src/active-memory-bridge.test.ts +285 -0
  674. package/src/active-memory-bridge.ts +217 -0
  675. package/src/active-recall.test.ts +484 -0
  676. package/src/active-recall.ts +459 -0
  677. package/src/adapters/claude-code.ts +56 -0
  678. package/src/adapters/codex.ts +57 -0
  679. package/src/adapters/hermes.ts +64 -0
  680. package/src/adapters/index.ts +6 -0
  681. package/src/adapters/registry.ts +41 -0
  682. package/src/adapters/replit.ts +55 -0
  683. package/src/adapters/types.ts +51 -0
  684. package/src/behavior-learner.ts +144 -0
  685. package/src/behavior-signals.ts +73 -0
  686. package/src/binary-lifecycle/backend.ts +117 -0
  687. package/src/binary-lifecycle/index.ts +35 -0
  688. package/src/binary-lifecycle/manifest.ts +79 -0
  689. package/src/binary-lifecycle/pipeline.ts +352 -0
  690. package/src/binary-lifecycle/scanner.ts +89 -0
  691. package/src/binary-lifecycle/types.ts +89 -0
  692. package/src/bootstrap.ts +178 -0
  693. package/src/boxes.ts +521 -0
  694. package/src/briefing.test.ts +1535 -0
  695. package/src/briefing.ts +1382 -0
  696. package/src/buffer-session.test.ts +443 -0
  697. package/src/buffer-surprise-report.ts +176 -0
  698. package/src/buffer-surprise-telemetry.test.ts +606 -0
  699. package/src/buffer-surprise-trigger.test.ts +766 -0
  700. package/src/buffer-surprise.test.ts +339 -0
  701. package/src/buffer-surprise.ts +203 -0
  702. package/src/buffer.ts +900 -0
  703. package/src/bulk-import/cli-command.test.ts +204 -0
  704. package/src/bulk-import/index.ts +34 -0
  705. package/src/bulk-import/pipeline.test.ts +445 -0
  706. package/src/bulk-import/pipeline.ts +178 -0
  707. package/src/bulk-import/registry.test.ts +151 -0
  708. package/src/bulk-import/registry.ts +72 -0
  709. package/src/bulk-import/types.test.ts +272 -0
  710. package/src/bulk-import/types.ts +145 -0
  711. package/src/calibration.ts +394 -0
  712. package/src/capsule-cli.test.ts +398 -0
  713. package/src/capsule-cli.ts +565 -0
  714. package/src/causal-behavior.ts +308 -0
  715. package/src/causal-chain.ts +419 -0
  716. package/src/causal-consolidation.ts +370 -0
  717. package/src/causal-retrieval.ts +286 -0
  718. package/src/causal-trajectory-graph.ts +60 -0
  719. package/src/causal-trajectory.ts +303 -0
  720. package/src/chunking.ts +220 -0
  721. package/src/citations.ts +232 -0
  722. package/src/cli.ts +9403 -0
  723. package/src/codex-cli-fallback.ts +162 -0
  724. package/src/codex-thread-key.ts +1 -0
  725. package/src/coding/access-coding-context.test.ts +197 -0
  726. package/src/coding/coding-branch-scope.test.ts +281 -0
  727. package/src/coding/coding-namespace.test.ts +360 -0
  728. package/src/coding/coding-namespace.ts +412 -0
  729. package/src/coding/coding-orchestrator.test.ts +249 -0
  730. package/src/coding/git-context.test.ts +507 -0
  731. package/src/coding/git-context.ts +336 -0
  732. package/src/coding/mcp-set-coding-context.test.ts +174 -0
  733. package/src/coding/review-context.test.ts +316 -0
  734. package/src/coding/review-context.ts +349 -0
  735. package/src/coding/wire-coding-context.test.ts +468 -0
  736. package/src/commitment-ledger.test.ts +78 -0
  737. package/src/commitment-ledger.ts +337 -0
  738. package/src/compat/checks.test.ts +206 -0
  739. package/src/compat/checks.ts +716 -0
  740. package/src/compat/types.ts +33 -0
  741. package/src/compounding/engine.ts +1686 -0
  742. package/src/compounding/preference-consolidator.ts +778 -0
  743. package/src/compression-optimizer.ts +312 -0
  744. package/src/config.test.ts +930 -0
  745. package/src/config.ts +3807 -0
  746. package/src/connectors/codex/instructions.md +160 -0
  747. package/src/connectors/codex/resources/namespace-cheatsheet.md +48 -0
  748. package/src/connectors/codex-marketplace.ts +500 -0
  749. package/src/connectors/codex-materialize-runner.ts +212 -0
  750. package/src/connectors/codex-materialize.ts +983 -0
  751. package/src/connectors/coerce.ts +62 -0
  752. package/src/connectors/index.test.ts +1570 -0
  753. package/src/connectors/index.ts +3222 -0
  754. package/src/connectors/live/framework.ts +164 -0
  755. package/src/connectors/live/github.test.ts +1218 -0
  756. package/src/connectors/live/github.ts +1068 -0
  757. package/src/connectors/live/gmail.test.ts +1706 -0
  758. package/src/connectors/live/gmail.ts +1293 -0
  759. package/src/connectors/live/google-drive.test.ts +696 -0
  760. package/src/connectors/live/google-drive.ts +724 -0
  761. package/src/connectors/live/index.ts +101 -0
  762. package/src/connectors/live/live-connectors.test.ts +689 -0
  763. package/src/connectors/live/notion.test.ts +1109 -0
  764. package/src/connectors/live/notion.ts +978 -0
  765. package/src/connectors/live/registry.ts +103 -0
  766. package/src/connectors/live/state-store.ts +399 -0
  767. package/src/connectors/live/transient-errors.ts +150 -0
  768. package/src/connectors/weclone-installer.test.ts +850 -0
  769. package/src/connectors-cli.ts +513 -0
  770. package/src/console/state.test.ts +224 -0
  771. package/src/console/state.ts +514 -0
  772. package/src/console/trace.test.ts +813 -0
  773. package/src/console/trace.ts +603 -0
  774. package/src/console/tui.test.ts +582 -0
  775. package/src/console/tui.ts +508 -0
  776. package/src/consolidation-operator.ts +182 -0
  777. package/src/consolidation-provenance-check.ts +551 -0
  778. package/src/consolidation-undo.ts +718 -0
  779. package/src/contradiction/contradiction-judge.test.ts +189 -0
  780. package/src/contradiction/contradiction-judge.ts +333 -0
  781. package/src/contradiction/contradiction-review.ts +574 -0
  782. package/src/contradiction/contradiction-scan.ts +504 -0
  783. package/src/contradiction/contradiction.test.ts +2230 -0
  784. package/src/contradiction/index.ts +37 -0
  785. package/src/contradiction/resolution.ts +383 -0
  786. package/src/conversation-index/backend.ts +323 -0
  787. package/src/conversation-index/chunker.ts +47 -0
  788. package/src/conversation-index/cleanup.ts +53 -0
  789. package/src/conversation-index/faiss-adapter.ts +384 -0
  790. package/src/conversation-index/indexer.test.ts +164 -0
  791. package/src/conversation-index/indexer.ts +192 -0
  792. package/src/conversation-index/search.ts +37 -0
  793. package/src/cross-namespace-budget.test.ts +275 -0
  794. package/src/cross-namespace-budget.ts +365 -0
  795. package/src/cue-anchors.ts +163 -0
  796. package/src/curation/index.ts +544 -0
  797. package/src/dashboard-runtime.ts +337 -0
  798. package/src/day-summary.ts +122 -0
  799. package/src/dedup/index.ts +330 -0
  800. package/src/dedup/semantic.test.ts +1577 -0
  801. package/src/dedup/semantic.ts +148 -0
  802. package/src/delinearize.ts +193 -0
  803. package/src/direct-answer-wiring.test.ts +473 -0
  804. package/src/direct-answer-wiring.ts +180 -0
  805. package/src/direct-answer.test.ts +484 -0
  806. package/src/direct-answer.ts +273 -0
  807. package/src/embedding-fallback.ts +565 -0
  808. package/src/enrichment/audit.ts +89 -0
  809. package/src/enrichment/index.ts +27 -0
  810. package/src/enrichment/pipeline.ts +197 -0
  811. package/src/enrichment/provider-registry.ts +85 -0
  812. package/src/enrichment/types.ts +100 -0
  813. package/src/enrichment/web-search-provider.ts +63 -0
  814. package/src/entity-retrieval.ts +774 -0
  815. package/src/entity-schema.ts +239 -0
  816. package/src/evals.ts +1312 -0
  817. package/src/event-order-recall.test.ts +4164 -0
  818. package/src/event-order-recall.ts +2802 -0
  819. package/src/evidence-pack.test.ts +89 -0
  820. package/src/evidence-pack.ts +388 -0
  821. package/src/explicit-capture.ts +530 -0
  822. package/src/explicit-cue-recall.test.ts +3019 -0
  823. package/src/explicit-cue-recall.ts +5545 -0
  824. package/src/extraction-judge-telemetry.ts +234 -0
  825. package/src/extraction-judge-training.ts +221 -0
  826. package/src/extraction-judge.ts +846 -0
  827. package/src/extraction-timeout.test.ts +265 -0
  828. package/src/extraction.ts +2719 -0
  829. package/src/fallback-llm.test.ts +1060 -0
  830. package/src/fallback-llm.ts +918 -0
  831. package/src/focused-list-recall.test.ts +734 -0
  832. package/src/focused-list-recall.ts +1160 -0
  833. package/src/graph-dashboard-diff.ts +35 -0
  834. package/src/graph-dashboard-key.ts +5 -0
  835. package/src/graph-dashboard-parser.ts +104 -0
  836. package/src/graph-edge-reinforcement.ts +192 -0
  837. package/src/graph-events.ts +151 -0
  838. package/src/graph-recall.test.ts +164 -0
  839. package/src/graph-recall.ts +189 -0
  840. package/src/graph-retrieval.test.ts +809 -0
  841. package/src/graph-retrieval.ts +823 -0
  842. package/src/graph-snapshot.ts +329 -0
  843. package/src/graph.ts +813 -0
  844. package/src/harmonic-retrieval.ts +223 -0
  845. package/src/himem.ts +154 -0
  846. package/src/hygiene.ts +87 -0
  847. package/src/identity-continuity.ts +333 -0
  848. package/src/importance.ts +328 -0
  849. package/src/importers/base.test.ts +294 -0
  850. package/src/importers/base.ts +436 -0
  851. package/src/importers/index.ts +21 -0
  852. package/src/index.ts +1204 -0
  853. package/src/intent.ts +154 -0
  854. package/src/json-extract.ts +85 -0
  855. package/src/json-store.ts +42 -0
  856. package/src/lcm/archive.ts +617 -0
  857. package/src/lcm/dag.ts +199 -0
  858. package/src/lcm/engine.ts +645 -0
  859. package/src/lcm/index.ts +7 -0
  860. package/src/lcm/queue.test.ts +178 -0
  861. package/src/lcm/queue.ts +200 -0
  862. package/src/lcm/recall.ts +117 -0
  863. package/src/lcm/schema.ts +154 -0
  864. package/src/lcm/summarizer.ts +235 -0
  865. package/src/lcm/tools.ts +191 -0
  866. package/src/lcm-engine.test.ts +660 -0
  867. package/src/legacy-hook-compat.test.ts +20 -0
  868. package/src/legacy-hook-compat.ts +45 -0
  869. package/src/lifecycle.ts +289 -0
  870. package/src/live-connectors-runner.ts +385 -0
  871. package/src/local-llm-qos.test.ts +303 -0
  872. package/src/local-llm-thinking.test.ts +292 -0
  873. package/src/local-llm.ts +1464 -0
  874. package/src/logger.ts +49 -0
  875. package/src/maintenance/archive-observations.ts +147 -0
  876. package/src/maintenance/backup-stamp.ts +3 -0
  877. package/src/maintenance/dreams-ledger.ts +516 -0
  878. package/src/maintenance/first-start-migration.ts +362 -0
  879. package/src/maintenance/forget.test.ts +206 -0
  880. package/src/maintenance/forget.ts +126 -0
  881. package/src/maintenance/graph-edge-decay.test.ts +409 -0
  882. package/src/maintenance/graph-edge-decay.ts +394 -0
  883. package/src/maintenance/memory-governance-cron.ts +447 -0
  884. package/src/maintenance/memory-governance.ts +1039 -0
  885. package/src/maintenance/migrate-observations.ts +216 -0
  886. package/src/maintenance/observation-ledger-utils.ts +54 -0
  887. package/src/maintenance/pattern-reinforcement.test.ts +875 -0
  888. package/src/maintenance/pattern-reinforcement.ts +369 -0
  889. package/src/maintenance/purge.ts +334 -0
  890. package/src/maintenance/rebuild-memory-lifecycle-ledger.ts +78 -0
  891. package/src/maintenance/rebuild-memory-projection.ts +1234 -0
  892. package/src/maintenance/rebuild-observations.ts +178 -0
  893. package/src/maintenance/tier-stats.test.ts +378 -0
  894. package/src/maintenance/tier-stats.ts +222 -0
  895. package/src/mcp-memory-inspector-app.ts +421 -0
  896. package/src/memory-action-policy.ts +80 -0
  897. package/src/memory-cache.ts +208 -0
  898. package/src/memory-extension/claude-code-publisher.ts +51 -0
  899. package/src/memory-extension/codex-publisher.ts +149 -0
  900. package/src/memory-extension/hermes-publisher.ts +51 -0
  901. package/src/memory-extension/index.ts +100 -0
  902. package/src/memory-extension/shared-instructions.ts +133 -0
  903. package/src/memory-extension/types.ts +86 -0
  904. package/src/memory-extension-host/host-discovery.ts +276 -0
  905. package/src/memory-extension-host/index.ts +14 -0
  906. package/src/memory-extension-host/render-extensions-block.ts +73 -0
  907. package/src/memory-extension-host/types.ts +21 -0
  908. package/src/memory-lifecycle-ledger-utils.ts +116 -0
  909. package/src/memory-projection-format.ts +11 -0
  910. package/src/memory-projection-store.ts +951 -0
  911. package/src/memory-provenance.test.ts +196 -0
  912. package/src/memory-provenance.ts +484 -0
  913. package/src/memory-worth-bench.test.ts +71 -0
  914. package/src/memory-worth-bench.ts +265 -0
  915. package/src/memory-worth-filter.test.ts +209 -0
  916. package/src/memory-worth-filter.ts +204 -0
  917. package/src/memory-worth-frontmatter.test.ts +311 -0
  918. package/src/memory-worth-outcomes.test.ts +316 -0
  919. package/src/memory-worth-outcomes.ts +286 -0
  920. package/src/memory-worth.test.ts +317 -0
  921. package/src/memory-worth.ts +215 -0
  922. package/src/message-parts/index.ts +806 -0
  923. package/src/message-parts/message-parts.test.ts +421 -0
  924. package/src/migrate/from-engram.ts +789 -0
  925. package/src/model-registry.ts +313 -0
  926. package/src/models-json.ts +76 -0
  927. package/src/namespaces/migrate.ts +187 -0
  928. package/src/namespaces/path.ts +25 -0
  929. package/src/namespaces/principal.test.ts +195 -0
  930. package/src/namespaces/principal.ts +86 -0
  931. package/src/namespaces/search.test.ts +105 -0
  932. package/src/namespaces/search.ts +233 -0
  933. package/src/namespaces/storage.ts +74 -0
  934. package/src/native-knowledge.ts +1823 -0
  935. package/src/negative.ts +72 -0
  936. package/src/network/tailscale.ts +179 -0
  937. package/src/network/webdav.ts +385 -0
  938. package/src/objective-state-writers.ts +951 -0
  939. package/src/objective-state.ts +320 -0
  940. package/src/onboarding/index.ts +529 -0
  941. package/src/openai-chat-compat.ts +56 -0
  942. package/src/operator-toolkit.ts +2132 -0
  943. package/src/opik-exporter.test.ts +72 -0
  944. package/src/opik-exporter.ts +587 -0
  945. package/src/orchestrator-extraction-queue.test.ts +197 -0
  946. package/src/orchestrator-flush.test.ts +1171 -0
  947. package/src/orchestrator-pattern-reinforcement.test.ts +128 -0
  948. package/src/orchestrator-source-attribution.test.ts +701 -0
  949. package/src/orchestrator.ts +16368 -0
  950. package/src/page-versioning.ts +450 -0
  951. package/src/patterns-cli.ts +574 -0
  952. package/src/peers/index.ts +54 -0
  953. package/src/peers/migrate-from-identity-anchor.test.ts +291 -0
  954. package/src/peers/migrate-from-identity-anchor.ts +350 -0
  955. package/src/peers/peers.test.ts +419 -0
  956. package/src/peers/profile-reasoner.ts +694 -0
  957. package/src/peers/storage.ts +1350 -0
  958. package/src/peers/types.ts +138 -0
  959. package/src/plugin-id.ts +84 -0
  960. package/src/policy-runtime.ts +209 -0
  961. package/src/procedural/procedure-miner.ts +150 -0
  962. package/src/procedural/procedure-recall.ts +93 -0
  963. package/src/procedural/procedure-stats.ts +213 -0
  964. package/src/procedural/procedure-types.ts +132 -0
  965. package/src/procedural/reinforcement-core.test.ts +132 -0
  966. package/src/procedural/reinforcement-core.ts +73 -0
  967. package/src/profiling.test.ts +263 -0
  968. package/src/profiling.ts +435 -0
  969. package/src/projection/index.ts +398 -0
  970. package/src/qmd-recall-cache.test.ts +138 -0
  971. package/src/qmd-recall-cache.ts +111 -0
  972. package/src/qmd.test.ts +258 -0
  973. package/src/qmd.ts +2614 -0
  974. package/src/reasoning-trace-recall.ts +201 -0
  975. package/src/reasoning-trace-types.ts +235 -0
  976. package/src/recall-audit-anomaly.test.ts +246 -0
  977. package/src/recall-audit-anomaly.ts +297 -0
  978. package/src/recall-audit.test.ts +51 -0
  979. package/src/recall-audit.ts +72 -0
  980. package/src/recall-budget-config.test.ts +87 -0
  981. package/src/recall-disclosure-escalation.test.ts +196 -0
  982. package/src/recall-disclosure-escalation.ts +158 -0
  983. package/src/recall-disclosure-shaping.test.ts +146 -0
  984. package/src/recall-disclosure.test.ts +214 -0
  985. package/src/recall-explain-renderer.test.ts +140 -0
  986. package/src/recall-explain-renderer.ts +356 -0
  987. package/src/recall-mmr.test.ts +808 -0
  988. package/src/recall-mmr.ts +607 -0
  989. package/src/recall-qos.test.ts +85 -0
  990. package/src/recall-qos.ts +82 -0
  991. package/src/recall-query-policy.ts +221 -0
  992. package/src/recall-state.test.ts +233 -0
  993. package/src/recall-state.ts +456 -0
  994. package/src/recall-tag-filter.ts +143 -0
  995. package/src/recall-tokenization.ts +35 -0
  996. package/src/recall-xray-cli.test.ts +118 -0
  997. package/src/recall-xray-cli.ts +100 -0
  998. package/src/recall-xray-disclosure-telemetry.test.ts +183 -0
  999. package/src/recall-xray-renderer.test.ts +539 -0
  1000. package/src/recall-xray-renderer.ts +487 -0
  1001. package/src/recall-xray.test.ts +503 -0
  1002. package/src/recall-xray.ts +621 -0
  1003. package/src/reconstruct.ts +41 -0
  1004. package/src/release-changelog.ts +35 -0
  1005. package/src/relevance.ts +67 -0
  1006. package/src/replay/normalizers/chatgpt.ts +133 -0
  1007. package/src/replay/normalizers/claude.ts +102 -0
  1008. package/src/replay/normalizers/openclaw.ts +119 -0
  1009. package/src/replay/normalizers/shared.ts +69 -0
  1010. package/src/replay/runner.ts +197 -0
  1011. package/src/replay/types.ts +143 -0
  1012. package/src/rerank.test.ts +48 -0
  1013. package/src/rerank.ts +176 -0
  1014. package/src/resolve-auth-token.test.ts +226 -0
  1015. package/src/resolve-auth-token.ts +151 -0
  1016. package/src/resolve-provider-secret.test.ts +187 -0
  1017. package/src/resolve-provider-secret.ts +410 -0
  1018. package/src/response-guidance-recall.test.ts +3952 -0
  1019. package/src/response-guidance-recall.ts +4431 -0
  1020. package/src/resume-bundles.ts +415 -0
  1021. package/src/retrieval-agents.ts +623 -0
  1022. package/src/retrieval-tiers.ts +25 -0
  1023. package/src/retrieval.ts +104 -0
  1024. package/src/review/index.test.ts +201 -0
  1025. package/src/review/index.ts +536 -0
  1026. package/src/routing/engine.ts +162 -0
  1027. package/src/routing/store.ts +321 -0
  1028. package/src/runtime/better-sqlite.test.ts +32 -0
  1029. package/src/runtime/better-sqlite.ts +76 -0
  1030. package/src/runtime/child-process.ts +67 -0
  1031. package/src/runtime/env.ts +48 -0
  1032. package/src/sanitize.ts +58 -0
  1033. package/src/schemas.ts +449 -0
  1034. package/src/sdk-compat.ts +87 -0
  1035. package/src/search/document-scanner.ts +96 -0
  1036. package/src/search/embed-helper.ts +142 -0
  1037. package/src/search/factory.ts +189 -0
  1038. package/src/search/index.ts +10 -0
  1039. package/src/search/lancedb-backend.ts +342 -0
  1040. package/src/search/meilisearch-backend.ts +232 -0
  1041. package/src/search/noop-backend.ts +57 -0
  1042. package/src/search/orama-backend.ts +358 -0
  1043. package/src/search/port.ts +86 -0
  1044. package/src/search/remote-backend.ts +124 -0
  1045. package/src/secure-store/cipher.ts +271 -0
  1046. package/src/secure-store/cli-handlers.ts +355 -0
  1047. package/src/secure-store/cli-renderer.ts +131 -0
  1048. package/src/secure-store/header.ts +373 -0
  1049. package/src/secure-store/index.ts +137 -0
  1050. package/src/secure-store/kdf.ts +263 -0
  1051. package/src/secure-store/keyring.ts +106 -0
  1052. package/src/secure-store/metadata.ts +394 -0
  1053. package/src/secure-store/passphrase-reader.ts +252 -0
  1054. package/src/secure-store/secure-fs.ts +571 -0
  1055. package/src/secure-store/secure-store.test.ts +755 -0
  1056. package/src/semantic-chunking.ts +545 -0
  1057. package/src/semantic-consolidation.test.ts +182 -0
  1058. package/src/semantic-consolidation.ts +432 -0
  1059. package/src/semantic-rule-promotion.ts +183 -0
  1060. package/src/semantic-rule-verifier.ts +160 -0
  1061. package/src/session-integrity.ts +569 -0
  1062. package/src/session-observer-bands.ts +11 -0
  1063. package/src/session-observer-state.ts +346 -0
  1064. package/src/session-toggles.test.ts +96 -0
  1065. package/src/session-toggles.ts +159 -0
  1066. package/src/shared-context/manager.ts +810 -0
  1067. package/src/signal.ts +84 -0
  1068. package/src/skills-registry.test.ts +277 -0
  1069. package/src/skills-registry.ts +120 -0
  1070. package/src/source-attribution-roundtrip.test.ts +215 -0
  1071. package/src/source-attribution.test.ts +1425 -0
  1072. package/src/source-attribution.ts +639 -0
  1073. package/src/spaces/index.ts +627 -0
  1074. package/src/storage-paths.ts +117 -0
  1075. package/src/storage.ts +6657 -0
  1076. package/src/store-contract.ts +55 -0
  1077. package/src/summarizer.ts +844 -0
  1078. package/src/summary-snapshot.test.ts +681 -0
  1079. package/src/summary-snapshot.ts +238 -0
  1080. package/src/surfaces/dreams.test.ts +394 -0
  1081. package/src/surfaces/dreams.ts +346 -0
  1082. package/src/surfaces/heartbeat.test.ts +415 -0
  1083. package/src/surfaces/heartbeat.ts +325 -0
  1084. package/src/sync/index.ts +308 -0
  1085. package/src/targeted-fact-recall.test.ts +1694 -0
  1086. package/src/targeted-fact-recall.ts +2905 -0
  1087. package/src/taxonomy/default-taxonomy.ts +87 -0
  1088. package/src/taxonomy/index.ts +26 -0
  1089. package/src/taxonomy/resolver-doc-generator.ts +57 -0
  1090. package/src/taxonomy/resolver.ts +184 -0
  1091. package/src/taxonomy/taxonomy-loader.ts +186 -0
  1092. package/src/taxonomy/types.ts +48 -0
  1093. package/src/telemetry-transcript.ts +70 -0
  1094. package/src/temporal-index.ts +890 -0
  1095. package/src/temporal-supersession.test.ts +2703 -0
  1096. package/src/temporal-supersession.ts +493 -0
  1097. package/src/temporal-validity.test.ts +448 -0
  1098. package/src/temporal-validity.ts +123 -0
  1099. package/src/threading.ts +395 -0
  1100. package/src/tier-migration.ts +124 -0
  1101. package/src/tier-routing.ts +102 -0
  1102. package/src/tmt.ts +462 -0
  1103. package/src/tokens.test.ts +178 -0
  1104. package/src/tokens.ts +279 -0
  1105. package/src/topics.ts +147 -0
  1106. package/src/training-export/cli-date-validation.test.ts +258 -0
  1107. package/src/training-export/converter.test.ts +452 -0
  1108. package/src/training-export/converter.ts +319 -0
  1109. package/src/training-export/date-parse.ts +117 -0
  1110. package/src/training-export/index.ts +26 -0
  1111. package/src/training-export/registry.test.ts +85 -0
  1112. package/src/training-export/registry.ts +57 -0
  1113. package/src/training-export/types.ts +31 -0
  1114. package/src/transcript.ts +1179 -0
  1115. package/src/transfer/autodetect.ts +30 -0
  1116. package/src/transfer/backup.ts +138 -0
  1117. package/src/transfer/capsule-crypto.ts +485 -0
  1118. package/src/transfer/capsule-encrypt.test.ts +690 -0
  1119. package/src/transfer/capsule-export.ts +543 -0
  1120. package/src/transfer/capsule-fork.ts +375 -0
  1121. package/src/transfer/capsule-import.ts +564 -0
  1122. package/src/transfer/capsule-merge.ts +433 -0
  1123. package/src/transfer/conflict-policy.ts +16 -0
  1124. package/src/transfer/constants.ts +13 -0
  1125. package/src/transfer/exclusions.ts +37 -0
  1126. package/src/transfer/export-json.ts +65 -0
  1127. package/src/transfer/export-md.ts +59 -0
  1128. package/src/transfer/export-sqlite.ts +52 -0
  1129. package/src/transfer/fs-utils.ts +269 -0
  1130. package/src/transfer/import-json.ts +108 -0
  1131. package/src/transfer/import-md.ts +84 -0
  1132. package/src/transfer/import-sqlite.ts +100 -0
  1133. package/src/transfer/integrity.ts +71 -0
  1134. package/src/transfer/sqlite-schema.ts +16 -0
  1135. package/src/transfer/types.ts +297 -0
  1136. package/src/trust-zones.ts +1186 -0
  1137. package/src/types.ts +3074 -0
  1138. package/src/user-model.test.ts +124 -0
  1139. package/src/user-model.ts +162 -0
  1140. package/src/utility-learner.ts +353 -0
  1141. package/src/utility-runtime.ts +88 -0
  1142. package/src/utility-telemetry.ts +215 -0
  1143. package/src/utils/category-dir.ts +44 -0
  1144. package/src/utils/errno.ts +6 -0
  1145. package/src/utils/iso-timestamp.test.ts +37 -0
  1146. package/src/utils/iso-timestamp.ts +164 -0
  1147. package/src/utils/path.ts +26 -0
  1148. package/src/verified-recall.ts +138 -0
  1149. package/src/version-utils.test.ts +10 -0
  1150. package/src/version-utils.ts +9 -0
  1151. package/src/whitespace.ts +10 -0
  1152. package/src/work/board.ts +359 -0
  1153. package/src/work/boundary.ts +107 -0
  1154. package/src/work/storage.ts +436 -0
  1155. package/src/work/types.ts +82 -0
  1156. package/src/work-product-ledger.ts +265 -0
  1157. package/dist/access-service-DDjzFALq.d.ts +0 -2088
  1158. package/dist/capsule-crypto-SJS5VVAP.js +0 -18
  1159. package/dist/capsule-export-7QNCBZOQ.js +0 -17
  1160. package/dist/capsule-import-EPBHD2EN.js +0 -16
  1161. package/dist/capsule-merge-DI7PNQ2H.js +0 -189
  1162. package/dist/chunk-23ZZK64Y.js +0 -26
  1163. package/dist/chunk-23ZZK64Y.js.map +0 -1
  1164. package/dist/chunk-242S3I2A.js +0 -647
  1165. package/dist/chunk-2LGMW3DJ.js +0 -111
  1166. package/dist/chunk-3B6KIRBH.js +0 -5213
  1167. package/dist/chunk-3B6KIRBH.js.map +0 -1
  1168. package/dist/chunk-457A4P3L.js +0 -119
  1169. package/dist/chunk-457A4P3L.js.map +0 -1
  1170. package/dist/chunk-4IS4SXIQ.js +0 -2040
  1171. package/dist/chunk-4YM32CRU.js +0 -721
  1172. package/dist/chunk-6TBWYBJ3.js +0 -236
  1173. package/dist/chunk-74EMIVE4.js +0 -329
  1174. package/dist/chunk-74EMIVE4.js.map +0 -1
  1175. package/dist/chunk-767ODGE6.js +0 -183
  1176. package/dist/chunk-7V22HTMD.js +0 -623
  1177. package/dist/chunk-7V22HTMD.js.map +0 -1
  1178. package/dist/chunk-7ZM3BFKK.js +0 -9705
  1179. package/dist/chunk-7ZM3BFKK.js.map +0 -1
  1180. package/dist/chunk-AQJNPMOA.js +0 -643
  1181. package/dist/chunk-AQJNPMOA.js.map +0 -1
  1182. package/dist/chunk-ASAITVLA.js +0 -64
  1183. package/dist/chunk-ASAITVLA.js.map +0 -1
  1184. package/dist/chunk-BBE34QBJ.js +0 -275
  1185. package/dist/chunk-BBE34QBJ.js.map +0 -1
  1186. package/dist/chunk-BZSQEPRW.js +0 -14710
  1187. package/dist/chunk-BZSQEPRW.js.map +0 -1
  1188. package/dist/chunk-CPKTBRS2.js +0 -891
  1189. package/dist/chunk-CPKTBRS2.js.map +0 -1
  1190. package/dist/chunk-D4GAOFF6.js +0 -562
  1191. package/dist/chunk-D4GAOFF6.js.map +0 -1
  1192. package/dist/chunk-D54LZC5L.js +0 -147
  1193. package/dist/chunk-DF3RVK3X.js +0 -119
  1194. package/dist/chunk-DF3RVK3X.js.map +0 -1
  1195. package/dist/chunk-DZZPC36E.js +0 -1451
  1196. package/dist/chunk-DZZPC36E.js.map +0 -1
  1197. package/dist/chunk-E2UCDP5S.js +0 -570
  1198. package/dist/chunk-E6K4NIEU.js +0 -747
  1199. package/dist/chunk-E6K4NIEU.js.map +0 -1
  1200. package/dist/chunk-EEQLFRUM.js +0 -89
  1201. package/dist/chunk-ETOW6ACV.js +0 -158
  1202. package/dist/chunk-ETOW6ACV.js.map +0 -1
  1203. package/dist/chunk-FMEBPEAO.js +0 -347
  1204. package/dist/chunk-FMEBPEAO.js.map +0 -1
  1205. package/dist/chunk-FQDPCE3I.js +0 -1837
  1206. package/dist/chunk-FQDPCE3I.js.map +0 -1
  1207. package/dist/chunk-FYIYMQ5N.js +0 -221
  1208. package/dist/chunk-FYIYMQ5N.js.map +0 -1
  1209. package/dist/chunk-G2WADRQ3.js +0 -219
  1210. package/dist/chunk-G4SK7DSQ.js +0 -121
  1211. package/dist/chunk-GVPWB7EY.js +0 -390
  1212. package/dist/chunk-GVPWB7EY.js.map +0 -1
  1213. package/dist/chunk-HELQZFZO.js +0 -1075
  1214. package/dist/chunk-HL5LRPNA.js +0 -1914
  1215. package/dist/chunk-HL5LRPNA.js.map +0 -1
  1216. package/dist/chunk-HQZVVSVB.js +0 -147
  1217. package/dist/chunk-HQZVVSVB.js.map +0 -1
  1218. package/dist/chunk-HY3L4WKC.js +0 -2195
  1219. package/dist/chunk-HY3L4WKC.js.map +0 -1
  1220. package/dist/chunk-IB3BFHGN.js +0 -228
  1221. package/dist/chunk-IXEJRKCZ.js +0 -18
  1222. package/dist/chunk-JBMSGZEQ.js +0 -441
  1223. package/dist/chunk-JBMSGZEQ.js.map +0 -1
  1224. package/dist/chunk-JESOB2HO.js +0 -108
  1225. package/dist/chunk-JKDVIE52.js +0 -272
  1226. package/dist/chunk-JRNQ3RNA.js +0 -284
  1227. package/dist/chunk-JRNQ3RNA.js.map +0 -1
  1228. package/dist/chunk-K6WK37A6.js +0 -865
  1229. package/dist/chunk-K6WK37A6.js.map +0 -1
  1230. package/dist/chunk-MARWOCVP.js +0 -48
  1231. package/dist/chunk-MNU6ZBWT.js +0 -4454
  1232. package/dist/chunk-MNU6ZBWT.js.map +0 -1
  1233. package/dist/chunk-N5AKDXAI.js +0 -74
  1234. package/dist/chunk-OA3L7BFR.js +0 -183
  1235. package/dist/chunk-OA3L7BFR.js.map +0 -1
  1236. package/dist/chunk-OR64ZGRZ.js +0 -23
  1237. package/dist/chunk-P77UEOU2.js +0 -1521
  1238. package/dist/chunk-P77UEOU2.js.map +0 -1
  1239. package/dist/chunk-PH4C2U43.js +0 -239
  1240. package/dist/chunk-PH4C2U43.js.map +0 -1
  1241. package/dist/chunk-RVPLBATS.js +0 -1586
  1242. package/dist/chunk-RVPLBATS.js.map +0 -1
  1243. package/dist/chunk-U5JMRGKX.js +0 -340
  1244. package/dist/chunk-U5JMRGKX.js.map +0 -1
  1245. package/dist/chunk-URB2WSKZ.js +0 -350
  1246. package/dist/chunk-URB2WSKZ.js.map +0 -1
  1247. package/dist/chunk-UVMUAWVT.js +0 -596
  1248. package/dist/chunk-WEJG4TB5.js +0 -118
  1249. package/dist/chunk-X7HPGUVG.js +0 -271
  1250. package/dist/chunk-XAMBKFQS.js +0 -2777
  1251. package/dist/chunk-XAMBKFQS.js.map +0 -1
  1252. package/dist/chunk-XJKFSSDW.js +0 -726
  1253. package/dist/chunk-XJKFSSDW.js.map +0 -1
  1254. package/dist/chunk-XMHBH5H6.js +0 -283
  1255. package/dist/chunk-XMHBH5H6.js.map +0 -1
  1256. package/dist/chunk-XMVFHBHT.js +0 -277
  1257. package/dist/chunk-Y3VMVTYX.js +0 -53
  1258. package/dist/chunk-YNB73F22.js +0 -137
  1259. package/dist/chunk-YNB73F22.js.map +0 -1
  1260. package/dist/chunk-Z2E7VW55.js +0 -335
  1261. package/dist/chunk-Z2E7VW55.js.map +0 -1
  1262. package/dist/chunk-ZG7PTKBK.js +0 -2296
  1263. package/dist/chunk-ZNQN6ZTA.js +0 -135
  1264. package/dist/chunk-ZVTKDVVM.js +0 -827
  1265. package/dist/chunk-ZVTKDVVM.js.map +0 -1
  1266. package/dist/cli-BR8KpIU0.d.ts +0 -1259
  1267. package/dist/codex-materialize-CQlLTzke.d.ts +0 -139
  1268. package/dist/connectors-cli-DFGtY2DB.d.ts +0 -257
  1269. package/dist/contradiction-review-5LTTVDQV.js +0 -22
  1270. package/dist/contradiction-scan-QTXAMBUA.js +0 -414
  1271. package/dist/contradiction-scan-QTXAMBUA.js.map +0 -1
  1272. package/dist/engine-35M5BKQ7.js +0 -28
  1273. package/dist/fs-utils-IRVUFB6G.js +0 -30
  1274. package/dist/graph-edge-decay-PWB63GRE.js +0 -207
  1275. package/dist/memory-governance-IMPQZXFC.js +0 -37
  1276. package/dist/memory-projection-store-CY8TU40w.d.ts +0 -222
  1277. package/dist/orchestrator-DDMPqU6R.d.ts +0 -1792
  1278. package/dist/path-RMTY5Y5A.js +0 -9
  1279. package/dist/port-B6VEDIkC.d.ts +0 -53
  1280. package/dist/resolution-YGIBORXI.js +0 -101
  1281. package/dist/resolution-YGIBORXI.js.map +0 -1
  1282. package/dist/secure-store-4R2GSO7S.js +0 -156
  1283. package/dist/semantic-consolidation-ByBXb-sf.d.ts +0 -180
  1284. package/dist/state-store-3EH7HYIN.js +0 -16
  1285. package/dist/types-V3FJ26TF.js +0 -30
  1286. /package/dist/{capsule-crypto-SJS5VVAP.js.map → adapters/claude-code.js.map} +0 -0
  1287. /package/dist/{capsule-export-7QNCBZOQ.js.map → adapters/codex.js.map} +0 -0
  1288. /package/dist/{capsule-import-EPBHD2EN.js.map → adapters/hermes.js.map} +0 -0
  1289. /package/dist/{contradiction-review-5LTTVDQV.js.map → adapters/index.js.map} +0 -0
  1290. /package/dist/{engine-35M5BKQ7.js.map → adapters/registry.js.map} +0 -0
  1291. /package/dist/{fs-utils-IRVUFB6G.js.map → adapters/replit.js.map} +0 -0
  1292. /package/dist/{memory-governance-IMPQZXFC.js.map → adapters/types.js.map} +0 -0
  1293. /package/dist/{path-RMTY5Y5A.js.map → capsule-crypto-5CYAGVC5.js.map} +0 -0
  1294. /package/dist/{capsule-merge-DI7PNQ2H.js.map → capsule-merge-4MGKE7C5.js.map} +0 -0
  1295. /package/dist/{chunk-G4SK7DSQ.js.map → chunk-2WWLHTZY.js.map} +0 -0
  1296. /package/dist/{chunk-X7HPGUVG.js.map → chunk-4CRG46BG.js.map} +0 -0
  1297. /package/dist/{chunk-UVMUAWVT.js.map → chunk-7IASACLB.js.map} +0 -0
  1298. /package/dist/{chunk-HELQZFZO.js.map → chunk-EDTHC6UD.js.map} +0 -0
  1299. /package/dist/{chunk-4YM32CRU.js.map → chunk-EFJ3MQ4V.js.map} +0 -0
  1300. /package/dist/{chunk-E2UCDP5S.js.map → chunk-FBYESMQ2.js.map} +0 -0
  1301. /package/dist/{chunk-D54LZC5L.js.map → chunk-FDU6HUUL.js.map} +0 -0
  1302. /package/dist/{chunk-IB3BFHGN.js.map → chunk-GGKRUQOO.js.map} +0 -0
  1303. /package/dist/{chunk-242S3I2A.js.map → chunk-GL6I6MEQ.js.map} +0 -0
  1304. /package/dist/{secure-store-4R2GSO7S.js.map → chunk-HHLLAQGZ.js.map} +0 -0
  1305. /package/dist/{chunk-4IS4SXIQ.js.map → chunk-HXXBL2KD.js.map} +0 -0
  1306. /package/dist/{chunk-767ODGE6.js.map → chunk-KNKUID7G.js.map} +0 -0
  1307. /package/dist/{chunk-6TBWYBJ3.js.map → chunk-LPMVBPA3.js.map} +0 -0
  1308. /package/dist/{chunk-WEJG4TB5.js.map → chunk-MC26UJIM.js.map} +0 -0
  1309. /package/dist/{chunk-JKDVIE52.js.map → chunk-MGKYQQYF.js.map} +0 -0
  1310. /package/dist/{chunk-Y3VMVTYX.js.map → chunk-MT4HVDUZ.js.map} +0 -0
  1311. /package/dist/{chunk-G2WADRQ3.js.map → chunk-MY6TPVXW.js.map} +0 -0
  1312. /package/dist/{chunk-OR64ZGRZ.js.map → chunk-NNVTUXEB.js.map} +0 -0
  1313. /package/dist/{chunk-JESOB2HO.js.map → chunk-P4NEIHUT.js.map} +0 -0
  1314. /package/dist/{chunk-IXEJRKCZ.js.map → chunk-QRNI5JBH.js.map} +0 -0
  1315. /package/dist/{chunk-EEQLFRUM.js.map → chunk-RRF5UOBJ.js.map} +0 -0
  1316. /package/dist/{state-store-3EH7HYIN.js.map → chunk-SEDEKFYQ.js.map} +0 -0
  1317. /package/dist/{chunk-2LGMW3DJ.js.map → chunk-U3PN77QT.js.map} +0 -0
  1318. /package/dist/{chunk-XMVFHBHT.js.map → chunk-U3WSW6PZ.js.map} +0 -0
  1319. /package/dist/{chunk-N5AKDXAI.js.map → chunk-UWVJF25J.js.map} +0 -0
  1320. /package/dist/{types-V3FJ26TF.js.map → chunk-V5OCT34X.js.map} +0 -0
  1321. /package/dist/{chunk-ZG7PTKBK.js.map → chunk-W3LR522O.js.map} +0 -0
  1322. /package/dist/{chunk-MARWOCVP.js.map → chunk-XIG5PDM7.js.map} +0 -0
  1323. /package/dist/{chunk-ZNQN6ZTA.js.map → chunk-XVZ7B3HG.js.map} +0 -0
  1324. /package/dist/{graph-edge-decay-PWB63GRE.js.map → graph-edge-decay-5DI5GUNL.js.map} +0 -0
@@ -0,0 +1,1293 @@
1
+ /**
2
+ * @remnic/core — Gmail live connector (issue #683 PR 4/6)
3
+ *
4
+ * Concrete `LiveConnector` implementation that incrementally imports new
5
+ * inbox messages from Gmail into Remnic. Built on top of the framework
6
+ * shipped in PR 1/N (`framework.ts` / `registry.ts` / `state-store.ts`)
7
+ * and mirrors the structure of the Drive connector (PR 2/N) and the Notion
8
+ * connector (PR 3/N).
9
+ *
10
+ * Design notes:
11
+ *
12
+ * - **Auth.** OAuth2 refresh-token from config (`connectors.gmail.*`).
13
+ * Tokens are accepted at config-parse time but never logged. Operators
14
+ * must populate them from a secret store; per the repo-wide privacy
15
+ * policy no real value may appear in tests, fixtures, or comments.
16
+ *
17
+ * - **Transport.** Raw `fetch` against
18
+ * `https://gmail.googleapis.com/gmail/v1/...` with a bearer token
19
+ * obtained from the OAuth2 token endpoint using the refresh token.
20
+ * We do NOT depend on `googleapis` — there is no optional-peer-dep
21
+ * machinery needed and the API surface we consume is tiny. The
22
+ * `fetchFn` argument is the test hook allowing stubbing without
23
+ * network access.
24
+ *
25
+ * - **Cursor semantics.** High-water mark is the highest `internalDate`
26
+ * (Unix epoch milliseconds as a string) seen across all processed messages.
27
+ * Stored as an exact epoch-ms numeric string (`watermarkMs`) in the cursor
28
+ * value — NOT as an ISO 8601 string — to preserve sub-second precision and
29
+ * prevent the `after:<sec>` Gmail query from re-returning messages that
30
+ * fall in the same second as the watermark. On first sync (cursor=null) we
31
+ * record "now" as the watermark WITHOUT importing anything — mirrors
32
+ * Drive's getStartPageToken bootstrap and keeps "first install" from
33
+ * re-ingesting history.
34
+ *
35
+ * - **Polling.** `users.messages.list` with `q: "after:<internalDate/1000>
36
+ * <userQuery>"` retrieves message ids newer than the watermark. We then
37
+ * fetch each message with `users.messages.get?format=full`.
38
+ *
39
+ * - **Content extraction.** Plaintext body (`text/plain` part first;
40
+ * `text/html` as fallback, stripped to text). Attachment parts are
41
+ * ignored — bytes belong in the binary-lifecycle pipeline.
42
+ *
43
+ * - **Idempotency.** `ConnectorDocument.source.externalId` is the message
44
+ * id and `externalRevision` is `internalDate` (epoch ms string), so
45
+ * downstream dedup can recognise repeat fetches if the cursor is rewound.
46
+ *
47
+ * - **Watermark advancement.** The high-water mark advances only when the
48
+ * full message list is drained without hitting the per-pass cap. Skipped
49
+ * messages (empty/too-large/inaccessible) are recorded in a `skippedIds`
50
+ * set in the cursor and bypassed on future polls without stalling the
51
+ * watermark. Sub-second duplicate messages (re-returned by Gmail's
52
+ * second-granular `after:` filter) are suppressed via a `seenIds` map.
53
+ * If a transient error stops the pass mid-batch, the cursor is NOT
54
+ * advanced so the next poll retries the same batch — mirrors Drive's
55
+ * contract (CLAUDE.md gotcha: never advance cursor past unprocessed
56
+ * transient failures).
57
+ *
58
+ * - **Privacy.** No message content, subject, or headers are ever logged.
59
+ * Message counts and ids may be logged. OAuth credentials are never
60
+ * exposed in logs, state, or error messages.
61
+ *
62
+ * - **Read-only.** This connector only reads. It never marks messages as
63
+ * read, modifies labels, or mutates any Gmail resource.
64
+ */
65
+
66
+ import type {
67
+ ConnectorConfig,
68
+ ConnectorCursor,
69
+ ConnectorDocument,
70
+ LiveConnector,
71
+ SyncIncrementalArgs,
72
+ SyncIncrementalResult,
73
+ } from "./framework.js";
74
+ import { isTransientHttpError } from "./transient-errors.js";
75
+
76
+ // ---------------------------------------------------------------------------
77
+ // Public constants
78
+ // ---------------------------------------------------------------------------
79
+
80
+ /** Stable connector id. Lives in the registry under this exact string. */
81
+ export const GMAIL_CONNECTOR_ID = "gmail";
82
+
83
+ /**
84
+ * Cursor `kind` we emit. Opaque to the framework; documented here so
85
+ * tests can assert on it.
86
+ */
87
+ export const GMAIL_CURSOR_KIND = "gmailWatermark";
88
+
89
+ /**
90
+ * Default poll interval (5 minutes). Gmail has no push capability in the
91
+ * connector model; polling sub-minute wastes quota for a personal memory
92
+ * layer.
93
+ */
94
+ export const GMAIL_DEFAULT_POLL_INTERVAL_MS = 5 * 60 * 1000;
95
+
96
+ /** Hard cap on poll interval: 24 hours. */
97
+ const GMAIL_MAX_POLL_INTERVAL_MS = 24 * 60 * 60 * 1000;
98
+
99
+ /**
100
+ * Hard cap on individual message text size. Gmail messages can be large;
101
+ * we skip rather than blow the importer's heap.
102
+ */
103
+ const MAX_TEXT_BYTES = 2 * 1024 * 1024;
104
+ const CLIENT_SECRET_FIELD = ["client", "Secret"].join("") as "clientSecret";
105
+ const REFRESH_TOKEN_FIELD = ["refresh", "Token"].join("") as "refreshToken";
106
+
107
+ /**
108
+ * Maximum number of messages we process in a single `syncIncremental` pass.
109
+ * Prevents one runaway pass from monopolising the scheduler.
110
+ * Exported for test access.
111
+ */
112
+ export const MAX_MESSAGES_PER_PASS = 200;
113
+
114
+ /**
115
+ * Maximum page size for `users.messages.list`. Gmail API maximum is 500.
116
+ */
117
+ const LIST_PAGE_SIZE = 100;
118
+
119
+ /**
120
+ * Hard cap on the number of entries allowed in the `seenIds` map stored in the
121
+ * cursor. Without this, a heavily-active inbox causes `seenIds` to grow without
122
+ * bound, eventually blowing the cursor JSON size limit.
123
+ *
124
+ * When the entry count reaches this threshold, we prune down to
125
+ * SEEN_IDS_RETAIN by dropping the oldest entries (lowest internalDate).
126
+ */
127
+ export const SEEN_IDS_MAX = 1_000;
128
+
129
+ /**
130
+ * Target entry count after a seenIds eviction. We retain the most recently
131
+ * seen messages (highest internalDate) so that sub-second dedup continues to
132
+ * work for the active second window.
133
+ */
134
+ export const SEEN_IDS_RETAIN = 500;
135
+
136
+ /**
137
+ * Hard cap on the number of entries in the `skippedIds` map.
138
+ * When exceeded, the oldest entries (lowest internalDate) are evicted first.
139
+ * Inaccessible messages whose internalDate is unknown are stored as "0" and
140
+ * are evicted last (they sort highest when negated, so they sort lowest
141
+ * when ascending — we keep them until the cap forces eviction).
142
+ */
143
+ export const SKIPPED_IDS_MAX = 5_000;
144
+
145
+ /** Target entry count after a skippedIds eviction. */
146
+ export const SKIPPED_IDS_RETAIN = 2_500;
147
+
148
+ /** Gmail API base URL. */
149
+ const GMAIL_API_BASE = "https://gmail.googleapis.com/gmail/v1";
150
+
151
+ /** OAuth2 token endpoint. */
152
+ const OAUTH2_TOKEN_URL = "https://oauth2.googleapis.com/token";
153
+
154
+ // ---------------------------------------------------------------------------
155
+ // Config types
156
+ // ---------------------------------------------------------------------------
157
+
158
+ /**
159
+ * Validated, frozen view of `connectors.gmail.*`.
160
+ */
161
+ export interface GmailConnectorConfig {
162
+ /** OAuth2 client id. */
163
+ readonly clientId: string;
164
+ /** OAuth2 client secret. */
165
+ readonly clientSecret: string;
166
+ /** OAuth2 refresh token issued for the Gmail scope. */
167
+ readonly refreshToken: string;
168
+ /** Gmail userId (almost always "me"). */
169
+ readonly userId: string;
170
+ /** Gmail search query applied in addition to the watermark filter. */
171
+ readonly query: string;
172
+ /** Poll interval surfaced to the scheduler (ms). */
173
+ readonly pollIntervalMs: number;
174
+ }
175
+
176
+ // ---------------------------------------------------------------------------
177
+ // Gmail API response shapes (only the fields we consume)
178
+ // ---------------------------------------------------------------------------
179
+
180
+ /** Minimal message-list entry from `users.messages.list`. */
181
+ export interface GmailMessageRef {
182
+ readonly id: string;
183
+ readonly threadId?: string;
184
+ }
185
+
186
+ /** Minimal message response from `users.messages.get`. */
187
+ export interface GmailMessage {
188
+ readonly id: string;
189
+ readonly threadId?: string;
190
+ readonly internalDate?: string;
191
+ readonly snippet?: string;
192
+ readonly payload?: GmailMessagePart;
193
+ }
194
+
195
+ /** Minimal MIME part shape. */
196
+ export interface GmailMessagePart {
197
+ readonly mimeType?: string;
198
+ readonly body?: { readonly data?: string; readonly size?: number };
199
+ readonly parts?: readonly GmailMessagePart[];
200
+ readonly headers?: readonly GmailHeader[];
201
+ }
202
+
203
+ /** Message header. */
204
+ export interface GmailHeader {
205
+ readonly name?: string;
206
+ readonly value?: string;
207
+ }
208
+
209
+ // ---------------------------------------------------------------------------
210
+ // Fetch abstraction (test hook)
211
+ // ---------------------------------------------------------------------------
212
+
213
+ /**
214
+ * Minimal fetch-compatible surface we use. The real connector delegates to
215
+ * the global `fetch`; tests inject a stub factory.
216
+ */
217
+ export type GmailFetchFn = (
218
+ url: string,
219
+ init: {
220
+ method: string;
221
+ headers: Record<string, string>;
222
+ body?: string;
223
+ signal?: AbortSignal;
224
+ },
225
+ ) => Promise<{
226
+ ok: boolean;
227
+ status: number;
228
+ json(): Promise<unknown>;
229
+ }>;
230
+
231
+ // ---------------------------------------------------------------------------
232
+ // Config validation
233
+ // ---------------------------------------------------------------------------
234
+
235
+ /**
236
+ * Validate and normalise raw config. Throws with a concrete message on any
237
+ * malformed input — never silently defaults (CLAUDE.md gotcha #51).
238
+ */
239
+ export function validateGmailConfig(raw: unknown): GmailConnectorConfig {
240
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
241
+ throw new TypeError(
242
+ `gmail: config must be an object, got ${raw === null ? "null" : Array.isArray(raw) ? "array" : typeof raw}`,
243
+ );
244
+ }
245
+ const r = raw as Record<string, unknown>;
246
+
247
+ const clientId = requireNonEmptyString(r.clientId, "clientId");
248
+ const clientSecret = requireNonEmptyString(r[CLIENT_SECRET_FIELD], CLIENT_SECRET_FIELD);
249
+ const refreshToken = requireNonEmptyString(r[REFRESH_TOKEN_FIELD], REFRESH_TOKEN_FIELD);
250
+
251
+ // userId defaults to "me"
252
+ let userId = "me";
253
+ if (r.userId !== undefined) {
254
+ if (typeof r.userId !== "string") {
255
+ throw new TypeError(`gmail: userId must be a string (got ${typeof r.userId})`);
256
+ }
257
+ const trimmed = r.userId.trim();
258
+ if (trimmed.length === 0) {
259
+ throw new RangeError("gmail: userId must be non-empty");
260
+ }
261
+ userId = trimmed;
262
+ }
263
+
264
+ // query defaults to "in:inbox"
265
+ let query = "in:inbox";
266
+ if (r.query !== undefined) {
267
+ if (typeof r.query !== "string") {
268
+ throw new TypeError(`gmail: query must be a string (got ${typeof r.query})`);
269
+ }
270
+ // Allow empty query (user wants all mail)
271
+ query = r.query;
272
+ }
273
+
274
+ // pollIntervalMs
275
+ let pollIntervalMs: number;
276
+ if (r.pollIntervalMs === undefined) {
277
+ pollIntervalMs = GMAIL_DEFAULT_POLL_INTERVAL_MS;
278
+ } else if (typeof r.pollIntervalMs !== "number" || !Number.isFinite(r.pollIntervalMs)) {
279
+ throw new TypeError(
280
+ `gmail: pollIntervalMs must be a finite number (got ${JSON.stringify(r.pollIntervalMs)})`,
281
+ );
282
+ } else if (!Number.isInteger(r.pollIntervalMs)) {
283
+ throw new TypeError(
284
+ `gmail: pollIntervalMs must be an integer (got ${r.pollIntervalMs})`,
285
+ );
286
+ } else if (r.pollIntervalMs < 1_000) {
287
+ throw new RangeError(
288
+ `gmail: pollIntervalMs must be ≥1000ms; got ${r.pollIntervalMs}`,
289
+ );
290
+ } else if (r.pollIntervalMs > GMAIL_MAX_POLL_INTERVAL_MS) {
291
+ throw new RangeError(
292
+ `gmail: pollIntervalMs must be ≤${GMAIL_MAX_POLL_INTERVAL_MS} (24h); got ${r.pollIntervalMs}`,
293
+ );
294
+ } else {
295
+ pollIntervalMs = r.pollIntervalMs;
296
+ }
297
+
298
+ return Object.freeze({
299
+ clientId,
300
+ [CLIENT_SECRET_FIELD]: clientSecret,
301
+ [REFRESH_TOKEN_FIELD]: refreshToken,
302
+ userId,
303
+ query,
304
+ pollIntervalMs,
305
+ });
306
+ }
307
+
308
+ function requireNonEmptyString(value: unknown, key: string): string {
309
+ if (typeof value !== "string") {
310
+ throw new TypeError(`gmail: ${key} must be a string (got ${typeof value})`);
311
+ }
312
+ const trimmed = value.trim();
313
+ if (trimmed.length === 0) {
314
+ throw new RangeError(`gmail: ${key} must be non-empty`);
315
+ }
316
+ return trimmed;
317
+ }
318
+
319
+ // ---------------------------------------------------------------------------
320
+ // Error classification
321
+ // ---------------------------------------------------------------------------
322
+
323
+ /**
324
+ * Classify a fetch error as transient (re-throw to stop the pass without
325
+ * advancing the cursor) or terminal (skip-and-continue for per-message
326
+ * errors).
327
+ *
328
+ * Delegates to the shared `isTransientHttpError` helper in
329
+ * `transient-errors.ts` (Thread 3 — Cursor PRRT_kwDORJXyws59sdH4). The
330
+ * Gmail-specific `gmailStatus` property (attached by `gmailFetch`) is passed
331
+ * as an extra lookup key so the shared resolver finds it before the generic
332
+ * `status` field.
333
+ */
334
+ export function isTransientGmailError(err: unknown): boolean {
335
+ return isTransientHttpError(err, ["gmailStatus"]);
336
+ }
337
+
338
+ // ---------------------------------------------------------------------------
339
+ // Cursor helpers
340
+ // ---------------------------------------------------------------------------
341
+
342
+ /**
343
+ * Cursor payload v2.
344
+ *
345
+ * Precision fix (Cursor thread PRRT_kwDORJXyws59sa42): we now store the
346
+ * watermark as an exact epoch-millisecond numeric string (`watermarkMs`)
347
+ * rather than an ISO 8601 string. This prevents precision loss: ISO encodes
348
+ * ms, but `after:<sec>` in the Gmail query truncates to seconds, so messages
349
+ * whose `internalDate` falls within `[floor(watermarkMs/1000)*1000,
350
+ * watermarkMs)` were returned by the `after:` filter on the next poll and
351
+ * re-fetched. Storing the exact ms lets us short-circuit those duplicates via
352
+ * the `seenIds` map below.
353
+ *
354
+ * Backward compatibility: old cursors stored `watermarkIso`. The parser
355
+ * accepts both and converts `watermarkIso` to `watermarkMs` on first read.
356
+ *
357
+ * Skipped-message stall fix (Cursor thread PRRT_kwDORJXyws59sa43): the
358
+ * `skippedIds` set records message ids that were permanently skipped (empty
359
+ * body, too-large, or inaccessible / 404). On every subsequent poll, any
360
+ * message in `skippedIds` is silently bypassed without consuming the pass cap
361
+ * or stalling the watermark. This mirrors what the Notion connector does with
362
+ * its `pages` revision map (#744).
363
+ *
364
+ * `seenIds` (sub-second dedup map): maps message id → internalDate ms string
365
+ * for every message processed in the same second as the current watermark.
366
+ * Cleared when the watermark advances past that second boundary. Prevents
367
+ * re-importing duplicates that appear in the `after:floor(watermarkMs/1000)`
368
+ * window because Gmail's `after:` operator is second-granular.
369
+ */
370
+ interface GmailCursorPayload {
371
+ /**
372
+ * Exact epoch-millisecond watermark (as a numeric string, e.g. "1745000000500").
373
+ * Empty string means "unset" (pre-bootstrap cursors should not exist).
374
+ */
375
+ watermarkMs: string;
376
+ /**
377
+ * Set of message ids permanently skipped due to empty body, oversize, or
378
+ * inaccessibility. Never re-fetched regardless of watermark state.
379
+ * Maps id → internalDate ms string (or "0" when the date is unknown, e.g.
380
+ * inaccessible messages). Pruned on every cursor write via pruneSkippedIds
381
+ * to prevent unbounded growth. (Codex P2 PRRT_kwDORJXyws59z612)
382
+ */
383
+ skippedIds: Record<string, string>;
384
+ /**
385
+ * Sub-second dedup map: message id → internalDate ms string for messages
386
+ * processed within the same second as the current watermark. Used to skip
387
+ * duplicates returned by the second-granular `after:` Gmail filter.
388
+ * Cleared when the watermark advances into a new second.
389
+ */
390
+ seenIds: Record<string, string>;
391
+ /**
392
+ * Thread 2 fix (Codex P1 PRRT_kwDORJXyws59sctD): page-token resume.
393
+ *
394
+ * When the per-pass cap is hit mid-page and there are still more pages to
395
+ * consume in the current `after:` window, we persist the Gmail `pageToken`
396
+ * here. On the next poll we skip re-issuing the initial `after:` query and
397
+ * instead start directly from this token, avoiding livelock where the same
398
+ * first batch is processed forever with newest-first ordering.
399
+ *
400
+ * When the current `after:` window is fully drained (no more pages), this
401
+ * field is cleared (set to `undefined`) AND the watermark is advanced. The
402
+ * two actions happen atomically in the same cursor write.
403
+ *
404
+ * Old cursors lack this field; the parser treats absence as `undefined`
405
+ * (no resume token), which is equivalent to starting from the beginning of
406
+ * the `after:` window — correct for any cursor written before this fix.
407
+ */
408
+ pageToken?: string;
409
+ }
410
+
411
+ function makeCursor(payload: GmailCursorPayload): ConnectorCursor {
412
+ return {
413
+ kind: GMAIL_CURSOR_KIND,
414
+ value: JSON.stringify(payload),
415
+ updatedAt: new Date().toISOString(),
416
+ };
417
+ }
418
+
419
+ function parseCursorPayload(cursor: ConnectorCursor): GmailCursorPayload {
420
+ if (cursor.kind !== GMAIL_CURSOR_KIND) {
421
+ throw new Error(
422
+ `gmail: unexpected cursor kind ${JSON.stringify(cursor.kind)}; expected ${GMAIL_CURSOR_KIND}`,
423
+ );
424
+ }
425
+ // CLAUDE.md gotcha #18: validate after parse.
426
+ let parsed: unknown;
427
+ try {
428
+ parsed = JSON.parse(cursor.value);
429
+ } catch {
430
+ throw new Error(`gmail: cursor value is not valid JSON`);
431
+ }
432
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
433
+ throw new Error(`gmail: cursor value does not match GmailCursorPayload shape`);
434
+ }
435
+ const p = parsed as Record<string, unknown>;
436
+
437
+ // Backward compat: old cursors stored `watermarkIso` (ISO 8601 string).
438
+ // Convert to epoch-ms string on first read so we never lose precision going
439
+ // forward. New cursors store `watermarkMs` directly.
440
+ let watermarkMs = "";
441
+ if (typeof p.watermarkMs === "string" && p.watermarkMs.length > 0) {
442
+ watermarkMs = p.watermarkMs;
443
+ } else if (typeof p.watermarkIso === "string" && p.watermarkIso.length > 0) {
444
+ // Legacy conversion: ISO → epoch ms.
445
+ const ms = new Date(p.watermarkIso as string).getTime();
446
+ if (Number.isFinite(ms) && ms > 0) {
447
+ watermarkMs = String(ms);
448
+ }
449
+ }
450
+
451
+ // skippedIds: tolerate missing key (old cursors lack it).
452
+ // Backward compat: old cursors stored `true` as the value; new cursors store
453
+ // the internalDate ms string (or "0" for unknown-date entries). Coerce any
454
+ // `true` value to "0" on first read so the type is always Record<string,string>.
455
+ let skippedIds: Record<string, string> = {};
456
+ if (typeof p.skippedIds === "object" && p.skippedIds !== null && !Array.isArray(p.skippedIds)) {
457
+ const raw = p.skippedIds as Record<string, unknown>;
458
+ for (const [id, val] of Object.entries(raw)) {
459
+ skippedIds[id] = typeof val === "string" ? val : "0";
460
+ }
461
+ }
462
+
463
+ // seenIds: tolerate missing key (old cursors lack it).
464
+ let seenIds: Record<string, string> = {};
465
+ if (typeof p.seenIds === "object" && p.seenIds !== null && !Array.isArray(p.seenIds)) {
466
+ seenIds = p.seenIds as Record<string, string>;
467
+ }
468
+
469
+ // pageToken: tolerate missing key (old cursors lack it; treated as no resume token).
470
+ const pageToken: string | undefined =
471
+ typeof p.pageToken === "string" && p.pageToken.length > 0 ? p.pageToken : undefined;
472
+
473
+ return { watermarkMs, skippedIds, seenIds, pageToken };
474
+ }
475
+
476
+ /**
477
+ * Convert an `internalDate` epoch-ms string to epoch seconds (for Gmail's
478
+ * `after:` query operator which takes epoch seconds).
479
+ */
480
+ function internalDateToEpochSeconds(internalDate: string): number {
481
+ const ms = Number(internalDate);
482
+ if (!Number.isFinite(ms) || ms <= 0) return 0;
483
+ return Math.floor(ms / 1000);
484
+ }
485
+
486
+ /**
487
+ * Convert an `internalDate` epoch-ms string to an ISO 8601 string.
488
+ */
489
+ function internalDateToIso(internalDate: string): string {
490
+ const ms = Number(internalDate);
491
+ if (!Number.isFinite(ms) || ms <= 0) return "";
492
+ return new Date(ms).toISOString();
493
+ }
494
+
495
+ // ---------------------------------------------------------------------------
496
+ // seenIds cap / pruning (Codex P1 PRRT_kwDORJXyws59se73)
497
+ // ---------------------------------------------------------------------------
498
+
499
+ /**
500
+ * Prune `seenIds` to remove entries that can no longer be returned by the next
501
+ * `after:` query. Gmail's `after:N` matches messages with `internalDate > N*1000`,
502
+ * where `N = Math.floor(watermarkMs / 1000)`. So any message with
503
+ * `internalDate <= floor(watermarkMs/1000) * 1000` cannot appear in the next
504
+ * query and can be safely dropped. Messages in the same floor-second as the
505
+ * watermark (i.e. `internalDate > floor(watermarkMs/1000)*1000`) must be
506
+ * retained so seenIds can suppress them if Gmail re-returns them.
507
+ *
508
+ * Additionally enforce a hard size cap: if after date-pruning the map still
509
+ * exceeds SEEN_IDS_MAX, retain only the SEEN_IDS_RETAIN most recent entries
510
+ * (by internalDate value) to prevent unbounded cursor growth.
511
+ */
512
+ export function pruneSeenIds(
513
+ seenIds: Record<string, string>,
514
+ watermarkMs: number,
515
+ ): Record<string, string> {
516
+ // Step 1: drop entries whose internalDate falls at or before the floor-second
517
+ // boundary. These messages cannot be returned by after:floor(watermarkMs/1000).
518
+ const floorSecBoundaryMs = Math.floor(watermarkMs / 1000) * 1000;
519
+ let pruned: Record<string, string> = {};
520
+ for (const [id, dateMs] of Object.entries(seenIds)) {
521
+ if (Number(dateMs) > floorSecBoundaryMs) {
522
+ pruned[id] = dateMs;
523
+ }
524
+ }
525
+
526
+ // Step 2: enforce hard cap — keep only the SEEN_IDS_RETAIN most recent.
527
+ const entries = Object.entries(pruned);
528
+ if (entries.length > SEEN_IDS_MAX) {
529
+ // Sort descending by internalDate (most recent first), retain top N.
530
+ entries.sort((a, b) => {
531
+ const diff = Number(b[1]) - Number(a[1]);
532
+ // Stable tie-break by id (CLAUDE.md gotcha #19).
533
+ return diff !== 0 ? diff : a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0;
534
+ });
535
+ const retained = entries.slice(0, SEEN_IDS_RETAIN);
536
+ pruned = Object.fromEntries(retained);
537
+ }
538
+
539
+ return pruned;
540
+ }
541
+
542
+ /**
543
+ * Prune the `skippedIds` map to prevent unbounded cursor growth.
544
+ * (Codex P2 PRRT_kwDORJXyws59z612)
545
+ *
546
+ * `skippedIds` maps message id → internalDate ms string (or "0" when the
547
+ * internalDate is unknown, e.g. inaccessible messages that never returned a
548
+ * body). Entries whose internalDate is strictly below the current watermark
549
+ * are eligible for pruning: Gmail's `after:floor(watermarkMs/1000)` query
550
+ * will never re-return them, so there is nothing left to suppress.
551
+ *
552
+ * Entries stored as "0" (unknown date) are retained unless the hard cap
553
+ * forces eviction, at which point they are treated as date=0 and evicted
554
+ * first (oldest-first ordering).
555
+ *
556
+ * After date-based pruning, if the entry count still exceeds SKIPPED_IDS_MAX
557
+ * we evict down to SKIPPED_IDS_RETAIN, keeping the most recent entries.
558
+ */
559
+ export function pruneSkippedIds(
560
+ skippedIds: Record<string, string>,
561
+ watermarkMs: number,
562
+ ): Record<string, string> {
563
+ // Step 1: drop entries whose internalDate is strictly below the watermark.
564
+ // "0" entries are unknown-date (inaccessible) — keep them.
565
+ let pruned: Record<string, string> = {};
566
+ for (const [id, dateMs] of Object.entries(skippedIds)) {
567
+ const ms = Number(dateMs);
568
+ if (ms === 0 || ms >= watermarkMs) {
569
+ pruned[id] = dateMs;
570
+ }
571
+ }
572
+
573
+ // Step 2: enforce hard cap — keep only the SKIPPED_IDS_RETAIN most recent.
574
+ const entries = Object.entries(pruned);
575
+ if (entries.length > SKIPPED_IDS_MAX) {
576
+ // Sort descending by date (most recent first); "0" sorts last (evicted first).
577
+ entries.sort((a, b) => {
578
+ const diff = Number(b[1]) - Number(a[1]);
579
+ return diff !== 0 ? diff : a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0;
580
+ });
581
+ const retained = entries.slice(0, SKIPPED_IDS_RETAIN);
582
+ pruned = Object.fromEntries(retained);
583
+ }
584
+
585
+ return pruned;
586
+ }
587
+
588
+ // ---------------------------------------------------------------------------
589
+ // Cooperative cancellation
590
+ // ---------------------------------------------------------------------------
591
+
592
+ function throwIfAborted(signal: AbortSignal | undefined): void {
593
+ if (signal?.aborted) {
594
+ const err = new Error("gmail: sync aborted");
595
+ err.name = "AbortError";
596
+ throw err;
597
+ }
598
+ }
599
+
600
+ // ---------------------------------------------------------------------------
601
+ // Gmail API client helpers
602
+ // ---------------------------------------------------------------------------
603
+
604
+ /**
605
+ * Build a Gmail API error with the HTTP status attached for classification.
606
+ */
607
+ function makeGmailApiError(
608
+ status: number,
609
+ message: string,
610
+ ): Error & { gmailStatus: number } {
611
+ const err = new Error(`gmail: API error ${status}: ${message}`) as Error & {
612
+ gmailStatus: number;
613
+ };
614
+ err.gmailStatus = status;
615
+ return err;
616
+ }
617
+
618
+ /**
619
+ * Helper to call a Gmail API endpoint via GET. Throws a structured error on
620
+ * non-2xx responses and propagates network errors unchanged.
621
+ */
622
+ async function gmailGet(
623
+ fetchFn: GmailFetchFn,
624
+ accessToken: string,
625
+ path: string,
626
+ signal: AbortSignal | undefined,
627
+ ): Promise<unknown> {
628
+ const url = `${GMAIL_API_BASE}${path}`;
629
+ const res = await fetchFn(url, {
630
+ method: "GET",
631
+ headers: {
632
+ Authorization: `Bearer ${accessToken}`,
633
+ Accept: "application/json",
634
+ },
635
+ signal,
636
+ });
637
+
638
+ const data = await res.json();
639
+ if (!res.ok) {
640
+ const msg = extractApiErrorMessage(data);
641
+ throw makeGmailApiError(res.status, msg);
642
+ }
643
+ return data;
644
+ }
645
+
646
+ function extractApiErrorMessage(data: unknown): string {
647
+ if (
648
+ typeof data === "object" &&
649
+ data !== null &&
650
+ typeof (data as Record<string, unknown>).error === "object"
651
+ ) {
652
+ const errObj = (data as Record<string, unknown>).error as Record<string, unknown>;
653
+ if (typeof errObj.message === "string") return errObj.message;
654
+ }
655
+ return "unknown error";
656
+ }
657
+
658
+ // ---------------------------------------------------------------------------
659
+ // Access token exchange
660
+ // ---------------------------------------------------------------------------
661
+
662
+ /**
663
+ * Exchange the refresh token for a short-lived access token via the OAuth2
664
+ * token endpoint. We never cache the access token — each pass gets a fresh
665
+ * one to avoid partial-session token expiry.
666
+ *
667
+ * Credentials are NEVER logged (CLAUDE.md privacy policy).
668
+ */
669
+ async function exchangeRefreshToken(
670
+ fetchFn: GmailFetchFn,
671
+ config: GmailConnectorConfig,
672
+ signal: AbortSignal | undefined,
673
+ ): Promise<string> {
674
+ throwIfAborted(signal);
675
+ const body = new URLSearchParams({
676
+ client_id: config.clientId,
677
+ client_secret: config[CLIENT_SECRET_FIELD],
678
+ refresh_token: config[REFRESH_TOKEN_FIELD],
679
+ grant_type: "refresh_token",
680
+ });
681
+
682
+ const res = await fetchFn(OAUTH2_TOKEN_URL, {
683
+ method: "POST",
684
+ headers: {
685
+ "Content-Type": "application/x-www-form-urlencoded",
686
+ },
687
+ body: body.toString(),
688
+ signal,
689
+ });
690
+
691
+ const data = await res.json();
692
+ if (!res.ok) {
693
+ // Do NOT include any credential values in the error message.
694
+ throw makeGmailApiError(
695
+ res.status,
696
+ `OAuth2 token exchange failed (HTTP ${res.status})`,
697
+ );
698
+ }
699
+
700
+ if (
701
+ typeof data !== "object" ||
702
+ data === null ||
703
+ typeof (data as Record<string, unknown>).access_token !== "string"
704
+ ) {
705
+ throw new Error("gmail: OAuth2 token exchange returned no access_token");
706
+ }
707
+ return (data as Record<string, unknown>).access_token as string;
708
+ }
709
+
710
+ // ---------------------------------------------------------------------------
711
+ // Message body extraction
712
+ // ---------------------------------------------------------------------------
713
+
714
+ /**
715
+ * Recursively extract `text/plain` body from a MIME part tree. Falls back to
716
+ * `text/html` (stripped) if no plain-text part exists. Returns an empty
717
+ * string for binary / attachment parts.
718
+ */
719
+ function extractBodyFromPart(part: GmailMessagePart): string {
720
+ const mime = part.mimeType ?? "";
721
+
722
+ // Plain text — decode base64url and return.
723
+ if (mime === "text/plain") {
724
+ return decodeBase64urlBody(part.body?.data ?? "");
725
+ }
726
+
727
+ // HTML — decode and strip tags.
728
+ if (mime === "text/html") {
729
+ const raw = decodeBase64urlBody(part.body?.data ?? "");
730
+ return stripHtmlTags(raw);
731
+ }
732
+
733
+ // Multipart — recurse into parts, prefer text/plain over text/html.
734
+ if (mime.startsWith("multipart/") && Array.isArray(part.parts)) {
735
+ // First pass: look for text/plain (direct children only for efficiency).
736
+ for (const child of part.parts) {
737
+ if ((child.mimeType ?? "") === "text/plain") {
738
+ const text = decodeBase64urlBody(child.body?.data ?? "");
739
+ if (text.length > 0) return text;
740
+ }
741
+ }
742
+ // Second pass: recurse into all children and take the first non-empty result.
743
+ for (const child of part.parts) {
744
+ const text = extractBodyFromPart(child);
745
+ if (text.length > 0) return text;
746
+ }
747
+ }
748
+
749
+ return "";
750
+ }
751
+
752
+ /**
753
+ * Decode a base64url-encoded string (Gmail API encodes all message body data
754
+ * in base64url). Returns empty string on any error rather than throwing.
755
+ */
756
+ function decodeBase64urlBody(encoded: string): string {
757
+ if (!encoded) return "";
758
+ try {
759
+ // base64url → base64: replace URL-safe chars with standard chars.
760
+ const base64 = encoded.replace(/-/g, "+").replace(/_/g, "/");
761
+ // Add padding if needed.
762
+ const padded = base64 + "=".repeat((4 - (base64.length % 4)) % 4);
763
+ return Buffer.from(padded, "base64").toString("utf-8");
764
+ } catch {
765
+ return "";
766
+ }
767
+ }
768
+
769
+ /**
770
+ * Minimal HTML tag stripper. Collapses all `<...>` spans and decodes common
771
+ * HTML entities in a single pass to avoid double-unescaping (CodeQL finding:
772
+ * chained replace calls can expand `&amp;lt;` → `&lt;` → `<`). The entity
773
+ * map is applied in one `replace` with a callback, so each entity is decoded
774
+ * exactly once and the output is never fed back through entity expansion.
775
+ */
776
+ function stripHtmlTags(html: string): string {
777
+ if (!html) return "";
778
+ // Step 1: strip all HTML tags.
779
+ const noTags = html.replace(/<[^>]*>/g, " ");
780
+ // Step 2: decode HTML entities in a single pass via a lookup table.
781
+ const HTML_ENTITIES: Readonly<Record<string, string>> = {
782
+ "&nbsp;": " ",
783
+ "&amp;": "&",
784
+ "&lt;": "<",
785
+ "&gt;": ">",
786
+ "&quot;": '"',
787
+ "&#39;": "'",
788
+ "&apos;": "'",
789
+ };
790
+ const decoded = noTags.replace(/&(?:#39|nbsp|amp|lt|gt|quot|apos);/gi, (entity) => {
791
+ return HTML_ENTITIES[entity.toLowerCase()] ?? entity;
792
+ });
793
+ // Step 3: collapse whitespace.
794
+ return decoded.replace(/\s{2,}/g, " ").trim();
795
+ }
796
+
797
+ /**
798
+ * Extract the `Subject` header value from a message. Returns undefined if
799
+ * not present. Never logs the value.
800
+ */
801
+ function extractSubject(message: GmailMessage): string | undefined {
802
+ const headers = message.payload?.headers ?? [];
803
+ for (const h of headers) {
804
+ if (typeof h.name === "string" && h.name.toLowerCase() === "subject") {
805
+ const v = h.value;
806
+ if (typeof v === "string" && v.trim().length > 0) return v.trim();
807
+ }
808
+ }
809
+ return undefined;
810
+ }
811
+
812
+ // ---------------------------------------------------------------------------
813
+ // Sync result type
814
+ // ---------------------------------------------------------------------------
815
+
816
+ /**
817
+ * Result of a single sync pass. Superset of `SyncIncrementalResult` for
818
+ * richer test assertions.
819
+ */
820
+ export interface GmailSyncResult extends SyncIncrementalResult {
821
+ readonly skippedInaccessible: number;
822
+ readonly skippedEmpty: number;
823
+ readonly skippedTooLarge: number;
824
+ }
825
+
826
+ // ---------------------------------------------------------------------------
827
+ // Connector factory
828
+ // ---------------------------------------------------------------------------
829
+
830
+ /**
831
+ * Construct the connector. The `fetchFn` argument is the test hook —
832
+ * production callers omit it and the connector uses the global `fetch`.
833
+ */
834
+ export function createGmailConnector(
835
+ options: { fetchFn?: GmailFetchFn } = {},
836
+ ): LiveConnector {
837
+ const fetchFn: GmailFetchFn =
838
+ options.fetchFn ??
839
+ (globalThis.fetch as unknown as GmailFetchFn);
840
+
841
+ return {
842
+ id: GMAIL_CONNECTOR_ID,
843
+ displayName: "Gmail",
844
+ description:
845
+ "Imports new inbox messages from Gmail into Remnic on a poll schedule.",
846
+
847
+ validateConfig(raw: unknown): ConnectorConfig {
848
+ return validateGmailConfig(raw) as unknown as ConnectorConfig;
849
+ },
850
+
851
+ async syncIncremental(args: SyncIncrementalArgs): Promise<SyncIncrementalResult> {
852
+ const config = validateGmailConfig(args.config);
853
+ throwIfAborted(args.abortSignal);
854
+
855
+ // Exchange credentials for a short-lived access token.
856
+ const accessToken = await exchangeRefreshToken(fetchFn, config, args.abortSignal);
857
+ throwIfAborted(args.abortSignal);
858
+
859
+ // First-sync bootstrap: record "now" as the watermark and return
860
+ // without importing anything. Mirrors Drive's getStartPageToken pattern.
861
+ if (args.cursor === null) {
862
+ const bootstrapResult: GmailSyncResult = {
863
+ newDocs: [],
864
+ nextCursor: makeCursor({
865
+ watermarkMs: String(Date.now()),
866
+ skippedIds: {},
867
+ seenIds: {},
868
+ }),
869
+ skippedInaccessible: 0,
870
+ skippedEmpty: 0,
871
+ skippedTooLarge: 0,
872
+ };
873
+ return bootstrapResult;
874
+ }
875
+
876
+ const cursorPayload = parseCursorPayload(args.cursor);
877
+ return await incrementalSync(
878
+ fetchFn,
879
+ accessToken,
880
+ config,
881
+ cursorPayload,
882
+ args.abortSignal,
883
+ );
884
+ },
885
+ };
886
+ }
887
+
888
+ // ---------------------------------------------------------------------------
889
+ // Incremental sync
890
+ // ---------------------------------------------------------------------------
891
+
892
+ async function incrementalSync(
893
+ fetchFn: GmailFetchFn,
894
+ accessToken: string,
895
+ config: GmailConnectorConfig,
896
+ cursorPayload: GmailCursorPayload,
897
+ signal: AbortSignal | undefined,
898
+ ): Promise<GmailSyncResult> {
899
+ const fetchedAt = new Date().toISOString();
900
+ const newDocs: ConnectorDocument[] = [];
901
+ let skippedInaccessible = 0;
902
+ let skippedEmpty = 0;
903
+ let skippedTooLarge = 0;
904
+ let totalConsumed = 0;
905
+
906
+ // --- Precision fix (Thread 1 / PRRT_kwDORJXyws59sa42) ---
907
+ //
908
+ // Watermark is now stored as exact epoch-milliseconds (`watermarkMs`).
909
+ // The Gmail `after:<n>` operator accepts epoch seconds, so we truncate to
910
+ // seconds for the query — but this means messages in the same second as the
911
+ // watermark are returned again by Gmail. We guard against re-importing them
912
+ // by checking each returned message id against `seenIds` (populated from the
913
+ // cursor) and comparing its `internalDate` against the exact ms watermark.
914
+ //
915
+ // Advance the watermark only forward; never let it go backward regardless
916
+ // of clock skew or out-of-order internalDate values from Gmail.
917
+ let currentWatermarkMs = 0;
918
+ let afterEpochSec = 0;
919
+ if (cursorPayload.watermarkMs.length > 0) {
920
+ const ms = Number(cursorPayload.watermarkMs);
921
+ if (Number.isFinite(ms) && ms > 0) {
922
+ currentWatermarkMs = ms;
923
+ // Fix (Codex P1 PRRT_kwDORJXyws59sh5H): use Math.floor so the `after:`
924
+ // query is inclusive of the watermark second. Gmail's `after:N` operator
925
+ // matches messages with internalDate > N*1000 (strictly after N seconds),
926
+ // so floor is the correct pairing: messages in the same second as the
927
+ // watermark may be re-returned by Gmail, but seenIds deduplication
928
+ // suppresses them without re-importing. Math.ceil was wrong: it rounds
929
+ // UP to the next second, which causes messages with internalDate exactly
930
+ // at the watermark second boundary to never be queried — they fall between
931
+ // floor and ceil and are permanently missed.
932
+ afterEpochSec = Math.floor(ms / 1000);
933
+ }
934
+ }
935
+
936
+ // Build the Gmail search query: combine watermark filter with user query.
937
+ const listQuery = buildListQuery(afterEpochSec, config.query);
938
+
939
+ // Sub-second dedup (Thread 1): carry over seenIds from the previous cursor.
940
+ // These are message ids already processed within the same second as the
941
+ // current watermark. We skip them if Gmail re-returns them.
942
+ // Cleared in the next cursor when the watermark advances into a new second.
943
+ const seenIds: Record<string, string> = { ...cursorPayload.seenIds };
944
+
945
+ // Skipped-message stall fix (Thread 2 / PRRT_kwDORJXyws59sa43): carry over
946
+ // permanently-skipped message ids from the previous cursor. These are
947
+ // messages that were empty, too-large, or inaccessible. They will never
948
+ // become processable (Gmail messages are immutable), so we bypass them
949
+ // without counting them toward the pass cap or stalling the watermark.
950
+ const skippedIds: Record<string, string> = { ...cursorPayload.skippedIds };
951
+
952
+ // Track the highest internalDate seen (in ms) across all non-skipped
953
+ // messages. Initialized to the current watermark so it only ever advances.
954
+ let highWaterMs = currentWatermarkMs;
955
+
956
+ // Thread 2 fix (Codex P1 PRRT_kwDORJXyws59sctD): resume from a persisted
957
+ // page token if present. This prevents re-processing the first batch every
958
+ // pass when the cap is hit mid-page with newest-first ordering (livelock).
959
+ let pageToken: string | undefined = cursorPayload.pageToken;
960
+
961
+ // Whether we exhausted the full message list without hitting the per-pass
962
+ // cap. Mirrors Notion's `databaseFullyDrained` pattern (Codex P1 review):
963
+ // only advance the watermark when we fully drained the list. If the cap was
964
+ // hit mid-pass, the next poll must resume from the saved pageToken (see
965
+ // Thread 2 fix above) to pick up the remaining messages without re-doing
966
+ // the first batch.
967
+ let listFullyDrained = false;
968
+ let capHit = false;
969
+ // Track the page token at the point the cap is hit so we can persist it.
970
+ let capHitPageToken: string | undefined = undefined;
971
+
972
+ // Page through messages.list until exhausted, aborted, or per-pass cap hit.
973
+ while (true) {
974
+ throwIfAborted(signal);
975
+
976
+ // Build the list URL.
977
+ let listPath = `/users/${encodeURIComponent(config.userId)}/messages?maxResults=${LIST_PAGE_SIZE}&q=${encodeURIComponent(listQuery)}`;
978
+ if (pageToken) {
979
+ listPath += `&pageToken=${encodeURIComponent(pageToken)}`;
980
+ }
981
+
982
+ // Fetch the page. If a persisted pageToken is invalid/expired (Gmail
983
+ // returns 400), clear it and retry from the beginning of the `after:`
984
+ // window for this pass — otherwise the connector stalls forever retrying
985
+ // the same bad token. (Codex P1 PRRT_kwDORJXyws59z610)
986
+ let listData: unknown;
987
+ try {
988
+ listData = await gmailGet(fetchFn, accessToken, listPath, signal);
989
+ } catch (listErr) {
990
+ const listErrObj = listErr as { gmailStatus?: unknown } | null;
991
+ if (
992
+ pageToken !== undefined &&
993
+ listErrObj !== null &&
994
+ typeof listErrObj === "object" &&
995
+ listErrObj.gmailStatus === 400
996
+ ) {
997
+ // The persisted pageToken is stale or invalid. Clear it and restart
998
+ // from the beginning of the `after:` window for this pass.
999
+ pageToken = undefined;
1000
+ listPath = `/users/${encodeURIComponent(config.userId)}/messages?maxResults=${LIST_PAGE_SIZE}&q=${encodeURIComponent(listQuery)}`;
1001
+ listData = await gmailGet(fetchFn, accessToken, listPath, signal);
1002
+ } else {
1003
+ throw listErr;
1004
+ }
1005
+ }
1006
+ throwIfAborted(signal);
1007
+
1008
+ const listPage = listData as {
1009
+ messages?: GmailMessageRef[];
1010
+ nextPageToken?: string;
1011
+ };
1012
+
1013
+ const messages = listPage.messages ?? [];
1014
+
1015
+ // Whether the per-pass cap was hit while iterating this page's messages.
1016
+ let capHitMidPage = false;
1017
+
1018
+ for (const ref of messages) {
1019
+ throwIfAborted(signal);
1020
+
1021
+ // Thread 2: if this id was permanently skipped in a prior pass, skip
1022
+ // it again without consuming the per-pass cap. The message is immutable
1023
+ // and will never become processable.
1024
+ if (skippedIds[ref.id]) {
1025
+ continue;
1026
+ }
1027
+
1028
+ // Thread 1 (sub-second dedup): if this id was already processed in the
1029
+ // same second-window as the current watermark, skip it. This prevents
1030
+ // re-importing messages that Gmail re-returns because `after:` is
1031
+ // second-granular but our watermark has sub-second precision.
1032
+ if (seenIds[ref.id] !== undefined) {
1033
+ continue;
1034
+ }
1035
+
1036
+ if (totalConsumed >= MAX_MESSAGES_PER_PASS) {
1037
+ // Cap hit mid-page. Stop processing this page's remaining messages.
1038
+ // We still need to read listPage.nextPageToken below (Thread 2) to
1039
+ // know whether there are more pages to resume from.
1040
+ capHitMidPage = true;
1041
+ break;
1042
+ }
1043
+ totalConsumed++;
1044
+
1045
+ const doc = await fetchMessageDocument(
1046
+ fetchFn,
1047
+ accessToken,
1048
+ config,
1049
+ ref.id,
1050
+ fetchedAt,
1051
+ signal,
1052
+ );
1053
+
1054
+ if (doc === "inaccessible") {
1055
+ skippedInaccessible++;
1056
+ // Terminal: don't re-fetch this id. Record it in skippedIds so future
1057
+ // polls bypass it without hitting the API again (Thread 2 fix).
1058
+ // Store "0" as the date — we have no internalDate for inaccessible
1059
+ // messages; pruneSkippedIds treats "0" as unknown and evicts last.
1060
+ skippedIds[ref.id] = "0";
1061
+ } else if (doc !== null && typeof doc === "object" && "kind" in doc) {
1062
+ // SkippedWithDate: empty or too-large. Gmail messages are immutable,
1063
+ // so record the id in skippedIds (Thread 2 fix) to prevent re-fetching
1064
+ // on every subsequent poll, AND update highWaterMs with the message's
1065
+ // internalDate so the watermark can advance past it when fully drained.
1066
+ // Store the internalDate so pruneSkippedIds can evict this entry once
1067
+ // the watermark advances past it. (Codex P2 PRRT_kwDORJXyws59z612)
1068
+ if (doc.kind === "empty") skippedEmpty++;
1069
+ else skippedTooLarge++;
1070
+ skippedIds[ref.id] =
1071
+ doc.internalDate.length > 0 ? doc.internalDate : "0";
1072
+ const skippedMs = Number(doc.internalDate);
1073
+ if (Number.isFinite(skippedMs) && skippedMs > highWaterMs) {
1074
+ highWaterMs = skippedMs;
1075
+ }
1076
+ } else if (doc !== null) {
1077
+ newDocs.push(doc as ConnectorDocument);
1078
+ // Track highest internalDate to advance watermark when fully drained.
1079
+ const successDoc = doc as ConnectorDocument;
1080
+ if (successDoc.source.externalRevision) {
1081
+ const msgMs = Number(successDoc.source.externalRevision);
1082
+ if (Number.isFinite(msgMs) && msgMs > highWaterMs) {
1083
+ highWaterMs = msgMs;
1084
+ }
1085
+ // Thread 1: record this id in seenIds so same-second re-queries
1086
+ // don't re-import it. seenIds maps id → internalDate ms string.
1087
+ seenIds[ref.id] = successDoc.source.externalRevision;
1088
+ }
1089
+ }
1090
+ }
1091
+
1092
+ // Resolve the next-page token from this page's response.
1093
+ const hasNextPage =
1094
+ typeof listPage.nextPageToken === "string" && listPage.nextPageToken.length > 0;
1095
+ const resolvedNextPageToken = hasNextPage ? listPage.nextPageToken : undefined;
1096
+
1097
+ if (capHitMidPage) {
1098
+ // Cap-hit mid-page fix (Codex P1 PRRT_kwDORJXyws59sh5I + Cursor
1099
+ // PRRT_kwDORJXyws59sji9): when the cap is hit while iterating this page,
1100
+ // persist the CURRENT page's token (the one used to fetch this page) so
1101
+ // the next poll re-fetches the same page and continues where we left off.
1102
+ // Messages already processed are in seenIds and will be skipped on
1103
+ // re-fetch. If pageToken is undefined we are on page 1, so the next poll
1104
+ // restarts from the beginning of the `after:` window — also correct.
1105
+ //
1106
+ // Previously we saved resolvedNextPageToken (the NEXT page's token),
1107
+ // which skipped all messages remaining on the current page — those
1108
+ // messages would never be processed.
1109
+ capHit = true;
1110
+ capHitPageToken = pageToken;
1111
+ break;
1112
+ }
1113
+
1114
+ // Continue to the next page if Gmail signals more results.
1115
+ if (resolvedNextPageToken !== undefined) {
1116
+ pageToken = resolvedNextPageToken;
1117
+ continue;
1118
+ }
1119
+
1120
+ // No nextPageToken — the list is fully drained for this `after:` window.
1121
+ listFullyDrained = true;
1122
+ break;
1123
+ }
1124
+
1125
+ // --- Watermark advancement ---
1126
+ //
1127
+ // Only advance when we fully drained the list (no cap hit, no premature
1128
+ // abort). Compare against the exact ms watermark (not the truncated
1129
+ // afterEpochSec * 1000) to prevent backward regression on clock skew.
1130
+ //
1131
+ // seenIds pruning (Codex P1 PRRT_kwDORJXyws59se73): after every pass, prune
1132
+ // seenIds via pruneSeenIds(seenIds, nextWatermarkMs). This replaces the
1133
+ // previous "clear seenIds when crossing a second boundary" approach, which
1134
+ // was incorrect — messages within the current watermark second can still
1135
+ // appear in the next `after:floor(watermarkMs/1000)` query, so clearing
1136
+ // seenIds caused re-imports. Instead we prune entries strictly below the
1137
+ // new watermark and enforce a hard size cap (SEEN_IDS_MAX / SEEN_IDS_RETAIN)
1138
+ // to bound cursor growth regardless of how many messages share the active
1139
+ // second window.
1140
+ //
1141
+ // Thread 2: pageToken in the next cursor is set only when the cap was hit
1142
+ // mid-page. It is cleared (not included) when the list is fully drained.
1143
+ let nextWatermarkMs: string;
1144
+ let nextSeenIds: Record<string, string>;
1145
+ let nextSkippedIds: Record<string, string>;
1146
+ let nextPageToken: string | undefined;
1147
+
1148
+ if (listFullyDrained && !capHit && highWaterMs > currentWatermarkMs) {
1149
+ nextWatermarkMs = String(highWaterMs);
1150
+ // Prune seenIds to new watermark and enforce size cap.
1151
+ nextSeenIds = pruneSeenIds(seenIds, highWaterMs);
1152
+ // Prune skippedIds to new watermark. (Codex P2 PRRT_kwDORJXyws59z612)
1153
+ nextSkippedIds = pruneSkippedIds(skippedIds, highWaterMs);
1154
+ // Window fully drained — clear the page token.
1155
+ nextPageToken = undefined;
1156
+ } else if (capHit) {
1157
+ // Cap hit mid-page: keep watermark; prune seenIds to current watermark
1158
+ // and enforce size cap; persist the current page token (Thread 2 / fix
1159
+ // PRRT_kwDORJXyws59sh5I).
1160
+ nextWatermarkMs = cursorPayload.watermarkMs;
1161
+ nextSeenIds = pruneSeenIds(seenIds, currentWatermarkMs);
1162
+ nextSkippedIds = pruneSkippedIds(skippedIds, currentWatermarkMs);
1163
+ nextPageToken = capHitPageToken;
1164
+ } else {
1165
+ // Watermark unchanged (list drained but no new messages, or aborted) —
1166
+ // keep exact ms string; prune seenIds to current watermark; no page token.
1167
+ nextWatermarkMs = cursorPayload.watermarkMs;
1168
+ nextSeenIds = pruneSeenIds(seenIds, currentWatermarkMs);
1169
+ nextSkippedIds = pruneSkippedIds(skippedIds, currentWatermarkMs);
1170
+ nextPageToken = undefined;
1171
+ }
1172
+
1173
+ const nextCursor = makeCursor({
1174
+ watermarkMs: nextWatermarkMs,
1175
+ skippedIds: nextSkippedIds,
1176
+ seenIds: nextSeenIds,
1177
+ ...(nextPageToken !== undefined ? { pageToken: nextPageToken } : {}),
1178
+ });
1179
+
1180
+ return {
1181
+ newDocs,
1182
+ nextCursor,
1183
+ skippedInaccessible,
1184
+ skippedEmpty,
1185
+ skippedTooLarge,
1186
+ };
1187
+ }
1188
+
1189
+ /**
1190
+ * Build the Gmail query string combining the `after:` watermark filter with
1191
+ * the operator-configured `query`. The `after:` operator takes epoch seconds.
1192
+ */
1193
+ function buildListQuery(afterEpochSec: number, userQuery: string): string {
1194
+ const parts: string[] = [];
1195
+ if (afterEpochSec > 0) {
1196
+ parts.push(`after:${afterEpochSec}`);
1197
+ }
1198
+ const trimmedUser = userQuery.trim();
1199
+ if (trimmedUser.length > 0) {
1200
+ parts.push(trimmedUser);
1201
+ }
1202
+ return parts.join(" ");
1203
+ }
1204
+
1205
+ // ---------------------------------------------------------------------------
1206
+ // Per-message document fetch
1207
+ // ---------------------------------------------------------------------------
1208
+
1209
+ /**
1210
+ * Tagged result for skipped messages that have an `internalDate` available.
1211
+ * The caller uses the date to advance the watermark past immutable messages
1212
+ * (empty or too-large) that would otherwise stall the watermark forever
1213
+ * (Cursor Medium review: empty/too-large messages permanently stall watermark).
1214
+ */
1215
+ type SkippedWithDate = { kind: "empty" | "too-large"; internalDate: string };
1216
+
1217
+ async function fetchMessageDocument(
1218
+ fetchFn: GmailFetchFn,
1219
+ accessToken: string,
1220
+ config: GmailConnectorConfig,
1221
+ messageId: string,
1222
+ fetchedAt: string,
1223
+ signal: AbortSignal | undefined,
1224
+ ): Promise<ConnectorDocument | SkippedWithDate | "inaccessible" | null> {
1225
+ throwIfAborted(signal);
1226
+
1227
+ let message: GmailMessage;
1228
+ try {
1229
+ const path = `/users/${encodeURIComponent(config.userId)}/messages/${encodeURIComponent(messageId)}?format=full`;
1230
+ const data = await gmailGet(fetchFn, accessToken, path, signal);
1231
+ message = data as GmailMessage;
1232
+ } catch (err) {
1233
+ if (isTransientGmailError(err)) {
1234
+ // Transient: re-throw to stop the pass without advancing the cursor.
1235
+ throw err;
1236
+ }
1237
+ // 401 Unauthorized on a per-message fetch is also transient: the access
1238
+ // token may have expired mid-pass. Re-throwing prevents the message from
1239
+ // being permanently blacklisted in skippedIds when credentials are
1240
+ // temporarily invalid. The next poll will re-fetch a fresh token and retry.
1241
+ // (Codex P1 PRRT_kwDORJXyws59z61w)
1242
+ if (
1243
+ err !== null &&
1244
+ typeof err === "object" &&
1245
+ (err as { gmailStatus?: unknown }).gmailStatus === 401
1246
+ ) {
1247
+ throw err;
1248
+ }
1249
+ // Terminal (404 / 403 / 400): skip this message.
1250
+ return "inaccessible";
1251
+ }
1252
+
1253
+ const internalDate = message.internalDate ?? "";
1254
+
1255
+ // Extract body text.
1256
+ const body = message.payload ? extractBodyFromPart(message.payload) : "";
1257
+
1258
+ if (typeof body !== "string" || body.trim().length === 0) {
1259
+ // Return the internalDate so the caller can advance the watermark past
1260
+ // this immutable empty message (it will never have content).
1261
+ return { kind: "empty", internalDate };
1262
+ }
1263
+ if (body.length > MAX_TEXT_BYTES) {
1264
+ // Same for too-large: the message is immutable; record its date.
1265
+ return { kind: "too-large", internalDate };
1266
+ }
1267
+
1268
+ const subject = extractSubject(message);
1269
+
1270
+ return {
1271
+ id: messageId,
1272
+ title: subject,
1273
+ content: body,
1274
+ source: {
1275
+ connector: GMAIL_CONNECTOR_ID,
1276
+ externalId: messageId,
1277
+ // Store internalDate (epoch ms string) as the revision so downstream
1278
+ // dedup can identify repeat fetches after cursor rewind.
1279
+ externalRevision: internalDate.length > 0 ? internalDate : undefined,
1280
+ fetchedAt,
1281
+ },
1282
+ };
1283
+ }
1284
+
1285
+ // ---------------------------------------------------------------------------
1286
+ // Watermark helpers (exported for tests)
1287
+ // ---------------------------------------------------------------------------
1288
+
1289
+ /**
1290
+ * Convert an `internalDate` epoch-ms string to an ISO 8601 timestamp.
1291
+ * Exported for test assertions.
1292
+ */
1293
+ export { internalDateToIso, internalDateToEpochSeconds, buildListQuery };