pi-mega-compact 0.13.4 → 0.13.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 (217) hide show
  1. package/README.md +11 -8
  2. package/dist/extensions/dashboard-server/api-contracts/endpoints/registry.js +50 -0
  3. package/dist/extensions/dashboard-server/api-contracts/rag-metrics.js +1 -0
  4. package/dist/extensions/dashboard-server/api-contracts/rag-settings.js +3 -3
  5. package/dist/extensions/dashboard-server/api-contracts/wiki.js +1 -0
  6. package/dist/extensions/dashboard-server/routes-rag-metrics.js +60 -0
  7. package/dist/extensions/dashboard-server/routes-rag-settings-helpers.js +167 -0
  8. package/dist/extensions/dashboard-server/routes-rag-settings.js +136 -77
  9. package/dist/extensions/dashboard-server/routes-wiki-helpers.js +97 -0
  10. package/dist/extensions/dashboard-server/routes-wiki.js +330 -0
  11. package/dist/extensions/dashboard-server/routes.js +2 -0
  12. package/dist/extensions/dashboard-server/server.js +17 -3
  13. package/dist/extensions/mega-events/context-handler/afterCompact.js +35 -2
  14. package/dist/extensions/mega-pipeline/recall.js +31 -0
  15. package/dist/extensions/mega-turn-store.js +2 -1
  16. package/dist/src/config/turns.js +10 -0
  17. package/dist/src/config.js +2 -0
  18. package/dist/src/recall/async.js +10 -1
  19. package/dist/src/recall/format.js +10 -1
  20. package/dist/src/recall/hydeTelemetry.js +22 -0
  21. package/dist/src/recall/sync.js +28 -2
  22. package/dist/src/store/turns/hydeStore.js +32 -0
  23. package/dist/src/store/turns/index.js +1 -0
  24. package/dist/src/store/turns/schema.js +102 -1
  25. package/dist/src/store/turns/sqlite-store/rows.js +23 -0
  26. package/dist/src/store/turns/sqlite-store/write.js +7 -3
  27. package/dist/src/topics/durability.js +187 -0
  28. package/dist/src/topics/index.js +2 -1
  29. package/dist/src/topics/store.js +28 -9
  30. package/dist/src/wiki/curation-helpers.js +71 -0
  31. package/dist/src/wiki/curation.js +147 -0
  32. package/dist/src/wiki/incremental.js +126 -0
  33. package/dist/src/wiki/index.js +5 -0
  34. package/extensions/dashboard-client/dist/assets/AreaChart-KAmp_6bL.js +70 -0
  35. package/extensions/dashboard-client/dist/assets/{SessionsTab-C30AwyoF.js.map → AreaChart-KAmp_6bL.js.map} +1 -1
  36. package/extensions/dashboard-client/dist/assets/CacheTab-Bk-gm-R0.js +2 -0
  37. package/extensions/dashboard-client/dist/assets/CacheTab-Bk-gm-R0.js.map +1 -0
  38. package/extensions/dashboard-client/dist/assets/EventsTab-Cyylo0of.js +2 -0
  39. package/extensions/dashboard-client/dist/assets/EventsTab-Cyylo0of.js.map +1 -0
  40. package/extensions/dashboard-client/dist/assets/HealthTab-D-IzmV29.js +2 -0
  41. package/extensions/dashboard-client/dist/assets/HealthTab-D-IzmV29.js.map +1 -0
  42. package/extensions/dashboard-client/dist/assets/MaintenanceTab-CrlkCFVj.js +2 -0
  43. package/extensions/dashboard-client/dist/assets/MaintenanceTab-CrlkCFVj.js.map +1 -0
  44. package/extensions/dashboard-client/dist/assets/MemoryMapTab-DHUdZ7RR.js +2 -0
  45. package/extensions/dashboard-client/dist/assets/MemoryMapTab-DHUdZ7RR.js.map +1 -0
  46. package/extensions/dashboard-client/dist/assets/MetricsTab-B7I4HWVg.js +2 -0
  47. package/extensions/dashboard-client/dist/assets/MetricsTab-B7I4HWVg.js.map +1 -0
  48. package/extensions/dashboard-client/dist/assets/OverviewTab-K6j4ZI7u.js +2 -0
  49. package/extensions/dashboard-client/dist/assets/OverviewTab-K6j4ZI7u.js.map +1 -0
  50. package/extensions/dashboard-client/dist/assets/ReposTab-BSRWhn56.js +2 -0
  51. package/extensions/dashboard-client/dist/assets/ReposTab-BSRWhn56.js.map +1 -0
  52. package/extensions/dashboard-client/dist/assets/SessionsTab-BXdizHN1.js +2 -0
  53. package/extensions/dashboard-client/dist/assets/SessionsTab-BXdizHN1.js.map +1 -0
  54. package/extensions/dashboard-client/dist/assets/SetupTab-CAgyfqY3.js +2 -0
  55. package/extensions/dashboard-client/dist/assets/SetupTab-CAgyfqY3.js.map +1 -0
  56. package/extensions/dashboard-client/dist/assets/TimeSavedCard-DwgCzPD9.js +2 -0
  57. package/extensions/dashboard-client/dist/assets/TimeSavedCard-DwgCzPD9.js.map +1 -0
  58. package/extensions/dashboard-client/dist/assets/TurnsTab-CVKcStBp.js +5 -0
  59. package/extensions/dashboard-client/dist/assets/TurnsTab-CVKcStBp.js.map +1 -0
  60. package/extensions/dashboard-client/dist/assets/WikiTab-BNohxTbs.js +2 -0
  61. package/extensions/dashboard-client/dist/assets/WikiTab-BNohxTbs.js.map +1 -0
  62. package/extensions/dashboard-client/dist/assets/button-B4A-_dCA.js +2 -0
  63. package/extensions/dashboard-client/dist/assets/button-B4A-_dCA.js.map +1 -0
  64. package/extensions/dashboard-client/dist/assets/card-Cjn7Ifoe.js +2 -0
  65. package/extensions/dashboard-client/dist/assets/card-Cjn7Ifoe.js.map +1 -0
  66. package/extensions/dashboard-client/dist/assets/index-CQjCLvv7.js +137 -0
  67. package/extensions/dashboard-client/dist/assets/index-CQjCLvv7.js.map +1 -0
  68. package/extensions/dashboard-client/dist/assets/index-CUA6EDRF.css +1 -0
  69. package/extensions/dashboard-client/dist/assets/switch-CcdXX0Zm.js +2 -0
  70. package/extensions/dashboard-client/dist/assets/switch-CcdXX0Zm.js.map +1 -0
  71. package/extensions/dashboard-client/dist/assets/toggle-KdBnFLu3.js +2 -0
  72. package/extensions/dashboard-client/dist/assets/toggle-KdBnFLu3.js.map +1 -0
  73. package/extensions/dashboard-client/dist/assets/{useSSE-p1pOI_-P.js → useSSE-B6t44vzc.js} +2 -2
  74. package/extensions/dashboard-client/dist/assets/{useSSE-p1pOI_-P.js.map → useSSE-B6t44vzc.js.map} +1 -1
  75. package/extensions/dashboard-client/dist/index.html +2 -2
  76. package/extensions/dashboard-client/package-lock.json +1995 -191
  77. package/extensions/dashboard-client/package.json +12 -1
  78. package/extensions/dashboard-client/postcss.config.js +6 -0
  79. package/extensions/dashboard-client/src/App.tsx +127 -88
  80. package/extensions/dashboard-client/src/api/client.ts +109 -10
  81. package/extensions/dashboard-client/src/components/ActiveReposTable.tsx +15 -7
  82. package/extensions/dashboard-client/src/components/ActiveSessionsTable.tsx +67 -55
  83. package/extensions/dashboard-client/src/components/CacheHitRateTrendCard.tsx +17 -13
  84. package/extensions/dashboard-client/src/components/CacheHitsCard.tsx +35 -30
  85. package/extensions/dashboard-client/src/components/CacheStatusPerModel.tsx +33 -28
  86. package/extensions/dashboard-client/src/components/EventCategoryFilter.tsx +5 -6
  87. package/extensions/dashboard-client/src/components/EventStream.tsx +17 -13
  88. package/extensions/dashboard-client/src/components/HydeDetailPanel.tsx +173 -0
  89. package/extensions/dashboard-client/src/components/LegendCard.tsx +16 -9
  90. package/extensions/dashboard-client/src/components/PerfCards.tsx +28 -20
  91. package/extensions/dashboard-client/src/components/PerfChart.tsx +9 -6
  92. package/extensions/dashboard-client/src/components/ProviderCacheCard.tsx +15 -7
  93. package/extensions/dashboard-client/src/components/RagDashboard.tsx +253 -0
  94. package/extensions/dashboard-client/src/components/RepoAllSessionsCard.tsx +15 -10
  95. package/extensions/dashboard-client/src/components/RepoContextStack.tsx +24 -16
  96. package/extensions/dashboard-client/src/components/RepoDetailModal.tsx +52 -49
  97. package/extensions/dashboard-client/src/components/RepoTable.tsx +26 -17
  98. package/extensions/dashboard-client/src/components/SessionContextGauges.tsx +11 -14
  99. package/extensions/dashboard-client/src/components/SessionInfo.tsx +20 -15
  100. package/extensions/dashboard-client/src/components/SessionsMemoryChart.tsx +8 -5
  101. package/extensions/dashboard-client/src/components/SummaryTiles.tsx +26 -17
  102. package/extensions/dashboard-client/src/components/TabBar.tsx +1 -3
  103. package/extensions/dashboard-client/src/components/layout/AppShell.tsx +42 -0
  104. package/extensions/dashboard-client/src/components/layout/BottomBar.tsx +88 -0
  105. package/extensions/dashboard-client/src/components/layout/Sidebar.tsx +83 -0
  106. package/extensions/dashboard-client/src/components/ui/badge.tsx +30 -0
  107. package/extensions/dashboard-client/src/components/ui/button.tsx +44 -0
  108. package/extensions/dashboard-client/src/components/ui/card.tsx +32 -0
  109. package/extensions/dashboard-client/src/components/ui/select.tsx +64 -0
  110. package/extensions/dashboard-client/src/components/ui/switch.tsx +26 -0
  111. package/extensions/dashboard-client/src/components/ui/tabs.tsx +36 -0
  112. package/extensions/dashboard-client/src/components/ui/toggle.tsx +28 -0
  113. package/extensions/dashboard-client/src/components/ui/tooltip.tsx +27 -0
  114. package/extensions/dashboard-client/src/config.ts +10 -0
  115. package/extensions/dashboard-client/src/main.tsx +2 -2
  116. package/extensions/dashboard-client/src/memory-map-layout.ts +1 -2
  117. package/extensions/dashboard-client/src/styles/index.css +79 -0
  118. package/extensions/dashboard-client/src/tabs/CacheTab.tsx +33 -26
  119. package/extensions/dashboard-client/src/tabs/EventsTab.tsx +22 -7
  120. package/extensions/dashboard-client/src/tabs/HealthTab.tsx +77 -46
  121. package/extensions/dashboard-client/src/tabs/MaintenanceTab/ActionsCard.tsx +60 -50
  122. package/extensions/dashboard-client/src/tabs/MaintenanceTab/DbStatsCard.tsx +61 -35
  123. package/extensions/dashboard-client/src/tabs/MaintenanceTab/DebugBundleCard.tsx +34 -23
  124. package/extensions/dashboard-client/src/tabs/MaintenanceTab/HealthMitigationCard.tsx +62 -43
  125. package/extensions/dashboard-client/src/tabs/MaintenanceTab/SchemaHealthCard.tsx +53 -32
  126. package/extensions/dashboard-client/src/tabs/MaintenanceTab.tsx +2 -2
  127. package/extensions/dashboard-client/src/tabs/MemoryMapTab/MemoryMapView.tsx +29 -46
  128. package/extensions/dashboard-client/src/tabs/MemoryMapTab/RaptorTreeView.tsx +10 -34
  129. package/extensions/dashboard-client/src/tabs/MemoryMapTab.tsx +14 -34
  130. package/extensions/dashboard-client/src/tabs/MetricsTab.tsx +5 -2
  131. package/extensions/dashboard-client/src/tabs/OverviewTab.tsx +11 -5
  132. package/extensions/dashboard-client/src/tabs/ReposTab.tsx +5 -5
  133. package/extensions/dashboard-client/src/tabs/SessionsTab.tsx +47 -33
  134. package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderSetup.tsx +6 -2
  135. package/extensions/dashboard-client/src/tabs/SetupTab/RagHealthCard.tsx +78 -0
  136. package/extensions/dashboard-client/src/tabs/SetupTab/SettingsPanel.tsx +198 -0
  137. package/extensions/dashboard-client/src/tabs/SetupTab/SettingsSection.tsx +50 -0
  138. package/extensions/dashboard-client/src/tabs/SetupTab.tsx +21 -59
  139. package/extensions/dashboard-client/src/tabs/TopicsTab.tsx +75 -40
  140. package/extensions/dashboard-client/src/tabs/TurnsTab.tsx +150 -112
  141. package/extensions/dashboard-client/src/tabs/WikiTab/TopicEvolutionGraph.tsx +274 -0
  142. package/extensions/dashboard-client/src/tabs/WikiTab/TopicEvolutionView.tsx +71 -0
  143. package/extensions/dashboard-client/src/tabs/WikiTab/TopicTimeline.tsx +103 -0
  144. package/extensions/dashboard-client/src/tabs/WikiTab/WikiPage.tsx +213 -0
  145. package/extensions/dashboard-client/src/tabs/WikiTab/WikiPageControls.tsx +188 -0
  146. package/extensions/dashboard-client/src/tabs/WikiTab.tsx +222 -0
  147. package/extensions/dashboard-client/src/tabs/registry.ts +57 -0
  148. package/extensions/dashboard-client/src/utils/cn.ts +7 -0
  149. package/extensions/dashboard-client/tailwind.config.js +46 -0
  150. package/extensions/dashboard-server/api-contracts/core.ts +59 -0
  151. package/extensions/dashboard-server/api-contracts/endpoints/registry.ts +79 -0
  152. package/extensions/dashboard-server/api-contracts/index.ts +48 -2
  153. package/extensions/dashboard-server/api-contracts/rag-metrics.ts +22 -0
  154. package/extensions/dashboard-server/api-contracts/rag-settings.ts +30 -20
  155. package/extensions/dashboard-server/api-contracts/wiki.ts +138 -0
  156. package/extensions/dashboard-server/routes-rag-metrics.ts +82 -0
  157. package/extensions/dashboard-server/routes-rag-settings-helpers.ts +314 -0
  158. package/extensions/dashboard-server/routes-rag-settings.ts +147 -97
  159. package/extensions/dashboard-server/routes-wiki-helpers.ts +126 -0
  160. package/extensions/dashboard-server/routes-wiki.ts +376 -0
  161. package/extensions/dashboard-server/routes.ts +2 -0
  162. package/extensions/dashboard-server/server.ts +18 -2
  163. package/extensions/mega-events/context-handler/afterCompact.ts +44 -1
  164. package/extensions/mega-pipeline/recall.ts +31 -0
  165. package/extensions/mega-turn-store.ts +13 -0
  166. package/package.json +1 -1
  167. package/src/config/turns.ts +17 -0
  168. package/src/config.ts +3 -0
  169. package/src/recall/async.ts +10 -1
  170. package/src/recall/format.ts +15 -2
  171. package/src/recall/hydeTelemetry.ts +44 -0
  172. package/src/recall/sync.ts +34 -2
  173. package/src/recall/types.ts +36 -0
  174. package/src/store/turns/hydeStore.ts +82 -0
  175. package/src/store/turns/index.ts +4 -0
  176. package/src/store/turns/schema.ts +126 -1
  177. package/src/store/turns/sqlite-store/rows.ts +25 -0
  178. package/src/store/turns/sqlite-store/write.ts +20 -2
  179. package/src/store/turns/types.ts +33 -0
  180. package/src/topics/durability.ts +231 -0
  181. package/src/topics/index.ts +7 -1
  182. package/src/topics/store.ts +35 -9
  183. package/src/wiki/curation-helpers.ts +140 -0
  184. package/src/wiki/curation.ts +217 -0
  185. package/src/wiki/incremental.ts +164 -0
  186. package/src/wiki/index.ts +13 -0
  187. package/extensions/dashboard-client/dist/assets/CacheTab-Cqnc7lMg.js +0 -2
  188. package/extensions/dashboard-client/dist/assets/CacheTab-Cqnc7lMg.js.map +0 -1
  189. package/extensions/dashboard-client/dist/assets/EventsTab-tYk3VFAp.js +0 -2
  190. package/extensions/dashboard-client/dist/assets/EventsTab-tYk3VFAp.js.map +0 -1
  191. package/extensions/dashboard-client/dist/assets/HealthTab-D2_kjgxw.js +0 -2
  192. package/extensions/dashboard-client/dist/assets/HealthTab-D2_kjgxw.js.map +0 -1
  193. package/extensions/dashboard-client/dist/assets/MaintenanceTab-Bc-uPYrz.js +0 -2
  194. package/extensions/dashboard-client/dist/assets/MaintenanceTab-Bc-uPYrz.js.map +0 -1
  195. package/extensions/dashboard-client/dist/assets/MemoryMapTab-D1V9g_NC.js +0 -2
  196. package/extensions/dashboard-client/dist/assets/MemoryMapTab-D1V9g_NC.js.map +0 -1
  197. package/extensions/dashboard-client/dist/assets/MetricsTab-DT_XfL96.js +0 -2
  198. package/extensions/dashboard-client/dist/assets/MetricsTab-DT_XfL96.js.map +0 -1
  199. package/extensions/dashboard-client/dist/assets/OverviewTab-BY6KZCme.js +0 -2
  200. package/extensions/dashboard-client/dist/assets/OverviewTab-BY6KZCme.js.map +0 -1
  201. package/extensions/dashboard-client/dist/assets/ReposTab-CeS-tpDM.js +0 -2
  202. package/extensions/dashboard-client/dist/assets/ReposTab-CeS-tpDM.js.map +0 -1
  203. package/extensions/dashboard-client/dist/assets/SessionsTab-C30AwyoF.js +0 -70
  204. package/extensions/dashboard-client/dist/assets/SetupTab-BJUHOVK2.js +0 -2
  205. package/extensions/dashboard-client/dist/assets/SetupTab-BJUHOVK2.js.map +0 -1
  206. package/extensions/dashboard-client/dist/assets/TimeSavedCard-p55K1tFP.js +0 -2
  207. package/extensions/dashboard-client/dist/assets/TimeSavedCard-p55K1tFP.js.map +0 -1
  208. package/extensions/dashboard-client/dist/assets/TopicsTab-D8FqyAbK.js +0 -2
  209. package/extensions/dashboard-client/dist/assets/TopicsTab-D8FqyAbK.js.map +0 -1
  210. package/extensions/dashboard-client/dist/assets/TurnsTab-ju-nXDys.js +0 -2
  211. package/extensions/dashboard-client/dist/assets/TurnsTab-ju-nXDys.js.map +0 -1
  212. package/extensions/dashboard-client/dist/assets/index-BEj1Zahy.js +0 -42
  213. package/extensions/dashboard-client/dist/assets/index-BEj1Zahy.js.map +0 -1
  214. package/extensions/dashboard-client/dist/assets/index-CUNn22iV.css +0 -1
  215. package/extensions/dashboard-client/src/styles/metrics-extra.css +0 -69
  216. package/extensions/dashboard-client/src/styles/turns.css +0 -142
  217. package/extensions/dashboard-client/src/tabs/SetupTab/RagSettingsCard.tsx +0 -160
