pi-mega-compact 0.13.5 → 0.13.7

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 (234) hide show
  1. package/dist/extensions/dashboard-server/api-contracts/endpoints/registry.js +50 -0
  2. package/dist/extensions/dashboard-server/api-contracts/rag-metrics.js +1 -0
  3. package/dist/extensions/dashboard-server/api-contracts/rag-settings.js +3 -3
  4. package/dist/extensions/dashboard-server/api-contracts/wiki.js +1 -0
  5. package/dist/extensions/dashboard-server/index-reader.js +3 -1
  6. package/dist/extensions/dashboard-server/resolve-snapshot.js +81 -0
  7. package/dist/extensions/dashboard-server/routes-core.js +8 -3
  8. package/dist/extensions/dashboard-server/routes-rag-metrics.js +60 -0
  9. package/dist/extensions/dashboard-server/routes-rag-settings-helpers.js +167 -0
  10. package/dist/extensions/dashboard-server/routes-rag-settings.js +136 -77
  11. package/dist/extensions/dashboard-server/routes-repo.js +5 -1
  12. package/dist/extensions/dashboard-server/routes-sessions.js +6 -3
  13. package/dist/extensions/dashboard-server/routes-wiki-helpers.js +97 -0
  14. package/dist/extensions/dashboard-server/routes-wiki.js +330 -0
  15. package/dist/extensions/dashboard-server/routes.js +2 -0
  16. package/dist/extensions/dashboard-server/server.js +17 -3
  17. package/dist/extensions/mega-events/context-handler/afterCompact.js +35 -2
  18. package/dist/extensions/mega-pipeline/recall.js +31 -0
  19. package/dist/extensions/mega-runtime/capture-model.js +5 -2
  20. package/dist/extensions/mega-turn-store.js +2 -1
  21. package/dist/src/config/turns.js +10 -0
  22. package/dist/src/config.js +2 -0
  23. package/dist/src/pricing.js +8 -0
  24. package/dist/src/recall/async.js +10 -1
  25. package/dist/src/recall/format.js +10 -1
  26. package/dist/src/recall/hydeTelemetry.js +22 -0
  27. package/dist/src/recall/sync.js +28 -2
  28. package/dist/src/store/turns/hydeStore.js +32 -0
  29. package/dist/src/store/turns/index.js +1 -0
  30. package/dist/src/store/turns/schema.js +102 -1
  31. package/dist/src/store/turns/sqlite-store/rows.js +23 -0
  32. package/dist/src/store/turns/sqlite-store/write.js +7 -3
  33. package/dist/src/topics/durability.js +187 -0
  34. package/dist/src/topics/index.js +2 -1
  35. package/dist/src/topics/store.js +28 -9
  36. package/dist/src/wiki/curation-helpers.js +71 -0
  37. package/dist/src/wiki/curation.js +147 -0
  38. package/dist/src/wiki/incremental.js +126 -0
  39. package/dist/src/wiki/index.js +5 -0
  40. package/extensions/dashboard-client/dist/assets/AreaChart-j2VOSRp6.js +70 -0
  41. package/extensions/dashboard-client/dist/assets/{SessionsTab-C30AwyoF.js.map → AreaChart-j2VOSRp6.js.map} +1 -1
  42. package/extensions/dashboard-client/dist/assets/CacheTab-Dr1HeMfc.js +2 -0
  43. package/extensions/dashboard-client/dist/assets/CacheTab-Dr1HeMfc.js.map +1 -0
  44. package/extensions/dashboard-client/dist/assets/EventsTab-DRG2k7FS.js +2 -0
  45. package/extensions/dashboard-client/dist/assets/EventsTab-DRG2k7FS.js.map +1 -0
  46. package/extensions/dashboard-client/dist/assets/HealthTab-DGE9PpW3.js +2 -0
  47. package/extensions/dashboard-client/dist/assets/HealthTab-DGE9PpW3.js.map +1 -0
  48. package/extensions/dashboard-client/dist/assets/MaintenanceTab-DeYRhF4q.js +2 -0
  49. package/extensions/dashboard-client/dist/assets/MaintenanceTab-DeYRhF4q.js.map +1 -0
  50. package/extensions/dashboard-client/dist/assets/MemoryMapTab-DSnSO3nG.js +2 -0
  51. package/extensions/dashboard-client/dist/assets/MemoryMapTab-DSnSO3nG.js.map +1 -0
  52. package/extensions/dashboard-client/dist/assets/MetricsTab-RIzNc1Uj.js +2 -0
  53. package/extensions/dashboard-client/dist/assets/MetricsTab-RIzNc1Uj.js.map +1 -0
  54. package/extensions/dashboard-client/dist/assets/OverviewTab-_1BJ4Bmh.js +2 -0
  55. package/extensions/dashboard-client/dist/assets/OverviewTab-_1BJ4Bmh.js.map +1 -0
  56. package/extensions/dashboard-client/dist/assets/ReposTab-DkU7ywZB.js +2 -0
  57. package/extensions/dashboard-client/dist/assets/ReposTab-DkU7ywZB.js.map +1 -0
  58. package/extensions/dashboard-client/dist/assets/SessionsTab-Bq_F_aOk.js +2 -0
  59. package/extensions/dashboard-client/dist/assets/SessionsTab-Bq_F_aOk.js.map +1 -0
  60. package/extensions/dashboard-client/dist/assets/SetupTab-BkBD2Y97.js +2 -0
  61. package/extensions/dashboard-client/dist/assets/SetupTab-BkBD2Y97.js.map +1 -0
  62. package/extensions/dashboard-client/dist/assets/TimeSavedCard-BXzFKU7C.js +2 -0
  63. package/extensions/dashboard-client/dist/assets/TimeSavedCard-BXzFKU7C.js.map +1 -0
  64. package/extensions/dashboard-client/dist/assets/TurnsTab-Bjpp3vBH.js +5 -0
  65. package/extensions/dashboard-client/dist/assets/TurnsTab-Bjpp3vBH.js.map +1 -0
  66. package/extensions/dashboard-client/dist/assets/WikiTab-dBN2EA5G.js +2 -0
  67. package/extensions/dashboard-client/dist/assets/WikiTab-dBN2EA5G.js.map +1 -0
  68. package/extensions/dashboard-client/dist/assets/button-Bt0b5QVp.js +2 -0
  69. package/extensions/dashboard-client/dist/assets/button-Bt0b5QVp.js.map +1 -0
  70. package/extensions/dashboard-client/dist/assets/card-D5CafXtg.js +2 -0
  71. package/extensions/dashboard-client/dist/assets/card-D5CafXtg.js.map +1 -0
  72. package/extensions/dashboard-client/dist/assets/index-CUA6EDRF.css +1 -0
  73. package/extensions/dashboard-client/dist/assets/index-GPHRnEN7.js +137 -0
  74. package/extensions/dashboard-client/dist/assets/index-GPHRnEN7.js.map +1 -0
  75. package/extensions/dashboard-client/dist/assets/pricing-DkYp8-vi.js +2 -0
  76. package/extensions/dashboard-client/dist/assets/pricing-DkYp8-vi.js.map +1 -0
  77. package/extensions/dashboard-client/dist/assets/switch-CY5Gwj1o.js +2 -0
  78. package/extensions/dashboard-client/dist/assets/switch-CY5Gwj1o.js.map +1 -0
  79. package/extensions/dashboard-client/dist/assets/toggle-C9HpkIfH.js +2 -0
  80. package/extensions/dashboard-client/dist/assets/toggle-C9HpkIfH.js.map +1 -0
  81. package/extensions/dashboard-client/dist/assets/{useSSE-p1pOI_-P.js → useSSE-2JFrLDlE.js} +2 -2
  82. package/extensions/dashboard-client/dist/assets/{useSSE-p1pOI_-P.js.map → useSSE-2JFrLDlE.js.map} +1 -1
  83. package/extensions/dashboard-client/dist/index.html +2 -2
  84. package/extensions/dashboard-client/package-lock.json +1995 -191
  85. package/extensions/dashboard-client/package.json +12 -1
  86. package/extensions/dashboard-client/postcss.config.js +6 -0
  87. package/extensions/dashboard-client/src/App.tsx +127 -88
  88. package/extensions/dashboard-client/src/api/client.ts +109 -10
  89. package/extensions/dashboard-client/src/components/ActiveReposTable.tsx +15 -7
  90. package/extensions/dashboard-client/src/components/ActiveSessionsTable.tsx +67 -55
  91. package/extensions/dashboard-client/src/components/CacheHitRateTrendCard.tsx +17 -13
  92. package/extensions/dashboard-client/src/components/CacheHitsCard.tsx +35 -30
  93. package/extensions/dashboard-client/src/components/CacheStatusPerModel.tsx +33 -28
  94. package/extensions/dashboard-client/src/components/EventCategoryFilter.tsx +5 -6
  95. package/extensions/dashboard-client/src/components/EventStream.tsx +17 -13
  96. package/extensions/dashboard-client/src/components/HydeDetailPanel.tsx +173 -0
  97. package/extensions/dashboard-client/src/components/LegendCard.tsx +16 -9
  98. package/extensions/dashboard-client/src/components/PerfCards.tsx +28 -20
  99. package/extensions/dashboard-client/src/components/PerfChart.tsx +9 -6
  100. package/extensions/dashboard-client/src/components/ProviderCacheCard.tsx +15 -7
  101. package/extensions/dashboard-client/src/components/RagDashboard.tsx +253 -0
  102. package/extensions/dashboard-client/src/components/RepoAllSessionsCard.tsx +15 -10
  103. package/extensions/dashboard-client/src/components/RepoContextStack.tsx +24 -16
  104. package/extensions/dashboard-client/src/components/RepoDetailModal.tsx +52 -49
  105. package/extensions/dashboard-client/src/components/RepoTable.tsx +26 -17
  106. package/extensions/dashboard-client/src/components/SessionContextGauges.tsx +11 -14
  107. package/extensions/dashboard-client/src/components/SessionInfo.tsx +20 -15
  108. package/extensions/dashboard-client/src/components/SessionsMemoryChart.tsx +8 -5
  109. package/extensions/dashboard-client/src/components/SummaryTiles.tsx +26 -17
  110. package/extensions/dashboard-client/src/components/TabBar.tsx +1 -3
  111. package/extensions/dashboard-client/src/components/layout/AppShell.tsx +42 -0
  112. package/extensions/dashboard-client/src/components/layout/BottomBar.tsx +88 -0
  113. package/extensions/dashboard-client/src/components/layout/Sidebar.tsx +83 -0
  114. package/extensions/dashboard-client/src/components/ui/badge.tsx +30 -0
  115. package/extensions/dashboard-client/src/components/ui/button.tsx +44 -0
  116. package/extensions/dashboard-client/src/components/ui/card.tsx +32 -0
  117. package/extensions/dashboard-client/src/components/ui/select.tsx +64 -0
  118. package/extensions/dashboard-client/src/components/ui/switch.tsx +26 -0
  119. package/extensions/dashboard-client/src/components/ui/tabs.tsx +36 -0
  120. package/extensions/dashboard-client/src/components/ui/toggle.tsx +28 -0
  121. package/extensions/dashboard-client/src/components/ui/tooltip.tsx +27 -0
  122. package/extensions/dashboard-client/src/config.ts +10 -0
  123. package/extensions/dashboard-client/src/main.tsx +2 -2
  124. package/extensions/dashboard-client/src/memory-map-layout.ts +1 -2
  125. package/extensions/dashboard-client/src/styles/index.css +79 -0
  126. package/extensions/dashboard-client/src/tabs/CacheTab.tsx +33 -26
  127. package/extensions/dashboard-client/src/tabs/EventsTab.tsx +22 -7
  128. package/extensions/dashboard-client/src/tabs/HealthTab.tsx +77 -46
  129. package/extensions/dashboard-client/src/tabs/MaintenanceTab/ActionsCard.tsx +60 -50
  130. package/extensions/dashboard-client/src/tabs/MaintenanceTab/DbStatsCard.tsx +61 -35
  131. package/extensions/dashboard-client/src/tabs/MaintenanceTab/DebugBundleCard.tsx +34 -23
  132. package/extensions/dashboard-client/src/tabs/MaintenanceTab/HealthMitigationCard.tsx +62 -43
  133. package/extensions/dashboard-client/src/tabs/MaintenanceTab/SchemaHealthCard.tsx +53 -32
  134. package/extensions/dashboard-client/src/tabs/MaintenanceTab.tsx +2 -2
  135. package/extensions/dashboard-client/src/tabs/MemoryMapTab/MemoryMapView.tsx +29 -46
  136. package/extensions/dashboard-client/src/tabs/MemoryMapTab/RaptorTreeView.tsx +10 -34
  137. package/extensions/dashboard-client/src/tabs/MemoryMapTab.tsx +14 -34
  138. package/extensions/dashboard-client/src/tabs/MetricsTab.tsx +5 -2
  139. package/extensions/dashboard-client/src/tabs/OverviewTab.tsx +11 -5
  140. package/extensions/dashboard-client/src/tabs/ReposTab.tsx +5 -5
  141. package/extensions/dashboard-client/src/tabs/SessionsTab.tsx +47 -33
  142. package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderSetup.tsx +6 -2
  143. package/extensions/dashboard-client/src/tabs/SetupTab/RagHealthCard.tsx +78 -0
  144. package/extensions/dashboard-client/src/tabs/SetupTab/SettingsPanel.tsx +198 -0
  145. package/extensions/dashboard-client/src/tabs/SetupTab/SettingsSection.tsx +50 -0
  146. package/extensions/dashboard-client/src/tabs/SetupTab.tsx +21 -59
  147. package/extensions/dashboard-client/src/tabs/TopicsTab.tsx +75 -40
  148. package/extensions/dashboard-client/src/tabs/TurnsTab.tsx +150 -112
  149. package/extensions/dashboard-client/src/tabs/WikiTab/TopicEvolutionGraph.tsx +274 -0
  150. package/extensions/dashboard-client/src/tabs/WikiTab/TopicEvolutionView.tsx +71 -0
  151. package/extensions/dashboard-client/src/tabs/WikiTab/TopicTimeline.tsx +103 -0
  152. package/extensions/dashboard-client/src/tabs/WikiTab/WikiPage.tsx +213 -0
  153. package/extensions/dashboard-client/src/tabs/WikiTab/WikiPageControls.tsx +188 -0
  154. package/extensions/dashboard-client/src/tabs/WikiTab.tsx +222 -0
  155. package/extensions/dashboard-client/src/tabs/registry.ts +57 -0
  156. package/extensions/dashboard-client/src/utils/cn.ts +7 -0
  157. package/extensions/dashboard-client/tailwind.config.js +46 -0
  158. package/extensions/dashboard-server/api-contracts/core.ts +59 -0
  159. package/extensions/dashboard-server/api-contracts/endpoints/registry.ts +79 -0
  160. package/extensions/dashboard-server/api-contracts/index.ts +48 -2
  161. package/extensions/dashboard-server/api-contracts/rag-metrics.ts +22 -0
  162. package/extensions/dashboard-server/api-contracts/rag-settings.ts +30 -20
  163. package/extensions/dashboard-server/api-contracts/wiki.ts +138 -0
  164. package/extensions/dashboard-server/index-reader.ts +3 -1
  165. package/extensions/dashboard-server/resolve-snapshot.ts +98 -0
  166. package/extensions/dashboard-server/routes-core.ts +8 -3
  167. package/extensions/dashboard-server/routes-rag-metrics.ts +82 -0
  168. package/extensions/dashboard-server/routes-rag-settings-helpers.ts +314 -0
  169. package/extensions/dashboard-server/routes-rag-settings.ts +147 -97
  170. package/extensions/dashboard-server/routes-repo.ts +5 -1
  171. package/extensions/dashboard-server/routes-sessions.ts +6 -3
  172. package/extensions/dashboard-server/routes-wiki-helpers.ts +126 -0
  173. package/extensions/dashboard-server/routes-wiki.ts +376 -0
  174. package/extensions/dashboard-server/routes.ts +2 -0
  175. package/extensions/dashboard-server/server.ts +18 -2
  176. package/extensions/mega-events/context-handler/afterCompact.ts +44 -1
  177. package/extensions/mega-pipeline/recall.ts +31 -0
  178. package/extensions/mega-runtime/capture-model.ts +5 -2
  179. package/extensions/mega-turn-store.ts +13 -0
  180. package/package.json +1 -1
  181. package/src/config/turns.ts +17 -0
  182. package/src/config.ts +3 -0
  183. package/src/pricing.ts +8 -0
  184. package/src/recall/async.ts +10 -1
  185. package/src/recall/format.ts +15 -2
  186. package/src/recall/hydeTelemetry.ts +44 -0
  187. package/src/recall/sync.ts +34 -2
  188. package/src/recall/types.ts +36 -0
  189. package/src/store/turns/hydeStore.ts +82 -0
  190. package/src/store/turns/index.ts +4 -0
  191. package/src/store/turns/schema.ts +126 -1
  192. package/src/store/turns/sqlite-store/rows.ts +25 -0
  193. package/src/store/turns/sqlite-store/write.ts +20 -2
  194. package/src/store/turns/types.ts +33 -0
  195. package/src/topics/durability.ts +231 -0
  196. package/src/topics/index.ts +7 -1
  197. package/src/topics/store.ts +35 -9
  198. package/src/wiki/curation-helpers.ts +140 -0
  199. package/src/wiki/curation.ts +217 -0
  200. package/src/wiki/incremental.ts +164 -0
  201. package/src/wiki/index.ts +13 -0
  202. package/extensions/dashboard-client/dist/assets/CacheTab-Cqnc7lMg.js +0 -2
  203. package/extensions/dashboard-client/dist/assets/CacheTab-Cqnc7lMg.js.map +0 -1
  204. package/extensions/dashboard-client/dist/assets/EventsTab-tYk3VFAp.js +0 -2
  205. package/extensions/dashboard-client/dist/assets/EventsTab-tYk3VFAp.js.map +0 -1
  206. package/extensions/dashboard-client/dist/assets/HealthTab-D2_kjgxw.js +0 -2
  207. package/extensions/dashboard-client/dist/assets/HealthTab-D2_kjgxw.js.map +0 -1
  208. package/extensions/dashboard-client/dist/assets/MaintenanceTab-Bc-uPYrz.js +0 -2
  209. package/extensions/dashboard-client/dist/assets/MaintenanceTab-Bc-uPYrz.js.map +0 -1
  210. package/extensions/dashboard-client/dist/assets/MemoryMapTab-D1V9g_NC.js +0 -2
  211. package/extensions/dashboard-client/dist/assets/MemoryMapTab-D1V9g_NC.js.map +0 -1
  212. package/extensions/dashboard-client/dist/assets/MetricsTab-DT_XfL96.js +0 -2
  213. package/extensions/dashboard-client/dist/assets/MetricsTab-DT_XfL96.js.map +0 -1
  214. package/extensions/dashboard-client/dist/assets/OverviewTab-BY6KZCme.js +0 -2
  215. package/extensions/dashboard-client/dist/assets/OverviewTab-BY6KZCme.js.map +0 -1
  216. package/extensions/dashboard-client/dist/assets/ReposTab-CeS-tpDM.js +0 -2
  217. package/extensions/dashboard-client/dist/assets/ReposTab-CeS-tpDM.js.map +0 -1
  218. package/extensions/dashboard-client/dist/assets/SessionsTab-C30AwyoF.js +0 -70
  219. package/extensions/dashboard-client/dist/assets/SetupTab-BJUHOVK2.js +0 -2
  220. package/extensions/dashboard-client/dist/assets/SetupTab-BJUHOVK2.js.map +0 -1
  221. package/extensions/dashboard-client/dist/assets/TimeSavedCard-p55K1tFP.js +0 -2
  222. package/extensions/dashboard-client/dist/assets/TimeSavedCard-p55K1tFP.js.map +0 -1
  223. package/extensions/dashboard-client/dist/assets/TopicsTab-D8FqyAbK.js +0 -2
  224. package/extensions/dashboard-client/dist/assets/TopicsTab-D8FqyAbK.js.map +0 -1
  225. package/extensions/dashboard-client/dist/assets/TurnsTab-ju-nXDys.js +0 -2
  226. package/extensions/dashboard-client/dist/assets/TurnsTab-ju-nXDys.js.map +0 -1
  227. package/extensions/dashboard-client/dist/assets/index-BEj1Zahy.js +0 -42
  228. package/extensions/dashboard-client/dist/assets/index-BEj1Zahy.js.map +0 -1
  229. package/extensions/dashboard-client/dist/assets/index-CUNn22iV.css +0 -1
  230. package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js +0 -2
  231. package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js.map +0 -1
  232. package/extensions/dashboard-client/src/styles/metrics-extra.css +0 -69
  233. package/extensions/dashboard-client/src/styles/turns.css +0 -142
  234. package/extensions/dashboard-client/src/tabs/SetupTab/RagSettingsCard.tsx +0 -160
