pi-mega-compact 0.11.4 → 0.11.5

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 (307) hide show
  1. package/dist/extensions/dashboard-server/api-contracts/endpoints.js +19 -0
  2. package/dist/extensions/dashboard-server/api-contracts/memory.js +8 -0
  3. package/dist/extensions/dashboard-server/api-contracts/provider-cache.js +1 -0
  4. package/dist/extensions/dashboard-server/api-contracts/setup.js +10 -0
  5. package/dist/extensions/dashboard-server/index-reader.js +6 -2
  6. package/dist/extensions/dashboard-server/routes-cache.js +115 -55
  7. package/dist/extensions/dashboard-server/routes-memory.js +51 -0
  8. package/dist/extensions/dashboard-server/routes-repo.js +2 -2
  9. package/dist/extensions/dashboard-server/routes-setup.js +162 -0
  10. package/dist/extensions/dashboard-server/routes.js +2 -0
  11. package/dist/extensions/dashboard-server/server.js +7 -1
  12. package/dist/extensions/mega-commands.js +189 -1
  13. package/dist/extensions/mega-config.js +2 -0
  14. package/dist/extensions/mega-events/agent-handlers.js +19 -4
  15. package/dist/extensions/mega-events/compact-handlers.js +1 -0
  16. package/dist/extensions/mega-events/context-handler.js +37 -92
  17. package/dist/extensions/mega-events/context-hwm.js +51 -0
  18. package/dist/extensions/mega-events/error-classifier.js +16 -5
  19. package/dist/extensions/mega-events/mirror-append.js +107 -0
  20. package/dist/extensions/mega-events/outage-advisor.js +7 -1
  21. package/dist/extensions/mega-events/perf-handler.js +51 -1
  22. package/dist/extensions/mega-events/recall-tail.js +59 -0
  23. package/dist/extensions/mega-events/session-handlers.js +15 -8
  24. package/dist/extensions/mega-runtime/reset-runtime.js +5 -0
  25. package/dist/extensions/mega-runtime/runtime.js +6 -0
  26. package/dist/src/embedder.js +41 -2
  27. package/dist/src/memoryStats.js +75 -0
  28. package/dist/src/prefix-break.js +43 -0
  29. package/dist/src/pricing.js +1 -1
  30. package/dist/src/store/sqlite/perf-samples.js +144 -16
  31. package/dist/src/store/turns/memory-store.js +8 -0
  32. package/dist/src/store/turns/sqlite-store.js +14 -3
  33. package/dist/src/store/turns/types.js +18 -1
  34. package/dist/src/store/vectorIndex.js +26 -5
  35. package/extensions/dashboard-client/dist/assets/{AchievementTiles-vEo2MtE2.js → AchievementTiles-BoL7qBOJ.js} +2 -2
  36. package/extensions/dashboard-client/dist/assets/{AchievementTiles-vEo2MtE2.js.map → AchievementTiles-BoL7qBOJ.js.map} +1 -1
  37. package/extensions/dashboard-client/dist/assets/AchievementsTab-BFDE3HYc.js +2 -0
  38. package/extensions/dashboard-client/dist/assets/{AchievementsTab-DjxfYrDc.js.map → AchievementsTab-BFDE3HYc.js.map} +1 -1
  39. package/extensions/dashboard-client/dist/assets/CacheTab-eKVc-NV1.js +2 -0
  40. package/extensions/dashboard-client/dist/assets/CacheTab-eKVc-NV1.js.map +1 -0
  41. package/extensions/dashboard-client/dist/assets/{ConfigTab-Cm6ymbmx.js → ConfigTab-DDFE-ckA.js} +2 -2
  42. package/extensions/dashboard-client/dist/assets/{ConfigTab-Cm6ymbmx.js.map → ConfigTab-DDFE-ckA.js.map} +1 -1
  43. package/extensions/dashboard-client/dist/assets/{EventsTab-DXWl_YzI.js → EventsTab-B6UxZ7PM.js} +2 -2
  44. package/extensions/dashboard-client/dist/assets/{EventsTab-DXWl_YzI.js.map → EventsTab-B6UxZ7PM.js.map} +1 -1
  45. package/extensions/dashboard-client/dist/assets/{GameTab-BLDudcO5.js → GameTab-DehUX-KE.js} +2 -2
  46. package/extensions/dashboard-client/dist/assets/{GameTab-BLDudcO5.js.map → GameTab-DehUX-KE.js.map} +1 -1
  47. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DLkKCztn.js → MaintenanceTab-0GWRt4wn.js} +2 -2
  48. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DLkKCztn.js.map → MaintenanceTab-0GWRt4wn.js.map} +1 -1
  49. package/extensions/dashboard-client/dist/assets/{MetricsTab-Cq4u-rZF.js → MetricsTab-C3rwMVsN.js} +2 -2
  50. package/extensions/dashboard-client/dist/assets/{MetricsTab-Cq4u-rZF.js.map → MetricsTab-C3rwMVsN.js.map} +1 -1
  51. package/extensions/dashboard-client/dist/assets/OverviewTab-39O9_x5j.js +2 -0
  52. package/extensions/dashboard-client/dist/assets/{OverviewTab-D4kGvsiQ.js.map → OverviewTab-39O9_x5j.js.map} +1 -1
  53. package/extensions/dashboard-client/dist/assets/ReposTab-Cfj6Q5sH.js +2 -0
  54. package/extensions/dashboard-client/dist/assets/ReposTab-Cfj6Q5sH.js.map +1 -0
  55. package/extensions/dashboard-client/dist/assets/{SessionsTab-DZC2-GCn.js → SessionsTab-DXDTCi3r.js} +2 -2
  56. package/extensions/dashboard-client/dist/assets/{SessionsTab-DZC2-GCn.js.map → SessionsTab-DXDTCi3r.js.map} +1 -1
  57. package/extensions/dashboard-client/dist/assets/SetupTab-mMlfunJa.js +2 -0
  58. package/extensions/dashboard-client/dist/assets/SetupTab-mMlfunJa.js.map +1 -0
  59. package/extensions/dashboard-client/dist/assets/TimeSavedCard-Cw1dJ4e9.js +2 -0
  60. package/extensions/dashboard-client/dist/assets/TimeSavedCard-Cw1dJ4e9.js.map +1 -0
  61. package/extensions/dashboard-client/dist/assets/{TopicsTab-01G71hv1.js → TopicsTab-BAw972BV.js} +2 -2
  62. package/extensions/dashboard-client/dist/assets/{TopicsTab-01G71hv1.js.map → TopicsTab-BAw972BV.js.map} +1 -1
  63. package/extensions/dashboard-client/dist/assets/{TurnsTab-DLRg0LZT.js → TurnsTab-Cf5mGIdl.js} +2 -2
  64. package/extensions/dashboard-client/dist/assets/{TurnsTab-DLRg0LZT.js.map → TurnsTab-Cf5mGIdl.js.map} +1 -1
  65. package/extensions/dashboard-client/dist/assets/format-COjDIVGj.js +2 -0
  66. package/extensions/dashboard-client/dist/assets/format-COjDIVGj.js.map +1 -0
  67. package/extensions/dashboard-client/dist/assets/{index-BX0bcgLu.js → index-4gQ7auad.js} +10 -10
  68. package/extensions/dashboard-client/dist/assets/index-4gQ7auad.js.map +1 -0
  69. package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js +2 -0
  70. package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js.map +1 -0
  71. package/extensions/dashboard-client/dist/assets/{useSSE-BBYt5UPB.js → useSSE-DNgMuyP6.js} +2 -2
  72. package/extensions/dashboard-client/dist/assets/{useSSE-BBYt5UPB.js.map → useSSE-DNgMuyP6.js.map} +1 -1
  73. package/extensions/dashboard-client/dist/index.html +1 -1
  74. package/extensions/dashboard-client/src/App.tsx +4 -0
  75. package/extensions/dashboard-client/src/api/client.ts +14 -0
  76. package/extensions/dashboard-client/src/components/ActiveReposTable.tsx +21 -12
  77. package/extensions/dashboard-client/src/components/ProviderCacheCard.tsx +56 -0
  78. package/extensions/dashboard-client/src/components/SavingsByModelTable.tsx +38 -57
  79. package/extensions/dashboard-client/src/tabs/CacheTab.tsx +1 -0
  80. package/extensions/dashboard-client/src/tabs/SetupTab.tsx +355 -0
  81. package/extensions/dashboard-client/tsconfig.json +3 -2
  82. package/extensions/dashboard-client/vite.config.ts +2 -0
  83. package/extensions/dashboard-server/api-contracts/endpoints.ts +36 -3
  84. package/extensions/dashboard-server/api-contracts/index.ts +7 -0
  85. package/extensions/dashboard-server/api-contracts/memory.ts +27 -0
  86. package/extensions/dashboard-server/api-contracts/multi-repo.ts +231 -231
  87. package/extensions/dashboard-server/api-contracts/provider-cache.ts +37 -0
  88. package/extensions/dashboard-server/api-contracts/setup.ts +58 -0
  89. package/extensions/dashboard-server/index-reader.ts +138 -121
  90. package/extensions/dashboard-server/routes-cache.ts +161 -85
  91. package/extensions/dashboard-server/routes-memory.ts +63 -0
  92. package/extensions/dashboard-server/routes-repo.ts +36 -36
  93. package/extensions/dashboard-server/routes-setup.ts +181 -0
  94. package/extensions/dashboard-server/routes.ts +2 -0
  95. package/extensions/dashboard-server/server.ts +6 -0
  96. package/extensions/mega-commands.ts +211 -1
  97. package/extensions/mega-config.ts +10 -0
  98. package/extensions/mega-events/agent-handlers.ts +20 -4
  99. package/extensions/mega-events/compact-handlers.ts +1 -0
  100. package/extensions/mega-events/context-handler.ts +45 -110
  101. package/extensions/mega-events/context-hwm.ts +85 -0
  102. package/extensions/mega-events/error-classifier.ts +15 -4
  103. package/extensions/mega-events/mirror-append.ts +155 -0
  104. package/extensions/mega-events/outage-advisor.ts +11 -5
  105. package/extensions/mega-events/perf-handler.ts +79 -5
  106. package/extensions/mega-events/recall-tail.ts +88 -0
  107. package/extensions/mega-events/session-handlers.ts +14 -7
  108. package/extensions/mega-runtime/helpers.ts +12 -0
  109. package/extensions/mega-runtime/reset-runtime.ts +5 -0
  110. package/extensions/mega-runtime/runtime.ts +6 -0
  111. package/package.json +5 -2
  112. package/src/embedder.ts +42 -2
  113. package/src/memoryStats.ts +107 -0
  114. package/src/prefix-break.ts +83 -0
  115. package/src/pricing.ts +2 -2
  116. package/src/store/sqlite/perf-samples.ts +215 -22
  117. package/src/store/turns/memory-store.ts +10 -1
  118. package/src/store/turns/sqlite-store.ts +27 -15
  119. package/src/store/turns/types.ts +21 -0
  120. package/src/store/vectorIndex.ts +33 -4
  121. package/dist/extensions/conflict-scan.test.js +0 -115
  122. package/dist/extensions/dashboard-server/api-contracts.test.js +0 -884
  123. package/dist/extensions/dashboard-server/html.test.js +0 -52
  124. package/dist/extensions/dashboard-server/perf-server.test.js +0 -80
  125. package/dist/extensions/dashboard-server/routes-cache.test.js +0 -248
  126. package/dist/extensions/dashboard-server/server.test.js +0 -120
  127. package/dist/extensions/dashboard-server-s32.test.js +0 -181
  128. package/dist/extensions/dashboard-server.test.js +0 -339
  129. package/dist/extensions/mega-cache-replay.test.js +0 -400
  130. package/dist/extensions/mega-compact-s38.test.js +0 -1383
  131. package/dist/extensions/mega-compact.test.js +0 -1112
  132. package/dist/extensions/mega-events.test.js +0 -47
  133. package/dist/extensions/mega-game-cmds.test.js +0 -163
  134. package/dist/extensions/mega-runtime/snapshot.test.js +0 -127
  135. package/dist/extensions/mega-runtime/state.test.js +0 -266
  136. package/dist/extensions/mega-runtime/widget.test.js +0 -343
  137. package/dist/extensions/mega-shutdown-widget.test.js +0 -121
  138. package/dist/extensions/mega-teamrun.test.js +0 -156
  139. package/dist/extensions/mega-trim.test.js +0 -58
  140. package/dist/extensions/mega-turn-store.test.js +0 -68
  141. package/dist/src/boundary.test.js +0 -170
  142. package/dist/src/compact.test.js +0 -78
  143. package/dist/src/config/themes.test.js +0 -94
  144. package/dist/src/dedup/dedup.test.js +0 -41
  145. package/dist/src/dedup/l1.test.js +0 -50
  146. package/dist/src/dedup/raptor/buildHistory.test.js +0 -292
  147. package/dist/src/dedup/raptor/multilevel-serve.test.js +0 -229
  148. package/dist/src/dedup/raptor/multilevel.test.js +0 -238
  149. package/dist/src/dedup/raptor/promote.test.js +0 -69
  150. package/dist/src/dedup/raptor/raptor.test.js +0 -248
  151. package/dist/src/dedup/raptor/retrieval.test.js +0 -95
  152. package/dist/src/dedup/raptor/serve-gate.test.js +0 -298
  153. package/dist/src/dedup/sprint12.test.js +0 -219
  154. package/dist/src/dedup-engine.test.js +0 -472
  155. package/dist/src/driftDetection.test.js +0 -87
  156. package/dist/src/e2e.test.js +0 -698
  157. package/dist/src/engine.test.js +0 -111
  158. package/dist/src/extractive.test.js +0 -147
  159. package/dist/src/fork.test.js +0 -81
  160. package/dist/src/game/scoring.test.js +0 -98
  161. package/dist/src/httpEmbedder.test.js +0 -277
  162. package/dist/src/importance.test.js +0 -372
  163. package/dist/src/intent.test.js +0 -78
  164. package/dist/src/log.test.js +0 -42
  165. package/dist/src/mechanical-fix.test.js +0 -65
  166. package/dist/src/memory.test.js +0 -70
  167. package/dist/src/memoryConsolidate.test.js +0 -38
  168. package/dist/src/memoryOps.test.js +0 -129
  169. package/dist/src/memoryRecall.test.js +0 -171
  170. package/dist/src/memoryRoundtrip.test.js +0 -137
  171. package/dist/src/metrics/turns.test.js +0 -152
  172. package/dist/src/mirror/mirror.test.js +0 -185
  173. package/dist/src/raptor-inject-summaries.test.js +0 -162
  174. package/dist/src/ratio.bench.test.js +0 -897
  175. package/dist/src/recall.integration.test.js +0 -77
  176. package/dist/src/recall.test.js +0 -379
  177. package/dist/src/sprint14.test.js +0 -219
  178. package/dist/src/sprint4x-rag-verification.test.js +0 -93
  179. package/dist/src/store/compression.test.js +0 -139
  180. package/dist/src/store/memoryIndex.test.js +0 -51
  181. package/dist/src/store/migrate.test.js +0 -139
  182. package/dist/src/store/pgOpenGuard.test.js +0 -74
  183. package/dist/src/store/phase01.test.js +0 -81
  184. package/dist/src/store/phase04.test.js +0 -54
  185. package/dist/src/store/sprint10.test.js +0 -186
  186. package/dist/src/store/sqlite/game-achievements.test.js +0 -67
  187. package/dist/src/store/sqlite/game-scores.test.js +0 -106
  188. package/dist/src/store/sqlite/game-state.test.js +0 -76
  189. package/dist/src/store/sqlite/global-index.test.js +0 -136
  190. package/dist/src/store/sqlite/mechanical-fix.test.js +0 -146
  191. package/dist/src/store/sqlite/perf-samples.test.js +0 -146
  192. package/dist/src/store/sqlite/raptor.test.js +0 -106
  193. package/dist/src/store/sqlite/turns.test.js +0 -183
  194. package/dist/src/store/sqlite.cachehit.test.js +0 -55
  195. package/dist/src/store/sqlite.dbmaint.test.js +0 -158
  196. package/dist/src/store/sqlite.dbmirror.test.js +0 -184
  197. package/dist/src/store/turns/contract-compliance.test.js +0 -428
  198. package/dist/src/store/turns/memory-store.test.js +0 -9
  199. package/dist/src/store/turns/migrations.test.js +0 -138
  200. package/dist/src/store/turns/sqlite-store.test.js +0 -144
  201. package/dist/src/store/vectorIndex.test.js +0 -123
  202. package/dist/src/store.test.js +0 -161
  203. package/dist/src/supersede.test.js +0 -36
  204. package/dist/src/topics/cluster.test.js +0 -150
  205. package/dist/src/topics/store.test.js +0 -117
  206. package/dist/src/types.test.js +0 -9
  207. package/dist/src/vector-search-cache.test.js +0 -157
  208. package/dist/src/vectorStore.test.js +0 -479
  209. package/dist/src/wiki.test.js +0 -171
  210. package/extensions/conflict-scan.test.ts +0 -129
  211. package/extensions/dashboard-client/dist/assets/AchievementsTab-DjxfYrDc.js +0 -2
  212. package/extensions/dashboard-client/dist/assets/CacheTab-Dnpv94wq.js +0 -2
  213. package/extensions/dashboard-client/dist/assets/CacheTab-Dnpv94wq.js.map +0 -1
  214. package/extensions/dashboard-client/dist/assets/OverviewTab-D4kGvsiQ.js +0 -2
  215. package/extensions/dashboard-client/dist/assets/ReposTab-C0Wnrf2u.js +0 -2
  216. package/extensions/dashboard-client/dist/assets/ReposTab-C0Wnrf2u.js.map +0 -1
  217. package/extensions/dashboard-client/dist/assets/TimeSavedCard-UqljSyP-.js +0 -2
  218. package/extensions/dashboard-client/dist/assets/TimeSavedCard-UqljSyP-.js.map +0 -1
  219. package/extensions/dashboard-client/dist/assets/index-BX0bcgLu.js.map +0 -1
  220. package/extensions/dashboard-server/api-contracts.test.ts +0 -1065
  221. package/extensions/dashboard-server/html.test.ts +0 -62
  222. package/extensions/dashboard-server/perf-server.test.ts +0 -101
  223. package/extensions/dashboard-server/routes-cache.test.ts +0 -302
  224. package/extensions/dashboard-server/server.test.ts +0 -131
  225. package/extensions/dashboard-server-s32.test.ts +0 -195
  226. package/extensions/dashboard-server.test.ts +0 -382
  227. package/extensions/mega-cache-replay.test.ts +0 -526
  228. package/extensions/mega-compact-s38.test.ts +0 -1433
  229. package/extensions/mega-compact.test.ts +0 -1509
  230. package/extensions/mega-events.test.ts +0 -55
  231. package/extensions/mega-game-cmds.test.ts +0 -197
  232. package/extensions/mega-runtime/snapshot.test.ts +0 -139
  233. package/extensions/mega-runtime/state.test.ts +0 -262
  234. package/extensions/mega-runtime/widget.test.ts +0 -468
  235. package/extensions/mega-shutdown-widget.test.ts +0 -141
  236. package/extensions/mega-teamrun.test.ts +0 -176
  237. package/extensions/mega-trim.test.ts +0 -64
  238. package/extensions/mega-turn-store.test.ts +0 -108
  239. package/src/boundary.test.ts +0 -187
  240. package/src/compact.test.ts +0 -99
  241. package/src/config/themes.test.ts +0 -116
  242. package/src/dedup/dedup.test.ts +0 -46
  243. package/src/dedup/l1.test.ts +0 -57
  244. package/src/dedup/raptor/buildHistory.test.ts +0 -353
  245. package/src/dedup/raptor/multilevel-serve.test.ts +0 -273
  246. package/src/dedup/raptor/multilevel.test.ts +0 -325
  247. package/src/dedup/raptor/promote.test.ts +0 -82
  248. package/src/dedup/raptor/raptor.test.ts +0 -297
  249. package/src/dedup/raptor/retrieval.test.ts +0 -118
  250. package/src/dedup/raptor/serve-gate.test.ts +0 -348
  251. package/src/dedup/sprint12.test.ts +0 -242
  252. package/src/dedup-engine.test.ts +0 -670
  253. package/src/driftDetection.test.ts +0 -100
  254. package/src/e2e.test.ts +0 -843
  255. package/src/engine.test.ts +0 -123
  256. package/src/extractive.test.ts +0 -174
  257. package/src/fork.test.ts +0 -94
  258. package/src/game/scoring.test.ts +0 -103
  259. package/src/httpEmbedder.test.ts +0 -286
  260. package/src/importance.test.ts +0 -538
  261. package/src/intent.test.ts +0 -87
  262. package/src/log.test.ts +0 -47
  263. package/src/mechanical-fix.test.ts +0 -70
  264. package/src/memory.test.ts +0 -92
  265. package/src/memoryConsolidate.test.ts +0 -47
  266. package/src/memoryOps.test.ts +0 -148
  267. package/src/memoryRecall.test.ts +0 -194
  268. package/src/memoryRoundtrip.test.ts +0 -155
  269. package/src/metrics/turns.test.ts +0 -165
  270. package/src/mirror/mirror.test.ts +0 -240
  271. package/src/raptor-inject-summaries.test.ts +0 -228
  272. package/src/ratio.bench.test.ts +0 -1316
  273. package/src/recall.integration.test.ts +0 -96
  274. package/src/recall.test.ts +0 -467
  275. package/src/sprint14.test.ts +0 -245
  276. package/src/sprint4x-rag-verification.test.ts +0 -119
  277. package/src/store/compression.test.ts +0 -168
  278. package/src/store/memoryIndex.test.ts +0 -61
  279. package/src/store/migrate.test.ts +0 -158
  280. package/src/store/pgOpenGuard.test.ts +0 -89
  281. package/src/store/phase01.test.ts +0 -88
  282. package/src/store/phase04.test.ts +0 -58
  283. package/src/store/sprint10.test.ts +0 -214
  284. package/src/store/sqlite/game-achievements.test.ts +0 -80
  285. package/src/store/sqlite/game-scores.test.ts +0 -132
  286. package/src/store/sqlite/game-state.test.ts +0 -89
  287. package/src/store/sqlite/global-index.test.ts +0 -222
  288. package/src/store/sqlite/mechanical-fix.test.ts +0 -162
  289. package/src/store/sqlite/perf-samples.test.ts +0 -169
  290. package/src/store/sqlite/raptor.test.ts +0 -139
  291. package/src/store/sqlite/turns.test.ts +0 -218
  292. package/src/store/sqlite.cachehit.test.ts +0 -68
  293. package/src/store/sqlite.dbmaint.test.ts +0 -193
  294. package/src/store/sqlite.dbmirror.test.ts +0 -229
  295. package/src/store/turns/contract-compliance.test.ts +0 -562
  296. package/src/store/turns/memory-store.test.ts +0 -15
  297. package/src/store/turns/migrations.test.ts +0 -161
  298. package/src/store/turns/sqlite-store.test.ts +0 -161
  299. package/src/store/vectorIndex.test.ts +0 -140
  300. package/src/store.test.ts +0 -191
  301. package/src/supersede.test.ts +0 -42
  302. package/src/topics/cluster.test.ts +0 -176
  303. package/src/topics/store.test.ts +0 -132
  304. package/src/types.test.ts +0 -10
  305. package/src/vector-search-cache.test.ts +0 -190
  306. package/src/vectorStore.test.ts +0 -533
  307. package/src/wiki.test.ts +0 -217
