@remnic/core 1.1.2 → 1.1.4

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 (489) hide show
  1. package/dist/abort-error.js +1 -0
  2. package/dist/abstraction-nodes.js +1 -0
  3. package/dist/access-audit.js +1 -0
  4. package/dist/access-cli.js +72 -47
  5. package/dist/access-cli.js.map +1 -1
  6. package/dist/access-http.d.ts +50 -5
  7. package/dist/access-http.js +39 -16
  8. package/dist/access-idempotency.js +1 -0
  9. package/dist/access-mcp.d.ts +10 -5
  10. package/dist/access-mcp.js +38 -14
  11. package/dist/access-schema.d.ts +133 -13
  12. package/dist/access-schema.js +20 -1
  13. package/dist/access-service-CtXFnprR.d.ts +2033 -0
  14. package/dist/access-service.d.ts +11 -6
  15. package/dist/access-service.js +40 -15
  16. package/dist/active-memory-bridge.js +1 -0
  17. package/dist/active-recall.js +1 -0
  18. package/dist/active-recall.js.map +1 -1
  19. package/dist/behavior-learner.js +1 -0
  20. package/dist/behavior-learner.js.map +1 -1
  21. package/dist/behavior-signals.js +1 -0
  22. package/dist/bootstrap.d.ts +6 -4
  23. package/dist/bootstrap.js +1 -0
  24. package/dist/boxes.js +1 -0
  25. package/dist/briefing.d.ts +9 -5
  26. package/dist/briefing.js +10 -7
  27. package/dist/buffer-surprise-report.js +1 -0
  28. package/dist/buffer-surprise.js +1 -0
  29. package/dist/buffer.d.ts +1 -1
  30. package/dist/buffer.js +1 -0
  31. package/dist/calibration.d.ts +8 -1
  32. package/dist/calibration.js +10 -2
  33. package/dist/calibration.js.map +1 -1
  34. package/dist/capsule-cli.d.ts +137 -0
  35. package/dist/capsule-cli.js +34 -0
  36. package/dist/capsule-crypto-5CYAGVC5.js +18 -0
  37. package/dist/capsule-export-NZQPOTQ4.js +17 -0
  38. package/dist/capsule-export-NZQPOTQ4.js.map +1 -0
  39. package/dist/capsule-import-SDCUXLEV.js +16 -0
  40. package/dist/capsule-import-SDCUXLEV.js.map +1 -0
  41. package/dist/capsule-merge-DI7PNQ2H.js +189 -0
  42. package/dist/capsule-merge-DI7PNQ2H.js.map +1 -0
  43. package/dist/causal-behavior.js +1 -0
  44. package/dist/causal-behavior.js.map +1 -1
  45. package/dist/causal-chain.js +1 -0
  46. package/dist/causal-consolidation.js +12 -9
  47. package/dist/causal-consolidation.js.map +1 -1
  48. package/dist/causal-retrieval.js +2 -1
  49. package/dist/causal-retrieval.js.map +1 -1
  50. package/dist/causal-trajectory-graph.js +4 -1
  51. package/dist/causal-trajectory-graph.js.map +1 -1
  52. package/dist/causal-trajectory.js +2 -1
  53. package/dist/chunk-2LSZVONP.js +67 -0
  54. package/dist/chunk-2LSZVONP.js.map +1 -0
  55. package/dist/chunk-32KD5IHZ.js +245 -0
  56. package/dist/chunk-32KD5IHZ.js.map +1 -0
  57. package/dist/chunk-3KIS4VGT.js +228 -0
  58. package/dist/chunk-3KIS4VGT.js.map +1 -0
  59. package/dist/chunk-3LCWFNVS.js +350 -0
  60. package/dist/chunk-3LCWFNVS.js.map +1 -0
  61. package/dist/chunk-43EKP2UK.js +26 -0
  62. package/dist/chunk-43EKP2UK.js.map +1 -0
  63. package/dist/chunk-457A4P3L.js +119 -0
  64. package/dist/chunk-457A4P3L.js.map +1 -0
  65. package/dist/{chunk-TMYO7B5P.js → chunk-47WOM4YW.js} +2 -2
  66. package/dist/{chunk-FVA6TGI3.js → chunk-52PDY6GD.js} +42 -2
  67. package/dist/chunk-52PDY6GD.js.map +1 -0
  68. package/dist/{chunk-ULYOGL6R.js → chunk-5HRY2WRF.js} +7 -3
  69. package/dist/chunk-5HRY2WRF.js.map +1 -0
  70. package/dist/{chunk-BOUYNNYD.js → chunk-67YLUWLG.js} +32 -13
  71. package/dist/{chunk-BOUYNNYD.js.map → chunk-67YLUWLG.js.map} +1 -1
  72. package/dist/chunk-6TBWYBJ3.js +236 -0
  73. package/dist/chunk-6TBWYBJ3.js.map +1 -0
  74. package/dist/chunk-74EMIVE4.js +329 -0
  75. package/dist/chunk-74EMIVE4.js.map +1 -0
  76. package/dist/chunk-74WWN7ZW.js +82 -0
  77. package/dist/chunk-74WWN7ZW.js.map +1 -0
  78. package/dist/chunk-A6XUJE5D.js +126 -0
  79. package/dist/chunk-A6XUJE5D.js.map +1 -0
  80. package/dist/{chunk-STGWEHYR.js → chunk-AEMBDV7M.js} +1187 -62
  81. package/dist/chunk-AEMBDV7M.js.map +1 -0
  82. package/dist/{chunk-PVICZTKG.js → chunk-AGZHRWPT.js} +5 -5
  83. package/dist/{chunk-PVICZTKG.js.map → chunk-AGZHRWPT.js.map} +1 -1
  84. package/dist/chunk-AJA46VX5.js +393 -0
  85. package/dist/chunk-AJA46VX5.js.map +1 -0
  86. package/dist/chunk-ASIQZXYO.js +277 -0
  87. package/dist/chunk-ASIQZXYO.js.map +1 -0
  88. package/dist/{chunk-DG6YMRDC.js → chunk-B2TL6GA2.js} +2 -2
  89. package/dist/chunk-BJMBJZ2Y.js +290 -0
  90. package/dist/chunk-BJMBJZ2Y.js.map +1 -0
  91. package/dist/chunk-BT7NVCML.js +79 -0
  92. package/dist/chunk-BT7NVCML.js.map +1 -0
  93. package/dist/chunk-CK5NTM2S.js +454 -0
  94. package/dist/chunk-CK5NTM2S.js.map +1 -0
  95. package/dist/{chunk-AYXIPSZO.js → chunk-CRU27Q4J.js} +2 -2
  96. package/dist/{chunk-UWB5LMWY.js → chunk-CUI2STX6.js} +526 -24
  97. package/dist/chunk-CUI2STX6.js.map +1 -0
  98. package/dist/{chunk-CUPFXL3J.js → chunk-EGEPUGN4.js} +4 -4
  99. package/dist/chunk-EGEPUGN4.js.map +1 -0
  100. package/dist/{chunk-3OGMS3PE.js → chunk-F5VQOQ2E.js} +3 -2
  101. package/dist/chunk-F5VQOQ2E.js.map +1 -0
  102. package/dist/chunk-FP2373TW.js +149 -0
  103. package/dist/chunk-FP2373TW.js.map +1 -0
  104. package/dist/{chunk-RBBWYEFJ.js → chunk-G2WADRQ3.js} +1 -1
  105. package/dist/chunk-G7D6GZ5J.js +48 -0
  106. package/dist/chunk-G7D6GZ5J.js.map +1 -0
  107. package/dist/chunk-H7XKCNR6.js +60 -0
  108. package/dist/chunk-H7XKCNR6.js.map +1 -0
  109. package/dist/{chunk-LOIMBRDE.js → chunk-HIRKCQGF.js} +1994 -412
  110. package/dist/chunk-HIRKCQGF.js.map +1 -0
  111. package/dist/chunk-IXEJRKCZ.js +18 -0
  112. package/dist/chunk-IXEJRKCZ.js.map +1 -0
  113. package/dist/chunk-IYY4MCPG.js +275 -0
  114. package/dist/chunk-IYY4MCPG.js.map +1 -0
  115. package/dist/{chunk-BECYBZLX.js → chunk-JWSENLQI.js} +502 -22
  116. package/dist/chunk-JWSENLQI.js.map +1 -0
  117. package/dist/chunk-KNKUID7G.js +183 -0
  118. package/dist/chunk-KNKUID7G.js.map +1 -0
  119. package/dist/chunk-L2IO2QPY.js +2036 -0
  120. package/dist/chunk-L2IO2QPY.js.map +1 -0
  121. package/dist/{chunk-ZAIM4TUE.js → chunk-LW2NMHDW.js} +46 -1
  122. package/dist/chunk-LW2NMHDW.js.map +1 -0
  123. package/dist/chunk-MDYG7VI7.js +48 -0
  124. package/dist/chunk-MDYG7VI7.js.map +1 -0
  125. package/dist/{chunk-VDX363PS.js → chunk-MUELDH4F.js} +10 -3
  126. package/dist/chunk-MUELDH4F.js.map +1 -0
  127. package/dist/chunk-MXC3AP5I.js +74 -0
  128. package/dist/chunk-MXC3AP5I.js.map +1 -0
  129. package/dist/chunk-NN3TS5BM.js +147 -0
  130. package/dist/chunk-NN3TS5BM.js.map +1 -0
  131. package/dist/{chunk-3YGHKTBF.js → chunk-NZS2BLTP.js} +963 -326
  132. package/dist/chunk-NZS2BLTP.js.map +1 -0
  133. package/dist/chunk-OA3L7BFR.js +183 -0
  134. package/dist/chunk-OA3L7BFR.js.map +1 -0
  135. package/dist/chunk-OZHRDTDX.js +240 -0
  136. package/dist/chunk-OZHRDTDX.js.map +1 -0
  137. package/dist/chunk-PCUKNJAZ.js +165 -0
  138. package/dist/chunk-PCUKNJAZ.js.map +1 -0
  139. package/dist/{chunk-6PFRXT4K.js → chunk-PFV5C235.js} +11 -6
  140. package/dist/chunk-PFV5C235.js.map +1 -0
  141. package/dist/chunk-PZ5AY32C.js +10 -0
  142. package/dist/chunk-PZ5AY32C.js.map +1 -0
  143. package/dist/{chunk-Y7R2XJ5Q.js → chunk-Q7FJ5ZHM.js} +6 -2
  144. package/dist/chunk-Q7FJ5ZHM.js.map +1 -0
  145. package/dist/{chunk-WCLICCGB.js → chunk-RILIVK4O.js} +91 -4
  146. package/dist/chunk-RILIVK4O.js.map +1 -0
  147. package/dist/{chunk-C2EFFULQ.js → chunk-RK2Y4XOM.js} +163 -20
  148. package/dist/chunk-RK2Y4XOM.js.map +1 -0
  149. package/dist/{chunk-TP4FZJIZ.js → chunk-RULE4VG5.js} +5 -1
  150. package/dist/chunk-RULE4VG5.js.map +1 -0
  151. package/dist/{chunk-PVPWZSSI.js → chunk-SMA4IMHV.js} +19 -3
  152. package/dist/chunk-SMA4IMHV.js.map +1 -0
  153. package/dist/{chunk-6YJHX2DL.js → chunk-TIFRGAKO.js} +242 -22
  154. package/dist/chunk-TIFRGAKO.js.map +1 -0
  155. package/dist/chunk-TUFG6VXY.js +875 -0
  156. package/dist/chunk-TUFG6VXY.js.map +1 -0
  157. package/dist/chunk-TYEOAFH3.js +251 -0
  158. package/dist/chunk-TYEOAFH3.js.map +1 -0
  159. package/dist/chunk-UKJAGEXH.js +260 -0
  160. package/dist/chunk-UKJAGEXH.js.map +1 -0
  161. package/dist/{chunk-KVBLZUKV.js → chunk-USFPPRAF.js} +93 -3
  162. package/dist/chunk-USFPPRAF.js.map +1 -0
  163. package/dist/{chunk-NBVAS5MT.js → chunk-V7TEH5I2.js} +6 -6
  164. package/dist/{chunk-GA5P7RST.js → chunk-VTJVUHRK.js} +22 -36
  165. package/dist/chunk-VTJVUHRK.js.map +1 -0
  166. package/dist/{chunk-SPI27QT6.js → chunk-W7WWT4FJ.js} +9 -4
  167. package/dist/chunk-W7WWT4FJ.js.map +1 -0
  168. package/dist/chunk-WIICJPET.js +45 -0
  169. package/dist/chunk-WIICJPET.js.map +1 -0
  170. package/dist/{chunk-VBVG2M5G.js → chunk-WPGJYVUH.js} +6 -2
  171. package/dist/chunk-WPGJYVUH.js.map +1 -0
  172. package/dist/{chunk-4HQS2HPX.js → chunk-WSZIHQBK.js} +29 -9
  173. package/dist/{chunk-4HQS2HPX.js.map → chunk-WSZIHQBK.js.map} +1 -1
  174. package/dist/{chunk-NZLQTHS5.js → chunk-WW3QQF4H.js} +4 -1
  175. package/dist/chunk-WW3QQF4H.js.map +1 -0
  176. package/dist/{chunk-DIXB44VE.js → chunk-X6VBWOVZ.js} +28 -13
  177. package/dist/chunk-X6VBWOVZ.js.map +1 -0
  178. package/dist/{chunk-XXVWLXSG.js → chunk-XQ4EJLUD.js} +64 -92
  179. package/dist/chunk-XQ4EJLUD.js.map +1 -0
  180. package/dist/{chunk-OC5OXUQ4.js → chunk-XRCYKJ3V.js} +780 -17
  181. package/dist/chunk-XRCYKJ3V.js.map +1 -0
  182. package/dist/{chunk-F5VP6YCB.js → chunk-Y4A6M3B6.js} +573 -156
  183. package/dist/chunk-Y4A6M3B6.js.map +1 -0
  184. package/dist/chunk-YNJHCGDT.js +309 -0
  185. package/dist/chunk-YNJHCGDT.js.map +1 -0
  186. package/dist/{chunk-L7IXWRYE.js → chunk-ZIBOQULP.js} +22 -13
  187. package/dist/chunk-ZIBOQULP.js.map +1 -0
  188. package/dist/{chunk-W6SL7OFG.js → chunk-ZTSE2ZJ6.js} +12 -2
  189. package/dist/{chunk-W6SL7OFG.js.map → chunk-ZTSE2ZJ6.js.map} +1 -1
  190. package/dist/chunking.js +1 -0
  191. package/dist/cipher-GVE2GQ5H.js +28 -0
  192. package/dist/cipher-GVE2GQ5H.js.map +1 -0
  193. package/dist/citations.js +1 -0
  194. package/dist/{cli-BkeRaYfk.d.ts → cli-lMql2FCr.d.ts} +26 -7
  195. package/dist/cli.d.ts +11 -6
  196. package/dist/cli.js +69 -34
  197. package/dist/codex-thread-key.js +1 -0
  198. package/dist/commitment-ledger.js +1 -0
  199. package/dist/compression-optimizer.js +1 -0
  200. package/dist/config.d.ts +2 -1
  201. package/dist/config.js +4 -1
  202. package/dist/connectors-cli-DFGtY2DB.d.ts +257 -0
  203. package/dist/connectors-cli.d.ts +2 -0
  204. package/dist/connectors-cli.js +22 -0
  205. package/dist/connectors-cli.js.map +1 -0
  206. package/dist/consolidation-operator.d.ts +65 -5
  207. package/dist/consolidation-operator.js +6 -1
  208. package/dist/consolidation-provenance-check.d.ts +1 -1
  209. package/dist/consolidation-provenance-check.js +3 -2
  210. package/dist/consolidation-undo.d.ts +1 -1
  211. package/dist/consolidation-undo.js +1 -0
  212. package/dist/consolidation-undo.js.map +1 -1
  213. package/dist/{contradiction-review-WIUBAR52.js → contradiction-review-5LTTVDQV.js} +2 -1
  214. package/dist/contradiction-review-5LTTVDQV.js.map +1 -0
  215. package/dist/{contradiction-scan-E3GJTI4F.js → contradiction-scan-3Z6YW7YA.js} +2 -1
  216. package/dist/{contradiction-scan-E3GJTI4F.js.map → contradiction-scan-3Z6YW7YA.js.map} +1 -1
  217. package/dist/cross-namespace-budget.js +1 -0
  218. package/dist/cue-anchors.js +1 -0
  219. package/dist/dashboard-runtime.js +1 -0
  220. package/dist/day-summary.js +1 -0
  221. package/dist/delinearize.js +1 -0
  222. package/dist/direct-answer-wiring.js +1 -0
  223. package/dist/direct-answer.js +1 -0
  224. package/dist/dreams-ledger-LR2NBAZE.js +286 -0
  225. package/dist/dreams-ledger-LR2NBAZE.js.map +1 -0
  226. package/dist/embedding-fallback.js +1 -0
  227. package/dist/engine-O6YWKQM3.js +28 -0
  228. package/dist/engine-O6YWKQM3.js.map +1 -0
  229. package/dist/entity-retrieval.d.ts +1 -1
  230. package/dist/entity-retrieval.js +10 -7
  231. package/dist/entity-schema.js +1 -0
  232. package/dist/evals.js +1 -0
  233. package/dist/evidence-pack.d.ts +16 -0
  234. package/dist/evidence-pack.js +8 -0
  235. package/dist/evidence-pack.js.map +1 -0
  236. package/dist/explicit-capture.d.ts +6 -4
  237. package/dist/explicit-capture.js +1 -0
  238. package/dist/extraction-judge-telemetry.js +1 -0
  239. package/dist/extraction-judge-training.js +1 -0
  240. package/dist/extraction-judge.js +1 -0
  241. package/dist/extraction.js +8 -7
  242. package/dist/fallback-llm.js +3 -2
  243. package/dist/first-start-migration-4MHQEOSD.js +263 -0
  244. package/dist/first-start-migration-4MHQEOSD.js.map +1 -0
  245. package/dist/forget-PLR6J5DN.js +69 -0
  246. package/dist/forget-PLR6J5DN.js.map +1 -0
  247. package/dist/framework-CyHYDcri.d.ts +153 -0
  248. package/dist/fs-utils-IRVUFB6G.js +30 -0
  249. package/dist/fs-utils-IRVUFB6G.js.map +1 -0
  250. package/dist/graph-dashboard-diff.js +1 -0
  251. package/dist/graph-dashboard-key.js +1 -0
  252. package/dist/graph-dashboard-parser.js +1 -0
  253. package/dist/graph-edge-decay-PWB63GRE.js +207 -0
  254. package/dist/graph-edge-decay-PWB63GRE.js.map +1 -0
  255. package/dist/graph-edge-reinforcement.d.ts +81 -0
  256. package/dist/graph-edge-reinforcement.js +24 -0
  257. package/dist/graph-edge-reinforcement.js.map +1 -0
  258. package/dist/graph-events.d.ts +87 -0
  259. package/dist/graph-events.js +14 -0
  260. package/dist/graph-events.js.map +1 -0
  261. package/dist/graph-recall.js +1 -0
  262. package/dist/graph-retrieval.js +1 -0
  263. package/dist/graph-snapshot.d.ts +112 -0
  264. package/dist/graph-snapshot.js +19 -0
  265. package/dist/graph-snapshot.js.map +1 -0
  266. package/dist/graph.d.ts +105 -7
  267. package/dist/graph.js +20 -3
  268. package/dist/harmonic-retrieval.js +1 -0
  269. package/dist/himem.js +1 -0
  270. package/dist/hygiene.js +1 -0
  271. package/dist/identity-continuity.js +1 -0
  272. package/dist/importance.js +1 -0
  273. package/dist/index.d.ts +574 -13
  274. package/dist/index.js +337 -69
  275. package/dist/index.js.map +1 -1
  276. package/dist/intent.js +1 -0
  277. package/dist/json-extract.js +1 -0
  278. package/dist/json-store.js +1 -0
  279. package/dist/kdf-7S6RWKLZ.js +26 -0
  280. package/dist/kdf-7S6RWKLZ.js.map +1 -0
  281. package/dist/legacy-hook-compat.js +1 -0
  282. package/dist/legacy-hook-compat.js.map +1 -1
  283. package/dist/lifecycle.js +1 -0
  284. package/dist/live-connectors-runner.d.ts +48 -0
  285. package/dist/live-connectors-runner.js +17 -0
  286. package/dist/live-connectors-runner.js.map +1 -0
  287. package/dist/local-llm.js +1 -0
  288. package/dist/logger.js +1 -0
  289. package/dist/memory-action-policy.js +1 -0
  290. package/dist/memory-cache.d.ts +2 -1
  291. package/dist/memory-cache.js +4 -1
  292. package/dist/memory-governance-JZHZDOLN.js +37 -0
  293. package/dist/memory-governance-JZHZDOLN.js.map +1 -0
  294. package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
  295. package/dist/memory-lifecycle-ledger-utils.js +4 -1
  296. package/dist/memory-projection-format.js +1 -0
  297. package/dist/{memory-projection-store-DeSXPh1j.d.ts → memory-projection-store-CY8TU40w.d.ts} +2 -1
  298. package/dist/memory-projection-store.d.ts +1 -1
  299. package/dist/memory-projection-store.js +2 -1
  300. package/dist/memory-worth-bench.js +1 -0
  301. package/dist/memory-worth-bench.js.map +1 -1
  302. package/dist/memory-worth-filter.js +1 -0
  303. package/dist/memory-worth-outcomes.d.ts +1 -1
  304. package/dist/memory-worth-outcomes.js +1 -0
  305. package/dist/memory-worth.js +1 -0
  306. package/dist/metadata-FC3XPDRQ.js +21 -0
  307. package/dist/metadata-FC3XPDRQ.js.map +1 -0
  308. package/dist/migrate-from-identity-anchor-TTEDEJGX.js +8 -0
  309. package/dist/migrate-from-identity-anchor-TTEDEJGX.js.map +1 -0
  310. package/dist/model-registry.js +1 -0
  311. package/dist/models-json.js +1 -0
  312. package/dist/native-knowledge.js +1 -0
  313. package/dist/negative.js +1 -0
  314. package/dist/objective-state-writers.js +1 -0
  315. package/dist/objective-state-writers.js.map +1 -1
  316. package/dist/objective-state.js +1 -0
  317. package/dist/openai-chat-compat.js +1 -0
  318. package/dist/operator-toolkit.d.ts +46 -2
  319. package/dist/operator-toolkit.js +29 -17
  320. package/dist/opik-exporter.js +1 -0
  321. package/dist/opik-exporter.js.map +1 -1
  322. package/dist/{orchestrator-CmJ-NTdJ.d.ts → orchestrator-ChkesB8U.d.ts} +177 -13
  323. package/dist/orchestrator.d.ts +6 -4
  324. package/dist/orchestrator.js +57 -41
  325. package/dist/page-versioning.js +1 -0
  326. package/dist/path-RMTY5Y5A.js +9 -0
  327. package/dist/path-RMTY5Y5A.js.map +1 -0
  328. package/dist/patterns-cli.d.ts +160 -0
  329. package/dist/patterns-cli.js +29 -0
  330. package/dist/patterns-cli.js.map +1 -0
  331. package/dist/peers-6OSQ3NK6.js +44 -0
  332. package/dist/peers-6OSQ3NK6.js.map +1 -0
  333. package/dist/plugin-id.js +1 -0
  334. package/dist/policy-runtime.js +1 -0
  335. package/dist/{port-BADbLZU5.d.ts → port-hqGnoStS.d.ts} +6 -0
  336. package/dist/profiling.js +1 -0
  337. package/dist/purge-6ATBGT77.js +205 -0
  338. package/dist/purge-6ATBGT77.js.map +1 -0
  339. package/dist/qmd-recall-cache.d.ts +1 -1
  340. package/dist/qmd-recall-cache.js +1 -0
  341. package/dist/qmd.d.ts +2 -1
  342. package/dist/qmd.js +4 -3
  343. package/dist/reasoning-trace-recall.js +1 -0
  344. package/dist/reasoning-trace-types.js +1 -0
  345. package/dist/recall-audit-anomaly.js +1 -0
  346. package/dist/recall-audit.js +1 -0
  347. package/dist/recall-disclosure-escalation.d.ts +84 -0
  348. package/dist/recall-disclosure-escalation.js +14 -0
  349. package/dist/recall-disclosure-escalation.js.map +1 -0
  350. package/dist/recall-explain-renderer.js +4 -1
  351. package/dist/recall-mmr.js +1 -0
  352. package/dist/recall-qos.js +1 -0
  353. package/dist/recall-query-policy.js +1 -0
  354. package/dist/recall-state.d.ts +7 -0
  355. package/dist/recall-state.js +2 -1
  356. package/dist/recall-tag-filter.d.ts +56 -0
  357. package/dist/recall-tag-filter.js +14 -0
  358. package/dist/recall-tag-filter.js.map +1 -0
  359. package/dist/recall-tokenization.js +1 -0
  360. package/dist/recall-xray-cli.d.ts +9 -2
  361. package/dist/recall-xray-cli.js +9 -4
  362. package/dist/recall-xray-renderer.js +4 -1
  363. package/dist/recall-xray.d.ts +116 -2
  364. package/dist/recall-xray.js +9 -3
  365. package/dist/reconstruct.js +1 -0
  366. package/dist/release-changelog.js +2 -0
  367. package/dist/release-changelog.js.map +1 -1
  368. package/dist/relevance.js +1 -0
  369. package/dist/rerank.js +1 -0
  370. package/dist/{resolution-QBTDHTG7.js → resolution-YGIBORXI.js} +2 -1
  371. package/dist/{resolution-QBTDHTG7.js.map → resolution-YGIBORXI.js.map} +1 -1
  372. package/dist/resolve-auth-token.d.ts +51 -0
  373. package/dist/resolve-auth-token.js +12 -0
  374. package/dist/resolve-auth-token.js.map +1 -0
  375. package/dist/resolve-provider-secret.d.ts +9 -1
  376. package/dist/resolve-provider-secret.js +4 -1
  377. package/dist/resume-bundles.js +4 -3
  378. package/dist/retrieval-agents.d.ts +1 -1
  379. package/dist/retrieval-agents.js +1 -0
  380. package/dist/retrieval-tiers.js +1 -0
  381. package/dist/retrieval.js +1 -0
  382. package/dist/sanitize.js +1 -0
  383. package/dist/schemas.d.ts +15 -2
  384. package/dist/schemas.js +2 -1
  385. package/dist/sdk-compat.js +1 -0
  386. package/dist/sdk-compat.js.map +1 -1
  387. package/dist/secure-store-4R2GSO7S.js +156 -0
  388. package/dist/secure-store-4R2GSO7S.js.map +1 -0
  389. package/dist/semantic-chunking.js +1 -0
  390. package/dist/{semantic-consolidation-CxJU6MJk.d.ts → semantic-consolidation-ByBXb-sf.d.ts} +3 -3
  391. package/dist/semantic-consolidation.d.ts +2 -2
  392. package/dist/semantic-consolidation.js +12 -7
  393. package/dist/semantic-rule-promotion.d.ts +1 -1
  394. package/dist/semantic-rule-promotion.js +10 -7
  395. package/dist/semantic-rule-verifier.d.ts +1 -1
  396. package/dist/semantic-rule-verifier.js +10 -7
  397. package/dist/session-integrity.js +1 -0
  398. package/dist/session-observer-bands.js +1 -0
  399. package/dist/session-observer-state.js +1 -0
  400. package/dist/session-toggles.js +2 -0
  401. package/dist/session-toggles.js.map +1 -1
  402. package/dist/signal.js +1 -0
  403. package/dist/skills-registry.js +2 -0
  404. package/dist/skills-registry.js.map +1 -1
  405. package/dist/source-attribution.js +1 -0
  406. package/dist/state-NCHQ4TRG.js +8 -0
  407. package/dist/state-NCHQ4TRG.js.map +1 -0
  408. package/dist/state-store-3EH7HYIN.js +16 -0
  409. package/dist/state-store-3EH7HYIN.js.map +1 -0
  410. package/dist/storage.d.ts +76 -2
  411. package/dist/storage.js +9 -6
  412. package/dist/store-contract.js +1 -0
  413. package/dist/summarizer.js +5 -4
  414. package/dist/summary-snapshot.js +1 -0
  415. package/dist/temporal-index.js +1 -0
  416. package/dist/temporal-supersession.d.ts +1 -1
  417. package/dist/temporal-supersession.js +2 -1
  418. package/dist/temporal-validity.d.ts +52 -0
  419. package/dist/temporal-validity.js +14 -0
  420. package/dist/temporal-validity.js.map +1 -0
  421. package/dist/threading.js +1 -0
  422. package/dist/tier-migration.d.ts +2 -2
  423. package/dist/tier-migration.js +1 -0
  424. package/dist/tier-routing.js +1 -0
  425. package/dist/tier-stats-62ZVDFKS.js +152 -0
  426. package/dist/tier-stats-62ZVDFKS.js.map +1 -0
  427. package/dist/tmt.js +1 -0
  428. package/dist/tokens.js +1 -0
  429. package/dist/topics.js +1 -0
  430. package/dist/trace-C5ETWBEF.js +290 -0
  431. package/dist/trace-C5ETWBEF.js.map +1 -0
  432. package/dist/transcript.js +1 -0
  433. package/dist/trust-zones.js +1 -0
  434. package/dist/tui-RI7P6PBS.js +13 -0
  435. package/dist/tui-RI7P6PBS.js.map +1 -0
  436. package/dist/types-V3FJ26TF.js +30 -0
  437. package/dist/types-V3FJ26TF.js.map +1 -0
  438. package/dist/types.d.ts +634 -9
  439. package/dist/types.js +10 -3
  440. package/dist/utility-learner.js +1 -0
  441. package/dist/utility-runtime.js +1 -0
  442. package/dist/utility-telemetry.js +1 -0
  443. package/dist/verified-recall.js +10 -7
  444. package/dist/version-utils.js +1 -0
  445. package/dist/whitespace.js +1 -0
  446. package/dist/work-product-ledger.js +1 -0
  447. package/package.json +7 -3
  448. package/scripts/ensure-better-sqlite3.mjs +124 -0
  449. package/dist/access-service-Br8ZydTK.d.ts +0 -827
  450. package/dist/chunk-3OGMS3PE.js.map +0 -1
  451. package/dist/chunk-3YGHKTBF.js.map +0 -1
  452. package/dist/chunk-6PFRXT4K.js.map +0 -1
  453. package/dist/chunk-6YJHX2DL.js.map +0 -1
  454. package/dist/chunk-BECYBZLX.js.map +0 -1
  455. package/dist/chunk-C2EFFULQ.js.map +0 -1
  456. package/dist/chunk-CUPFXL3J.js.map +0 -1
  457. package/dist/chunk-DIXB44VE.js.map +0 -1
  458. package/dist/chunk-F5VP6YCB.js.map +0 -1
  459. package/dist/chunk-FVA6TGI3.js.map +0 -1
  460. package/dist/chunk-GA5P7RST.js.map +0 -1
  461. package/dist/chunk-KVBLZUKV.js.map +0 -1
  462. package/dist/chunk-L7IXWRYE.js.map +0 -1
  463. package/dist/chunk-LOIMBRDE.js.map +0 -1
  464. package/dist/chunk-LTCGGW2D.js +0 -14
  465. package/dist/chunk-LTCGGW2D.js.map +0 -1
  466. package/dist/chunk-NZLQTHS5.js.map +0 -1
  467. package/dist/chunk-OC5OXUQ4.js.map +0 -1
  468. package/dist/chunk-PVPWZSSI.js.map +0 -1
  469. package/dist/chunk-SPI27QT6.js.map +0 -1
  470. package/dist/chunk-STGWEHYR.js.map +0 -1
  471. package/dist/chunk-TP4FZJIZ.js.map +0 -1
  472. package/dist/chunk-ULYOGL6R.js.map +0 -1
  473. package/dist/chunk-UWB5LMWY.js.map +0 -1
  474. package/dist/chunk-VBVG2M5G.js.map +0 -1
  475. package/dist/chunk-VDX363PS.js.map +0 -1
  476. package/dist/chunk-WCLICCGB.js.map +0 -1
  477. package/dist/chunk-X6GF3FX2.js +0 -26
  478. package/dist/chunk-X6GF3FX2.js.map +0 -1
  479. package/dist/chunk-XXVWLXSG.js.map +0 -1
  480. package/dist/chunk-Y7R2XJ5Q.js.map +0 -1
  481. package/dist/chunk-ZAIM4TUE.js.map +0 -1
  482. package/dist/engine-72LSIWQP.js +0 -23
  483. /package/dist/{contradiction-review-WIUBAR52.js.map → capsule-cli.js.map} +0 -0
  484. /package/dist/{engine-72LSIWQP.js.map → capsule-crypto-5CYAGVC5.js.map} +0 -0
  485. /package/dist/{chunk-TMYO7B5P.js.map → chunk-47WOM4YW.js.map} +0 -0
  486. /package/dist/{chunk-DG6YMRDC.js.map → chunk-B2TL6GA2.js.map} +0 -0
  487. /package/dist/{chunk-AYXIPSZO.js.map → chunk-CRU27Q4J.js.map} +0 -0
  488. /package/dist/{chunk-RBBWYEFJ.js.map → chunk-G2WADRQ3.js.map} +0 -0
  489. /package/dist/{chunk-NBVAS5MT.js.map → chunk-V7TEH5I2.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/connectors/live/state-store.ts","../src/connectors/live/framework.ts"],"sourcesContent":["/**\n * @remnic/core — Live Connectors State Store (issue #683 PR 1/N)\n *\n * Persists per-connector cursor + sync metadata to\n * `<memoryDir>/state/connectors/<id>.json`\n *\n * Reasons this lives next to memory data, not in user config:\n * - cursors are *operational* state that should travel with the memory\n * directory when a user moves it across machines;\n * - it keeps memory + ingest provenance co-located so tooling that backs up\n * the memory directory captures cursor state too.\n *\n * Atomic-write contract (CLAUDE.md gotcha #54):\n * - We NEVER `rmSync(target)` before `renameSync(tmp, target)`.\n * - Writes go to a sibling tmp file and `rename()` swaps it in.\n * - On error, the tmp file is best-effort cleaned up; the previous good\n * state file is left untouched.\n *\n * Privacy: cursors are opaque connector-defined strings. We do not log them\n * and do not surface them through user-visible APIs. Document content NEVER\n * touches this module.\n */\n\nimport { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\n\nimport { expandTildePath } from \"../../utils/path.js\";\n\nimport {\n isValidConnectorId,\n type ConnectorCursor,\n} from \"./framework.js\";\n\n/**\n * Status of the most recent sync attempt for a connector.\n *\n * `\"never\"` is distinct from `\"success\"` so callers can detect\n * \"registered but never run\" without inspecting timestamps. Per CLAUDE.md\n * gotcha #34, we deliberately distinguish empty/unknown from failure states.\n */\nexport type ConnectorSyncStatus = \"success\" | \"error\" | \"never\";\n\n/**\n * Persisted per-connector state.\n *\n * Stored as pretty-printed JSON for human inspection — the file is small\n * (one record per connector) and operators may need to debug stuck cursors\n * by hand.\n */\nexport interface ConnectorState {\n /** Connector id. Matches the filename stem. */\n readonly id: string;\n /** Last persisted cursor, or `null` if the connector has never synced. */\n readonly cursor: ConnectorCursor | null;\n /** ISO 8601 timestamp of the last completed sync attempt, or `null`. */\n readonly lastSyncAt: string | null;\n /** Status of the last completed sync attempt. */\n readonly lastSyncStatus: ConnectorSyncStatus;\n /** Optional error message from the last failed sync. Truncated to 1 KB. */\n readonly lastSyncError?: string;\n /** Cumulative count of documents successfully imported across all syncs. */\n readonly totalDocsImported: number;\n /** ISO 8601 timestamp of when this state record was last written. */\n readonly updatedAt: string;\n}\n\nconst STATE_DIR_NAME = \"state\";\nconst CONNECTORS_DIR_NAME = \"connectors\";\nconst MAX_ERROR_LENGTH = 1024;\nconst VALID_SYNC_STATUSES: ReadonlySet<ConnectorSyncStatus> = new Set([\n \"success\",\n \"error\",\n \"never\",\n]);\n\n/**\n * Internal error thrown when a state file's JSON is unparseable or its shape\n * doesn't match `ConnectorState`. Used by `listConnectorStates` to distinguish\n * \"skip this corrupt file\" cases from genuine I/O failures (`EACCES`, `EIO`)\n * that the caller must see.\n */\nclass ConnectorStateCorruptionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ConnectorStateCorruptionError\";\n }\n}\n\n/**\n * Resolve `<memoryDir>/state/connectors/`, expanding `~` per CLAUDE.md #17.\n */\nfunction resolveConnectorsDir(memoryDir: string): string {\n if (typeof memoryDir !== \"string\" || memoryDir.length === 0) {\n throw new TypeError(\"memoryDir must be a non-empty string\");\n }\n return path.join(expandTildePath(memoryDir), STATE_DIR_NAME, CONNECTORS_DIR_NAME);\n}\n\n/**\n * Resolve the state file path for a single connector. Throws on invalid id\n * to prevent path traversal via crafted ids.\n */\nfunction resolveConnectorStatePath(memoryDir: string, id: string): string {\n if (!isValidConnectorId(id)) {\n throw new TypeError(\n `invalid connector id ${JSON.stringify(id)} — must match /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/`,\n );\n }\n return path.join(resolveConnectorsDir(memoryDir), `${id}.json`);\n}\n\n/**\n * Type guard for parsed state records. Validates the on-disk shape so a\n * corrupted/edited file produces a clear error rather than crashing later.\n *\n * Per CLAUDE.md gotcha #18, JSON.parse('null') yields `null` which would\n * pass a naive truthy check. We explicitly require an object.\n */\nfunction isConnectorStateShape(value: unknown): value is ConnectorState {\n if (typeof value !== \"object\" || value === null) return false;\n const v = value as Record<string, unknown>;\n if (typeof v.id !== \"string\") return false;\n if (typeof v.lastSyncStatus !== \"string\") return false;\n if (![\"success\", \"error\", \"never\"].includes(v.lastSyncStatus)) return false;\n // totalDocsImported is a cumulative count — fractional values would corrupt\n // metrics on later increments. Mirror the boundary check in writeConnectorState.\n if (typeof v.totalDocsImported !== \"number\" || !Number.isInteger(v.totalDocsImported)) return false;\n if (v.totalDocsImported < 0) return false;\n if (typeof v.updatedAt !== \"string\") return false;\n if (v.lastSyncAt !== null && typeof v.lastSyncAt !== \"string\") return false;\n if (v.cursor !== null) {\n if (typeof v.cursor !== \"object\" || v.cursor === null) return false;\n const c = v.cursor as Record<string, unknown>;\n if (typeof c.kind !== \"string\" || typeof c.value !== \"string\" || typeof c.updatedAt !== \"string\") {\n return false;\n }\n }\n if (v.lastSyncError !== undefined && typeof v.lastSyncError !== \"string\") return false;\n return true;\n}\n\n/**\n * Reject any path component along `<memoryDir>/state/connectors/<id>.json`\n * that is a symlink. Without this guard, a symlink in any of those\n * components would let `fs.readFile` escape the memory root and consume an\n * arbitrary outside file as cursor state — silently poisoning sync state and\n * violating the project-wide rule against symlink traversal.\n *\n * `lstat` is used (not `stat`) so we observe the link itself rather than its\n * target. Missing components are tolerated — the caller's `readFile` /\n * `mkdir` will surface ENOENT in its normal way.\n *\n * (PR #724 review.)\n */\nasync function assertNoSymlinkOnPath(memoryDir: string, filePath: string): Promise<void> {\n const expandedRoot = expandTildePath(memoryDir);\n // Normalize so `..` segments can't bypass the prefix check below.\n const root = path.resolve(expandedRoot);\n const target = path.resolve(filePath);\n const rel = path.relative(root, target);\n // path.relative() yields a \"../...\" prefix when target escapes root.\n if (rel.startsWith(\"..\") || path.isAbsolute(rel)) {\n throw new Error(\n `connector state path ${target} escapes memory root ${root}`,\n );\n }\n // Walk every component from root to target (inclusive) and lstat each.\n const segments = rel.length === 0 ? [] : rel.split(path.sep);\n let current = root;\n const componentsToCheck = [current];\n for (const seg of segments) {\n current = path.join(current, seg);\n componentsToCheck.push(current);\n }\n for (const component of componentsToCheck) {\n let stat: import(\"node:fs\").Stats;\n try {\n stat = await fs.lstat(component);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n // Not yet created — that's fine; caller's readFile/mkdir handles it.\n continue;\n }\n throw err;\n }\n if (stat.isSymbolicLink()) {\n throw new Error(\n `connector state path component ${component} is a symlink; refusing to follow`,\n );\n }\n }\n}\n\n/**\n * Read the persisted state for a single connector.\n *\n * Returns `null` if the file does not exist (ENOENT). Throws on any other\n * I/O error or on shape mismatch — operators should see corruption loudly.\n *\n * Rejects symlinks anywhere on the path so a planted symlink can't redirect\n * reads outside the memory root. (PR #724 review.)\n */\nexport async function readConnectorState(\n memoryDir: string,\n id: string,\n): Promise<ConnectorState | null> {\n const filePath = resolveConnectorStatePath(memoryDir, id);\n await assertNoSymlinkOnPath(memoryDir, filePath);\n let raw: string;\n try {\n raw = await fs.readFile(filePath, \"utf-8\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return null;\n throw err;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n throw new ConnectorStateCorruptionError(\n `connector state at ${filePath} is not valid JSON: ${(err as Error).message}`,\n );\n }\n if (!isConnectorStateShape(parsed)) {\n throw new ConnectorStateCorruptionError(\n `connector state at ${filePath} does not match ConnectorState shape`,\n );\n }\n if (parsed.id !== id) {\n throw new ConnectorStateCorruptionError(\n `connector state at ${filePath} has mismatched id ${JSON.stringify(parsed.id)}; expected ${JSON.stringify(id)}`,\n );\n }\n return parsed;\n}\n\n/**\n * Write state atomically: create-tmp + rename. Never destroys the previous\n * file before the new one is in place — see CLAUDE.md gotcha #54.\n *\n * We accept `Omit<ConnectorState, \"updatedAt\">` and stamp `updatedAt`\n * ourselves so callers can't accidentally persist a stale timestamp.\n */\nexport async function writeConnectorState(\n memoryDir: string,\n id: string,\n state: Omit<ConnectorState, \"updatedAt\">,\n): Promise<ConnectorState> {\n if (!isValidConnectorId(id)) {\n throw new TypeError(\n `invalid connector id ${JSON.stringify(id)} — must match /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/`,\n );\n }\n if (state.id !== id) {\n throw new Error(\n `writeConnectorState(): state.id ${JSON.stringify(state.id)} does not match id argument ${JSON.stringify(id)}`,\n );\n }\n // Full boundary validation. Persisting an out-of-shape record would brick\n // the connector's cursor file: subsequent `readConnectorState` calls would\n // throw `ConnectorStateCorruptionError` until manual repair. JS callers\n // bypassing TS types must be rejected here, not later. (PR #724 review.)\n if (!VALID_SYNC_STATUSES.has(state.lastSyncStatus as ConnectorSyncStatus)) {\n throw new Error(\n `writeConnectorState(): lastSyncStatus must be one of ${[...VALID_SYNC_STATUSES].join(\", \")}, got ${JSON.stringify(state.lastSyncStatus)}`,\n );\n }\n if (state.lastSyncAt !== null && typeof state.lastSyncAt !== \"string\") {\n throw new Error(\n `writeConnectorState(): lastSyncAt must be a string or null, got ${typeof state.lastSyncAt}`,\n );\n }\n if (state.cursor !== null) {\n if (typeof state.cursor !== \"object\") {\n throw new Error(`writeConnectorState(): cursor must be an object or null`);\n }\n if (\n typeof state.cursor.kind !== \"string\" ||\n typeof state.cursor.value !== \"string\" ||\n typeof state.cursor.updatedAt !== \"string\"\n ) {\n throw new Error(\n `writeConnectorState(): cursor must have string kind, value, and updatedAt`,\n );\n }\n }\n if (\n typeof state.totalDocsImported !== \"number\" ||\n !Number.isInteger(state.totalDocsImported) ||\n state.totalDocsImported < 0\n ) {\n throw new Error(\n `writeConnectorState(): totalDocsImported must be a non-negative integer`,\n );\n }\n if (state.lastSyncError !== undefined && typeof state.lastSyncError !== \"string\") {\n throw new Error(`writeConnectorState(): lastSyncError must be a string when provided`);\n }\n const truncatedError =\n state.lastSyncError !== undefined && state.lastSyncError.length > MAX_ERROR_LENGTH\n ? state.lastSyncError.slice(0, MAX_ERROR_LENGTH)\n : state.lastSyncError;\n\n const finalState: ConnectorState = {\n id: state.id,\n cursor: state.cursor,\n lastSyncAt: state.lastSyncAt,\n lastSyncStatus: state.lastSyncStatus,\n ...(truncatedError !== undefined ? { lastSyncError: truncatedError } : {}),\n totalDocsImported: state.totalDocsImported,\n updatedAt: new Date().toISOString(),\n };\n\n const dir = resolveConnectorsDir(memoryDir);\n const targetPath = path.join(dir, `${id}.json`);\n // Reject planted symlinks before mkdir/write so a redirected target can't\n // overwrite an arbitrary file outside the memory root. (PR #724 review.)\n await assertNoSymlinkOnPath(memoryDir, targetPath);\n await fs.mkdir(dir, { recursive: true });\n const tmpPath = `${targetPath}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n\n const body = `${JSON.stringify(finalState, null, 2)}\\n`;\n try {\n await fs.writeFile(tmpPath, body, { encoding: \"utf-8\", mode: 0o600 });\n await fs.rename(tmpPath, targetPath);\n } catch (err) {\n // Best-effort cleanup of the tmp file. Never touch `targetPath` — the\n // previous good state must remain readable on failure.\n try {\n await fs.unlink(tmpPath);\n } catch {\n // ignore\n }\n throw err;\n }\n return finalState;\n}\n\n/**\n * Enumerate every persisted connector state. Returns an empty array when\n * the directory does not exist yet (clean install, no syncs ever run).\n *\n * Files that do not match the `<id>.json` naming rule are skipped — this\n * keeps stray editor backups (`.json~`, `.swp`) from breaking enumeration.\n *\n * Corruption (unparseable JSON, shape mismatch, id mismatch) is also\n * skipped so one bad file doesn't take down the listing. Operators\n * inspecting `state/connectors/` can still see the offending file by hand.\n *\n * **Genuine I/O failures (`EACCES`, `EIO`, etc.) are NOT swallowed** —\n * silently returning an incomplete state set would make active connectors\n * appear missing and trigger duplicate ingestion on the next scheduler tick.\n * (PR #724 review.)\n */\nexport async function listConnectorStates(memoryDir: string): Promise<ConnectorState[]> {\n const dir = resolveConnectorsDir(memoryDir);\n // Refuse to enumerate through a symlinked state directory — a planted\n // symlink at <memoryDir>/state or <memoryDir>/state/connectors would\n // otherwise let reads escape the memory root. (PR #724 review.)\n await assertNoSymlinkOnPath(memoryDir, dir);\n let entries: string[];\n try {\n entries = await fs.readdir(dir);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw err;\n }\n const out: ConnectorState[] = [];\n for (const entry of entries) {\n if (!entry.endsWith(\".json\")) continue;\n const id = entry.slice(0, -\".json\".length);\n if (!isValidConnectorId(id)) continue;\n try {\n const state = await readConnectorState(memoryDir, id);\n if (state !== null) out.push(state);\n } catch (err) {\n if (err instanceof ConnectorStateCorruptionError) {\n // Skip corrupt files; preserve availability of the rest.\n continue;\n }\n // Anything else (EACCES, EIO, ENOTDIR, ...) is a real operational\n // failure. Fail loudly so the scheduler / CLI can surface it.\n throw err;\n }\n }\n out.sort((a, b) => a.id.localeCompare(b.id));\n return out;\n}\n\n/**\n * Test-only helper: resolve where a given connector's state lives. Exported\n * so tests can assert the on-disk layout without duplicating the path math.\n * Not part of the stable public API.\n *\n * @internal\n */\nexport function _connectorStatePathForTest(memoryDir: string, id: string): string {\n return resolveConnectorStatePath(memoryDir, id);\n}\n","/**\n * @remnic/core — Live Connectors Framework (issue #683 PR 1/N)\n *\n * Defines the contract that every \"live\" connector (Drive, Notion, Gmail,\n * GitHub, ...) must satisfy. A live connector is **continuous**: it runs on a\n * schedule, persists a cursor to disk, and ingests *new* documents since the\n * last sync. This is distinct from one-shot importers in\n * `packages/remnic-core/src/importers/` which transform an entire export file\n * in a single pass.\n *\n * This module is intentionally pure types + interfaces. No I/O. No schedule\n * wiring. Concrete connectors (PRs 2–5), the maintenance scheduler hookup\n * (separate PR), and the CLI surface (PR 6) are deferred.\n *\n * Naming caveat: `packages/remnic-core/src/connectors/` is already scoped to\n * the Codex marketplace integration. The live-connector framework lives under\n * the `live/` subdirectory to avoid collision. Do not import Codex symbols\n * from here, and do not import live-connector symbols from the Codex code.\n */\n\n/**\n * Free-form connector configuration. Validated by each connector's\n * `validateConfig` implementation. Stored alongside the cursor in the state\n * store. MUST be JSON-serializable: no functions, no class instances, no\n * circular references.\n *\n * Connectors MUST NOT persist secrets here — credentials belong in OS keychain\n * / OAuth token storage (PR 2 design).\n */\nexport type ConnectorConfig = Record<string, unknown>;\n\n/**\n * Opaque cursor describing \"where the last sync left off\". Each connector\n * defines what `kind` and `value` mean (e.g. Drive: `{kind: \"pageToken\",\n * value: \"...\"}`, Gmail: `{kind: \"historyId\", value: \"...\"}`). The orchestrator\n * treats it as opaque and only round-trips it through the state store.\n *\n * `updatedAt` is an ISO 8601 timestamp set by the framework when the cursor is\n * written. It is informational — connectors MUST NOT use it to decide\n * monotonicity. They own the `value` semantics.\n */\nexport interface ConnectorCursor {\n /** Connector-defined cursor kind (e.g. `\"pageToken\"`, `\"historyId\"`, `\"sinceTs\"`). */\n readonly kind: string;\n /** Connector-defined opaque cursor value. */\n readonly value: string;\n /** ISO 8601 timestamp of when this cursor was last written. */\n readonly updatedAt: string;\n}\n\n/**\n * Provenance for a connector-ingested document. Required so downstream recall\n * can attribute facts back to their origin and avoid re-ingesting on the next\n * incremental pass.\n */\nexport interface ConnectorDocumentSource {\n /** Stable connector id (matches `LiveConnector.id`). */\n readonly connector: string;\n /** Source-system identifier (Drive file id, Notion page id, Gmail msg id, ...). */\n readonly externalId: string;\n /** Optional source-system revision/version (etag, page version, history id). */\n readonly externalRevision?: string;\n /** Optional canonical URL pointing back at the source document. */\n readonly externalUrl?: string;\n /** ISO 8601 timestamp of when the connector fetched this document. */\n readonly fetchedAt: string;\n}\n\n/**\n * A single document yielded by an incremental sync. Connectors are responsible\n * for chunking large source documents themselves if needed; the orchestrator\n * ingests `content` as a unit.\n */\nexport interface ConnectorDocument {\n /** Connector-local stable id for this document. SHOULD match `source.externalId`. */\n readonly id: string;\n /** Optional human-readable title. */\n readonly title?: string;\n /** Body content. Plaintext or Markdown — connectors document their format. */\n readonly content: string;\n /** Provenance. Required. */\n readonly source: ConnectorDocumentSource;\n}\n\n/**\n * Arguments passed to `syncIncremental`. The framework owns cursor/config\n * lifecycle; connectors only read these and return the next cursor.\n */\nexport interface SyncIncrementalArgs {\n /** Last persisted cursor, or `null` on the first ever sync. */\n readonly cursor: ConnectorCursor | null;\n /** Validated connector config (already passed through `validateConfig`). */\n readonly config: ConnectorConfig;\n /** Optional abort signal. Connectors SHOULD honor it for cooperative cancellation. */\n readonly abortSignal?: AbortSignal;\n}\n\n/**\n * Result of a single incremental sync pass.\n *\n * `newDocs` MAY be empty (no new documents since the last cursor). `nextCursor`\n * MUST always be returned — even on no-op syncs the framework persists it so\n * `updatedAt` reflects the most recent attempt.\n */\nexport interface SyncIncrementalResult {\n readonly newDocs: ConnectorDocument[];\n readonly nextCursor: ConnectorCursor;\n}\n\n/**\n * The contract every live connector implements.\n *\n * Connectors MUST be:\n * - **Idempotent**: re-running with the same cursor MUST NOT duplicate\n * documents. The `source.externalId` + `source.externalRevision` pair is\n * used downstream for dedup.\n * - **Read-only on the source**: live connectors never mutate the upstream\n * system (no marking emails read, no editing Notion pages).\n * - **Cancellable**: long-running syncs SHOULD periodically check\n * `abortSignal.aborted` and bail cleanly.\n * - **Privacy-aware**: connectors MUST NOT log document content. Logging\n * metadata (counts, ids, timings) is fine.\n */\nexport interface LiveConnector {\n /**\n * Stable connector id. MUST match `CONNECTOR_ID_PATTERN` — lowercase\n * alphanumeric plus dash, 1–64 chars, must start AND end with alphanumeric\n * (no leading or trailing dash). The registry enforces this.\n */\n readonly id: string;\n /** Short human-readable name shown in CLI / status output. */\n readonly displayName: string;\n /** Optional longer description. */\n readonly description?: string;\n\n /**\n * Validate raw user-supplied config. MUST throw on malformed input — never\n * silently default. The returned object is what gets persisted and passed\n * back to `syncIncremental`. Connectors SHOULD strip unknown fields.\n */\n validateConfig(raw: unknown): ConnectorConfig;\n\n /**\n * Run one incremental sync pass. See `SyncIncrementalArgs` /\n * `SyncIncrementalResult` for the contract.\n */\n syncIncremental(args: SyncIncrementalArgs): Promise<SyncIncrementalResult>;\n}\n\n/**\n * Regex enforcing the connector-id naming rule. Exported so connectors and\n * tests can validate ids consistently with the registry.\n *\n * Rule: lowercase alphanumeric + dash, 1..64 chars, must start AND end with\n * alphanumeric (no leading or trailing dash). Single-char ids are allowed.\n */\nexport const CONNECTOR_ID_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;\n\n/**\n * Returns `true` if `id` is a syntactically valid connector id.\n */\nexport function isValidConnectorId(id: unknown): id is string {\n return typeof id === \"string\" && CONNECTOR_ID_PATTERN.test(id);\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,329 @@
1
+ // src/capsule-cli.ts
2
+ import path from "path";
3
+ function parseCapsuleOutputFormat(raw) {
4
+ if (raw === void 0 || raw === null) return "text";
5
+ if (typeof raw !== "string" || raw.trim() === "") {
6
+ throw new Error(
7
+ `--format expects one of text, markdown, json; got ${JSON.stringify(raw)}`
8
+ );
9
+ }
10
+ const v = raw.trim();
11
+ if (v !== "text" && v !== "markdown" && v !== "json") {
12
+ throw new Error(
13
+ `--format expects one of text, markdown, json; got ${JSON.stringify(raw)}`
14
+ );
15
+ }
16
+ return v;
17
+ }
18
+ function parseCapsuleImportMode(raw) {
19
+ if (raw === void 0 || raw === null) return "skip";
20
+ if (typeof raw !== "string" || raw.trim() === "") {
21
+ throw new Error(
22
+ `--mode expects one of skip, overwrite, fork; got ${JSON.stringify(raw)}`
23
+ );
24
+ }
25
+ const v = raw.trim();
26
+ if (v !== "skip" && v !== "overwrite" && v !== "fork") {
27
+ throw new Error(
28
+ `--mode expects one of skip, overwrite, fork; got ${JSON.stringify(raw)}`
29
+ );
30
+ }
31
+ return v;
32
+ }
33
+ function parseCapsuleConflictMode(raw) {
34
+ if (raw === void 0 || raw === null) return "skip-conflicts";
35
+ if (typeof raw !== "string" || raw.trim() === "") {
36
+ throw new Error(
37
+ `--conflict-mode expects one of skip-conflicts, prefer-source, prefer-local; got ${JSON.stringify(raw)}`
38
+ );
39
+ }
40
+ const v = raw.trim();
41
+ if (v !== "skip-conflicts" && v !== "prefer-source" && v !== "prefer-local") {
42
+ throw new Error(
43
+ `--conflict-mode expects one of skip-conflicts, prefer-source, prefer-local; got ${JSON.stringify(raw)}`
44
+ );
45
+ }
46
+ return v;
47
+ }
48
+ var ISO_8601_RE = /^\d{4}-\d{2}-\d{2}(?:[Tt]\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:[Zz]|[+-]\d{2}:?\d{2}))?$/;
49
+ function parseCapsuleSince(raw) {
50
+ if (raw === void 0 || raw === null) return void 0;
51
+ if (typeof raw !== "string") {
52
+ throw new Error(
53
+ `--since expects an ISO 8601 timestamp; got ${JSON.stringify(raw)}`
54
+ );
55
+ }
56
+ if (raw.trim() === "") {
57
+ throw new Error(`--since expects an ISO 8601 timestamp; received empty string`);
58
+ }
59
+ if (!ISO_8601_RE.test(raw)) {
60
+ throw new Error(
61
+ `--since is not a valid ISO 8601 timestamp: ${raw}. Accepted forms: YYYY-MM-DD, YYYY-MM-DDTHH:MM:SSZ, YYYY-MM-DDTHH:MM:SS\xB1HH:MM`
62
+ );
63
+ }
64
+ const ms = Date.parse(raw);
65
+ if (!Number.isFinite(ms)) {
66
+ throw new Error(`--since is not a valid ISO 8601 timestamp: ${raw}`);
67
+ }
68
+ const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(raw);
69
+ if (m) {
70
+ const offsetMatch = /([+-])(\d{2}):?(\d{2})$/.exec(raw);
71
+ let displayMs = ms;
72
+ if (offsetMatch) {
73
+ const sign = offsetMatch[1] === "-" ? -1 : 1;
74
+ const offsetMin = sign * (Number(offsetMatch[2]) * 60 + Number(offsetMatch[3]));
75
+ displayMs = ms + offsetMin * 6e4;
76
+ }
77
+ const dd = new Date(displayMs);
78
+ if (dd.getUTCFullYear() !== Number(m[1]) || dd.getUTCMonth() + 1 !== Number(m[2]) || dd.getUTCDate() !== Number(m[3])) {
79
+ throw new Error(
80
+ `--since: calendar overflow \u2014 ${raw} normalises to a different calendar date`
81
+ );
82
+ }
83
+ }
84
+ return raw;
85
+ }
86
+ function parseCapsuleIncludeKinds(raw) {
87
+ if (raw === void 0 || raw === null) return void 0;
88
+ if (typeof raw !== "string") {
89
+ throw new Error(
90
+ `--include-kinds expects a comma-separated list of directory names; got ${JSON.stringify(raw)}`
91
+ );
92
+ }
93
+ if (raw.trim() === "") {
94
+ throw new Error(
95
+ `--include-kinds expects at least one non-empty kind name`
96
+ );
97
+ }
98
+ const parts = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
99
+ if (parts.length === 0) {
100
+ throw new Error(`--include-kinds expects at least one non-empty kind name`);
101
+ }
102
+ for (const p of parts) {
103
+ if (p.includes("/") || p.includes("\\")) {
104
+ throw new Error(
105
+ `--include-kinds entries must be top-level directory names (no path separators): ${p}`
106
+ );
107
+ }
108
+ }
109
+ return [...new Set(parts)];
110
+ }
111
+ function parseCapsulePeers(raw) {
112
+ if (raw === void 0 || raw === null) return void 0;
113
+ if (typeof raw !== "string") {
114
+ throw new Error(
115
+ `--peers expects a comma-separated list of peer ids; got ${JSON.stringify(raw)}`
116
+ );
117
+ }
118
+ if (raw.trim() === "") {
119
+ throw new Error(`--peers expects at least one non-empty peer id`);
120
+ }
121
+ const parts = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
122
+ if (parts.length === 0) {
123
+ throw new Error(`--peers expects at least one non-empty peer id`);
124
+ }
125
+ for (const p of parts) {
126
+ if (p.includes("/") || p.includes("\\") || p === "." || p === "..") {
127
+ throw new Error(
128
+ `--peers entries must be plain id tokens (no path separators): ${p}`
129
+ );
130
+ }
131
+ }
132
+ return [...new Set(parts)];
133
+ }
134
+ function parseCapsuleExportOptions(nameArg, opts) {
135
+ if (typeof nameArg !== "string" || nameArg.trim() === "") {
136
+ throw new Error(
137
+ `capsule export: <name> is required (e.g. "remnic capsule export my-capsule")`
138
+ );
139
+ }
140
+ const name = nameArg.trim();
141
+ const out = typeof opts.out === "string" && opts.out.trim() !== "" ? opts.out.trim() : void 0;
142
+ const since = parseCapsuleSince(opts.since);
143
+ const includeKinds = parseCapsuleIncludeKinds(opts.includeKinds);
144
+ const peers = parseCapsulePeers(opts.peers);
145
+ return { name, out, since, includeKinds, peers };
146
+ }
147
+ function parseCapsuleImportOptions(archiveArg, opts) {
148
+ if (typeof archiveArg !== "string" || archiveArg.trim() === "") {
149
+ throw new Error(
150
+ `capsule import: <archive> path is required (e.g. "remnic capsule import /path/to/my-capsule.capsule.json.gz")`
151
+ );
152
+ }
153
+ const archive = archiveArg.trim();
154
+ const mode = parseCapsuleImportMode(opts.mode);
155
+ return { archive, mode };
156
+ }
157
+ function parseCapsuleMergeOptions(archiveArg, opts) {
158
+ if (typeof archiveArg !== "string" || archiveArg.trim() === "") {
159
+ throw new Error(
160
+ `capsule merge: <archive> path is required (e.g. "remnic capsule merge /path/to/my-capsule.capsule.json.gz")`
161
+ );
162
+ }
163
+ const archive = archiveArg.trim();
164
+ const conflictMode = parseCapsuleConflictMode(opts.conflictMode);
165
+ return { archive, conflictMode };
166
+ }
167
+ function parseCapsuleListOptions(opts, defaultCapsulesDir2) {
168
+ const format = parseCapsuleOutputFormat(opts.format);
169
+ const rawDir = typeof opts.dir === "string" && opts.dir.trim() !== "" ? opts.dir.trim() : void 0;
170
+ const capsulesDir = rawDir ?? defaultCapsulesDir2;
171
+ return { format, capsulesDir };
172
+ }
173
+ function parseCapsuleInspectOptions(archiveArg, opts) {
174
+ if (typeof archiveArg !== "string" || archiveArg.trim() === "") {
175
+ throw new Error(
176
+ `capsule inspect: <archive> path is required (e.g. "remnic capsule inspect my-capsule.capsule.json.gz")`
177
+ );
178
+ }
179
+ const archive = archiveArg.trim();
180
+ const format = parseCapsuleOutputFormat(opts.format);
181
+ return { archive, format };
182
+ }
183
+ function defaultCapsulesDir(memoryDir) {
184
+ return path.join(memoryDir, ".capsules");
185
+ }
186
+ function escapeMarkdownCell(v) {
187
+ return v.replace(/\\/g, "\\\\").replace(/\|/g, "\\|");
188
+ }
189
+ function renderCapsuleList(entries, format) {
190
+ if (format === "json") {
191
+ return JSON.stringify({ capsules: entries }, null, 2);
192
+ }
193
+ if (entries.length === 0) {
194
+ if (format === "markdown") return "_No capsule archives found._\n";
195
+ return "No capsule archives found.\n";
196
+ }
197
+ if (format === "markdown") {
198
+ const rows = entries.map((e) => {
199
+ const id = escapeMarkdownCell(e.id);
200
+ const date = escapeMarkdownCell(e.createdAt?.slice(0, 10) ?? "\u2014");
201
+ const ver = escapeMarkdownCell(e.pluginVersion ?? "\u2014");
202
+ const files = e.fileCount !== null ? String(e.fileCount) : "\u2014";
203
+ const desc = escapeMarkdownCell(
204
+ e.description != null && e.description.trim() !== "" ? e.description.trim() : "\u2014"
205
+ );
206
+ return `| \`${id}\` | ${date} | ${ver} | ${files} | ${desc} |`;
207
+ });
208
+ return [
209
+ "# Capsule archives",
210
+ "",
211
+ "| ID | Created | Version | Files | Description |",
212
+ "| -- | ------- | ------- | ----- | ----------- |",
213
+ ...rows,
214
+ ""
215
+ ].join("\n");
216
+ }
217
+ const lines = entries.map((e) => {
218
+ const date = e.createdAt?.slice(0, 10) ?? "\u2014";
219
+ const files = e.fileCount !== null ? `${e.fileCount} file${e.fileCount !== 1 ? "s" : ""}` : "? files";
220
+ const desc = e.description != null && e.description.trim() !== "" ? ` ${e.description.trim()}` : "";
221
+ return `${e.id} [${date}] [${files}]${desc}`;
222
+ });
223
+ return lines.join("\n") + "\n";
224
+ }
225
+ function renderCapsuleInspect(manifest, format) {
226
+ if (format === "json") {
227
+ return JSON.stringify(manifest, null, 2);
228
+ }
229
+ const {
230
+ capsuleId,
231
+ version,
232
+ schemaVersion,
233
+ createdAt,
234
+ pluginVersion,
235
+ fileCount,
236
+ includesTranscripts,
237
+ description,
238
+ parentCapsule,
239
+ retrievalPolicy,
240
+ includes,
241
+ topFiles
242
+ } = manifest;
243
+ if (format === "markdown") {
244
+ const policyLines = Object.entries(retrievalPolicy.tierWeights ?? {}).map(
245
+ ([k, v]) => ` - ${k}: ${v}`
246
+ );
247
+ const policyBlock = policyLines.length > 0 ? policyLines.join("\n") : " _(no tier weight overrides)_";
248
+ return [
249
+ `# Capsule: \`${capsuleId}\``,
250
+ "",
251
+ `**Version:** ${version} `,
252
+ `**Schema version:** ${schemaVersion} `,
253
+ `**Created:** ${createdAt ?? "\u2014"} `,
254
+ `**Plugin version:** ${pluginVersion ?? "\u2014"} `,
255
+ `**Files:** ${fileCount} `,
256
+ `**Includes transcripts:** ${includesTranscripts ? "yes" : "no"} `,
257
+ `**Parent capsule:** ${parentCapsule ?? "_none_"} `,
258
+ `**Description:** ${description && description.trim() !== "" ? description.trim() : "_none_"} `,
259
+ "",
260
+ "## Includes",
261
+ `- taxonomy: ${includes.taxonomy ? "yes" : "no"}`,
262
+ `- identityAnchors: ${includes.identityAnchors ? "yes" : "no"}`,
263
+ `- peerProfiles: ${includes.peerProfiles ? "yes" : "no"}`,
264
+ `- procedural: ${includes.procedural ? "yes" : "no"}`,
265
+ "",
266
+ "## Retrieval policy",
267
+ `- directAnswerEnabled: ${retrievalPolicy.directAnswerEnabled ? "yes" : "no"}`,
268
+ `- tierWeights:`,
269
+ policyBlock,
270
+ "",
271
+ ...topFiles.length > 0 ? [
272
+ `## Files (${fileCount} total, showing first ${topFiles.length})`,
273
+ ...topFiles.map((f) => `- \`${f}\``),
274
+ ""
275
+ ] : [`## Files (${fileCount} total)`, "_Empty capsule._", ""]
276
+ ].join("\n");
277
+ }
278
+ const lines = [
279
+ `Capsule: ${capsuleId}`,
280
+ ` version: ${version}`,
281
+ ` schema: ${schemaVersion}`,
282
+ ` created: ${createdAt ?? "\u2014"}`,
283
+ ` plugin: ${pluginVersion ?? "\u2014"}`,
284
+ ` files: ${fileCount}`,
285
+ ` transcripts: ${includesTranscripts ? "yes" : "no"}`,
286
+ ` parent: ${parentCapsule ?? "(none)"}`,
287
+ ` description: ${description && description.trim() !== "" ? description.trim() : "(none)"}`,
288
+ "",
289
+ ` includes.taxonomy: ${includes.taxonomy ? "yes" : "no"}`,
290
+ ` includes.identityAnchors: ${includes.identityAnchors ? "yes" : "no"}`,
291
+ ` includes.peerProfiles: ${includes.peerProfiles ? "yes" : "no"}`,
292
+ ` includes.procedural: ${includes.procedural ? "yes" : "no"}`,
293
+ "",
294
+ ` policy.directAnswer: ${retrievalPolicy.directAnswerEnabled ? "yes" : "no"}`
295
+ ];
296
+ const weights = Object.entries(retrievalPolicy.tierWeights ?? {});
297
+ if (weights.length > 0) {
298
+ for (const [k, v] of weights) {
299
+ lines.push(` policy.tierWeight[${k}]: ${v}`);
300
+ }
301
+ } else {
302
+ lines.push(` policy.tierWeights: (none)`);
303
+ }
304
+ if (topFiles.length > 0) {
305
+ lines.push("", ` files (first ${topFiles.length} of ${fileCount}):`);
306
+ for (const f of topFiles) {
307
+ lines.push(` ${f}`);
308
+ }
309
+ }
310
+ return lines.join("\n") + "\n";
311
+ }
312
+
313
+ export {
314
+ parseCapsuleOutputFormat,
315
+ parseCapsuleImportMode,
316
+ parseCapsuleConflictMode,
317
+ parseCapsuleSince,
318
+ parseCapsuleIncludeKinds,
319
+ parseCapsulePeers,
320
+ parseCapsuleExportOptions,
321
+ parseCapsuleImportOptions,
322
+ parseCapsuleMergeOptions,
323
+ parseCapsuleListOptions,
324
+ parseCapsuleInspectOptions,
325
+ defaultCapsulesDir,
326
+ renderCapsuleList,
327
+ renderCapsuleInspect
328
+ };
329
+ //# sourceMappingURL=chunk-74EMIVE4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/capsule-cli.ts"],"sourcesContent":["/**\n * Pure-function helpers for the `remnic capsule` CLI surface (issue #676 PR 6/6).\n *\n * All functions here are free of orchestrator / filesystem side-effects so\n * they can be unit-tested without booting the gateway (CLAUDE.md rules 14, 51).\n *\n * Responsibilities:\n * - Input validation + option parsing for every capsule sub-command flag.\n * - Rendering of `capsule list` and `capsule inspect` output in text /\n * markdown / json forms.\n *\n * The actual I/O (export, import, merge, directory listing, manifest read) is\n * wired in `cli.ts` because those operations need the orchestrator's config.\n */\n\nimport path from \"node:path\";\n\n// ---------------------------------------------------------------------------\n// Shared types\n// ---------------------------------------------------------------------------\n\nexport type CapsuleOutputFormat = \"text\" | \"markdown\" | \"json\";\n\n/**\n * Metadata entry returned by `capsule list` for a single archive file found\n * in the capsule store directory.\n */\nexport interface CapsuleListEntry {\n /** Capsule id extracted from the filename (slug before `.capsule.json.gz`). */\n id: string;\n /** Absolute path to the `.capsule.json.gz` archive. */\n archivePath: string;\n /** Absolute path to the sidecar `.manifest.json`, or null if missing. */\n manifestPath: string | null;\n /** `createdAt` ISO string from the sidecar manifest, or null if unreadable. */\n createdAt: string | null;\n /** `pluginVersion` from the sidecar manifest, or null. */\n pluginVersion: string | null;\n /** `files` array length from the sidecar manifest, or null. */\n fileCount: number | null;\n /** `capsule.description` from the sidecar manifest, or null. */\n description: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// Validation helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Validate and coerce the `--format` flag value.\n *\n * Rule 51: invalid values must throw with a listed-options error, not silently\n * fall back to a default.\n */\nexport function parseCapsuleOutputFormat(\n raw: unknown,\n): CapsuleOutputFormat {\n if (raw === undefined || raw === null) return \"text\";\n if (typeof raw !== \"string\" || raw.trim() === \"\") {\n throw new Error(\n `--format expects one of text, markdown, json; got ${JSON.stringify(raw)}`,\n );\n }\n const v = raw.trim() as CapsuleOutputFormat;\n if (v !== \"text\" && v !== \"markdown\" && v !== \"json\") {\n throw new Error(\n `--format expects one of text, markdown, json; got ${JSON.stringify(raw)}`,\n );\n }\n return v;\n}\n\n/**\n * Validate and coerce the `--mode` flag for `capsule import`.\n */\nexport function parseCapsuleImportMode(\n raw: unknown,\n): \"skip\" | \"overwrite\" | \"fork\" {\n if (raw === undefined || raw === null) return \"skip\";\n if (typeof raw !== \"string\" || raw.trim() === \"\") {\n throw new Error(\n `--mode expects one of skip, overwrite, fork; got ${JSON.stringify(raw)}`,\n );\n }\n const v = raw.trim();\n if (v !== \"skip\" && v !== \"overwrite\" && v !== \"fork\") {\n throw new Error(\n `--mode expects one of skip, overwrite, fork; got ${JSON.stringify(raw)}`,\n );\n }\n return v as \"skip\" | \"overwrite\" | \"fork\";\n}\n\n/**\n * Validate and coerce the `--conflict-mode` flag for `capsule merge`.\n */\nexport function parseCapsuleConflictMode(\n raw: unknown,\n): \"skip-conflicts\" | \"prefer-source\" | \"prefer-local\" {\n if (raw === undefined || raw === null) return \"skip-conflicts\";\n if (typeof raw !== \"string\" || raw.trim() === \"\") {\n throw new Error(\n `--conflict-mode expects one of skip-conflicts, prefer-source, prefer-local; got ${JSON.stringify(raw)}`,\n );\n }\n const v = raw.trim();\n if (v !== \"skip-conflicts\" && v !== \"prefer-source\" && v !== \"prefer-local\") {\n throw new Error(\n `--conflict-mode expects one of skip-conflicts, prefer-source, prefer-local; got ${JSON.stringify(raw)}`,\n );\n }\n return v as \"skip-conflicts\" | \"prefer-source\" | \"prefer-local\";\n}\n\n/**\n * Parse and validate the `--since` ISO-8601 string.\n *\n * Accepts date-only (`YYYY-MM-DD`) and date+time with explicit timezone\n * (`YYYY-MM-DDTHH:MM...Z` / `±HH:MM`). Rejects datetime without a timezone\n * designator (host-dependent interpretation, Rule 51).\n */\nconst ISO_8601_RE =\n /^\\d{4}-\\d{2}-\\d{2}(?:[Tt]\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d{1,9})?)?(?:[Zz]|[+-]\\d{2}:?\\d{2}))?$/;\n\nexport function parseCapsuleSince(raw: unknown): string | undefined {\n if (raw === undefined || raw === null) return undefined;\n if (typeof raw !== \"string\") {\n throw new Error(\n `--since expects an ISO 8601 timestamp; got ${JSON.stringify(raw)}`,\n );\n }\n if (raw.trim() === \"\") {\n throw new Error(`--since expects an ISO 8601 timestamp; received empty string`);\n }\n if (!ISO_8601_RE.test(raw)) {\n throw new Error(\n `--since is not a valid ISO 8601 timestamp: ${raw}. ` +\n `Accepted forms: YYYY-MM-DD, YYYY-MM-DDTHH:MM:SSZ, YYYY-MM-DDTHH:MM:SS±HH:MM`,\n );\n }\n const ms = Date.parse(raw);\n if (!Number.isFinite(ms)) {\n throw new Error(`--since is not a valid ISO 8601 timestamp: ${raw}`);\n }\n // Calendar overflow detection (same logic as capsule-export.ts parseSince).\n const m = /^(\\d{4})-(\\d{2})-(\\d{2})/.exec(raw);\n if (m) {\n const offsetMatch = /([+-])(\\d{2}):?(\\d{2})$/.exec(raw);\n let displayMs = ms;\n if (offsetMatch) {\n const sign = offsetMatch[1] === \"-\" ? -1 : 1;\n const offsetMin = sign * (Number(offsetMatch[2]) * 60 + Number(offsetMatch[3]));\n displayMs = ms + offsetMin * 60_000;\n }\n const dd = new Date(displayMs);\n if (\n dd.getUTCFullYear() !== Number(m[1]) ||\n dd.getUTCMonth() + 1 !== Number(m[2]) ||\n dd.getUTCDate() !== Number(m[3])\n ) {\n throw new Error(\n `--since: calendar overflow — ${raw} normalises to a different calendar date`,\n );\n }\n }\n return raw;\n}\n\n/**\n * Parse a comma-separated `--include-kinds` value into an array of non-empty\n * top-level directory names. Rejects values containing path separators.\n */\nexport function parseCapsuleIncludeKinds(raw: unknown): string[] | undefined {\n if (raw === undefined || raw === null) return undefined;\n if (typeof raw !== \"string\") {\n throw new Error(\n `--include-kinds expects a comma-separated list of directory names; got ${JSON.stringify(raw)}`,\n );\n }\n if (raw.trim() === \"\") {\n throw new Error(\n `--include-kinds expects at least one non-empty kind name`,\n );\n }\n const parts = raw\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n if (parts.length === 0) {\n throw new Error(`--include-kinds expects at least one non-empty kind name`);\n }\n for (const p of parts) {\n if (p.includes(\"/\") || p.includes(\"\\\\\")) {\n throw new Error(\n `--include-kinds entries must be top-level directory names (no path separators): ${p}`,\n );\n }\n }\n // Deduplicate while preserving order.\n return [...new Set(parts)];\n}\n\n/**\n * Parse a comma-separated `--peers` value into an array of peer ids.\n */\nexport function parseCapsulePeers(raw: unknown): string[] | undefined {\n if (raw === undefined || raw === null) return undefined;\n if (typeof raw !== \"string\") {\n throw new Error(\n `--peers expects a comma-separated list of peer ids; got ${JSON.stringify(raw)}`,\n );\n }\n if (raw.trim() === \"\") {\n throw new Error(`--peers expects at least one non-empty peer id`);\n }\n const parts = raw\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n if (parts.length === 0) {\n throw new Error(`--peers expects at least one non-empty peer id`);\n }\n for (const p of parts) {\n if (p.includes(\"/\") || p.includes(\"\\\\\") || p === \".\" || p === \"..\") {\n throw new Error(\n `--peers entries must be plain id tokens (no path separators): ${p}`,\n );\n }\n }\n return [...new Set(parts)];\n}\n\n// ---------------------------------------------------------------------------\n// Parsed option bags (returned by the parse helpers below and consumed by\n// cli.ts action handlers).\n// ---------------------------------------------------------------------------\n\nexport interface CapsuleExportOptions {\n name: string;\n out: string | undefined;\n since: string | undefined;\n includeKinds: string[] | undefined;\n peers: string[] | undefined;\n}\n\nexport interface CapsuleImportOptions {\n archive: string;\n mode: \"skip\" | \"overwrite\" | \"fork\";\n}\n\nexport interface CapsuleMergeOptions {\n archive: string;\n conflictMode: \"skip-conflicts\" | \"prefer-source\" | \"prefer-local\";\n}\n\nexport interface CapsuleListOptions {\n format: CapsuleOutputFormat;\n capsulesDir: string;\n}\n\nexport interface CapsuleInspectOptions {\n archive: string;\n format: CapsuleOutputFormat;\n}\n\n// ---------------------------------------------------------------------------\n// Option bag parsers (Rule 51: validate + throw on bad input, never silently\n// default to a value that hides user misconfiguration).\n// ---------------------------------------------------------------------------\n\nexport function parseCapsuleExportOptions(\n nameArg: unknown,\n opts: Record<string, unknown>,\n): CapsuleExportOptions {\n if (typeof nameArg !== \"string\" || nameArg.trim() === \"\") {\n throw new Error(\n `capsule export: <name> is required (e.g. \"remnic capsule export my-capsule\")`,\n );\n }\n const name = nameArg.trim();\n\n const out =\n typeof opts.out === \"string\" && opts.out.trim() !== \"\"\n ? opts.out.trim()\n : undefined;\n\n const since = parseCapsuleSince(opts.since);\n const includeKinds = parseCapsuleIncludeKinds(opts.includeKinds);\n const peers = parseCapsulePeers(opts.peers);\n\n return { name, out, since, includeKinds, peers };\n}\n\nexport function parseCapsuleImportOptions(\n archiveArg: unknown,\n opts: Record<string, unknown>,\n): CapsuleImportOptions {\n if (typeof archiveArg !== \"string\" || archiveArg.trim() === \"\") {\n throw new Error(\n `capsule import: <archive> path is required (e.g. \"remnic capsule import /path/to/my-capsule.capsule.json.gz\")`,\n );\n }\n const archive = archiveArg.trim();\n const mode = parseCapsuleImportMode(opts.mode);\n return { archive, mode };\n}\n\nexport function parseCapsuleMergeOptions(\n archiveArg: unknown,\n opts: Record<string, unknown>,\n): CapsuleMergeOptions {\n if (typeof archiveArg !== \"string\" || archiveArg.trim() === \"\") {\n throw new Error(\n `capsule merge: <archive> path is required (e.g. \"remnic capsule merge /path/to/my-capsule.capsule.json.gz\")`,\n );\n }\n const archive = archiveArg.trim();\n const conflictMode = parseCapsuleConflictMode(opts.conflictMode);\n return { archive, conflictMode };\n}\n\nexport function parseCapsuleListOptions(\n opts: Record<string, unknown>,\n defaultCapsulesDir: string,\n): CapsuleListOptions {\n const format = parseCapsuleOutputFormat(opts.format);\n const rawDir =\n typeof opts.dir === \"string\" && opts.dir.trim() !== \"\"\n ? opts.dir.trim()\n : undefined;\n const capsulesDir = rawDir ?? defaultCapsulesDir;\n return { format, capsulesDir };\n}\n\nexport function parseCapsuleInspectOptions(\n archiveArg: unknown,\n opts: Record<string, unknown>,\n): CapsuleInspectOptions {\n if (typeof archiveArg !== \"string\" || archiveArg.trim() === \"\") {\n throw new Error(\n `capsule inspect: <archive> path is required (e.g. \"remnic capsule inspect my-capsule.capsule.json.gz\")`,\n );\n }\n const archive = archiveArg.trim();\n const format = parseCapsuleOutputFormat(opts.format);\n return { archive, format };\n}\n\n// ---------------------------------------------------------------------------\n// Default capsules directory\n// ---------------------------------------------------------------------------\n\n/**\n * Return the default capsule store directory for a given memory root.\n * This mirrors the `outDir` default in `exportCapsule` (`<root>/.capsules`)\n * so that `capsule list` discovers archives written by `capsule export`\n * without extra configuration.\n *\n * For `capsule list`, the POSIX conventional path is:\n * `<memoryDir>/.capsules`\n *\n * Operators can override it with `--dir <path>` at runtime.\n */\nexport function defaultCapsulesDir(memoryDir: string): string {\n return path.join(memoryDir, \".capsules\");\n}\n\n// ---------------------------------------------------------------------------\n// Renderers\n// ---------------------------------------------------------------------------\n\nfunction escapeMarkdownCell(v: string): string {\n return v.replace(/\\\\/g, \"\\\\\\\\\").replace(/\\|/g, \"\\\\|\");\n}\n\n/**\n * Render the `capsule list` output.\n */\nexport function renderCapsuleList(\n entries: CapsuleListEntry[],\n format: CapsuleOutputFormat,\n): string {\n if (format === \"json\") {\n return JSON.stringify({ capsules: entries }, null, 2);\n }\n\n if (entries.length === 0) {\n if (format === \"markdown\") return \"_No capsule archives found._\\n\";\n return \"No capsule archives found.\\n\";\n }\n\n if (format === \"markdown\") {\n const rows = entries.map((e) => {\n const id = escapeMarkdownCell(e.id);\n const date = escapeMarkdownCell(e.createdAt?.slice(0, 10) ?? \"—\");\n const ver = escapeMarkdownCell(e.pluginVersion ?? \"—\");\n const files = e.fileCount !== null ? String(e.fileCount) : \"—\";\n const desc = escapeMarkdownCell(\n e.description != null && e.description.trim() !== \"\"\n ? e.description.trim()\n : \"—\",\n );\n return `| \\`${id}\\` | ${date} | ${ver} | ${files} | ${desc} |`;\n });\n return [\n \"# Capsule archives\",\n \"\",\n \"| ID | Created | Version | Files | Description |\",\n \"| -- | ------- | ------- | ----- | ----------- |\",\n ...rows,\n \"\",\n ].join(\"\\n\");\n }\n\n // text\n const lines = entries.map((e) => {\n const date = e.createdAt?.slice(0, 10) ?? \"—\";\n const files =\n e.fileCount !== null ? `${e.fileCount} file${e.fileCount !== 1 ? \"s\" : \"\"}` : \"? files\";\n const desc =\n e.description != null && e.description.trim() !== \"\"\n ? ` ${e.description.trim()}`\n : \"\";\n return `${e.id} [${date}] [${files}]${desc}`;\n });\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/**\n * Render the `capsule inspect` output from a manifest object.\n */\nexport function renderCapsuleInspect(\n manifest: CapsuleInspectData,\n format: CapsuleOutputFormat,\n): string {\n if (format === \"json\") {\n return JSON.stringify(manifest, null, 2);\n }\n\n const {\n capsuleId,\n version,\n schemaVersion,\n createdAt,\n pluginVersion,\n fileCount,\n includesTranscripts,\n description,\n parentCapsule,\n retrievalPolicy,\n includes,\n topFiles,\n } = manifest;\n\n if (format === \"markdown\") {\n const policyLines = Object.entries(retrievalPolicy.tierWeights ?? {}).map(\n ([k, v]) => ` - ${k}: ${v}`,\n );\n const policyBlock =\n policyLines.length > 0\n ? policyLines.join(\"\\n\")\n : \" _(no tier weight overrides)_\";\n\n return [\n `# Capsule: \\`${capsuleId}\\``,\n \"\",\n `**Version:** ${version} `,\n `**Schema version:** ${schemaVersion} `,\n `**Created:** ${createdAt ?? \"—\"} `,\n `**Plugin version:** ${pluginVersion ?? \"—\"} `,\n `**Files:** ${fileCount} `,\n `**Includes transcripts:** ${includesTranscripts ? \"yes\" : \"no\"} `,\n `**Parent capsule:** ${parentCapsule ?? \"_none_\"} `,\n `**Description:** ${description && description.trim() !== \"\" ? description.trim() : \"_none_\"} `,\n \"\",\n \"## Includes\",\n `- taxonomy: ${includes.taxonomy ? \"yes\" : \"no\"}`,\n `- identityAnchors: ${includes.identityAnchors ? \"yes\" : \"no\"}`,\n `- peerProfiles: ${includes.peerProfiles ? \"yes\" : \"no\"}`,\n `- procedural: ${includes.procedural ? \"yes\" : \"no\"}`,\n \"\",\n \"## Retrieval policy\",\n `- directAnswerEnabled: ${retrievalPolicy.directAnswerEnabled ? \"yes\" : \"no\"}`,\n `- tierWeights:`,\n policyBlock,\n \"\",\n ...(topFiles.length > 0\n ? [\n `## Files (${fileCount} total, showing first ${topFiles.length})`,\n ...topFiles.map((f) => `- \\`${f}\\``),\n \"\",\n ]\n : [`## Files (${fileCount} total)`, \"_Empty capsule._\", \"\"]),\n ].join(\"\\n\");\n }\n\n // text\n const lines: string[] = [\n `Capsule: ${capsuleId}`,\n ` version: ${version}`,\n ` schema: ${schemaVersion}`,\n ` created: ${createdAt ?? \"—\"}`,\n ` plugin: ${pluginVersion ?? \"—\"}`,\n ` files: ${fileCount}`,\n ` transcripts: ${includesTranscripts ? \"yes\" : \"no\"}`,\n ` parent: ${parentCapsule ?? \"(none)\"}`,\n ` description: ${description && description.trim() !== \"\" ? description.trim() : \"(none)\"}`,\n \"\",\n ` includes.taxonomy: ${includes.taxonomy ? \"yes\" : \"no\"}`,\n ` includes.identityAnchors: ${includes.identityAnchors ? \"yes\" : \"no\"}`,\n ` includes.peerProfiles: ${includes.peerProfiles ? \"yes\" : \"no\"}`,\n ` includes.procedural: ${includes.procedural ? \"yes\" : \"no\"}`,\n \"\",\n ` policy.directAnswer: ${retrievalPolicy.directAnswerEnabled ? \"yes\" : \"no\"}`,\n ];\n\n const weights = Object.entries(retrievalPolicy.tierWeights ?? {});\n if (weights.length > 0) {\n for (const [k, v] of weights) {\n lines.push(` policy.tierWeight[${k}]: ${v}`);\n }\n } else {\n lines.push(` policy.tierWeights: (none)`);\n }\n\n if (topFiles.length > 0) {\n lines.push(\"\", ` files (first ${topFiles.length} of ${fileCount}):`);\n for (const f of topFiles) {\n lines.push(` ${f}`);\n }\n }\n\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/**\n * Data shape consumed by {@link renderCapsuleInspect}.\n * Populated by the cli.ts action handler from the parsed manifest.\n */\nexport interface CapsuleInspectData {\n capsuleId: string;\n version: string;\n schemaVersion: string;\n createdAt: string | null;\n pluginVersion: string | null;\n fileCount: number;\n includesTranscripts: boolean;\n description: string;\n parentCapsule: string | null;\n retrievalPolicy: {\n tierWeights: Record<string, number>;\n directAnswerEnabled: boolean;\n };\n includes: {\n taxonomy: boolean;\n identityAnchors: boolean;\n peerProfiles: boolean;\n procedural: boolean;\n };\n /** First N file paths from manifest.files (for preview). */\n topFiles: string[];\n}\n"],"mappings":"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","names":["defaultCapsulesDir"]}
@@ -0,0 +1,82 @@
1
+ // src/evidence-pack.ts
2
+ var DEFAULT_MAX_ITEM_CHARS = 1200;
3
+ function buildEvidencePack(items, options) {
4
+ const budget = normalizePositiveInteger(options.maxChars);
5
+ if (budget <= 0 || items.length === 0) {
6
+ return "";
7
+ }
8
+ const maxItemChars = normalizePositiveInteger(
9
+ options.maxItemChars ?? DEFAULT_MAX_ITEM_CHARS
10
+ );
11
+ if (maxItemChars <= 0) {
12
+ return "";
13
+ }
14
+ const title = options.title ?? "Evidence";
15
+ const lines = [`## ${title}`];
16
+ const seenIds = /* @__PURE__ */ new Set();
17
+ const seenContent = /* @__PURE__ */ new Set();
18
+ let used = lines[0].length;
19
+ for (const item of items) {
20
+ const content = item.content.trim();
21
+ if (!content) continue;
22
+ const id = item.id ?? evidenceItemFallbackId(item);
23
+ if (id && seenIds.has(id)) continue;
24
+ const contentKey = normalizeEvidenceContent(content);
25
+ if (seenContent.has(contentKey)) continue;
26
+ const label = formatEvidenceLabel(item);
27
+ const clipped = clipText(content, maxItemChars);
28
+ const block = `${label}: ${clipped}`;
29
+ const separatorLength = lines.length > 0 ? 2 : 0;
30
+ const remaining = budget - used - separatorLength;
31
+ if (remaining <= 0) break;
32
+ const finalBlock = block.length > remaining ? clipText(block, remaining) : block;
33
+ if (!finalBlock.trim()) break;
34
+ lines.push(finalBlock);
35
+ used += separatorLength + finalBlock.length;
36
+ if (id) seenIds.add(id);
37
+ seenContent.add(contentKey);
38
+ }
39
+ return lines.length === 1 ? "" : lines.join("\n\n");
40
+ }
41
+ function normalizePositiveInteger(value) {
42
+ if (!Number.isFinite(value) || value <= 0) {
43
+ return 0;
44
+ }
45
+ return Math.floor(value);
46
+ }
47
+ function evidenceItemFallbackId(item) {
48
+ if (item.sessionId && typeof item.turnIndex === "number") {
49
+ return `${item.sessionId}:${item.turnIndex}`;
50
+ }
51
+ return void 0;
52
+ }
53
+ function normalizeEvidenceContent(content) {
54
+ return content.toLowerCase().replace(/\s+/g, " ").trim();
55
+ }
56
+ function formatEvidenceLabel(item) {
57
+ const parts = [];
58
+ if (item.sessionId) parts.push(item.sessionId);
59
+ if (typeof item.turnIndex === "number") parts.push(`turn ${item.turnIndex}`);
60
+ if (item.role) parts.push(item.role);
61
+ if (typeof item.score === "number" && Number.isFinite(item.score)) {
62
+ parts.push(`score ${item.score.toFixed(3)}`);
63
+ }
64
+ return parts.length > 0 ? `[${parts.join(", ")}]` : "[evidence]";
65
+ }
66
+ function clipText(text, maxChars) {
67
+ if (text.length <= maxChars) {
68
+ return text;
69
+ }
70
+ if (maxChars <= 1) {
71
+ return text.slice(0, maxChars);
72
+ }
73
+ if (maxChars <= 3) {
74
+ return text.slice(0, maxChars);
75
+ }
76
+ return `${text.slice(0, maxChars - 3).trimEnd()}...`;
77
+ }
78
+
79
+ export {
80
+ buildEvidencePack
81
+ };
82
+ //# sourceMappingURL=chunk-74WWN7ZW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/evidence-pack.ts"],"sourcesContent":["export interface EvidencePackItem {\n id?: string;\n sessionId?: string;\n turnIndex?: number;\n role?: string;\n content: string;\n score?: number;\n}\n\nexport interface EvidencePackOptions {\n title?: string;\n maxChars: number;\n maxItemChars?: number;\n}\n\nconst DEFAULT_MAX_ITEM_CHARS = 1_200;\n\nexport function buildEvidencePack(\n items: readonly EvidencePackItem[],\n options: EvidencePackOptions,\n): string {\n const budget = normalizePositiveInteger(options.maxChars);\n if (budget <= 0 || items.length === 0) {\n return \"\";\n }\n\n const maxItemChars = normalizePositiveInteger(\n options.maxItemChars ?? DEFAULT_MAX_ITEM_CHARS,\n );\n if (maxItemChars <= 0) {\n return \"\";\n }\n\n const title = options.title ?? \"Evidence\";\n const lines: string[] = [`## ${title}`];\n const seenIds = new Set<string>();\n const seenContent = new Set<string>();\n let used = lines[0]!.length;\n\n for (const item of items) {\n const content = item.content.trim();\n if (!content) continue;\n\n const id = item.id ?? evidenceItemFallbackId(item);\n if (id && seenIds.has(id)) continue;\n\n const contentKey = normalizeEvidenceContent(content);\n if (seenContent.has(contentKey)) continue;\n\n const label = formatEvidenceLabel(item);\n const clipped = clipText(content, maxItemChars);\n const block = `${label}: ${clipped}`;\n const separatorLength = lines.length > 0 ? 2 : 0;\n const remaining = budget - used - separatorLength;\n if (remaining <= 0) break;\n\n const finalBlock =\n block.length > remaining ? clipText(block, remaining) : block;\n if (!finalBlock.trim()) break;\n\n lines.push(finalBlock);\n used += separatorLength + finalBlock.length;\n if (id) seenIds.add(id);\n seenContent.add(contentKey);\n }\n\n return lines.length === 1 ? \"\" : lines.join(\"\\n\\n\");\n}\n\nfunction normalizePositiveInteger(value: number): number {\n if (!Number.isFinite(value) || value <= 0) {\n return 0;\n }\n return Math.floor(value);\n}\n\nfunction evidenceItemFallbackId(item: EvidencePackItem): string | undefined {\n if (item.sessionId && typeof item.turnIndex === \"number\") {\n return `${item.sessionId}:${item.turnIndex}`;\n }\n return undefined;\n}\n\nfunction normalizeEvidenceContent(content: string): string {\n return content.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\n\nfunction formatEvidenceLabel(item: EvidencePackItem): string {\n const parts: string[] = [];\n if (item.sessionId) parts.push(item.sessionId);\n if (typeof item.turnIndex === \"number\") parts.push(`turn ${item.turnIndex}`);\n if (item.role) parts.push(item.role);\n if (typeof item.score === \"number\" && Number.isFinite(item.score)) {\n parts.push(`score ${item.score.toFixed(3)}`);\n }\n return parts.length > 0 ? `[${parts.join(\", \")}]` : \"[evidence]\";\n}\n\nfunction clipText(text: string, maxChars: number): string {\n if (text.length <= maxChars) {\n return text;\n }\n if (maxChars <= 1) {\n return text.slice(0, maxChars);\n }\n if (maxChars <= 3) {\n return text.slice(0, maxChars);\n }\n return `${text.slice(0, maxChars - 3).trimEnd()}...`;\n}\n"],"mappings":";AAeA,IAAM,yBAAyB;AAExB,SAAS,kBACd,OACA,SACQ;AACR,QAAM,SAAS,yBAAyB,QAAQ,QAAQ;AACxD,MAAI,UAAU,KAAK,MAAM,WAAW,GAAG;AACrC,WAAO;AAAA,EACT;AAEA,QAAM,eAAe;AAAA,IACnB,QAAQ,gBAAgB;AAAA,EAC1B;AACA,MAAI,gBAAgB,GAAG;AACrB,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,QAAkB,CAAC,MAAM,KAAK,EAAE;AACtC,QAAM,UAAU,oBAAI,IAAY;AAChC,QAAM,cAAc,oBAAI,IAAY;AACpC,MAAI,OAAO,MAAM,CAAC,EAAG;AAErB,aAAW,QAAQ,OAAO;AACxB,UAAM,UAAU,KAAK,QAAQ,KAAK;AAClC,QAAI,CAAC,QAAS;AAEd,UAAM,KAAK,KAAK,MAAM,uBAAuB,IAAI;AACjD,QAAI,MAAM,QAAQ,IAAI,EAAE,EAAG;AAE3B,UAAM,aAAa,yBAAyB,OAAO;AACnD,QAAI,YAAY,IAAI,UAAU,EAAG;AAEjC,UAAM,QAAQ,oBAAoB,IAAI;AACtC,UAAM,UAAU,SAAS,SAAS,YAAY;AAC9C,UAAM,QAAQ,GAAG,KAAK,KAAK,OAAO;AAClC,UAAM,kBAAkB,MAAM,SAAS,IAAI,IAAI;AAC/C,UAAM,YAAY,SAAS,OAAO;AAClC,QAAI,aAAa,EAAG;AAEpB,UAAM,aACJ,MAAM,SAAS,YAAY,SAAS,OAAO,SAAS,IAAI;AAC1D,QAAI,CAAC,WAAW,KAAK,EAAG;AAExB,UAAM,KAAK,UAAU;AACrB,YAAQ,kBAAkB,WAAW;AACrC,QAAI,GAAI,SAAQ,IAAI,EAAE;AACtB,gBAAY,IAAI,UAAU;AAAA,EAC5B;AAEA,SAAO,MAAM,WAAW,IAAI,KAAK,MAAM,KAAK,MAAM;AACpD;AAEA,SAAS,yBAAyB,OAAuB;AACvD,MAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GAAG;AACzC,WAAO;AAAA,EACT;AACA,SAAO,KAAK,MAAM,KAAK;AACzB;AAEA,SAAS,uBAAuB,MAA4C;AAC1E,MAAI,KAAK,aAAa,OAAO,KAAK,cAAc,UAAU;AACxD,WAAO,GAAG,KAAK,SAAS,IAAI,KAAK,SAAS;AAAA,EAC5C;AACA,SAAO;AACT;AAEA,SAAS,yBAAyB,SAAyB;AACzD,SAAO,QAAQ,YAAY,EAAE,QAAQ,QAAQ,GAAG,EAAE,KAAK;AACzD;AAEA,SAAS,oBAAoB,MAAgC;AAC3D,QAAM,QAAkB,CAAC;AACzB,MAAI,KAAK,UAAW,OAAM,KAAK,KAAK,SAAS;AAC7C,MAAI,OAAO,KAAK,cAAc,SAAU,OAAM,KAAK,QAAQ,KAAK,SAAS,EAAE;AAC3E,MAAI,KAAK,KAAM,OAAM,KAAK,KAAK,IAAI;AACnC,MAAI,OAAO,KAAK,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,GAAG;AACjE,UAAM,KAAK,SAAS,KAAK,MAAM,QAAQ,CAAC,CAAC,EAAE;AAAA,EAC7C;AACA,SAAO,MAAM,SAAS,IAAI,IAAI,MAAM,KAAK,IAAI,CAAC,MAAM;AACtD;AAEA,SAAS,SAAS,MAAc,UAA0B;AACxD,MAAI,KAAK,UAAU,UAAU;AAC3B,WAAO;AAAA,EACT;AACA,MAAI,YAAY,GAAG;AACjB,WAAO,KAAK,MAAM,GAAG,QAAQ;AAAA,EAC/B;AACA,MAAI,YAAY,GAAG;AACjB,WAAO,KAAK,MAAM,GAAG,QAAQ;AAAA,EAC/B;AACA,SAAO,GAAG,KAAK,MAAM,GAAG,WAAW,CAAC,EAAE,QAAQ,CAAC;AACjD;","names":[]}