pi-mega-compact 0.11.4 → 0.11.6

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 (381) hide show
  1. package/dist/extensions/dashboard-server/api-contracts/cache-stripes.js +8 -0
  2. package/dist/extensions/dashboard-server/api-contracts/endpoints.js +32 -0
  3. package/dist/extensions/dashboard-server/api-contracts/memory-map.js +1 -0
  4. package/dist/extensions/dashboard-server/api-contracts/memory.js +8 -0
  5. package/dist/extensions/dashboard-server/api-contracts/provider-cache.js +1 -0
  6. package/dist/extensions/dashboard-server/api-contracts/setup.js +10 -0
  7. package/dist/extensions/dashboard-server/index-reader.js +6 -2
  8. package/dist/extensions/dashboard-server/routes-cache.js +135 -47
  9. package/dist/extensions/dashboard-server/routes-game.js +3 -0
  10. package/dist/extensions/dashboard-server/routes-memory-map.js +50 -0
  11. package/dist/extensions/dashboard-server/routes-memory.js +51 -0
  12. package/dist/extensions/dashboard-server/routes-repo.js +2 -2
  13. package/dist/extensions/dashboard-server/routes-setup.js +267 -0
  14. package/dist/extensions/dashboard-server/routes.js +4 -0
  15. package/dist/extensions/dashboard-server/server.js +13 -1
  16. package/dist/extensions/mega-commands.js +189 -1
  17. package/dist/extensions/mega-compact.js +5 -0
  18. package/dist/extensions/mega-config.js +7 -0
  19. package/dist/extensions/mega-events/agent-handlers.js +19 -4
  20. package/dist/extensions/mega-events/compact-handlers.js +1 -0
  21. package/dist/extensions/mega-events/context-handler.js +45 -92
  22. package/dist/extensions/mega-events/context-hwm.js +51 -0
  23. package/dist/extensions/mega-events/error-classifier.js +16 -5
  24. package/dist/extensions/mega-events/mirror-append.js +107 -0
  25. package/dist/extensions/mega-events/outage-advisor.js +7 -1
  26. package/dist/extensions/mega-events/perf-handler.js +134 -2
  27. package/dist/extensions/mega-events/recall-tail.js +59 -0
  28. package/dist/extensions/mega-events/separated-prompt.js +248 -0
  29. package/dist/extensions/mega-events/session-handlers.js +15 -8
  30. package/dist/extensions/mega-runtime/env-loader.js +56 -0
  31. package/dist/extensions/mega-runtime/reset-runtime.js +6 -0
  32. package/dist/extensions/mega-runtime/runtime-snapshot.js +1 -0
  33. package/dist/extensions/mega-runtime/runtime.js +7 -0
  34. package/dist/extensions/mega-runtime/snapshot.js +1 -0
  35. package/dist/extensions/mega-runtime/widget.js +5 -0
  36. package/dist/src/cache-stripe-impl.js +288 -0
  37. package/dist/src/cache-stripe.js +11 -0
  38. package/dist/src/config/stopwords.js +24 -0
  39. package/dist/src/config.js +17 -0
  40. package/dist/src/embedder.js +41 -2
  41. package/dist/src/memoryGraph.js +299 -0
  42. package/dist/src/memoryStats.js +75 -0
  43. package/dist/src/monitoring.js +13 -0
  44. package/dist/src/prefix-break.js +43 -0
  45. package/dist/src/pricing.js +1 -1
  46. package/dist/src/queryExpansion.js +163 -0
  47. package/dist/src/queryReformulation/cache.js +123 -0
  48. package/dist/src/queryReformulation/rrf.js +29 -0
  49. package/dist/src/queryReformulation/tfidf.js +61 -0
  50. package/dist/src/queryReformulation/vagueness.js +33 -0
  51. package/dist/src/queryReformulation.js +225 -0
  52. package/dist/src/recallMetrics.js +258 -0
  53. package/dist/src/store/sqlite/cache-stripes.js +133 -0
  54. package/dist/src/store/sqlite/fts5-search.js +68 -0
  55. package/dist/src/store/sqlite/perf-samples.js +145 -16
  56. package/dist/src/store/sqlite/schema.js +60 -1
  57. package/dist/src/store/sqlite.js +1 -0
  58. package/dist/src/store/turns/memory-store.js +8 -0
  59. package/dist/src/store/turns/sqlite-store.js +14 -3
  60. package/dist/src/store/turns/types.js +18 -1
  61. package/dist/src/store/vectorIndex.js +55 -10
  62. package/dist/src/tiered-router/types.js +18 -0
  63. package/dist/src/tieredRouter.js +421 -0
  64. package/dist/src/vectorStore.js +8 -6
  65. package/extensions/dashboard-client/dist/assets/{AchievementTiles-vEo2MtE2.js → AchievementTiles-DR9cLGDL.js} +2 -2
  66. package/extensions/dashboard-client/dist/assets/{AchievementTiles-vEo2MtE2.js.map → AchievementTiles-DR9cLGDL.js.map} +1 -1
  67. package/extensions/dashboard-client/dist/assets/AchievementsTab-svNUgJ1e.js +2 -0
  68. package/extensions/dashboard-client/dist/assets/{AchievementsTab-DjxfYrDc.js.map → AchievementsTab-svNUgJ1e.js.map} +1 -1
  69. package/extensions/dashboard-client/dist/assets/CacheTab-ASwhOMjR.js +2 -0
  70. package/extensions/dashboard-client/dist/assets/CacheTab-ASwhOMjR.js.map +1 -0
  71. package/extensions/dashboard-client/dist/assets/{ConfigTab-Cm6ymbmx.js → ConfigTab-CmmWheuW.js} +2 -2
  72. package/extensions/dashboard-client/dist/assets/{ConfigTab-Cm6ymbmx.js.map → ConfigTab-CmmWheuW.js.map} +1 -1
  73. package/extensions/dashboard-client/dist/assets/{EventsTab-DXWl_YzI.js → EventsTab-CFE7jLsa.js} +2 -2
  74. package/extensions/dashboard-client/dist/assets/{EventsTab-DXWl_YzI.js.map → EventsTab-CFE7jLsa.js.map} +1 -1
  75. package/extensions/dashboard-client/dist/assets/GameTab-CJAX_th_.js +2 -0
  76. package/extensions/dashboard-client/dist/assets/{GameTab-BLDudcO5.js.map → GameTab-CJAX_th_.js.map} +1 -1
  77. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DLkKCztn.js → MaintenanceTab-P4SUsvMf.js} +2 -2
  78. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DLkKCztn.js.map → MaintenanceTab-P4SUsvMf.js.map} +1 -1
  79. package/extensions/dashboard-client/dist/assets/MemoryMapTab-BBiH76eF.js +2 -0
  80. package/extensions/dashboard-client/dist/assets/MemoryMapTab-BBiH76eF.js.map +1 -0
  81. package/extensions/dashboard-client/dist/assets/{MetricsTab-Cq4u-rZF.js → MetricsTab-CHQscixy.js} +2 -2
  82. package/extensions/dashboard-client/dist/assets/{MetricsTab-Cq4u-rZF.js.map → MetricsTab-CHQscixy.js.map} +1 -1
  83. package/extensions/dashboard-client/dist/assets/OverviewTab-DBs4DJdd.js +2 -0
  84. package/extensions/dashboard-client/dist/assets/{OverviewTab-D4kGvsiQ.js.map → OverviewTab-DBs4DJdd.js.map} +1 -1
  85. package/extensions/dashboard-client/dist/assets/ReposTab-DeFz76L5.js +2 -0
  86. package/extensions/dashboard-client/dist/assets/ReposTab-DeFz76L5.js.map +1 -0
  87. package/extensions/dashboard-client/dist/assets/{SessionsTab-DZC2-GCn.js → SessionsTab-BWNsj1OB.js} +2 -2
  88. package/extensions/dashboard-client/dist/assets/{SessionsTab-DZC2-GCn.js.map → SessionsTab-BWNsj1OB.js.map} +1 -1
  89. package/extensions/dashboard-client/dist/assets/SetupTab-uS6A0xmw.js +2 -0
  90. package/extensions/dashboard-client/dist/assets/SetupTab-uS6A0xmw.js.map +1 -0
  91. package/extensions/dashboard-client/dist/assets/TimeSavedCard-CiqCOQuL.js +2 -0
  92. package/extensions/dashboard-client/dist/assets/TimeSavedCard-CiqCOQuL.js.map +1 -0
  93. package/extensions/dashboard-client/dist/assets/{TopicsTab-01G71hv1.js → TopicsTab-BWWQxltv.js} +2 -2
  94. package/extensions/dashboard-client/dist/assets/{TopicsTab-01G71hv1.js.map → TopicsTab-BWWQxltv.js.map} +1 -1
  95. package/extensions/dashboard-client/dist/assets/{TurnsTab-DLRg0LZT.js → TurnsTab-CVz4f4-o.js} +2 -2
  96. package/extensions/dashboard-client/dist/assets/{TurnsTab-DLRg0LZT.js.map → TurnsTab-CVz4f4-o.js.map} +1 -1
  97. package/extensions/dashboard-client/dist/assets/format-COjDIVGj.js +2 -0
  98. package/extensions/dashboard-client/dist/assets/format-COjDIVGj.js.map +1 -0
  99. package/extensions/dashboard-client/dist/assets/index-CUNn22iV.css +1 -0
  100. package/extensions/dashboard-client/dist/assets/index-DrktNOoT.js +42 -0
  101. package/extensions/dashboard-client/dist/assets/index-DrktNOoT.js.map +1 -0
  102. package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js +2 -0
  103. package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js.map +1 -0
  104. package/extensions/dashboard-client/dist/assets/{useSSE-BBYt5UPB.js → useSSE-Bf5LOLSi.js} +2 -2
  105. package/extensions/dashboard-client/dist/assets/{useSSE-BBYt5UPB.js.map → useSSE-Bf5LOLSi.js.map} +1 -1
  106. package/extensions/dashboard-client/dist/index.html +2 -2
  107. package/extensions/dashboard-client/src/App.tsx +28 -8
  108. package/extensions/dashboard-client/src/api/client.ts +29 -0
  109. package/extensions/dashboard-client/src/components/ActiveReposTable.tsx +21 -12
  110. package/extensions/dashboard-client/src/components/CacheHitRateTrendCard.tsx +100 -0
  111. package/extensions/dashboard-client/src/components/ProviderCacheCard.tsx +56 -0
  112. package/extensions/dashboard-client/src/components/SavingsByModelTable.tsx +38 -57
  113. package/extensions/dashboard-client/src/components/StripeDistributionCard.tsx +110 -0
  114. package/extensions/dashboard-client/src/components/TabBar.tsx +49 -4
  115. package/extensions/dashboard-client/src/main.tsx +1 -0
  116. package/extensions/dashboard-client/src/styles/base.css +30 -0
  117. package/extensions/dashboard-client/src/styles/cache.css +167 -0
  118. package/extensions/dashboard-client/src/tabs/CacheTab.tsx +75 -12
  119. package/extensions/dashboard-client/src/tabs/MemoryMapTab.tsx +440 -0
  120. package/extensions/dashboard-client/src/tabs/SetupTab.tsx +418 -0
  121. package/extensions/dashboard-client/tsconfig.json +3 -2
  122. package/extensions/dashboard-client/vite.config.ts +2 -0
  123. package/extensions/dashboard-server/api-contracts/cache-stripes.ts +49 -0
  124. package/extensions/dashboard-server/api-contracts/endpoints.ts +66 -3
  125. package/extensions/dashboard-server/api-contracts/index.ts +22 -0
  126. package/extensions/dashboard-server/api-contracts/memory-map.ts +50 -0
  127. package/extensions/dashboard-server/api-contracts/memory.ts +27 -0
  128. package/extensions/dashboard-server/api-contracts/multi-repo.ts +231 -231
  129. package/extensions/dashboard-server/api-contracts/provider-cache.ts +37 -0
  130. package/extensions/dashboard-server/api-contracts/setup.ts +80 -0
  131. package/extensions/dashboard-server/index-reader.ts +138 -121
  132. package/extensions/dashboard-server/routes-cache.ts +186 -75
  133. package/extensions/dashboard-server/routes-game.ts +3 -0
  134. package/extensions/dashboard-server/routes-memory-map.ts +105 -0
  135. package/extensions/dashboard-server/routes-memory.ts +63 -0
  136. package/extensions/dashboard-server/routes-repo.ts +36 -36
  137. package/extensions/dashboard-server/routes-setup.ts +293 -0
  138. package/extensions/dashboard-server/routes.ts +4 -0
  139. package/extensions/dashboard-server/server.ts +12 -0
  140. package/extensions/mega-commands.ts +211 -1
  141. package/extensions/mega-compact.ts +5 -0
  142. package/extensions/mega-config.ts +27 -0
  143. package/extensions/mega-events/agent-handlers.ts +20 -4
  144. package/extensions/mega-events/compact-handlers.ts +1 -0
  145. package/extensions/mega-events/context-handler.ts +53 -110
  146. package/extensions/mega-events/context-hwm.ts +85 -0
  147. package/extensions/mega-events/error-classifier.ts +15 -4
  148. package/extensions/mega-events/mirror-append.ts +155 -0
  149. package/extensions/mega-events/outage-advisor.ts +11 -5
  150. package/extensions/mega-events/perf-handler.ts +190 -6
  151. package/extensions/mega-events/recall-tail.ts +88 -0
  152. package/extensions/mega-events/separated-prompt.ts +329 -0
  153. package/extensions/mega-events/session-handlers.ts +14 -7
  154. package/extensions/mega-runtime/env-loader.ts +55 -0
  155. package/extensions/mega-runtime/helpers.ts +14 -0
  156. package/extensions/mega-runtime/reset-runtime.ts +6 -0
  157. package/extensions/mega-runtime/runtime-snapshot.ts +1 -0
  158. package/extensions/mega-runtime/runtime.ts +7 -0
  159. package/extensions/mega-runtime/snapshot.ts +6 -0
  160. package/extensions/mega-runtime/widget-types.ts +3 -0
  161. package/extensions/mega-runtime/widget.ts +5 -0
  162. package/package.json +5 -2
  163. package/src/cache-stripe-impl.ts +385 -0
  164. package/src/cache-stripe.ts +18 -0
  165. package/src/config/stopwords.ts +25 -0
  166. package/src/config.ts +26 -0
  167. package/src/embedder.ts +42 -2
  168. package/src/memoryGraph.ts +438 -0
  169. package/src/memoryStats.ts +107 -0
  170. package/src/monitoring.ts +35 -0
  171. package/src/prefix-break.ts +83 -0
  172. package/src/pricing.ts +2 -2
  173. package/src/queryExpansion.ts +206 -0
  174. package/src/queryReformulation/cache.ts +169 -0
  175. package/src/queryReformulation/rrf.ts +51 -0
  176. package/src/queryReformulation/tfidf.ts +79 -0
  177. package/src/queryReformulation/vagueness.ts +38 -0
  178. package/src/queryReformulation.ts +355 -0
  179. package/src/recallMetrics.ts +388 -0
  180. package/src/store/sqlite/cache-stripes.ts +196 -0
  181. package/src/store/sqlite/fts5-search.ts +90 -0
  182. package/src/store/sqlite/perf-samples.ts +218 -23
  183. package/src/store/sqlite/schema.ts +60 -1
  184. package/src/store/sqlite.ts +1 -0
  185. package/src/store/turns/memory-store.ts +10 -1
  186. package/src/store/turns/sqlite-store.ts +27 -15
  187. package/src/store/turns/types.ts +21 -0
  188. package/src/store/vectorIndex.ts +71 -11
  189. package/src/tiered-router/types.ts +64 -0
  190. package/src/tieredRouter.ts +489 -0
  191. package/src/vectorStore.ts +9 -5
  192. package/dist/extensions/conflict-scan.test.js +0 -115
  193. package/dist/extensions/dashboard-server/api-contracts.test.js +0 -884
  194. package/dist/extensions/dashboard-server/html.test.js +0 -52
  195. package/dist/extensions/dashboard-server/perf-server.test.js +0 -80
  196. package/dist/extensions/dashboard-server/routes-cache.test.js +0 -248
  197. package/dist/extensions/dashboard-server/server.test.js +0 -120
  198. package/dist/extensions/dashboard-server-s32.test.js +0 -181
  199. package/dist/extensions/dashboard-server.test.js +0 -339
  200. package/dist/extensions/mega-cache-replay.test.js +0 -400
  201. package/dist/extensions/mega-compact-s38.test.js +0 -1383
  202. package/dist/extensions/mega-compact.test.js +0 -1112
  203. package/dist/extensions/mega-events.test.js +0 -47
  204. package/dist/extensions/mega-game-cmds.test.js +0 -163
  205. package/dist/extensions/mega-runtime/snapshot.test.js +0 -127
  206. package/dist/extensions/mega-runtime/state.test.js +0 -266
  207. package/dist/extensions/mega-runtime/widget.test.js +0 -343
  208. package/dist/extensions/mega-shutdown-widget.test.js +0 -121
  209. package/dist/extensions/mega-teamrun.test.js +0 -156
  210. package/dist/extensions/mega-trim.test.js +0 -58
  211. package/dist/extensions/mega-turn-store.test.js +0 -68
  212. package/dist/src/boundary.test.js +0 -170
  213. package/dist/src/compact.test.js +0 -78
  214. package/dist/src/config/themes.test.js +0 -94
  215. package/dist/src/dedup/dedup.test.js +0 -41
  216. package/dist/src/dedup/l1.test.js +0 -50
  217. package/dist/src/dedup/raptor/buildHistory.test.js +0 -292
  218. package/dist/src/dedup/raptor/multilevel-serve.test.js +0 -229
  219. package/dist/src/dedup/raptor/multilevel.test.js +0 -238
  220. package/dist/src/dedup/raptor/promote.test.js +0 -69
  221. package/dist/src/dedup/raptor/raptor.test.js +0 -248
  222. package/dist/src/dedup/raptor/retrieval.test.js +0 -95
  223. package/dist/src/dedup/raptor/serve-gate.test.js +0 -298
  224. package/dist/src/dedup/sprint12.test.js +0 -219
  225. package/dist/src/dedup-engine.test.js +0 -472
  226. package/dist/src/driftDetection.test.js +0 -87
  227. package/dist/src/e2e.test.js +0 -698
  228. package/dist/src/engine.test.js +0 -111
  229. package/dist/src/extractive.test.js +0 -147
  230. package/dist/src/fork.test.js +0 -81
  231. package/dist/src/game/scoring.test.js +0 -98
  232. package/dist/src/httpEmbedder.test.js +0 -277
  233. package/dist/src/importance.test.js +0 -372
  234. package/dist/src/intent.test.js +0 -78
  235. package/dist/src/log.test.js +0 -42
  236. package/dist/src/mechanical-fix.test.js +0 -65
  237. package/dist/src/memory.test.js +0 -70
  238. package/dist/src/memoryConsolidate.test.js +0 -38
  239. package/dist/src/memoryOps.test.js +0 -129
  240. package/dist/src/memoryRecall.test.js +0 -171
  241. package/dist/src/memoryRoundtrip.test.js +0 -137
  242. package/dist/src/metrics/turns.test.js +0 -152
  243. package/dist/src/mirror/mirror.test.js +0 -185
  244. package/dist/src/raptor-inject-summaries.test.js +0 -162
  245. package/dist/src/ratio.bench.test.js +0 -897
  246. package/dist/src/recall.integration.test.js +0 -77
  247. package/dist/src/recall.test.js +0 -379
  248. package/dist/src/sprint14.test.js +0 -219
  249. package/dist/src/sprint4x-rag-verification.test.js +0 -93
  250. package/dist/src/store/compression.test.js +0 -139
  251. package/dist/src/store/memoryIndex.test.js +0 -51
  252. package/dist/src/store/migrate.test.js +0 -139
  253. package/dist/src/store/pgOpenGuard.test.js +0 -74
  254. package/dist/src/store/phase01.test.js +0 -81
  255. package/dist/src/store/phase04.test.js +0 -54
  256. package/dist/src/store/sprint10.test.js +0 -186
  257. package/dist/src/store/sqlite/game-achievements.test.js +0 -67
  258. package/dist/src/store/sqlite/game-scores.test.js +0 -106
  259. package/dist/src/store/sqlite/game-state.test.js +0 -76
  260. package/dist/src/store/sqlite/global-index.test.js +0 -136
  261. package/dist/src/store/sqlite/mechanical-fix.test.js +0 -146
  262. package/dist/src/store/sqlite/perf-samples.test.js +0 -146
  263. package/dist/src/store/sqlite/raptor.test.js +0 -106
  264. package/dist/src/store/sqlite/turns.test.js +0 -183
  265. package/dist/src/store/sqlite.cachehit.test.js +0 -55
  266. package/dist/src/store/sqlite.dbmaint.test.js +0 -158
  267. package/dist/src/store/sqlite.dbmirror.test.js +0 -184
  268. package/dist/src/store/turns/contract-compliance.test.js +0 -428
  269. package/dist/src/store/turns/memory-store.test.js +0 -9
  270. package/dist/src/store/turns/migrations.test.js +0 -138
  271. package/dist/src/store/turns/sqlite-store.test.js +0 -144
  272. package/dist/src/store/vectorIndex.test.js +0 -123
  273. package/dist/src/store.test.js +0 -161
  274. package/dist/src/supersede.test.js +0 -36
  275. package/dist/src/topics/cluster.test.js +0 -150
  276. package/dist/src/topics/store.test.js +0 -117
  277. package/dist/src/types.test.js +0 -9
  278. package/dist/src/vector-search-cache.test.js +0 -157
  279. package/dist/src/vectorStore.test.js +0 -479
  280. package/dist/src/wiki.test.js +0 -171
  281. package/extensions/conflict-scan.test.ts +0 -129
  282. package/extensions/dashboard-client/dist/assets/AchievementsTab-DjxfYrDc.js +0 -2
  283. package/extensions/dashboard-client/dist/assets/CacheTab-Dnpv94wq.js +0 -2
  284. package/extensions/dashboard-client/dist/assets/CacheTab-Dnpv94wq.js.map +0 -1
  285. package/extensions/dashboard-client/dist/assets/GameTab-BLDudcO5.js +0 -2
  286. package/extensions/dashboard-client/dist/assets/OverviewTab-D4kGvsiQ.js +0 -2
  287. package/extensions/dashboard-client/dist/assets/ReposTab-C0Wnrf2u.js +0 -2
  288. package/extensions/dashboard-client/dist/assets/ReposTab-C0Wnrf2u.js.map +0 -1
  289. package/extensions/dashboard-client/dist/assets/TimeSavedCard-UqljSyP-.js +0 -2
  290. package/extensions/dashboard-client/dist/assets/TimeSavedCard-UqljSyP-.js.map +0 -1
  291. package/extensions/dashboard-client/dist/assets/index-BEdKlpAB.css +0 -1
  292. package/extensions/dashboard-client/dist/assets/index-BX0bcgLu.js +0 -42
  293. package/extensions/dashboard-client/dist/assets/index-BX0bcgLu.js.map +0 -1
  294. package/extensions/dashboard-server/api-contracts.test.ts +0 -1065
  295. package/extensions/dashboard-server/html.test.ts +0 -62
  296. package/extensions/dashboard-server/perf-server.test.ts +0 -101
  297. package/extensions/dashboard-server/routes-cache.test.ts +0 -302
  298. package/extensions/dashboard-server/server.test.ts +0 -131
  299. package/extensions/dashboard-server-s32.test.ts +0 -195
  300. package/extensions/dashboard-server.test.ts +0 -382
  301. package/extensions/mega-cache-replay.test.ts +0 -526
  302. package/extensions/mega-compact-s38.test.ts +0 -1433
  303. package/extensions/mega-compact.test.ts +0 -1509
  304. package/extensions/mega-events.test.ts +0 -55
  305. package/extensions/mega-game-cmds.test.ts +0 -197
  306. package/extensions/mega-runtime/snapshot.test.ts +0 -139
  307. package/extensions/mega-runtime/state.test.ts +0 -262
  308. package/extensions/mega-runtime/widget.test.ts +0 -468
  309. package/extensions/mega-shutdown-widget.test.ts +0 -141
  310. package/extensions/mega-teamrun.test.ts +0 -176
  311. package/extensions/mega-trim.test.ts +0 -64
  312. package/extensions/mega-turn-store.test.ts +0 -108
  313. package/src/boundary.test.ts +0 -187
  314. package/src/compact.test.ts +0 -99
  315. package/src/config/themes.test.ts +0 -116
  316. package/src/dedup/dedup.test.ts +0 -46
  317. package/src/dedup/l1.test.ts +0 -57
  318. package/src/dedup/raptor/buildHistory.test.ts +0 -353
  319. package/src/dedup/raptor/multilevel-serve.test.ts +0 -273
  320. package/src/dedup/raptor/multilevel.test.ts +0 -325
  321. package/src/dedup/raptor/promote.test.ts +0 -82
  322. package/src/dedup/raptor/raptor.test.ts +0 -297
  323. package/src/dedup/raptor/retrieval.test.ts +0 -118
  324. package/src/dedup/raptor/serve-gate.test.ts +0 -348
  325. package/src/dedup/sprint12.test.ts +0 -242
  326. package/src/dedup-engine.test.ts +0 -670
  327. package/src/driftDetection.test.ts +0 -100
  328. package/src/e2e.test.ts +0 -843
  329. package/src/engine.test.ts +0 -123
  330. package/src/extractive.test.ts +0 -174
  331. package/src/fork.test.ts +0 -94
  332. package/src/game/scoring.test.ts +0 -103
  333. package/src/httpEmbedder.test.ts +0 -286
  334. package/src/importance.test.ts +0 -538
  335. package/src/intent.test.ts +0 -87
  336. package/src/log.test.ts +0 -47
  337. package/src/mechanical-fix.test.ts +0 -70
  338. package/src/memory.test.ts +0 -92
  339. package/src/memoryConsolidate.test.ts +0 -47
  340. package/src/memoryOps.test.ts +0 -148
  341. package/src/memoryRecall.test.ts +0 -194
  342. package/src/memoryRoundtrip.test.ts +0 -155
  343. package/src/metrics/turns.test.ts +0 -165
  344. package/src/mirror/mirror.test.ts +0 -240
  345. package/src/raptor-inject-summaries.test.ts +0 -228
  346. package/src/ratio.bench.test.ts +0 -1316
  347. package/src/recall.integration.test.ts +0 -96
  348. package/src/recall.test.ts +0 -467
  349. package/src/sprint14.test.ts +0 -245
  350. package/src/sprint4x-rag-verification.test.ts +0 -119
  351. package/src/store/compression.test.ts +0 -168
  352. package/src/store/memoryIndex.test.ts +0 -61
  353. package/src/store/migrate.test.ts +0 -158
  354. package/src/store/pgOpenGuard.test.ts +0 -89
  355. package/src/store/phase01.test.ts +0 -88
  356. package/src/store/phase04.test.ts +0 -58
  357. package/src/store/sprint10.test.ts +0 -214
  358. package/src/store/sqlite/game-achievements.test.ts +0 -80
  359. package/src/store/sqlite/game-scores.test.ts +0 -132
  360. package/src/store/sqlite/game-state.test.ts +0 -89
  361. package/src/store/sqlite/global-index.test.ts +0 -222
  362. package/src/store/sqlite/mechanical-fix.test.ts +0 -162
  363. package/src/store/sqlite/perf-samples.test.ts +0 -169
  364. package/src/store/sqlite/raptor.test.ts +0 -139
  365. package/src/store/sqlite/turns.test.ts +0 -218
  366. package/src/store/sqlite.cachehit.test.ts +0 -68
  367. package/src/store/sqlite.dbmaint.test.ts +0 -193
  368. package/src/store/sqlite.dbmirror.test.ts +0 -229
  369. package/src/store/turns/contract-compliance.test.ts +0 -562
  370. package/src/store/turns/memory-store.test.ts +0 -15
  371. package/src/store/turns/migrations.test.ts +0 -161
  372. package/src/store/turns/sqlite-store.test.ts +0 -161
  373. package/src/store/vectorIndex.test.ts +0 -140
  374. package/src/store.test.ts +0 -191
  375. package/src/supersede.test.ts +0 -42
  376. package/src/topics/cluster.test.ts +0 -176
  377. package/src/topics/store.test.ts +0 -132
  378. package/src/types.test.ts +0 -10
  379. package/src/vector-search-cache.test.ts +0 -190
  380. package/src/vectorStore.test.ts +0 -533
  381. package/src/wiki.test.ts +0 -217