@@ -13,7 +13,10 @@ import { ACTIVE_WINDOW_SEC } from "./types.js";
13
13
  import type { RouteContext } from "./routes-core.js";
14
14
  import type { LiveSnapshot } from "./types.js";
15
15
  import { readProviderCacheForRepo } from "../../src/store/sqlite/perf-samples.js";
16
- import { computeCacheSavings, lookupModelInputRate } from "../../src/pricing.js";
16
+ import {
17
+ computeCacheSavings,
18
+ lookupModelInputRate,
19
+ } from "../../src/pricing.js";
17
20
  import { latestModelSnapshot } from "../../src/store/sqlite/model-snapshots.js";
18
21
 
19
22
  // ---------------------------------------------------------------------------
@@ -154,43 +157,42 @@ export function handleRepoIndex(
154
157
  try {
155
158
  const p = join(r.stateDir, "dashboard.json");
156
159
  if (existsSync(p)) {
157
- const snap = JSON.parse(
158
- readFileSync(p, "utf-8"),
159
- ) as LiveSnapshot;
160
+ const snap = JSON.parse(readFileSync(p, "utf-8")) as LiveSnapshot;
160
161
  out.tier = snap.tier ?? null;
161
162
  out.contextPct =
162
163
  snap.context && snap.context.percent != null
163
164
  ? snap.context.percent
164
165
  : null;
165
166
  out.state = (snap.session && snap.session.state) || null;
166
- out.cacheHits = snap.cacheHits ?? null;
167
- out.compacts = snap.compacts ?? null;
168
- out.timeSaved = snap.timeSaved ?? null;
169
- out.updatedAt = snap.updatedAt ?? null;
170
- // Provider cache per-repo lifetime (E.2)
171
- try {
172
- const pc = readProviderCacheForRepo(r.stateDir);
173
- // Price from model snapshot if available
174
- const modelSnap = latestModelSnapshot(r.stateDir);
175
- const inputRate = modelSnap
176
- ? modelSnap.inputRate
177
- : lookupModelInputRate(r.modelName ?? "") ?? 0;
178
- const savings = computeCacheSavings(
179
- pc.totalCacheRead,
180
- pc.totalCacheWrite,
181
- inputRate,
182
- );
183
- out.providerCache = {
184
- avgHitPct: pc.avgHitPct,
185
- cacheRead: pc.totalCacheRead,
186
- cacheWrite: pc.totalCacheWrite,
187
- totalInput: pc.totalInput,
188
- sampleCount: pc.sampleCount,
189
- estimatedSaved: savings.netSaved > 0 ? savings.netSaved : null,
190
- };
191
- } catch {
192
- /* best-effort — repo may not have perf_samples */
193
- }
167
+ out.cacheHits = snap.cacheHits ?? null;
168
+ out.compacts = snap.compacts ?? null;
169
+ out.timeSaved = snap.timeSaved ?? null;
170
+ out.updatedAt = snap.updatedAt ?? null;
171
+ // Provider cache per-repo lifetime (E.2)
172
+ try {
173
+ const pc = readProviderCacheForRepo(r.stateDir);
174
+ // Price from model snapshot if available
175
+ const modelSnap = latestModelSnapshot(r.stateDir);
176
+ const inputRate = modelSnap
177
+ ? modelSnap.inputRate
178
+ : (lookupModelInputRate(r.modelName ?? "") ?? 0);
179
+ const savings = computeCacheSavings(
180
+ pc.totalCacheRead,
181
+ pc.totalCacheWrite,
182
+ inputRate,
183
+ );
184
+ out.providerCache = {
185
+ avgHitPct: pc.avgHitPct,
186
+ cacheRead: pc.totalCacheRead,
187
+ cacheWrite: pc.totalCacheWrite,
188
+ totalInput: pc.totalInput,
189
+ sampleCount: pc.sampleCount,
190
+ estimatedSaved:
191
+ savings.netSaved > 0 ? savings.netSaved : null,
192
+ };
193
+ } catch {
194
+ /* best-effort — repo may not have perf_samples */
195
+ }
194
196
  }
195
197
  } catch {
196
198
  /* best-effort */
@@ -199,9 +201,7 @@ export function handleRepoIndex(
199
201
  })
200
202
  .sort((a, b) => (b.lastSeen as number) - (a.lastSeen as number));
201
203
  res.writeHead(200, { "Content-Type": "application/json" });
202
- res.end(
203
- JSON.stringify({ updatedAt: new Date().toISOString(), servers }),
204
- );
204
+ res.end(JSON.stringify({ updatedAt: new Date().toISOString(), servers }));
205
205
  } catch {
206
206
  res.writeHead(500, { "Content-Type": "application/json" });
207
207
  res.end(JSON.stringify({ error: "servers_unavailable" }));
@@ -236,4 +236,4 @@ export function handleStatic(
236
236
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
237
237
  res.end(dashboardHtml(tier));
238
238
  return true;
239
- }
239
+ }
@@ -0,0 +1,181 @@
1
+ /**
2
+ * dashboard-server/routes-setup.ts — Setup wizard route handlers.
3
+ *
4
+ * GET /api/setup-status — Returns current embedder configuration from env.
5
+ * GET /api/setup-detect — Runs best-effort detection of local embedder backends.
6
+ *
7
+ * Guardrails: PREVENT-PI-004 (loopback-only), PREVENT-001 (null-safe JSON).
8
+ * The detection commands run local subprocesses via spawnSync, NOT network calls.
9
+ * Each decoration line carries a guardrails-allow annotation.
10
+ */
11
+
12
+ import { spawnSync } from "node:child_process"; // guardrails-allow PREVENT-PI-004: local subprocess detection only
13
+ import { createRequire } from "node:module";
14
+ import type { IncomingMessage, ServerResponse } from "node:http";
15
+ import type { RouteContext } from "./routes-core.js";
16
+ import type {
17
+ SetupStatusResponse,
18
+ SetupDetectResponse,
19
+ DetectResult,
20
+ OllamaDetectResult,
21
+ } from "./api-contracts/setup.js";
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // handleSetupStatus — "/api/setup-status"
25
+ // ---------------------------------------------------------------------------
26
+
27
+ function detectCurrentEmbedder(): SetupStatusResponse["currentEmbedder"] {
28
+ const url = process.env["MEGACOMPACT_EMBEDDING_URL"];
29
+ const minilm = process.env["MEGACOMPACT_MINILM"];
30
+ if (url && url.trim().length > 0) return "http";
31
+ if (minilm && ["1", "true", "yes"].includes(minilm.trim().toLowerCase()))
32
+ return "minilm";
33
+ return "trigram";
34
+ }
35
+
36
+ export function handleSetupStatus(
37
+ req: IncomingMessage,
38
+ res: ServerResponse,
39
+ _ctx: RouteContext,
40
+ ): boolean {
41
+ if (req.url !== "/api/setup-status") return false;
42
+ if (req.method !== "GET") {
43
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
44
+ res.writeHead(405, { "Content-Type": "application/json" });
45
+ res.end(JSON.stringify({ error: "method_not_allowed" }));
46
+ return true;
47
+ }
48
+ const body: SetupStatusResponse = {
49
+ currentEmbedder: detectCurrentEmbedder(),
50
+ embeddingUrl: process.env["MEGACOMPACT_EMBEDDING_URL"] ?? null,
51
+ embedCache: process.env["MEGACOMPACT_EMBED_CACHE"] ?? null,
52
+ minilm: ["1", "true", "yes"].includes(
53
+ (process.env["MEGACOMPACT_MINILM"] ?? "").trim().toLowerCase(),
54
+ ),
55
+ };
56
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
57
+ res.writeHead(200, { "Content-Type": "application/json" });
58
+ res.end(JSON.stringify(body));
59
+ return true;
60
+ }
61
+
62
+ // ---------------------------------------------------------------------------
63
+ // handleSetupDetect — "/api/setup-detect"
64
+ // ---------------------------------------------------------------------------
65
+
66
+ function detectOllama(): OllamaDetectResult | null {
67
+ try {
68
+ const version = spawnSync("ollama", ["--version"], {
69
+ timeout: 5000,
70
+ encoding: "utf-8",
71
+ stdio: ["ignore", "pipe", "pipe"],
72
+ });
73
+ if (version.status !== 0) {
74
+ return { installed: false, models: [], running: false, detail: version.stderr?.trim() || "not found" };
75
+ }
76
+ // Check for running server
77
+ let running = false;
78
+ let models: string[] = [];
79
+ try {
80
+ const listResult = spawnSync("ollama", ["list"], {
81
+ timeout: 5000,
82
+ encoding: "utf-8",
83
+ stdio: ["ignore", "pipe", "pipe"],
84
+ });
85
+ if (listResult.status === 0) {
86
+ running = true;
87
+ // Parse lines: NAME ID SIZE MODIFIED
88
+ const lines = listResult.stdout?.split("\n") ?? [];
89
+ for (const line of lines) {
90
+ const name = line.split(/\s+/)[0];
91
+ if (name && name !== "NAME") models.push(name);
92
+ }
93
+ }
94
+ } catch {
95
+ // ollama list failed — server may not be running
96
+ running = false;
97
+ }
98
+ return {
99
+ installed: true,
100
+ models,
101
+ running,
102
+ detail: version.stdout?.trim() || null,
103
+ };
104
+ } catch {
105
+ return { installed: false, models: [], running: false, detail: "detection error" };
106
+ }
107
+ }
108
+
109
+ function detectLlamaCpp(): DetectResult | null {
110
+ try {
111
+ const which = spawnSync("which", ["llama-server", "llama.cpp"], {
112
+ timeout: 3000,
113
+ encoding: "utf-8",
114
+ stdio: ["ignore", "pipe", "pipe"],
115
+ });
116
+ const installed = which.status === 0 && which.stdout.trim().length > 0;
117
+ return {
118
+ installed,
119
+ detail: installed ? which.stdout.trim() : null,
120
+ };
121
+ } catch {
122
+ return { installed: false, detail: "detection error" };
123
+ }
124
+ }
125
+
126
+ function detectOnnx(): DetectResult | null {
127
+ try {
128
+ // Check for onnxruntime-node in a parent node_modules
129
+ const req = createRequire(import.meta.url);
130
+ try {
131
+ req.resolve("onnxruntime-node");
132
+ return { installed: true, detail: "onnxruntime-node found in node_modules" };
133
+ } catch {
134
+ return { installed: false, detail: "onnxruntime-node not found in node_modules" };
135
+ }
136
+ } catch {
137
+ return { installed: false, detail: "detection error" };
138
+ }
139
+ }
140
+
141
+ export function handleSetupDetect(
142
+ req: IncomingMessage,
143
+ res: ServerResponse,
144
+ _ctx: RouteContext,
145
+ ): boolean {
146
+ if (req.url !== "/api/setup-detect") return false;
147
+ if (req.method !== "GET") {
148
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
149
+ res.writeHead(405, { "Content-Type": "application/json" });
150
+ res.end(JSON.stringify({ error: "method_not_allowed" }));
151
+ return true;
152
+ }
153
+ let error: string | null = null;
154
+ let ollama: OllamaDetectResult | null = null;
155
+ let llamaCpp: DetectResult | null = null;
156
+ let onnx: DetectResult | null = null;
157
+
158
+ try {
159
+ ollama = detectOllama();
160
+ } catch (e) {
161
+ error = `ollama detection failed: ${e instanceof Error ? e.message : String(e)}`;
162
+ }
163
+
164
+ try {
165
+ llamaCpp = detectLlamaCpp();
166
+ } catch (e) {
167
+ error = error ?? `llama.cpp detection failed: ${e instanceof Error ? e.message : String(e)}`;
168
+ }
169
+
170
+ try {
171
+ onnx = detectOnnx();
172
+ } catch (e) {
173
+ error = error ?? `onnx detection failed: ${e instanceof Error ? e.message : String(e)}`;
174
+ }
175
+
176
+ const body: SetupDetectResponse = { ollama, llamaCpp, onnx, error };
177
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
178
+ res.writeHead(200, { "Content-Type": "application/json" });
179
+ res.end(JSON.stringify(body));
180
+ return true;
181
+ }
@@ -20,3 +20,5 @@ export { handleTopics } from "./routes-topics.js";
20
20
  export { handleTurns } from "./routes-turns.js";
