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
@@ -10,6 +10,7 @@
10
10
  import type React from "react";
11
11
  import { useState, useMemo } from "react";
12
12
  import type { IndexesIndexRow } from "@contracts";
13
+ import { Card, CardContent } from "../components/ui/card";
13
14
 
14
15
  export interface RepoTableProps {
15
16
  repos: IndexesIndexRow[];
@@ -99,30 +100,32 @@ export function RepoTable({
99
100
  };
100
101
 
101
102
  return (
102
- <div className="repo-table-wrap">
103
+ <Card>
104
+ <CardContent>
103
105
  <input
104
106
  type="search"
105
- className="repo-search"
107
+ className="mb-3 w-full rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/60"
106
108
  placeholder="Search repos…"
107
109
  value={search}
108
110
  onChange={(e) => setSearch(e.target.value)}
109
111
  aria-label="Search repos"
110
112
  />
111
- <table className="repo-table">
113
+ <div className="overflow-x-auto">
114
+ <table className="w-full border-collapse text-sm">
112
115
  <thead>
113
116
  <tr>
114
117
  {COLUMNS.map((col) => (
115
- <th key={col.key}>
118
+ <th key={col.key} className="border-b border-border px-3 py-2 text-left">
116
119
  <button
117
120
  type="button"
118
- className={`sort-header ${sortKey === col.key ? `active-${sortDir}` : ""}`}
121
+ className={`font-medium text-muted-foreground transition-colors hover:text-foreground ${
122
+ sortKey === col.key ? "text-neon" : ""
123
+ }`}
119
124
  onClick={() => handleSort(col.key)}
120
125
  >
121
126
  {col.label}
122
127
  {sortKey === col.key && (
123
- <span className="sort-arrow">
124
- {sortDir === "asc" ? " ▲" : " ▼"}
125
- </span>
128
+ <span>{sortDir === "asc" ? " ▲" : " ▼"}</span>
126
129
  )}
127
130
  </button>
128
131
  </th>
@@ -132,7 +135,7 @@ export function RepoTable({
132
135
  <tbody>
133
136
  {filtered.length === 0 && (
134
137
  <tr>
135
- <td colSpan={COLUMNS.length} className="repo-empty">
138
+ <td colSpan={COLUMNS.length} className="px-3 py-4 text-muted-foreground">
136
139
  {repos.length === 0
137
140
  ? "No repositories registered yet."
138
141
  : "No repos match your search."}
@@ -140,19 +143,25 @@ export function RepoTable({
140
143
  </tr>
141
144
  )}
142
145
  {filtered.map((repo) => (
143
- <tr key={repo.stateDir} onClick={() => onSelect(repo)}>
144
- <td className="repo-name" title={repo.repoRoot}>
146
+ <tr
147
+ key={repo.stateDir}
148
+ onClick={() => onSelect(repo)}
149
+ className="cursor-pointer border-b border-border/50 transition-colors hover:bg-bg-elevated/40"
150
+ >
151
+ <td className="px-3 py-2 font-medium" title={repo.repoRoot}>
145
152
  {repo.displayName}
146
153
  </td>
147
- <td className="repo-model">{repo.modelName ?? "\u2014"}</td>
148
- <td className="num">{repo.checkpointCount.toLocaleString()}</td>
149
- <td className="num">{repo.tokensSaved.toLocaleString()}</td>
150
- <td className="num">{fmtBytesTop(repo.compressedOriginalBytes)}</td>
151
- <td className="num">{formatTs(repo.lastCompactedAt)}</td>
154
+ <td className="px-3 py-2 text-muted-foreground">{repo.modelName ?? "\u2014"}</td>
155
+ <td className="px-3 py-2 text-right">{repo.checkpointCount.toLocaleString()}</td>
156
+ <td className="px-3 py-2 text-right">{repo.tokensSaved.toLocaleString()}</td>
157
+ <td className="px-3 py-2 text-right">{fmtBytesTop(repo.compressedOriginalBytes)}</td>
158
+ <td className="px-3 py-2 text-right">{formatTs(repo.lastCompactedAt)}</td>
152
159
  </tr>
153
160
  ))}
154
161
  </tbody>
155
162
  </table>
156
- </div>
163
+ </div>
164
+ </CardContent>
165
+ </Card>
157
166
  );
158
167
  }
@@ -19,6 +19,7 @@
19
19
 
20
20
  import type React from "react";
21
21
  import type { ActiveSession, SessionsResponse } from "@contracts";
22
+ import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card";
22
23
 
23
24
  export interface SessionContextGaugesProps {
24
25
  /** Active sessions from /api/sessions (may be null while loading). */
@@ -153,29 +154,25 @@ export function SessionContextGauges({
153
154
  const showLoading = loading && !sessions;
154
155
 
155
156
  return (
156
- <div className="card session-gauges-card">
157
- <h3>Context per Session (live)</h3>
157
+ <Card className="electric-hover">
158
+ <CardHeader>
159
+ <CardTitle>Context per Session (live)</CardTitle>
160
+ </CardHeader>
161
+ <CardContent>
158
162
  {hasError ? (
159
- <div className="sessions-empty">
163
+ <div className="text-sm text-muted-foreground">
160
164
  Error loading sessions: {error!.message}
161
165
  </div>
162
166
  ) : showLoading ? (
163
- <div className="sessions-empty">Loading sessions…</div>
164
- ) : gauges.length <= 1 && others.length === 0 ? (
165
- // Launcher-only: just render the one self gauge (no "no sessions"
166
- // message — the launcher always has a gauge).
167
- <div className="session-gauges-grid">
168
- {gauges.map((g) => (
169
- <SessionGauge key={g.key} data={g} />
170
- ))}
171
- </div>
167
+ <div className="text-sm text-muted-foreground">Loading sessions…</div>
172
168
  ) : (
173
- <div className="session-gauges-grid">
169
+ <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
174
170
  {gauges.map((g) => (
175
171
  <SessionGauge key={g.key} data={g} />
176
172
  ))}
177
173
  </div>
178
174
  )}
179
- </div>
175
+ </CardContent>
176
+ </Card>
180
177
  );
181
178
  }
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import type React from "react";
8
+ import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card";
8
9
 
9
10
  export interface SessionInfoProps {
10
11
  /** Number of active crew agents. */
@@ -21,20 +22,24 @@ export function SessionInfo(
21
22
  activeAgents > 0 ? `▶ ${activeAgents} running` : "idle";
22
23
 
23
24
  return (
24
- <div className="card crew-card">
25
- <h3>Crew / Agents</h3>
26
- <div className="ov-stat-row">
27
- <span className="ov-stat-label">Active Agents</span>
28
- <span className="ov-stat-value">{activeAgents}</span>
29
- </div>
30
- <div className="ov-stat-row">
31
- <span className="ov-stat-label">Current Turn</span>
32
- <span className="ov-stat-value">{currentTurn}</span>
33
- </div>
34
- <div className="ov-stat-row">
35
- <span className="ov-stat-label">Status</span>
36
- <span className="ov-stat-value">{status}</span>
37
- </div>
38
- </div>
25
+ <Card className="electric-hover">
26
+ <CardHeader>
27
+ <CardTitle>Crew / Agents</CardTitle>
28
+ </CardHeader>
29
+ <CardContent>
30
+ <div className="flex items-baseline justify-between border-b border-border py-1 text-sm">
31
+ <span className="text-xs text-muted-foreground">Active Agents</span>
32
+ <span className="font-semibold">{activeAgents}</span>
33
+ </div>
34
+ <div className="flex items-baseline justify-between border-b border-border py-1 text-sm">
35
+ <span className="text-xs text-muted-foreground">Current Turn</span>
36
+ <span className="font-semibold">{currentTurn}</span>
37
+ </div>
38
+ <div className="flex items-baseline justify-between py-1 text-sm">
39
+ <span className="text-xs text-muted-foreground">Status</span>
40
+ <span className="font-semibold">{status}</span>
41
+ </div>
42
+ </CardContent>
43
+ </Card>
39
44
  );
40
45
  }
@@ -25,6 +25,7 @@ import {
25
25
  Legend,
26
26
  } from "recharts";
27
27
  import type { SessionSeries } from "@contracts";
28
+ import { Card, CardContent } from "../components/ui/card";
28
29
 
29
30
  export interface SessionsMemoryChartProps {
30
31
  /** Per-session series with stable colors (from /api/sessions/timeseries). */
@@ -110,14 +111,15 @@ export function SessionsMemoryChart({
110
111
 
111
112
  if (series.length === 0) {
112
113
  return (
113
- <div className="sessions-chart-empty">
114
- No token samples in this window yet.
115
- </div>
114
+ <Card>
115
+ <CardContent>No token samples in this window yet.</CardContent>
116
+ </Card>
116
117
  );
117
118
  }
118
119
 
119
120
  return (
120
- <div className="sessions-chart">
121
+ <Card>
122
+ <CardContent>
121
123
  <ResponsiveContainer width="100%" height={360}>
122
124
  <AreaChart
123
125
  data={data}
@@ -194,6 +196,7 @@ export function SessionsMemoryChart({
194
196
  />
195
197
  </AreaChart>
196
198
  </ResponsiveContainer>
197
- </div>
199
+ </CardContent>
200
+ </Card>
198
201
  );
199
202
  }
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import type React from "react";
9
+ import { Card, CardContent } from "../components/ui/card";
9
10
 
10
11
  export interface SummaryTilesProps {
11
12
  /** Total repos in the registry. */
@@ -39,23 +40,31 @@ export function SummaryTiles({
39
40
  compressedOriginalBytes,
40
41
  }: SummaryTilesProps): React.ReactElement {
41
42
  return (
42
- <div className="summary-tiles">
43
- <div className="tile">
44
- <span className="tile-label">Repositories</span>
45
- <span className="tile-value">{totalRepos.toLocaleString()}</span>
46
- </div>
47
- <div className="tile">
48
- <span className="tile-label">Total Checkpoints</span>
49
- <span className="tile-value">{totalCheckpoints.toLocaleString()}</span>
50
- </div>
51
- <div className="tile tile-highlight">
52
- <span className="tile-label">Total Tokens Saved</span>
53
- <span className="tile-value">{fmt(totalTokensSaved)}</span>
54
- </div>
55
- <div className="tile">
56
- <span className="tile-label">Compressed-Original</span>
57
- <span className="tile-value">{fmtBytesTop(compressedOriginalBytes)}</span>
58
- </div>
43
+ <div className="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-4">
44
+ <Card className="electric-hover">
45
+ <CardContent>
46
+ <span className="tile-label">Repositories</span>
47
+ <div className="text-xl font-semibold">{totalRepos.toLocaleString()}</div>
48
+ </CardContent>
49
+ </Card>
50
+ <Card className="electric-hover">
51
+ <CardContent>
52
+ <span className="tile-label">Total Checkpoints</span>
53
+ <div className="text-xl font-semibold">{totalCheckpoints.toLocaleString()}</div>
54
+ </CardContent>
55
+ </Card>
56
+ <Card className="electric-hover">
57
+ <CardContent>
58
+ <span className="tile-label">Total Tokens Saved</span>
59
+ <div className="text-xl font-semibold">{fmt(totalTokensSaved)}</div>
60
+ </CardContent>
61
+ </Card>
62
+ <Card className="electric-hover">
63
+ <CardContent>
64
+ <span className="tile-label">Compressed-Original</span>
65
+ <div className="text-xl font-semibold">{fmtBytesTop(compressedOriginalBytes)}</div>
66
+ </CardContent>
67
+ </Card>
59
68
  </div>
60
69
  );
61
70
  }
@@ -11,7 +11,7 @@ import type { TabId } from "../App";
11
11
  export interface TabBarProps {
12
12
  primaryTabs: Array<{ id: TabId; label: string }>;
13
13
  advancedTabs: Array<{ id: TabId; label: string }>;
14
- advancedTabIds: Set<TabId>;
14
+ advancedTabIds: ReadonlySet<TabId>;
15
15
  active: TabId;
16
16
  onTabChange: (id: TabId) => void;
17
17
  }
@@ -27,8 +27,6 @@ export function TabBar({
27
27
  () => advancedTabIds.has(active), // start open if an advanced tab is active
28
28
  );
29
29
 
30
- const isAdvancedActive = advancedTabIds.has(active);
31
-
32
30
  return (
33
31
  <nav className="tab-bar" role="tablist">
34
32
  {primaryTabs.map((tab) => (
@@ -0,0 +1,42 @@
1
+ import React from "react";
2
+ import type { SnapshotResponse } from "@contracts";
3
+ import { Sidebar } from "./Sidebar";
4
+ import { BottomBar } from "./BottomBar";
5
+ import type { TabId } from "../../tabs/registry";
6
+
7
+ interface AppShellProps {
8
+ active: TabId;
9
+ onTabChange: (id: TabId) => void;
10
+ snapshot: SnapshotResponse | null;
11
+ children: React.ReactNode;
12
+ }
13
+
14
+ export function AppShell({ active, onTabChange, snapshot, children }: AppShellProps) {
15
+ const tier = snapshot?.tier ?? "unknown";
16
+ const version = snapshot?.model?.name ?? "";
17
+
18
+ return (
19
+ <div className="min-h-screen bg-background text-foreground">
20
+ <div className="mx-auto flex max-w-[1600px] gap-6 px-4 py-4">
21
+ <Sidebar active={active} onTabChange={onTabChange} />
22
+ <div className="flex min-w-0 flex-1 flex-col">
23
+ <header className="mb-4 flex items-center gap-3">
24
+ <h1 className="font-heading text-lg font-semibold">
25
+ <span className="gradient-text">mega-compact dashboard</span>
26
+ </h1>
27
+ <span className="rounded-md border border-border bg-bg-elevated px-2 py-0.5 text-xs text-muted">
28
+ {tier}
29
+ </span>
30
+ {version && (
31
+ <span className="rounded-md border border-border bg-bg-elevated px-2 py-0.5 text-xs text-muted">
32
+ {version}
33
+ </span>
34
+ )}
35
+ </header>
36
+ <main className="flex-1 pb-20 lg:pb-4">{children}</main>
37
+ </div>
38
+ </div>
39
+ <BottomBar active={active} onTabChange={onTabChange} />
40
+ </div>
41
+ );
42
+ }
@@ -0,0 +1,88 @@
1
+ import { useState } from "react";
2
+ import { MoreHorizontal } from "lucide-react";
3
+ import { cn } from "../../utils/cn";
4
+ import {
5
+ PRIMARY_TABS,
6
+ ADVANCED_TABS,
7
+ type TabId,
8
+ } from "../../tabs/registry";
9
+
10
+ interface BottomBarProps {
11
+ active: TabId;
12
+ onTabChange: (id: TabId) => void;
13
+ }
14
+
15
+ export function BottomBar({ active, onTabChange }: BottomBarProps) {
16
+ const [moreOpen, setMoreOpen] = useState(false);
17
+ const primary = PRIMARY_TABS.slice(0, 4);
18
+
19
+ return (
20
+ <nav className="glass-panel fixed inset-x-3 bottom-3 z-40 flex items-center justify-around rounded-xl p-2 lg:hidden">
21
+ {primary.map((tab) => {
22
+ const Icon = tab.icon;
23
+ const isActive = active === tab.id;
24
+ return (
25
+ <button
26
+ key={tab.id}
27
+ type="button"
28
+ onClick={() => onTabChange(tab.id)}
29
+ className={cn(
30
+ "flex flex-col items-center gap-1 rounded-lg px-3 py-1.5 text-[11px] font-medium",
31
+ isActive
32
+ ? "text-neon glow-primary"
33
+ : "text-muted hover:text-foreground",
34
+ )}
35
+ aria-current={isActive ? "page" : undefined}
36
+ >
37
+ <Icon className="h-5 w-5" />
38
+ {tab.label}
39
+ </button>
40
+ );
41
+ })}
42
+
43
+ <button
44
+ type="button"
45
+ onClick={() => setMoreOpen((o) => !o)}
46
+ aria-expanded={moreOpen}
47
+ aria-controls="bottombar-more-section"
48
+ className={cn(
49
+ "flex flex-col items-center gap-1 rounded-lg px-3 py-1.5 text-[11px] font-medium",
50
+ moreOpen ? "text-neon" : "text-muted hover:text-foreground",
51
+ )}
52
+ >
53
+ <MoreHorizontal className="h-5 w-5" />
54
+ More
55
+ </button>
56
+
57
+ {moreOpen && (
58
+ <div
59
+ id="bottombar-more-section"
60
+ className="absolute bottom-16 right-2 w-56 rounded-xl border border-border bg-bg-elevated p-2 shadow-panel"
61
+ >
62
+ {[...PRIMARY_TABS.slice(4), ...ADVANCED_TABS].map((tab) => {
63
+ const Icon = tab.icon;
64
+ return (
65
+ <button
66
+ key={tab.id}
67
+ type="button"
68
+ onClick={() => {
69
+ onTabChange(tab.id);
70
+ setMoreOpen(false);
71
+ }}
72
+ className={cn(
73
+ "flex w-full items-center gap-3 rounded-lg px-3 py-2 text-left text-sm",
74
+ active === tab.id
75
+ ? "bg-primary/15 text-neon"
76
+ : "text-muted hover:bg-bg-elevated hover:text-foreground",
77
+ )}
78
+ >
79
+ <Icon className="h-4 w-4 shrink-0" />
80
+ {tab.label}
81
+ </button>
82
+ );
83
+ })}
84
+ </div>
85
+ )}
86
+ </nav>
87
+ );
88
+ }
@@ -0,0 +1,83 @@
1
+ import { useEffect, useState } from "react";
2
+ import { ChevronDown, Sparkles } from "lucide-react";
3
+ import { cn } from "../../utils/cn";
4
+ import {
5
+ PRIMARY_TABS,
6
+ ADVANCED_TABS,
7
+ ADVANCED_TAB_IDS,
8
+ type TabId,
9
+ } from "../../tabs/registry";
10
+ import { Badge } from "../ui/badge";
11
+
12
+ interface SidebarProps {
13
+ active: TabId;
14
+ onTabChange: (id: TabId) => void;
15
+ }
16
+
17
+ export function Sidebar({ active, onTabChange }: SidebarProps) {
18
+ const [advancedOpen, setAdvancedOpen] = useState<boolean>(
19
+ () => ADVANCED_TAB_IDS.has(active),
20
+ );
21
+
22
+ // Keep the advanced section expanded whenever the active tab is advanced,
23
+ // regardless of how the navigation happened (tab click, cross-device recalc).
24
+ useEffect(() => {
25
+ if (ADVANCED_TAB_IDS.has(active)) setAdvancedOpen(true);
26
+ }, [active]);
27
+
28
+ const Tile = ({ tab }: { tab: (typeof PRIMARY_TABS)[number] }) => {
29
+ const Icon = tab.icon;
30
+ const isActive = active === tab.id;
31
+ return (
32
+ <button
33
+ type="button"
34
+ onClick={() => onTabChange(tab.id)}
35
+ className={cn(
36
+ "flex w-full items-center gap-3 rounded-lg px-3 py-2 text-left text-sm font-medium transition-all",
37
+ isActive
38
+ ? "bg-primary/15 text-neon glow-primary border border-primary/40"
39
+ : "border border-transparent text-muted hover:bg-bg-elevated hover:text-foreground",
40
+ )}
41
+ aria-current={isActive ? "page" : undefined}
42
+ >
43
+ <Icon className="h-4 w-4 shrink-0" />
44
+ <span className="truncate">{tab.label}</span>
45
+ {isActive && <Badge variant="default" className="ml-auto">●</Badge>}
46
+ </button>
47
+ );
48
+ };
49
+
50
+ return (
51
+ <aside className="glass-panel hidden w-64 shrink-0 flex-col gap-1 p-3 lg:flex">
52
+ <div className="mb-2 flex items-center gap-2 px-2">
53
+ <Sparkles className="h-4 w-4 text-neon" />
54
+ <span className="font-heading text-sm uppercase tracking-widest text-muted">
55
+ Tabs
56
+ </span>
57
+ </div>
58
+ {PRIMARY_TABS.map((tab) => (
59
+ <Tile key={tab.id} tab={tab} />
60
+ ))}
61
+
62
+ <button
63
+ type="button"
64
+ onClick={() => setAdvancedOpen((o) => !o)}
65
+ className="mt-2 flex w-full items-center justify-between rounded-lg px-3 py-2 text-left text-sm font-semibold text-muted hover:text-foreground"
66
+ aria-expanded={advancedOpen}
67
+ aria-controls="sidebar-advanced-section"
68
+ >
69
+ Advanced
70
+ <ChevronDown
71
+ className={cn("h-4 w-4 transition-transform", advancedOpen && "rotate-180")}
72
+ />
73
+ </button>
74
+ {advancedOpen && (
75
+ <div id="sidebar-advanced-section" className="mt-1 flex flex-col gap-1">
76
+ {ADVANCED_TABS.map((tab) => (
77
+ <Tile key={tab.id} tab={tab} />
78
+ ))}
79
+ </div>
80
+ )}
81
+ </aside>
82
+ );
83
+ }
@@ -0,0 +1,30 @@
1
+ import * as React from "react";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import { cn } from "../../utils/cn";
4
+
5
+ const badgeVariants = cva(
6
+ "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none",
7
+ {
8
+ variants: {
9
+ variant: {
10
+ default: "border-primary/40 bg-primary/15 text-neon",
11
+ success: "border-success/40 bg-success/15 text-success",
12
+ warning: "border-warning/40 bg-warning/15 text-warning",
13
+ danger: "border-danger/40 bg-danger/15 text-danger",
14
+ outline: "border-border text-foreground",
15
+ accent: "border-accent/40 bg-accent/15 text-accent",
16
+ },
17
+ },
18
+ defaultVariants: { variant: "default" },
19
+ },
20
+ );
21
+
22
+ export interface BadgeProps
23
+ extends React.HTMLAttributes<HTMLSpanElement>,
24
+ VariantProps<typeof badgeVariants> {}
25
+
26
+ function Badge({ className, variant, ...props }: BadgeProps) {
27
+ return <span className={cn(badgeVariants({ variant }), className)} {...props} />;
28
+ }
29
+
30
+ export { Badge, badgeVariants };
@@ -0,0 +1,44 @@
1
+ import * as React from "react";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import { cn } from "../../utils/cn";
4
+
5
+ const buttonVariants = cva(
6
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
7
+ {
8
+ variants: {
9
+ variant: {
10
+ default: "bg-primary text-primary-foreground hover:bg-primary/90 glow-primary",
11
+ outline: "border border-border bg-transparent hover:bg-bg-elevated hover:text-foreground",
12
+ ghost: "hover:bg-bg-elevated hover:text-foreground",
13
+ glass: "glass-panel electric-hover",
14
+ },
15
+ size: {
16
+ default: "h-9 px-4 py-2",
17
+ sm: "h-8 rounded-md px-3 text-xs",
18
+ lg: "h-10 rounded-md px-8",
19
+ icon: "h-9 w-9",
20
+ },
21
+ },
22
+ defaultVariants: {
23
+ variant: "default",
24
+ size: "default",
25
+ },
26
+ },
27
+ );
28
+
29
+ export interface ButtonProps
30
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
31
+ VariantProps<typeof buttonVariants> {}
32
+
33
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
34
+ ({ className, variant, size, ...props }, ref) => (
35
+ <button
36
+ ref={ref}
37
+ className={cn(buttonVariants({ variant, size, className }))}
38
+ {...props}
39
+ />
40
+ ),
41
+ );
42
+ Button.displayName = "Button";
43
+
44
+ export { Button, buttonVariants };
@@ -0,0 +1,32 @@
1
+ import * as React from "react";
2
+ import { cn } from "../../utils/cn";
3
+
4
+ const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
5
+ ({ className, ...props }, ref) => (
6
+ <div ref={ref} className={cn("glass-panel p-4", className)} {...props} />
7
+ ),
8
+ );
9
+ Card.displayName = "Card";
10
+
11
+ const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
12
+ ({ className, ...props }, ref) => (
13
+ <div ref={ref} className={cn("mb-3 flex flex-col space-y-1.5", className)} {...props} />
14
+ ),
15
+ );
16
+ CardHeader.displayName = "CardHeader";
17
+
18
+ const CardTitle = React.forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(
19
+ ({ className, ...props }, ref) => (
20
+ <h3 ref={ref} className={cn("font-heading text-sm font-semibold leading-none tracking-tight", className)} {...props} />
21
+ ),
22
+ );
23
+ CardTitle.displayName = "CardTitle";
24
+
25
+ const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
26
+ ({ className, ...props }, ref) => (
27
+ <div ref={ref} className={cn("text-sm", className)} {...props} />
28
+ ),
29
+ );
30
+ CardContent.displayName = "CardContent";
31
+
32
+ export { Card, CardHeader, CardTitle, CardContent };