@@ -16,6 +16,11 @@ import { type MegaRuntime, C, recentUserQuery } from "./mega-runtime.js";
16
16
  import { runCompact, doRecall, doRecallAsync } from "./mega-pipeline.js";
17
17
  import { vectorStats, vectorRepoStats, vectorDataInvariant } from "../src/vectorStore.js";
18
18
  import type { MegaConfig } from "./mega-config.js";
19
+ import { spawnSync } from "node:child_process"; // guardrails-allow PREVENT-PI-004: local subprocess detection only (no network)
20
+ import { mkdirSync, writeFileSync } from "node:fs";
21
+ import path from "node:path";
22
+ import os from "node:os";
23
+ import { createRequire } from "node:module";
19
24
 
20
25
  /** Resolve a checkpoint by id (or "recent"/"last") from this session's store. */
21
26
  export function findCheckpoint(runtime: MegaRuntime, sid: string, ref: string) {
@@ -79,7 +84,7 @@ export function registerCommands(pi: ExtensionAPI, runtime: MegaRuntime, config:
79
84
  runtime.setStatus(ctx, `mega-compact: recalled ${r.toInject.length} chkpt${crossRepo ? " (cross-repo)" : ""}`);
80
85
  ctx.ui.notify(
81
86
  `[mega-compact] recall staged ${r.toInject.length} checkpoint(s) for "${query}"${crossRepo ? " (cross-repo)" : ""}:\n${list}\n` +
82
- `(injected at the next turn via system prompt)`,
87
+ `(injected at the tail of the next turn's context)`,
83
88
  );
84
89
  } catch (e) {
85
90
  ctx.ui.notify(`[mega-compact] /mega-recall failed: ${String(e)}`);
@@ -275,6 +280,211 @@ export function registerCommands(pi: ExtensionAPI, runtime: MegaRuntime, config:
275
280
  },
276
281
  });