@@ -1,9 +1,13 @@
1
1
  /**
2
- * dashboard-server/routes-rag-settings.ts — RAG Settings route handler.
2
+ * dashboard-server/routes-rag-settings.ts — comprehensive settings route handler.
3
3
  *
4
- * GET /api/rag-settings — Returns the state of all RAG feature flags (B1–B5).
5
- * POST /api/rag-settings Toggles flags by writing MEGACOMPACT_*_DISABLED
6
- * lines to the per-repo .mega-compact.env file.
4
+ * GET /api/rag-settings — Returns every adjustable MEGACOMPACT_* setting,
5
+ * grouped by category, with live values from env.
6
+ * POST /api/rag-settings Updates a single setting by writing its line to the
7
+ * per-repo .mega-compact.env file.
8
+ *
9
+ * The SETTINGS inventory lives in routes-rag-settings-helpers.ts so this file
10
+ * stays within the line budget.
7
11
  *
8
12
  * Guardrails: PREVENT-PI-004 (loopback-only), PREVENT-001 (null-safe JSON),
9
13
  * PREVENT-011 (no `any`). Each JSON write carries a guardrails-allow annotation.
@@ -11,47 +15,83 @@
11
15
  import { readFileSync, existsSync, writeFileSync, mkdirSync } from "node:fs";
12
16
  import { join } from "node:path";
13
17
  import { detectCurrentEmbedder } from "./routes-setup.js";
18
+ import { SETTINGS, SETTING_BY_KEY } from "./routes-rag-settings-helpers.js";
14
19
  // ---------------------------------------------------------------------------
15
- // RAG_FLAGSthe five feature flags surfaced by this panel.
20
+ // Env-reading helpers one per setting type.
16
21
  // ---------------------------------------------------------------------------
17
- const RAG_FLAGS = [
18
- {
19
- key: "MEGACOMPACT_QUERY_REFORMULATION",
20
- label: "Query Reformulation",
21
- description: "TF-IDF keyword expansion for vague recall queries (TrigramEmbedder path)",
22
- requiresLlm: false,
23
- },
24
- {
25
- key: "MEGACOMPACT_TIERED_ROUTER",
26
- label: "Tiered Recall Router",
27
- description: "L0 cache → L1 FTS5 → L2 HNSW routing for faster recall",
28
- requiresLlm: false,
29
- },
30
- {
31
- key: "MEGACOMPACT_RECALL_METRICS",
32
- label: "Recall Quality Metrics",
33
- description: "Precision/recall scoring and logging for recall evaluation",
34
- requiresLlm: false,
35
- },
36
- {
37
- key: "MEGACOMPACT_MEMORY_GRAPH",
38
- label: "Memory Graph",
39
- description: "Dashboard-oriented memory graph traversal across sessions",
40
- requiresLlm: false,
41
- },
42
- {
43
- key: "MEGACOMPACT_HYDE",
44
- label: "HyDE (Hypothetical Document Embeddings)",
45
- description: "Generate hypothetical answer via LLM, embed it, RRF-fuse with raw-query results",
46
- requiresLlm: true,
47
- },
48
- ];
49
- /** Strip any MEGACOMPACT_*_DISABLED assignment lines from env file content. */
50
- const DISABLED_LINE = /^export\s+MEGACOMPACT_\w+_DISABLED=/;
51
22
  function isDisabled(key) {
52
23
  const v = process.env[key + "_DISABLED"];
53
24
  return v === "true" || v === "1";
54
25
  }