21
21
  export { handleMaintenance } from "./routes-maintenance.js";
22
22
  export { handleProviderCache } from "./routes-cache.js";
23
+ export { handleMemoryStatus } from "./routes-memory.js";
24
+ export { handleSetupStatus, handleSetupDetect } from "./routes-setup.js";
@@ -38,6 +38,9 @@ import {
38
38
  handleTurns,
39
39
  handleMaintenance,
40
40
  handleProviderCache,
41
+ handleMemoryStatus,
42
+ handleSetupStatus,
43
+ handleSetupDetect,
41
44
  handleStatic,
42
45
  } from "./routes.js";
43
46
 
@@ -227,6 +230,9 @@ export async function launchDashboardServer(
227
230
  if (handleTurns(req, res, ctx)) return;
228
231
  if (handleMaintenance(req, res, ctx)) return;
229
232
  if (handleProviderCache(req, res, ctx)) return;
233
+ if (handleMemoryStatus(req, res, ctx)) return;
234
+ if (handleSetupStatus(req, res, ctx)) return;
235
+ if (handleSetupDetect(req, res, ctx)) return;
230
236
  handleStatic(req, res, ctx);
231
237
  });
232
238
 
@@ -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.
@@ -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,6 +164,10 @@ 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;
163
171
  debug: boolean;