277
282
 
283
+ pi.registerCommand("mega-setup", {
284
+ description:
285
+ "Local embedding setup wizard — detect available embedders and configure mega-compact.",
286
+ handler: async (_args: string, ctx: ExtensionContext) => {
287
+ try {
288
+ const log = (msg: string) => ctx.ui.notify(msg);
289
+
290
+ // --- 1. Current config ---
291
+ const embeddingUrl = process.env["MEGACOMPACT_EMBEDDING_URL"];
292
+ const minilm = process.env["MEGACOMPACT_MINILM"];
293
+
294
+ let currentEmbedder = "TrigramEmbedder (heuristic, default)";
295
+ if (embeddingUrl) currentEmbedder = `httpEmbedder → ${embeddingUrl}`;
296
+ else if (minilm) currentEmbedder = "MiniLM (experimental)";
297
+
298
+ // --- 2. Detection ---
299
+ let ollamaDetected = false;
300
+ let ollamaModels: string[] = [];
301
+ let ollamaRunning = false;
302
+ let llamaDetected = false;
303
+ let onnxDetected = false;
304
+
305
+ try {
306
+ const ollamaVer = spawnSync("ollama", ["--version"], {
307
+ timeout: 5000,
308
+ encoding: "utf-8",
309
+ stdio: ["ignore", "pipe", "pipe"],
310
+ }); // guardrails-allow PREVENT-PI-004: local subprocess detection only
311
+ if (ollamaVer.status === 0) {
312
+ ollamaDetected = true;
313
+ try {
314
+ const listResult = spawnSync("ollama", ["list"], {
315
+ timeout: 5000,
316
+ encoding: "utf-8",
317
+ stdio: ["ignore", "pipe", "pipe"],
318
+ }); // guardrails-allow PREVENT-PI-004: local subprocess detection only
319
+ if (listResult.status === 0) {
320
+ ollamaRunning = true;
321
+ const lines = listResult.stdout?.split("\n") ?? [];
322
+ for (const line of lines) {
323
+ const name = line.split(/\s+/)[0];
324
+ if (name && name !== "NAME") ollamaModels.push(name);
325
+ }
326
+ }
327
+ } catch {
328
+ // ollama list fails if server not running — that's fine
329
+ }
330
+ }
331
+ } catch {
332
+ // ollama not found
333
+ }
334
+
335
+ try {
336
+ const whichLlama = spawnSync("which", ["llama-server"], {
337
+ timeout: 3000,
338
+ encoding: "utf-8",
339
+ stdio: ["ignore", "pipe", "pipe"],
340
+ }); // guardrails-allow PREVENT-PI-004: local subprocess detection only
341
+ llamaDetected = whichLlama.status === 0;
342
+ } catch {
343
+ // not found
344
+ }
345
+
346
+ try {
347
+ const req = createRequire(import.meta.url);
348
+ try {
349
+ req.resolve("onnxruntime-node");
350
+ onnxDetected = true;
351
+ } catch {
352
+ // not in node_modules
353
+ }
354
+ } catch {
355
+ // require error
356
+ }
357
+
358
+ // --- 3. Build choices ---
359
+ interface Choice {
360
+ label: string;
361
+ value: string;
362
+ }
363
+ const choices: Choice[] = [];
364
+
365
+ if (ollamaDetected && ollamaRunning) {
366
+ const model = ollamaModels.find(
367
+ (m) =>
368
+ m.includes("nomic-embed") ||
369
+ m.includes("embed") ||
370
+ m.includes("mxbai"),
371
+ );
372
+ const suggestedModel = model ?? "nomic-embed-text";
373
+ choices.push({
374
+ label: `Use Ollama (${suggestedModel}) at localhost:11434`,
375
+ value: `ollama:${suggestedModel}`,
376
+ });
377
+ } else if (ollamaDetected && !ollamaRunning) {
378
+ choices.push({
379
+ label: "Ollama detected but server is not running — start it first",
380
+ value: "ollama:offline",
381
+ });
382
+ }
383
+
384
+ if (llamaDetected) {
385
+ choices.push({
386
+ label: "Use llama.cpp server at localhost:8080",
387
+ value: "llama:default",
388
+ });
389
+ }
390
+
391
+ if (onnxDetected) {
392
+ choices.push({
393
+ label: "Use ONNX Runtime (experimental, requires config)",
394
+ value: "onnx:default",
395
+ });
396
+ }
397
+
398
+ choices.push({
399
+ label: "Keep TrigramEmbedder (default, no setup)",
400
+ value: "trigram",
401
+ });
402
+
403
+ // --- 4. Prompt user ---
404
+ log(`Current embedder: ${currentEmbedder}`);
405
+ let selected = "trigram";
406
+ if (choices.length > 1) {
407
+ try {
408
+ const labels = choices.map((c) => c.label);
409
+ const picked = await ctx.ui.select("Select an embedder to configure:", labels);
410
+ if (picked === undefined) {
411
+ log("Setup cancelled by user.");
412
+ return;
413
+ }
414
+ const match = choices.find((c) => c.label === picked);
415
+ selected = match?.value ?? "trigram";
416
+ } catch {
417
+ log("Setup cancelled by user.");
418
+ return;
419
+ }
420
+ } else {
421
+ log("No local embedders detected. Keeping TrigramEmbedder default.");
422
+ }
423
+
424
+ // --- 5. Apply selection ---
425
+ if (selected.startsWith("ollama:")) {
426
+ const model = selected.split(":")[1];
427
+ const url = `http://localhost:11434/api/embeddings`; // guardrails-allow PREVENT-PI-004: localhost-only config string, not a runtime fetch
428
+ const lines = [
429
+ `# Mega-Compact Embedder Configuration — Ollama`,
430
+ `# Generated by /megasetup at ${new Date().toISOString()}`,
431
+ `export MEGACOMPACT_EMBEDDING_URL="${url}"`,
432
+ `# Optional: uncomment to set cache size (default 1000)`,
433
+ `# export MEGACOMPACT_EMBED_CACHE=1000`,
434
+ ];
435
+ const envContent = lines.join("\n") + "\n";
436
+
437
+ // Write .mega-compact.env to state dir
438
+ const stateDir = process.env["MEGACOMPACT_STATE_DIR"] ?? path.join(os.homedir(), ".pi", "mega-compact");
439
+ try {
440
+ mkdirSync(stateDir, { recursive: true });
441
+ writeFileSync(path.join(stateDir, ".mega-compact.env"), envContent, "utf-8");
442
+ } catch {
443
+ // non-fatal
444
+ }
445
+
446
+ log(
447
+ `Configured for Ollama (${model}).\n\nAdd to your shell profile (~/.bashrc, ~/.zshrc, or ~/.config/fish/config.fish):\n\n source "${path.join(
448
+ stateDir,
449
+ ".mega-compact.env",
450
+ )}"\n\nOr export manually:\n\n export MEGACOMPACT_EMBEDDING_URL="${url}"\n\nThen restart pi to activate the http embedder.`,
451
+ );
452
+ } else if (selected.startsWith("llama:")) {
453
+ const url = "http://localhost:8080/v1/embeddings"; // guardrails-allow PREVENT-PI-004: localhost-only config string, not a runtime fetch
454
+ const lines = [
455
+ `# Mega-Compact Embedder Configuration — llama.cpp`,
456
+ `# Generated by /megasetup at ${new Date().toISOString()}`,
457
+ `export MEGACOMPACT_EMBEDDING_URL="${url}"`,
458
+ ];
459
+ const envContent = lines.join("\n") + "\n";
460
+
461
+ const stateDir = process.env["MEGACOMPACT_STATE_DIR"] ?? path.join(os.homedir(), ".pi", "mega-compact");
462
+ try {
463
+ mkdirSync(stateDir, { recursive: true });
464
+ writeFileSync(path.join(stateDir, ".mega-compact.env"), envContent, "utf-8");
465
+ } catch {
466
+ // non-fatal
467
+ }
468
+
469
+ log(
470
+ `Configured for llama.cpp server.\n\nAdd to your shell profile:\n\n source "${path.join(
471
+ stateDir,
472
+ ".mega-compact.env",
473
+ )}"\n\nOr export manually:\n\n export MEGACOMPACT_EMBEDDING_URL="${url}"\n\nThen restart pi to activate the http embedder.`,
474
+ );
475
+ } else if (selected.startsWith("onnx:")) {
476
+ log(
477
+ "ONNX Runtime configuration is experimental.\n\nSet MEGACOMPACT_EMBEDDING_URL to your local ONNX server URL, or see docs for manual setup.\nKeeping TrigramEmbedder for now.",
478
+ );
479
+ } else {
480
+ log("Keeping TrigramEmbedder (default). No configuration needed.");
481
+ }
482
+ } catch (e) {
483
+ ctx.ui.notify(`[mega-compact] /mega-setup failed: ${String(e)}`);
484
+ }
485
+ },
486
+ });
487
+
278
488
  // NOTE: /mega-tier was removed in S24. The tier the user sees is now the LIVE