26
+ function isEnabled(key, def) {
27
+ const v = process.env[key];
28
+ if (v === undefined)
29
+ return def;
30
+ return v === "true" || v === "1";
31
+ }
32
+ function readNumber(key, def) {
33
+ const v = process.env[key];
34
+ if (v === undefined)
35
+ return def;
36
+ const n = Number(v);
37
+ return Number.isNaN(n) ? def : n;
38
+ }
39
+ function resolveValue(spec) {
40
+ if (spec.type === "boolean") {
41
+ return spec.disabledConvention
42
+ ? !isDisabled(spec.key)
43
+ : isEnabled(spec.key, spec.default);
44
+ }
45
+ if (spec.type === "number") {
46
+ return readNumber(spec.key, spec.default);
47
+ }
48
+ return process.env[spec.key] ?? spec.default;
49
+ }
50
+ function toSettingState(spec, category) {
51
+ return {
52
+ key: spec.key,
53
+ label: spec.label,
54
+ description: spec.description,
55
+ category,
56
+ type: spec.type,
57
+ value: resolveValue(spec),
58
+ default: spec.default,
59
+ disabledConvention: spec.disabledConvention,
60
+ requiresLlm: spec.requiresLlm,
61
+ ...(spec.unit !== undefined ? { unit: spec.unit } : {}),
62
+ ...(spec.min !== undefined ? { min: spec.min } : {}),
63
+ ...(spec.max !== undefined ? { max: spec.max } : {}),
64
+ };
65
+ }
66
+ // ---------------------------------------------------------------------------
67
+ // Env file I/O.
68
+ // ---------------------------------------------------------------------------
69
+ /** Strip lines assigning KEY or KEY_DISABLED from env file content. */
70
+ const keyLinePattern = (key) => new RegExp(`^export\\s+${key}(_DISABLED)?=`);
71
+ function envPathOf(ctx) {
72
+ return join(ctx.stateDir, ".mega-compact.env");
73
+ }
74
+ function readEnvLines(envPath, key) {
75
+ if (!existsSync(envPath))
76
+ return [];
77
+ return readFileSync(envPath, "utf-8")
78
+ .split("\n")
79
+ .filter((l) => !keyLinePattern(key).test(l));
80
+ }
81
+ function writeSetting(envPath, key, line) {
82
+ const lines = readEnvLines(envPath, key);
83
+ lines.push(line);
84
+ if (lines[lines.length - 1] !== "")
85
+ lines.push("");
86
+ writeFileSync(envPath, lines.join("\n"), "utf-8");
87
+ }
88
+ /** Strip KEY/KEY_DISABLED lines, leaving the file otherwise intact. */
89
+ function removeSetting(envPath, key) {
90
+ writeFileSync(envPath, readEnvLines(envPath, key).join("\n"), "utf-8");
91
+ }
92
+ // ---------------------------------------------------------------------------
93
+ // Request body parsing.
94
+ // ---------------------------------------------------------------------------
55
95
  function readJsonBody(req, cb) {
56
96
  let body = "";
57
97
  let tooBig = false;
@@ -85,15 +125,12 @@ export function handleRagSettings(req, res, ctx) {
85
125
  if (req.url !== "/api/rag-settings")
86
126
  return false;
87
127
  if (req.method === "GET") {
88
- const flags = RAG_FLAGS.map((f) => ({
89
- key: f.key,
90
- label: f.label,
91
- description: f.description,
92
- enabled: !isDisabled(f.key),
93
- requiresLlm: f.requiresLlm,
128
+ const categories = SETTINGS.map((cat) => ({
129
+ name: cat.name,
130
+ settings: cat.settings.map((s) => toSettingState(s, cat.name)),
94
131
  }));
95
132
  const body = {
96
- flags,
133
+ categories,
97
134
  llmActive: detectCurrentEmbedder() === "http",
98
135
  };
99
136
  // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
@@ -109,47 +146,63 @@ export function handleRagSettings(req, res, ctx) {
109
146
  res.end(JSON.stringify({ error: parsed.error }));
110
147
  return;
111
148
  }
112
- const body = parsed.value;
113
- const desired = body.flags;
114
- if (typeof desired !== "object" || desired === null || Array.isArray(desired)) {
149
+ const reqBody = parsed.value;
150
+ const key = reqBody.key;
151
+ const value = reqBody.value;
152
+ if (typeof key !== "string" || typeof value !== "string") {
115
153
  // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
116
154
  res.writeHead(400, { "Content-Type": "application/json" });
117
- res.end(JSON.stringify({ error: "invalid_flags" }));
155
+ res.end(JSON.stringify({ error: "invalid_body" }));
118
156
  return;
119
157
  }
120
- // Only accept known RAG flag keys.
121
- const known = new Set(RAG_FLAGS.map((f) => f.key));
122
- for (const key of Object.keys(desired)) {
123
- if (!known.has(key)) {
124
- // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
125
- res.writeHead(400, { "Content-Type": "application/json" });
126
- res.end(JSON.stringify({ error: `unknown_flag: ${key}` }));
127
- return;
128
- }
129
- }
130
- const envPath = join(ctx.stateDir, ".mega-compact.env");
131
- let lines = [];
132
- if (existsSync(envPath)) {
133
- const content = readFileSync(envPath, "utf-8");
134
- lines = content.split("\n").filter((line) => !DISABLED_LINE.test(line));
135
- }
136
- for (const key of Object.keys(desired)) {
137
- if (desired[key] === false) {
138
- lines.push(`export ${key}_DISABLED="true"`);
139
- }
158
+ const spec = SETTING_BY_KEY.get(key);
159
+ if (!spec) {
160
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
161
+ res.writeHead(400, { "Content-Type": "application/json" });
162
+ res.end(JSON.stringify({ error: `unknown_setting: ${key}` }));
163
+ return;
140
164
  }
141
- if (lines.length > 0 && lines[lines.length - 1] !== "")
142
- lines.push("");
165
+ const envPath = envPathOf(ctx);
143
166
  try {
144
167
  mkdirSync(ctx.stateDir, { recursive: true });
145
- writeFileSync(envPath, lines.join("\n"), "utf-8");
168
+ if (spec.type === "boolean") {
169
+ if (value !== "true" && value !== "false") {
170
+ throw new SettingError("boolean_value_required");
171
+ }
172
+ if (spec.disabledConvention) {
173
+ // false → opt out via KEY_DISABLED="true"; true → strip the line.
174
+ if (value === "false") {
175
+ writeSetting(envPath, spec.key, `export ${spec.key}_DISABLED="true"`);
176
+ }
177
+ else {
178
+ removeSetting(envPath, spec.key);
179
+ }
180
+ }
181
+ else {
182
+ writeSetting(envPath, spec.key, `export ${spec.key}="${value}"`);
183
+ }
184
+ }
185
+ else if (spec.type === "number") {
186
+ const n = Number(value);
187
+ if (Number.isNaN(n))
188
+ throw new SettingError("invalid_number");
189
+ if (spec.min !== undefined && n < spec.min)
190
+ throw new SettingError("below_min");
191
+ if (spec.max !== undefined && n > spec.max)
192
+ throw new SettingError("above_max");
193
+ writeSetting(envPath, spec.key, `export ${spec.key}="${n}"`);
194
+ }
195
+ else {
196
+ writeSetting(envPath, spec.key, `export ${spec.key}="${value}"`);
197
+ }
146
198
  }
147
199
  catch (e) {
200
+ const msg = e instanceof SettingError
201
+ ? e.message
202
+ : `write_failed: ${e instanceof Error ? e.message : String(e)}`;
148
203
  // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
149
- res.writeHead(500, { "Content-Type": "application/json" });
150
- res.end(JSON.stringify({
151
- error: `write_failed: ${e instanceof Error ? e.message : String(e)}`,
152
- }));
204
+ res.writeHead(400, { "Content-Type": "application/json" });
205
+ res.end(JSON.stringify({ error: msg }));
153
206
  return;
154
207
  }
155
208
  const resp = {
@@ -167,3 +220,9 @@ export function handleRagSettings(req, res, ctx) {
167
220
  res.end(JSON.stringify({ error: "method_not_allowed" }));
168
221
  return true;
169
222
  }
223
+ class SettingError extends Error {
224
+ constructor(message) {
225
+ super(message);
226
+ this.name = "SettingError";
227
+ }
228
+ }
@@ -4,6 +4,7 @@
4
4
  import { existsSync, readFileSync } from "node:fs";
5
5
  import { join } from "node:path";
6
6
  import { readSnapshot } from "./snapshot.js";
7
+ import { resolveSnapshot } from "./resolve-snapshot.js";
7
8
  import { dashboardHtml } from "./html.js";
8
9
  import { readIndex, getIndexDir } from "./index-reader.js";
9
10
  import { ACTIVE_WINDOW_SEC } from "./types.js";
@@ -26,7 +27,10 @@ export function handleIndex(req, res, ctx) {
26
27
  return true;
27
28
  }
28
29
  if (req.url === "/api/snapshot") {
29
- const snap = readSnapshot(snapshotPath);
30
+ // Dynamically resolve the most recently active session's dashboard.json
31
+ // so the Overview shows live data from the repo pi is running in — not
32
+ // the stale launcher dir the server was started with.
33
+ const { snapshot: snap } = resolveSnapshot(snapshotPath, ctx.stateDir);
30
34
  res.writeHead(200, { "Content-Type": "application/json" });
31
35
  res.end(JSON.stringify(snap));
32
36
  return true;
@@ -16,10 +16,13 @@ export function handleEvents(req, res, ctx) {
16
16
  "Cache-Control": "no-cache",
17
17
  Connection: "keep-alive",
18
18
  });
19
- // Drain existing events so the client starts with history
19
+ // Drain existing events so the client starts with history.
20
+ // Only stream events with a "type" field — events.log also contains
21
+ // internal monitoring rows (e.g. captureModel:recorded) that use "event"
22
+ // instead of "type" and aren't part of the SseEvent contract.
20
23
  const { data: existing, offset: initialOffset } = readFrom(eventsPath, 0);
21
24
  eventOffsetRef.value = initialOffset;
22
- const lines = existing.split("\n").filter((l) => l.trim());
25
+ const lines = existing.split("\n").filter((l) => l.trim() && l.includes('"type"'));
23
26
  for (const line of lines) {
24
27
  res.write(`data: ${line}\n\n`);
25
28
  }
@@ -32,7 +35,7 @@ export function handleEvents(req, res, ctx) {
32
35
  watchTimer = null;
33
36
  const { data, offset } = readFrom(eventsPath, eventOffsetRef.value);
34
37
  eventOffsetRef.value = offset;
35
- const newLines = data.split("\n").filter((l) => l.trim());
38
+ const newLines = data.split("\n").filter((l) => l.trim() && l.includes('"type"'));
36
39
  for (const line of newLines) {
37
40
  res.write(`data: ${line}\n\n`);
38
41
  }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * routes-wiki-helpers.ts — shared read/build helpers for routes-wiki.ts.
3
+ *
4
+ * Content access, index-entry resolution, provenance + time-bucket builders,
5
+ * lazy topic-model build, and SSE emission. Kept out of the dispatcher so
6
+ * routes-wiki.ts stays a thin pointer. Loopback-only (PREVENT-PI-004),
7
+ * parameterized (PREVENT-002).
8
+ */
9
+ import { appendFileSync } from "node:fs";
10
+ import { openStore } from "../../src/store/sqlite.js";
11
+ import { createTopicStore } from "../../src/topics/store.js";
12
+ import { buildTopicModel } from "../../src/topics/cluster.js";
13
+ /** Append a JSONL SSE line to events.log (best-effort, non-fatal). */
14
+ export function emitWikiEvent(ctx, event) {
15
+ try {
16
+ appendFileSync(ctx.eventsPath, JSON.stringify({ ts: new Date().toISOString(), ...event }) + "\n");
17
+ }
18
+ catch {
19
+ /* non-fatal: SSE push best-effort */
20
+ }
21
+ }
22
+ /** Lazy-build the topic model when the topics table is empty (best-effort). */
23
+ export function ensureWikiBuilt(ctx, tdb) {
24
+ const topicCount = tdb.prepare("SELECT COUNT(*) AS c FROM topics").get().c;
25
+ if (topicCount > 0)
26
+ return;
27
+ try {
28
+ const mainDb = openStore(ctx.stateDir);
29
+ const model = buildTopicModel(mainDb);
30
+ if (model.k > 0 && model.totalChunks > 0) {
31
+ createTopicStore(ctx.stateDir).replaceTopicModel(model);
32
+ }
33
+ }
34
+ catch {
35
+ /* non-fatal: lazy wiki build is best-effort */
36
+ }
37
+ }
38
+ /** Build a topic index entry with resolved label + override badges. */
39
+ export function toIndexEntry(topic, curation) {
40
+ const resolved = curation.resolveLabel(topic.id, topic.label);
41
+ return {
42
+ id: topic.id,
43
+ label: resolved.label,
44
+ memoryCount: topic.memoryCount,
45
+ lastUpdated: topic.lastUpdated,
46
+ edited: resolved.edited,
47
+ overrideKinds: curation.overrideKinds(topic.id),
48
+ };
49
+ }
50
+ /** Convert a member assignment into contract provenance. */
51
+ export function toProvenance(member) {
52
+ return {
53
+ memoryId: member.memoryId,
54
+ sessionId: member.sessionId ?? "",
55
+ assignedAt: member.assignedAt,
56
+ method: member.method,
57
+ };
58
+ }
59
+ /** Bucket epoch-ms values by day; returns ascending [{bucket, count}]. */
60
+ export function bucketize(values) {
61
+ const DAY = 86_400_000;
62
+ const counts = new Map();
63
+ for (const v of values) {
64
+ if (!Number.isFinite(v) || v <= 0)
65
+ continue;
66
+ const b = Math.floor(v / DAY) * DAY;
67
+ counts.set(b, (counts.get(b) ?? 0) + 1);
68
+ }
69
+ return [...counts.entries()]
70
+ .sort((a, b) => a[0] - b[0])
71
+ .map(([bucket, count]) => ({ bucket, count }));
72
+ }
73
+ /** Fetch member content (text + timestamp) from the main DB. */
74
+ export function memberContent(ctx, members) {
75
+ const out = new Map();
76
+ if (members.length === 0)
77
+ return out;
78
+ try {
79
+ const mainDb = openStore(ctx.stateDir);
80
+ for (const m of members) {
81
+ const row = mainDb
82
+ .prepare(`SELECT COALESCE(normalized_text, summary, topic_summary) AS text, timestamp
83
+ FROM context_chunks WHERE session_id = ? AND id = ?`)
84
+ .get(m.sessionId ?? "", m.memoryId);
85
+ if (row) {
86
+ out.set(m.memoryId, {
87
+ text: (row.text ?? "").trim(),
88
+ timestamp: row.timestamp ?? 0,
89
+ });
90
+ }
91
+ }
92
+ }
93
+ catch {
94
+ /* content fetch is best-effort */
95
+ }
96
+ return out;
97
+ }