@@ -0,0 +1,376 @@
1
+ /**
2
+ * dashboard-server/routes-wiki.ts — W2 wiki revival routes (curation + provenance).
3
+ *
4
+ * GET /api/wiki/index — topics with resolved labels
5
+ * GET /api/wiki/evolution — D3 nodes/edges/time buckets
6
+ * GET /api/wiki/topic/:topicId — single topic page + provenance
7
+ * GET /api/wiki/topic/:topicId/timeline — per-topic time buckets
8
+ * PUT /api/wiki/topic/:topicId/label — rename (emits wiki_topic_renamed)
9
+ * POST /api/wiki/merge — merge (emits wiki_topics_merged)
10
+ * POST /api/wiki/topic/:topicId/split — split (emits wiki_topic_split)
11
+ *
12
+ * Flag-gated by MEGACOMPACT_WIKI_ENHANCED (flag-OFF → 404 for all /api/wiki/*).
13
+ * Read/build helpers live in routes-wiki-helpers.ts (pointer-file split).
14
+ * Loopback-only (PREVENT-PI-004); parameterized (PREVENT-002); no `any`.
15
+ */
16
+
17
+ import type { IncomingMessage, ServerResponse } from "node:http";
18
+ import type { RouteContext } from "./routes-core.js";
19
+ import { TurnsConfig } from "../../src/config/turns.js";
20
+ import { openTurnStore } from "../../src/store/turns/connection.js";
21
+ import { createTopicStore } from "../../src/topics/store.js";
22
+ import { extractiveSummary } from "../../src/wiki.js";
23
+ import { createWikiCuration } from "../../src/wiki/curation.js";
24
+ import {
25
+ emitWikiEvent,
26
+ ensureWikiBuilt,
27
+ toIndexEntry,
28
+ toProvenance,
29
+ bucketize,
30
+ memberContent,
31
+ } from "./routes-wiki-helpers.js";
32
+ import type {
33
+ WikiIndexResponse,
34
+ WikiPageResponse,
35
+ TopicEvolutionResponse,
36
+ TopicTimelineResponse,
37
+ CurationResult,
38
+ } from "./api-contracts/wiki.js";
39
+
40
+ function sendJson(res: ServerResponse, status: number, body: unknown): void {
41
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
42
+ res.writeHead(status, { "Content-Type": "application/json" });
43
+ res.end(JSON.stringify(body));
44
+ }
45
+
46
+ /** Decode a percent-encoded path segment; null on malformed encoding (%zz). */
47
+ function decodeSegment(raw: string): string | null {
48
+ try {
49
+ return decodeURIComponent(raw);
50
+ } catch {
51
+ return null;
52
+ }
53
+ }
54
+
55
+ /** Read a capped JSON body; returns { ok, value } or { error }. */
56
+ function readJsonBody(
57
+ req: IncomingMessage,
58
+ cb: (
59
+ result:
60
+ | { ok: true; value: Record<string, unknown> }
61
+ | { ok: false; error: string },
62
+ ) => void,
63
+ ): void {
64
+ let body = "";
65
+ let tooBig = false;
66
+ req.on("data", (chunk: Buffer) => {
67
+ if (body.length > 65536) {
68
+ tooBig = true;
69
+ return;
70
+ }
71
+ body += chunk.toString();
72
+ });
73
+ req.on("end", () => {
74
+ if (tooBig) return cb({ ok: false, error: "body_too_large" });
75
+ try {
76
+ const v = body ? JSON.parse(body) : {};
77
+ if (typeof v !== "object" || v === null || Array.isArray(v)) {
78
+ return cb({ ok: false, error: "invalid_object" });
79
+ }
80
+ cb({ ok: true, value: v as Record<string, unknown> });
81
+ } catch {
82
+ cb({ ok: false, error: "invalid_json" });
83
+ }
84
+ });
85
+ }
86
+
87
+ export function handleWiki(
88
+ req: IncomingMessage,
89
+ res: ServerResponse,
90
+ ctx: RouteContext,
91
+ ): boolean {
92
+ const url = req.url ?? "";
93
+ if (!url.startsWith("/api/wiki")) return false;
94
+
95
+ // Flag gate: feature-OFF → 404 for every wiki endpoint.
96
+ if (!TurnsConfig.WIKI_ENHANCED_ENABLED) {
97
+ sendJson(res, 404, { error: "wiki_enhanced_disabled" });
98
+ return true;
99
+ }
100
+
101
+ // ── GET /api/wiki/index ──────────────────────────────────────────
102
+ if (req.method === "GET" && url === "/api/wiki/index") {
103
+ try {
104
+ const tdb = openTurnStore(ctx.stateDir);
105
+ ensureWikiBuilt(ctx, tdb);
106
+ const store = createTopicStore(ctx.stateDir);
107
+ const curation = createWikiCuration(ctx.stateDir);
108
+ const entries = store.getTopics().map((t) => toIndexEntry(t, curation));
109
+ const totalMemories = entries.reduce((s, e) => s + e.memoryCount, 0);
110
+ const lastRebuildAt =
111
+ entries.length > 0 ? Math.max(...entries.map((e) => e.lastUpdated)) : null;
112
+ const body: WikiIndexResponse = {
113
+ topics: entries,
114
+ totalTopics: entries.length,
115
+ totalMemories,
116
+ lastRebuildAt,
117
+ };
118
+ sendJson(res, 200, body);
119
+ } catch (e) {
120
+ sendJson(res, 500, { error: String(e) });
121
+ }
122
+ return true;
123
+ }
124
+
125
+ // ── GET /api/wiki/evolution ──────────────────────────────────────
126
+ if (req.method === "GET" && url === "/api/wiki/evolution") {
127
+ try {
128
+ const tdb = openTurnStore(ctx.stateDir);
129
+ const curation = createWikiCuration(ctx.stateDir);
130
+ const nodes = createTopicStore(ctx.stateDir)
131
+ .getTopics()
132
+ .map((t) => ({
133
+ id: t.id,
134
+ label: curation.resolveLabel(t.id, t.label).label,
135
+ memoryCount: t.memoryCount,
136
+ }));
137
+ const overrides = tdb
138
+ .prepare(
139
+ `SELECT kind, topic_id, merged_into, split_from, overridden_at
140
+ FROM topic_overrides WHERE kind IN ('merge','split')`,
141
+ )
142
+ .all() as Array<{
143
+ kind: string;
144
+ topic_id: string;
145
+ merged_into: string | null;
146
+ split_from: string | null;
147
+ overridden_at: number;
148
+ }>;
149
+ const edges = overrides.flatMap(
150
+ (o): TopicEvolutionResponse["edges"][number][] => {
151
+ if (o.kind === "merge" && o.merged_into) {
152
+ return [
153
+ {
154
+ source: o.topic_id,
155
+ target: o.merged_into,
156
+ kind: "merge",
157
+ at: o.overridden_at,
158
+ },
159
+ ];
160
+ }
161
+ if (o.kind === "split" && o.split_from) {
162
+ return [
163
+ {
164
+ source: o.split_from,
165
+ target: o.topic_id,
166
+ kind: "split",
167
+ at: o.overridden_at,
168
+ },
169
+ ];
170
+ }
171
+ return [];
172
+ },
173
+ );
174
+ const evoRows = tdb
175
+ .prepare("SELECT assigned_at FROM topic_evolution")
176
+ .all() as Array<{ assigned_at: number }>;
177
+ const body: TopicEvolutionResponse = {
178
+ nodes,
179
+ edges,
180
+ buckets: bucketize(evoRows.map((r) => r.assigned_at)),
181
+ };
182
+ sendJson(res, 200, body);
183
+ } catch (e) {
184
+ sendJson(res, 500, { error: String(e) });
185
+ }
186
+ return true;
187
+ }
188
+
189
+ // ── GET /api/wiki/topic/:topicId/timeline ────────────────────────
190
+ const timelineMatch =
191
+ req.method === "GET"
192
+ ? url.match(/^\/api\/wiki\/topic\/([^/?]+)\/timeline$/)
193
+ : null;
194
+ if (timelineMatch) {
195
+ const topicId = decodeSegment(timelineMatch[1]);
196
+ if (topicId === null) {
197
+ sendJson(res, 400, { error: "malformed_topic_id" });
198
+ return true;
199
+ }
200
+ try {
201
+ const tdb = openTurnStore(ctx.stateDir);
202
+ const rows = tdb
203
+ .prepare("SELECT assigned_at FROM memory_topics WHERE topic_id = ?")
204
+ .all(topicId) as Array<{ assigned_at: number }>;
205
+ const body: TopicTimelineResponse = {
206
+ topicId,
207
+ buckets: bucketize(rows.map((r) => r.assigned_at)),
208
+ total: rows.length,
209
+ };
210
+ sendJson(res, 200, body);
211
+ } catch (e) {
212
+ sendJson(res, 500, { error: String(e) });
213
+ }
214
+ return true;
215
+ }
216
+
217
+ // ── GET /api/wiki/topic/:topicId ─────────────────────────────────
218
+ const topicMatch =
219
+ req.method === "GET" ? url.match(/^\/api\/wiki\/topic\/([^/?]+)$/) : null;
220
+ if (topicMatch) {
221
+ const topicId = decodeSegment(topicMatch[1]);
222
+ if (topicId === null) {
223
+ sendJson(res, 400, { error: "malformed_topic_id" });
224
+ return true;
225
+ }
226
+ try {
227
+ const store = createTopicStore(ctx.stateDir);
228
+ const topic = store.getTopics().find((t) => t.id === topicId);
229
+ if (!topic) {
230
+ sendJson(res, 404, { error: "topic_not_found" });
231
+ return true;
232
+ }
233
+ const members = store.getMemoriesForTopic(topicId, 200);
234
+ const content = memberContent(ctx, members);
235
+ const getText = (memId: string): string => content.get(memId)?.text ?? "";
236
+ const summary = extractiveSummary(topic, members, getText);
237
+ const present = members.filter((m) => content.has(m.memoryId));
238
+ const keyMemories = [...present]
239
+ .sort(
240
+ (a, b) =>
241
+ (content.get(b.memoryId)?.text.length ?? 0) -
242
+ (content.get(a.memoryId)?.text.length ?? 0),
243
+ )
244
+ .slice(0, 10)
245
+ .map((m) => ({
246
+ memoryId: m.memoryId,
247
+ content: content.get(m.memoryId)?.text ?? "",
248
+ timestamp: content.get(m.memoryId)?.timestamp ?? 0,
249
+ importance: Math.round(
250
+ (content.get(m.memoryId)?.text.length ?? 0) / 40,
251
+ ),
252
+ }));
253
+ const relatedTopicIds = store
254
+ .getTopics()
255
+ .filter((t) => t.id !== topicId && t.memoryCount > 0)
256
+ .slice(0, 3)
257
+ .map((t) => t.id);
258
+ const body: WikiPageResponse = {
259
+ topic: toIndexEntry(topic, createWikiCuration(ctx.stateDir)),
260
+ summary,
261
+ keyMemories,
262
+ provenance: members.map(toProvenance),
263
+ relatedTopicIds,
264
+ generatedAt: Date.now(),
265
+ };
266
+ sendJson(res, 200, body);
267
+ } catch (e) {
268
+ sendJson(res, 500, { error: String(e) });
269
+ }
270
+ return true;
271
+ }
272
+
273
+ // ── PUT /api/wiki/topic/:topicId/label ───────────────────────────
274
+ const renameMatch =
275
+ req.method === "PUT"
276
+ ? url.match(/^\/api\/wiki\/topic\/([^/?]+)\/label$/)
277
+ : null;
278
+ if (renameMatch) {
279
+ readJsonBody(req, (result) => {
280
+ if (!result.ok) return sendJson(res, 400, { error: result.error });
281
+ const topicId = decodeSegment(renameMatch[1]);
282
+ if (topicId === null) return sendJson(res, 400, { error: "malformed_topic_id" });
283
+ const label = typeof result.value.label === "string" ? result.value.label : "";
284
+ try {
285
+ const curation = createWikiCuration(ctx.stateDir);
286
+ const out = curation.renameTopic(topicId, label);
287
+ if (!out.ok) return sendJson(res, 404, { error: "topic_not_found" });
288
+ emitWikiEvent(ctx, {
289
+ type: "wiki_topic_renamed",
290
+ topicId,
291
+ label: out.label,
292
+ edited: out.edited,
293
+ });
294
+ sendJson(res, 200, out satisfies CurationResult);
295
+ } catch (e) {
296
+ sendJson(res, 500, { error: String(e) });
297
+ }
298
+ });
299
+ return true;
300
+ }
301
+
302
+ // ── POST /api/wiki/merge ─────────────────────────────────────────
303
+ if (req.method === "POST" && url === "/api/wiki/merge") {
304
+ readJsonBody(req, (result) => {
305
+ if (!result.ok) return sendJson(res, 400, { error: result.error });
306
+ const sourceTopicId =
307
+ typeof result.value.sourceTopicId === "string"
308
+ ? result.value.sourceTopicId
309
+ : "";
310
+ const targetTopicId =
311
+ typeof result.value.targetTopicId === "string"
312
+ ? result.value.targetTopicId
313
+ : "";
314
+ if (!sourceTopicId || !targetTopicId) {
315
+ return sendJson(res, 400, { error: "missing_source_or_target" });
316
+ }
317
+ try {
318
+ const curation = createWikiCuration(ctx.stateDir);
319
+ const out = curation.mergeTopics(sourceTopicId, targetTopicId);
320
+ if (!out.ok) {
321
+ return sendJson(res, 400, {
322
+ error:
323
+ sourceTopicId === targetTopicId
324
+ ? "cannot_merge_into_itself"
325
+ : "topic_not_found",
326
+ });
327
+ }
328
+ emitWikiEvent(ctx, {
329
+ type: "wiki_topics_merged",
330
+ sourceTopicId,
331
+ targetTopicId,
332
+ });
333
+ sendJson(res, 200, out satisfies CurationResult);
334
+ } catch (e) {
335
+ sendJson(res, 500, { error: String(e) });
336
+ }
337
+ });
338
+ return true;
339
+ }
340
+
341
+ // ── POST /api/wiki/topic/:topicId/split ──────────────────────────
342
+ const splitMatch =
343
+ req.method === "POST"
344
+ ? url.match(/^\/api\/wiki\/topic\/([^/?]+)\/split$/)
345
+ : null;
346
+ if (splitMatch) {
347
+ readJsonBody(req, (result) => {
348
+ if (!result.ok) return sendJson(res, 400, { error: result.error });
349
+ const topicId = decodeSegment(splitMatch[1]);
350
+ if (topicId === null) return sendJson(res, 400, { error: "malformed_topic_id" });
351
+ const raw = result.value.memoryIds;
352
+ const memoryIds = Array.isArray(raw)
353
+ ? raw.filter((m): m is string => typeof m === "string")
354
+ : [];
355
+ if (memoryIds.length === 0) {
356
+ return sendJson(res, 400, { error: "empty_memoryIds" });
357
+ }
358
+ try {
359
+ const curation = createWikiCuration(ctx.stateDir);
360
+ const out = curation.splitTopic(topicId, memoryIds);
361
+ if (!out.ok) return sendJson(res, 404, { error: "topic_not_found" });
362
+ emitWikiEvent(ctx, {
363
+ type: "wiki_topic_split",
364
+ fromTopicId: topicId,
365
+ toTopicId: out.topicId,
366
+ });
367
+ sendJson(res, 200, out satisfies CurationResult);
368
+ } catch (e) {
369
+ sendJson(res, 500, { error: String(e) });
370
+ }
371
+ });
372
+ return true;
373
+ }
374
+
375
+ return false;
376
+ }
@@ -28,3 +28,5 @@ export { handleCacheStripes } from "./routes-cache.js";
28
28
  export { handleContextHealth, handleCachePoison, handleHealthSettings } from "./routes-health.js";