279
489
  // pressure band (low/medium/high/ultra/mega), which climbs automatically as
280
490
  // context fills — there is no manual tier to set. See docs/specs/s24-unified-pressure.md.
@@ -30,6 +30,7 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
30
30
  import { closeVectorIndex } from "../src/store/vectorIndex.js";
31
31
  import { closeMemoryIndex } from "../src/store/memoryIndex.js";
32
32
  import { loadConfig } from "./mega-config.js";
33
+ import { loadMegaEnv } from "./mega-runtime/env-loader.js";
33
34
  import { MegaRuntime } from "./mega-runtime.js";
34
35
  import { registerEventHandlers } from "./mega-events.js";
35
36
  import { registerCommands } from "./mega-commands.js";
@@ -41,6 +42,10 @@ import { registerMetricsCommands } from "./mega-metrics-cmds.js";
41
42
  import { registerTopicsCommands } from "./mega-topics-cmds.js";
42
43
 
43
44
  export default function (pi: ExtensionAPI) {
45
+ // Load .mega-compact.env (written by /mega-setup + dashboard Setup tab) BEFORE
46
+ // config resolution so the wizard's choices take effect. Shell env wins over
47
+ // the file (see env-loader.ts). Non-fatal: missing/malformed file is a no-op.
48
+ loadMegaEnv(loadConfig().stateDir);
44
49
  const config = loadConfig();
45
50
  // S38.9: preflight env validation — check for obviously invalid values at startup.
46
51
  // Non-fatal: log warnings and fall back to defaults.
@@ -111,6 +111,10 @@ export interface MegaConfig {
111
111
  * advisory is sent to the user (distinct from the poisoned /clear advise).
112
112
  * Default 3. `0` disables the advisory entirely. */
113
113
  providerOutageAdviseThreshold: number;
114
+ /** R13: when true (default), poisoned-context and provider-outage advisories
115
+ * are dashboard-only (events tab + log) — no user-visible message injection.
116
+ * When false, the legacy sendUserMessage path runs (byte-identical pre-R13). */
117
+ advisoryChannel: boolean;
114
118
  /** S29: override the auto-compact fire point for tiered configs, as a
115
119
  * fraction of the context window (e.g. 0.85). null = inherit the tier's
116
120
  * tierPct (default; preserves existing fire points). The context-handler
@@ -160,9 +164,25 @@ export interface MegaConfig {
160
164
  * a hit whose summary is ≥ dedupSim similar to a live message — "dedupe on
161
165
  * inline/read" so we never re-inject context already resident. */
162
166
  windowDedupe: boolean;
167
+ /** S53: Recall Tail Injection — inject staged recall block as a user message at
168
+ * the tail of the view when auto is OFF AND no trim action is needed. Default ON
169
+ * (true). When false, restores the pre-sprint systemPrompt prepend behavior. */
170
+ recallTailInject: boolean;
171
+ /** A1 PLAN_V2 Phase 2: Message Separation — isolate user/assistant turns
172
+ * from volatile tool results so the prompt-cache prefix stays stable.
173
+ * Default OFF (flag-OFF = byte-identical pre-sprint). */
174
+ messageSeparation: boolean;
163
175
  debug: boolean;
164
176
  /** Master reconciliation: TUI shutdown widget (MEGACOMPACT_TUI_WIDGET=0 to disable). */
165
177
  tuiWidget: boolean;
178
+ /** S57 B1: Query reformulation via embedding-neighbor keyword expansion. */
179
+ ragQueryReformulation: boolean;
180
+ /** S57 B2: Tiered recall router (L0 cache -> L1 FTS5 -> L2). */
181
+ ragTieredRouter: boolean;
182
+ /** S57 B3: Recall quality metrics (precision/recall scoring + logging). */
183
+ ragRecallMetrics: boolean;
184
+ /** S57 B4: Memory graph traversal (dashboard-oriented). */
185
+ ragMemoryGraph: boolean;
166
186
  }
167
187
 
168
188
  function envFlag(name: string, fallback: number): number {
@@ -306,6 +326,7 @@ export function loadConfig(): MegaConfig {
306
326
  "MEGACOMPACT_PROVIDER_OUTAGE_THRESHOLD",
307
327
  3,
308
328
  ),
329
+ advisoryChannel: envBool("MEGACOMPACT_ADVISORY_CHANNEL", true),
309
330
  autoPctTrigger,
310
331
  autoInlineK: envFlag("MEGACOMPACT_AUTO_INLINE_K", 3),
311
332
  dedupSim: Number(process.env.MEGACOMPACT_DEDUP_SIM ?? "0.9"),
@@ -322,7 +343,13 @@ export function loadConfig(): MegaConfig {
322
343
  memoryReviewInterval: envFlag("MEGACOMPACT_MEMORY_REVIEW_INTERVAL", 10),
323
344
  recallMaxTokens: envFlag("MEGACOMPACT_RECALL_MAX_TOKENS", 1500),
324
345
  windowDedupe: envBool("MEGACOMPACT_WINDOW_DEDUPE", true),
346
+ recallTailInject: envBool("MEGACOMPACT_RECALL_TAIL_INJECT", true),
347
+ messageSeparation: envBool("MEGACOMPACT_MESSAGE_SEPARATION", false),
325
348
  tuiWidget: envBool("MEGACOMPACT_TUI_WIDGET", true),
349
+ ragQueryReformulation: envBool("MEGACOMPACT_QUERY_REFORMULATION", false),
350
+ ragTieredRouter: envBool("MEGACOMPACT_TIERED_ROUTER", false),
351
+ ragRecallMetrics: envBool("MEGACOMPACT_RECALL_METRICS", false),
352
+ ragMemoryGraph: envBool("MEGACOMPACT_MEMORY_GRAPH", false),
326
353
  // D.1: env-overridable recompact delta (minimum context growth % before
327
354
  // re-compacting instead of replaying the cached live trim). Default 50.
328
355
  recompactPctDelta: envFlag("MEGACOMPACT_RECOMPACT_PCT_DELTA", 50),
@@ -189,7 +189,10 @@ export function registerAgentHandlers(
189
189
  setTimeout(() => {
190
190
  try {
191
191
  if (runtime.rt.sessionId !== liveSid) return; // session reset
192
- const since2 = now - (runtime.rt.lastNativeCompactAt ?? 0);
192
+ // IMPORTANT: recompute Date.now() inside the timeout.
193
+ // `now` above is the durable-trim handler's timestamp and can be
194
+ // ~500ms stale by the time this callback runs.
195
+ const since2 = Date.now() - (runtime.rt.lastNativeCompactAt ?? 0);
193
196
  if (
194
197
  runtime.rt.lastNativeCompactAt !== stamp &&
195
198
  since2 < cooldownMs
@@ -267,6 +270,16 @@ export function registerAgentHandlers(
267
270
  runtime.dashboard.event("turn_end", { turnIndex: event.turnIndex });
268
271
  runtime.snapshot(ctx);
269
272
 
273
+ // S53: consume staged recall blocks ONLY if they were actually injected
274
+ // into a view this turn. If no context event fired (edge: turn ended
275
+ // before any LLM call), recallInjectedThisTurn stays false and the blocks
276
+ // remain staged for the next turn's first context event.
277
+ if (config.recallTailInject && runtime.rt.recallInjectedThisTurn) {
278
+ runtime.pendingRecallBlock = undefined;
279
+ runtime.pendingMemoryRecallBlock = undefined;
280
+ runtime.rt.recallInjectedThisTurn = false;
281
+ }
282
+
270
283
  // S43 (per-turn tracking): record one turn row with the cached metrics so
271
284
  // the turn layer is queryable + forkable. Best-effort + non-fatal: a write
272
285
  // failure never breaks the agent loop.
@@ -571,9 +584,12 @@ export function registerAgentHandlers(
571
584
  rawText: (errSig || '').slice(0, 500),
572
585
  ...(detail.httpStatus !== undefined ? { httpStatus: detail.httpStatus } : {}),
573
586
  });
574
- // (b) one-per-session advise message (throttled by poisonedAdviseSent)
575
- if (!runtime.rt.poisonedAdviseSent) {
576
- runtime.rt.poisonedAdviseSent = true;
587
+ // (b) throttle flag: set unconditionally so the advise fires at
588
+ // most once per session regardless of channel.
589
+ runtime.rt.poisonedAdviseSent = true;
590
+ // Legacy flag-OFF path: user-role advise message.
591
+ // Default ON (advisoryChannel=true): dashboard-only, no user message.
592
+ if (!config.advisoryChannel) {
577
593
  // PREVENT-PI-003: user-role sendUserMessage only.
578
594
  await safeSendUserMessage(
579
595
  pi,
@@ -69,6 +69,7 @@ async function nudgeResume(pi: ExtensionAPI, runtime: MegaRuntime): Promise<void
69
69
  const now = Date.now();
70
70
  if (now >= runtime.resumeNudgeUntil) {
71
71
  runtime.resumeNudgeUntil = now + 30_000;
72
+ runtime.rt.extensionInitiatedTurn = true; // R13: suppress self-classification
72
73
  await safeSendUserMessage(
73
74
  pi,
74
75
  "[mega-compact] continue from the compacted context above.",
@@ -13,10 +13,8 @@ import type {
13
13
  import type { AgentMessage } from "@earendil-works/pi-agent-core";
14
14
  import {
15
15
  openStore,
16
- appendRawTranscript,
17
16
  writeCheckpointEpoch,
18
17
  type CheckpointEpoch,
19
- type RawTranscriptRow,
20
18
  } from "../../src/store/sqlite.js";
21
19
  import { epochIdFor } from "../../src/mirror/epoch.js";
22
20
  import { autoCompactCheck } from "../../src/compact.js";
@@ -37,84 +35,9 @@ import {
37
35
  pressureRatio,
38
36
  type MegaConfig,
39
37
  } from "../mega-config.js";
40
- import { computeContentDigest } from "../../src/dedup/digest.js";
41
-
42
- /**
43
- * Recursively canonicalize a value for deterministic JSON serialization:
44
- * - Objects: keys sorted alphabetically, values recursively canonicalized
45
- * - Arrays: elements recursively canonicalized (array ORDER is preserved)
46
- * - Primitives: returned as-is
47
- *
48
- * F5 fix: shallow-sorted JSON.stringify(content, Object.keys(content).sort())
49
- * omitted nested keys not in the top-level keys array and only sorted one level.
50
- * This recursively sorts every object at every depth so semantically-equal
51
- * differently-ordered content hashes identically.
52
- */
53
- function canonicalize(value: unknown): unknown {
54
- if (value === null || value === undefined) return value;
55
- if (typeof value !== "object") return value;
56
- if (Array.isArray(value)) return value.map(canonicalize);
57
- // Plain object: sort keys, recursively canonicalize values.
58
- const sorted = Object.keys(value as Record<string, unknown>).sort();
59
- const out: Record<string, unknown> = {};
60
- for (const k of sorted) {
61
- out[k] = canonicalize((value as Record<string, unknown>)[k]);
62
- }
63
- return out;
64
- }
65
-
66
- /**
67
- * Convert a pi AgentMessage to a RawTranscriptRow for the DB mirror.
68
- * content_bytes is canonical JSON (sorted keys, recursive) for deterministic
69
- * storage; contentHash is the canonical digest (normalize + hash) that matches
70
- * what dedupTranscript computes so the two pipelines use the same linkage key.
71
- *
72
- * F4 fix: the hash key MUST match on both sides of the append/dedup split.
73
- * Using computeContentDigest here (normalize → hash) ensures content_ref set
74
- * by dedupTranscript always resolves to an existing dedup_mirror row even for
75
- * whitespace/case-variant content. F5 fix: recursive canonicalize replaces the
76
- * broken shallow-sorted JSON.stringify replacer.
77
- */
78
- function toRawTranscriptRow(
79
- msg: AgentMessage,
80
- sessionId: string,
81
- epochId: string,
82
- currentTurn?: number,
83
- ): RawTranscriptRow | null {
84
- // Narrow to Message union (has content + timestamp).
85
- const m = msg as {
86
- role?: string;
87
- content?: unknown;
88
- timestamp?: number;
89
- toolName?: string;
90
- };
91
- const content = m.content;
92
- if (content == null || content === "") return null;
93
- // Canonical bytes: string content → normalize for consistent byte content;
94
- // object content → recursive canonicalize then JSON (no replacer).
95
- const contentBytes =
96
- typeof content === "string"
97
- ? content // F5: strings are primitives; their byte content is fixed
98
- : JSON.stringify(canonicalize(content));
99
- // F4 fix: use the same digest as dedupTranscript so contentHash is consistent
100
- // on both sides of the append/dedup split. computeContentDigest normalizes
101
- // (strip ANSI, NFC, case-fold, collapse whitespace) then hashes → the same
102
- // key is stored in raw_transcript.content_hash AND used as the dedup link.
103
- const { contentHash } = computeContentDigest(contentBytes);
104
- return {
105
- contentHash,
106
- sessionId,
107
- seq: 0, // assigned by appendRawTranscript (COALESCE(MAX(seq),0)+1)
108
- role: m.role ?? "unknown",
109
- contentBytes,
110
- toolName: m.toolName ?? null,
111
- messageTimestamp: m.timestamp ?? null,
112
- checkpointEpoch: epochId,
113
- // S50: label the row with the turn that produced it (per-turn dedup /
114
- // compression-by-turn metrics). Null when the writer omits it (back-compat).
115
- turnIndex: currentTurn ?? null,
116
- };
117
- }
38
+ import { appendMirrorMessages } from "./mirror-append.js";
39
+ import { stagedForTail, withRecallTail } from "./recall-tail.js";
40
+ import { buildSeparatedPrompt } from "./separated-prompt.js";
118
41
 
119
42
  /** Register the context event handler (live-trim auto-trigger). */
120
43
  export function registerContextHandler(
@@ -140,6 +63,23 @@ export function registerContextHandler(
140
63
  const usage = ctx.getContextUsage();
141
64
  const pct = usage?.percent;
142
65
  const messages = event.messages;
66
+ // S53: helper to inject the staged recall/memory block as a user-role
67
+ // tail message at any view-return point. Returns undefined when nothing
68
+ // is staged (or the flag is OFF) so the caller falls through to its
69
+ // normal return. The F3 mirror append (above the gates) runs on the
70
+ // REAL transcript before any view is built, so the injected tail never
71
+ // reaches raw_transcript (PREVENT-PI: append-only, view-only).
72
+ const tailResult = (msgs?: readonly AgentMessage[]) => {
73
+ const base = msgs ?? messages;
74
+ if (!stagedForTail(runtime, config) && !config.messageSeparation) return undefined;
75
+ let result: AgentMessage[] = stagedForTail(runtime, config)
76
+ ? withRecallTail(base, runtime, config)
77
+ : (base as AgentMessage[]);
78
+ if (config.messageSeparation) {
79
+ result = buildSeparatedPrompt(result);
80
+ }
81
+ return { messages: result };
82
+ };
143
83
  // Always track context for the dashboard/widget, even when auto is off.
144
84
  // (v0.8 regression: !config.auto gate sat above this, leaving ctx stats
145
85
  // null -> widget '?% / ?/?' when auto disabled. Track first, THEN gate.)
@@ -162,30 +102,35 @@ export function registerContextHandler(
162
102
  runtime.lastCtxPercent = pct ?? null;
163
103
  runtime.lastCtxWindow = usage?.contextWindow ?? 0;
164
104
  runtime.snapshot(ctx);
165
- if (!config.auto) return;
105
+ if (!config.auto) {
106
+ const tailed = tailResult();
107
+ if (tailed) return tailed;
108
+ return;
109
+ }
166
110
 
167
111
  const view = viewForFallback ?? runtime.engineView(messages);
168
112
 
169
- // S27 DB-mirror: append ALL incoming messages to raw_transcript.
170
- // Runs BEFORE fast-gate so every message is captured, even if we
171
- // don't compact this turn. Append is idempotent (content_hash PK).
172
- if (config.dbMirror) {
173
- try {
174
- const db = openStore(runtime.currentStateDir);
175
- const epochId = epochIdFor(runtime.rt.sessionId);
176
- for (const msg of messages) {
177
- const raw = toRawTranscriptRow(
178
- msg,
113
+ // S27 DB-mirror: append incoming messages to raw_transcript.
114
+ // Runs BEFORE fast-gate so every message is captured, even if we
115
+ // don't compact this turn. Append is idempotent (content_hash PK).
116
+ // F3: high-water mark (mirror-append.ts) skips already-processed
117
+ // messages on subsequent events. On fork/rewind (shorter list or
118
+ // boundary hash mismatch) the mark is dropped, falling back to a
119
+ // full reprocess.
120
+ if (config.dbMirror) {
121
+ try {
122
+ const db = openStore(runtime.currentStateDir);
123
+ appendMirrorMessages(
124
+ db,
125
+ messages,
179
126
  runtime.rt.sessionId,
180
- epochId,
127
+ epochIdFor(runtime.rt.sessionId),
181
128
  runtime.currentTurn,
182
129
  );
183
- if (raw) appendRawTranscript(db, raw);
130
+ } catch (e) {
131
+ runtime.logger.warn("db-mirror-append-fail", { error: String(e) });
184
132
  }
185
- } catch (e) {
186
- runtime.logger.warn("db-mirror-append-fail", { error: String(e) });
187
133
  }
188
- }
189
134
 
190
135
  // S29 FAST GATE: drive the auto-trigger off the context % (the number the
191
136
  // menu bar shows), NOT the token count — the model under-reports tokens,
@@ -205,18 +150,18 @@ export function registerContextHandler(
205
150
  // custom tier OR tiered-but-pct-unavailable → token gate (S27 fallback).
206
151
  if (currentTokens < runtime.effectiveThreshold) {
207
152
  runtime.diagCtxFastGate++;
208
- return;
153
+ return tailResult() ?? undefined;
209
154
  }
210
155
  const check = autoCompactCheck(currentTokens, runtime.effectiveThreshold); // SERVER-STYLE CONFIRM (local)
211
156
  if (!check.shouldCompact) {
212
157
  runtime.diagCtxNoCompact++;
213
- return;
158
+ return tailResult() ?? undefined;
214
159
  }
215
160
  gatePassed = true;
216
161
  }
217
162
  if (!gatePassed) {
218
163
  runtime.diagCtxFastGate++;
219
- return;
164
+ return tailResult() ?? undefined;
220
165
  }
221
166
 
222
167
  // D.2: Replay MUST be exempt from debounce — replay is free (no compute,
@@ -249,9 +194,8 @@ export function registerContextHandler(
249
194
  runtime.snapshot(ctx);
250
195
  // v0.8.7: shallow-copy the cached summary so pi's transformContext can't
251
196
  // mutate the shared reference across replays (audit P3).
252
- return {
253
- messages: [{ ...runtime.trimCache.summaryAgentMsg }, ...recent],
254
- };
197
+ const replayView = [{ ...runtime.trimCache.summaryAgentMsg }, ...recent];
198
+ return tailResult(replayView) ?? { messages: replayView };
255
199
  }
256
200
  // else: context grew enough → fall through to re-compact (cache is stale)
257
201
  }
@@ -261,7 +205,7 @@ export function registerContextHandler(
261
205
  const now = Date.now();
262
206
  if (now < runtime.debounceUntil) {
263
207
  runtime.diagCtxDebounce++;
264
- return;
208
+ return tailResult() ?? undefined;
265
209
  }
266
210
  runtime.debounceUntil = now + 2000;
267
211
 
@@ -290,11 +234,10 @@ export function registerContextHandler(
290
234
  runtime.diagLiveTrimFires++;
291
235
  runtime.diagLiveTrimReplays++;
292
236
  runtime.snapshot(ctx);
293
- return {
294
- messages: [{ ...runtime.trimCache.summaryAgentMsg }, ...recent],
295
- };
237
+ const skipView = [{ ...runtime.trimCache.summaryAgentMsg }, ...recent];
238
+ return tailResult(skipView) ?? { messages: skipView };
296
239
  }
297
- return;
240
+ return tailResult() ?? undefined;
298
241
  }
299
242
 
300
243
  // S27 DB-mirror: write checkpoint_epoch with deterministic nonce.
@@ -460,7 +403,7 @@ export function registerContextHandler(
460
403
  viewLen: view.length,
461
404
  anchorUserMessages,
462
405
  });
463
- return; // unsafe / below anchor floor — no trim this call
406
+ return tailResult() ?? undefined; // unsafe / below anchor floor — no trim this call
464
407
  }
465
408
  const summaryMsg = liveTrimSummaryMessage({
466
409
  compactedFrom: ran.result.compactedFrom,
@@ -515,10 +458,10 @@ export function registerContextHandler(
515
458
  ctxPct: pct,
516
459
  ctxTokens: usage?.tokens ?? null,
517
460
  });
518
- return { messages: [summaryAgentMsg, ...recent] };
461
+ return tailResult([summaryAgentMsg, ...recent]) ?? { messages: [summaryAgentMsg, ...recent] };
519
462
  } catch {
520
463
  runtime.diagCtxThrown++;
521
- return; // non-fatal: no trim this call; the next context event retries
464
+ return tailResult() ?? undefined; // non-fatal: no trim this call; the next context event retries
522
465
  }
523
466
  });
524
467
  }