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.
- package/README.md +11 -8
- package/dist/extensions/dashboard-server/api-contracts/endpoints/registry.js +50 -0
- package/dist/extensions/dashboard-server/api-contracts/rag-metrics.js +1 -0
- package/dist/extensions/dashboard-server/api-contracts/rag-settings.js +3 -3
- package/dist/extensions/dashboard-server/api-contracts/wiki.js +1 -0
- package/dist/extensions/dashboard-server/routes-rag-metrics.js +60 -0
- package/dist/extensions/dashboard-server/routes-rag-settings-helpers.js +167 -0
- package/dist/extensions/dashboard-server/routes-rag-settings.js +136 -77
- package/dist/extensions/dashboard-server/routes-wiki-helpers.js +97 -0
- package/dist/extensions/dashboard-server/routes-wiki.js +330 -0
- package/dist/extensions/dashboard-server/routes.js +2 -0
- package/dist/extensions/dashboard-server/server.js +17 -3
- package/dist/extensions/mega-events/context-handler/afterCompact.js +35 -2
- package/dist/extensions/mega-pipeline/recall.js +31 -0
- package/dist/extensions/mega-turn-store.js +2 -1
- package/dist/src/config/turns.js +10 -0
- package/dist/src/config.js +2 -0
- package/dist/src/recall/async.js +10 -1
- package/dist/src/recall/format.js +10 -1
- package/dist/src/recall/hydeTelemetry.js +22 -0
- package/dist/src/recall/sync.js +28 -2
- package/dist/src/store/turns/hydeStore.js +32 -0
- package/dist/src/store/turns/index.js +1 -0
- package/dist/src/store/turns/schema.js +102 -1
- package/dist/src/store/turns/sqlite-store/rows.js +23 -0
- package/dist/src/store/turns/sqlite-store/write.js +7 -3
- package/dist/src/topics/durability.js +187 -0
- package/dist/src/topics/index.js +2 -1
- package/dist/src/topics/store.js +28 -9
- package/dist/src/wiki/curation-helpers.js +71 -0
- package/dist/src/wiki/curation.js +147 -0
- package/dist/src/wiki/incremental.js +126 -0
- package/dist/src/wiki/index.js +5 -0
- package/extensions/dashboard-client/dist/assets/AreaChart-KAmp_6bL.js +70 -0
- package/extensions/dashboard-client/dist/assets/{SessionsTab-C30AwyoF.js.map → AreaChart-KAmp_6bL.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/CacheTab-Bk-gm-R0.js +2 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-Bk-gm-R0.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/EventsTab-Cyylo0of.js +2 -0
- package/extensions/dashboard-client/dist/assets/EventsTab-Cyylo0of.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/HealthTab-D-IzmV29.js +2 -0
- package/extensions/dashboard-client/dist/assets/HealthTab-D-IzmV29.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-CrlkCFVj.js +2 -0
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-CrlkCFVj.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-DHUdZ7RR.js +2 -0
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-DHUdZ7RR.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/MetricsTab-B7I4HWVg.js +2 -0
- package/extensions/dashboard-client/dist/assets/MetricsTab-B7I4HWVg.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/OverviewTab-K6j4ZI7u.js +2 -0
- package/extensions/dashboard-client/dist/assets/OverviewTab-K6j4ZI7u.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/ReposTab-BSRWhn56.js +2 -0
- package/extensions/dashboard-client/dist/assets/ReposTab-BSRWhn56.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/SessionsTab-BXdizHN1.js +2 -0
- package/extensions/dashboard-client/dist/assets/SessionsTab-BXdizHN1.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-CAgyfqY3.js +2 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-CAgyfqY3.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-DwgCzPD9.js +2 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-DwgCzPD9.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/TurnsTab-CVKcStBp.js +5 -0
- package/extensions/dashboard-client/dist/assets/TurnsTab-CVKcStBp.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/WikiTab-BNohxTbs.js +2 -0
- package/extensions/dashboard-client/dist/assets/WikiTab-BNohxTbs.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/button-B4A-_dCA.js +2 -0
- package/extensions/dashboard-client/dist/assets/button-B4A-_dCA.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/card-Cjn7Ifoe.js +2 -0
- package/extensions/dashboard-client/dist/assets/card-Cjn7Ifoe.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/index-CQjCLvv7.js +137 -0
- package/extensions/dashboard-client/dist/assets/index-CQjCLvv7.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/index-CUA6EDRF.css +1 -0
- package/extensions/dashboard-client/dist/assets/switch-CcdXX0Zm.js +2 -0
- package/extensions/dashboard-client/dist/assets/switch-CcdXX0Zm.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/toggle-KdBnFLu3.js +2 -0
- package/extensions/dashboard-client/dist/assets/toggle-KdBnFLu3.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{useSSE-p1pOI_-P.js → useSSE-B6t44vzc.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-p1pOI_-P.js.map → useSSE-B6t44vzc.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +2 -2
- package/extensions/dashboard-client/package-lock.json +1995 -191
- package/extensions/dashboard-client/package.json +12 -1
- package/extensions/dashboard-client/postcss.config.js +6 -0
- package/extensions/dashboard-client/src/App.tsx +127 -88
- package/extensions/dashboard-client/src/api/client.ts +109 -10
- package/extensions/dashboard-client/src/components/ActiveReposTable.tsx +15 -7
- package/extensions/dashboard-client/src/components/ActiveSessionsTable.tsx +67 -55
- package/extensions/dashboard-client/src/components/CacheHitRateTrendCard.tsx +17 -13
- package/extensions/dashboard-client/src/components/CacheHitsCard.tsx +35 -30
- package/extensions/dashboard-client/src/components/CacheStatusPerModel.tsx +33 -28
- package/extensions/dashboard-client/src/components/EventCategoryFilter.tsx +5 -6
- package/extensions/dashboard-client/src/components/EventStream.tsx +17 -13
- package/extensions/dashboard-client/src/components/HydeDetailPanel.tsx +173 -0
- package/extensions/dashboard-client/src/components/LegendCard.tsx +16 -9
- package/extensions/dashboard-client/src/components/PerfCards.tsx +28 -20
- package/extensions/dashboard-client/src/components/PerfChart.tsx +9 -6
- package/extensions/dashboard-client/src/components/ProviderCacheCard.tsx +15 -7
- package/extensions/dashboard-client/src/components/RagDashboard.tsx +253 -0
- package/extensions/dashboard-client/src/components/RepoAllSessionsCard.tsx +15 -10
- package/extensions/dashboard-client/src/components/RepoContextStack.tsx +24 -16
- package/extensions/dashboard-client/src/components/RepoDetailModal.tsx +52 -49
- package/extensions/dashboard-client/src/components/RepoTable.tsx +26 -17
- package/extensions/dashboard-client/src/components/SessionContextGauges.tsx +11 -14
- package/extensions/dashboard-client/src/components/SessionInfo.tsx +20 -15
- package/extensions/dashboard-client/src/components/SessionsMemoryChart.tsx +8 -5
- package/extensions/dashboard-client/src/components/SummaryTiles.tsx +26 -17
- package/extensions/dashboard-client/src/components/TabBar.tsx +1 -3
- package/extensions/dashboard-client/src/components/layout/AppShell.tsx +42 -0
- package/extensions/dashboard-client/src/components/layout/BottomBar.tsx +88 -0
- package/extensions/dashboard-client/src/components/layout/Sidebar.tsx +83 -0
- package/extensions/dashboard-client/src/components/ui/badge.tsx +30 -0
- package/extensions/dashboard-client/src/components/ui/button.tsx +44 -0
- package/extensions/dashboard-client/src/components/ui/card.tsx +32 -0
- package/extensions/dashboard-client/src/components/ui/select.tsx +64 -0
- package/extensions/dashboard-client/src/components/ui/switch.tsx +26 -0
- package/extensions/dashboard-client/src/components/ui/tabs.tsx +36 -0
- package/extensions/dashboard-client/src/components/ui/toggle.tsx +28 -0
- package/extensions/dashboard-client/src/components/ui/tooltip.tsx +27 -0
- package/extensions/dashboard-client/src/config.ts +10 -0
- package/extensions/dashboard-client/src/main.tsx +2 -2
- package/extensions/dashboard-client/src/memory-map-layout.ts +1 -2
- package/extensions/dashboard-client/src/styles/index.css +79 -0
- package/extensions/dashboard-client/src/tabs/CacheTab.tsx +33 -26
- package/extensions/dashboard-client/src/tabs/EventsTab.tsx +22 -7
- package/extensions/dashboard-client/src/tabs/HealthTab.tsx +77 -46
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/ActionsCard.tsx +60 -50
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/DbStatsCard.tsx +61 -35
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/DebugBundleCard.tsx +34 -23
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/HealthMitigationCard.tsx +62 -43
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/SchemaHealthCard.tsx +53 -32
- package/extensions/dashboard-client/src/tabs/MaintenanceTab.tsx +2 -2
- package/extensions/dashboard-client/src/tabs/MemoryMapTab/MemoryMapView.tsx +29 -46
- package/extensions/dashboard-client/src/tabs/MemoryMapTab/RaptorTreeView.tsx +10 -34
- package/extensions/dashboard-client/src/tabs/MemoryMapTab.tsx +14 -34
- package/extensions/dashboard-client/src/tabs/MetricsTab.tsx +5 -2
- package/extensions/dashboard-client/src/tabs/OverviewTab.tsx +11 -5
- package/extensions/dashboard-client/src/tabs/ReposTab.tsx +5 -5
- package/extensions/dashboard-client/src/tabs/SessionsTab.tsx +47 -33
- package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderSetup.tsx +6 -2
- package/extensions/dashboard-client/src/tabs/SetupTab/RagHealthCard.tsx +78 -0
- package/extensions/dashboard-client/src/tabs/SetupTab/SettingsPanel.tsx +198 -0
- package/extensions/dashboard-client/src/tabs/SetupTab/SettingsSection.tsx +50 -0
- package/extensions/dashboard-client/src/tabs/SetupTab.tsx +21 -59
- package/extensions/dashboard-client/src/tabs/TopicsTab.tsx +75 -40
- package/extensions/dashboard-client/src/tabs/TurnsTab.tsx +150 -112
- package/extensions/dashboard-client/src/tabs/WikiTab/TopicEvolutionGraph.tsx +274 -0
- package/extensions/dashboard-client/src/tabs/WikiTab/TopicEvolutionView.tsx +71 -0
- package/extensions/dashboard-client/src/tabs/WikiTab/TopicTimeline.tsx +103 -0
- package/extensions/dashboard-client/src/tabs/WikiTab/WikiPage.tsx +213 -0
- package/extensions/dashboard-client/src/tabs/WikiTab/WikiPageControls.tsx +188 -0
- package/extensions/dashboard-client/src/tabs/WikiTab.tsx +222 -0
- package/extensions/dashboard-client/src/tabs/registry.ts +57 -0
- package/extensions/dashboard-client/src/utils/cn.ts +7 -0
- package/extensions/dashboard-client/tailwind.config.js +46 -0
- package/extensions/dashboard-server/api-contracts/core.ts +59 -0
- package/extensions/dashboard-server/api-contracts/endpoints/registry.ts +79 -0
- package/extensions/dashboard-server/api-contracts/index.ts +48 -2
- package/extensions/dashboard-server/api-contracts/rag-metrics.ts +22 -0
- package/extensions/dashboard-server/api-contracts/rag-settings.ts +30 -20
- package/extensions/dashboard-server/api-contracts/wiki.ts +138 -0
- package/extensions/dashboard-server/routes-rag-metrics.ts +82 -0
- package/extensions/dashboard-server/routes-rag-settings-helpers.ts +314 -0
- package/extensions/dashboard-server/routes-rag-settings.ts +147 -97
- package/extensions/dashboard-server/routes-wiki-helpers.ts +126 -0
- package/extensions/dashboard-server/routes-wiki.ts +376 -0
- package/extensions/dashboard-server/routes.ts +2 -0
- package/extensions/dashboard-server/server.ts +18 -2
- package/extensions/mega-events/context-handler/afterCompact.ts +44 -1
- package/extensions/mega-pipeline/recall.ts +31 -0
- package/extensions/mega-turn-store.ts +13 -0
- package/package.json +1 -1
- package/src/config/turns.ts +17 -0
- package/src/config.ts +3 -0
- package/src/recall/async.ts +10 -1
- package/src/recall/format.ts +15 -2
- package/src/recall/hydeTelemetry.ts +44 -0
- package/src/recall/sync.ts +34 -2
- package/src/recall/types.ts +36 -0
- package/src/store/turns/hydeStore.ts +82 -0
- package/src/store/turns/index.ts +4 -0
- package/src/store/turns/schema.ts +126 -1
- package/src/store/turns/sqlite-store/rows.ts +25 -0
- package/src/store/turns/sqlite-store/write.ts +20 -2
- package/src/store/turns/types.ts +33 -0
- package/src/topics/durability.ts +231 -0
- package/src/topics/index.ts +7 -1
- package/src/topics/store.ts +35 -9
- package/src/wiki/curation-helpers.ts +140 -0
- package/src/wiki/curation.ts +217 -0
- package/src/wiki/incremental.ts +164 -0
- package/src/wiki/index.ts +13 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-Cqnc7lMg.js +0 -2
- package/extensions/dashboard-client/dist/assets/CacheTab-Cqnc7lMg.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/EventsTab-tYk3VFAp.js +0 -2
- package/extensions/dashboard-client/dist/assets/EventsTab-tYk3VFAp.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/HealthTab-D2_kjgxw.js +0 -2
- package/extensions/dashboard-client/dist/assets/HealthTab-D2_kjgxw.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-Bc-uPYrz.js +0 -2
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-Bc-uPYrz.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-D1V9g_NC.js +0 -2
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-D1V9g_NC.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MetricsTab-DT_XfL96.js +0 -2
- package/extensions/dashboard-client/dist/assets/MetricsTab-DT_XfL96.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/OverviewTab-BY6KZCme.js +0 -2
- package/extensions/dashboard-client/dist/assets/OverviewTab-BY6KZCme.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/ReposTab-CeS-tpDM.js +0 -2
- package/extensions/dashboard-client/dist/assets/ReposTab-CeS-tpDM.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/SessionsTab-C30AwyoF.js +0 -70
- package/extensions/dashboard-client/dist/assets/SetupTab-BJUHOVK2.js +0 -2
- package/extensions/dashboard-client/dist/assets/SetupTab-BJUHOVK2.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-p55K1tFP.js +0 -2
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-p55K1tFP.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TopicsTab-D8FqyAbK.js +0 -2
- package/extensions/dashboard-client/dist/assets/TopicsTab-D8FqyAbK.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TurnsTab-ju-nXDys.js +0 -2
- package/extensions/dashboard-client/dist/assets/TurnsTab-ju-nXDys.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-BEj1Zahy.js +0 -42
- package/extensions/dashboard-client/dist/assets/index-BEj1Zahy.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-CUNn22iV.css +0 -1
- package/extensions/dashboard-client/src/styles/metrics-extra.css +0 -69
- package/extensions/dashboard-client/src/styles/turns.css +0 -142
- package/extensions/dashboard-client/src/tabs/SetupTab/RagSettingsCard.tsx +0 -160
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{j as e,u as A,r as k,f as B,B as E,s as G,h as I,N as z}from"./index-CQjCLvv7.js";import{C as n,a as h,b as u,c}from"./card-Cjn7Ifoe.js";import{g as D,L as $,X as j,Y as v,f as L,B as w,R as g,C as b,T as y,A as H,a as K,b as R}from"./AreaChart-KAmp_6bL.js";function x(s){return s>=1e3?`${(s/1e3).toFixed(1)}s`:`${s.toFixed(0)}ms`}function m({value:s,max:a,colorClass:t}){const l=a>0?Math.max(0,Math.min(100,s/a*100)):0;return e.jsx("div",{className:"perf-bar-track",children:e.jsx("div",{className:`perf-bar-fill ${t}`,style:{width:`${l}%`}})})}function U({perf:s}){const a=Math.max(s.turn_latency_ms.p95,s.provider_latency_ms.p95,1),t=Math.max(s.tps.avg,1);return e.jsxs(n,{children:[e.jsxs(h,{className:"flex-row items-center justify-between space-y-0",children:[e.jsx(u,{children:"Performance"}),e.jsxs("span",{className:"text-xs text-muted-foreground",children:[s.windowMinutes,"min window · ",s.sampleCount," samples"]})]}),e.jsxs(c,{children:[e.jsxs("div",{className:"perf-grid",children:[e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"Turn latency p50 / p95"}),e.jsxs("span",{className:"perf-value",children:[x(s.turn_latency_ms.p50)," /"," ",x(s.turn_latency_ms.p95)]}),e.jsx(m,{value:s.turn_latency_ms.p95,max:a,colorClass:"perf-blue"})]}),e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"Provider latency p50 / p95"}),e.jsxs("span",{className:"perf-value",children:[x(s.provider_latency_ms.p50)," /"," ",x(s.provider_latency_ms.p95)]}),e.jsx(m,{value:s.provider_latency_ms.p95,max:a,colorClass:"perf-purple"})]}),e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"Tokens/sec (avg)"}),e.jsx("span",{className:"perf-value",children:s.tps.avg.toFixed(1)}),e.jsx(m,{value:s.tps.avg,max:t,colorClass:"perf-green"})]}),e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"Cache hit (avg / latest)"}),e.jsxs("span",{className:"perf-value",children:[s.cache_hit_pct.avg.toFixed(1),"% /"," ",s.cache_hit_pct.latest.toFixed(1),"%"]}),e.jsx(m,{value:s.cache_hit_pct.avg,max:100,colorClass:"perf-green"})]}),e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"DB recompute p95"}),e.jsx("span",{className:"perf-value",children:x(s.db_recompute_ms.p95)}),e.jsx(m,{value:s.db_recompute_ms.p95,max:a,colorClass:"perf-yellow"})]}),e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"Disk write p95"}),e.jsx("span",{className:"perf-value",children:x(s.disk_write_ms.p95)}),e.jsx(m,{value:s.disk_write_ms.p95,max:a,colorClass:"perf-yellow"})]})]}),e.jsxs("div",{className:"perf-resources",children:[e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"RSS"}),e.jsxs("span",{className:"perf-value",children:[s.rss_mb.latest.toFixed(0)," MB"]})]}),e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"Heap"}),e.jsxs("span",{className:"perf-value",children:[s.heap_mb.latest.toFixed(0)," MB"]})]}),e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"CPU user"}),e.jsxs("span",{className:"perf-value",children:[(s.cpu_user_ms.latest/1e3).toFixed(1),"s"]})]}),e.jsxs("div",{className:"perf-metric",children:[e.jsx("span",{className:"perf-label",children:"CPU sys"}),e.jsxs("span",{className:"perf-value",children:[(s.cpu_sys_ms.latest/1e3).toFixed(1),"s"]})]})]}),s.diag&&e.jsxs("div",{className:"perf-diag",children:[e.jsxs("span",{className:"perf-label",children:["Fast-gate fires: ",s.diag.ctxFastGate]}),e.jsxs("span",{className:"perf-label",children:["Live trim fires: ",s.diag.liveTrimFires]}),e.jsxs("span",{className:"perf-label",children:["Live trim replays: ",s.diag.liveTrimReplays]})]})]})]})}function d(s){return s==null?"—":s>=100?`${Math.round(s)}ms`:`${s.toFixed(1)}ms`}function p(s,a){return s==null||typeof s!="number"?"—":s.toFixed(a)}function T(s){return s==null?"—":String(s)}function r({label:s,value:a}){return e.jsxs("div",{className:"flex items-baseline justify-between border-b border-border py-1 text-sm",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:s}),e.jsx("span",{className:"font-semibold",children:a})]})}function f({title:s,children:a}){return e.jsxs(n,{className:"electric-hover",children:[e.jsx(h,{children:e.jsx(u,{children:s})}),e.jsx(c,{children:a})]})}function O({perf:s}){const a=`${p(s.cpu_user_ms.latest,1)} / ${p(s.cpu_sys_ms.latest,1)} ms`;return e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3",children:[e.jsxs(f,{title:"Model latency",children:[e.jsx(r,{label:"Turn p50",value:d(s.turn_latency_ms.p50)}),e.jsx(r,{label:"Turn p95",value:d(s.turn_latency_ms.p95)}),e.jsx(r,{label:"Provider p50",value:d(s.provider_latency_ms.p50)}),e.jsx(r,{label:"Provider p95",value:d(s.provider_latency_ms.p95)})]}),e.jsxs(f,{title:"Throughput",children:[e.jsx(r,{label:"TPS (avg)",value:p(s.tps.avg,1)}),e.jsx(r,{label:"Cache hit %",value:`${p(s.cache_hit_pct.avg,1)}%`})]}),e.jsxs(f,{title:"Process",children:[e.jsx(r,{label:"RSS",value:`${p(s.rss_mb.latest,1)} MB`}),e.jsx(r,{label:"Heap",value:`${p(s.heap_mb.latest,1)} MB`}),e.jsx(r,{label:"CPU user / sys",value:a})]}),e.jsxs(f,{title:"Snapshot cost",children:[e.jsx(r,{label:"DB recompute p50",value:d(s.db_recompute_ms.p50)}),e.jsx(r,{label:"DB recompute p95",value:d(s.db_recompute_ms.p95)}),e.jsx(r,{label:"Disk write p50",value:d(s.disk_write_ms.p50)})]}),e.jsxs(f,{title:"TUI lag proxy",children:[e.jsx(r,{label:"Live-trim fires",value:T(s.diag?.liveTrimFires)}),e.jsx(r,{label:"Cache replays",value:T(s.diag?.liveTrimReplays)}),e.jsx(r,{label:"Fast-gate skips",value:T(s.diag?.ctxFastGate)}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"skip vs recompute vs replay cadence"})]})]})}function N({label:s,value:a,title:t}){return e.jsxs("div",{className:"model-field",title:t,children:[e.jsx("span",{className:"model-field-label",children:s}),e.jsx("span",{className:"model-field-value",children:a})]})}function X({name:s,providerName:a,provider:t,inputRate:l,outputRate:o}){const S=a||t||"—";return e.jsxs("div",{className:"model-badge",children:[e.jsx(N,{label:"Model",value:s,title:"The model pi is currently using — its pricing drives the cost figure."}),e.jsx(N,{label:"Provider",value:S,title:"The provider serving the model."}),e.jsx(N,{label:"Input Rate",value:`$${l.toFixed(6)}`,title:"USD per input token, from the model's pricing."}),e.jsx(N,{label:"Output Rate",value:`$${o.toFixed(6)}`,title:"USD per output token, from the model's pricing."})]})}var W=D({chartName:"LineChart",GraphicalChild:$,axisComponents:[{axisType:"xAxis",AxisComp:j},{axisType:"yAxis",AxisComp:v}],formatAxisMap:L}),M=D({chartName:"BarChart",GraphicalChild:w,defaultTooltipEventType:"axis",validateTooltipEventTypes:["axis","item"],axisComponents:[{axisType:"xAxis",AxisComp:j},{axisType:"yAxis",AxisComp:v}],formatAxisMap:L});const i="#8b949e",_="#30363d",C={background:"#161b22",border:"1px solid #30363d",borderRadius:"6px",color:"#e6edf3",fontSize:12};function Y(s){return s.map(a=>{const t=Math.max(0,a.recallCount-a.hydeRanCount);return{day:a.day.slice(5),avgLift:a.avgLift??0,avgScore:a.avgScore??0,avgGenMs:a.avgGenMs??0,passRate:a.avgScore==null?0:a.avgScore,hydeTurns:a.hydeRanCount,baseTurns:t,recallCount:a.recallCount}})}const Q=({metrics:s})=>{const{data:a,loading:t}=A(k.useMemo(()=>()=>B(),[]),{pollInterval:3e4}),l=s??a,o=k.useMemo(()=>l?Y(l.daily):[],[l]);if(t&&!l)return e.jsx("div",{className:"text-sm text-muted-foreground",children:"Loading RAG metrics…"});if(!l)return e.jsx("div",{className:"text-sm text-muted-foreground",children:"No RAG metrics available yet. They appear once turns record HyDE/recall telemetry."});const{totals:S,flags:P}=l;return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx(V,{totals:S,flags:P}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 lg:grid-cols-2",children:[e.jsxs(n,{children:[e.jsx(h,{children:e.jsx(u,{children:"HyDE Recall Lift"})}),e.jsx(c,{children:e.jsx(g,{width:"100%",height:200,children:e.jsxs(M,{data:o,margin:{top:8,right:12,left:0,bottom:0},children:[e.jsx(b,{strokeDasharray:"3 3",stroke:_}),e.jsx(j,{dataKey:"day",stroke:i,tick:{fontSize:11}}),e.jsx(v,{stroke:i,tick:{fontSize:11},width:40}),e.jsx(y,{contentStyle:C}),e.jsx(w,{dataKey:"avgLift",name:"avg lift",fill:"#58a6ff",isAnimationActive:!1})]})})})]}),e.jsxs(n,{children:[e.jsx(h,{children:e.jsx(u,{children:"CRAG Quality"})}),e.jsx(c,{children:e.jsx(g,{width:"100%",height:200,children:e.jsxs(W,{data:o,margin:{top:8,right:12,left:0,bottom:0},children:[e.jsx(b,{strokeDasharray:"3 3",stroke:_}),e.jsx(j,{dataKey:"day",stroke:i,tick:{fontSize:11}}),e.jsx(v,{stroke:i,tick:{fontSize:11},width:40,domain:[0,1]}),e.jsx(y,{contentStyle:C}),e.jsx($,{type:"monotone",dataKey:"avgScore",name:"avg score",stroke:"#3fb950",dot:!1,strokeWidth:2,isAnimationActive:!1})]})})})]}),e.jsxs(n,{children:[e.jsx(h,{children:e.jsx(u,{children:"Recall Latency (avg gen ms)"})}),e.jsx(c,{children:e.jsx(g,{width:"100%",height:200,children:e.jsxs(M,{data:o,margin:{top:8,right:12,left:0,bottom:0},children:[e.jsx(b,{strokeDasharray:"3 3",stroke:_}),e.jsx(j,{dataKey:"day",stroke:i,tick:{fontSize:11}}),e.jsx(v,{stroke:i,tick:{fontSize:11},width:40}),e.jsx(y,{contentStyle:C}),e.jsx(w,{dataKey:"avgGenMs",name:"gen ms",fill:"#d29922",isAnimationActive:!1})]})})})]}),e.jsxs(n,{children:[e.jsx(h,{children:e.jsx(u,{children:"HyDE vs Base Turn Volume"})}),e.jsx(c,{children:e.jsx(g,{width:"100%",height:200,children:e.jsxs(H,{data:o,margin:{top:8,right:12,left:0,bottom:0},children:[e.jsx(b,{strokeDasharray:"3 3",stroke:_}),e.jsx(j,{dataKey:"day",stroke:i,tick:{fontSize:11}}),e.jsx(v,{stroke:i,tick:{fontSize:11},width:40}),e.jsx(y,{contentStyle:C}),e.jsx(K,{wrapperStyle:{fontSize:11}}),e.jsx(R,{type:"monotone",dataKey:"hydeTurns",name:"hyde turns",stackId:"1",stroke:"#58a6ff",fill:"#58a6ff",fillOpacity:.5,isAnimationActive:!1}),e.jsx(R,{type:"monotone",dataKey:"baseTurns",name:"base turns",stackId:"1",stroke:"#8b949e",fill:"#8b949e",fillOpacity:.4,isAnimationActive:!1})]})})})]})]})]})};function V({totals:s,flags:a}){const t=[{label:"Telemetry turns",value:String(s.telemetryTurns),hint:"turns with HyDE or recall data"},{label:"HyDE ran",value:String(s.hydeRanTurns),hint:"turns where HyDE generated a doc"},{label:"Avg lift",value:`${s.avgLift.toFixed(2)}×`,hint:"fused / raw hit breadth"},{label:"Pass rate",value:`${Math.round(s.recentPassRate*100)}%`,hint:s.avgScore==null?"no scored turns":`avg score ${s.avgScore.toFixed(2)}`}];return e.jsxs("div",{className:"grid grid-cols-2 gap-4 lg:grid-cols-5",children:[t.map(l=>e.jsx(n,{children:e.jsxs(c,{children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:l.label}),e.jsx("div",{className:"font-heading text-2xl font-semibold text-foreground",children:l.value}),e.jsx("div",{className:"mt-0.5 text-xs text-muted-foreground",children:l.hint})]})},l.label)),e.jsx(n,{children:e.jsxs(c,{children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:"Flags"}),e.jsxs("div",{className:"mt-1 flex flex-col gap-1 text-xs",children:[e.jsx(F,{label:"HyDE",on:a.hydeEnabled}),e.jsx(F,{label:"Recall metrics",on:a.recallMetricsEnabled})]})]})})]})}function F({label:s,on:a}){return e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:`inline-block h-2 w-2 rounded-full ${a?"bg-success":"bg-danger"}`,"aria-hidden":"true"}),s,":"," ",e.jsx(E,{variant:a?"success":"danger",children:a?"on":"off"})]})}function ee(){const{data:s,error:a}=A(k.useCallback(()=>G({minutes:30}),[]),{pollInterval:1e4}),{data:t}=A(k.useCallback(()=>I(),[]),{pollInterval:1e4});return a&&!s?e.jsxs("div",{className:"tab-stub",children:["Error loading perf: ",a.message]}):s?e.jsxs("div",{className:"flex flex-col gap-4",children:[t?.model&&e.jsx(X,{name:t.model.name,providerName:t.model.providerName,provider:t.model.provider,inputRate:t.model.inputRate,outputRate:t.model.outputRate}),e.jsx(U,{perf:s}),e.jsx(O,{perf:s}),e.jsxs("div",{className:"text-xs text-muted-foreground",children:[s.sampleCount," samples · updated ",s.updatedAt]}),z()&&e.jsx(Q,{})]}):e.jsx("div",{className:"tab-stub",children:"Loading perf…"})}export{ee as default};
|
|
2
|
+
//# sourceMappingURL=MetricsTab-B7I4HWVg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MetricsTab-B7I4HWVg.js","sources":["../../src/components/PerfChart.tsx","../../src/components/PerfCards.tsx","../../src/components/ModelBadge.tsx","../../node_modules/recharts/es6/chart/LineChart.js","../../node_modules/recharts/es6/chart/BarChart.js","../../src/components/RagDashboard.tsx","../../src/tabs/MetricsTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/components/PerfChart.tsx — perf stat chart.\n *\n * The /api/perf endpoint returns rolling-window aggregates (not time-series),\n * so this renders a stat-card \"chart\": p50/p95 latency bars, TPS, cache hit %,\n * db recompute + disk write. Each metric shows a normalized bar + numeric.\n */\n\nimport type React from \"react\";\nimport type { PerfResponse } from \"@contracts\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"../components/ui/card\";\n\nexport interface PerfChartProps {\n\tperf: PerfResponse;\n}\n\nfunction fmtMs(n: number): string {\n\treturn n >= 1000 ? `${(n / 1000).toFixed(1)}s` : `${n.toFixed(0)}ms`;\n}\n\ninterface BarProps {\n\t/** Current value. */\n\tvalue: number;\n\t/** Value that represents 100% bar fill (the \"max\" reference). */\n\tmax: number;\n\t/** Color class. */\n\tcolorClass: string;\n}\n\nfunction Bar({ value, max, colorClass }: BarProps): React.ReactElement {\n\tconst pct = max > 0 ? Math.max(0, Math.min(100, (value / max) * 100)) : 0;\n\treturn (\n\t\t<div className=\"perf-bar-track\">\n\t\t\t<div\n\t\t\t\tclassName={`perf-bar-fill ${colorClass}`}\n\t\t\t\tstyle={{ width: `${pct}%` }}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n\nexport function PerfChart({ perf }: PerfChartProps): React.ReactElement {\n\t// Reference maxes: p95 is the upper bound for latency bars; rates scale to a\n\t// reasonable reference (tok/s) so bars are visually meaningful even with\n\t// small samples. cache_hit_pct is already 0-100.\n\tconst latencyMax = Math.max(\n\t\tperf.turn_latency_ms.p95,\n\t\tperf.provider_latency_ms.p95,\n\t\t1,\n\t);\n\tconst tpsRef = Math.max(perf.tps.avg, 1);\n\n\treturn (\n\t\t<Card>\n\t\t\t<CardHeader className=\"flex-row items-center justify-between space-y-0\">\n\t\t\t\t<CardTitle>Performance</CardTitle>\n\t\t\t\t<span className=\"text-xs text-muted-foreground\">\n\t\t\t\t\t{perf.windowMinutes}min window · {perf.sampleCount} samples\n\t\t\t\t</span>\n\t\t\t</CardHeader>\n\t\t\t<CardContent>\n\t\t\t<div className=\"perf-grid\">\n\t\t\t\t<div className=\"perf-metric\">\n\t\t\t\t\t<span className=\"perf-label\">Turn latency p50 / p95</span>\n\t\t\t\t\t<span className=\"perf-value\">\n\t\t\t\t\t\t{fmtMs(perf.turn_latency_ms.p50)} /{\" \"}\n\t\t\t\t\t\t{fmtMs(perf.turn_latency_ms.p95)}\n\t\t\t\t\t</span>\n\t\t\t\t\t<Bar\n\t\t\t\t\t\tvalue={perf.turn_latency_ms.p95}\n\t\t\t\t\t\tmax={latencyMax}\n\t\t\t\t\t\tcolorClass=\"perf-blue\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"perf-metric\">\n\t\t\t\t\t<span className=\"perf-label\">Provider latency p50 / p95</span>\n\t\t\t\t\t<span className=\"perf-value\">\n\t\t\t\t\t\t{fmtMs(perf.provider_latency_ms.p50)} /{\" \"}\n\t\t\t\t\t\t{fmtMs(perf.provider_latency_ms.p95)}\n\t\t\t\t\t</span>\n\t\t\t\t\t<Bar\n\t\t\t\t\t\tvalue={perf.provider_latency_ms.p95}\n\t\t\t\t\t\tmax={latencyMax}\n\t\t\t\t\t\tcolorClass=\"perf-purple\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"perf-metric\">\n\t\t\t\t\t<span className=\"perf-label\">Tokens/sec (avg)</span>\n\t\t\t\t\t<span className=\"perf-value\">{perf.tps.avg.toFixed(1)}</span>\n\t\t\t\t\t<Bar value={perf.tps.avg} max={tpsRef} colorClass=\"perf-green\" />\n\t\t\t\t</div>\n\t\t\t\t<div className=\"perf-metric\">\n\t\t\t\t\t<span className=\"perf-label\">Cache hit (avg / latest)</span>\n\t\t\t\t\t<span className=\"perf-value\">\n\t\t\t\t\t\t{perf.cache_hit_pct.avg.toFixed(1)}% /{\" \"}\n\t\t\t\t\t\t{perf.cache_hit_pct.latest.toFixed(1)}%\n\t\t\t\t\t</span>\n\t\t\t\t\t<Bar\n\t\t\t\t\t\tvalue={perf.cache_hit_pct.avg}\n\t\t\t\t\t\tmax={100}\n\t\t\t\t\t\tcolorClass=\"perf-green\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"perf-metric\">\n\t\t\t\t\t<span className=\"perf-label\">DB recompute p95</span>\n\t\t\t\t\t<span className=\"perf-value\">{fmtMs(perf.db_recompute_ms.p95)}</span>\n\t\t\t\t\t<Bar\n\t\t\t\t\t\tvalue={perf.db_recompute_ms.p95}\n\t\t\t\t\t\tmax={latencyMax}\n\t\t\t\t\t\tcolorClass=\"perf-yellow\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"perf-metric\">\n\t\t\t\t\t<span className=\"perf-label\">Disk write p95</span>\n\t\t\t\t\t<span className=\"perf-value\">{fmtMs(perf.disk_write_ms.p95)}</span>\n\t\t\t\t\t<Bar\n\t\t\t\t\t\tvalue={perf.disk_write_ms.p95}\n\t\t\t\t\t\tmax={latencyMax}\n\t\t\t\t\t\tcolorClass=\"perf-yellow\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div className=\"perf-resources\">\n\t\t\t\t<div className=\"perf-metric\">\n\t\t\t\t\t<span className=\"perf-label\">RSS</span>\n\t\t\t\t\t<span className=\"perf-value\">{perf.rss_mb.latest.toFixed(0)} MB</span>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"perf-metric\">\n\t\t\t\t\t<span className=\"perf-label\">Heap</span>\n\t\t\t\t\t<span className=\"perf-value\">\n\t\t\t\t\t\t{perf.heap_mb.latest.toFixed(0)} MB\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"perf-metric\">\n\t\t\t\t\t<span className=\"perf-label\">CPU user</span>\n\t\t\t\t\t<span className=\"perf-value\">\n\t\t\t\t\t\t{(perf.cpu_user_ms.latest / 1000).toFixed(1)}s\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"perf-metric\">\n\t\t\t\t\t<span className=\"perf-label\">CPU sys</span>\n\t\t\t\t\t<span className=\"perf-value\">\n\t\t\t\t\t\t{(perf.cpu_sys_ms.latest / 1000).toFixed(1)}s\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t{perf.diag && (\n\t\t\t\t<div className=\"perf-diag\">\n\t\t\t\t\t<span className=\"perf-label\">\n\t\t\t\t\t\tFast-gate fires: {perf.diag.ctxFastGate}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span className=\"perf-label\">\n\t\t\t\t\t\tLive trim fires: {perf.diag.liveTrimFires}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span className=\"perf-label\">\n\t\t\t\t\t\tLive trim replays: {perf.diag.liveTrimReplays}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t</CardContent>\n\t\t</Card>\n\t);\n}\n","/**\n * dashboard-client/src/components/PerfCards.tsx — 5 perf metric cards.\n *\n * Mirrors the old html.ts perf grid: model latency, throughput, process,\n * snapshot cost, and TUI lag proxy. Uses the existing perf-metric CSS\n * classes from repos-metrics.css plus metrics-extra.css for card headers.\n */\n\nimport type React from \"react\";\nimport type { PerfResponse } from \"@contracts\";\nimport {\n\tCard,\n\tCardContent,\n\tCardHeader,\n\tCardTitle,\n} from \"../components/ui/card\";\n\n/** Format milliseconds (em-dash for null/undefined). */\nfunction fmtMs(v: number | null | undefined): string {\n\treturn v == null ? \"\\u2014\" : v >= 100 ? `${Math.round(v)}ms` : `${v.toFixed(1)}ms`;\n}\n\n/** Format a number with fixed decimals (em-dash for null/non-number). */\nfunction fmtNum(v: number | null | undefined, dec: number): string {\n\treturn v == null || typeof v !== \"number\" ? \"\\u2014\" : v.toFixed(dec);\n}\n\n/** Format a diag counter (em-dash for null). */\nfunction fmtDiag(v: number | null | undefined): string {\n\treturn v == null ? \"\\u2014\" : String(v);\n}\n\ninterface PerfCardsProps {\n\tperf: PerfResponse;\n}\n\n/** A single stat row inside a perf card. */\nfunction Stat({ label, value }: { label: string; value: string }): React.ReactElement {\n\treturn (\n\t\t<div className=\"flex items-baseline justify-between border-b border-border py-1 text-sm\">\n\t\t\t<span className=\"text-xs text-muted-foreground\">{label}</span>\n\t\t\t<span className=\"font-semibold\">{value}</span>\n\t\t</div>\n\t);\n}\n\n/** Card wrapper with a title. */\nfunction PerfCard({ title, children }: { title: string; children: React.ReactNode }): React.ReactElement {\n\treturn (\n\t\t<Card className=\"electric-hover\">\n\t\t\t<CardHeader>\n\t\t\t\t<CardTitle>{title}</CardTitle>\n\t\t\t</CardHeader>\n\t\t\t<CardContent>{children}</CardContent>\n\t\t</Card>\n\t);\n}\n\nexport function PerfCards({ perf }: PerfCardsProps): React.ReactElement {\n\tconst cpuTxt = `${fmtNum(perf.cpu_user_ms.latest, 1)} / ${fmtNum(perf.cpu_sys_ms.latest, 1)} ms`;\n\n\treturn (\n\t\t<div className=\"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3\">\n\t\t\t<PerfCard title=\"Model latency\">\n\t\t\t\t<Stat label=\"Turn p50\" value={fmtMs(perf.turn_latency_ms.p50)} />\n\t\t\t\t<Stat label=\"Turn p95\" value={fmtMs(perf.turn_latency_ms.p95)} />\n\t\t\t\t<Stat label=\"Provider p50\" value={fmtMs(perf.provider_latency_ms.p50)} />\n\t\t\t\t<Stat label=\"Provider p95\" value={fmtMs(perf.provider_latency_ms.p95)} />\n\t\t\t</PerfCard>\n\n\t\t\t<PerfCard title=\"Throughput\">\n\t\t\t\t<Stat label=\"TPS (avg)\" value={fmtNum(perf.tps.avg, 1)} />\n\t\t\t\t<Stat\n\t\t\t\t\tlabel=\"Cache hit %\"\n\t\t\t\t\tvalue={`${fmtNum(perf.cache_hit_pct.avg, 1)}%`}\n\t\t\t\t/>\n\t\t\t</PerfCard>\n\n\t\t\t<PerfCard title=\"Process\">\n\t\t\t\t<Stat label=\"RSS\" value={`${fmtNum(perf.rss_mb.latest, 1)} MB`} />\n\t\t\t\t<Stat label=\"Heap\" value={`${fmtNum(perf.heap_mb.latest, 1)} MB`} />\n\t\t\t\t<Stat label=\"CPU user / sys\" value={cpuTxt} />\n\t\t\t</PerfCard>\n\n\t\t\t<PerfCard title=\"Snapshot cost\">\n\t\t\t\t<Stat label=\"DB recompute p50\" value={fmtMs(perf.db_recompute_ms.p50)} />\n\t\t\t\t<Stat label=\"DB recompute p95\" value={fmtMs(perf.db_recompute_ms.p95)} />\n\t\t\t\t<Stat label=\"Disk write p50\" value={fmtMs(perf.disk_write_ms.p50)} />\n\t\t\t</PerfCard>\n\n\t\t\t<PerfCard title=\"TUI lag proxy\">\n\t\t\t\t<Stat label=\"Live-trim fires\" value={fmtDiag(perf.diag?.liveTrimFires)} />\n\t\t\t\t<Stat label=\"Cache replays\" value={fmtDiag(perf.diag?.liveTrimReplays)} />\n\t\t\t\t<Stat label=\"Fast-gate skips\" value={fmtDiag(perf.diag?.ctxFastGate)} />\n\t\t\t\t<span className=\"text-xs text-muted-foreground\">skip vs recompute vs replay cadence</span>\n\t\t\t</PerfCard>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/components/ModelBadge.tsx — model + provider + rates.\n *\n * Shows the active model name, provider, and input/output rates.\n * Tooltips copied verbatim from html.ts. Used in the Metrics tab header.\n */\n\nimport type React from \"react\";\n\nexport interface ModelBadgeProps {\n\t/** Model name/identifier. */\n\tname: string;\n\t/** Human-readable provider name. */\n\tproviderName: string;\n\t/** Machine-readable provider identifier. */\n\tprovider: string;\n\t/** USD per input token (from model pricing). */\n\tinputRate: number;\n\t/** USD per output token (from model pricing). */\n\toutputRate: number;\n}\n\nfunction Field({\n\tlabel,\n\tvalue,\n\ttitle,\n}: {\n\tlabel: string;\n\tvalue: string;\n\ttitle?: string;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"model-field\" title={title}>\n\t\t\t<span className=\"model-field-label\">{label}</span>\n\t\t\t<span className=\"model-field-value\">{value}</span>\n\t\t</div>\n\t);\n}\n\nexport function ModelBadge({\n\tname,\n\tproviderName,\n\tprovider,\n\tinputRate,\n\toutputRate,\n}: ModelBadgeProps): React.ReactElement {\n\tconst providerDisplay = providerName || provider || \"—\";\n\treturn (\n\t\t<div className=\"model-badge\">\n\t\t\t<Field\n\t\t\t\tlabel=\"Model\"\n\t\t\t\tvalue={name}\n\t\t\t\ttitle=\"The model pi is currently using — its pricing drives the cost figure.\"\n\t\t\t/>\n\t\t\t<Field\n\t\t\t\tlabel=\"Provider\"\n\t\t\t\tvalue={providerDisplay}\n\t\t\t\ttitle=\"The provider serving the model.\"\n\t\t\t/>\n\t\t\t<Field\n\t\t\t\tlabel=\"Input Rate\"\n\t\t\t\tvalue={`$${inputRate.toFixed(6)}`}\n\t\t\t\ttitle=\"USD per input token, from the model's pricing.\"\n\t\t\t/>\n\t\t\t<Field\n\t\t\t\tlabel=\"Output Rate\"\n\t\t\t\tvalue={`$${outputRate.toFixed(6)}`}\n\t\t\t\ttitle=\"USD per output token, from the model's pricing.\"\n\t\t\t/>\n\t\t</div>\n\t);\n}\n","/**\n * @fileOverview Line Chart\n */\nimport { generateCategoricalChart } from './generateCategoricalChart';\nimport { Line } from '../cartesian/Line';\nimport { XAxis } from '../cartesian/XAxis';\nimport { YAxis } from '../cartesian/YAxis';\nimport { formatAxisMap } from '../util/CartesianUtils';\nexport var LineChart = generateCategoricalChart({\n chartName: 'LineChart',\n GraphicalChild: Line,\n axisComponents: [{\n axisType: 'xAxis',\n AxisComp: XAxis\n }, {\n axisType: 'yAxis',\n AxisComp: YAxis\n }],\n formatAxisMap: formatAxisMap\n});","/**\n * @fileOverview Bar Chart\n */\nimport { generateCategoricalChart } from './generateCategoricalChart';\nimport { Bar } from '../cartesian/Bar';\nimport { XAxis } from '../cartesian/XAxis';\nimport { YAxis } from '../cartesian/YAxis';\nimport { formatAxisMap } from '../util/CartesianUtils';\nexport var BarChart = generateCategoricalChart({\n chartName: 'BarChart',\n GraphicalChild: Bar,\n defaultTooltipEventType: 'axis',\n validateTooltipEventTypes: ['axis', 'item'],\n axisComponents: [{\n axisType: 'xAxis',\n AxisComp: XAxis\n }, {\n axisType: 'yAxis',\n AxisComp: YAxis\n }],\n formatAxisMap: formatAxisMap\n});","/**\n * dashboard-client/src/components/RagDashboard.tsx — full RAG metrics section\n * (H3.2). Rendered in the Metrics tab.\n *\n * Fetches /api/rag-metrics and renders:\n * 1. Stat row: telemetry turns, HyDE-ran count, avg lift, pass rate.\n * 2. HyDE Recall Lift Bar (BarChart over daily avg lift).\n * 3. CRAG Quality Line (LineChart over daily avg score).\n * 4. Per-flag status dots (hydeEnabled, recallMetricsEnabled).\n * 5. Recall Latency Stacked Bar (hyde vs base turn counts) + Hit-Rate Area.\n *\n * PREVENT-PI-004: relative-path fetch to the same-origin dashboard server.\n * recharts is bundled into this localhost-served static bundle (no runtime\n * network calls).\n */\n\nimport type React from \"react\";\nimport { useMemo } from \"react\";\nimport { useApi } from \"../hooks/useApi\";\nimport { fetchRagMetrics } from \"../api/client\";\nimport type { RagMetricsResponse } from \"@contracts\";\n\n/** Daily-aggregate row shape (derived from the rag-metrics contract). */\ntype DailyTelemetry = RagMetricsResponse[\"daily\"][number];\nimport {\n\tResponsiveContainer,\n\tBarChart,\n\tBar,\n\tLineChart,\n\tLine,\n\tAreaChart,\n\tArea,\n\tXAxis,\n\tYAxis,\n\tCartesianGrid,\n\tTooltip,\n\tLegend,\n} from \"recharts\";\nimport { Card, CardHeader, CardTitle, CardContent } from \"./ui/card\";\nimport { Badge } from \"./ui/badge\";\n\nconst AXIS = \"#8b949e\";\nconst GRID = \"#30363d\";\nconst TOOLTIP = {\n\tbackground: \"#161b22\",\n\tborder: \"1px solid #30363d\",\n\tborderRadius: \"6px\",\n\tcolor: \"#e6edf3\",\n\tfontSize: 12,\n} as const;\n\n/** One row per day, with lead/lag-safe derived series for the charts. */\ninterface DailyRow {\n\tday: string;\n\tavgLift: number;\n\tavgScore: number;\n\tavgGenMs: number;\n\tpassRate: number;\n\thydeTurns: number;\n\tbaseTurns: number;\n\trecallCount: number;\n}\n\nfunction toRows(daily: DailyTelemetry[]): DailyRow[] {\n\treturn daily.map((d) => {\n\t\tconst baseTurns = Math.max(0, d.recallCount - d.hydeRanCount);\n\t\treturn {\n\t\t\tday: d.day.slice(5), // \"MM-DD\"\n\t\t\tavgLift: d.avgLift ?? 0,\n\t\t\tavgScore: d.avgScore ?? 0,\n\t\t\tavgGenMs: d.avgGenMs ?? 0,\n\t\t\tpassRate: d.avgScore == null ? 0 : d.avgScore,\n\t\t\thydeTurns: d.hydeRanCount,\n\t\t\tbaseTurns,\n\t\t\trecallCount: d.recallCount,\n\t\t};\n\t});\n}\n\nexport interface RagDashboardProps {\n\t/** Optional pre-fetched metrics; when absent, the card fetches inline. */\n\tmetrics?: RagMetricsResponse | null;\n}\n\nexport const RagDashboard: React.FC<RagDashboardProps> = ({ metrics }) => {\n\tconst { data, loading } = useApi<RagMetricsResponse>(\n\t\tuseMemo(() => () => fetchRagMetrics(), []),\n\t\t{ pollInterval: 30_000 },\n\t);\n\tconst m = metrics ?? data;\n\tconst rows = useMemo(() => (m ? toRows(m.daily) : []), [m]);\n\n\tif (loading && !m) {\n\t\treturn <div className=\"text-sm text-muted-foreground\">Loading RAG metrics…</div>;\n\t}\n\tif (!m) {\n\t\treturn (\n\t\t\t<div className=\"text-sm text-muted-foreground\">\n\t\t\t\tNo RAG metrics available yet. They appear once turns record HyDE/recall\n\t\t\t\ttelemetry.\n\t\t\t</div>\n\t\t);\n\t}\n\n\tconst { totals, flags } = m;\n\n\treturn (\n\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t<StatRow totals={totals} flags={flags} />\n\n\t\t\t<div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n\t\t\t\t<Card>\n\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t<CardTitle>HyDE Recall Lift</CardTitle>\n\t\t\t\t\t</CardHeader>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<ResponsiveContainer width=\"100%\" height={200}>\n\t\t\t\t\t\t\t<BarChart data={rows} margin={{ top: 8, right: 12, left: 0, bottom: 0 }}>\n\t\t\t\t\t\t\t\t<CartesianGrid strokeDasharray=\"3 3\" stroke={GRID} />\n\t\t\t\t\t\t\t\t<XAxis dataKey=\"day\" stroke={AXIS} tick={{ fontSize: 11 }} />\n\t\t\t\t\t\t\t\t<YAxis stroke={AXIS} tick={{ fontSize: 11 }} width={40} />\n\t\t\t\t\t\t\t\t<Tooltip contentStyle={TOOLTIP} />\n\t\t\t\t\t\t\t\t<Bar dataKey=\"avgLift\" name=\"avg lift\" fill=\"#58a6ff\" isAnimationActive={false} />\n\t\t\t\t\t\t\t</BarChart>\n\t\t\t\t\t\t</ResponsiveContainer>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\n\t\t\t\t<Card>\n\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t<CardTitle>CRAG Quality</CardTitle>\n\t\t\t\t\t</CardHeader>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<ResponsiveContainer width=\"100%\" height={200}>\n\t\t\t\t\t\t\t<LineChart data={rows} margin={{ top: 8, right: 12, left: 0, bottom: 0 }}>\n\t\t\t\t\t\t\t\t<CartesianGrid strokeDasharray=\"3 3\" stroke={GRID} />\n\t\t\t\t\t\t\t\t<XAxis dataKey=\"day\" stroke={AXIS} tick={{ fontSize: 11 }} />\n\t\t\t\t\t\t\t\t<YAxis stroke={AXIS} tick={{ fontSize: 11 }} width={40} domain={[0, 1]} />\n\t\t\t\t\t\t\t\t<Tooltip contentStyle={TOOLTIP} />\n\t\t\t\t\t\t\t\t<Line type=\"monotone\" dataKey=\"avgScore\" name=\"avg score\" stroke=\"#3fb950\" dot={false} strokeWidth={2} isAnimationActive={false} />\n\t\t\t\t\t\t\t</LineChart>\n\t\t\t\t\t\t</ResponsiveContainer>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\n\t\t\t\t<Card>\n\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t<CardTitle>Recall Latency (avg gen ms)</CardTitle>\n\t\t\t\t\t</CardHeader>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<ResponsiveContainer width=\"100%\" height={200}>\n\t\t\t\t\t\t\t<BarChart data={rows} margin={{ top: 8, right: 12, left: 0, bottom: 0 }}>\n\t\t\t\t\t\t\t\t<CartesianGrid strokeDasharray=\"3 3\" stroke={GRID} />\n\t\t\t\t\t\t\t\t<XAxis dataKey=\"day\" stroke={AXIS} tick={{ fontSize: 11 }} />\n\t\t\t\t\t\t\t\t<YAxis stroke={AXIS} tick={{ fontSize: 11 }} width={40} />\n\t\t\t\t\t\t\t\t<Tooltip contentStyle={TOOLTIP} />\n\t\t\t\t\t\t\t\t<Bar dataKey=\"avgGenMs\" name=\"gen ms\" fill=\"#d29922\" isAnimationActive={false} />\n\t\t\t\t\t\t\t</BarChart>\n\t\t\t\t\t\t</ResponsiveContainer>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\n\t\t\t\t<Card>\n\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t<CardTitle>HyDE vs Base Turn Volume</CardTitle>\n\t\t\t\t\t</CardHeader>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<ResponsiveContainer width=\"100%\" height={200}>\n\t\t\t\t\t\t\t<AreaChart data={rows} margin={{ top: 8, right: 12, left: 0, bottom: 0 }}>\n\t\t\t\t\t\t\t\t<CartesianGrid strokeDasharray=\"3 3\" stroke={GRID} />\n\t\t\t\t\t\t\t\t<XAxis dataKey=\"day\" stroke={AXIS} tick={{ fontSize: 11 }} />\n\t\t\t\t\t\t\t\t<YAxis stroke={AXIS} tick={{ fontSize: 11 }} width={40} />\n\t\t\t\t\t\t\t\t<Tooltip contentStyle={TOOLTIP} />\n\t\t\t\t\t\t\t\t<Legend wrapperStyle={{ fontSize: 11 }} />\n\t\t\t\t\t\t\t\t<Area type=\"monotone\" dataKey=\"hydeTurns\" name=\"hyde turns\" stackId=\"1\" stroke=\"#58a6ff\" fill=\"#58a6ff\" fillOpacity={0.5} isAnimationActive={false} />\n\t\t\t\t\t\t\t\t<Area type=\"monotone\" dataKey=\"baseTurns\" name=\"base turns\" stackId=\"1\" stroke=\"#8b949e\" fill=\"#8b949e\" fillOpacity={0.4} isAnimationActive={false} />\n\t\t\t\t\t\t\t</AreaChart>\n\t\t\t\t\t\t</ResponsiveContainer>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t</div>\n\t\t</div>\n\t);\n};\n\nfunction StatRow({\n\ttotals,\n\tflags,\n}: {\n\ttotals: RagMetricsResponse[\"totals\"];\n\tflags: RagMetricsResponse[\"flags\"];\n}): React.ReactElement {\n\tconst stats: Array<{ label: string; value: string; hint: string }> = [\n\t\t{\n\t\t\tlabel: \"Telemetry turns\",\n\t\t\tvalue: String(totals.telemetryTurns),\n\t\t\thint: \"turns with HyDE or recall data\",\n\t\t},\n\t\t{\n\t\t\tlabel: \"HyDE ran\",\n\t\t\tvalue: String(totals.hydeRanTurns),\n\t\t\thint: \"turns where HyDE generated a doc\",\n\t\t},\n\t\t{\n\t\t\tlabel: \"Avg lift\",\n\t\t\tvalue: `${totals.avgLift.toFixed(2)}×`,\n\t\t\thint: \"fused / raw hit breadth\",\n\t\t},\n\t\t{\n\t\t\tlabel: \"Pass rate\",\n\t\t\tvalue: `${Math.round(totals.recentPassRate * 100)}%`,\n\t\t\thint: totals.avgScore == null ? \"no scored turns\" : `avg score ${totals.avgScore.toFixed(2)}`,\n\t\t},\n\t];\n\n\treturn (\n\t\t<div className=\"grid grid-cols-2 gap-4 lg:grid-cols-5\">\n\t\t\t{stats.map((s) => (\n\t\t\t\t<Card key={s.label}>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<div className=\"text-xs text-muted-foreground\">{s.label}</div>\n\t\t\t\t\t\t<div className=\"font-heading text-2xl font-semibold text-foreground\">\n\t\t\t\t\t\t\t{s.value}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"mt-0.5 text-xs text-muted-foreground\">{s.hint}</div>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t))}\n\t\t\t<Card>\n\t\t\t\t<CardContent>\n\t\t\t\t\t<div className=\"text-xs text-muted-foreground\">Flags</div>\n\t\t\t\t\t<div className=\"mt-1 flex flex-col gap-1 text-xs\">\n\t\t\t\t\t\t<FlagDot label=\"HyDE\" on={flags.hydeEnabled} />\n\t\t\t\t\t\t<FlagDot label=\"Recall metrics\" on={flags.recallMetricsEnabled} />\n\t\t\t\t\t</div>\n\t\t\t\t</CardContent>\n\t\t\t</Card>\n\t\t</div>\n\t);\n}\n\nfunction FlagDot({ label, on }: { label: string; on: boolean }): React.ReactElement {\n\treturn (\n\t\t<span className=\"flex items-center gap-1.5\">\n\t\t\t<span\n\t\t\t\tclassName={`inline-block h-2 w-2 rounded-full ${on ? \"bg-success\" : \"bg-danger\"}`}\n\t\t\t\taria-hidden=\"true\"\n\t\t\t/>\n\t\t\t{label}:{\" \"}\n\t\t\t<Badge variant={on ? \"success\" : \"danger\"}>{on ? \"on\" : \"off\"}</Badge>\n\t\t</span>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/MetricsTab.tsx — Metrics tab (C2).\n *\n * Fetches /api/perf (rolling-window aggregates) + /api/snapshot (for model).\n * Renders ModelBadge + PerfChart + 5 perf cards (latency, throughput, process,\n * snapshot cost, TUI lag proxy). Polls every 10s.\n */\n\nimport type React from \"react\";\nimport { useCallback } from \"react\";\nimport { useApi } from \"../hooks/useApi\";\nimport { fetchPerf, fetchSnapshot } from \"../api/client\";\nimport type { PerfResponse, SnapshotResponse } from \"@contracts\";\nimport { NEW_UI } from \"../config\";\nimport { PerfChart } from \"../components/PerfChart\";\nimport { PerfCards } from \"../components/PerfCards\";\nimport { ModelBadge } from \"../components/ModelBadge\";\nimport { RagDashboard } from \"../components/RagDashboard\";\n\nexport default function MetricsTab(): React.ReactElement {\n\tconst { data: perf, error: perfErr } = useApi<PerfResponse>(\n\t\tuseCallback(() => fetchPerf({ minutes: 30 }), []),\n\t\t{ pollInterval: 10_000 },\n\t);\n\tconst { data: snapshot } = useApi<SnapshotResponse>(\n\t\tuseCallback(() => fetchSnapshot(), []),\n\t\t{ pollInterval: 10_000 },\n\t);\n\n\tif (perfErr && !perf) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">Error loading perf: {perfErr.message}</div>\n\t\t);\n\t}\n\tif (!perf) {\n\t\treturn <div className=\"tab-stub\">Loading perf…</div>;\n\t}\n\n\treturn (\n\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t{snapshot?.model && (\n\t\t\t\t<ModelBadge\n\t\t\t\t\tname={snapshot.model.name}\n\t\t\t\t\tproviderName={snapshot.model.providerName}\n\t\t\t\t\tprovider={snapshot.model.provider}\n\t\t\t\t\tinputRate={snapshot.model.inputRate}\n\t\t\t\t\toutputRate={snapshot.model.outputRate}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t<PerfChart perf={perf} />\n\t\t\t<PerfCards perf={perf} />\n\t\t\t<div className=\"text-xs text-muted-foreground\">\n\t\t\t\t{perf.sampleCount} samples · updated {perf.updatedAt}\n\t\t\t</div>\n\t\t\t{NEW_UI() && <RagDashboard />}\n\t\t</div>\n\t);\n}\n"],"names":["fmtMs","n","Bar","value","max","colorClass","pct","jsx","PerfChart","perf","latencyMax","tpsRef","Card","jsxs","CardHeader","CardTitle","CardContent","v","fmtNum","dec","fmtDiag","Stat","label","PerfCard","title","children","PerfCards","cpuTxt","Field","ModelBadge","name","providerName","provider","inputRate","outputRate","providerDisplay","LineChart","generateCategoricalChart","Line","XAxis","YAxis","formatAxisMap","BarChart","AXIS","GRID","TOOLTIP","toRows","daily","d","baseTurns","RagDashboard","metrics","data","loading","useApi","useMemo","fetchRagMetrics","m","rows","totals","flags","StatRow","ResponsiveContainer","CartesianGrid","Tooltip","AreaChart","Legend","Area","stats","s","FlagDot","on","Badge","MetricsTab","perfErr","useCallback","fetchPerf","snapshot","fetchSnapshot","NEW_UI"],"mappings":"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","x_google_ignoreList":[3,4]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{j as e,u as _,r as C,f as B,a as U,B as K,N as z}from"./index-CQjCLvv7.js";import{u as V}from"./useSSE-B6t44vzc.js";import{C as p,a as k,b as N,c as f}from"./card-Cjn7Ifoe.js";import{f as v,a as I}from"./format-COjDIVGj.js";import{C as q,T as X}from"./TimeSavedCard-DwgCzPD9.js";const E=["#58a6ff","#3fb950","#d29922","#f85149","#bc8cff","#ff7b72","#79c0ff","#56d4dd","#e3b341","#a5d6ff","#7ee787","#ffa657"];function J(s){let t=5381;for(let n=0;n<s.length;n++)t=(t<<5)+t+s.charCodeAt(n)>>>0;return t}function Q(s){return s?E[J(s)%E.length]:E[0]}function Y(s){if(!s)return"(unknown)";const t=s.replace(/[\\/]+$/,"");if(!t)return"(unknown)";const n=t.split(/[\\/]/);return n[n.length-1]||t}function Z(s){const t=new Map;for(const r of s){const i=r.repoRoot??"__null__",u=r.tokens??0,m=t.get(i);if(m)m.tokens+=u;else{const c=Y(r.repoRoot);t.set(i,{repoRoot:r.repoRoot,basename:c,tokens:u,color:Q(c)})}}const n=[...t.values()],o=n.reduce((r,i)=>r+i.tokens,0),l=s.reduce((r,i)=>Math.max(r,i.ctxWindow),0);return{repos:n,totalTokens:o,maxWindow:l,sessionCount:s.length}}function F(s){return s>=1e5?`${(s/1e3).toFixed(0)}k`:s.toLocaleString()}function L({children:s}){return e.jsxs(p,{className:"electric-hover",children:[e.jsx(k,{children:e.jsx(N,{children:"Context per Repo (live)"})}),e.jsx(f,{children:s})]})}function ee({sessions:s,loading:t,error:n}){if(n)return e.jsx(L,{children:e.jsxs("span",{className:"text-sm text-muted-foreground",children:["Error loading sessions: ",n.message]})});if(t&&!s)return e.jsx(L,{children:e.jsx("span",{className:"text-sm text-muted-foreground",children:"Loading sessions…"})});const o=s?.sessions??[],{repos:l,totalTokens:r,maxWindow:i,sessionCount:u}=Z(o);if(l.length===0)return e.jsx(L,{children:e.jsx("span",{className:"text-sm text-muted-foreground",children:"No active sessions."})});const m=i>0?Math.round(r/i*100):0;return e.jsxs(L,{children:[e.jsx("div",{className:"repo-stack-bar",role:"group","aria-label":"Per-repo context usage",children:l.map(c=>{const a=r>0?c.tokens/r*100:0,x=r>0?a:0,d=`${c.basename}: ${F(c.tokens)} tokens (${a.toFixed(1)}% of total)`;return e.jsx("div",{className:"repo-stack-segment",style:{width:`${Math.max(x,.5)}%`,backgroundColor:c.color},title:d,"aria-label":d},c.repoRoot??"__null__")})}),e.jsxs("p",{className:"repo-stack-total",children:[F(r)," tokens across ",l.length," ",l.length===1?"repo":"repos"," /"," ",u," ",u===1?"session":"sessions"," ",e.jsxs("span",{className:"pct",children:["— ",m,"% of combined max window"]})]}),e.jsx("div",{className:"repo-stack-legend",children:l.map(c=>{const a=r>0?c.tokens/r*100:0;return e.jsxs("div",{className:"repo-stack-legend-item",children:[e.jsx("span",{className:"repo-stack-legend-swatch",style:{backgroundColor:c.color}}),e.jsx("span",{className:"repo-stack-legend-name",children:c.basename}),e.jsxs("span",{children:[F(c.tokens)," (",a.toFixed(0),"%)"]})]},c.repoRoot??"__null__")})})]})}function se(s){return s>=90?"gauge-red":s>=70?"gauge-yellow":"gauge-green"}function te(s){return s==null?"?":s>=1e5?`${(s/1e3).toFixed(0)}k`:s.toLocaleString()}function ne(s){if(!s)return"(unknown)";const t=s.replace(/[\\/]+$/,"");if(!t)return"(unknown)";const n=t.split(/[\\/]/);return n[n.length-1]||t}function ae(s){const t=Math.max(0,Math.round(s/1e3));if(t<60)return`${t}s ago`;const n=Math.floor(t/60);return n<60?`${n}m ago`:`${Math.floor(n/60)}h ${n%60}m ago`}function oe({data:s}){const t=s.percent??0,n=Math.max(t,1),o=se(t),l=te(s.tokens),r=s.contextWindow.toLocaleString(),i=`${l} / ${r} tokens`;return e.jsxs("div",{className:`session-gauge ${s.isSelf?"session-gauge-self":""}`,children:[e.jsxs("div",{className:"session-gauge-head",children:[e.jsx("span",{className:"session-gauge-label",children:s.label}),e.jsxs("span",{className:"session-gauge-pct",children:[t,"%"]})]}),e.jsx("div",{className:`gauge-bar ${o}`,role:"meter","aria-valuenow":t,"aria-valuemin":0,"aria-valuemax":100,"aria-label":`${s.label}: ${t}%`,children:e.jsx("div",{className:"gauge-fill",style:{width:`${n}%`}})}),e.jsx("p",{className:"gauge-label session-gauge-sub",children:i}),s.sublabel&&e.jsx("p",{className:"session-gauge-meta",children:s.sublabel})]})}function re({sessions:s,loading:t,error:n,launcherSessionId:o,launcher:l}){const r=Date.now(),i=[{key:"self",label:"this session",sublabel:"",tokens:l.tokens,percent:l.percent,contextWindow:l.contextWindow,isSelf:!0}],u=(s?.sessions??[]).filter(a=>a.sessionId!==o);u.sort((a,x)=>x.lastSeen-a.lastSeen);for(const a of u)i.push({key:a.sessionId,label:ne(a.repoRoot),sublabel:`pid ${a.pid} · ${ae(r-a.lastSeen)}${a.model?` · ${a.model}`:""}`,tokens:a.tokens,percent:a.percent,contextWindow:a.ctxWindow||0,isSelf:!1});const m=n&&!s,c=t&&!s;return e.jsxs(p,{className:"electric-hover",children:[e.jsx(k,{children:e.jsx(N,{children:"Context per Session (live)"})}),e.jsx(f,{children:m?e.jsxs("div",{className:"text-sm text-muted-foreground",children:["Error loading sessions: ",n.message]}):c?e.jsx("div",{className:"text-sm text-muted-foreground",children:"Loading sessions…"}):e.jsx("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:i.map(a=>e.jsx(oe,{data:a},a.key))})})]})}function O({state:s,label:t}){const n=s==="on"?"bullet-on":s==="na"?"bullet-na":"bullet-off";return e.jsxs("div",{className:`bullet ${n}`,children:[e.jsx("span",{className:"bullet-dot","aria-hidden":"true"}),e.jsx("span",{className:"bullet-label",children:t})]})}function le({armed:s,ready:t}){const n=s?"on":"off",o=t?"on":s?"off":"na",l=t?"THRESHOLD EXCEEDED — compacting next event":s?"past fast gate — monitoring token count":"idle — below fast gate";return e.jsxs("div",{className:"card trigger-status",children:[e.jsx("h3",{children:"Trigger Status"}),e.jsxs("div",{className:"bullet-row",children:[e.jsx(O,{state:n,label:"Armed"}),e.jsx(O,{state:o,label:"Ready"})]}),e.jsx("p",{className:"trigger-state-text",children:l})]})}function ie(s){return s>=.9?"meter-green":s>=.6?"meter-yellow":"meter-red"}function h({label:s,value:t,title:n}){return e.jsxs("div",{className:"ov-stat-row",children:[e.jsx("span",{className:"ov-stat-label",title:n,children:s}),e.jsx("span",{className:"ov-stat-value",children:t})]})}function ce(s){const t=s.compressionPct,n=ie(t),o=Math.max(t*100,.5),l=`${v(t)} tokens saved · dedup: ${v(s.dedupPct)}`;return e.jsxs("div",{className:"card vector-store-card",children:[e.jsx("h3",{children:"Vector Store (session)"}),e.jsx(h,{label:"Checkpoints",value:s.checkpointCount.toLocaleString(),title:"A saved summary of a chunk of your conversation that was compacted to free up space."}),e.jsx(h,{label:"Original (dropped)",value:s.tokensIn.toLocaleString(),title:"Total size of the original conversation text dropped into compaction this session, including redundant regions skipped by dedup. This is the 'in'."}),e.jsx(h,{label:"Kept (summaries)",value:s.tokensOut.toLocaleString(),title:"Compact summaries we are currently holding as 'memory' for this session (the 'out'). Smaller is better."}),e.jsx(h,{label:"Freed",value:s.tokensFreed.toLocaleString(),title:"Conversation space freed = dropped − kept (the 'saved')."}),e.jsx(h,{label:"Injected",value:s.injectedCount,title:"How many times old context was automatically brought back into the conversation because it was relevant to what you were doing."}),e.jsx(h,{label:"Recall Relevance",value:v(s.dedupHitRate),title:"Of the times we recalled old context, how often it was actually on-topic."}),e.jsx(h,{label:"Storage Dedup",value:v(s.storageDedupRate),title:"How often new content matched something we already had, so we skipped storing a duplicate copy. Higher = less wasted space."}),e.jsx(h,{label:"Collapsed",value:s.dedupCollapsed,title:"How many duplicate chunks we collapsed into one instead of storing separately."}),e.jsx(h,{label:"Last ID",value:s.lastCheckpointId??"—",title:"The ID of the most recent saved checkpoint."}),e.jsxs("div",{className:"ov-compression-meter",children:[e.jsx("div",{className:"meter-track",children:e.jsx("div",{className:`meter-fill ${n}`,style:{width:`${o}%`}})}),e.jsx("span",{className:"meter-sub",children:l})]})]})}function de(s){return s>=.9?"meter-green":s>=.6?"meter-yellow":"meter-red"}function g({label:s,value:t}){return e.jsxs("div",{className:"flex items-baseline justify-between border-b border-border py-1 text-sm",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:s}),e.jsx("span",{className:"font-semibold",children:t})]})}function ue(s){const t=s.compressionPct,n=de(t),o=Math.max(t*100,.5),l=`${v(t)} tokens saved · dedup: ${v(s.dedupPct)}`;return e.jsxs(p,{className:"electric-hover",children:[e.jsx(k,{children:e.jsx(N,{children:"Repo (all sessions)"})}),e.jsxs(f,{children:[e.jsx(g,{label:"Checkpoints",value:s.checkpointCount.toLocaleString()}),e.jsx(g,{label:"Original",value:s.tokensIn.toLocaleString()}),e.jsx(g,{label:"Kept",value:s.tokensOut.toLocaleString()}),e.jsx(g,{label:"Freed",value:s.tokensFreed.toLocaleString()}),e.jsx(g,{label:"Sessions",value:s.sessionCount.toLocaleString()}),e.jsx(g,{label:"Collapsed",value:s.dedupCollapsed}),e.jsx(g,{label:"Storage Dedup",value:v(s.storageDedupRate)}),e.jsxs("div",{children:[e.jsx("div",{className:"mt-2 h-2 w-full overflow-hidden rounded-full bg-bg-elevated",children:e.jsx("div",{className:`meter-fill h-full ${n}`,style:{width:`${o}%`}})}),e.jsx("span",{className:"mt-1 block text-xs text-muted-foreground",children:l})]})]})]})}function me(s){return e.jsxs("div",{className:"card data-safety-card",children:[e.jsx("h3",{children:"🛡 Data Safety"}),e.jsxs("div",{className:"ov-stat-row",children:[e.jsx("span",{className:"ov-stat-label",children:"Regions Retained"}),e.jsx("span",{className:"ov-stat-value",children:s.regionsRetained.toLocaleString()})]}),e.jsxs("div",{className:"ov-stat-row",children:[e.jsx("span",{className:"ov-stat-label",children:"Compressed-Original"}),e.jsx("span",{className:"ov-stat-value",children:I(s.compressedOriginalBytes)})]}),e.jsxs("div",{className:"ov-stat-row",children:[e.jsx("span",{className:"ov-stat-label",children:"Dedup Duplicates"}),e.jsx("span",{className:"ov-stat-value",children:s.duplicatesCollapsed.toLocaleString()})]}),e.jsxs("div",{className:"ov-stat-row",children:[e.jsx("span",{className:"ov-stat-label",children:"Permanently Deleted"}),e.jsx("span",{className:"ov-stat-value ov-value-ok",children:I(s.bytesPermanentlyDeleted)})]}),e.jsx("p",{className:"safe-note",children:'Every compacted region is kept verbatim (compressed). "Drop" = removed from the live window only. We never delete your data.'})]})}function j({label:s,value:t,title:n}){return e.jsxs("div",{className:"ov-stat-row",children:[e.jsx("span",{className:"ov-stat-label",title:n,children:s}),e.jsx("span",{className:"ov-stat-value",children:t})]})}function xe(s){const t=`${Math.round((s.pressure??0)*100)}%`;let n=s.thresholdTokens.toLocaleString();return s.tierPct!=null&&s.contextWindow>0&&(n+=` (${Math.round(s.tierPct*100)}% of ${s.contextWindow.toLocaleString()})`),e.jsxs("div",{className:"card config-summary-card",children:[e.jsx("h3",{children:"Configuration"}),e.jsx(j,{label:"Tier",value:`${s.tier} (live)`,title:"Live pressure band — climbs low→mega as context fills the window."}),e.jsx(j,{label:"Preset",value:s.presetTier,title:"The env-resolved base compaction preset (low/medium/high/ultra/mega) that set the token threshold."}),e.jsx(j,{label:"Pressure",value:t,title:"Live pressure = currentTokens / threshold — % of the model context window (threshold fires at the tier's % of window)."}),e.jsx(j,{label:"Threshold",value:n,title:"Compaction threshold = tierPct × model context window — mega-compact trims BELOW pi's native ~80% auto-compact for any model size."}),e.jsx(j,{label:"Fast Gate",value:`${s.fastGatePct}%`,title:"Fast-gate arming floor — the live trim arms once context passes this % of the window."}),e.jsx(j,{label:"Auto",value:s.auto?"enabled":"disabled"}),e.jsx(j,{label:"Anchor",value:String(s.anchorUserMessages)})]})}function D({label:s,value:t,title:n}){return e.jsxs("div",{className:"flex items-baseline justify-between border-b border-border py-1 text-sm",children:[e.jsx("span",{className:"text-xs text-muted-foreground",title:n,children:s}),e.jsx("span",{className:"font-semibold",children:t})]})}function he(s){const t=s.repoTokensFreed||0;let n=0,o="0";if(s.inputRate&&t>0){n=t*s.inputRate;const i=s.contextWindow||0;o=i>0?(t/i).toFixed(1):"0"}const l=`≈ $${n.toFixed(4)} saved`,r=`${o} context-windows extended`;return e.jsxs(p,{className:"electric-hover",children:[e.jsx(k,{children:e.jsx(N,{children:"💰 Model & Cost Savings"})}),e.jsxs(f,{children:[e.jsx("div",{className:"text-neon text-xl font-semibold",children:l}),e.jsx("div",{className:"mb-2 text-xs text-muted-foreground",children:r}),e.jsx(D,{label:"Model",value:s.name,title:"The model pi is currently using — its pricing drives the cost figure."}),e.jsx(D,{label:"Provider",value:s.provider,title:"The provider serving the model."}),e.jsx(D,{label:"Input Rate",value:`$${s.inputRate.toFixed(6)}`,title:"USD per input token, from the model's pricing."}),e.jsx(D,{label:"Output Rate",value:`$${s.outputRate.toFixed(6)}`,title:"USD per output token, from the model's pricing."})]})]})}function pe(s){const{activeAgents:t,currentTurn:n}=s,o=t>0?`▶ ${t} running`:"idle";return e.jsxs(p,{className:"electric-hover",children:[e.jsx(k,{children:e.jsx(N,{children:"Crew / Agents"})}),e.jsxs(f,{children:[e.jsxs("div",{className:"flex items-baseline justify-between border-b border-border py-1 text-sm",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"Active Agents"}),e.jsx("span",{className:"font-semibold",children:t})]}),e.jsxs("div",{className:"flex items-baseline justify-between border-b border-border py-1 text-sm",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"Current Turn"}),e.jsx("span",{className:"font-semibold",children:n})]}),e.jsxs("div",{className:"flex items-baseline justify-between py-1 text-sm",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:"Status"}),e.jsx("span",{className:"font-semibold",children:o})]})]})]})}const fe=[e.jsxs("li",{children:[e.jsx("b",{children:"Original (dropped)"}),' — everything compacted away (including duplicates caught by dedup). The "in."']},"1"),e.jsxs("li",{children:[e.jsx("b",{children:"Kept (summaries)"}),' — compact summaries still held as "memory" (the "out").']},"2"),e.jsxs("li",{children:[e.jsx("b",{children:"Freed"})," = dropped − kept — tokens saved so far (higher = better)."]},"3"),e.jsxs("li",{children:[e.jsx("b",{children:"Compression %"})," — Freed ÷ Dropped — the headline efficiency number. Higher = more space reclaimed."]},"4"),e.jsxs("li",{children:[e.jsx("b",{children:"Storage dedup %"})," — how often new content matched something already saved, so no duplicate copy was written."]},"5"),e.jsxs("li",{children:[e.jsx("b",{children:"Data safety"})," — every compacted region is kept verbatim (compressed). Nothing is permanently deleted; you can restore any of it."]},"6")];function ge(){return e.jsx(p,{children:e.jsx(f,{children:e.jsxs("details",{children:[e.jsx("summary",{className:"cursor-pointer text-sm font-semibold",children:"What these numbers mean"}),e.jsx("ol",{className:"mt-2 list-decimal space-y-1 pl-5 text-sm",children:fe}),e.jsx("p",{className:"mt-2 text-xs text-muted-foreground",children:"Hover any label above for a quick explanation."})]})})})}const je=()=>{const{data:s}=_(C.useMemo(()=>()=>B(),[]),{pollInterval:3e4});if(!s)return e.jsx(p,{children:e.jsx(f,{className:"text-sm text-muted-foreground",children:"Loading RAG health…"})});const{totals:t,flags:n}=s,o=n.hydeEnabled||n.recallMetricsEnabled;return e.jsxs(p,{children:[e.jsx(k,{children:e.jsxs(N,{className:"flex items-center gap-2",children:[e.jsx("span",{className:`inline-block h-2 w-2 rounded-full ${o?"bg-success":"bg-muted-foreground"}`,"aria-hidden":"true"}),"RAG Health"]})}),e.jsx(f,{children:o?e.jsxs("dl",{className:"grid grid-cols-2 gap-x-4 gap-y-2 text-sm",children:[e.jsxs("div",{children:[e.jsx("dt",{className:"text-xs text-muted-foreground",children:"Pass rate"}),e.jsxs("dd",{className:"font-semibold text-foreground",children:[Math.round(t.recentPassRate*100),"%"]})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"text-xs text-muted-foreground",children:"Avg lift"}),e.jsxs("dd",{className:"font-semibold text-foreground",children:[t.avgLift.toFixed(2),"×"]})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"text-xs text-muted-foreground",children:"Telemetry turns"}),e.jsx("dd",{className:"font-semibold text-foreground",children:t.telemetryTurns})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"text-xs text-muted-foreground",children:"HyDE ran"}),e.jsx("dd",{className:"font-semibold text-foreground",children:t.hydeRanTurns})]})]}):e.jsx("div",{className:"text-sm text-muted-foreground",children:"All RAG recall feature flags are off."})})]})};function ve(s){return s.type==="session_sample"}function be(s){if(!s)return"never";try{return new Date(s).toLocaleString()}catch{return s}}function Ce({snapshot:s,loading:t,error:n}){const{data:o,error:l,loading:r,refetch:i}=_(C.useCallback(()=>U(),[]),{pollInterval:2e3}),{events:u}=V(),m=C.useMemo(()=>u.filter(ve),[u]),c=C.useMemo(()=>m.length===0?null:m[m.length-1].ts,[m]);if(C.useEffect(()=>{c!=null&&i()},[c,i]),t&&!s)return e.jsx("div",{className:"tab-stub",children:"Loading snapshot…"});if(n&&!s)return e.jsxs("div",{className:"tab-stub",children:["Error: ",n.message]});if(!s)return e.jsx("div",{className:"tab-stub",children:"No snapshot data."});const a=s,{context:x,compression:d,trigger:w,session:M,store:S,tier:H,updatedAt:G}=a,y=a.config,W=a.crew,T=a.integrity,R=a.cacheHits,A=a.compacts,$=a.timeSaved,P=a.repo,b=a.model;return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(K,{variant:"accent",children:H}),e.jsxs("span",{className:"text-xs text-muted-foreground",children:["updated ",be(G)]})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3",children:[e.jsx(re,{sessions:o,loading:r,error:l,launcherSessionId:M.id,launcher:{tokens:x.tokens,percent:x.percent,contextWindow:x.contextWindow}}),e.jsx(ee,{sessions:o,loading:r,error:l}),e.jsx(le,{armed:w.armed,ready:w.ready,currentTokens:w.currentTokens,thresholdTokens:w.thresholdTokens,fastGatePct:w.fastGatePct}),e.jsx(ce,{checkpointCount:S.checkpointCount,tokensIn:d.session.tokensIn,tokensOut:d.session.tokensOut,tokensFreed:d.session.tokensFreed,injectedCount:S.injectedCount,dedupHitRate:S.dedupHitRate,storageDedupRate:S.storageDedupRate,dedupCollapsed:S.dedupCollapsed,lastCheckpointId:M.lastCheckpointId,compressionPct:d.session.compressionPct,dedupPct:d.session.dedupPct}),e.jsx(ue,{checkpointCount:P.checkpointCount,tokensIn:d.repo.tokensIn,tokensOut:d.repo.tokensOut,tokensFreed:d.repo.tokensFreed,sessionCount:P.sessionCount,dedupCollapsed:P.dedupCollapsed,storageDedupRate:P.storageDedupRate,compressionPct:d.repo.compressionPct,dedupPct:d.repo.dedupPct}),e.jsx(me,{regionsRetained:T.regionsRetained,compressedOriginalBytes:T.compressedOriginalBytes,duplicatesCollapsed:T.duplicatesCollapsed,bytesPermanentlyDeleted:T.bytesPermanentlyDeleted}),e.jsx(xe,{tier:H,presetTier:a.presetTier,pressure:a.pressure,thresholdTokens:y.thresholdTokens,tierPct:y.tierPct,contextWindow:x.contextWindow,fastGatePct:y.fastGatePct,auto:y.auto,anchorUserMessages:y.anchorUserMessages}),b&&e.jsx(he,{name:b.name,provider:b.providerName||b.provider,inputRate:b.inputRate,outputRate:b.outputRate,repoTokensFreed:d.repo.tokensFreed,contextWindow:x.contextWindow}),e.jsx(pe,{activeAgents:W.activeAgents,currentTurn:W.currentTurn}),e.jsx(q,{cacheHitsSession:R.session,cacheHitsTotal:R.total,tokensSavedSession:R.sessionTokensSaved,tokensSavedTotal:R.totalTokensSaved,compactionsSession:A.session,compactionsTotal:A.total}),e.jsx(X,{compactSessionSec:$.compact.sessionSec,compactTotalSec:$.compact.totalSec,cacheHitSessionSec:$.cacheHit.sessionSec,cacheHitTotalSec:$.cacheHit.totalSec}),z()&&e.jsx(je,{}),e.jsx(ge,{})]})]})}export{Ce as default};
|
|
2
|
+
//# sourceMappingURL=OverviewTab-K6j4ZI7u.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OverviewTab-K6j4ZI7u.js","sources":["../../src/components/RepoContextStack.tsx","../../src/components/SessionContextGauges.tsx","../../src/components/TriggerStatus.tsx","../../src/components/VectorStoreCard.tsx","../../src/components/RepoAllSessionsCard.tsx","../../src/components/DataSafetyCard.tsx","../../src/components/ConfigSummaryCard.tsx","../../src/components/CacheStatusPerModel.tsx","../../src/components/SessionInfo.tsx","../../src/components/LegendCard.tsx","../../src/tabs/SetupTab/RagHealthCard.tsx","../../src/tabs/OverviewTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/components/RepoContextStack.tsx — Stacked per-repo context bar (S40).\n *\n * Horizontal stacked bar: one colored segment per active repo, aggregating\n * that repo's active sessions' token counts. Renders a combined total line\n * and a legend mapping each repo (basename of repoRoot) to its segment color\n * + token count + % of total.\n *\n * Stable per-repo colors: the repoRoot basename is hashed to a deterministic\n * index into a fixed palette array, so the same repo always gets the same\n * color across renders/tabs (mirrors SessionsMemoryChart's stable-color\n * contract from S39).\n *\n * PREVENT-PI-004: this is a pure presentational component — no fetch, no\n * network. Data is passed in by the parent (OverviewTab) via\n * useApi(fetchSessions) + useSSE() for real-time updates.\n */\n\nimport type React from \"react\";\nimport type { ActiveSession, SessionsResponse } from \"@contracts\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"../components/ui/card\";\n\nexport interface RepoContextStackProps {\n\t/** Active sessions from /api/sessions (may be null while loading). */\n\tsessions: SessionsResponse | null;\n\t/** Whether the initial fetch is in flight. */\n\tloading: boolean;\n\t/** Fetch error, if any. */\n\terror: Error | null;\n}\n\n// ─── Stable color palette ─────────────────────────────────────────────────────\n// Fixed set of hex colors used for stable per-repo coloring. The hash function\n// maps a repoRoot basename to a deterministic palette index so the same repo\n// always renders the same color.\nconst REPO_PALETTE: ReadonlyArray<string> = [\n\t\"#58a6ff\", // blue\n\t\"#3fb950\", // green\n\t\"#d29922\", // yellow\n\t\"#f85149\", // red\n\t\"#bc8cff\", // purple\n\t\"#ff7b72\", // salmon\n\t\"#79c0ff\", // light blue\n\t\"#56d4dd\", // cyan\n\t\"#e3b341\", // gold\n\t\"#a5d6ff\", // pale blue\n\t\"#7ee787\", // mint\n\t\"#ffa657\", // orange\n];\n\n/**\n * Simple deterministic string hash (djb2 variant). Returns a non-negative\n * 32-bit integer.\n */\nfunction hashString(str: string): number {\n\tlet hash = 5381;\n\tfor (let i = 0; i < str.length; i++) {\n\t\thash = ((hash << 5) + hash + str.charCodeAt(i)) >>> 0;\n\t}\n\treturn hash;\n}\n\n/**\n * Pick a stable color for a repoRoot basename. Falls back to \"(unknown)\" if\n * the basename is empty.\n */\nfunction colorForRepo(basename: string): string {\n\tif (!basename) return REPO_PALETTE[0];\n\treturn REPO_PALETTE[hashString(basename) % REPO_PALETTE.length];\n}\n\n/**\n * Extract the basename from a repoRoot path. Uses `\"/\"` as the universal\n * separator on all OSes (repoRoot is an absolute path from the dashboard\n * server; on Windows pi actually uses forward-slash normalized paths anyway).\n */\nfunction repoBasename(repoRoot: string | null): string {\n\tif (!repoRoot) return \"(unknown)\";\n\tconst trimmed = repoRoot.replace(/[\\\\/]+$/, \"\");\n\tif (!trimmed) return \"(unknown)\";\n\tconst parts = trimmed.split(/[\\\\/]/);\n\tconst last = parts[parts.length - 1];\n\treturn last || trimmed;\n}\n\n// ─── Aggregation ─────────────────────────────────────────────────────────────\n\ninterface RepoAggregate {\n\trepoRoot: string | null;\n\tbasename: string;\n\ttokens: number;\n\tcolor: string;\n}\n\nfunction aggregateRepos(sessions: ReadonlyArray<ActiveSession>): {\n\trepos: RepoAggregate[];\n\ttotalTokens: number;\n\tmaxWindow: number;\n\tsessionCount: number;\n} {\n\tconst map = new Map<string, RepoAggregate>();\n\tfor (const s of sessions) {\n\t\tconst key = s.repoRoot ?? \"__null__\";\n\t\tconst tokens = s.tokens ?? 0;\n\t\tconst existing = map.get(key);\n\t\tif (existing) {\n\t\t\texisting.tokens += tokens;\n\t\t} else {\n\t\t\tconst basename = repoBasename(s.repoRoot);\n\t\t\tmap.set(key, {\n\t\t\t\trepoRoot: s.repoRoot,\n\t\t\t\tbasename,\n\t\t\t\ttokens,\n\t\t\t\tcolor: colorForRepo(basename),\n\t\t\t});\n\t\t}\n\t}\n\tconst repos = [...map.values()];\n\tconst totalTokens = repos.reduce((sum, r) => sum + r.tokens, 0);\n\t// Combined max window: the largest ctxWindow among the active sessions.\n\t// This mirrors SessionsTab's SummaryTiles combined-% logic.\n\tconst maxWindow = sessions.reduce(\n\t\t(max, s) => Math.max(max, s.ctxWindow),\n\t\t0,\n\t);\n\treturn {\n\t\trepos,\n\t\ttotalTokens,\n\t\tmaxWindow,\n\t\tsessionCount: sessions.length,\n\t};\n}\n\nfunction fmtTokens(n: number): string {\n\tif (n >= 100_000) return `${(n / 1000).toFixed(0)}k`;\n\treturn n.toLocaleString();\n}\n\nfunction StackCard({ children }: { children: React.ReactNode }): React.ReactElement {\n\treturn (\n\t\t<Card className=\"electric-hover\">\n\t\t\t<CardHeader>\n\t\t\t\t<CardTitle>Context per Repo (live)</CardTitle>\n\t\t\t</CardHeader>\n\t\t\t<CardContent>{children}</CardContent>\n\t\t</Card>\n\t);\n}\n\nexport function RepoContextStack({\n\tsessions,\n\tloading,\n\terror,\n}: RepoContextStackProps): React.ReactElement | null {\n\tif (error) {\n\t\treturn (\n\t\t\t<StackCard>\n\t\t\t\t<span className=\"text-sm text-muted-foreground\">\n\t\t\t\t\tError loading sessions: {error.message}\n\t\t\t\t</span>\n\t\t\t</StackCard>\n\t\t);\n\t}\n\n\tif (loading && !sessions) {\n\t\treturn (\n\t\t\t<StackCard>\n\t\t\t\t<span className=\"text-sm text-muted-foreground\">Loading sessions…</span>\n\t\t\t</StackCard>\n\t\t);\n\t}\n\n\tconst activeSessions = sessions?.sessions ?? [];\n\tconst { repos, totalTokens, maxWindow, sessionCount } =\n\t\taggregateRepos(activeSessions);\n\n\tif (repos.length === 0) {\n\t\treturn (\n\t\t\t<StackCard>\n\t\t\t\t<span className=\"text-sm text-muted-foreground\">No active sessions.</span>\n\t\t\t</StackCard>\n\t\t);\n\t}\n\n\tconst combinedPct =\n\t\tmaxWindow > 0 ? Math.round((totalTokens / maxWindow) * 100) : 0;\n\n\treturn (\n\t\t<StackCard>\n\t\t\t<div\n\t\t\t\tclassName=\"repo-stack-bar\"\n\t\t\t\trole=\"group\"\n\t\t\t\taria-label=\"Per-repo context usage\"\n\t\t\t>\n\t\t\t\t{repos.map((r) => {\n\t\t\t\t\tconst pctOfTotal =\n\t\t\t\t\t\ttotalTokens > 0 ? (r.tokens / totalTokens) * 100 : 0;\n\t\t\t\t\tconst widthPct = totalTokens > 0 ? pctOfTotal : 0;\n\t\t\t\t\tconst tooltip =\n\t\t\t\t\t\t`${r.basename}: ${fmtTokens(r.tokens)} tokens ` +\n\t\t\t\t\t\t`(${pctOfTotal.toFixed(1)}% of total)`;\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tkey={r.repoRoot ?? \"__null__\"}\n\t\t\t\t\t\t\tclassName=\"repo-stack-segment\"\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\twidth: `${Math.max(widthPct, 0.5)}%`,\n\t\t\t\t\t\t\t\tbackgroundColor: r.color,\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\ttitle={tooltip}\n\t\t\t\t\t\t\taria-label={tooltip}\n\t\t\t\t\t\t/>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</div>\n\t\t\t<p className=\"repo-stack-total\">\n\t\t\t\t{fmtTokens(totalTokens)} tokens across {repos.length}{\" \"}\n\t\t\t\t{repos.length === 1 ? \"repo\" : \"repos\"} /{\" \"}\n\t\t\t\t{sessionCount}{\" \"}\n\t\t\t\t{sessionCount === 1 ? \"session\" : \"sessions\"}{\" \"}\n\t\t\t\t<span className=\"pct\">— {combinedPct}% of combined max window</span>\n\t\t\t</p>\n\t\t\t<div className=\"repo-stack-legend\">\n\t\t\t\t{repos.map((r) => {\n\t\t\t\t\tconst pctOfTotal =\n\t\t\t\t\t\ttotalTokens > 0 ? (r.tokens / totalTokens) * 100 : 0;\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tkey={r.repoRoot ?? \"__null__\"}\n\t\t\t\t\t\t\tclassName=\"repo-stack-legend-item\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tclassName=\"repo-stack-legend-swatch\"\n\t\t\t\t\t\t\t\tstyle={{ backgroundColor: r.color }}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<span className=\"repo-stack-legend-name\">{r.basename}</span>\n\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t{fmtTokens(r.tokens)} ({pctOfTotal.toFixed(0)}%)\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</div>\n\t\t</StackCard>\n\t);\n}\n","/**\n * dashboard-client/src/components/SessionContextGauges.tsx — Per-session context gauges (S40).\n *\n * Replaces the single launcher-only ContextGauge on the Overview tab with a\n * wrapping grid of compact gauges, one per active pi session. The launcher's\n * own session is always shown first + highlighted (\"this session\"), sourced\n * from the live snapshot (always available, never depends on heartbeat\n * timing). Other active sessions come from /api/sessions, sorted by lastSeen\n * descending, each labeled with repo basename + PID.\n *\n * Reuses the existing .gauge-bar / .gauge-fill / .gauge-{green,yellow,red}\n * classes from overview-events.css so the fill bars match the original\n * ContextGauge styling.\n *\n * PREVENT-PI-004: pure presentational component — no fetch, no network. Data\n * is passed in by the parent (OverviewTab) via its useApi(fetchSessions) +\n * useSSE() for real-time updates.\n */\n\nimport type React from \"react\";\nimport type { ActiveSession, SessionsResponse } from \"@contracts\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"../components/ui/card\";\n\nexport interface SessionContextGaugesProps {\n\t/** Active sessions from /api/sessions (may be null while loading). */\n\tsessions: SessionsResponse | null;\n\t/** Whether the initial fetch is in flight. */\n\tloading: boolean;\n\t/** Fetch error, if any. */\n\terror: Error | null;\n\t/** Launcher's own session ID (from snapshot.session.id), to exclude it\n\t * from the \"other sessions\" list (it's always rendered separately). */\n\tlauncherSessionId: string | null;\n\t/** Launcher's own context values (from snapshot — always available). */\n\tlauncher: {\n\t\ttokens: number | null;\n\t\tpercent: number | null;\n\t\tcontextWindow: number;\n\t};\n}\n\nfunction severityClass(percent: number): string {\n\tif (percent >= 90) return \"gauge-red\";\n\tif (percent >= 70) return \"gauge-yellow\";\n\treturn \"gauge-green\";\n}\n\nfunction fmtTokens(n: number | null): string {\n\tif (n == null) return \"?\";\n\tif (n >= 100_000) return `${(n / 1000).toFixed(0)}k`;\n\treturn n.toLocaleString();\n}\n\nfunction repoBasename(repoRoot: string | null): string {\n\tif (!repoRoot) return \"(unknown)\";\n\tconst trimmed = repoRoot.replace(/[\\\\/]+$/, \"\");\n\tif (!trimmed) return \"(unknown)\";\n\tconst parts = trimmed.split(/[\\\\/]/);\n\treturn parts[parts.length - 1] || trimmed;\n}\n\nfunction fmtAge(ms: number): string {\n\tconst s = Math.max(0, Math.round(ms / 1000));\n\tif (s < 60) return `${s}s ago`;\n\tconst m = Math.floor(s / 60);\n\tif (m < 60) return `${m}m ago`;\n\tconst h = Math.floor(m / 60);\n\treturn `${h}h ${m % 60}m ago`;\n}\n\ninterface GaugeData {\n\tkey: string;\n\tlabel: string;\n\tsublabel: string;\n\ttokens: number | null;\n\tpercent: number | null;\n\tcontextWindow: number;\n\tisSelf: boolean;\n}\n\n/** A single compact gauge: header label, fill bar, tokens/window sublabel. */\nfunction SessionGauge({ data }: { data: GaugeData }): React.ReactElement {\n\tconst pct = data.percent ?? 0;\n\tconst fillWidth = Math.max(pct, 1);\n\tconst cls = severityClass(pct);\n\tconst tokStr = fmtTokens(data.tokens);\n\tconst windowStr = data.contextWindow.toLocaleString();\n\tconst sublabel = `${tokStr} / ${windowStr} tokens`;\n\treturn (\n\t\t<div className={`session-gauge ${data.isSelf ? \"session-gauge-self\" : \"\"}`}>\n\t\t\t<div className=\"session-gauge-head\">\n\t\t\t\t<span className=\"session-gauge-label\">{data.label}</span>\n\t\t\t\t<span className=\"session-gauge-pct\">{pct}%</span>\n\t\t\t</div>\n\t\t\t<div\n\t\t\t\tclassName={`gauge-bar ${cls}`}\n\t\t\t\trole=\"meter\"\n\t\t\t\taria-valuenow={pct}\n\t\t\t\taria-valuemin={0}\n\t\t\t\taria-valuemax={100}\n\t\t\t\taria-label={`${data.label}: ${pct}%`}\n\t\t\t>\n\t\t\t\t<div className=\"gauge-fill\" style={{ width: `${fillWidth}%` }} />\n\t\t\t</div>\n\t\t\t<p className=\"gauge-label session-gauge-sub\">{sublabel}</p>\n\t\t\t{data.sublabel && <p className=\"session-gauge-meta\">{data.sublabel}</p>}\n\t\t</div>\n\t);\n}\n\nexport function SessionContextGauges({\n\tsessions,\n\tloading,\n\terror,\n\tlauncherSessionId,\n\tlauncher,\n}: SessionContextGaugesProps): React.ReactElement {\n\tconst now = Date.now();\n\n\t// Launcher gauge (always rendered, sourced from the snapshot).\n\tconst gauges: GaugeData[] = [\n\t\t{\n\t\t\tkey: \"self\",\n\t\t\tlabel: \"this session\",\n\t\t\tsublabel: \"\",\n\t\t\ttokens: launcher.tokens,\n\t\t\tpercent: launcher.percent,\n\t\t\tcontextWindow: launcher.contextWindow,\n\t\t\tisSelf: true,\n\t\t},\n\t];\n\n\t// Other active sessions (exclude the launcher by sessionId to avoid dup).\n\tconst others: ActiveSession[] = (sessions?.sessions ?? []).filter(\n\t\t(s) => s.sessionId !== launcherSessionId,\n\t);\n\t// Sort by lastSeen descending (most recent first).\n\tothers.sort((a, b) => b.lastSeen - a.lastSeen);\n\tfor (const s of others) {\n\t\tgauges.push({\n\t\t\tkey: s.sessionId,\n\t\t\tlabel: repoBasename(s.repoRoot),\n\t\t\tsublabel: `pid ${s.pid} · ${fmtAge(now - s.lastSeen)}${\n\t\t\t\ts.model ? ` · ${s.model}` : \"\"\n\t\t\t}`,\n\t\t\ttokens: s.tokens,\n\t\t\tpercent: s.percent,\n\t\t\tcontextWindow: s.ctxWindow || 0,\n\t\t\tisSelf: false,\n\t\t});\n\t}\n\n\tconst hasError = error && !sessions;\n\tconst showLoading = loading && !sessions;\n\n\treturn (\n\t\t<Card className=\"electric-hover\">\n\t\t\t<CardHeader>\n\t\t\t\t<CardTitle>Context per Session (live)</CardTitle>\n\t\t\t</CardHeader>\n\t\t\t<CardContent>\n\t\t\t{hasError ? (\n\t\t\t\t<div className=\"text-sm text-muted-foreground\">\n\t\t\t\t\tError loading sessions: {error!.message}\n\t\t\t\t</div>\n\t\t\t) : showLoading ? (\n\t\t\t\t<div className=\"text-sm text-muted-foreground\">Loading sessions…</div>\n\t\t\t) : (\n\t\t\t\t<div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n\t\t\t\t\t{gauges.map((g) => (\n\t\t\t\t\t\t<SessionGauge key={g.key} data={g} />\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t</CardContent>\n\t\t</Card>\n\t);\n}\n","/**\n * dashboard-client/src/components/TriggerStatus.tsx — trigger armed/ready status.\n *\n * Two bullets (Armed, Ready) + state text.\n * Ready bullet shows \"na\" (yellow) when not armed.\n * State text: ready → \"THRESHOLD EXCEEDED — compacting next event\",\n * armed → \"past fast gate — monitoring token count\",\n * idle → \"idle — below fast gate\".\n */\n\nimport type React from \"react\";\n\nexport interface TriggerStatusProps {\n\t/** Whether the trigger is armed (waiting for threshold). */\n\tarmed: boolean;\n\t/** Whether the trigger is ready to fire (pressure at/above threshold). */\n\tready: boolean;\n\t/** Current context token count, or null if unknown. */\n\tcurrentTokens: number | null;\n\t/** Token threshold for firing. */\n\tthresholdTokens: number;\n\t/** Fast-gate pressure threshold (percent, 0–100). */\n\tfastGatePct: number;\n}\n\ntype BulletState = \"on\" | \"off\" | \"na\";\n\nfunction Bullet({\n\tstate,\n\tlabel,\n}: {\n\tstate: BulletState;\n\tlabel: string;\n}): React.ReactElement {\n\tconst cls =\n\t\tstate === \"on\" ? \"bullet-on\" : state === \"na\" ? \"bullet-na\" : \"bullet-off\";\n\treturn (\n\t\t<div className={`bullet ${cls}`}>\n\t\t\t<span className=\"bullet-dot\" aria-hidden=\"true\" />\n\t\t\t<span className=\"bullet-label\">{label}</span>\n\t\t</div>\n\t);\n}\n\nexport function TriggerStatus({\n\tarmed,\n\tready,\n}: TriggerStatusProps): React.ReactElement {\n\t// tr-armed: on if armed, off if not\n\t// tr-ready: on if ready, na (yellow) if not armed, off if armed but not ready\n\tconst armedState: BulletState = armed ? \"on\" : \"off\";\n\tconst readyState: BulletState = ready\n\t\t? \"on\"\n\t\t: !armed\n\t\t\t? \"na\"\n\t\t\t: \"off\";\n\n\tconst stateText = ready\n\t\t? \"THRESHOLD EXCEEDED — compacting next event\"\n\t\t: armed\n\t\t\t? \"past fast gate — monitoring token count\"\n\t\t\t: \"idle — below fast gate\";\n\n\treturn (\n\t\t<div className=\"card trigger-status\">\n\t\t\t<h3>Trigger Status</h3>\n\t\t\t<div className=\"bullet-row\">\n\t\t\t\t<Bullet state={armedState} label=\"Armed\" />\n\t\t\t\t<Bullet state={readyState} label=\"Ready\" />\n\t\t\t</div>\n\t\t\t<p className=\"trigger-state-text\">{stateText}</p>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/components/VectorStoreCard.tsx — Vector Store (session) card.\n *\n * 9 fields: Checkpoints, Original (dropped), Kept (summaries), Freed,\n * Injected, Recall Relevance %, Storage Dedup %, Collapsed, Last ID.\n * Plus a compression meter bar (green ≥90%, yellow ≥60%, red <60%).\n *\n * NOTE: dedupHitRate, storageDedupRate, compressionPct, dedupPct are\n * 0–1 fractions at runtime (despite contract saying 0–100).\n * Tooltips copied verbatim from html.ts.\n */\n\nimport type React from \"react\";\nimport { fmtPctFromFraction } from \"../utils/format\";\n\nexport interface VectorStoreCardProps {\n\tcheckpointCount: number;\n\t/** Original tokens dropped into compaction (session). */\n\ttokensIn: number;\n\t/** Kept summary tokens (session). */\n\ttokensOut: number;\n\t/** Tokens freed = dropped − kept (session). */\n\ttokensFreed: number;\n\t/** Recall injection count. */\n\tinjectedCount: number;\n\t/** Recall relevance — 0–1 fraction. */\n\tdedupHitRate: number;\n\t/** Storage dedup rate — 0–1 fraction. */\n\tstorageDedupRate: number;\n\t/** Duplicate chunks collapsed. */\n\tdedupCollapsed: number;\n\t/** Last checkpoint ID or null. */\n\tlastCheckpointId: string | null;\n\t/** Session compression ratio — 0–1 fraction. */\n\tcompressionPct: number;\n\t/** Session dedup contribution — 0–1 fraction. */\n\tdedupPct: number;\n}\n\n/** Compression meter colour class (inverse of context: high = good). */\nfunction compressClass(sp: number): string {\n\tif (sp >= 0.9) return \"meter-green\";\n\tif (sp >= 0.6) return \"meter-yellow\";\n\treturn \"meter-red\";\n}\n\n/** Stat row with optional tooltip. */\nfunction StatRow({\n\tlabel,\n\tvalue,\n\ttitle,\n}: {\n\tlabel: string;\n\tvalue: string | number;\n\ttitle?: string;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"ov-stat-row\">\n\t\t\t<span className=\"ov-stat-label\" title={title}>\n\t\t\t\t{label}\n\t\t\t</span>\n\t\t\t<span className=\"ov-stat-value\">{value}</span>\n\t\t</div>\n\t);\n}\n\nexport function VectorStoreCard(\n\tprops: VectorStoreCardProps,\n): React.ReactElement {\n\tconst sp = props.compressionPct;\n\tconst barCls = compressClass(sp);\n\tconst barWidth = Math.max(sp * 100, 0.5);\n\tconst compressSub = `${fmtPctFromFraction(sp)} tokens saved · dedup: ${fmtPctFromFraction(props.dedupPct)}`;\n\n\treturn (\n\t\t<div className=\"card vector-store-card\">\n\t\t\t<h3>Vector Store (session)</h3>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Checkpoints\"\n\t\t\t\tvalue={props.checkpointCount.toLocaleString()}\n\t\t\t\ttitle=\"A saved summary of a chunk of your conversation that was compacted to free up space.\"\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Original (dropped)\"\n\t\t\t\tvalue={props.tokensIn.toLocaleString()}\n\t\t\t\ttitle=\"Total size of the original conversation text dropped into compaction this session, including redundant regions skipped by dedup. This is the 'in'.\"\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Kept (summaries)\"\n\t\t\t\tvalue={props.tokensOut.toLocaleString()}\n\t\t\t\ttitle=\"Compact summaries we are currently holding as 'memory' for this session (the 'out'). Smaller is better.\"\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Freed\"\n\t\t\t\tvalue={props.tokensFreed.toLocaleString()}\n\t\t\t\ttitle=\"Conversation space freed = dropped − kept (the 'saved').\"\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Injected\"\n\t\t\t\tvalue={props.injectedCount}\n\t\t\t\ttitle=\"How many times old context was automatically brought back into the conversation because it was relevant to what you were doing.\"\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Recall Relevance\"\n\t\t\t\tvalue={fmtPctFromFraction(props.dedupHitRate)}\n\t\t\t\ttitle=\"Of the times we recalled old context, how often it was actually on-topic.\"\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Storage Dedup\"\n\t\t\t\tvalue={fmtPctFromFraction(props.storageDedupRate)}\n\t\t\t\ttitle=\"How often new content matched something we already had, so we skipped storing a duplicate copy. Higher = less wasted space.\"\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Collapsed\"\n\t\t\t\tvalue={props.dedupCollapsed}\n\t\t\t\ttitle=\"How many duplicate chunks we collapsed into one instead of storing separately.\"\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Last ID\"\n\t\t\t\tvalue={props.lastCheckpointId ?? \"—\"}\n\t\t\t\ttitle=\"The ID of the most recent saved checkpoint.\"\n\t\t\t/>\n\t\t\t<div className=\"ov-compression-meter\">\n\t\t\t\t<div className=\"meter-track\">\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={`meter-fill ${barCls}`}\n\t\t\t\t\t\tstyle={{ width: `${barWidth}%` }}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t\t<span className=\"meter-sub\">{compressSub}</span>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/components/RepoAllSessionsCard.tsx — Repo (all sessions) card.\n *\n * 7 fields: Checkpoints, Original, Kept, Freed, Sessions, Collapsed, Storage Dedup.\n * Plus a compression meter bar (green ≥90%, yellow ≥60%, red <60%).\n *\n * NOTE: storageDedupRate, compressionPct, dedupPct are 0–1 fractions\n * at runtime (despite contract saying 0–100).\n */\n\nimport type React from \"react\";\nimport { fmtPctFromFraction } from \"../utils/format\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"../components/ui/card\";\n\nexport interface RepoAllSessionsCardProps {\n\tcheckpointCount: number;\n\t/** Original tokens dropped (repo-level). */\n\ttokensIn: number;\n\t/** Kept summary tokens (repo-level). */\n\ttokensOut: number;\n\t/** Tokens freed (repo-level). */\n\ttokensFreed: number;\n\t/** Number of sessions. */\n\tsessionCount: number;\n\t/** Duplicate chunks collapsed (repo-level). */\n\tdedupCollapsed: number;\n\t/** Storage dedup rate — 0–1 fraction. */\n\tstorageDedupRate: number;\n\t/** Repo compression ratio — 0–1 fraction. */\n\tcompressionPct: number;\n\t/** Repo dedup contribution — 0–1 fraction. */\n\tdedupPct: number;\n}\n\nfunction compressClass(sp: number): string {\n\tif (sp >= 0.9) return \"meter-green\";\n\tif (sp >= 0.6) return \"meter-yellow\";\n\treturn \"meter-red\";\n}\n\nfunction StatRow({\n\tlabel,\n\tvalue,\n}: {\n\tlabel: string;\n\tvalue: string | number;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"flex items-baseline justify-between border-b border-border py-1 text-sm\">\n\t\t\t<span className=\"text-xs text-muted-foreground\">{label}</span>\n\t\t\t<span className=\"font-semibold\">{value}</span>\n\t\t</div>\n\t);\n}\n\nexport function RepoAllSessionsCard(\n\tprops: RepoAllSessionsCardProps,\n): React.ReactElement {\n\tconst sp = props.compressionPct;\n\tconst barCls = compressClass(sp);\n\tconst barWidth = Math.max(sp * 100, 0.5);\n\tconst compressSub = `${fmtPctFromFraction(sp)} tokens saved · dedup: ${fmtPctFromFraction(props.dedupPct)}`;\n\n\treturn (\n\t\t<Card className=\"electric-hover\">\n\t\t\t<CardHeader>\n\t\t\t\t<CardTitle>Repo (all sessions)</CardTitle>\n\t\t\t</CardHeader>\n\t\t\t<CardContent>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Checkpoints\"\n\t\t\t\tvalue={props.checkpointCount.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Original\"\n\t\t\t\tvalue={props.tokensIn.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Kept\"\n\t\t\t\tvalue={props.tokensOut.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Freed\"\n\t\t\t\tvalue={props.tokensFreed.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Sessions\"\n\t\t\t\tvalue={props.sessionCount.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow label=\"Collapsed\" value={props.dedupCollapsed} />\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Storage Dedup\"\n\t\t\t\tvalue={fmtPctFromFraction(props.storageDedupRate)}\n\t\t\t/>\n\t\t\t<div>\n\t\t\t\t<div className=\"mt-2 h-2 w-full overflow-hidden rounded-full bg-bg-elevated\">\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={`meter-fill h-full ${barCls}`}\n\t\t\t\t\t\tstyle={{ width: `${barWidth}%` }}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t\t<span className=\"mt-1 block text-xs text-muted-foreground\">{compressSub}</span>\n\t\t\t</div>\n\t\t\t</CardContent>\n\t\t</Card>\n\t);\n}\n","/**\n * dashboard-client/src/components/DataSafetyCard.tsx — Data Safety / Shield.\n *\n * 4 fields: Regions Retained, Compressed-Original bytes, Dedup Duplicates,\n * Permanently Deleted (always 0B, shown in green).\n * Plus the safe-note text (verbatim from html.ts).\n */\n\nimport type React from \"react\";\nimport { fmtBytes } from \"../utils/format\";\n\nexport interface DataSafetyCardProps {\n\tregionsRetained: number;\n\t/** Original byte size of compressed data (bytes). */\n\tcompressedOriginalBytes: number;\n\t/** Number of duplicate chunks collapsed. */\n\tduplicatesCollapsed: number;\n\t/** Bytes permanently deleted (always 0). */\n\tbytesPermanentlyDeleted: number;\n}\n\nexport function DataSafetyCard(\n\tprops: DataSafetyCardProps,\n): React.ReactElement {\n\treturn (\n\t\t<div className=\"card data-safety-card\">\n\t\t\t<h3>🛡 Data Safety</h3>\n\t\t\t<div className=\"ov-stat-row\">\n\t\t\t\t<span className=\"ov-stat-label\">Regions Retained</span>\n\t\t\t\t<span className=\"ov-stat-value\">\n\t\t\t\t\t{props.regionsRetained.toLocaleString()}\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t\t<div className=\"ov-stat-row\">\n\t\t\t\t<span className=\"ov-stat-label\">Compressed-Original</span>\n\t\t\t\t<span className=\"ov-stat-value\">\n\t\t\t\t\t{fmtBytes(props.compressedOriginalBytes)}\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t\t<div className=\"ov-stat-row\">\n\t\t\t\t<span className=\"ov-stat-label\">Dedup Duplicates</span>\n\t\t\t\t<span className=\"ov-stat-value\">\n\t\t\t\t\t{props.duplicatesCollapsed.toLocaleString()}\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t\t<div className=\"ov-stat-row\">\n\t\t\t\t<span className=\"ov-stat-label\">Permanently Deleted</span>\n\t\t\t\t<span className=\"ov-stat-value ov-value-ok\">\n\t\t\t\t\t{fmtBytes(props.bytesPermanentlyDeleted)}\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t\t<p className=\"safe-note\">\n\t\t\t\tEvery compacted region is kept verbatim (compressed). "Drop" =\n\t\t\t\tremoved from the live window only. We never delete your data.\n\t\t\t</p>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/components/ConfigSummaryCard.tsx — Configuration summary.\n *\n * 7 fields with tooltips (verbatim from html.ts):\n * Tier (live), Preset, Pressure, Threshold, Fast Gate, Auto, Anchor.\n *\n * NOTE: pressure and tierPct are 0–1 fractions at runtime.\n * fastGatePct is 0–100 at runtime.\n */\n\nimport type React from \"react\";\n\nexport interface ConfigSummaryCardProps {\n\t/** Current tier name. */\n\ttier: string;\n\t/** Preset tier name. */\n\tpresetTier: string;\n\t/** Live pressure — 0–1 fraction. */\n\tpressure: number;\n\t/** Token threshold. */\n\tthresholdTokens: number;\n\t/** Tier percentage — 0–1 fraction (runtime-only field). */\n\ttierPct?: number;\n\t/** Context window size. */\n\tcontextWindow: number;\n\t/** Fast-gate percentage — 0–100. */\n\tfastGatePct: number;\n\t/** Whether auto-compaction is enabled. */\n\tauto: boolean;\n\t/** Number of anchor user messages. */\n\tanchorUserMessages: number;\n}\n\nfunction StatRow({\n\tlabel,\n\tvalue,\n\ttitle,\n}: {\n\tlabel: string;\n\tvalue: string;\n\ttitle?: string;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"ov-stat-row\">\n\t\t\t<span className=\"ov-stat-label\" title={title}>\n\t\t\t\t{label}\n\t\t\t</span>\n\t\t\t<span className=\"ov-stat-value\">{value}</span>\n\t\t</div>\n\t);\n}\n\nexport function ConfigSummaryCard(\n\tprops: ConfigSummaryCardProps,\n): React.ReactElement {\n\tconst pressurePct = `${Math.round((props.pressure ?? 0) * 100)}%`;\n\n\tlet thresholdTxt = props.thresholdTokens.toLocaleString();\n\tif (props.tierPct != null && props.contextWindow > 0) {\n\t\tthresholdTxt += ` (${Math.round(props.tierPct * 100)}% of ${props.contextWindow.toLocaleString()})`;\n\t}\n\n\treturn (\n\t\t<div className=\"card config-summary-card\">\n\t\t\t<h3>Configuration</h3>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Tier\"\n\t\t\t\tvalue={`${props.tier} (live)`}\n\t\t\t\ttitle=\"Live pressure band — climbs low→mega as context fills the window.\"\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Preset\"\n\t\t\t\tvalue={props.presetTier}\n\t\t\t\ttitle=\"The env-resolved base compaction preset (low/medium/high/ultra/mega) that set the token threshold.\"\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Pressure\"\n\t\t\t\tvalue={pressurePct}\n\t\t\t\ttitle=\"Live pressure = currentTokens / threshold — % of the model context window (threshold fires at the tier's % of window).\"\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Threshold\"\n\t\t\t\tvalue={thresholdTxt}\n\t\t\t\ttitle=\"Compaction threshold = tierPct × model context window — mega-compact trims BELOW pi's native ~80% auto-compact for any model size.\"\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Fast Gate\"\n\t\t\t\tvalue={`${props.fastGatePct}%`}\n\t\t\t\ttitle=\"Fast-gate arming floor — the live trim arms once context passes this % of the window.\"\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Auto\"\n\t\t\t\tvalue={props.auto ? \"enabled\" : \"disabled\"}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Anchor\"\n\t\t\t\tvalue={String(props.anchorUserMessages)}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/components/CacheStatusPerModel.tsx — Model & Cost Savings card.\n *\n * Shows $ saved, context-windows extended, Model, Provider, Input Rate, Output Rate.\n * Tooltips copied verbatim from html.ts.\n */\n\nimport type React from \"react\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"../components/ui/card\";\n\nexport interface ModelCostCardProps {\n\t/** Model name. */\n\tname: string;\n\t/** Provider display name (providerName fallback to provider). */\n\tprovider: string;\n\t/** USD per input token. */\n\tinputRate: number;\n\t/** USD per output token. */\n\toutputRate: number;\n\t/** Tokens freed (repo-level) used for cost calc. */\n\trepoTokensFreed: number;\n\t/** Context window size used for windows calc. */\n\tcontextWindow: number;\n}\n\nfunction StatRow({\n\tlabel,\n\tvalue,\n\ttitle,\n}: {\n\tlabel: string;\n\tvalue: string;\n\ttitle?: string;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"flex items-baseline justify-between border-b border-border py-1 text-sm\">\n\t\t\t<span className=\"text-xs text-muted-foreground\" title={title}>\n\t\t\t\t{label}\n\t\t\t</span>\n\t\t\t<span className=\"font-semibold\">{value}</span>\n\t\t</div>\n\t);\n}\n\nexport function CacheStatusPerModel(\n\tprops: ModelCostCardProps,\n): React.ReactElement {\n\tconst repoSaved = props.repoTokensFreed || 0;\n\tlet usd = 0;\n\tlet windows = \"0\";\n\n\tif (props.inputRate && repoSaved > 0) {\n\t\tusd = repoSaved * props.inputRate;\n\t\tconst win = props.contextWindow || 0;\n\t\twindows = win > 0 ? (repoSaved / win).toFixed(1) : \"0\";\n\t}\n\n\tconst usdStr = `≈ $${usd.toFixed(4)} saved`;\n\tconst windowsStr = `${windows} context-windows extended`;\n\n\treturn (\n\t\t<Card className=\"electric-hover\">\n\t\t\t<CardHeader>\n\t\t\t\t<CardTitle>💰 Model & Cost Savings</CardTitle>\n\t\t\t</CardHeader>\n\t\t\t<CardContent>\n\t\t\t\t<div className=\"text-neon text-xl font-semibold\">{usdStr}</div>\n\t\t\t\t<div className=\"mb-2 text-xs text-muted-foreground\">{windowsStr}</div>\n\t\t\t\t<StatRow\n\t\t\t\t\tlabel=\"Model\"\n\t\t\t\t\tvalue={props.name}\n\t\t\t\t\ttitle=\"The model pi is currently using — its pricing drives the cost figure.\"\n\t\t\t\t/>\n\t\t\t\t<StatRow\n\t\t\t\t\tlabel=\"Provider\"\n\t\t\t\t\tvalue={props.provider}\n\t\t\t\t\ttitle=\"The provider serving the model.\"\n\t\t\t\t/>\n\t\t\t\t<StatRow\n\t\t\t\t\tlabel=\"Input Rate\"\n\t\t\t\t\tvalue={`$${props.inputRate.toFixed(6)}`}\n\t\t\t\t\ttitle=\"USD per input token, from the model's pricing.\"\n\t\t\t\t/>\n\t\t\t\t<StatRow\n\t\t\t\t\tlabel=\"Output Rate\"\n\t\t\t\t\tvalue={`$${props.outputRate.toFixed(6)}`}\n\t\t\t\t\ttitle=\"USD per output token, from the model's pricing.\"\n\t\t\t\t/>\n\t\t\t</CardContent>\n\t\t</Card>\n\t);\n}\n","/**\n * dashboard-client/src/components/SessionInfo.tsx — Crew / Agents card.\n *\n * Shows Active Agents, Current Turn, and Status.\n */\n\nimport type React from \"react\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"../components/ui/card\";\n\nexport interface SessionInfoProps {\n\t/** Number of active crew agents. */\n\tactiveAgents: number;\n\t/** Current turn index in the crew round-robin. */\n\tcurrentTurn: number;\n}\n\nexport function SessionInfo(\n\tprops: SessionInfoProps,\n): React.ReactElement {\n\tconst { activeAgents, currentTurn } = props;\n\tconst status =\n\t\tactiveAgents > 0 ? `▶ ${activeAgents} running` : \"idle\";\n\n\treturn (\n\t\t<Card className=\"electric-hover\">\n\t\t\t<CardHeader>\n\t\t\t\t<CardTitle>Crew / Agents</CardTitle>\n\t\t\t</CardHeader>\n\t\t\t<CardContent>\n\t\t\t\t<div className=\"flex items-baseline justify-between border-b border-border py-1 text-sm\">\n\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">Active Agents</span>\n\t\t\t\t\t<span className=\"font-semibold\">{activeAgents}</span>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"flex items-baseline justify-between border-b border-border py-1 text-sm\">\n\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">Current Turn</span>\n\t\t\t\t\t<span className=\"font-semibold\">{currentTurn}</span>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"flex items-baseline justify-between py-1 text-sm\">\n\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">Status</span>\n\t\t\t\t\t<span className=\"font-semibold\">{status}</span>\n\t\t\t\t</div>\n\t\t\t</CardContent>\n\t\t</Card>\n\t);\n}\n","/**\n * dashboard-client/src/components/LegendCard.tsx — \"What these numbers mean\" legend.\n *\n * Collapsible <details> with the legend list (verbatim from html.ts).\n * Full-width card (grid-column: 1 / -1).\n */\n\nimport type React from \"react\";\nimport { Card, CardContent } from \"../components/ui/card\";\n\nconst LEGEND_ITEMS: ReadonlyArray<React.ReactNode> = [\n\t<li key=\"1\">\n\t\t<b>Original (dropped)</b> — everything compacted away (including\n\t\tduplicates caught by dedup). The "in."\n\t</li>,\n\t<li key=\"2\">\n\t\t<b>Kept (summaries)</b> — compact summaries still held as "memory"\n\t\t(the "out").\n\t</li>,\n\t<li key=\"3\">\n\t\t<b>Freed</b> = dropped − kept — tokens saved so far (higher = better).\n\t</li>,\n\t<li key=\"4\">\n\t\t<b>Compression %</b> — Freed ÷ Dropped — the headline efficiency\n\t\tnumber. Higher = more space reclaimed.\n\t</li>,\n\t<li key=\"5\">\n\t\t<b>Storage dedup %</b> — how often new content matched something\n\t\talready saved, so no duplicate copy was written.\n\t</li>,\n\t<li key=\"6\">\n\t\t<b>Data safety</b> — every compacted region is kept verbatim\n\t\t(compressed). Nothing is permanently deleted; you can restore any of\n\t\tit.\n\t</li>,\n];\n\nexport function LegendCard(): React.ReactElement {\n\treturn (\n\t\t<Card>\n\t\t\t<CardContent>\n\t\t\t\t<details>\n\t\t\t\t\t<summary className=\"cursor-pointer text-sm font-semibold\">\n\t\t\t\t\t\tWhat these numbers mean\n\t\t\t\t\t</summary>\n\t\t\t\t\t<ol className=\"mt-2 list-decimal space-y-1 pl-5 text-sm\">\n\t\t\t\t\t\t{LEGEND_ITEMS}\n\t\t\t\t\t</ol>\n\t\t\t\t\t<p className=\"mt-2 text-xs text-muted-foreground\">\n\t\t\t\t\t\tHover any label above for a quick explanation.\n\t\t\t\t\t</p>\n\t\t\t\t</details>\n\t\t\t</CardContent>\n\t\t</Card>\n\t);\n}\n","/**\n * SetupTab/RagHealthCard.tsx — mini RAG health summary for the Overview tab\n * (H3.2). Shows pass rate, avg lift, and an on/off indicator dot, fetched\n * inline from /api/rag-metrics.\n *\n * PREVENT-PI-004: relative-path fetch to the same-origin dashboard server.\n */\n\nimport type React from \"react\";\nimport { useMemo } from \"react\";\nimport { useApi } from \"../../hooks/useApi\";\nimport { fetchRagMetrics } from \"../../api/client\";\nimport type { RagMetricsResponse } from \"@contracts\";\nimport { Card, CardHeader, CardTitle, CardContent } from \"../../components/ui/card\";\n\nexport const RagHealthCard: React.FC = () => {\n\tconst { data: m } = useApi<RagMetricsResponse>(\n\t\tuseMemo(() => () => fetchRagMetrics(), []),\n\t\t{ pollInterval: 30_000 },\n\t);\n\n\tif (!m) {\n\t\treturn (\n\t\t\t<Card>\n\t\t\t\t<CardContent className=\"text-sm text-muted-foreground\">Loading RAG health…</CardContent>\n\t\t\t</Card>\n\t\t);\n\t}\n\n\tconst { totals, flags } = m;\n\tconst active = flags.hydeEnabled || flags.recallMetricsEnabled;\n\n\treturn (\n\t\t<Card>\n\t\t\t<CardHeader>\n\t\t\t\t<CardTitle className=\"flex items-center gap-2\">\n\t\t\t\t\t<span\n\t\t\t\t\t\tclassName={`inline-block h-2 w-2 rounded-full ${active ? \"bg-success\" : \"bg-muted-foreground\"}`}\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t/>\n\t\t\t\t\tRAG Health\n\t\t\t\t</CardTitle>\n\t\t\t</CardHeader>\n\t\t\t<CardContent>\n\t\t\t\t{!active ? (\n\t\t\t\t\t<div className=\"text-sm text-muted-foreground\">\n\t\t\t\t\t\tAll RAG recall feature flags are off.\n\t\t\t\t\t</div>\n\t\t\t\t) : (\n\t\t\t\t\t<dl className=\"grid grid-cols-2 gap-x-4 gap-y-2 text-sm\">\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<dt className=\"text-xs text-muted-foreground\">Pass rate</dt>\n\t\t\t\t\t\t\t<dd className=\"font-semibold text-foreground\">\n\t\t\t\t\t\t\t\t{Math.round(totals.recentPassRate * 100)}%\n\t\t\t\t\t\t\t</dd>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<dt className=\"text-xs text-muted-foreground\">Avg lift</dt>\n\t\t\t\t\t\t\t<dd className=\"font-semibold text-foreground\">\n\t\t\t\t\t\t\t\t{totals.avgLift.toFixed(2)}×\n\t\t\t\t\t\t\t</dd>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<dt className=\"text-xs text-muted-foreground\">Telemetry turns</dt>\n\t\t\t\t\t\t\t<dd className=\"font-semibold text-foreground\">{totals.telemetryTurns}</dd>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<dt className=\"text-xs text-muted-foreground\">HyDE ran</dt>\n\t\t\t\t\t\t\t<dd className=\"font-semibold text-foreground\">{totals.hydeRanTurns}</dd>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</dl>\n\t\t\t\t)}\n\t\t\t</CardContent>\n\t\t</Card>\n\t);\n};\n\nexport default RagHealthCard;\n","/**\n * dashboard-client/src/tabs/OverviewTab.tsx — Overview tab (full spec).\n *\n * Renders all 11 cards from the spec:\n * 1. Context Window (ContextGauge)\n * 2. Trigger Status (TriggerStatus)\n * 3. Vector Store (session) (VectorStoreCard)\n * 4. Repo (all sessions) (RepoAllSessionsCard)\n * 5. Data Safety (DataSafetyCard)\n * 6. Configuration (ConfigSummaryCard)\n * 7. Model & Cost Savings (CacheStatusPerModel)\n * 8. Crew / Agents (SessionInfo)\n * 9. Cache Hits & Compactions (CacheHitsCard)\n * 10. Time Saved (TimeSavedCard)\n * 11. Legend (LegendCard)\n *\n * All data comes from the snapshot prop passed by App.tsx.\n */\n\nimport type React from \"react\";\nimport { useCallback, useEffect, useMemo } from \"react\";\nimport { useApi } from \"../hooks/useApi\";\nimport { useSSE } from \"../hooks/useSSE\";\nimport { fetchSessions } from \"../api/client\";\nimport type {\n\tSnapshotResponse,\n\tSseEvent,\n\tSseSessionSample,\n\tSessionsResponse,\n} from \"@contracts\";\nimport type { RuntimeSnapshot } from \"../utils/types\";\nimport { RepoContextStack } from \"../components/RepoContextStack\";\nimport { SessionContextGauges } from \"../components/SessionContextGauges\";\nimport { TriggerStatus } from \"../components/TriggerStatus\";\nimport { VectorStoreCard } from \"../components/VectorStoreCard\";\nimport { RepoAllSessionsCard } from \"../components/RepoAllSessionsCard\";\nimport { DataSafetyCard } from \"../components/DataSafetyCard\";\nimport { ConfigSummaryCard } from \"../components/ConfigSummaryCard\";\nimport { CacheStatusPerModel } from \"../components/CacheStatusPerModel\";\nimport { SessionInfo } from \"../components/SessionInfo\";\nimport { CacheHitsCard } from \"../components/CacheHitsCard\";\nimport { TimeSavedCard } from \"../components/TimeSavedCard\";\nimport { LegendCard } from \"../components/LegendCard\";\nimport { Badge } from \"../components/ui/badge\";\nimport { NEW_UI } from \"../config\";\nimport RagHealthCard from \"./SetupTab/RagHealthCard\";\n\n/** Type guard: narrows an SSE event to a session_sample event. */\nfunction isSessionSample(e: SseEvent): e is SseSessionSample {\n\treturn e.type === \"session_sample\";\n}\n\nexport interface OverviewTabProps {\n\tsnapshot: SnapshotResponse | null;\n\tloading: boolean;\n\terror: Error | null;\n}\n\nfunction formatUpdatedAt(ts: string | null): string {\n\tif (!ts) return \"never\";\n\ttry {\n\t\treturn new Date(ts).toLocaleString();\n\t} catch {\n\t\treturn ts;\n\t}\n}\n\nexport default function OverviewTab({\n\tsnapshot,\n\tloading,\n\terror,\n}: OverviewTabProps): React.ReactElement {\n\t// S40: real-time per-repo context via /api/sessions + SSE. Mirrors the\n\t// SessionsTab pattern: 2s poll + session_sample SSE refetch.\n\tconst {\n\t\tdata: sessionsData,\n\t\terror: sessionsErr,\n\t\tloading: sessionsLoading,\n\t\trefetch: refetchSessions,\n\t} = useApi<SessionsResponse>(\n\t\tuseCallback(() => fetchSessions(), []),\n\t\t{ pollInterval: 2_000 },\n\t);\n\n\tconst { events } = useSSE();\n\n\tconst sampleEvents = useMemo(() => events.filter(isSessionSample), [events]);\n\tconst lastSampleTs = useMemo(() => {\n\t\tif (sampleEvents.length === 0) return null;\n\t\treturn sampleEvents[sampleEvents.length - 1].ts;\n\t}, [sampleEvents]);\n\n\tuseEffect(() => {\n\t\tif (lastSampleTs == null) return;\n\t\trefetchSessions();\n\t}, [lastSampleTs, refetchSessions]);\n\n\tif (loading && !snapshot)\n\t\treturn <div className=\"tab-stub\">Loading snapshot…</div>;\n\tif (error && !snapshot)\n\t\treturn <div className=\"tab-stub\">Error: {error.message}</div>;\n\tif (!snapshot) return <div className=\"tab-stub\">No snapshot data.</div>;\n\n\t// Cast to RuntimeSnapshot for tierPct (runtime-only field).\n\tconst d = snapshot as RuntimeSnapshot;\n\tconst { context, compression, trigger, session, store, tier, updatedAt } = d;\n\tconst cfg = d.config;\n\tconst crew = d.crew;\n\tconst integrity = d.integrity;\n\tconst cacheHits = d.cacheHits;\n\tconst compacts = d.compacts;\n\tconst timeSaved = d.timeSaved;\n\tconst repo = d.repo;\n\tconst model = d.model;\n\n\treturn (\n\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t<Badge variant=\"accent\">{tier}</Badge>\n\t\t\t\t<span className=\"text-xs text-muted-foreground\">\n\t\t\t\t\tupdated {formatUpdatedAt(updatedAt)}\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t\t<div className=\"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3\">\n\t\t\t\t<SessionContextGauges\n\t\t\t\t\tsessions={sessionsData}\n\t\t\t\t\tloading={sessionsLoading}\n\t\t\t\t\terror={sessionsErr}\n\t\t\t\t\tlauncherSessionId={session.id}\n\t\t\t\t\tlauncher={{\n\t\t\t\t\t\ttokens: context.tokens,\n\t\t\t\t\t\tpercent: context.percent,\n\t\t\t\t\t\tcontextWindow: context.contextWindow,\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t\t<RepoContextStack\n\t\t\t\t\tsessions={sessionsData}\n\t\t\t\t\tloading={sessionsLoading}\n\t\t\t\t\terror={sessionsErr}\n\t\t\t\t/>\n\t\t\t\t<TriggerStatus\n\t\t\t\t\tarmed={trigger.armed}\n\t\t\t\t\tready={trigger.ready}\n\t\t\t\t\tcurrentTokens={trigger.currentTokens}\n\t\t\t\t\tthresholdTokens={trigger.thresholdTokens}\n\t\t\t\t\tfastGatePct={trigger.fastGatePct}\n\t\t\t\t/>\n\t\t\t\t<VectorStoreCard\n\t\t\t\t\tcheckpointCount={store.checkpointCount}\n\t\t\t\t\ttokensIn={compression.session.tokensIn}\n\t\t\t\t\ttokensOut={compression.session.tokensOut}\n\t\t\t\t\ttokensFreed={compression.session.tokensFreed}\n\t\t\t\t\tinjectedCount={store.injectedCount}\n\t\t\t\t\tdedupHitRate={store.dedupHitRate}\n\t\t\t\t\tstorageDedupRate={store.storageDedupRate}\n\t\t\t\t\tdedupCollapsed={store.dedupCollapsed}\n\t\t\t\t\tlastCheckpointId={session.lastCheckpointId}\n\t\t\t\t\tcompressionPct={compression.session.compressionPct}\n\t\t\t\t\tdedupPct={compression.session.dedupPct}\n\t\t\t\t/>\n\t\t\t\t<RepoAllSessionsCard\n\t\t\t\t\tcheckpointCount={repo.checkpointCount}\n\t\t\t\t\ttokensIn={compression.repo.tokensIn}\n\t\t\t\t\ttokensOut={compression.repo.tokensOut}\n\t\t\t\t\ttokensFreed={compression.repo.tokensFreed}\n\t\t\t\t\tsessionCount={repo.sessionCount}\n\t\t\t\t\tdedupCollapsed={repo.dedupCollapsed}\n\t\t\t\t\tstorageDedupRate={repo.storageDedupRate}\n\t\t\t\t\tcompressionPct={compression.repo.compressionPct}\n\t\t\t\t\tdedupPct={compression.repo.dedupPct}\n\t\t\t\t/>\n\t\t\t\t<DataSafetyCard\n\t\t\t\t\tregionsRetained={integrity.regionsRetained}\n\t\t\t\t\tcompressedOriginalBytes={integrity.compressedOriginalBytes}\n\t\t\t\t\tduplicatesCollapsed={integrity.duplicatesCollapsed}\n\t\t\t\t\tbytesPermanentlyDeleted={integrity.bytesPermanentlyDeleted}\n\t\t\t\t/>\n\t\t\t\t<ConfigSummaryCard\n\t\t\t\t\ttier={tier}\n\t\t\t\t\tpresetTier={d.presetTier}\n\t\t\t\t\tpressure={d.pressure}\n\t\t\t\t\tthresholdTokens={cfg.thresholdTokens}\n\t\t\t\t\ttierPct={cfg.tierPct}\n\t\t\t\t\tcontextWindow={context.contextWindow}\n\t\t\t\t\tfastGatePct={cfg.fastGatePct}\n\t\t\t\t\tauto={cfg.auto}\n\t\t\t\t\tanchorUserMessages={cfg.anchorUserMessages}\n\t\t\t\t/>\n\t\t\t\t{model && (\n\t\t\t\t\t<CacheStatusPerModel\n\t\t\t\t\t\tname={model.name}\n\t\t\t\t\t\tprovider={model.providerName || model.provider}\n\t\t\t\t\t\tinputRate={model.inputRate}\n\t\t\t\t\t\toutputRate={model.outputRate}\n\t\t\t\t\t\trepoTokensFreed={compression.repo.tokensFreed}\n\t\t\t\t\t\tcontextWindow={context.contextWindow}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t<SessionInfo\n\t\t\t\t\tactiveAgents={crew.activeAgents}\n\t\t\t\t\tcurrentTurn={crew.currentTurn}\n\t\t\t\t/>\n\t\t\t\t<CacheHitsCard\n\t\t\t\t\tcacheHitsSession={cacheHits.session}\n\t\t\t\t\tcacheHitsTotal={cacheHits.total}\n\t\t\t\t\ttokensSavedSession={cacheHits.sessionTokensSaved}\n\t\t\t\t\ttokensSavedTotal={cacheHits.totalTokensSaved}\n\t\t\t\t\tcompactionsSession={compacts.session}\n\t\t\t\t\tcompactionsTotal={compacts.total}\n\t\t\t\t/>\n\t\t\t\t<TimeSavedCard\n\t\t\t\t\tcompactSessionSec={timeSaved.compact.sessionSec}\n\t\t\t\t\tcompactTotalSec={timeSaved.compact.totalSec}\n\t\t\t\t\tcacheHitSessionSec={timeSaved.cacheHit.sessionSec}\n\t\t\t\t\tcacheHitTotalSec={timeSaved.cacheHit.totalSec}\n\t\t\t\t/>\n\t\t\t\t{NEW_UI() && <RagHealthCard />}\n\t\t\t\t<LegendCard />\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n"],"names":["REPO_PALETTE","hashString","str","hash","i","colorForRepo","basename","repoBasename","repoRoot","trimmed","parts","aggregateRepos","sessions","map","s","key","tokens","existing","repos","totalTokens","sum","r","maxWindow","max","fmtTokens","n","StackCard","children","jsxs","Card","jsx","CardHeader","CardTitle","CardContent","RepoContextStack","loading","error","activeSessions","sessionCount","combinedPct","pctOfTotal","widthPct","tooltip","severityClass","percent","fmtAge","ms","m","SessionGauge","data","pct","fillWidth","cls","tokStr","windowStr","sublabel","SessionContextGauges","launcherSessionId","launcher","now","gauges","others","b","hasError","showLoading","g","Bullet","state","label","TriggerStatus","armed","ready","armedState","readyState","stateText","compressClass","sp","StatRow","value","title","VectorStoreCard","props","barCls","barWidth","compressSub","fmtPctFromFraction","RepoAllSessionsCard","DataSafetyCard","fmtBytes","ConfigSummaryCard","pressurePct","thresholdTxt","CacheStatusPerModel","repoSaved","usd","windows","win","usdStr","windowsStr","SessionInfo","activeAgents","currentTurn","status","LEGEND_ITEMS","LegendCard","RagHealthCard","useApi","useMemo","fetchRagMetrics","totals","flags","active","isSessionSample","e","formatUpdatedAt","ts","OverviewTab","snapshot","sessionsData","sessionsErr","sessionsLoading","refetchSessions","useCallback","fetchSessions","events","useSSE","sampleEvents","lastSampleTs","useEffect","d","context","compression","trigger","session","store","tier","updatedAt","cfg","crew","integrity","cacheHits","compacts","timeSaved","repo","model","Badge","CacheHitsCard","TimeSavedCard","NEW_UI"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{j as e,r as d,u as y,b as F,c as W}from"./index-CQjCLvv7.js";import{C as m,c as x}from"./card-Cjn7Ifoe.js";import{b as C}from"./format-COjDIVGj.js";import{c as A}from"./pricing-CvE4NllQ.js";function I(t){return t>=1048576?`${(t/1048576).toFixed(1)} MiB`:t>=1024?`${(t/1024).toFixed(1)} KiB`:`${t} B`}function D(t){return t>=1e6?`${(t/1e6).toFixed(1)}M`:t>=1e3?`${(t/1e3).toFixed(1)}K`:String(t)}function R({totalRepos:t,totalCheckpoints:n,totalTokensSaved:s,compressedOriginalBytes:r}){return e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-4",children:[e.jsx(m,{className:"electric-hover",children:e.jsxs(x,{children:[e.jsx("span",{className:"tile-label",children:"Repositories"}),e.jsx("div",{className:"text-xl font-semibold",children:t.toLocaleString()})]})}),e.jsx(m,{className:"electric-hover",children:e.jsxs(x,{children:[e.jsx("span",{className:"tile-label",children:"Total Checkpoints"}),e.jsx("div",{className:"text-xl font-semibold",children:n.toLocaleString()})]})}),e.jsx(m,{className:"electric-hover",children:e.jsxs(x,{children:[e.jsx("span",{className:"tile-label",children:"Total Tokens Saved"}),e.jsx("div",{className:"text-xl font-semibold",children:D(s)})]})}),e.jsx(m,{className:"electric-hover",children:e.jsxs(x,{children:[e.jsx("span",{className:"tile-label",children:"Compressed-Original"}),e.jsx("div",{className:"text-xl font-semibold",children:I(r)})]})})]})}const w=[{key:"displayName",label:"Repo"},{key:"modelName",label:"Model"},{key:"checkpointCount",label:"Checkpoints"},{key:"tokensSaved",label:"Tokens Saved"},{key:"compressedOriginalBytes",label:"Retained"},{key:"lastCompactedAt",label:"Last Compacted"}];function E(t){return t>=1048576?`${(t/1048576).toFixed(1)} MiB`:t>=1024?`${(t/1024).toFixed(1)} KiB`:`${t} B`}function H(t){if(t==null)return"—";try{return new Date(t).toLocaleString()}catch{return String(t)}}function K({repos:t,onSelect:n}){const[s,r]=d.useState(""),[a,c]=d.useState("lastCompactedAt"),[l,j]=d.useState("desc"),b=d.useMemo(()=>{const o=s.trim().toLowerCase(),f=o?t.filter(g=>g.displayName.toLowerCase().includes(o)):t.slice();return f.sort((g,B)=>{const h=g[a],u=B[a],v=h==null,k=u==null;if(v&&k)return 0;if(v)return l==="desc"?1:-1;if(k)return l==="desc"?-1:1;const S=typeof h=="number"&&typeof u=="number"?h-u:String(h).localeCompare(String(u));return l==="desc"?-S:S}),f},[t,s,a,l]),O=o=>{a===o?j(f=>f==="asc"?"desc":"asc"):(c(o),j(o==="lastCompactedAt"||o==="tokensSaved"||o==="compressedOriginalBytes"?"desc":"asc"))};return e.jsx(m,{children:e.jsxs(x,{children:[e.jsx("input",{type:"search",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",placeholder:"Search repos…",value:s,onChange:o=>r(o.target.value),"aria-label":"Search repos"}),e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full border-collapse text-sm",children:[e.jsx("thead",{children:e.jsx("tr",{children:w.map(o=>e.jsx("th",{className:"border-b border-border px-3 py-2 text-left",children:e.jsxs("button",{type:"button",className:`font-medium text-muted-foreground transition-colors hover:text-foreground ${a===o.key?"text-neon":""}`,onClick:()=>O(o.key),children:[o.label,a===o.key&&e.jsx("span",{children:l==="asc"?" ▲":" ▼"})]})},o.key))})}),e.jsxs("tbody",{children:[b.length===0&&e.jsx("tr",{children:e.jsx("td",{colSpan:w.length,className:"px-3 py-4 text-muted-foreground",children:t.length===0?"No repositories registered yet.":"No repos match your search."})}),b.map(o=>e.jsxs("tr",{onClick:()=>n(o),className:"cursor-pointer border-b border-border/50 transition-colors hover:bg-bg-elevated/40",children:[e.jsx("td",{className:"px-3 py-2 font-medium",title:o.repoRoot,children:o.displayName}),e.jsx("td",{className:"px-3 py-2 text-muted-foreground",children:o.modelName??"—"}),e.jsx("td",{className:"px-3 py-2 text-right",children:o.checkpointCount.toLocaleString()}),e.jsx("td",{className:"px-3 py-2 text-right",children:o.tokensSaved.toLocaleString()}),e.jsx("td",{className:"px-3 py-2 text-right",children:E(o.compressedOriginalBytes)}),e.jsx("td",{className:"px-3 py-2 text-right",children:H(o.lastCompactedAt)})]},o.stateDir))]})]})})]})})}function p(t){return t>=1e6?`${(t/1e6).toFixed(1)}M`:t>=1e3?`${(t/1e3).toFixed(1)}K`:String(t)}function P(t){return t>=1048576?`${(t/1048576).toFixed(1)} MiB`:t>=1024?`${(t/1024).toFixed(1)} KiB`:`${t} B`}function $(t){if(t==null)return"never";try{return new Date(t).toLocaleString()}catch{return String(t)}}function U({repo:t,onClose:n}){return d.useEffect(()=>{const s=r=>{r.key==="Escape"&&n()};return window.addEventListener("keydown",s),()=>window.removeEventListener("keydown",s)},[n]),e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4",onClick:n,role:"dialog","aria-modal":"true",children:e.jsxs("div",{className:"max-h-[85vh] w-full max-w-xl overflow-y-auto rounded-xl border border-border bg-bg-card p-5 shadow-panel",onClick:s=>s.stopPropagation(),children:[e.jsxs("header",{className:"mb-2 flex items-start justify-between gap-4",children:[e.jsx("h2",{className:"font-heading text-lg font-semibold",children:t.displayName}),e.jsx("button",{type:"button",className:"text-2xl leading-none text-muted-foreground hover:text-foreground",onClick:n,"aria-label":"Close",children:"×"})]}),e.jsx("p",{className:"mb-4 break-all font-mono text-xs text-muted-foreground",children:t.repoRoot}),e.jsxs("div",{className:"mb-4 grid grid-cols-2 gap-3 sm:grid-cols-3",children:[e.jsxs("div",{className:"rounded-md border border-border/50 bg-bg-elevated/40 p-3",children:[e.jsx("span",{className:"block text-xs text-muted-foreground",children:"Checkpoints"}),e.jsx("span",{className:"text-xl font-semibold",children:t.checkpointCount.toLocaleString()})]}),e.jsxs("div",{className:"rounded-md border border-border/50 bg-bg-elevated/40 p-3",children:[e.jsx("span",{className:"block text-xs text-muted-foreground",children:"Sessions"}),e.jsx("span",{className:"text-xl font-semibold",children:t.sessions.toLocaleString()})]}),e.jsxs("div",{className:"rounded-md border border-border/50 bg-primary/10 p-3",children:[e.jsx("span",{className:"block text-xs text-muted-foreground",children:"Tokens saved"}),e.jsx("span",{className:"text-xl font-semibold",children:p(t.tokensSaved)})]}),e.jsxs("div",{className:"rounded-md border border-border/50 bg-bg-elevated/40 p-3",children:[e.jsx("span",{className:"block text-xs text-muted-foreground",children:"Tokens kept"}),e.jsx("span",{className:"text-xl font-semibold",children:p(t.tokensKept)})]}),e.jsxs("div",{className:"rounded-md border border-border/50 bg-bg-elevated/40 p-3",children:[e.jsx("span",{className:"block text-xs text-muted-foreground",children:"Tokens dropped"}),e.jsx("span",{className:"text-xl font-semibold",children:p(t.tokensDropped)})]}),e.jsxs("div",{className:"rounded-md border border-border/50 bg-bg-elevated/40 p-3",children:[e.jsx("span",{className:"block text-xs text-muted-foreground",children:"Dedup rate"}),e.jsx("span",{className:"text-xl font-semibold",children:"—"})]})]}),e.jsx("h3",{className:"mb-2 font-heading text-sm font-semibold",children:"Model"}),e.jsxs("dl",{className:"mb-4 grid grid-cols-1 gap-1 text-sm sm:grid-cols-2",children:[e.jsx("dt",{className:"text-muted-foreground",children:"Provider"}),e.jsx("dd",{className:"text-right",children:t.providerName??"—"}),e.jsx("dt",{className:"text-muted-foreground",children:"Model"}),e.jsx("dd",{className:"text-right",children:t.modelName??"—"}),e.jsx("dt",{className:"text-muted-foreground",children:"Input rate"}),e.jsx("dd",{className:"text-right",children:t.inputRate!==null?`${t.inputRate} tok/s`:"—"}),e.jsx("dt",{className:"text-muted-foreground",children:"Output rate"}),e.jsx("dd",{className:"text-right",children:t.outputRate!==null?`${t.outputRate} tok/s`:"—"}),e.jsx("dt",{className:"text-muted-foreground",children:"Context window"}),e.jsx("dd",{className:"text-right",children:t.contextWindow!==null?p(t.contextWindow):"—"}),e.jsx("dt",{className:"text-muted-foreground",children:"Max tokens"}),e.jsx("dd",{className:"text-right",children:t.maxTokens!==null?p(t.maxTokens):"—"}),e.jsx("dt",{className:"text-muted-foreground",children:"Reasoning"}),e.jsx("dd",{className:"text-right",children:t.reasoning===null?"—":t.reasoning?"on":"off"})]}),e.jsx("h3",{className:"mb-2 font-heading text-sm font-semibold",children:"Activity"}),e.jsxs("dl",{className:"grid grid-cols-1 gap-1 text-sm sm:grid-cols-2",children:[e.jsx("dt",{className:"text-muted-foreground",children:"Last compacted"}),e.jsx("dd",{className:"text-right",children:$(t.lastCompactedAt)}),e.jsx("dt",{className:"text-muted-foreground",children:"Last seen"}),e.jsx("dd",{className:"text-right",children:$(t.lastSeen)}),e.jsx("dt",{className:"text-muted-foreground",children:"Compressed-Original"}),e.jsx("dd",{className:"text-right",children:P(t.compressedOriginalBytes)})]})]})})}function N(t){const n=t??0;return n>=3600?`${(n/3600).toFixed(1)}h`:n>=60?`${Math.round(n/60)}m`:n>=1?`${n.toFixed(1)}s`:`${Math.round(n*1e3)}ms`}const T=["Repo","Model","Tier","Context %","State","Compactions (s/t)","Cache Hits (s/t)","Cache Hit %","Est. Saved","Cache Read","Cache Write","Compact s/t (s)","CacheHit s/t (s)"];function q({servers:t}){return e.jsx(m,{children:e.jsxs(x,{children:[e.jsx("p",{className:"mb-3 text-xs text-muted-foreground",children:"Repos seen within the last 30 minutes, with their per-repo cache-hit, compaction, and time-saved (est.) totals pulled live from each repo's dashboard.json."}),e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full border-collapse text-sm",children:[e.jsx("thead",{children:e.jsx("tr",{children:T.map((n,s)=>e.jsx("th",{className:`border-b border-border px-3 py-2 text-left font-medium text-muted-foreground${s>=3&&s!==4?" text-right":""}`,children:n},n))})}),e.jsxs("tbody",{children:[t.length===0&&e.jsx("tr",{children:e.jsx("td",{colSpan:T.length,className:"px-3 py-4 text-muted-foreground",children:"No active repositories."})}),t.map(n=>{const s=n.cacheHits??{session:0,total:0},r=n.compacts??{session:0,total:0},a=n.timeSaved??{compact:{sessionSec:0,totalSec:0},cacheHit:{sessionSec:0,totalSec:0}};return e.jsxs("tr",{children:[e.jsx("td",{title:n.repoRoot,children:n.displayName||n.repoRoot}),e.jsx("td",{children:n.model??"—"}),e.jsx("td",{children:n.tier??"—"}),e.jsx("td",{className:"num",children:n.contextPct!=null?`${Math.round(n.contextPct*100)}%`:"—"}),e.jsx("td",{children:n.state??"—"}),e.jsxs("td",{className:"num",children:[r.session," / ",r.total]}),e.jsxs("td",{className:"num",children:[s.session," / ",s.total]}),e.jsx("td",{className:"num",children:n.providerCache!=null?`${n.providerCache.avgHitPct.toFixed(1)}%`:"—"}),e.jsx("td",{className:"num",children:n.providerCache?.estimatedSaved!=null?`$${n.providerCache.estimatedSaved.toFixed(2)}`:"—"}),e.jsx("td",{className:"num",children:n.providerCache?.cacheRead!=null?C(n.providerCache.cacheRead):"—"}),e.jsx("td",{className:"num",children:n.providerCache?.cacheWrite!=null?C(n.providerCache.cacheWrite):"—"}),e.jsxs("td",{className:"num",children:[N(a.compact.sessionSec)," /"," ",N(a.compact.totalSec)]}),e.jsxs("td",{className:"num",children:[N(a.cacheHit.sessionSec)," /"," ",N(a.cacheHit.totalSec)]})]},n.repoRoot)})]})]})})]})})}function L(t){if(!t.length)return"—";const n=Math.min(...t),s=Math.max(...t);return n===s?n.toLocaleString():`${n.toLocaleString()}–${s.toLocaleString()}`}function M(t){if(!t.length)return"—";const n=Math.min(...t),s=Math.max(...t),r=a=>`$${a.toFixed(6)}`;return n===s?r(n):`${r(n)}–${r(s)}`}function z(t){const n={};for(const s of t){const r=s.modelName&&s.modelName.trim()||"(unknown)";n[r]||(n[r]={model:r,provider:s.providerName??s.provider??"—",checkpoints:0,tokensSaved:0,tokensIn:0,tokensOut:0,sessions:0,usd:0,inRates:[],outRates:[],ctxWindows:[],maxTokens:[],reasoning:null,lastAt:0,cacheRead:0,cacheWrite:0});const a=n[r];a.checkpoints+=s.checkpointCount||0,a.tokensSaved+=s.tokensSaved||0,a.tokensIn+=s.tokensDropped||0,a.tokensOut+=s.tokensKept||0,a.sessions+=s.sessions||0,s.inputRate&&(a.usd+=(s.tokensSaved||0)*s.inputRate,a.inRates.push(s.inputRate)),s.outputRate&&a.outRates.push(s.outputRate),s.contextWindow&&a.ctxWindows.push(s.contextWindow),s.maxTokens&&a.maxTokens.push(s.maxTokens),s.reasoning!=null&&(a.reasoning=s.reasoning),s.providerCacheRead&&(a.cacheRead+=s.providerCacheRead),s.providerCacheWrite&&(a.cacheWrite+=s.providerCacheWrite),s.lastCompactedAt&&s.lastCompactedAt>a.lastAt&&(a.lastAt=s.lastCompactedAt)}return Object.values(n).sort((s,r)=>r.tokensSaved-s.tokensSaved)}const i={tokensIn:"Tokens dropped from context by compaction (the input reclaimed)",tokensOut:"Tokens kept as compacted summaries still in context (the output retained)",ctxWindow:"Model context window (max input tokens the model accepts)",maxOut:"Model max output tokens per turn",reas:"Reasoning-capable model",sessions:"Distinct sessions with at least one checkpoint",inRate:"USD per input token",outRate:"USD per output token"};function _({repos:t}){const n=d.useMemo(()=>z(t),[t]);return e.jsxs("div",{className:"savings-by-model",children:[e.jsx("p",{className:"legend-note",children:"How much context & cost mega-compact has reclaimed, grouped by the model you were running. Compression ratio reflects workload/content, not model quality."}),e.jsx("div",{className:"table-scroll",children:e.jsxs("table",{className:"savings-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Model"}),e.jsx("th",{children:"Provider"}),e.jsx("th",{className:"num",title:i.tokensIn,children:"Tokens In"}),e.jsx("th",{className:"num",title:i.tokensOut,children:"Tokens Out"}),e.jsx("th",{className:"num",children:"Freed"}),e.jsx("th",{className:"num",title:i.ctxWindow,children:"Ctx Window"}),e.jsx("th",{className:"num",title:i.maxOut,children:"Max Out"}),e.jsx("th",{className:"num",title:i.reas,children:"Reas."}),e.jsx("th",{className:"num",title:i.sessions,children:"Sessions"}),e.jsx("th",{className:"num",children:"Checkpoints"}),e.jsx("th",{className:"num",title:i.inRate,children:"In $/tok"}),e.jsx("th",{className:"num",title:i.outRate,children:"Out $/tok"}),e.jsx("th",{className:"num",children:"$ Saved"}),e.jsx("th",{className:"num",title:"Provider prompt-cache hit rate (reads / reads+writes+tokens_in)",children:"Cache Hit %"}),e.jsx("th",{className:"num",title:"Estimated provider prompt-cache savings (read tokens * 0.9 * inputRate − write tokens * 0.25 * inputRate)",children:"Cache $ Saved"}),e.jsx("th",{className:"num",children:"Last Used"})]})}),e.jsxs("tbody",{children:[n.length===0&&e.jsx("tr",{children:e.jsx("td",{colSpan:16,className:"repo-empty",children:"No repositories registered yet."})}),n.map(s=>{const r=(s.tokensIn||0)-(s.tokensOut||0),a=s.usd>0?`$${s.usd.toFixed(4)}`:"—",c=s.lastAt?new Date(s.lastAt).toLocaleString():"—",l=s.reasoning==null?"—":s.reasoning?"yes":"no";return e.jsxs("tr",{children:[e.jsx("td",{className:"repo-model",children:s.model}),e.jsx("td",{children:s.provider}),e.jsx("td",{className:"num",children:s.tokensIn.toLocaleString()}),e.jsx("td",{className:"num",children:s.tokensOut.toLocaleString()}),e.jsx("td",{className:"num",children:r.toLocaleString()}),e.jsx("td",{className:"num",children:L(s.ctxWindows)}),e.jsx("td",{className:"num",children:L(s.maxTokens)}),e.jsx("td",{className:"num",children:l}),e.jsx("td",{className:"num",children:s.sessions.toLocaleString()}),e.jsx("td",{className:"num",children:s.checkpoints.toLocaleString()}),e.jsx("td",{className:"num",children:M(s.inRates)}),e.jsx("td",{className:"num",children:M(s.outRates)}),e.jsx("td",{className:"num",children:a}),e.jsx("td",{className:"num",children:s.cacheRead>0?`${(s.cacheRead*100/(s.cacheRead+s.cacheWrite+s.tokensIn||1)).toFixed(1)}%`:"—"}),e.jsx("td",{className:"num",children:s.cacheRead>0?`$${A(s.cacheRead,s.cacheWrite,s.inRates[0]||0).netSaved.toFixed(4)}`:"—"}),e.jsx("td",{className:"num",children:c})]},s.model)})]})]})}),e.jsx("p",{className:"legend-note",children:"Tokens In = Σ original region tokens dropped by compaction. Tokens Out = Σ compacted summary tokens still retained in context. Freed = Tokens In − Tokens Out (net context reclaimed). Ctx Window / Max Out / Reas. come from the latest captured model snapshot for each repo."})]})}async function G(){return await W()}function Y(){const[t,n]=d.useState(null),{data:s,error:r}=y(d.useCallback(()=>G(),[]),{pollInterval:1e4}),{data:a}=y(d.useCallback(()=>F(),[]),{pollInterval:1e4});if(r&&!s)return e.jsxs("div",{className:"tab-stub",children:["Error loading repos: ",r.message]});if(!s)return e.jsx("div",{className:"tab-stub",children:"Loading repos…"});const c=s.summary,l=s.repos,j=a?.servers??[];return l.length===0?e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx(R,{totalRepos:0,totalCheckpoints:0,totalTokensSaved:0,compressedOriginalBytes:0}),e.jsxs("div",{className:"tab-stub",children:[e.jsx("h3",{children:"Repositories / Memory"}),e.jsx("p",{children:"Repo memory appears after the first compaction. Compaction fires when context crosses the tier threshold (~50-70% of the window). Run a longer session or lower the compaction tier to see it sooner."})]})]}):e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx(R,{totalRepos:c?.totalRepos??0,totalCheckpoints:c?.totalCheckpoints??0,totalTokensSaved:c?.totalTokensSaved??0,compressedOriginalBytes:c?.totalCompressedOriginalBytes??0}),e.jsx("h2",{className:"font-heading text-lg font-semibold",children:"All Repositories"}),e.jsx(K,{repos:l,onSelect:n}),e.jsx("h2",{className:"font-heading text-lg font-semibold",children:"Active Repos — Live Cache Hits & Compactions"}),e.jsx(q,{servers:j}),e.jsx("h2",{className:"font-heading text-lg font-semibold",children:"Savings by Model"}),e.jsx(_,{repos:l}),t&&e.jsx(U,{repo:t,onClose:()=>n(null)})]})}export{Y as default};
|
|
2
|
+
//# sourceMappingURL=ReposTab-BSRWhn56.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReposTab-BSRWhn56.js","sources":["../../src/components/SummaryTiles.tsx","../../src/components/RepoTable.tsx","../../src/components/RepoDetailModal.tsx","../../src/components/ActiveReposTable.tsx","../../src/components/SavingsByModelTable.tsx","../../src/tabs/ReposTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/components/SummaryTiles.tsx — aggregate header tiles.\n *\n * 4 tiles: Repositories, Total Checkpoints, Total Tokens Saved,\n * Compressed-Original. Matches old dashboard #panel-summary tiles.\n */\n\nimport type React from \"react\";\nimport { Card, CardContent } from \"../components/ui/card\";\n\nexport interface SummaryTilesProps {\n\t/** Total repos in the registry. */\n\ttotalRepos: number;\n\t/** Total checkpoints across all repos. */\n\ttotalCheckpoints: number;\n\t/** Total tokens saved across all repos. */\n\ttotalTokensSaved: number;\n\t/** Total compressed-original bytes across all repos. */\n\tcompressedOriginalBytes: number;\n}\n\n/** Format bytes → MiB/KiB/B (matches html.ts fmtBytesTop). */\nfunction fmtBytesTop(b: number): string {\n\tif (b >= 1_048_576) return `${(b / 1_048_576).toFixed(1)} MiB`;\n\tif (b >= 1024) return `${(b / 1024).toFixed(1)} KiB`;\n\treturn `${b} B`;\n}\n\n/** Format large numbers with K/M suffix. */\nfunction fmt(n: number): string {\n\tif (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n\tif (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n\treturn String(n);\n}\n\nexport function SummaryTiles({\n\ttotalRepos,\n\ttotalCheckpoints,\n\ttotalTokensSaved,\n\tcompressedOriginalBytes,\n}: SummaryTilesProps): React.ReactElement {\n\treturn (\n\t\t<div className=\"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-4\">\n\t\t\t<Card className=\"electric-hover\">\n\t\t\t\t<CardContent>\n\t\t\t\t\t<span className=\"tile-label\">Repositories</span>\n\t\t\t\t\t<div className=\"text-xl font-semibold\">{totalRepos.toLocaleString()}</div>\n\t\t\t\t</CardContent>\n\t\t\t</Card>\n\t\t\t<Card className=\"electric-hover\">\n\t\t\t\t<CardContent>\n\t\t\t\t\t<span className=\"tile-label\">Total Checkpoints</span>\n\t\t\t\t\t<div className=\"text-xl font-semibold\">{totalCheckpoints.toLocaleString()}</div>\n\t\t\t\t</CardContent>\n\t\t\t</Card>\n\t\t\t<Card className=\"electric-hover\">\n\t\t\t\t<CardContent>\n\t\t\t\t\t<span className=\"tile-label\">Total Tokens Saved</span>\n\t\t\t\t\t<div className=\"text-xl font-semibold\">{fmt(totalTokensSaved)}</div>\n\t\t\t\t</CardContent>\n\t\t\t</Card>\n\t\t\t<Card className=\"electric-hover\">\n\t\t\t\t<CardContent>\n\t\t\t\t\t<span className=\"tile-label\">Compressed-Original</span>\n\t\t\t\t\t<div className=\"text-xl font-semibold\">{fmtBytesTop(compressedOriginalBytes)}</div>\n\t\t\t\t</CardContent>\n\t\t\t</Card>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/components/RepoTable.tsx — sortable, searchable repo table.\n *\n * 6 columns: Repo, Model, Checkpoints, Tokens Saved, Retained, Last Compacted.\n * Client-side sort (click header to toggle asc/desc). Search by displayName\n * (case-insensitive substring). Default sort: Last Compacted DESC.\n * Row click opens RepoDetailModal.\n */\n\nimport type React from \"react\";\nimport { useState, useMemo } from \"react\";\nimport type { IndexesIndexRow } from \"@contracts\";\nimport { Card, CardContent } from \"../components/ui/card\";\n\nexport interface RepoTableProps {\n\trepos: IndexesIndexRow[];\n\t/** Called when a row is clicked — opens the detail modal. */\n\tonSelect: (repo: IndexesIndexRow) => void;\n}\n\ntype SortKey =\n\t| \"displayName\"\n\t| \"modelName\"\n\t| \"checkpointCount\"\n\t| \"tokensSaved\"\n\t| \"compressedOriginalBytes\"\n\t| \"lastCompactedAt\";\n\ntype SortDir = \"asc\" | \"desc\";\n\nconst COLUMNS: Array<{ key: SortKey; label: string }> = [\n\t{ key: \"displayName\", label: \"Repo\" },\n\t{ key: \"modelName\", label: \"Model\" },\n\t{ key: \"checkpointCount\", label: \"Checkpoints\" },\n\t{ key: \"tokensSaved\", label: \"Tokens Saved\" },\n\t{ key: \"compressedOriginalBytes\", label: \"Retained\" },\n\t{ key: \"lastCompactedAt\", label: \"Last Compacted\" },\n];\n\n/** Format bytes → MiB/KiB/B (matches html.ts fmtBytesTop). */\nfunction fmtBytesTop(b: number): string {\n\tif (b >= 1_048_576) return `${(b / 1_048_576).toFixed(1)} MiB`;\n\tif (b >= 1024) return `${(b / 1024).toFixed(1)} KiB`;\n\treturn `${b} B`;\n}\n\nfunction formatTs(ts: number | null): string {\n\tif (ts === null || ts === undefined) return \"\\u2014\";\n\ttry {\n\t\treturn new Date(ts).toLocaleString();\n\t} catch {\n\t\treturn String(ts);\n\t}\n}\n\nexport function RepoTable({\n\trepos,\n\tonSelect,\n}: RepoTableProps): React.ReactElement {\n\tconst [search, setSearch] = useState(\"\");\n\tconst [sortKey, setSortKey] = useState<SortKey>(\"lastCompactedAt\");\n\tconst [sortDir, setSortDir] = useState<SortDir>(\"desc\");\n\n\tconst filtered = useMemo(() => {\n\t\tconst q = search.trim().toLowerCase();\n\t\tconst list = q\n\t\t\t? repos.filter((r) => r.displayName.toLowerCase().includes(q))\n\t\t\t: repos.slice();\n\t\tlist.sort((a, b) => {\n\t\t\tconst av = a[sortKey];\n\t\t\tconst bv = b[sortKey];\n\t\t\t// nulls last on desc, first on asc (consistent UX)\n\t\t\tconst aNull = av === null || av === undefined;\n\t\t\tconst bNull = bv === null || bv === undefined;\n\t\t\tif (aNull && bNull) return 0;\n\t\t\tif (aNull) return sortDir === \"desc\" ? 1 : -1;\n\t\t\tif (bNull) return sortDir === \"desc\" ? -1 : 1;\n\t\t\tconst cmp =\n\t\t\t\ttypeof av === \"number\" && typeof bv === \"number\"\n\t\t\t\t\t? av - bv\n\t\t\t\t\t: String(av).localeCompare(String(bv));\n\t\t\treturn sortDir === \"desc\" ? -cmp : cmp;\n\t\t});\n\t\treturn list;\n\t}, [repos, search, sortKey, sortDir]);\n\n\tconst handleSort = (key: SortKey): void => {\n\t\tif (sortKey === key) {\n\t\t\tsetSortDir((d) => (d === \"asc\" ? \"desc\" : \"asc\"));\n\t\t} else {\n\t\t\tsetSortKey(key);\n\t\t\tsetSortDir(\n\t\t\t\tkey === \"lastCompactedAt\" ||\n\t\t\t\tkey === \"tokensSaved\" ||\n\t\t\t\tkey === \"compressedOriginalBytes\"\n\t\t\t\t\t? \"desc\"\n\t\t\t\t\t: \"asc\",\n\t\t\t);\n\t\t}\n\t};\n\n\treturn (\n\t\t<Card>\n\t\t\t<CardContent>\n\t\t\t<input\n\t\t\t\ttype=\"search\"\n\t\t\t\tclassName=\"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\"\n\t\t\t\tplaceholder=\"Search repos…\"\n\t\t\t\tvalue={search}\n\t\t\t\tonChange={(e) => setSearch(e.target.value)}\n\t\t\t\taria-label=\"Search repos\"\n\t\t\t/>\n\t\t\t<div className=\"overflow-x-auto\">\n\t\t\t<table className=\"w-full border-collapse text-sm\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t{COLUMNS.map((col) => (\n\t\t\t\t\t\t\t<th key={col.key} className=\"border-b border-border px-3 py-2 text-left\">\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tclassName={`font-medium text-muted-foreground transition-colors hover:text-foreground ${\n\t\t\t\t\t\t\t\t\t\tsortKey === col.key ? \"text-neon\" : \"\"\n\t\t\t\t\t\t\t\t\t}`}\n\t\t\t\t\t\t\t\t\tonClick={() => handleSort(col.key)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{col.label}\n\t\t\t\t\t\t\t\t\t{sortKey === col.key && (\n\t\t\t\t\t\t\t\t\t\t<span>{sortDir === \"asc\" ? \" ▲\" : \" ▼\"}</span>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t{filtered.length === 0 && (\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td colSpan={COLUMNS.length} className=\"px-3 py-4 text-muted-foreground\">\n\t\t\t\t\t\t\t\t{repos.length === 0\n\t\t\t\t\t\t\t\t\t? \"No repositories registered yet.\"\n\t\t\t\t\t\t\t\t\t: \"No repos match your search.\"}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t)}\n\t\t\t\t\t{filtered.map((repo) => (\n\t\t\t\t\t\t<tr\n\t\t\t\t\t\t\tkey={repo.stateDir}\n\t\t\t\t\t\t\tonClick={() => onSelect(repo)}\n\t\t\t\t\t\t\tclassName=\"cursor-pointer border-b border-border/50 transition-colors hover:bg-bg-elevated/40\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<td className=\"px-3 py-2 font-medium\" title={repo.repoRoot}>\n\t\t\t\t\t\t\t\t{repo.displayName}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td className=\"px-3 py-2 text-muted-foreground\">{repo.modelName ?? \"\\u2014\"}</td>\n\t\t\t\t\t\t\t<td className=\"px-3 py-2 text-right\">{repo.checkpointCount.toLocaleString()}</td>\n\t\t\t\t\t\t\t<td className=\"px-3 py-2 text-right\">{repo.tokensSaved.toLocaleString()}</td>\n\t\t\t\t\t\t\t<td className=\"px-3 py-2 text-right\">{fmtBytesTop(repo.compressedOriginalBytes)}</td>\n\t\t\t\t\t\t\t<td className=\"px-3 py-2 text-right\">{formatTs(repo.lastCompactedAt)}</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t))}\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t\t</div>\n\t\t\t</CardContent>\n\t\t</Card>\n\t);\n}\n","/**\n * dashboard-client/src/components/RepoDetailModal.tsx — repo drill-down.\n *\n * Full detail from an /api/index row: token breakdown (kept/dropped), model\n * info, context window, dedup rate, reasoning flag. Click backdrop to close.\n */\n\nimport type React from \"react\";\nimport { useEffect } from \"react\";\nimport type { IndexesIndexRow } from \"@contracts\";\n\nexport interface RepoDetailModalProps {\n\trepo: IndexesIndexRow;\n\tonClose: () => void;\n}\n\nfunction fmt(n: number): string {\n\tif (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n\tif (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n\treturn String(n);\n}\n\n/** Format bytes → MiB/KiB/B (matches html.ts fmtBytesTop). */\nfunction fmtBytesTop(b: number): string {\n\tif (b >= 1_048_576) return `${(b / 1_048_576).toFixed(1)} MiB`;\n\tif (b >= 1024) return `${(b / 1024).toFixed(1)} KiB`;\n\treturn `${b} B`;\n}\n\nfunction formatTs(ts: number | null): string {\n\tif (ts === null || ts === undefined) return \"never\";\n\ttry {\n\t\treturn new Date(ts).toLocaleString();\n\t} catch {\n\t\treturn String(ts);\n\t}\n}\n\nexport function RepoDetailModal({\n\trepo,\n\tonClose,\n}: RepoDetailModalProps): React.ReactElement {\n\t// Close on Escape key.\n\tuseEffect(() => {\n\t\tconst handler = (e: KeyboardEvent): void => {\n\t\t\tif (e.key === \"Escape\") onClose();\n\t\t};\n\t\twindow.addEventListener(\"keydown\", handler);\n\t\treturn () => window.removeEventListener(\"keydown\", handler);\n\t}, [onClose]);\n\n\treturn (\n\t\t<div\n\t\t\tclassName=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4\"\n\t\t\tonClick={onClose}\n\t\t\trole=\"dialog\"\n\t\t\taria-modal=\"true\"\n\t\t>\n\t\t\t<div\n\t\t\t\tclassName=\"max-h-[85vh] w-full max-w-xl overflow-y-auto rounded-xl border border-border bg-bg-card p-5 shadow-panel\"\n\t\t\t\tonClick={(e) => e.stopPropagation()}\n\t\t\t>\n\t\t\t\t<header className=\"mb-2 flex items-start justify-between gap-4\">\n\t\t\t\t\t<h2 className=\"font-heading text-lg font-semibold\">{repo.displayName}</h2>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"text-2xl leading-none text-muted-foreground hover:text-foreground\"\n\t\t\t\t\t\tonClick={onClose}\n\t\t\t\t\t\taria-label=\"Close\"\n\t\t\t\t\t>\n\t\t\t\t\t\t×\n\t\t\t\t\t</button>\n\t\t\t\t</header>\n\t\t\t\t<p className=\"mb-4 break-all font-mono text-xs text-muted-foreground\">{repo.repoRoot}</p>\n\t\t\t\t<div className=\"mb-4 grid grid-cols-2 gap-3 sm:grid-cols-3\">\n\t\t\t\t\t<div className=\"rounded-md border border-border/50 bg-bg-elevated/40 p-3\">\n\t\t\t\t\t\t<span className=\"block text-xs text-muted-foreground\">Checkpoints</span>\n\t\t\t\t\t\t<span className=\"text-xl font-semibold\">\n\t\t\t\t\t\t\t{repo.checkpointCount.toLocaleString()}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"rounded-md border border-border/50 bg-bg-elevated/40 p-3\">\n\t\t\t\t\t\t<span className=\"block text-xs text-muted-foreground\">Sessions</span>\n\t\t\t\t\t\t<span className=\"text-xl font-semibold\">\n\t\t\t\t\t\t\t{repo.sessions.toLocaleString()}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"rounded-md border border-border/50 bg-primary/10 p-3\">\n\t\t\t\t\t\t<span className=\"block text-xs text-muted-foreground\">Tokens saved</span>\n\t\t\t\t\t\t<span className=\"text-xl font-semibold\">{fmt(repo.tokensSaved)}</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"rounded-md border border-border/50 bg-bg-elevated/40 p-3\">\n\t\t\t\t\t\t<span className=\"block text-xs text-muted-foreground\">Tokens kept</span>\n\t\t\t\t\t\t<span className=\"text-xl font-semibold\">{fmt(repo.tokensKept)}</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"rounded-md border border-border/50 bg-bg-elevated/40 p-3\">\n\t\t\t\t\t\t<span className=\"block text-xs text-muted-foreground\">Tokens dropped</span>\n\t\t\t\t\t\t<span className=\"text-xl font-semibold\">{fmt(repo.tokensDropped)}</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"rounded-md border border-border/50 bg-bg-elevated/40 p-3\">\n\t\t\t\t\t\t<span className=\"block text-xs text-muted-foreground\">Dedup rate</span>\n\t\t\t\t\t\t<span className=\"text-xl font-semibold\">—</span>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold\">Model</h3>\n\t\t\t\t<dl className=\"mb-4 grid grid-cols-1 gap-1 text-sm sm:grid-cols-2\">\n\t\t\t\t\t<dt className=\"text-muted-foreground\">Provider</dt>\n\t\t\t\t\t<dd className=\"text-right\">{repo.providerName ?? \"—\"}</dd>\n\t\t\t\t\t<dt className=\"text-muted-foreground\">Model</dt>\n\t\t\t\t\t<dd className=\"text-right\">{repo.modelName ?? \"—\"}</dd>\n\t\t\t\t\t<dt className=\"text-muted-foreground\">Input rate</dt>\n\t\t\t\t\t<dd className=\"text-right\">{repo.inputRate !== null ? `${repo.inputRate} tok/s` : \"—\"}</dd>\n\t\t\t\t\t<dt className=\"text-muted-foreground\">Output rate</dt>\n\t\t\t\t\t<dd className=\"text-right\">{repo.outputRate !== null ? `${repo.outputRate} tok/s` : \"—\"}</dd>\n\t\t\t\t\t<dt className=\"text-muted-foreground\">Context window</dt>\n\t\t\t\t\t<dd className=\"text-right\">{repo.contextWindow !== null ? fmt(repo.contextWindow) : \"—\"}</dd>\n\t\t\t\t\t<dt className=\"text-muted-foreground\">Max tokens</dt>\n\t\t\t\t\t<dd className=\"text-right\">{repo.maxTokens !== null ? fmt(repo.maxTokens) : \"—\"}</dd>\n\t\t\t\t\t<dt className=\"text-muted-foreground\">Reasoning</dt>\n\t\t\t\t\t<dd className=\"text-right\">\n\t\t\t\t\t\t{repo.reasoning === null ? \"—\" : repo.reasoning ? \"on\" : \"off\"}\n\t\t\t\t\t</dd>\n\t\t\t\t</dl>\n\t\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold\">Activity</h3>\n\t\t\t\t<dl className=\"grid grid-cols-1 gap-1 text-sm sm:grid-cols-2\">\n\t\t\t\t\t<dt className=\"text-muted-foreground\">Last compacted</dt>\n\t\t\t\t\t<dd className=\"text-right\">{formatTs(repo.lastCompactedAt)}</dd>\n\t\t\t\t\t<dt className=\"text-muted-foreground\">Last seen</dt>\n\t\t\t\t\t<dd className=\"text-right\">{formatTs(repo.lastSeen)}</dd>\n\t\t\t\t\t<dt className=\"text-muted-foreground\">Compressed-Original</dt>\n\t\t\t\t\t<dd className=\"text-right\">{fmtBytesTop(repo.compressedOriginalBytes)}</dd>\n\t\t\t\t</dl>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/components/ActiveReposTable.tsx — Active repos table.\n *\n * Columns: Repo, Model, Tier, Context %, State, Compactions s/t,\n * Cache Hits s/t, Cache Hit %, Cache Read, Cache Write, Est. Saved,\n * Compact s/t (s), CacheHit s/t (s).\n * Data from fetchServers() via useApi with 10s polling.\n */\n\nimport type React from \"react\";\nimport type { ServerEntry } from \"@contracts\";\nimport { fmtTokens } from \"@/utils/format.ts\";\nimport { Card, CardContent } from \"../components/ui/card\";\n\nexport interface ActiveReposTableProps {\n\tservers: ServerEntry[];\n}\n\n/** Format seconds → human-readable duration (matches html.ts fmtSec). */\nfunction fmtSec(s: number | undefined): string {\n\tconst v = s ?? 0;\n\tif (v >= 3600) return `${(v / 3600).toFixed(1)}h`;\n\tif (v >= 60) return `${Math.round(v / 60)}m`;\n\tif (v >= 1) return `${v.toFixed(1)}s`;\n\treturn `${Math.round(v * 1000)}ms`;\n}\n\nconst HEADERS = [\n\t\"Repo\",\n\t\"Model\",\n\t\"Tier\",\n\t\"Context %\",\n\t\"State\",\n\t\"Compactions (s/t)\",\n\t\"Cache Hits (s/t)\",\n\t\"Cache Hit %\",\n\t\"Est. Saved\",\n\t\"Cache Read\",\n\t\"Cache Write\",\n\t\"Compact s/t (s)\",\n\t\"CacheHit s/t (s)\",\n] as const;\n\nexport function ActiveReposTable({\n\tservers,\n}: ActiveReposTableProps): React.ReactElement {\n\treturn (\n\t\t<Card>\n\t\t\t<CardContent>\n\t\t\t<p className=\"mb-3 text-xs text-muted-foreground\">\n\t\t\t\tRepos seen within the last 30 minutes, with their per-repo cache-hit,\n\t\t\t\tcompaction, and time-saved (est.) totals pulled live from each\n\t\t\t\trepo's dashboard.json.\n\t\t\t</p>\n\t\t\t<div className=\"overflow-x-auto\">\n\t\t\t\t<table className=\"w-full border-collapse text-sm\">\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t{HEADERS.map((h, i) => (\n\t\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\t\tkey={h}\n\t\t\t\t\t\t\t\t\tclassName={`border-b border-border px-3 py-2 text-left font-medium text-muted-foreground${\n\t\t\t\t\t\t\t\t\t\ti >= 3 && i !== 4 ? \" text-right\" : \"\"\n\t\t\t\t\t\t\t\t\t}`}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{h}\n\t\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</thead>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t{servers.length === 0 && (\n\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t<td colSpan={HEADERS.length} className=\"px-3 py-4 text-muted-foreground\">\n\t\t\t\t\t\t\t\t\tNo active repositories.\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t{servers.map((r) => {\n\t\t\t\t\t\t\tconst ch = r.cacheHits ?? {\n\t\t\t\t\t\t\t\tsession: 0,\n\t\t\t\t\t\t\t\ttotal: 0,\n\t\t\t\t\t\t\t\tsessionTokensSaved: 0,\n\t\t\t\t\t\t\t\ttotalTokensSaved: 0,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tconst cp = r.compacts ?? { session: 0, total: 0 };\n\t\t\t\t\t\t\tconst ts = r.timeSaved ?? {\n\t\t\t\t\t\t\t\tcompact: { sessionSec: 0, totalSec: 0 },\n\t\t\t\t\t\t\t\tcacheHit: { sessionSec: 0, totalSec: 0 },\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<tr key={r.repoRoot}>\n\t\t\t\t\t\t\t\t\t<td title={r.repoRoot}>{r.displayName || r.repoRoot}</td>\n\t\t\t\t\t\t\t\t\t<td>{r.model ?? \"\\u2014\"}</td>\n\t\t\t\t\t\t\t\t\t<td>{r.tier ?? \"\\u2014\"}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t\t\t\t{r.contextPct != null\n\t\t\t\t\t\t\t\t\t\t\t? `${Math.round(r.contextPct * 100)}%`\n\t\t\t\t\t\t\t\t\t\t\t: \"\\u2014\"}\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td>{r.state ?? \"\\u2014\"}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t\t\t\t{cp.session} / {cp.total}\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t\t\t\t{ch.session} / {ch.total}\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t\t\t\t{r.providerCache != null\n\t\t\t\t\t\t\t\t\t\t\t? `${r.providerCache.avgHitPct.toFixed(1)}%`\n\t\t\t\t\t\t\t\t\t\t\t: \"—\"}\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t\t\t\t{r.providerCache?.estimatedSaved != null\n\t\t\t\t\t\t\t\t\t\t\t? `$${r.providerCache.estimatedSaved.toFixed(2)}`\n\t\t\t\t\t\t\t\t\t\t\t: \"—\"}\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t\t\t\t{r.providerCache?.cacheRead != null\n\t\t\t\t\t\t\t\t\t\t\t? fmtTokens(r.providerCache.cacheRead)\n\t\t\t\t\t\t\t\t\t\t\t: \"—\"}\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t\t\t\t{r.providerCache?.cacheWrite != null\n\t\t\t\t\t\t\t\t\t\t\t? fmtTokens(r.providerCache.cacheWrite)\n\t\t\t\t\t\t\t\t\t\t\t: \"—\"}\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t\t\t\t{fmtSec(ts.compact.sessionSec)} /{\" \"}\n\t\t\t\t\t\t\t\t\t\t{fmtSec(ts.compact.totalSec)}\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t\t\t\t{fmtSec(ts.cacheHit.sessionSec)} /{\" \"}\n\t\t\t\t\t\t\t\t\t\t{fmtSec(ts.cacheHit.totalSec)}\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</tbody>\n\t\t\t\t</table>\n\t\t\t</div>\n\t\t\t</CardContent>\n\t\t</Card>\n\t);\n}\n","/**\n * dashboard-client/src/components/SavingsByModelTable.tsx — Savings by Model.\n *\n * 14 columns aggregated client-side from /api/index repos by model.\n * Replicates html.ts renderByModel logic: group by modelName, accumulate\n * tokens/cost/sessions, collapse numeric ranges when repos disagree.\n */\n\nimport type React from \"react\";\nimport { useMemo } from \"react\";\nimport type { IndexesIndexRow } from \"@contracts\";\nimport { computeCacheSavings } from \"@pricing\";\n\nexport interface SavingsByModelTableProps {\n\trepos: IndexesIndexRow[];\n}\n\ninterface ModelGroup {\n\tmodel: string;\n\tprovider: string;\n\tcheckpoints: number;\n\ttokensSaved: number;\n\ttokensIn: number;\n\ttokensOut: number;\n\tsessions: number;\n\tusd: number;\n\tinRates: number[];\n\toutRates: number[];\n\tctxWindows: number[];\n\tmaxTokens: number[];\n\treasoning: boolean | null;\n\tlastAt: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n}\n\n/** Collapse numeric samples: \"—\" | single | \"lo–hi\" (matches html.ts). */\nfunction collapseNum(samples: number[]): string {\n\tif (!samples.length) return \"\\u2014\";\n\tconst lo = Math.min(...samples);\n\tconst hi = Math.max(...samples);\n\treturn lo === hi\n\t\t? lo.toLocaleString()\n\t\t: `${lo.toLocaleString()}\\u2013${hi.toLocaleString()}`;\n}\n\n/** Collapse rate samples: \"—\" | \"$rate\" | \"$lo–$hi\" (matches html.ts). */\nfunction collapseRate(samples: number[]): string {\n\tif (!samples.length) return \"\\u2014\";\n\tconst lo = Math.min(...samples);\n\tconst hi = Math.max(...samples);\n\tconst fmt = (v: number): string => `$${v.toFixed(6)}`;\n\treturn lo === hi ? fmt(lo) : `${fmt(lo)}\\u2013${fmt(hi)}`;\n}\n\n/** Group repos by model, accumulate totals, sort by tokensSaved desc. */\nfunction aggregate(repos: IndexesIndexRow[]): ModelGroup[] {\n\tconst map: Record<string, ModelGroup> = {};\n\tfor (const r of repos) {\n\t\tconst key = (r.modelName && r.modelName.trim()) || \"(unknown)\";\n\t\tif (!map[key]) {\n\t\t\tmap[key] = {\n\t\t\t\tmodel: key,\n\t\t\t\tprovider: r.providerName ?? r.provider ?? \"\\u2014\",\n\t\t\t\tcheckpoints: 0,\n\t\t\t\ttokensSaved: 0,\n\t\t\t\ttokensIn: 0,\n\t\t\t\ttokensOut: 0,\n\t\t\t\tsessions: 0,\n\t\t\t\tusd: 0,\n\t\t\t\tinRates: [],\n\t\t\t\toutRates: [],\n\t\t\t\tctxWindows: [],\n\t\t\t\tmaxTokens: [],\n\t\t\t\treasoning: null,\n\t\t\t\tlastAt: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t};\n\t\t}\n\t\tconst g = map[key];\n\t\tg.checkpoints += r.checkpointCount || 0;\n\t\tg.tokensSaved += r.tokensSaved || 0;\n\t\tg.tokensIn += r.tokensDropped || 0;\n\t\tg.tokensOut += r.tokensKept || 0;\n\t\tg.sessions += r.sessions || 0;\n\t\tif (r.inputRate) {\n\t\t\tg.usd += (r.tokensSaved || 0) * r.inputRate;\n\t\t\tg.inRates.push(r.inputRate);\n\t\t}\n\t\tif (r.outputRate) g.outRates.push(r.outputRate);\n\t\tif (r.contextWindow) g.ctxWindows.push(r.contextWindow);\n\t\tif (r.maxTokens) g.maxTokens.push(r.maxTokens);\n\t\tif (r.reasoning != null) g.reasoning = r.reasoning;\n\t\tif (r.providerCacheRead) g.cacheRead += r.providerCacheRead;\n\t\tif (r.providerCacheWrite) g.cacheWrite += r.providerCacheWrite;\n\t\tif (r.lastCompactedAt && r.lastCompactedAt > g.lastAt)\n\t\t\tg.lastAt = r.lastCompactedAt;\n\t}\n\treturn Object.values(map).sort((a, b) => b.tokensSaved - a.tokensSaved);\n}\n\n/** Tooltip text copied verbatim from html.ts title attributes. */\nconst TOOLTIPS = {\n\ttokensIn: \"Tokens dropped from context by compaction (the input reclaimed)\",\n\ttokensOut:\n\t\t\"Tokens kept as compacted summaries still in context (the output retained)\",\n\tctxWindow: \"Model context window (max input tokens the model accepts)\",\n\tmaxOut: \"Model max output tokens per turn\",\n\treas: \"Reasoning-capable model\",\n\tsessions: \"Distinct sessions with at least one checkpoint\",\n\tinRate: \"USD per input token\",\n\toutRate: \"USD per output token\",\n} as const;\n\nexport function SavingsByModelTable({\n\trepos,\n}: SavingsByModelTableProps): React.ReactElement {\n\tconst groups = useMemo(() => aggregate(repos), [repos]);\n\n\treturn (\n\t\t<div className=\"savings-by-model\">\n\t\t\t<p className=\"legend-note\">\n\t\t\t\tHow much context & cost mega-compact has reclaimed, grouped by the\n\t\t\t\tmodel you were running. Compression ratio reflects workload/content, not\n\t\t\t\tmodel quality.\n\t\t\t</p>\n\t\t\t<div className=\"table-scroll\">\n\t\t\t\t<table className=\"savings-table\">\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<th>Model</th>\n\t\t\t\t\t\t\t<th>Provider</th>\n\t\t\t\t\t\t\t<th className=\"num\" title={TOOLTIPS.tokensIn}>\n\t\t\t\t\t\t\t\tTokens In\n\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t<th className=\"num\" title={TOOLTIPS.tokensOut}>\n\t\t\t\t\t\t\t\tTokens Out\n\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t<th className=\"num\">Freed</th>\n\t\t\t\t\t\t\t<th className=\"num\" title={TOOLTIPS.ctxWindow}>\n\t\t\t\t\t\t\t\tCtx Window\n\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t<th className=\"num\" title={TOOLTIPS.maxOut}>\n\t\t\t\t\t\t\t\tMax Out\n\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t<th className=\"num\" title={TOOLTIPS.reas}>\n\t\t\t\t\t\t\t\tReas.\n\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t<th className=\"num\" title={TOOLTIPS.sessions}>\n\t\t\t\t\t\t\t\tSessions\n\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t<th className=\"num\">Checkpoints</th>\n\t\t\t\t\t\t\t<th className=\"num\" title={TOOLTIPS.inRate}>\n\t\t\t\t\t\t\t\tIn $/tok\n\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t<th className=\"num\" title={TOOLTIPS.outRate}>\n\t\t\t\t\t\t\t\tOut $/tok\n\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t<th className=\"num\">$ Saved</th>\n\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\tclassName=\"num\"\n\t\t\t\t\t\t\t\ttitle=\"Provider prompt-cache hit rate (reads / reads+writes+tokens_in)\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tCache Hit %\n\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t<th\n\t\t\t\t\t\t\t\tclassName=\"num\"\n\t\t\t\t\t\t\t\ttitle=\"Estimated provider prompt-cache savings (read tokens * 0.9 * inputRate − write tokens * 0.25 * inputRate)\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tCache $ Saved\n\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t<th className=\"num\">Last Used</th>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</thead>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t{groups.length === 0 && (\n\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t<td colSpan={16} className=\"repo-empty\">\n\t\t\t\t\t\t\t\t\tNo repositories registered yet.\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t{groups.map((g) => {\n\t\t\t\t\t\t\tconst freed = (g.tokensIn || 0) - (g.tokensOut || 0);\n\t\t\t\t\t\t\tconst usd = g.usd > 0 ? `$${g.usd.toFixed(4)}` : \"\\u2014\";\n\t\t\t\t\t\t\tconst when = g.lastAt\n\t\t\t\t\t\t\t\t? new Date(g.lastAt).toLocaleString()\n\t\t\t\t\t\t\t\t: \"\\u2014\";\n\t\t\t\t\t\t\tconst reas =\n\t\t\t\t\t\t\t\tg.reasoning == null ? \"\\u2014\" : g.reasoning ? \"yes\" : \"no\";\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<tr key={g.model}>\n\t\t\t\t\t\t\t\t\t<td className=\"repo-model\">{g.model}</td>\n\t\t\t\t\t\t\t\t\t<td>{g.provider}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">{g.tokensIn.toLocaleString()}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">{g.tokensOut.toLocaleString()}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">{freed.toLocaleString()}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">{collapseNum(g.ctxWindows)}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">{collapseNum(g.maxTokens)}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">{reas}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">{g.sessions.toLocaleString()}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">{g.checkpoints.toLocaleString()}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">{collapseRate(g.inRates)}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">{collapseRate(g.outRates)}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">{usd}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t\t\t\t{g.cacheRead > 0\n\t\t\t\t\t\t\t\t\t\t\t? `${(\n\t\t\t\t\t\t\t\t\t\t\t\t\t(g.cacheRead * 100) /\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t(g.cacheRead + g.cacheWrite + g.tokensIn || 1)\n\t\t\t\t\t\t\t\t\t\t\t\t).toFixed(1)}%`\n\t\t\t\t\t\t\t\t\t\t\t: \"—\"}\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t\t\t\t{g.cacheRead > 0\n\t\t\t\t\t\t\t\t\t\t\t? `$${computeCacheSavings(g.cacheRead, g.cacheWrite, g.inRates[0] || 0).netSaved.toFixed(4)}`\n\t\t\t\t\t\t\t\t\t\t\t: \"—\"}\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td className=\"num\">{when}</td>\n\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</tbody>\n\t\t\t\t</table>\n\t\t\t</div>\n\t\t\t<p className=\"legend-note\">\n\t\t\t\tTokens In = Σ original region tokens dropped by compaction. Tokens Out =\n\t\t\t\tΣ compacted summary tokens still retained in context. Freed = Tokens In\n\t\t\t\t− Tokens Out (net context reclaimed). Ctx Window / Max Out / Reas. come\n\t\t\t\tfrom the latest captured model snapshot for each repo.\n\t\t\t</p>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/ReposTab.tsx — Repos tab (C2 fleshed out).\n *\n * Renders: SummaryTiles (4 tiles), All Repositories table (RepoTable),\n * Active Repos table (ActiveReposTable), Savings by Model table\n * (SavingsByModelTable), and per-repo detail modal (RepoDetailModal).\n *\n * Data sources: fetchIndex() for summary + all repos + savings-by-model;\n * fetchServers() for active repos. Both polled every 10s.\n */\n\nimport type React from \"react\";\nimport { useCallback, useState } from \"react\";\nimport { useApi } from \"../hooks/useApi\";\nimport { fetchIndex, fetchServers } from \"../api/client\";\nimport type { IndexesIndexRow, ServersResponse } from \"@contracts\";\nimport { SummaryTiles } from \"../components/SummaryTiles\";\nimport { RepoTable } from \"../components/RepoTable\";\nimport { RepoDetailModal } from \"../components/RepoDetailModal\";\nimport { ActiveReposTable } from \"../components/ActiveReposTable\";\nimport { SavingsByModelTable } from \"../components/SavingsByModelTable\";\n\n/**\n * Actual runtime shape of /api/index. The contract's IndexesSummaryResponse\n * puts summary fields at the top level, but the real server nests them under\n * `summary` (matching IndexFallbackResponse shape with non-null summary).\n */\ninterface DashboardIndexSummary {\n\ttotalRepos: number;\n\ttotalCheckpoints: number;\n\ttotalTokensSaved: number;\n\ttotalCompressedOriginalBytes: number;\n}\n\ninterface DashboardIndexResponse {\n\tupdatedAt: string | null;\n\tsummary: DashboardIndexSummary | null;\n\trepos: IndexesIndexRow[];\n}\n\n/** Fetch /api/index and cast to the actual runtime shape. */\nasync function fetchIndexTyped(): Promise<DashboardIndexResponse> {\n\treturn (await fetchIndex()) as unknown as DashboardIndexResponse;\n}\n\nexport default function ReposTab(): React.ReactElement {\n\tconst [selected, setSelected] = useState<IndexesIndexRow | null>(null);\n\n\tconst { data: indexData, error: indexErr } =\n\t\tuseApi<DashboardIndexResponse>(\n\t\t\tuseCallback(() => fetchIndexTyped(), []),\n\t\t\t{ pollInterval: 10_000 },\n\t\t);\n\n\tconst { data: serversData } = useApi<ServersResponse>(\n\t\tuseCallback(() => fetchServers(), []),\n\t\t{ pollInterval: 10_000 },\n\t);\n\n\tif (indexErr && !indexData) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">Error loading repos: {indexErr.message}</div>\n\t\t);\n\t}\n\tif (!indexData) {\n\t\treturn <div className=\"tab-stub\">Loading repos…</div>;\n\t}\n\n\tconst summary = indexData.summary;\n\tconst repos = indexData.repos;\n\tconst servers = serversData?.servers ?? [];\n\n\tif (repos.length === 0) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t\t<SummaryTiles\n\t\t\t\t\ttotalRepos={0}\n\t\t\t\t\ttotalCheckpoints={0}\n\t\t\t\t\ttotalTokensSaved={0}\n\t\t\t\t\tcompressedOriginalBytes={0}\n\t\t\t\t/>\n\t\t\t\t<div className=\"tab-stub\">\n\t\t\t\t\t<h3>Repositories / Memory</h3>\n\t\t\t\t\t<p>\n\t\t\t\t\t\tRepo memory appears after the first compaction. Compaction fires\n\t\t\t\t\t\twhen context crosses the tier threshold (~50-70% of the window).\n\t\t\t\t\t\tRun a longer session or lower the compaction tier to see it sooner.\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t<SummaryTiles\n\t\t\t\ttotalRepos={summary?.totalRepos ?? 0}\n\t\t\t\ttotalCheckpoints={summary?.totalCheckpoints ?? 0}\n\t\t\t\ttotalTokensSaved={summary?.totalTokensSaved ?? 0}\n\t\t\t\tcompressedOriginalBytes={summary?.totalCompressedOriginalBytes ?? 0}\n\t\t\t/>\n\t\t\t<h2 className=\"font-heading text-lg font-semibold\">All Repositories</h2>\n\t\t\t<RepoTable repos={repos} onSelect={setSelected} />\n\t\t\t<h2 className=\"font-heading text-lg font-semibold\">\n\t\t\t\tActive Repos — Live Cache Hits & Compactions\n\t\t\t</h2>\n\t\t\t<ActiveReposTable servers={servers} />\n\t\t\t<h2 className=\"font-heading text-lg font-semibold\">Savings by Model</h2>\n\t\t\t<SavingsByModelTable repos={repos} />\n\t\t\t{selected && (\n\t\t\t\t<RepoDetailModal repo={selected} onClose={() => setSelected(null)} />\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"],"names":["fmtBytesTop","b","fmt","n","SummaryTiles","totalRepos","totalCheckpoints","totalTokensSaved","compressedOriginalBytes","jsxs","jsx","Card","CardContent","COLUMNS","formatTs","ts","RepoTable","repos","onSelect","search","setSearch","useState","sortKey","setSortKey","sortDir","setSortDir","filtered","useMemo","q","list","r","a","av","bv","aNull","bNull","cmp","handleSort","key","d","e","col","repo","RepoDetailModal","onClose","useEffect","handler","fmtSec","s","v","HEADERS","ActiveReposTable","servers","h","i","ch","cp","fmtTokens","collapseNum","samples","lo","hi","collapseRate","aggregate","map","g","TOOLTIPS","SavingsByModelTable","groups","freed","usd","when","reas","computeCacheSavings","fetchIndexTyped","fetchIndex","ReposTab","selected","setSelected","indexData","indexErr","useApi","useCallback","serversData","fetchServers","summary"],"mappings":"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"}
|