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
@@ -17,6 +17,7 @@ import {
17
17
  fmtRelativeTime,
18
18
  } from "../utils/format";
19
19
  import { lookupModelInputRate } from "@pricing";
20
+ import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card";
20
21
 
21
22
  // ---------------------------------------------------------------------------
22
23
  // Per-model breakdown type (mirrors the API contract).
@@ -90,11 +91,11 @@ function StatRow({
90
91
  title?: string;
91
92
  }): React.ReactElement {
92
93
  return (
93
- <div className="ov-stat-row">
94
- <span className="ov-stat-label" title={title}>
94
+ <div className="flex items-baseline justify-between border-b border-border py-1 text-sm">
95
+ <span className="text-xs text-muted-foreground" title={title}>
95
96
  {label}
96
97
  </span>
97
- <span className={`ov-stat-value${className ? ` ${className}` : ""}`}>
98
+ <span className={`font-semibold${className ? ` ${className}` : ""}`}>
98
99
  {value}
99
100
  </span>
100
101
  </div>
@@ -109,7 +110,11 @@ export function ProviderCacheCard(
109
110
  props: ProviderCacheCardProps,
110
111
  ): React.ReactElement {
111
112
  return (
112
- <div className="card provider-cache-card">
113
+ <Card className="electric-hover">
114
+ <CardHeader>
115
+ <CardTitle>Provider Prompt Cache</CardTitle>
116
+ </CardHeader>
117
+ <CardContent>
113
118
  {/* --- Hit Rate + Turns --- */}
114
119
  <StatRow
115
120
  label="Cache Hit Rate"
@@ -155,7 +160,9 @@ export function ProviderCacheCard(
155
160
  {/* --- Per-model breakdown (F4) --- */}
156
161
  {props.byModel.length > 0 && (
157
162
  <>
158
- <div className="ov-stat-section-label">Per Model</div>
163
+ <div className="mt-2 text-xs font-semibold text-muted-foreground">
164
+ Per Model
165
+ </div>
159
166
  {props.byModel.map((m) => {
160
167
  const rate = lookupModelInputRate(m.model);
161
168
  const cr =
@@ -163,7 +170,7 @@ export function ProviderCacheCard(
163
170
  const cw =
164
171
  rate != null ? (m.totalCacheWrite / 1_000_000) * rate : null;
165
172
  return (
166
- <div key={m.model} className="ov-stat-group">
173
+ <div key={m.model} className="mt-2">
167
174
  <StatRow label="Model" value={m.model} />
168
175
  <StatRow
169
176
  label="Hit Rate"
@@ -192,6 +199,7 @@ export function ProviderCacheCard(
192
199
  })}
193
200
  </>
194
201
  )}
195
- </div>
202
+ </CardContent>
203
+ </Card>
196
204
  );
197
205
  }
@@ -0,0 +1,253 @@
1
+ /**
2
+ * dashboard-client/src/components/RagDashboard.tsx — full RAG metrics section
3
+ * (H3.2). Rendered in the Metrics tab.
4
+ *
5
+ * Fetches /api/rag-metrics and renders:
6
+ * 1. Stat row: telemetry turns, HyDE-ran count, avg lift, pass rate.
7
+ * 2. HyDE Recall Lift Bar (BarChart over daily avg lift).
8
+ * 3. CRAG Quality Line (LineChart over daily avg score).
9
+ * 4. Per-flag status dots (hydeEnabled, recallMetricsEnabled).
10
+ * 5. Recall Latency Stacked Bar (hyde vs base turn counts) + Hit-Rate Area.
11
+ *
12
+ * PREVENT-PI-004: relative-path fetch to the same-origin dashboard server.
13
+ * recharts is bundled into this localhost-served static bundle (no runtime
14
+ * network calls).
15
+ */
16
+
17
+ import type React from "react";
18
+ import { useMemo } from "react";
19
+ import { useApi } from "../hooks/useApi";
20
+ import { fetchRagMetrics } from "../api/client";
21
+ import type { RagMetricsResponse } from "@contracts";
22
+
23
+ /** Daily-aggregate row shape (derived from the rag-metrics contract). */
24
+ type DailyTelemetry = RagMetricsResponse["daily"][number];
25
+ import {
26
+ ResponsiveContainer,
27
+ BarChart,
28
+ Bar,
29
+ LineChart,
30
+ Line,
31
+ AreaChart,
32
+ Area,
33
+ XAxis,
34
+ YAxis,
35
+ CartesianGrid,
36
+ Tooltip,
37
+ Legend,
38
+ } from "recharts";
39
+ import { Card, CardHeader, CardTitle, CardContent } from "./ui/card";
40
+ import { Badge } from "./ui/badge";
41
+
42
+ const AXIS = "#8b949e";
43
+ const GRID = "#30363d";
44
+ const TOOLTIP = {
45
+ background: "#161b22",
46
+ border: "1px solid #30363d",
47
+ borderRadius: "6px",
48
+ color: "#e6edf3",
49
+ fontSize: 12,
50
+ } as const;
51
+
52
+ /** One row per day, with lead/lag-safe derived series for the charts. */
53
+ interface DailyRow {
54
+ day: string;
55
+ avgLift: number;
56
+ avgScore: number;
57
+ avgGenMs: number;
58
+ passRate: number;
59
+ hydeTurns: number;
60
+ baseTurns: number;
61
+ recallCount: number;
62
+ }
63
+
64
+ function toRows(daily: DailyTelemetry[]): DailyRow[] {
65
+ return daily.map((d) => {
66
+ const baseTurns = Math.max(0, d.recallCount - d.hydeRanCount);
67
+ return {
68
+ day: d.day.slice(5), // "MM-DD"
69
+ avgLift: d.avgLift ?? 0,
70
+ avgScore: d.avgScore ?? 0,
71
+ avgGenMs: d.avgGenMs ?? 0,
72
+ passRate: d.avgScore == null ? 0 : d.avgScore,
73
+ hydeTurns: d.hydeRanCount,
74
+ baseTurns,
75
+ recallCount: d.recallCount,
76
+ };
77
+ });
78
+ }
79
+
80
+ export interface RagDashboardProps {
81
+ /** Optional pre-fetched metrics; when absent, the card fetches inline. */
82
+ metrics?: RagMetricsResponse | null;
83
+ }
84
+
85
+ export const RagDashboard: React.FC<RagDashboardProps> = ({ metrics }) => {
86
+ const { data, loading } = useApi<RagMetricsResponse>(
87
+ useMemo(() => () => fetchRagMetrics(), []),
88
+ { pollInterval: 30_000 },
89
+ );
90
+ const m = metrics ?? data;
91
+ const rows = useMemo(() => (m ? toRows(m.daily) : []), [m]);
92
+
93
+ if (loading && !m) {
94
+ return <div className="text-sm text-muted-foreground">Loading RAG metrics…</div>;
95
+ }
96
+ if (!m) {
97
+ return (
98
+ <div className="text-sm text-muted-foreground">
99
+ No RAG metrics available yet. They appear once turns record HyDE/recall
100
+ telemetry.
101
+ </div>
102
+ );
103
+ }
104
+
105
+ const { totals, flags } = m;
106
+
107
+ return (
108
+ <div className="flex flex-col gap-4">
109
+ <StatRow totals={totals} flags={flags} />
110
+
111
+ <div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
112
+ <Card>
113
+ <CardHeader>
114
+ <CardTitle>HyDE Recall Lift</CardTitle>
115
+ </CardHeader>
116
+ <CardContent>
117
+ <ResponsiveContainer width="100%" height={200}>
118
+ <BarChart data={rows} margin={{ top: 8, right: 12, left: 0, bottom: 0 }}>
119
+ <CartesianGrid strokeDasharray="3 3" stroke={GRID} />
120
+ <XAxis dataKey="day" stroke={AXIS} tick={{ fontSize: 11 }} />
121
+ <YAxis stroke={AXIS} tick={{ fontSize: 11 }} width={40} />
122
+ <Tooltip contentStyle={TOOLTIP} />
123
+ <Bar dataKey="avgLift" name="avg lift" fill="#58a6ff" isAnimationActive={false} />
124
+ </BarChart>
125
+ </ResponsiveContainer>
126
+ </CardContent>
127
+ </Card>
128
+
129
+ <Card>
130
+ <CardHeader>
131
+ <CardTitle>CRAG Quality</CardTitle>
132
+ </CardHeader>
133
+ <CardContent>
134
+ <ResponsiveContainer width="100%" height={200}>
135
+ <LineChart data={rows} margin={{ top: 8, right: 12, left: 0, bottom: 0 }}>
136
+ <CartesianGrid strokeDasharray="3 3" stroke={GRID} />
137
+ <XAxis dataKey="day" stroke={AXIS} tick={{ fontSize: 11 }} />
138
+ <YAxis stroke={AXIS} tick={{ fontSize: 11 }} width={40} domain={[0, 1]} />
139
+ <Tooltip contentStyle={TOOLTIP} />
140
+ <Line type="monotone" dataKey="avgScore" name="avg score" stroke="#3fb950" dot={false} strokeWidth={2} isAnimationActive={false} />
141
+ </LineChart>
142
+ </ResponsiveContainer>
143
+ </CardContent>
144
+ </Card>
145
+
146
+ <Card>
147
+ <CardHeader>
148
+ <CardTitle>Recall Latency (avg gen ms)</CardTitle>
149
+ </CardHeader>
150
+ <CardContent>
151
+ <ResponsiveContainer width="100%" height={200}>
152
+ <BarChart data={rows} margin={{ top: 8, right: 12, left: 0, bottom: 0 }}>
153
+ <CartesianGrid strokeDasharray="3 3" stroke={GRID} />
154
+ <XAxis dataKey="day" stroke={AXIS} tick={{ fontSize: 11 }} />
155
+ <YAxis stroke={AXIS} tick={{ fontSize: 11 }} width={40} />
156
+ <Tooltip contentStyle={TOOLTIP} />
157
+ <Bar dataKey="avgGenMs" name="gen ms" fill="#d29922" isAnimationActive={false} />
158
+ </BarChart>
159
+ </ResponsiveContainer>
160
+ </CardContent>
161
+ </Card>
162
+
163
+ <Card>
164
+ <CardHeader>
165
+ <CardTitle>HyDE vs Base Turn Volume</CardTitle>
166
+ </CardHeader>
167
+ <CardContent>
168
+ <ResponsiveContainer width="100%" height={200}>
169
+ <AreaChart data={rows} margin={{ top: 8, right: 12, left: 0, bottom: 0 }}>
170
+ <CartesianGrid strokeDasharray="3 3" stroke={GRID} />
171
+ <XAxis dataKey="day" stroke={AXIS} tick={{ fontSize: 11 }} />
172
+ <YAxis stroke={AXIS} tick={{ fontSize: 11 }} width={40} />
173
+ <Tooltip contentStyle={TOOLTIP} />
174
+ <Legend wrapperStyle={{ fontSize: 11 }} />
175
+ <Area type="monotone" dataKey="hydeTurns" name="hyde turns" stackId="1" stroke="#58a6ff" fill="#58a6ff" fillOpacity={0.5} isAnimationActive={false} />
176
+ <Area type="monotone" dataKey="baseTurns" name="base turns" stackId="1" stroke="#8b949e" fill="#8b949e" fillOpacity={0.4} isAnimationActive={false} />
177
+ </AreaChart>
178
+ </ResponsiveContainer>
179
+ </CardContent>
180
+ </Card>
181
+ </div>
182
+ </div>
183
+ );
184
+ };
185
+
186
+ function StatRow({
187
+ totals,
188
+ flags,
189
+ }: {
190
+ totals: RagMetricsResponse["totals"];
191
+ flags: RagMetricsResponse["flags"];
192
+ }): React.ReactElement {
193
+ const stats: Array<{ label: string; value: string; hint: string }> = [
194
+ {
195
+ label: "Telemetry turns",
196
+ value: String(totals.telemetryTurns),
197
+ hint: "turns with HyDE or recall data",
198
+ },
199
+ {
200
+ label: "HyDE ran",
201
+ value: String(totals.hydeRanTurns),
202
+ hint: "turns where HyDE generated a doc",
203
+ },
204
+ {
205
+ label: "Avg lift",
206
+ value: `${totals.avgLift.toFixed(2)}×`,
207
+ hint: "fused / raw hit breadth",
208
+ },
209
+ {
210
+ label: "Pass rate",
211
+ value: `${Math.round(totals.recentPassRate * 100)}%`,
212
+ hint: totals.avgScore == null ? "no scored turns" : `avg score ${totals.avgScore.toFixed(2)}`,
213
+ },
214
+ ];
215
+
216
+ return (
217
+ <div className="grid grid-cols-2 gap-4 lg:grid-cols-5">
218
+ {stats.map((s) => (
219
+ <Card key={s.label}>
220
+ <CardContent>
221
+ <div className="text-xs text-muted-foreground">{s.label}</div>
222
+ <div className="font-heading text-2xl font-semibold text-foreground">
223
+ {s.value}
224
+ </div>
225
+ <div className="mt-0.5 text-xs text-muted-foreground">{s.hint}</div>
226
+ </CardContent>
227
+ </Card>
228
+ ))}
229
+ <Card>
230
+ <CardContent>
231
+ <div className="text-xs text-muted-foreground">Flags</div>
232
+ <div className="mt-1 flex flex-col gap-1 text-xs">
233
+ <FlagDot label="HyDE" on={flags.hydeEnabled} />
234
+ <FlagDot label="Recall metrics" on={flags.recallMetricsEnabled} />
235
+ </div>
236
+ </CardContent>
237
+ </Card>
238
+ </div>
239
+ );
240
+ }
241
+
242
+ function FlagDot({ label, on }: { label: string; on: boolean }): React.ReactElement {
243
+ return (
244
+ <span className="flex items-center gap-1.5">
245
+ <span
246
+ className={`inline-block h-2 w-2 rounded-full ${on ? "bg-success" : "bg-danger"}`}
247
+ aria-hidden="true"
248
+ />
249
+ {label}:{" "}
250
+ <Badge variant={on ? "success" : "danger"}>{on ? "on" : "off"}</Badge>
251
+ </span>
252
+ );
253
+ }
@@ -10,6 +10,7 @@
10
10
 
11
11
  import type React from "react";
12
12
  import { fmtPctFromFraction } from "../utils/format";
13
+ import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card";
13
14
 
14
15
  export interface RepoAllSessionsCardProps {
15
16
  checkpointCount: number;
@@ -45,9 +46,9 @@ function StatRow({
45
46
  value: string | number;
46
47
  }): React.ReactElement {
47
48
  return (
48
- <div className="ov-stat-row">
49
- <span className="ov-stat-label">{label}</span>
50
- <span className="ov-stat-value">{value}</span>
49
+ <div className="flex items-baseline justify-between border-b border-border py-1 text-sm">
50
+ <span className="text-xs text-muted-foreground">{label}</span>
51
+ <span className="font-semibold">{value}</span>
51
52
  </div>
52
53
  );
53
54
  }
@@ -61,8 +62,11 @@ export function RepoAllSessionsCard(
61
62
  const compressSub = `${fmtPctFromFraction(sp)} tokens saved · dedup: ${fmtPctFromFraction(props.dedupPct)}`;
62
63
 
63
64
  return (
64
- <div className="card repo-sessions-card">
65
- <h3>Repo (all sessions)</h3>
65
+ <Card className="electric-hover">
66
+ <CardHeader>
67
+ <CardTitle>Repo (all sessions)</CardTitle>
68
+ </CardHeader>
69
+ <CardContent>
66
70
  <StatRow
67
71
  label="Checkpoints"
68
72
  value={props.checkpointCount.toLocaleString()}
@@ -88,15 +92,16 @@ export function RepoAllSessionsCard(
88
92
  label="Storage Dedup"
89
93
  value={fmtPctFromFraction(props.storageDedupRate)}
90
94
  />
91
- <div className="ov-compression-meter">
92
- <div className="meter-track">
95
+ <div>
96
+ <div className="mt-2 h-2 w-full overflow-hidden rounded-full bg-bg-elevated">
93
97
  <div
94
- className={`meter-fill ${barCls}`}
98
+ className={`meter-fill h-full ${barCls}`}
95
99
  style={{ width: `${barWidth}%` }}
96
100
  />
97
101
  </div>
98
- <span className="meter-sub">{compressSub}</span>
102
+ <span className="mt-1 block text-xs text-muted-foreground">{compressSub}</span>
99
103
  </div>
100
- </div>
104
+ </CardContent>
105
+ </Card>
101
106
  );
102
107
  }
@@ -18,6 +18,7 @@
18
18
 
19
19
  import type React from "react";
20
20
  import type { ActiveSession, SessionsResponse } from "@contracts";
21
+ import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card";
21
22
 
22
23
  export interface RepoContextStackProps {
23
24
  /** Active sessions from /api/sessions (may be null while loading). */
@@ -135,6 +136,17 @@ function fmtTokens(n: number): string {
135
136
  return n.toLocaleString();
136
137
  }
137
138
 
139
+ function StackCard({ children }: { children: React.ReactNode }): React.ReactElement {
140
+ return (
141
+ <Card className="electric-hover">
142
+ <CardHeader>
143
+ <CardTitle>Context per Repo (live)</CardTitle>
144
+ </CardHeader>
145
+ <CardContent>{children}</CardContent>
146
+ </Card>
147
+ );
148
+ }
149
+
138
150
  export function RepoContextStack({
139
151
  sessions,
140
152
  loading,
@@ -142,21 +154,19 @@ export function RepoContextStack({
142
154
  }: RepoContextStackProps): React.ReactElement | null {
143
155
  if (error) {
144
156
  return (
145
- <div className="card repo-stack-card">
146
- <h3>Context per Repo (live)</h3>
147
- <div className="sessions-empty">
157
+ <StackCard>
158
+ <span className="text-sm text-muted-foreground">
148
159
  Error loading sessions: {error.message}
149
- </div>
150
- </div>
160
+ </span>
161
+ </StackCard>
151
162
  );
152
163
  }
153
164
 
154
165
  if (loading && !sessions) {
155
166
  return (
156
- <div className="card repo-stack-card">
157
- <h3>Context per Repo (live)</h3>
158
- <div className="sessions-empty">Loading sessions…</div>
159
- </div>
167
+ <StackCard>
168
+ <span className="text-sm text-muted-foreground">Loading sessions…</span>
169
+ </StackCard>
160
170
  );
161
171
  }
162
172
 
@@ -166,10 +176,9 @@ export function RepoContextStack({
166
176
 
167
177
  if (repos.length === 0) {
168
178
  return (
169
- <div className="card repo-stack-card">
170
- <h3>Context per Repo (live)</h3>
171
- <div className="sessions-empty">No active sessions.</div>
172
- </div>
179
+ <StackCard>
180
+ <span className="text-sm text-muted-foreground">No active sessions.</span>
181
+ </StackCard>
173
182
  );
174
183
  }
175
184
 
@@ -177,8 +186,7 @@ export function RepoContextStack({
177
186
  maxWindow > 0 ? Math.round((totalTokens / maxWindow) * 100) : 0;
178
187
 
179
188
  return (
180
- <div className="card repo-stack-card">
181
- <h3>Context per Repo (live)</h3>
189
+ <StackCard>
182
190
  <div
183
191
  className="repo-stack-bar"
184
192
  role="group"
@@ -233,6 +241,6 @@ export function RepoContextStack({
233
241
  );
234
242
  })}
235
243
  </div>
236
- </div>
244
+ </StackCard>
237
245
  );
238
246
  }
@@ -51,81 +51,84 @@ export function RepoDetailModal({
51
51
 
52
52
  return (
53
53
  <div
54
- className="modal-backdrop"
54
+ className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4"
55
55
  onClick={onClose}
56
56
  role="dialog"
57
57
  aria-modal="true"
58
58
  >
59
- <div className="modal-card" onClick={(e) => e.stopPropagation()}>
60
- <header className="modal-header">
61
- <h2>{repo.displayName}</h2>
59
+ <div
60
+ className="max-h-[85vh] w-full max-w-xl overflow-y-auto rounded-xl border border-border bg-bg-card p-5 shadow-panel"
61
+ onClick={(e) => e.stopPropagation()}
62
+ >
63
+ <header className="mb-2 flex items-start justify-between gap-4">
64
+ <h2 className="font-heading text-lg font-semibold">{repo.displayName}</h2>
62
65
  <button
63
66
  type="button"
64
- className="modal-close"
67
+ className="text-2xl leading-none text-muted-foreground hover:text-foreground"
65
68
  onClick={onClose}
66
69
  aria-label="Close"
67
70
  >
68
71
  ×
69
72
  </button>
70
73
  </header>
71
- <p className="modal-path">{repo.repoRoot}</p>
72
- <div className="modal-grid">
73
- <div className="modal-stat">
74
- <span className="modal-label">Checkpoints</span>
75
- <span className="modal-value">
74
+ <p className="mb-4 break-all font-mono text-xs text-muted-foreground">{repo.repoRoot}</p>
75
+ <div className="mb-4 grid grid-cols-2 gap-3 sm:grid-cols-3">
76
+ <div className="rounded-md border border-border/50 bg-bg-elevated/40 p-3">
77
+ <span className="block text-xs text-muted-foreground">Checkpoints</span>
78
+ <span className="text-xl font-semibold">
76
79
  {repo.checkpointCount.toLocaleString()}
77
80
  </span>
78
81
  </div>
79
- <div className="modal-stat">
80
- <span className="modal-label">Sessions</span>
81
- <span className="modal-value">
82
+ <div className="rounded-md border border-border/50 bg-bg-elevated/40 p-3">
83
+ <span className="block text-xs text-muted-foreground">Sessions</span>
84
+ <span className="text-xl font-semibold">
82
85
  {repo.sessions.toLocaleString()}
83
86
  </span>
84
87
  </div>
85
- <div className="modal-stat modal-highlight">
86
- <span className="modal-label">Tokens saved</span>
87
- <span className="modal-value">{fmt(repo.tokensSaved)}</span>
88
+ <div className="rounded-md border border-border/50 bg-primary/10 p-3">
89
+ <span className="block text-xs text-muted-foreground">Tokens saved</span>
90
+ <span className="text-xl font-semibold">{fmt(repo.tokensSaved)}</span>
88
91
  </div>
89
- <div className="modal-stat">
90
- <span className="modal-label">Tokens kept</span>
91
- <span className="modal-value">{fmt(repo.tokensKept)}</span>
92
+ <div className="rounded-md border border-border/50 bg-bg-elevated/40 p-3">
93
+ <span className="block text-xs text-muted-foreground">Tokens kept</span>
94
+ <span className="text-xl font-semibold">{fmt(repo.tokensKept)}</span>
92
95
  </div>
93
- <div className="modal-stat">
94
- <span className="modal-label">Tokens dropped</span>
95
- <span className="modal-value">{fmt(repo.tokensDropped)}</span>
96
+ <div className="rounded-md border border-border/50 bg-bg-elevated/40 p-3">
97
+ <span className="block text-xs text-muted-foreground">Tokens dropped</span>
98
+ <span className="text-xl font-semibold">{fmt(repo.tokensDropped)}</span>
96
99
  </div>
97
- <div className="modal-stat">
98
- <span className="modal-label">Dedup rate</span>
99
- <span className="modal-value">—</span>
100
+ <div className="rounded-md border border-border/50 bg-bg-elevated/40 p-3">
101
+ <span className="block text-xs text-muted-foreground">Dedup rate</span>
102
+ <span className="text-xl font-semibold">—</span>
100
103
  </div>
101
104
  </div>
102
- <h3>Model</h3>
103
- <dl className="modal-dl">
104
- <dt>Provider</dt>
105
- <dd>{repo.providerName ?? "—"}</dd>
106
- <dt>Model</dt>
107
- <dd>{repo.modelName ?? "—"}</dd>
108
- <dt>Input rate</dt>
109
- <dd>{repo.inputRate !== null ? `${repo.inputRate} tok/s` : "—"}</dd>
110
- <dt>Output rate</dt>
111
- <dd>{repo.outputRate !== null ? `${repo.outputRate} tok/s` : "—"}</dd>
112
- <dt>Context window</dt>
113
- <dd>{repo.contextWindow !== null ? fmt(repo.contextWindow) : "—"}</dd>
114
- <dt>Max tokens</dt>
115
- <dd>{repo.maxTokens !== null ? fmt(repo.maxTokens) : "—"}</dd>
116
- <dt>Reasoning</dt>
117
- <dd>
105
+ <h3 className="mb-2 font-heading text-sm font-semibold">Model</h3>
106
+ <dl className="mb-4 grid grid-cols-1 gap-1 text-sm sm:grid-cols-2">
107
+ <dt className="text-muted-foreground">Provider</dt>
108
+ <dd className="text-right">{repo.providerName ?? "—"}</dd>
109
+ <dt className="text-muted-foreground">Model</dt>
110
+ <dd className="text-right">{repo.modelName ?? "—"}</dd>
111
+ <dt className="text-muted-foreground">Input rate</dt>
112
+ <dd className="text-right">{repo.inputRate !== null ? `${repo.inputRate} tok/s` : "—"}</dd>
113
+ <dt className="text-muted-foreground">Output rate</dt>
114
+ <dd className="text-right">{repo.outputRate !== null ? `${repo.outputRate} tok/s` : "—"}</dd>
115
+ <dt className="text-muted-foreground">Context window</dt>
116
+ <dd className="text-right">{repo.contextWindow !== null ? fmt(repo.contextWindow) : "—"}</dd>
117
+ <dt className="text-muted-foreground">Max tokens</dt>
118
+ <dd className="text-right">{repo.maxTokens !== null ? fmt(repo.maxTokens) : "—"}</dd>
119
+ <dt className="text-muted-foreground">Reasoning</dt>
120
+ <dd className="text-right">
118
121
  {repo.reasoning === null ? "—" : repo.reasoning ? "on" : "off"}
119
122
  </dd>
120
123
  </dl>
121
- <h3>Activity</h3>
122
- <dl className="modal-dl">
123
- <dt>Last compacted</dt>
124
- <dd>{formatTs(repo.lastCompactedAt)}</dd>
125
- <dt>Last seen</dt>
126
- <dd>{formatTs(repo.lastSeen)}</dd>
127
- <dt>Compressed-Original</dt>
128
- <dd>{fmtBytesTop(repo.compressedOriginalBytes)}</dd>
124
+ <h3 className="mb-2 font-heading text-sm font-semibold">Activity</h3>
125
+ <dl className="grid grid-cols-1 gap-1 text-sm sm:grid-cols-2">
126
+ <dt className="text-muted-foreground">Last compacted</dt>
127
+ <dd className="text-right">{formatTs(repo.lastCompactedAt)}</dd>
128
+ <dt className="text-muted-foreground">Last seen</dt>
129
+ <dd className="text-right">{formatTs(repo.lastSeen)}</dd>
130
+ <dt className="text-muted-foreground">Compressed-Original</dt>
131
+ <dd className="text-right">{fmtBytesTop(repo.compressedOriginalBytes)}</dd>
129
132
  </dl>
130
133
  </div>
131
134
  </div>