29
29
  export { handleEmbedderHealth } from "./routes-embedder-health.js";
30
30
  export { handleRagSettings } from "./routes-rag-settings.js";
31
+ export { handleRagMetrics } from "./routes-rag-metrics.js";
32
+ export { handleWiki } from "./routes-wiki.js";
@@ -23,6 +23,7 @@ import { join, dirname } from "node:path";
23
23
  import { fileURLToPath } from "node:url";
24
24
  import { createRequire } from "node:module";
25
25
 
26
+ import { NEW_UI } from "../../src/config.js";
26
27
  import { log, setLogPath, setDashboardServerVersion } from "./state.js";
27
28
  import {
28
29
  buildRouteContext,
@@ -50,6 +51,8 @@ import {
50
51
  handleHealthSettings,
51
52
  handleEmbedderHealth,
52
53
  handleRagSettings,
54
+ handleRagMetrics,
55
+ handleWiki,
53
56
  handleStatic,
54
57
  } from "./routes.js";
55
58
 
@@ -119,6 +122,15 @@ export async function launchDashboardServer(
119
122
  const hasClientBuild = existsSync(clientIndexHtml);
120
123
  if (hasClientBuild) log("client build present", { clientDist });
121
124
 
125
+ function injectUiFlag(html: string): string {
126
+ const flag = NEW_UI() ? "true" : "false";
127
+ const script = `<script>window.MEGACOMPACT_NEW_UI=${flag}</script>`;
128
+ if (html.includes("</head>")) {
129
+ return html.replace("</head>", `${script}</head>`);
130
+ }
131
+ return html + script;
132
+ }
133
+
122
134
  // guardrails-allow PREVENT-PI-004: read-only static file serving from the local dashboard-client/dist bundle (loopback-only UI).
123
135
  const serveClientAsset = (reqPath: string, res: ServerResponse): boolean => {
124
136
  if (!hasClientBuild) return false;
@@ -131,7 +143,7 @@ export async function launchDashboardServer(
131
143
  if (!file.startsWith(clientDist) || !existsSync(file)) {
132
144
  // SPA fallback: unknown non-asset routes serve index.html (client-side routing).
133
145
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
134
- res.end(readFileSync(clientIndexHtml));
146
+ res.end(injectUiFlag(readFileSync(clientIndexHtml, "utf-8")));
135
147
  return true;
136
148
  }
137
149
  const ext = rel.slice(rel.lastIndexOf(".") + 1);
@@ -145,10 +157,12 @@ export async function launchDashboardServer(
145
157
  ico: "image/x-icon",
146
158
  map: "application/json",
147
159
  };
160
+ const payload: string | Uint8Array =
161
+ ext === "html" ? injectUiFlag(readFileSync(file, "utf-8")) : readFileSync(file);
148
162
  res.writeHead(200, {
149
163
  "Content-Type": types[ext] ?? "application/octet-stream",
150
164
  });
151
- res.end(readFileSync(file));
165
+ res.end(payload);
152
166
  return true;
153
167
  };
154
168
 
@@ -251,6 +265,8 @@ export async function launchDashboardServer(
251
265
  if (handleHealthSettings(req, res, ctx)) return;
252
266
  if (handleEmbedderHealth(req, res, ctx)) return;
253
267
  if (handleRagSettings(req, res, ctx)) return;
268
+ if (handleRagMetrics(req, res, ctx)) return;
269
+ if (handleWiki(req, res, ctx)) return;
254
270
  handleStatic(req, res, ctx);
255
271
  });
256
272
 
@@ -21,7 +21,10 @@ import {
21
21
  buildTopicModel,
22
22
  createTopicStore,
23
23
  bumpWikiCompactCounter,
24
+ applyOverridesAfterRebuild,
25
+ applyFullOverridesAfterRebuild,
24
26
  } from "../../../src/topics/index.js";
27
+ import { assignNewMemoriesIncremental } from "../../../src/wiki/index.js";
25
28
  import { TrigramEmbedder } from "../../../src/embedder.js";
26
29
  import type { EmbeddedChunk } from "../../../src/topics/types.js";
27
30
  import type { MegaConfig } from "../../mega-config.js";
@@ -89,7 +92,36 @@ export async function persistEpochAndMaintain(
89
92
  );
90
93
  const tdb = openTurnStore(runtime.currentStateDir);
91
94
  const n = bumpWikiCompactCounter(tdb);
92
- if (n % every === 0) {
95
+ // W5-B: on the Nth compact we full-rebuild; otherwise try the
96
+ // cheap incremental path (assign new memories to nearest
97
+ // centroid) and only force a full rebuild when the mean
98
+ // silhouette has degraded below the configured floor.
99
+ let rebuildNow = n % every === 0;
100
+ if (
101
+ !rebuildNow &&
102
+ TurnsConfig.WIKI_INCREMENTAL_ENABLED &&
103
+ TurnsConfig.WIKI_ENHANCED_ENABLED
104
+ ) {
105
+ const inc = assignNewMemoriesIncremental(
106
+ db,
107
+ runtime.currentStateDir,
108
+ );
109
+ if (
110
+ inc.silhouette !== null &&
111
+ inc.silhouette < TurnsConfig.WIKI_INCREMENTAL_SILHOUETTE_MIN
112
+ ) {
113
+ // Silhouette degraded — fall through to a full rebuild.
114
+ rebuildNow = true;
115
+ } else {
116
+ runtime.logger.info("wiki_incremental", {
117
+ assigned: inc.assigned,
118
+ pending: inc.pending,
119
+ silhouetteScore: inc.silhouette,
120
+ uncalibrated: false,
121
+ });
122
+ }
123
+ }
124
+ if (rebuildNow) {
93
125
  const model = buildTopicModel(db, {
94
126
  kRange: [TurnsConfig.WIKI_K_MIN, TurnsConfig.WIKI_K_MAX],
95
127
  labelTopTerms: TurnsConfig.WIKI_LABEL_TOP_TERMS,
@@ -99,6 +131,13 @@ export async function persistEpochAndMaintain(
99
131
  createTopicStore(runtime.currentStateDir).replaceTopicModel(
100
132
  model,
101
133
  );
134
+ // W5-A: full hybrid replay — label + merge + split overrides
135
+ // survive the rebuild (feature A, not just the label fast path).
136
+ applyFullOverridesAfterRebuild(tdb);
137
+ // SSE push so the dashboard Wiki/Evolution views refresh (non-fatal).
138
+ runtime.dashboard.event("wiki_rebuilt", {
139
+ topicCount: model.k,
140
+ });
102
141
  runtime.logger.info("wiki_rebuild", {
103
142
  clusterCount: model.k,
104
143
  totalChunks: model.totalChunks,
@@ -177,6 +216,10 @@ export async function persistEpochAndMaintain(
177
216
  createTopicStore(
178
217
  runtime.currentStateDir,
179
218
  ).replaceTopicModel(model);
219
+ // Re-stamp custom label overrides wiped by the seed rebuild.
220
+ applyOverridesAfterRebuild(
221
+ openTurnStore(runtime.currentStateDir),
222
+ );
180
223
  runtime.logger.info("wiki_seed", {
181
224
  clusterCount: model.k,
182
225
  sourceChunks: seedChunks.length,
@@ -66,6 +66,32 @@ export function doRecall(
66
66
  injected: result.toInject.length,
67
67
  empty: result.empty,
68
68
  });
69
+ if (config.ragRecallMetrics && result.hydeInfo) {
70
+ runtime.dashboard.event("hyde_executed", {
71
+ sessionId: sid,
72
+ ran: result.hydeInfo.ran,
73
+ skipped: result.hydeInfo.skipped,
74
+ reason: result.hydeInfo.reason,
75
+ hypotheticalDoc: result.hydeInfo.hypotheticalDoc.slice(0, 400),
76
+ generationMs: result.hydeInfo.generationMs,
77
+ rawHitCount: result.hydeInfo.rawHitCount,
78
+ hydeHitCount: result.hydeInfo.hydeHitCount,
79
+ fusedHitCount: result.hydeInfo.fusedHitCount,
80
+ lift: result.hydeInfo.lift,
81
+ });
82
+ }
83
+ if (config.ragRecallMetrics && result.recallMetrics) {
84
+ runtime.dashboard.event("recall_metrics", {
85
+ sessionId: sid,
86
+ hitCount: result.recallMetrics.hitCount,
87
+ score: result.recallMetrics.score,
88
+ pass: result.recallMetrics.pass,
89
+ relevance: result.recallMetrics.relevance,
90
+ coverage: result.recallMetrics.coverage,
91
+ diversity: result.recallMetrics.diversity,
92
+ specificity: result.recallMetrics.specificity,
93
+ });
94
+ }
69
95
  if (!result.empty && result.toInject.length > 0) {
70
96
  const top = result.toInject[0];
71
97
  const scorePct = Math.round((top.score ?? 0) * 100);
@@ -105,6 +131,8 @@ export function doRecall(
105
131
  turnIndex: runtime.currentTurn,
106
132
  role: "assistant",
107
133
  startedAt: Date.now(),
134
+ hyde: result.hydeInfo ?? undefined,
135
+ recallMetrics: result.recallMetrics ?? undefined,
108
136
  },
109
137
  runtime.currentStateDir,
110
138
  );
@@ -229,6 +257,9 @@ export async function doRecallAsync(
229
257
  ),
230
258
  block,
231
259
  empty: merged.length === 0,
260
+ // H1: merged cross-repo result reuses the same-repo pass's telemetry.
261
+ hydeInfo: sameRepo.hydeInfo,
262
+ recallMetrics: sameRepo.recallMetrics,
232
263
  };
233
264
  } catch {
234
265
  return sameRepo; // cross-repo failure → same-repo only (non-fatal)
@@ -14,6 +14,8 @@ import {
14
14
  type TurnStore,
15
15
  type TurnEntry,
16
16
  type TurnRecallEntry,
17
+ type TurnHydeTelemetry,
18
+ type TurnRecallTelemetry,
17
19
  } from "../src/store/turns/index.js";
18
20
  import {
19
21
  recordTurn as legacyRecordTurn,
@@ -64,6 +66,11 @@ export function ensureConversationIdFor(
64
66
  }
65
67
 
66
68
  /** Record one turn row (turn_end). Returns the contract TurnId (string). */
69
+ /** H1: HyDE telemetry write — a structural subset of HydeInvocationInfo. */
70
+ export type RecallHydeWrite = TurnHydeTelemetry;
71
+ /** H1: recall-quality write — a structural subset of RecallMetricsSnapshot. */
72
+ export type RecallMetricsWrite = TurnRecallTelemetry;
73
+
67
74
  export function recordTurnWrite(
68
75
  config: MegaConfig,
69
76
  input: {
@@ -78,6 +85,10 @@ export function recordTurnWrite(
78
85
  pressureBand?: string;
79
86
  modelId?: string;
80
87
  epochId?: string;
88
+ /** H1: HyDE invocation telemetry (persisted to hyde_* columns). */
89
+ hyde?: RecallHydeWrite;
90
+ /** H1: recall-quality snapshot (persisted to recall_* columns). */
91
+ recallMetrics?: RecallMetricsWrite;
81
92
  },
82
93
  stateDir: string,
83
94
  ): string {
@@ -96,6 +107,8 @@ export function recordTurnWrite(
96
107
  pressureBand: input.pressureBand as TurnEntry["pressureBand"],
97
108
  model: input.modelId,
98
109
  epochId: input.epochId,
110
+ hyde: input.hyde,
111
+ recallMetrics: input.recallMetrics,
99
112
  };
100
113
  return storeFor(stateDir).appendTurn(entry);
101
114
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-mega-compact",
3
- "version": "0.13.4",
3
+ "version": "0.13.6",
4
4
  "description": "Layered, local, vector-backed context compressor for pi — supersede/collapse/cluster compaction with deduped inline recall.",
5
5
  "type": "module",
6
6
  "license": "BSD-3-Clause",
@@ -23,6 +23,14 @@ function envNum(name: string, def: number): number {
23
23
  return Number.isFinite(n) ? n : def;
24
24
  }
25
25
 
26
+ /** Default-ON toggle honoring the MEGACOMPACT_<NAME>_DISABLED opt-out convention. */
27
+ function envEnabled(name: string, def: boolean): boolean {
28
+ if (process.env[`${name}_DISABLED`] === "true" || process.env[`${name}_DISABLED`] === "1") {
29
+ return false;
30
+ }
31
+ return envBool(name, def);
32
+ }
33
+
26
34
  export interface TurnsConfigShape {
27
35
  /** Isolated turns.db store enabled (default true). OFF = legacy main-db path. */
28
36
  TURNS_DB_ENABLED: boolean;
@@ -41,6 +49,12 @@ export interface TurnsConfigShape {
41
49
  WIKI_REBUILD_EVERY_N_COMPACTS: number;
42
50
  /** D1: seed the topic model from raw_transcript when context_chunks is thin (default true). */
43
51
  WIKI_SEED_FROM_TURNS: boolean;
52
+ /** W2: wiki revival curation + provenance endpoints. Default ON; off via MEGACOMPACT_WIKI_ENHANCED_DISABLED. */
53
+ WIKI_ENHANCED_ENABLED: boolean;
54
+ /** W5: incremental topic assignment for new memories (default ON when WIKI_ENHANCED is ON). */
55
+ WIKI_INCREMENTAL_ENABLED: boolean;
56
+ /** W5: full rebuild triggers when mean silhouette drops below this (default 0.2). */
57
+ WIKI_INCREMENTAL_SILHOUETTE_MIN: number;
44
58
  }
45
59
 
46
60
  function envKRange(defMin: number, defMax: number): [number, number] {
@@ -66,6 +80,9 @@ export function loadTurnsConfig(): TurnsConfigShape {
66
80
  WIKI_LABEL_TOP_TERMS: envNum("MEGACOMPACT_WIKI_LABEL_TOP_TERMS", 5),
67
81
  WIKI_REBUILD_EVERY_N_COMPACTS: envNum("MEGACOMPACT_WIKI_REBUILD_EVERY", 3),
68
82
  WIKI_SEED_FROM_TURNS: envBool("MEGACOMPACT_WIKI_SEED_FROM_TURNS", true),
83
+ WIKI_ENHANCED_ENABLED: envEnabled("MEGACOMPACT_WIKI_ENHANCED", true),
84
+ WIKI_INCREMENTAL_ENABLED: envEnabled("MEGACOMPACT_WIKI_INCREMENTAL", true),
85
+ WIKI_INCREMENTAL_SILHOUETTE_MIN: envNum("MEGACOMPACT_WIKI_SILHOUETTE_MIN", 0.2),
69
86
  };
70
87
  }
71
88
 
package/src/config.ts CHANGED
@@ -140,3 +140,6 @@ export const RAG_MEMORY_GRAPH = (): boolean =>
140
140
  * MEGACOMPACT_HYDE_DISABLED=true. TrigramEmbedder path is unaffected. */
141
141
  export const RAG_HYDE_ENABLED = (): boolean =>
142
142
  ragEnabled("MEGACOMPACT_HYDE");
143
+
144
+ /** Spec 1: vbrainstorm visual design migration for the dashboard. */
145
+ export const NEW_UI = (): boolean => ragEnabled("MEGACOMPACT_NEW_UI");
@@ -138,5 +138,14 @@ export async function recallAndInlineAsync(
138
138
  ` • ${h.checkpoint.checkpointId} (${h.checkpoint.summary.slice(0, 60).replace(/\n/g, " ")}…)`,
139
139
  );
140
140
 
141
- return { toInject, report, block, empty: toInject.length === 0 };
141
+ return {
142
+ toInject,
143
+ report,
144
+ block,
145
+ empty: toInject.length === 0,
146
+ // H1: cross-repo async path is HyDE-free; telemetry stays null until a
147
+ // future sprint threads it here.
148
+ hydeInfo: null,
149
+ recallMetrics: null,
150
+ };
142
151
  }