164
172
  /** Master reconciliation: TUI shutdown widget (MEGACOMPACT_TUI_WIDGET=0 to disable). */
165
173
  tuiWidget: boolean;
@@ -306,6 +314,7 @@ export function loadConfig(): MegaConfig {
306
314
  "MEGACOMPACT_PROVIDER_OUTAGE_THRESHOLD",
307
315
  3,
308
316
  ),
317
+ advisoryChannel: envBool("MEGACOMPACT_ADVISORY_CHANNEL", true),
309
318
  autoPctTrigger,
310
319
  autoInlineK: envFlag("MEGACOMPACT_AUTO_INLINE_K", 3),
311
320
  dedupSim: Number(process.env.MEGACOMPACT_DEDUP_SIM ?? "0.9"),
@@ -322,6 +331,7 @@ export function loadConfig(): MegaConfig {
322
331
  memoryReviewInterval: envFlag("MEGACOMPACT_MEMORY_REVIEW_INTERVAL", 10),
323
332
  recallMaxTokens: envFlag("MEGACOMPACT_RECALL_MAX_TOKENS", 1500),
324
333
  windowDedupe: envBool("MEGACOMPACT_WINDOW_DEDUPE", true),
334
+ recallTailInject: envBool("MEGACOMPACT_RECALL_TAIL_INJECT", true),
325
335
  tuiWidget: envBool("MEGACOMPACT_TUI_WIDGET", true),
326
336
  // D.1: env-overridable recompact delta (minimum context growth % before
327
337
  // re-compacting instead of replaying the cached live trim). Default 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.",