pi-mega-compact 0.20.59 → 0.20.60
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/dist/config/vector-cortex-dash-0c.js +23 -0
- package/dist/config/vector-cortex.js +2 -0
- package/dist/config.js +1 -1
- package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +1 -0
- package/dist/src/config/vector-cortex-dash-0c.js +23 -0
- package/dist/src/config/vector-cortex.js +2 -0
- package/dist/src/config.js +1 -1
- package/extensions/dashboard-client/dist/assets/{AreaChart-GTwQxOAm.js → AreaChart-B5Is2_EN.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AreaChart-GTwQxOAm.js.map → AreaChart-B5Is2_EN.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{BarChart-BFqUD5L4.js → BarChart-Bj2oT871.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{BarChart-BFqUD5L4.js.map → BarChart-Bj2oT871.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/CacheTab-DuhLeKHW.js +2 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-DuhLeKHW.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{EventsTab-BYLh6cud.js → EventsTab-BG6L8uWh.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-BYLh6cud.js.map → EventsTab-BG6L8uWh.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-CkJXEbjn.js → HealthTab-CZmGCUJh.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-CkJXEbjn.js.map → HealthTab-CZmGCUJh.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HydeDetailPanel-Dt9T7kc5.js → HydeDetailPanel-B-P1jTtk.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HydeDetailPanel-Dt9T7kc5.js.map → HydeDetailPanel-B-P1jTtk.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-Lm3v0nJO.js → MaintenanceTab-CoZ1mSjU.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-Lm3v0nJO.js.map → MaintenanceTab-CoZ1mSjU.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-C8AeBIQi.js → MemoryMapTab-BwVaWniY.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-C8AeBIQi.js.map → MemoryMapTab-BwVaWniY.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-m410T4vk.js → MetricsCards-BCJoHe_n.js} +2 -2
- package/extensions/dashboard-client/dist/assets/MetricsCards-BCJoHe_n.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/MetricsTab-UQSqUGXe.js +2 -0
- package/extensions/dashboard-client/dist/assets/MetricsTab-UQSqUGXe.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{OverviewTab-BfDfMFXx.js → OverviewTab-qi12IYvs.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-BfDfMFXx.js.map → OverviewTab-qi12IYvs.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-CsFxxqJ6.js → ReposTab-CcHZPzOO.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-CsFxxqJ6.js.map → ReposTab-CcHZPzOO.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-DstDOzwu.js → SessionsTab-nzd1408Z.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-DstDOzwu.js.map → SessionsTab-nzd1408Z.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/SetupTab-DPrG3s9V.js +3 -0
- package/extensions/dashboard-client/dist/assets/{SetupTab-DVT4PrH0.js.map → SetupTab-DPrG3s9V.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BkRzjyRm.js → TimeSavedCard-DhfdRM3_.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BkRzjyRm.js.map → TimeSavedCard-DhfdRM3_.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-D5QTnv52.js → TurnsTab-oalBNLVr.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-D5QTnv52.js.map → TurnsTab-oalBNLVr.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{VcStatusBadge-B8B8RStV.js → VcStatusBadge-XGMW6u62.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{VcStatusBadge-B8B8RStV.js.map → VcStatusBadge-XGMW6u62.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{VectorCortexTab-CrGANNd_.js → VectorCortexTab-BACHKLjU.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{VectorCortexTab-CrGANNd_.js.map → VectorCortexTab-BACHKLjU.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{WikiTab-DyD0yGzI.js → WikiTab-CGQWHuRq.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{WikiTab-DyD0yGzI.js.map → WikiTab-CGQWHuRq.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{button-Bynl3ONj.js → button-SyOWCGkp.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{button-Bynl3ONj.js.map → button-SyOWCGkp.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{card-Daf3pQIu.js → card-69DCTMel.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{card-Daf3pQIu.js.map → card-69DCTMel.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{client-extra-DqAYZBW1.js → client-extra-CgeDg1Md.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{client-extra-DqAYZBW1.js.map → client-extra-CgeDg1Md.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-B-fe5jjr.js → generateCategoricalChart-BwTtrqm5.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-B-fe5jjr.js.map → generateCategoricalChart-BwTtrqm5.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-Bjvv23bp.js → index-BZcYzeCr.js} +3 -3
- package/extensions/dashboard-client/dist/assets/{index-Bjvv23bp.js.map → index-BZcYzeCr.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{switch-CivyERPS.js → switch-DhQfmSFD.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{switch-CivyERPS.js.map → switch-DhQfmSFD.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{toggle-qmdkrAgF.js → toggle-B3gNAVog.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{toggle-qmdkrAgF.js.map → toggle-B3gNAVog.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-uNuduyGe.js → useSSE-BkkjZ4bO.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-uNuduyGe.js.map → useSSE-BkkjZ4bO.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/tabs/AdminTab.tsx +81 -0
- package/extensions/dashboard-client/src/tabs/CacheTab/MetricsCards.tsx +66 -0
- package/extensions/dashboard-client/src/tabs/CacheTab.tsx +46 -0
- package/extensions/dashboard-client/src/tabs/MetricsTab.tsx +10 -51
- package/extensions/dashboard-client/src/tabs/SetupTab.tsx +33 -4
- package/extensions/dashboard-client/src/tabs/index.ts +7 -6
- package/extensions/dashboard-client/src/tabs/registry.ts +17 -0
- package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +6 -0
- package/package.json +1 -1
- package/src/config/vector-cortex-dash-0c.ts +25 -0
- package/src/config/vector-cortex.ts +2 -0
- package/src/config.ts +1 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-BLM6_PQQ.js +0 -2
- package/extensions/dashboard-client/dist/assets/CacheTab-BLM6_PQQ.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MetricsTab-m410T4vk.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/SetupTab-DVT4PrH0.js +0 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionsTab-DstDOzwu.js","sources":["../../src/components/SessionsMemoryChart.tsx","../../src/components/ActiveSessionsTable.tsx","../../src/tabs/SessionsTab/TurnMemoryView.tsx","../../src/tabs/SessionsTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/components/SessionsMemoryChart.tsx — Stacked memory graph (S39).\n *\n * Recharts stacked `<Area>` per session + total `<Line>` + `<Tooltip>` +\n * `<Legend>` + `<ResponsiveContainer>`. Data comes from `/api/sessions/timeseries`\n * which returns `SessionSeries[]` (per-session data points + stable hex color)\n * and a `totals[]` array (sum across all sessions per timestamp).\n *\n * PREVENT-PI-004: recharts is bundled into this localhost-served static\n * dashboard bundle; it makes no runtime network calls. Chart data arrives via\n * same-origin fetch to the dashboard server (loopback, ports 9320–9329).\n */\n\nimport type React from \"react\";\nimport { useMemo } from \"react\";\nimport {\n\tResponsiveContainer,\n\tAreaChart,\n\tArea,\n\tLine,\n\tXAxis,\n\tYAxis,\n\tCartesianGrid,\n\tTooltip,\n\tLegend,\n} from \"recharts\";\nimport type { SessionSeries } from \"@contracts\";\nimport { Card, CardContent } from \"../components/ui/card\";\n\nexport interface SessionsMemoryChartProps {\n\t/** Per-session series with stable colors (from /api/sessions/timeseries). */\n\tseries: SessionSeries[];\n\t/** Totals (sum across all sessions) per timestamp. */\n\ttotals: ReadonlyArray<{ ts: number; tokens: number }>;\n}\n\n/** A row in the pivoted data table passed to recharts `<AreaChart>`. */\ninterface PivotedRow {\n\t/** Unix timestamp (ms). */\n\tts: number;\n\t/** Total tokens across all sessions at this timestamp. */\n\ttotal: number;\n\t/** Per-session token count keyed by sessionId. */\n\t[sessionId: string]: number;\n}\n\n/**\n * Pivot the per-session series + totals into recharts' expected flat shape:\n * one row per unique timestamp, with each session's token count as a column\n * keyed by sessionId. Missing values for a session at a given timestamp are\n * filled with zero so the stack renders continuously.\n */\nfunction pivot(\n\tseries: SessionSeries[],\n\ttotals: ReadonlyArray<{ ts: number; tokens: number }>,\n): PivotedRow[] {\n\tconst map = new Map<number, PivotedRow>();\n\tconst sessionIds = series.map((s) => s.sessionId);\n\n\tfor (const s of series) {\n\t\tfor (const pt of s.data) {\n\t\t\tlet row = map.get(pt.ts);\n\t\t\tif (!row) {\n\t\t\t\trow = { ts: pt.ts, total: 0 } as PivotedRow;\n\t\t\t\tfor (const sid of sessionIds) row[sid] = 0;\n\t\t\t\tmap.set(pt.ts, row);\n\t\t\t}\n\t\t\trow[s.sessionId] = pt.tokens;\n\t\t}\n\t}\n\tfor (const t of totals) {\n\t\tlet row = map.get(t.ts);\n\t\tif (!row) {\n\t\t\trow = { ts: t.ts, total: 0 } as PivotedRow;\n\t\t\tfor (const sid of sessionIds) row[sid] = 0;\n\t\t\tmap.set(t.ts, row);\n\t\t}\n\t\trow.total = t.tokens;\n\t}\n\n\treturn [...map.values()].sort((a, b) => a.ts - b.ts);\n}\n\nfunction fmtTs(ts: number): string {\n\treturn new Date(ts).toLocaleTimeString([], {\n\t\thour: \"2-digit\",\n\t\tminute: \"2-digit\",\n\t\tsecond: \"2-digit\",\n\t});\n}\n\nfunction fmtTokens(value: number | string): string {\n\tconst n = Number(value);\n\treturn Number.isFinite(n) ? n.toLocaleString() : String(value);\n}\n\n/** Sanitize an arbitrary sessionId for use in an SVG gradient id. */\nfunction gradId(sessionId: string): string {\n\tconst safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n\treturn `grad-${safe}`;\n}\n\nexport function SessionsMemoryChart({\n\tseries,\n\ttotals,\n}: SessionsMemoryChartProps): React.ReactElement {\n\tconst data = useMemo(\n\t\t() => pivot(series, totals),\n\t\t[series, totals],\n\t);\n\n\tif (series.length === 0) {\n\t\treturn (\n\t\t\t<Card>\n\t\t\t\t<CardContent>No token samples in this window yet.</CardContent>\n\t\t\t</Card>\n\t\t);\n\t}\n\n\treturn (\n\t\t<Card>\n\t\t\t<CardContent>\n\t\t\t<ResponsiveContainer width=\"100%\" height={360}>\n\t\t\t\t<AreaChart\n\t\t\t\t\tdata={data}\n\t\t\t\t\tmargin={{ top: 8, right: 16, left: 0, bottom: 0 }}\n\t\t\t\t>\n\t\t\t\t\t<defs>\n\t\t\t\t\t\t{series.map((s) => (\n\t\t\t\t\t\t\t<linearGradient\n\t\t\t\t\t\t\t\tkey={`${s.sessionId}-grad`}\n\t\t\t\t\t\t\t\tid={gradId(s.sessionId)}\n\t\t\t\t\t\t\t\tx1=\"0\"\n\t\t\t\t\t\t\t\ty1=\"0\"\n\t\t\t\t\t\t\t\tx2=\"0\"\n\t\t\t\t\t\t\t\ty2=\"1\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<stop offset=\"5%\" stopColor={s.color} stopOpacity={0.7} />\n\t\t\t\t\t\t\t\t<stop offset=\"95%\" stopColor={s.color} stopOpacity={0.25} />\n\t\t\t\t\t\t\t</linearGradient>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</defs>\n\t\t\t\t\t<CartesianGrid strokeDasharray=\"3 3\" stroke=\"#30363d\" />\n\t\t\t\t\t<XAxis\n\t\t\t\t\t\tdataKey=\"ts\"\n\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\tdomain={[\"dataMin\", \"dataMax\"]}\n\t\t\t\t\t\ttickFormatter={(ts: number) => fmtTs(ts)}\n\t\t\t\t\t\tstroke=\"#8b949e\"\n\t\t\t\t\t\ttick={{ fontSize: 11 }}\n\t\t\t\t\t\tscale=\"time\"\n\t\t\t\t\t/>\n\t\t\t\t\t<YAxis\n\t\t\t\t\t\tstroke=\"#8b949e\"\n\t\t\t\t\t\ttick={{ fontSize: 11 }}\n\t\t\t\t\t\twidth={56}\n\t\t\t\t\t\ttickFormatter={(v: number) => fmtTokens(v)}\n\t\t\t\t\t/>\n\t\t\t\t\t<Tooltip\n\t\t\t\t\t\tlabelFormatter={(ts: number) => fmtTs(ts)}\n\t\t\t\t\t\tformatter={(value) =>\n\t\t\t\t\t\t\t[fmtTokens(value as number), \"tokens\"] as [string, string]\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontentStyle={{\n\t\t\t\t\t\t\tbackground: \"#161b22\",\n\t\t\t\t\t\t\tborder: \"1px solid #30363d\",\n\t\t\t\t\t\t\tborderRadius: \"6px\",\n\t\t\t\t\t\t\tcolor: \"#e6edf3\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tlabelStyle={{ color: \"#8b949e\", fontSize: 12 }}\n\t\t\t\t\t/>\n\t\t\t\t\t<Legend wrapperStyle={{ fontSize: 12 }} />\n\t\t\t\t\t{series.map((s) => (\n\t\t\t\t\t\t<Area\n\t\t\t\t\t\t\tkey={s.sessionId}\n\t\t\t\t\t\t\ttype=\"monotone\"\n\t\t\t\t\t\t\tdataKey={s.sessionId}\n\t\t\t\t\t\t\tname={s.label}\n\t\t\t\t\t\t\tstackId=\"1\"\n\t\t\t\t\t\t\tstroke={s.color}\n\t\t\t\t\t\t\tfill={`url(#${gradId(s.sessionId)})`}\n\t\t\t\t\t\t\tfillOpacity={1}\n\t\t\t\t\t\t\tisAnimationActive={false}\n\t\t\t\t\t\t\tdot={false}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t\t<Line\n\t\t\t\t\t\ttype=\"monotone\"\n\t\t\t\t\t\tdataKey=\"total\"\n\t\t\t\t\t\tname=\"Total\"\n\t\t\t\t\t\tstroke=\"#e6edf3\"\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t\tstrokeDasharray=\"4 2\"\n\t\t\t\t\t\tdot={false}\n\t\t\t\t\t\tisAnimationActive={false}\n\t\t\t\t\t/>\n\t\t\t\t</AreaChart>\n\t\t\t</ResponsiveContainer>\n\t\t\t</CardContent>\n\t\t</Card>\n\t);\n}\n","/**\n * dashboard-client/src/components/ActiveSessionsTable.tsx — Active sessions table (S39).\n *\n * Per-session rows: PID, Repo, Model, Context %, Tokens/Window,\n * Heartbeat age, State dir, Sparkline.\n *\n * Data from /api/sessions (active sessions list) and /api/sessions/timeseries\n * (per-session data points used to render inline sparklines).\n */\n\nimport type React from \"react\";\nimport type { ActiveSession, SessionSeries } from \"@contracts\";\nimport { Card, CardContent } from \"../components/ui/card\";\n\nexport interface ActiveSessionsTableProps {\n\t/** Active sessions, sorted by lastSeen descending (from /api/sessions). */\n\tsessions: ActiveSession[];\n\t/** Per-session timeseries used to render the inline sparkline column. */\n\tseries: SessionSeries[];\n}\n\nconst HEADERS = [\n\t\"PID\",\n\t\"Repo\",\n\t\"Model\",\n\t\"Context %\",\n\t\"Tokens / Window\",\n\t\"Last Heartbeat\",\n\t\"State Dir\",\n\t\"Trend\",\n] as const;\n\n/** Format a duration in milliseconds → human-readable age string. */\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 ${s % 60}s ago`;\n\tconst h = Math.floor(m / 60);\n\treturn `${h}h ${m % 60}m ago`;\n}\n\nfunction fmtTokens(n: number | null): string {\n\tif (n == null) return \"\\u2014\";\n\tif (n >= 100_000) return `${(n / 1000).toFixed(0)}k`;\n\tif (n >= 1000) return `${(n / 1000).toFixed(1)}k`;\n\treturn n.toLocaleString();\n}\n\nfunction pctClass(pct: number | null): string {\n\tif (pct == null) return \"sessions-pct-ok\";\n\tif (pct >= 85) return \"sessions-pct-err\";\n\tif (pct >= 60) return \"sessions-pct-warn\";\n\treturn \"sessions-pct-ok\";\n}\n\nfunction fmtPct(pct: number | null): string {\n\tif (pct == null) return \"\\u2014\";\n\treturn `${Math.round(pct)}%`;\n}\n\nfunction fmtWindow(tokens: number | null, window: number): string {\n\tif (tokens == null) return \"\\u2014\";\n\treturn `${fmtTokens(tokens)} / ${fmtTokens(window)}`;\n}\n\ninterface SparklineProps {\n\t/** Token counts over time (oldest → newest). */\n\tpoints: number[];\n\t/** Stable hex color for the stroke. */\n\tcolor: string;\n}\n\nfunction Sparkline({ points, color }: SparklineProps): React.ReactElement {\n\tif (points.length < 2) {\n\t\treturn <span className=\"sessions-sparkline-empty\">{\"\\u2014\"}</span>;\n\t}\n\tconst min = Math.min(...points);\n\tconst max = Math.max(...points);\n\tconst range = max - min || 1;\n\tconst w = 64;\n\tconst h = 18;\n\tconst stepX = w / (points.length - 1);\n\tconst segments = points.map((p, i) => {\n\t\tconst x = i * stepX;\n\t\tconst y = h - ((p - min) / range) * h;\n\t\treturn `${i === 0 ? \"M\" : \"L\"} ${x.toFixed(1)} ${y.toFixed(1)}`;\n\t});\n\treturn (\n\t\t<svg\n\t\t\tclassName=\"sessions-sparkline\"\n\t\t\twidth={w}\n\t\t\theight={h}\n\t\t\tviewBox={`0 0 ${w} ${h}`}\n\t\t\trole=\"img\"\n\t\t\taria-label=\"token trend\"\n\t\t>\n\t\t\t<path\n\t\t\t\td={segments.join(\" \")}\n\t\t\t\tfill=\"none\"\n\t\t\t\tstroke={color}\n\t\t\t\tstrokeWidth=\"1.5\"\n\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t/>\n\t\t</svg>\n\t);\n}\n\n/** Map sessionId → series for the sparkline column lookup. */\nfunction indexSeries(\n\tseries: SessionSeries[],\n): Map<string, SessionSeries> {\n\tconst m = new Map<string, SessionSeries>();\n\tfor (const s of series) m.set(s.sessionId, s);\n\treturn m;\n}\n\nexport function ActiveSessionsTable({\n\tsessions,\n\tseries,\n}: ActiveSessionsTableProps): React.ReactElement {\n\tconst seriesById = indexSeries(series);\n\tconst now = Date.now();\n\n\treturn (\n\t\t<Card>\n\t\t\t<CardContent>\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 !== 6 ? \" 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{sessions.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 sessions.\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{sessions.map((s) => {\n\t\t\t\t\t\t\tconst srs = seriesById.get(s.sessionId);\n\t\t\t\t\t\t\tconst sparkPts =\n\t\t\t\t\t\t\t\tsrs?.data.map((d) => d.tokens) ?? [];\n\t\t\t\t\t\t\tconst color = srs?.color ?? \"#58a6ff\";\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<tr\n\t\t\t\t\t\t\t\t\tkey={`${s.pid}:${s.sessionId}`}\n\t\t\t\t\t\t\t\t\tclassName=\"border-b border-border/50 hover:bg-bg-elevated/40\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-2 text-right font-mono\">{s.pid}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-2\" title={s.repoRoot ?? undefined}>\n\t\t\t\t\t\t\t\t\t\t{s.displayName || s.repoRoot || \"\\u2014\"}\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-2\">{s.model ?? \"\\u2014\"}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-2 text-right\">\n\t\t\t\t\t\t\t\t\t\t<span className={`sessions-pct-pill ${pctClass(s.percent)}`}>\n\t\t\t\t\t\t\t\t\t\t\t{fmtPct(s.percent)}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-2 text-right\">\n\t\t\t\t\t\t\t\t\t\t{fmtWindow(s.tokens, s.ctxWindow)}\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-2 text-right\">{fmtAge(now - s.lastSeen)}</td>\n\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\ttitle={s.stateDir ?? undefined}\n\t\t\t\t\t\t\t\t\t\tclassName=\"px-3 py-2 font-mono text-muted-foreground\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{s.stateDir\n\t\t\t\t\t\t\t\t\t\t\t? s.stateDir.split(\"/\").pop() || s.stateDir\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 className=\"px-3 py-2\">\n\t\t\t\t\t\t\t\t\t\t<Sparkline points={sparkPts} color={color} />\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/tabs/SessionsTab/TurnMemoryView.tsx — Turn-by-turn memory\n * tracking + recall (S52), moved VERBATIM from the top-level TurnsTab.tsx.\n *\n * DASH-0b: the Sessions surface absorbs the existent TurnsTab as a drill-down.\n * This file holds the byte-preserved turns body (the `TurnMemoryView`\n * component). The standalone `tabs/TurnsTab.tsx` is LEFT UNTOUCHED this sprint —\n * its copy stays live for flag-off / pre-DASH parity. A DASH-0d cleanup deletes\n * the standalone copy after a deep-link audit proves no live consumer points\n * at it. Only the export name changed (TurnsTab → TurnMemoryView); the render\n * body is otherwise identical.\n *\n * Fetches /api/turns (conversation list), expands the active conversation into\n * per-turn detail (/api/turns/conversation/:id), and renders:\n * - Conversation summary list (turn count, recall total, epochs, last turn).\n * - Per-turn rows: turn index, role, ctx tokens/percent + pressure band,\n * epoch id, and the injected-checkpoint recall set (the memory recalled\n * at each turn, with score + source).\n * - Pending rewind intents (S52A) + Fork action (S50C primitive).\n *\n * Read-mostly via /api/turns; fork/intent/prune via POST. No absolute URLs\n * (PREVENT-PI-004: loopback-only, same-origin static bundle).\n */\n\nimport type React from \"react\";\nimport { useCallback, useState } from \"react\";\nimport { useApi } from \"../../hooks/useApi\";\nimport {\n\tfetchTurns,\n\tfetchConversationTurns,\n\tfetchTurnIntents,\n\tpostFork,\n\tpostTurnIntent,\n} from \"../../api/client\";\nimport type {\n\tTurnsResponse,\n\tConversationTurnsResponse,\n\tRewindIntentsResponse,\n\tTurnRow,\n\tConversationSummary,\n} from \"@contracts\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"../../components/ui/card\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { HydeDetailPanel } from \"../../components/HydeDetailPanel\";\n\nfunction fmtTs(ms: number): string {\n\tif (!ms) return \"—\";\n\treturn new Date(ms).toLocaleString();\n}\n\nfunction bandVariant(band: TurnRow[\"pressureBand\"]): \"success\" | \"warning\" | \"danger\" | \"default\" {\n\tif (band === \"green\") return \"success\";\n\tif (band === \"yellow\") return \"warning\";\n\tif (band === \"red\") return \"danger\";\n\treturn \"default\";\n}\n\nfunction sourceLabel(s: TurnRow[\"recall\"][number][\"source\"]): string {\n\tif (s === \"checkpoint\") return \"ckpt\";\n\tif (s === \"cluster_summary\") return \"raptor\";\n\treturn \"mem\";\n}\n\nexport function TurnMemoryView(): React.ReactElement {\n\tconst {\n\t\tdata: turns,\n\t\tloading,\n\t\terror,\n\t} = useApi<TurnsResponse>(\n\t\tuseCallback(() => fetchTurns(), []),\n\t\t{\n\t\t\tpollInterval: 10_000,\n\t\t},\n\t);\n\tconst { data: intents } = useApi<RewindIntentsResponse>(\n\t\tuseCallback(() => fetchTurnIntents(), []),\n\t\t{ pollInterval: 5_000 },\n\t);\n\tconst [expanded, setExpanded] = useState<string | null>(null);\n\tconst [detail, setDetail] = useState<ConversationTurnsResponse | null>(null);\n\tconst [detailLoading, setDetailLoading] = useState(false);\n\tconst [busy, setBusy] = useState<string | null>(null);\n\tconst [notice, setNotice] = useState<string | null>(null);\n\n\tconst expand = useCallback(\n\t\tasync (conversationId: string) => {\n\t\t\tif (expanded === conversationId) {\n\t\t\t\tsetExpanded(null);\n\t\t\t\tsetDetail(null);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsetExpanded(conversationId);\n\t\t\tsetDetailLoading(true);\n\t\t\tsetDetail(null);\n\t\t\ttry {\n\t\t\t\tconst d = await fetchConversationTurns(conversationId);\n\t\t\t\tsetDetail(d);\n\t\t\t} finally {\n\t\t\t\tsetDetailLoading(false);\n\t\t\t}\n\t\t},\n\t\t[expanded],\n\t);\n\n\tconst onFork = useCallback(\n\t\tasync (conversationId: string, turnIndex: number) => {\n\t\t\tsetBusy(`fork:${conversationId}:${turnIndex}`);\n\t\t\tsetNotice(null);\n\t\t\ttry {\n\t\t\t\tconst out = await postFork(conversationId, turnIndex);\n\t\t\t\tsetNotice(\n\t\t\t\t\t`Forked → ${out.childConversationId} (${out.recalledCount} recalled)`,\n\t\t\t\t);\n\t\t\t} catch (e) {\n\t\t\t\tsetNotice(`Fork failed: ${(e as Error).message}`);\n\t\t\t} finally {\n\t\t\t\tsetBusy(null);\n\t\t\t}\n\t\t},\n\t\t[],\n\t);\n\n\tconst onRewind = useCallback(\n\t\tasync (conversationId: string, turnIndex: number) => {\n\t\t\tsetBusy(`rewind:${conversationId}:${turnIndex}`);\n\t\t\tsetNotice(null);\n\t\t\ttry {\n\t\t\t\tawait postTurnIntent(conversationId, turnIndex);\n\t\t\t\tsetNotice(`Rewind intent queued for turn ${turnIndex}`);\n\t\t\t} catch (e) {\n\t\t\t\tsetNotice(`Rewind failed: ${(e as Error).message}`);\n\t\t\t} finally {\n\t\t\t\tsetBusy(null);\n\t\t\t}\n\t\t},\n\t\t[],\n\t);\n\n\tif (error && !turns) {\n\t\treturn <div className=\"tab-stub\">Error loading turns: {error.message}</div>;\n\t}\n\tif (loading && !turns) {\n\t\treturn <div className=\"tab-stub\">Loading turns…</div>;\n\t}\n\tif (!turns || turns.conversations.length === 0) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">\n\t\t\t\t<h3>Turn-by-turn memory</h3>\n\t\t\t\t<p>\n\t\t\t\t\tNo turns recorded yet. Per-turn tracking starts when{\" \"}\n\t\t\t\t\t<code>MEGACOMPACT_TURNS_DB=1</code> and the session runs through a\n\t\t\t\t\tcompaction. Each turn records its context metrics + the checkpoints\n\t\t\t\t\trecalled into it.\n\t\t\t\t</p>\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<h3 className=\"font-heading text-lg font-semibold\">\n\t\t\t\tTurn-by-turn memory tracking + recall\n\t\t\t</h3>\n\t\t\t{notice && <Badge variant=\"warning\">{notice}</Badge>}\n\n\t\t\t{intents && intents.intents.length > 0 && (\n\t\t\t\t<Card>\n\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t<CardTitle>\n\t\t\t\t\t\t\tPending rewind intents ({intents.intents.length})\n\t\t\t\t\t\t</CardTitle>\n\t\t\t\t\t</CardHeader>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<ul className=\"list-disc space-y-1 pl-5\">\n\t\t\t\t\t\t\t{intents.intents.map((i) => (\n\t\t\t\t\t\t\t\t<li key={i.id}>\n\t\t\t\t\t\t\t\t\t{fmtTs(i.createdAt)} — rewind{\" \"}\n\t\t\t\t\t\t\t\t\t<code>{i.conversationId}</code> to turn {i.targetTurnIndex}\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t)}\n\n\t\t\t<Card>\n\t\t\t\t<CardHeader>\n\t\t\t\t\t<CardTitle>\n\t\t\t\t\t\tConversations ({turns.conversations.length})\n\t\t\t\t\t</CardTitle>\n\t\t\t\t</CardHeader>\n\t\t\t\t<CardContent>\n\t\t\t\t\t<table className=\"w-full border-collapse text-sm\">\n\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Conversation</th>\n\t\t\t\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Turns</th>\n\t\t\t\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Recall</th>\n\t\t\t\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Epochs</th>\n\t\t\t\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Avg ctx%</th>\n\t\t\t\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Last turn</th>\n\t\t\t\t\t\t\t\t<th className=\"border-b border-border px-3 py-2\"></th>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t{turns.conversations.map((c: ConversationSummary) => (\n\t\t\t\t\t\t\t\t<ConversationRow\n\t\t\t\t\t\t\t\t\tkey={c.conversationId}\n\t\t\t\t\t\t\t\t\tc={c}\n\t\t\t\t\t\t\t\t\tactive={turns.activeConversationId === c.conversationId}\n\t\t\t\t\t\t\t\t\texpanded={expanded === c.conversationId}\n\t\t\t\t\t\t\t\t\tonExpand={() => expand(c.conversationId)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</tbody>\n\t\t\t\t\t</table>\n\t\t\t\t</CardContent>\n\t\t\t</Card>\n\n\t\t\t{expanded && (\n\t\t\t\t<Card>\n\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t<CardTitle>\n\t\t\t\t\t\t\tTurns in <code>{expanded}</code>\n\t\t\t\t\t\t</CardTitle>\n\t\t\t\t\t</CardHeader>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t{detailLoading ? (\n\t\t\t\t\t\t\t<div className=\"text-sm text-muted-foreground\">Loading turns…</div>\n\t\t\t\t\t\t) : detail ? (\n\t\t\t\t\t\t\t<TurnDetail\n\t\t\t\t\t\t\t\tdetail={detail}\n\t\t\t\t\t\t\t\tbusy={busy}\n\t\t\t\t\t\t\t\tonFork={onFork}\n\t\t\t\t\t\t\t\tonRewind={onRewind}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<div className=\"text-sm text-muted-foreground\">No detail.</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction ConversationRow({\n\tc,\n\tactive,\n\texpanded,\n\tonExpand,\n}: {\n\tc: ConversationSummary;\n\tactive: boolean;\n\texpanded: boolean;\n\tonExpand: () => void;\n}): React.ReactElement {\n\treturn (\n\t\t<>\n\t\t\t<tr\n\t\t\t\tclassName={`border-b border-border/50 hover:bg-bg-elevated/40 ${\n\t\t\t\t\tactive ? \"bg-primary/10\" : \"\"\n\t\t\t\t}`}\n\t\t\t\tonClick={onExpand}\n\t\t\t\tstyle={{ cursor: \"pointer\" }}\n\t\t\t>\n\t\t\t\t<td className=\"px-3 py-2\">\n\t\t\t\t\t{expanded ? \"▾\" : \"▸\"} <code>{c.conversationId}</code>\n\t\t\t\t\t{active && <Badge variant=\"accent\" className=\"ml-2\">active</Badge>}\n\t\t\t\t</td>\n\t\t\t\t<td className=\"px-3 py-2 text-right\">{c.turnCount}</td>\n\t\t\t\t<td className=\"px-3 py-2 text-right\">{c.totalRecall}</td>\n\t\t\t\t<td className=\"px-3 py-2 text-right\">{c.epochCount}</td>\n\t\t\t\t<td className=\"px-3 py-2 text-right\">{c.avgCtxPercent.toFixed(0)}%</td>\n\t\t\t\t<td className=\"px-3 py-2\">{fmtTs(c.lastTurnAt)}</td>\n\t\t\t\t<td className=\"px-3 py-2\" />\n\t\t\t</tr>\n\t\t</>\n\t);\n}\n\nfunction TurnDetail({\n\tdetail,\n\tbusy,\n\tonFork,\n\tonRewind,\n}: {\n\tdetail: ConversationTurnsResponse;\n\tbusy: string | null;\n\tonFork: (conversationId: string, turnIndex: number) => void;\n\tonRewind: (conversationId: string, turnIndex: number) => void;\n}): React.ReactElement {\n\treturn (\n\t\t<table className=\"w-full border-collapse text-sm\">\n\t\t\t<thead>\n\t\t\t\t<tr>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">#</th>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Role</th>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Ctx</th>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Band</th>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Epoch</th>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Recalled checkpoints (memory recall)</th>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">HyDE</th>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Ended</th>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Actions</th>\n\t\t\t\t</tr>\n\t\t\t</thead>\n\t\t\t<tbody>\n\t\t\t\t{detail.turns.map((t) => (\n\t\t\t\t\t<tr\n\t\t\t\t\t\tkey={`${t.conversationId}:${t.turnIndex}`}\n\t\t\t\t\t\tclassName=\"border-b border-border/50 hover:bg-bg-elevated/40\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<td className=\"px-3 py-2 text-right\">{t.turnIndex}</td>\n\t\t\t\t\t\t<td className=\"px-3 py-2\">{t.role}</td>\n\t\t\t\t\t\t<td className=\"px-3 py-2\">\n\t\t\t\t\t\t\t{t.ctxTokens ?? \"—\"}\n\t\t\t\t\t\t\t{t.ctxPercent != null && (\n\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t{\" \"}\n\t\t\t\t\t\t\t\t\t· {t.ctxPercent.toFixed(0)}%\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td className=\"px-3 py-2\">\n\t\t\t\t\t\t\t<Badge variant={bandVariant(t.pressureBand)}>\n\t\t\t\t\t\t\t\t{t.pressureBand ?? \"—\"}\n\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td className=\"px-3 py-2\">{t.epochId ? <code>{t.epochId.slice(0, 8)}</code> : \"—\"}</td>\n\t\t\t\t\t\t<td className=\"px-3 py-2\">\n\t\t\t\t\t\t\t{t.recall.length === 0 ? (\n\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground\">—</span>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<ul className=\"space-y-1\">\n\t\t\t\t\t\t\t\t\t{t.recall.map((r) => (\n\t\t\t\t\t\t\t\t\t\t<li key={r.checkpointId}>\n\t\t\t\t\t\t\t\t\t\t\t<code>{r.checkpointId.slice(0, 12)}</code>{\" \"}\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t{sourceLabel(r.source)} · {r.score.toFixed(2)}\n\t\t\t\t\t\t\t\t\t\t\t\t{r.raptorLevel != null ? ` · L${r.raptorLevel}` : \"\"}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td className=\"px-3 py-2 align-top\">\n\t\t\t\t\t\t\t<HydeDetailPanel\n\t\t\t\t\t\t\t\tconversationId={t.conversationId}\n\t\t\t\t\t\t\t\tturnIndex={t.turnIndex}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td className=\"px-3 py-2\">{fmtTs(t.endedAt)}</td>\n\t\t\t\t\t\t<td className=\"px-3 py-2\">\n\t\t\t\t\t\t\t<div className=\"flex gap-2\">\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\tvariant=\"outline\"\n\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\tdisabled={busy !== null}\n\t\t\t\t\t\t\t\t\tonClick={() => onFork(t.conversationId, t.turnIndex)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\tfork\n\t\t\t\t\t\t\t\t</Button>\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\tvariant=\"outline\"\n\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\tdisabled={busy !== null}\n\t\t\t\t\t\t\t\t\tonClick={() => onRewind(t.conversationId, t.turnIndex)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\trewind\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\n\t\t\t\t))}\n\t\t\t</tbody>\n\t\t</table>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/SessionsTab.tsx — Sessions tab (S39, DASH-0b).\n *\n * DASH-0b: the Sessions surface absorbs the existent TurnsTab as a drill-down.\n * A `SessionsViews` toggle (\"Active Sessions\" / \"Turn Memory\") switches between\n * the existent sessions summary/chart/table body and the turns view (rendered by\n * `SessionsTab/TurnMemoryView.tsx` — the turns body moved VERBATIM from the\n * standalone TurnsTab.tsx, which is left untouched this sprint for flag-off\n * parity).\n *\n * Flag: `MEGACOMPACT_DASH_0B` default ON. The dashboard client is a browser\n * bundle with NO `process` global, so the positive sprint flag cannot be read\n * server-side-style (`process.env`) inside the client. Instead the flag is read\n * from the server-authoritative `/api/rag-settings` state: the server resolves\n * `process.env[\"MEGACOMPACT_DASH_0B\"] ?? default` into the `SettingState.value`\n * boolean. When the flag is OFF (settings confirmed value=false), this surface\n * renders ONLY the existent sessions body — no toggle, no TurnMemoryView branch\n * (byte-identical predecessor). The standalone TurnsTab.tsx top-level surface is\n * untouched and remains reachable for flag-off parity.\n *\n * Data sources: fetchSessions() + fetchSessionTimeseries(minutes). Both poll\n * every 2s for near-real-time updates. useSSE() listens for session_sample\n * events emitted by appendTokenSample (Step 5) so the chart refetches\n * instantly between polls when a new token sample is appended to events.log.\n *\n * Empty state: shows \"No active sessions.\" when the /api/sessions response\n * returns an empty array (e.g. no pi processes are running yet).\n */\n\nimport type React from \"react\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { useApi } from \"../hooks/useApi\";\nimport { useSSE } from \"../hooks/useSSE\";\nimport { fetchSessions, fetchSessionTimeseries, fetchSettings } from \"../api/client\";\nimport type {\n\tSseEvent,\n\tSseSessionSample,\n\tSessionsResponse,\n\tSessionTimeseriesResponse,\n\tSettingsResponse,\n} from \"@contracts\";\nimport { SessionsMemoryChart } from \"../components/SessionsMemoryChart\";\nimport { ActiveSessionsTable } from \"../components/ActiveSessionsTable\";\nimport { Toggle } from \"../components/ui/toggle\";\nimport { Card, CardContent } from \"../components/ui/card\";\nimport { TurnMemoryView } from \"./SessionsTab/TurnMemoryView\";\n\n/**\n * Shape of the {@link SseSessionSample} SSE event appended to events.log by\n * `appendTokenSample` (src/store/sqlite/global-index.ts). The contract now\n * defines this variant as part of the {@link SseEvent} union (Step 5); the\n * local alias keeps the surface terser in this file.\n */\ntype SessionSampleEvent = SseSessionSample;\n\n/** Type guard: narrows an SSE event to a session_sample event. */\nfunction isSessionSample(\n\te: SseEvent,\n): e is SessionSampleEvent {\n\treturn e.type === \"session_sample\";\n}\n\nconst DASH_0B_KEY = \"MEGACOMPACT_DASH_0B\";\n\n/** Resolve the DASH-0b consolidation flag from the server settings state.\n * Absent/not-yet-loaded => false (flag-off posture), so flag-off users never\n * see a toggle flash; the toggle appears only once settings confirm it is ON. */\nfunction dash0bEnabled(settings: SettingsResponse | null): boolean {\n\tif (!settings) return false;\n\tfor (const cat of settings.categories) {\n\t\tfor (const s of cat.settings) {\n\t\t\tif (s.key === DASH_0B_KEY && s.type === \"boolean\") return s.value === true;\n\t\t}\n\t}\n\treturn false;\n}\n\nconst WINDOWS: ReadonlyArray<{ value: number; label: string }> = [\n\t{ value: 5, label: \"5m\" },\n\t{ value: 15, label: \"15m\" },\n\t{ value: 30, label: \"30m\" },\n\t{ value: 60, label: \"60m\" },\n] as const;\n\ninterface SummaryTilesProps {\n\tsessions: SessionsResponse;\n}\n\nfunction SummaryTiles({ sessions }: SummaryTilesProps): React.ReactElement {\n\tconst active = sessions.sessions.length;\n\tconst combinedTokens = sessions.sessions.reduce(\n\t\t(sum, s) => sum + (s.tokens ?? 0),\n\t\t0,\n\t);\n\tconst maxWindow = sessions.sessions.reduce(\n\t\t(max, s) => Math.max(max, s.ctxWindow),\n\t\t0,\n\t);\n\tconst combinedPct = maxWindow > 0 ? (combinedTokens / maxWindow) * 100 : 0;\n\treturn (\n\t\t<div className=\"grid grid-cols-2 gap-4 md:grid-cols-4\">\n\t\t\t<Card>\n\t\t\t\t<CardContent>\n\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">Active sessions</span>\n\t\t\t\t\t<div className=\"text-xl font-semibold\">{active}</div>\n\t\t\t\t</CardContent>\n\t\t\t</Card>\n\t\t\t<Card>\n\t\t\t\t<CardContent>\n\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">Combined tokens</span>\n\t\t\t\t\t<div className=\"text-xl font-semibold\">\n\t\t\t\t\t\t{combinedTokens >= 100_000\n\t\t\t\t\t\t\t? `${(combinedTokens / 1000).toFixed(0)}k`\n\t\t\t\t\t\t\t: combinedTokens.toLocaleString()}\n\t\t\t\t\t</div>\n\t\t\t\t</CardContent>\n\t\t\t</Card>\n\t\t\t<Card>\n\t\t\t\t<CardContent>\n\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">\n\t\t\t\t\t\tCombined % of max window\n\t\t\t\t\t</span>\n\t\t\t\t\t<div className=\"text-xl font-semibold\">{Math.round(combinedPct)}%</div>\n\t\t\t\t</CardContent>\n\t\t\t</Card>\n\t\t\t<Card>\n\t\t\t\t<CardContent>\n\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">Pruned (stale)</span>\n\t\t\t\t\t<div className=\"text-xl font-semibold\">{sessions.pruned}</div>\n\t\t\t\t</CardContent>\n\t\t\t</Card>\n\t\t</div>\n\t);\n}\n\ntype SessionsView = \"active\" | \"turns\";\n\nexport default function SessionsTab(): React.ReactElement {\n\tconst [minutes, setMinutes] = useState(30);\n\tconst [view, setView] = useState<SessionsView>(\"active\");\n\n\tconst {\n\t\tdata: settingsData,\n\t} = useApi<SettingsResponse>(\n\t\tuseCallback(() => fetchSettings(), []),\n\t\t{ pollInterval: 0, maxRetries: 0 },\n\t);\n\tconst dash0bOn = dash0bEnabled(settingsData);\n\n\tconst {\n\t\tdata: sessionsData,\n\t\terror: sessionsErr,\n\t\trefetch: refetchSessions,\n\t} = useApi<SessionsResponse>(\n\t\tuseCallback(() => fetchSessions(), []),\n\t\t{ pollInterval: 2_000 },\n\t);\n\n\tconst {\n\t\tdata: timeseriesData,\n\t\terror: timeseriesErr,\n\t\trefetch: refetchTimeseries,\n\t} = useApi<SessionTimeseriesResponse>(\n\t\tuseCallback(() => fetchSessionTimeseries(minutes), [minutes]),\n\t\t{ pollInterval: 2_000 },\n\t);\n\n\tconst { events } = useSSE();\n\n\t// Filter SSE events for session_sample pushes (Step 5) and trigger an\n\t// immediate refetch when a new sample arrives, so the chart updates\n\t// between the 2s polls. The events array grows as new samples arrive; the\n\t// length-based dependency means the effect re-runs when a new sample event\n\t// lands (not on every poll). We debounce via a microtask guard.\n\tconst sampleEvents = useMemo(\n\t\t() => events.filter(isSessionSample),\n\t\t[events],\n\t);\n\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\trefetchTimeseries();\n\t}, [lastSampleTs, refetchSessions, refetchTimeseries]);\n\n\tif (dash0bOn && view === \"turns\") {\n\t\treturn <TurnMemoryView />;\n\t}\n\n\tif (sessionsErr && !sessionsData) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">\n\t\t\t\tError loading sessions: {sessionsErr.message}\n\t\t\t</div>\n\t\t);\n\t}\n\tif (timeseriesErr && !timeseriesData) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">\n\t\t\t\tError loading timeseries: {timeseriesErr.message}\n\t\t\t</div>\n\t\t);\n\t}\n\tif (!sessionsData) {\n\t\treturn <div className=\"tab-stub\">Loading sessions…</div>;\n\t}\n\n\tconst sessions = sessionsData.sessions;\n\tconst series = timeseriesData?.series ?? [];\n\tconst totals = timeseriesData?.totals ?? [];\n\tconst windowLabel =\n\t\tWINDOWS.find((w) => w.value === minutes)?.label ?? `${minutes}m`;\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<h2 className=\"font-heading text-lg font-semibold\">\n\t\t\t\t\tSession Memory Graph\n\t\t\t\t</h2>\n\t\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t\t{WINDOWS.map((w) => (\n\t\t\t\t\t\t<Toggle\n\t\t\t\t\t\t\tkey={w.value}\n\t\t\t\t\t\t\tpressed={minutes === w.value}\n\t\t\t\t\t\t\tonClick={() => setMinutes(w.value)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{w.label}\n\t\t\t\t\t\t</Toggle>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t{dash0bOn && (\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"flex items-center gap-2\"\n\t\t\t\t\trole=\"tablist\"\n\t\t\t\t\taria-label=\"Sessions views\"\n\t\t\t\t>\n\t\t\t\t\t<Toggle\n\t\t\t\t\t\tpressed={view === \"active\"}\n\t\t\t\t\t\tonClick={() => setView(\"active\")}\n\t\t\t\t\t>\n\t\t\t\t\t\tActive Sessions\n\t\t\t\t\t</Toggle>\n\t\t\t\t\t<Toggle\n\t\t\t\t\t\tpressed={view === \"turns\"}\n\t\t\t\t\t\tonClick={() => setView(\"turns\")}\n\t\t\t\t\t>\n\t\t\t\t\t\tTurn Memory\n\t\t\t\t\t</Toggle>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{sessions.length === 0 ? (\n\t\t\t\t<div className=\"text-sm text-muted-foreground\">No active sessions.</div>\n\t\t\t) : (\n\t\t\t\t<>\n\t\t\t\t\t<SummaryTiles sessions={sessionsData} />\n\t\t\t\t\t<SessionsMemoryChart series={series} totals={totals} />\n\t\t\t\t\t<h2 className=\"font-heading text-lg font-semibold\">\n\t\t\t\t\t\tActive Sessions\n\t\t\t\t\t</h2>\n\t\t\t\t\t<ActiveSessionsTable sessions={sessions} series={series} />\n\t\t\t\t\t<div className=\"text-xs text-muted-foreground\">\n\t\t\t\t\t\t{series.length} series · {totals.length} timestamps ·{\" \"}\n\t\t\t\t\t\t{windowLabel} window · updated{\" \"}\n\t\t\t\t\t\t{timeseriesData?.updatedAt ?? sessionsData.updatedAt}\n\t\t\t\t\t</div>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"],"names":["pivot","series","totals","map","sessionIds","pt","row","sid","t","a","b","fmtTs","ts","fmtTokens","value","n","gradId","sessionId","SessionsMemoryChart","data","useMemo","jsx","Card","CardContent","ResponsiveContainer","jsxs","AreaChart","s","CartesianGrid","XAxis","YAxis","v","Tooltip","Legend","Area","Line","HEADERS","fmtAge","ms","m","pctClass","pct","fmtPct","fmtWindow","tokens","window","Sparkline","points","color","min","range","w","h","stepX","segments","i","x","indexSeries","ActiveSessionsTable","sessions","seriesById","now","srs","sparkPts","d","bandVariant","band","sourceLabel","TurnMemoryView","turns","loading","error","useApi","useCallback","fetchTurns","intents","fetchTurnIntents","expanded","setExpanded","useState","detail","setDetail","detailLoading","setDetailLoading","busy","setBusy","notice","setNotice","expand","conversationId","fetchConversationTurns","onFork","turnIndex","out","postFork","e","onRewind","postTurnIntent","Badge","CardHeader","CardTitle","c","ConversationRow","TurnDetail","active","onExpand","Fragment","r","HydeDetailPanel","Button","isSessionSample","DASH_0B_KEY","dash0bEnabled","settings","cat","WINDOWS","SummaryTiles","combinedTokens","sum","maxWindow","max","combinedPct","SessionsTab","minutes","setMinutes","view","setView","settingsData","fetchSettings","dash0bOn","sessionsData","sessionsErr","refetchSessions","fetchSessions","timeseriesData","timeseriesErr","refetchTimeseries","fetchSessionTimeseries","events","useSSE","sampleEvents","lastSampleTs","useEffect","windowLabel","Toggle"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SessionsTab-nzd1408Z.js","sources":["../../src/components/SessionsMemoryChart.tsx","../../src/components/ActiveSessionsTable.tsx","../../src/tabs/SessionsTab/TurnMemoryView.tsx","../../src/tabs/SessionsTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/components/SessionsMemoryChart.tsx — Stacked memory graph (S39).\n *\n * Recharts stacked `<Area>` per session + total `<Line>` + `<Tooltip>` +\n * `<Legend>` + `<ResponsiveContainer>`. Data comes from `/api/sessions/timeseries`\n * which returns `SessionSeries[]` (per-session data points + stable hex color)\n * and a `totals[]` array (sum across all sessions per timestamp).\n *\n * PREVENT-PI-004: recharts is bundled into this localhost-served static\n * dashboard bundle; it makes no runtime network calls. Chart data arrives via\n * same-origin fetch to the dashboard server (loopback, ports 9320–9329).\n */\n\nimport type React from \"react\";\nimport { useMemo } from \"react\";\nimport {\n\tResponsiveContainer,\n\tAreaChart,\n\tArea,\n\tLine,\n\tXAxis,\n\tYAxis,\n\tCartesianGrid,\n\tTooltip,\n\tLegend,\n} from \"recharts\";\nimport type { SessionSeries } from \"@contracts\";\nimport { Card, CardContent } from \"../components/ui/card\";\n\nexport interface SessionsMemoryChartProps {\n\t/** Per-session series with stable colors (from /api/sessions/timeseries). */\n\tseries: SessionSeries[];\n\t/** Totals (sum across all sessions) per timestamp. */\n\ttotals: ReadonlyArray<{ ts: number; tokens: number }>;\n}\n\n/** A row in the pivoted data table passed to recharts `<AreaChart>`. */\ninterface PivotedRow {\n\t/** Unix timestamp (ms). */\n\tts: number;\n\t/** Total tokens across all sessions at this timestamp. */\n\ttotal: number;\n\t/** Per-session token count keyed by sessionId. */\n\t[sessionId: string]: number;\n}\n\n/**\n * Pivot the per-session series + totals into recharts' expected flat shape:\n * one row per unique timestamp, with each session's token count as a column\n * keyed by sessionId. Missing values for a session at a given timestamp are\n * filled with zero so the stack renders continuously.\n */\nfunction pivot(\n\tseries: SessionSeries[],\n\ttotals: ReadonlyArray<{ ts: number; tokens: number }>,\n): PivotedRow[] {\n\tconst map = new Map<number, PivotedRow>();\n\tconst sessionIds = series.map((s) => s.sessionId);\n\n\tfor (const s of series) {\n\t\tfor (const pt of s.data) {\n\t\t\tlet row = map.get(pt.ts);\n\t\t\tif (!row) {\n\t\t\t\trow = { ts: pt.ts, total: 0 } as PivotedRow;\n\t\t\t\tfor (const sid of sessionIds) row[sid] = 0;\n\t\t\t\tmap.set(pt.ts, row);\n\t\t\t}\n\t\t\trow[s.sessionId] = pt.tokens;\n\t\t}\n\t}\n\tfor (const t of totals) {\n\t\tlet row = map.get(t.ts);\n\t\tif (!row) {\n\t\t\trow = { ts: t.ts, total: 0 } as PivotedRow;\n\t\t\tfor (const sid of sessionIds) row[sid] = 0;\n\t\t\tmap.set(t.ts, row);\n\t\t}\n\t\trow.total = t.tokens;\n\t}\n\n\treturn [...map.values()].sort((a, b) => a.ts - b.ts);\n}\n\nfunction fmtTs(ts: number): string {\n\treturn new Date(ts).toLocaleTimeString([], {\n\t\thour: \"2-digit\",\n\t\tminute: \"2-digit\",\n\t\tsecond: \"2-digit\",\n\t});\n}\n\nfunction fmtTokens(value: number | string): string {\n\tconst n = Number(value);\n\treturn Number.isFinite(n) ? n.toLocaleString() : String(value);\n}\n\n/** Sanitize an arbitrary sessionId for use in an SVG gradient id. */\nfunction gradId(sessionId: string): string {\n\tconst safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n\treturn `grad-${safe}`;\n}\n\nexport function SessionsMemoryChart({\n\tseries,\n\ttotals,\n}: SessionsMemoryChartProps): React.ReactElement {\n\tconst data = useMemo(\n\t\t() => pivot(series, totals),\n\t\t[series, totals],\n\t);\n\n\tif (series.length === 0) {\n\t\treturn (\n\t\t\t<Card>\n\t\t\t\t<CardContent>No token samples in this window yet.</CardContent>\n\t\t\t</Card>\n\t\t);\n\t}\n\n\treturn (\n\t\t<Card>\n\t\t\t<CardContent>\n\t\t\t<ResponsiveContainer width=\"100%\" height={360}>\n\t\t\t\t<AreaChart\n\t\t\t\t\tdata={data}\n\t\t\t\t\tmargin={{ top: 8, right: 16, left: 0, bottom: 0 }}\n\t\t\t\t>\n\t\t\t\t\t<defs>\n\t\t\t\t\t\t{series.map((s) => (\n\t\t\t\t\t\t\t<linearGradient\n\t\t\t\t\t\t\t\tkey={`${s.sessionId}-grad`}\n\t\t\t\t\t\t\t\tid={gradId(s.sessionId)}\n\t\t\t\t\t\t\t\tx1=\"0\"\n\t\t\t\t\t\t\t\ty1=\"0\"\n\t\t\t\t\t\t\t\tx2=\"0\"\n\t\t\t\t\t\t\t\ty2=\"1\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<stop offset=\"5%\" stopColor={s.color} stopOpacity={0.7} />\n\t\t\t\t\t\t\t\t<stop offset=\"95%\" stopColor={s.color} stopOpacity={0.25} />\n\t\t\t\t\t\t\t</linearGradient>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</defs>\n\t\t\t\t\t<CartesianGrid strokeDasharray=\"3 3\" stroke=\"#30363d\" />\n\t\t\t\t\t<XAxis\n\t\t\t\t\t\tdataKey=\"ts\"\n\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\tdomain={[\"dataMin\", \"dataMax\"]}\n\t\t\t\t\t\ttickFormatter={(ts: number) => fmtTs(ts)}\n\t\t\t\t\t\tstroke=\"#8b949e\"\n\t\t\t\t\t\ttick={{ fontSize: 11 }}\n\t\t\t\t\t\tscale=\"time\"\n\t\t\t\t\t/>\n\t\t\t\t\t<YAxis\n\t\t\t\t\t\tstroke=\"#8b949e\"\n\t\t\t\t\t\ttick={{ fontSize: 11 }}\n\t\t\t\t\t\twidth={56}\n\t\t\t\t\t\ttickFormatter={(v: number) => fmtTokens(v)}\n\t\t\t\t\t/>\n\t\t\t\t\t<Tooltip\n\t\t\t\t\t\tlabelFormatter={(ts: number) => fmtTs(ts)}\n\t\t\t\t\t\tformatter={(value) =>\n\t\t\t\t\t\t\t[fmtTokens(value as number), \"tokens\"] as [string, string]\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontentStyle={{\n\t\t\t\t\t\t\tbackground: \"#161b22\",\n\t\t\t\t\t\t\tborder: \"1px solid #30363d\",\n\t\t\t\t\t\t\tborderRadius: \"6px\",\n\t\t\t\t\t\t\tcolor: \"#e6edf3\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tlabelStyle={{ color: \"#8b949e\", fontSize: 12 }}\n\t\t\t\t\t/>\n\t\t\t\t\t<Legend wrapperStyle={{ fontSize: 12 }} />\n\t\t\t\t\t{series.map((s) => (\n\t\t\t\t\t\t<Area\n\t\t\t\t\t\t\tkey={s.sessionId}\n\t\t\t\t\t\t\ttype=\"monotone\"\n\t\t\t\t\t\t\tdataKey={s.sessionId}\n\t\t\t\t\t\t\tname={s.label}\n\t\t\t\t\t\t\tstackId=\"1\"\n\t\t\t\t\t\t\tstroke={s.color}\n\t\t\t\t\t\t\tfill={`url(#${gradId(s.sessionId)})`}\n\t\t\t\t\t\t\tfillOpacity={1}\n\t\t\t\t\t\t\tisAnimationActive={false}\n\t\t\t\t\t\t\tdot={false}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t\t<Line\n\t\t\t\t\t\ttype=\"monotone\"\n\t\t\t\t\t\tdataKey=\"total\"\n\t\t\t\t\t\tname=\"Total\"\n\t\t\t\t\t\tstroke=\"#e6edf3\"\n\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t\tstrokeDasharray=\"4 2\"\n\t\t\t\t\t\tdot={false}\n\t\t\t\t\t\tisAnimationActive={false}\n\t\t\t\t\t/>\n\t\t\t\t</AreaChart>\n\t\t\t</ResponsiveContainer>\n\t\t\t</CardContent>\n\t\t</Card>\n\t);\n}\n","/**\n * dashboard-client/src/components/ActiveSessionsTable.tsx — Active sessions table (S39).\n *\n * Per-session rows: PID, Repo, Model, Context %, Tokens/Window,\n * Heartbeat age, State dir, Sparkline.\n *\n * Data from /api/sessions (active sessions list) and /api/sessions/timeseries\n * (per-session data points used to render inline sparklines).\n */\n\nimport type React from \"react\";\nimport type { ActiveSession, SessionSeries } from \"@contracts\";\nimport { Card, CardContent } from \"../components/ui/card\";\n\nexport interface ActiveSessionsTableProps {\n\t/** Active sessions, sorted by lastSeen descending (from /api/sessions). */\n\tsessions: ActiveSession[];\n\t/** Per-session timeseries used to render the inline sparkline column. */\n\tseries: SessionSeries[];\n}\n\nconst HEADERS = [\n\t\"PID\",\n\t\"Repo\",\n\t\"Model\",\n\t\"Context %\",\n\t\"Tokens / Window\",\n\t\"Last Heartbeat\",\n\t\"State Dir\",\n\t\"Trend\",\n] as const;\n\n/** Format a duration in milliseconds → human-readable age string. */\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 ${s % 60}s ago`;\n\tconst h = Math.floor(m / 60);\n\treturn `${h}h ${m % 60}m ago`;\n}\n\nfunction fmtTokens(n: number | null): string {\n\tif (n == null) return \"\\u2014\";\n\tif (n >= 100_000) return `${(n / 1000).toFixed(0)}k`;\n\tif (n >= 1000) return `${(n / 1000).toFixed(1)}k`;\n\treturn n.toLocaleString();\n}\n\nfunction pctClass(pct: number | null): string {\n\tif (pct == null) return \"sessions-pct-ok\";\n\tif (pct >= 85) return \"sessions-pct-err\";\n\tif (pct >= 60) return \"sessions-pct-warn\";\n\treturn \"sessions-pct-ok\";\n}\n\nfunction fmtPct(pct: number | null): string {\n\tif (pct == null) return \"\\u2014\";\n\treturn `${Math.round(pct)}%`;\n}\n\nfunction fmtWindow(tokens: number | null, window: number): string {\n\tif (tokens == null) return \"\\u2014\";\n\treturn `${fmtTokens(tokens)} / ${fmtTokens(window)}`;\n}\n\ninterface SparklineProps {\n\t/** Token counts over time (oldest → newest). */\n\tpoints: number[];\n\t/** Stable hex color for the stroke. */\n\tcolor: string;\n}\n\nfunction Sparkline({ points, color }: SparklineProps): React.ReactElement {\n\tif (points.length < 2) {\n\t\treturn <span className=\"sessions-sparkline-empty\">{\"\\u2014\"}</span>;\n\t}\n\tconst min = Math.min(...points);\n\tconst max = Math.max(...points);\n\tconst range = max - min || 1;\n\tconst w = 64;\n\tconst h = 18;\n\tconst stepX = w / (points.length - 1);\n\tconst segments = points.map((p, i) => {\n\t\tconst x = i * stepX;\n\t\tconst y = h - ((p - min) / range) * h;\n\t\treturn `${i === 0 ? \"M\" : \"L\"} ${x.toFixed(1)} ${y.toFixed(1)}`;\n\t});\n\treturn (\n\t\t<svg\n\t\t\tclassName=\"sessions-sparkline\"\n\t\t\twidth={w}\n\t\t\theight={h}\n\t\t\tviewBox={`0 0 ${w} ${h}`}\n\t\t\trole=\"img\"\n\t\t\taria-label=\"token trend\"\n\t\t>\n\t\t\t<path\n\t\t\t\td={segments.join(\" \")}\n\t\t\t\tfill=\"none\"\n\t\t\t\tstroke={color}\n\t\t\t\tstrokeWidth=\"1.5\"\n\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t/>\n\t\t</svg>\n\t);\n}\n\n/** Map sessionId → series for the sparkline column lookup. */\nfunction indexSeries(\n\tseries: SessionSeries[],\n): Map<string, SessionSeries> {\n\tconst m = new Map<string, SessionSeries>();\n\tfor (const s of series) m.set(s.sessionId, s);\n\treturn m;\n}\n\nexport function ActiveSessionsTable({\n\tsessions,\n\tseries,\n}: ActiveSessionsTableProps): React.ReactElement {\n\tconst seriesById = indexSeries(series);\n\tconst now = Date.now();\n\n\treturn (\n\t\t<Card>\n\t\t\t<CardContent>\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 !== 6 ? \" 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{sessions.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 sessions.\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{sessions.map((s) => {\n\t\t\t\t\t\t\tconst srs = seriesById.get(s.sessionId);\n\t\t\t\t\t\t\tconst sparkPts =\n\t\t\t\t\t\t\t\tsrs?.data.map((d) => d.tokens) ?? [];\n\t\t\t\t\t\t\tconst color = srs?.color ?? \"#58a6ff\";\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<tr\n\t\t\t\t\t\t\t\t\tkey={`${s.pid}:${s.sessionId}`}\n\t\t\t\t\t\t\t\t\tclassName=\"border-b border-border/50 hover:bg-bg-elevated/40\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-2 text-right font-mono\">{s.pid}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-2\" title={s.repoRoot ?? undefined}>\n\t\t\t\t\t\t\t\t\t\t{s.displayName || s.repoRoot || \"\\u2014\"}\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-2\">{s.model ?? \"\\u2014\"}</td>\n\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-2 text-right\">\n\t\t\t\t\t\t\t\t\t\t<span className={`sessions-pct-pill ${pctClass(s.percent)}`}>\n\t\t\t\t\t\t\t\t\t\t\t{fmtPct(s.percent)}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-2 text-right\">\n\t\t\t\t\t\t\t\t\t\t{fmtWindow(s.tokens, s.ctxWindow)}\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-2 text-right\">{fmtAge(now - s.lastSeen)}</td>\n\t\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\t\ttitle={s.stateDir ?? undefined}\n\t\t\t\t\t\t\t\t\t\tclassName=\"px-3 py-2 font-mono text-muted-foreground\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{s.stateDir\n\t\t\t\t\t\t\t\t\t\t\t? s.stateDir.split(\"/\").pop() || s.stateDir\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 className=\"px-3 py-2\">\n\t\t\t\t\t\t\t\t\t\t<Sparkline points={sparkPts} color={color} />\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/tabs/SessionsTab/TurnMemoryView.tsx — Turn-by-turn memory\n * tracking + recall (S52), moved VERBATIM from the top-level TurnsTab.tsx.\n *\n * DASH-0b: the Sessions surface absorbs the existent TurnsTab as a drill-down.\n * This file holds the byte-preserved turns body (the `TurnMemoryView`\n * component). The standalone `tabs/TurnsTab.tsx` is LEFT UNTOUCHED this sprint —\n * its copy stays live for flag-off / pre-DASH parity. A DASH-0d cleanup deletes\n * the standalone copy after a deep-link audit proves no live consumer points\n * at it. Only the export name changed (TurnsTab → TurnMemoryView); the render\n * body is otherwise identical.\n *\n * Fetches /api/turns (conversation list), expands the active conversation into\n * per-turn detail (/api/turns/conversation/:id), and renders:\n * - Conversation summary list (turn count, recall total, epochs, last turn).\n * - Per-turn rows: turn index, role, ctx tokens/percent + pressure band,\n * epoch id, and the injected-checkpoint recall set (the memory recalled\n * at each turn, with score + source).\n * - Pending rewind intents (S52A) + Fork action (S50C primitive).\n *\n * Read-mostly via /api/turns; fork/intent/prune via POST. No absolute URLs\n * (PREVENT-PI-004: loopback-only, same-origin static bundle).\n */\n\nimport type React from \"react\";\nimport { useCallback, useState } from \"react\";\nimport { useApi } from \"../../hooks/useApi\";\nimport {\n\tfetchTurns,\n\tfetchConversationTurns,\n\tfetchTurnIntents,\n\tpostFork,\n\tpostTurnIntent,\n} from \"../../api/client\";\nimport type {\n\tTurnsResponse,\n\tConversationTurnsResponse,\n\tRewindIntentsResponse,\n\tTurnRow,\n\tConversationSummary,\n} from \"@contracts\";\nimport { Card, CardContent, CardHeader, CardTitle } from \"../../components/ui/card\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { HydeDetailPanel } from \"../../components/HydeDetailPanel\";\n\nfunction fmtTs(ms: number): string {\n\tif (!ms) return \"—\";\n\treturn new Date(ms).toLocaleString();\n}\n\nfunction bandVariant(band: TurnRow[\"pressureBand\"]): \"success\" | \"warning\" | \"danger\" | \"default\" {\n\tif (band === \"green\") return \"success\";\n\tif (band === \"yellow\") return \"warning\";\n\tif (band === \"red\") return \"danger\";\n\treturn \"default\";\n}\n\nfunction sourceLabel(s: TurnRow[\"recall\"][number][\"source\"]): string {\n\tif (s === \"checkpoint\") return \"ckpt\";\n\tif (s === \"cluster_summary\") return \"raptor\";\n\treturn \"mem\";\n}\n\nexport function TurnMemoryView(): React.ReactElement {\n\tconst {\n\t\tdata: turns,\n\t\tloading,\n\t\terror,\n\t} = useApi<TurnsResponse>(\n\t\tuseCallback(() => fetchTurns(), []),\n\t\t{\n\t\t\tpollInterval: 10_000,\n\t\t},\n\t);\n\tconst { data: intents } = useApi<RewindIntentsResponse>(\n\t\tuseCallback(() => fetchTurnIntents(), []),\n\t\t{ pollInterval: 5_000 },\n\t);\n\tconst [expanded, setExpanded] = useState<string | null>(null);\n\tconst [detail, setDetail] = useState<ConversationTurnsResponse | null>(null);\n\tconst [detailLoading, setDetailLoading] = useState(false);\n\tconst [busy, setBusy] = useState<string | null>(null);\n\tconst [notice, setNotice] = useState<string | null>(null);\n\n\tconst expand = useCallback(\n\t\tasync (conversationId: string) => {\n\t\t\tif (expanded === conversationId) {\n\t\t\t\tsetExpanded(null);\n\t\t\t\tsetDetail(null);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsetExpanded(conversationId);\n\t\t\tsetDetailLoading(true);\n\t\t\tsetDetail(null);\n\t\t\ttry {\n\t\t\t\tconst d = await fetchConversationTurns(conversationId);\n\t\t\t\tsetDetail(d);\n\t\t\t} finally {\n\t\t\t\tsetDetailLoading(false);\n\t\t\t}\n\t\t},\n\t\t[expanded],\n\t);\n\n\tconst onFork = useCallback(\n\t\tasync (conversationId: string, turnIndex: number) => {\n\t\t\tsetBusy(`fork:${conversationId}:${turnIndex}`);\n\t\t\tsetNotice(null);\n\t\t\ttry {\n\t\t\t\tconst out = await postFork(conversationId, turnIndex);\n\t\t\t\tsetNotice(\n\t\t\t\t\t`Forked → ${out.childConversationId} (${out.recalledCount} recalled)`,\n\t\t\t\t);\n\t\t\t} catch (e) {\n\t\t\t\tsetNotice(`Fork failed: ${(e as Error).message}`);\n\t\t\t} finally {\n\t\t\t\tsetBusy(null);\n\t\t\t}\n\t\t},\n\t\t[],\n\t);\n\n\tconst onRewind = useCallback(\n\t\tasync (conversationId: string, turnIndex: number) => {\n\t\t\tsetBusy(`rewind:${conversationId}:${turnIndex}`);\n\t\t\tsetNotice(null);\n\t\t\ttry {\n\t\t\t\tawait postTurnIntent(conversationId, turnIndex);\n\t\t\t\tsetNotice(`Rewind intent queued for turn ${turnIndex}`);\n\t\t\t} catch (e) {\n\t\t\t\tsetNotice(`Rewind failed: ${(e as Error).message}`);\n\t\t\t} finally {\n\t\t\t\tsetBusy(null);\n\t\t\t}\n\t\t},\n\t\t[],\n\t);\n\n\tif (error && !turns) {\n\t\treturn <div className=\"tab-stub\">Error loading turns: {error.message}</div>;\n\t}\n\tif (loading && !turns) {\n\t\treturn <div className=\"tab-stub\">Loading turns…</div>;\n\t}\n\tif (!turns || turns.conversations.length === 0) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">\n\t\t\t\t<h3>Turn-by-turn memory</h3>\n\t\t\t\t<p>\n\t\t\t\t\tNo turns recorded yet. Per-turn tracking starts when{\" \"}\n\t\t\t\t\t<code>MEGACOMPACT_TURNS_DB=1</code> and the session runs through a\n\t\t\t\t\tcompaction. Each turn records its context metrics + the checkpoints\n\t\t\t\t\trecalled into it.\n\t\t\t\t</p>\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<h3 className=\"font-heading text-lg font-semibold\">\n\t\t\t\tTurn-by-turn memory tracking + recall\n\t\t\t</h3>\n\t\t\t{notice && <Badge variant=\"warning\">{notice}</Badge>}\n\n\t\t\t{intents && intents.intents.length > 0 && (\n\t\t\t\t<Card>\n\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t<CardTitle>\n\t\t\t\t\t\t\tPending rewind intents ({intents.intents.length})\n\t\t\t\t\t\t</CardTitle>\n\t\t\t\t\t</CardHeader>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<ul className=\"list-disc space-y-1 pl-5\">\n\t\t\t\t\t\t\t{intents.intents.map((i) => (\n\t\t\t\t\t\t\t\t<li key={i.id}>\n\t\t\t\t\t\t\t\t\t{fmtTs(i.createdAt)} — rewind{\" \"}\n\t\t\t\t\t\t\t\t\t<code>{i.conversationId}</code> to turn {i.targetTurnIndex}\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t)}\n\n\t\t\t<Card>\n\t\t\t\t<CardHeader>\n\t\t\t\t\t<CardTitle>\n\t\t\t\t\t\tConversations ({turns.conversations.length})\n\t\t\t\t\t</CardTitle>\n\t\t\t\t</CardHeader>\n\t\t\t\t<CardContent>\n\t\t\t\t\t<table className=\"w-full border-collapse text-sm\">\n\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Conversation</th>\n\t\t\t\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Turns</th>\n\t\t\t\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Recall</th>\n\t\t\t\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Epochs</th>\n\t\t\t\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Avg ctx%</th>\n\t\t\t\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Last turn</th>\n\t\t\t\t\t\t\t\t<th className=\"border-b border-border px-3 py-2\"></th>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t{turns.conversations.map((c: ConversationSummary) => (\n\t\t\t\t\t\t\t\t<ConversationRow\n\t\t\t\t\t\t\t\t\tkey={c.conversationId}\n\t\t\t\t\t\t\t\t\tc={c}\n\t\t\t\t\t\t\t\t\tactive={turns.activeConversationId === c.conversationId}\n\t\t\t\t\t\t\t\t\texpanded={expanded === c.conversationId}\n\t\t\t\t\t\t\t\t\tonExpand={() => expand(c.conversationId)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</tbody>\n\t\t\t\t\t</table>\n\t\t\t\t</CardContent>\n\t\t\t</Card>\n\n\t\t\t{expanded && (\n\t\t\t\t<Card>\n\t\t\t\t\t<CardHeader>\n\t\t\t\t\t\t<CardTitle>\n\t\t\t\t\t\t\tTurns in <code>{expanded}</code>\n\t\t\t\t\t\t</CardTitle>\n\t\t\t\t\t</CardHeader>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t{detailLoading ? (\n\t\t\t\t\t\t\t<div className=\"text-sm text-muted-foreground\">Loading turns…</div>\n\t\t\t\t\t\t) : detail ? (\n\t\t\t\t\t\t\t<TurnDetail\n\t\t\t\t\t\t\t\tdetail={detail}\n\t\t\t\t\t\t\t\tbusy={busy}\n\t\t\t\t\t\t\t\tonFork={onFork}\n\t\t\t\t\t\t\t\tonRewind={onRewind}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<div className=\"text-sm text-muted-foreground\">No detail.</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction ConversationRow({\n\tc,\n\tactive,\n\texpanded,\n\tonExpand,\n}: {\n\tc: ConversationSummary;\n\tactive: boolean;\n\texpanded: boolean;\n\tonExpand: () => void;\n}): React.ReactElement {\n\treturn (\n\t\t<>\n\t\t\t<tr\n\t\t\t\tclassName={`border-b border-border/50 hover:bg-bg-elevated/40 ${\n\t\t\t\t\tactive ? \"bg-primary/10\" : \"\"\n\t\t\t\t}`}\n\t\t\t\tonClick={onExpand}\n\t\t\t\tstyle={{ cursor: \"pointer\" }}\n\t\t\t>\n\t\t\t\t<td className=\"px-3 py-2\">\n\t\t\t\t\t{expanded ? \"▾\" : \"▸\"} <code>{c.conversationId}</code>\n\t\t\t\t\t{active && <Badge variant=\"accent\" className=\"ml-2\">active</Badge>}\n\t\t\t\t</td>\n\t\t\t\t<td className=\"px-3 py-2 text-right\">{c.turnCount}</td>\n\t\t\t\t<td className=\"px-3 py-2 text-right\">{c.totalRecall}</td>\n\t\t\t\t<td className=\"px-3 py-2 text-right\">{c.epochCount}</td>\n\t\t\t\t<td className=\"px-3 py-2 text-right\">{c.avgCtxPercent.toFixed(0)}%</td>\n\t\t\t\t<td className=\"px-3 py-2\">{fmtTs(c.lastTurnAt)}</td>\n\t\t\t\t<td className=\"px-3 py-2\" />\n\t\t\t</tr>\n\t\t</>\n\t);\n}\n\nfunction TurnDetail({\n\tdetail,\n\tbusy,\n\tonFork,\n\tonRewind,\n}: {\n\tdetail: ConversationTurnsResponse;\n\tbusy: string | null;\n\tonFork: (conversationId: string, turnIndex: number) => void;\n\tonRewind: (conversationId: string, turnIndex: number) => void;\n}): React.ReactElement {\n\treturn (\n\t\t<table className=\"w-full border-collapse text-sm\">\n\t\t\t<thead>\n\t\t\t\t<tr>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">#</th>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Role</th>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Ctx</th>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Band</th>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Epoch</th>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Recalled checkpoints (memory recall)</th>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">HyDE</th>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Ended</th>\n\t\t\t\t\t<th className=\"border-b border-border px-3 py-2 text-left font-medium text-muted-foreground\">Actions</th>\n\t\t\t\t</tr>\n\t\t\t</thead>\n\t\t\t<tbody>\n\t\t\t\t{detail.turns.map((t) => (\n\t\t\t\t\t<tr\n\t\t\t\t\t\tkey={`${t.conversationId}:${t.turnIndex}`}\n\t\t\t\t\t\tclassName=\"border-b border-border/50 hover:bg-bg-elevated/40\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<td className=\"px-3 py-2 text-right\">{t.turnIndex}</td>\n\t\t\t\t\t\t<td className=\"px-3 py-2\">{t.role}</td>\n\t\t\t\t\t\t<td className=\"px-3 py-2\">\n\t\t\t\t\t\t\t{t.ctxTokens ?? \"—\"}\n\t\t\t\t\t\t\t{t.ctxPercent != null && (\n\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t{\" \"}\n\t\t\t\t\t\t\t\t\t· {t.ctxPercent.toFixed(0)}%\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td className=\"px-3 py-2\">\n\t\t\t\t\t\t\t<Badge variant={bandVariant(t.pressureBand)}>\n\t\t\t\t\t\t\t\t{t.pressureBand ?? \"—\"}\n\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td className=\"px-3 py-2\">{t.epochId ? <code>{t.epochId.slice(0, 8)}</code> : \"—\"}</td>\n\t\t\t\t\t\t<td className=\"px-3 py-2\">\n\t\t\t\t\t\t\t{t.recall.length === 0 ? (\n\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground\">—</span>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<ul className=\"space-y-1\">\n\t\t\t\t\t\t\t\t\t{t.recall.map((r) => (\n\t\t\t\t\t\t\t\t\t\t<li key={r.checkpointId}>\n\t\t\t\t\t\t\t\t\t\t\t<code>{r.checkpointId.slice(0, 12)}</code>{\" \"}\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t{sourceLabel(r.source)} · {r.score.toFixed(2)}\n\t\t\t\t\t\t\t\t\t\t\t\t{r.raptorLevel != null ? ` · L${r.raptorLevel}` : \"\"}\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td className=\"px-3 py-2 align-top\">\n\t\t\t\t\t\t\t<HydeDetailPanel\n\t\t\t\t\t\t\t\tconversationId={t.conversationId}\n\t\t\t\t\t\t\t\tturnIndex={t.turnIndex}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td className=\"px-3 py-2\">{fmtTs(t.endedAt)}</td>\n\t\t\t\t\t\t<td className=\"px-3 py-2\">\n\t\t\t\t\t\t\t<div className=\"flex gap-2\">\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\tvariant=\"outline\"\n\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\tdisabled={busy !== null}\n\t\t\t\t\t\t\t\t\tonClick={() => onFork(t.conversationId, t.turnIndex)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\tfork\n\t\t\t\t\t\t\t\t</Button>\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\tvariant=\"outline\"\n\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\tdisabled={busy !== null}\n\t\t\t\t\t\t\t\t\tonClick={() => onRewind(t.conversationId, t.turnIndex)}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\trewind\n\t\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\n\t\t\t\t))}\n\t\t\t</tbody>\n\t\t</table>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/SessionsTab.tsx — Sessions tab (S39, DASH-0b).\n *\n * DASH-0b: the Sessions surface absorbs the existent TurnsTab as a drill-down.\n * A `SessionsViews` toggle (\"Active Sessions\" / \"Turn Memory\") switches between\n * the existent sessions summary/chart/table body and the turns view (rendered by\n * `SessionsTab/TurnMemoryView.tsx` — the turns body moved VERBATIM from the\n * standalone TurnsTab.tsx, which is left untouched this sprint for flag-off\n * parity).\n *\n * Flag: `MEGACOMPACT_DASH_0B` default ON. The dashboard client is a browser\n * bundle with NO `process` global, so the positive sprint flag cannot be read\n * server-side-style (`process.env`) inside the client. Instead the flag is read\n * from the server-authoritative `/api/rag-settings` state: the server resolves\n * `process.env[\"MEGACOMPACT_DASH_0B\"] ?? default` into the `SettingState.value`\n * boolean. When the flag is OFF (settings confirmed value=false), this surface\n * renders ONLY the existent sessions body — no toggle, no TurnMemoryView branch\n * (byte-identical predecessor). The standalone TurnsTab.tsx top-level surface is\n * untouched and remains reachable for flag-off parity.\n *\n * Data sources: fetchSessions() + fetchSessionTimeseries(minutes). Both poll\n * every 2s for near-real-time updates. useSSE() listens for session_sample\n * events emitted by appendTokenSample (Step 5) so the chart refetches\n * instantly between polls when a new token sample is appended to events.log.\n *\n * Empty state: shows \"No active sessions.\" when the /api/sessions response\n * returns an empty array (e.g. no pi processes are running yet).\n */\n\nimport type React from \"react\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { useApi } from \"../hooks/useApi\";\nimport { useSSE } from \"../hooks/useSSE\";\nimport { fetchSessions, fetchSessionTimeseries, fetchSettings } from \"../api/client\";\nimport type {\n\tSseEvent,\n\tSseSessionSample,\n\tSessionsResponse,\n\tSessionTimeseriesResponse,\n\tSettingsResponse,\n} from \"@contracts\";\nimport { SessionsMemoryChart } from \"../components/SessionsMemoryChart\";\nimport { ActiveSessionsTable } from \"../components/ActiveSessionsTable\";\nimport { Toggle } from \"../components/ui/toggle\";\nimport { Card, CardContent } from \"../components/ui/card\";\nimport { TurnMemoryView } from \"./SessionsTab/TurnMemoryView\";\n\n/**\n * Shape of the {@link SseSessionSample} SSE event appended to events.log by\n * `appendTokenSample` (src/store/sqlite/global-index.ts). The contract now\n * defines this variant as part of the {@link SseEvent} union (Step 5); the\n * local alias keeps the surface terser in this file.\n */\ntype SessionSampleEvent = SseSessionSample;\n\n/** Type guard: narrows an SSE event to a session_sample event. */\nfunction isSessionSample(\n\te: SseEvent,\n): e is SessionSampleEvent {\n\treturn e.type === \"session_sample\";\n}\n\nconst DASH_0B_KEY = \"MEGACOMPACT_DASH_0B\";\n\n/** Resolve the DASH-0b consolidation flag from the server settings state.\n * Absent/not-yet-loaded => false (flag-off posture), so flag-off users never\n * see a toggle flash; the toggle appears only once settings confirm it is ON. */\nfunction dash0bEnabled(settings: SettingsResponse | null): boolean {\n\tif (!settings) return false;\n\tfor (const cat of settings.categories) {\n\t\tfor (const s of cat.settings) {\n\t\t\tif (s.key === DASH_0B_KEY && s.type === \"boolean\") return s.value === true;\n\t\t}\n\t}\n\treturn false;\n}\n\nconst WINDOWS: ReadonlyArray<{ value: number; label: string }> = [\n\t{ value: 5, label: \"5m\" },\n\t{ value: 15, label: \"15m\" },\n\t{ value: 30, label: \"30m\" },\n\t{ value: 60, label: \"60m\" },\n] as const;\n\ninterface SummaryTilesProps {\n\tsessions: SessionsResponse;\n}\n\nfunction SummaryTiles({ sessions }: SummaryTilesProps): React.ReactElement {\n\tconst active = sessions.sessions.length;\n\tconst combinedTokens = sessions.sessions.reduce(\n\t\t(sum, s) => sum + (s.tokens ?? 0),\n\t\t0,\n\t);\n\tconst maxWindow = sessions.sessions.reduce(\n\t\t(max, s) => Math.max(max, s.ctxWindow),\n\t\t0,\n\t);\n\tconst combinedPct = maxWindow > 0 ? (combinedTokens / maxWindow) * 100 : 0;\n\treturn (\n\t\t<div className=\"grid grid-cols-2 gap-4 md:grid-cols-4\">\n\t\t\t<Card>\n\t\t\t\t<CardContent>\n\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">Active sessions</span>\n\t\t\t\t\t<div className=\"text-xl font-semibold\">{active}</div>\n\t\t\t\t</CardContent>\n\t\t\t</Card>\n\t\t\t<Card>\n\t\t\t\t<CardContent>\n\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">Combined tokens</span>\n\t\t\t\t\t<div className=\"text-xl font-semibold\">\n\t\t\t\t\t\t{combinedTokens >= 100_000\n\t\t\t\t\t\t\t? `${(combinedTokens / 1000).toFixed(0)}k`\n\t\t\t\t\t\t\t: combinedTokens.toLocaleString()}\n\t\t\t\t\t</div>\n\t\t\t\t</CardContent>\n\t\t\t</Card>\n\t\t\t<Card>\n\t\t\t\t<CardContent>\n\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">\n\t\t\t\t\t\tCombined % of max window\n\t\t\t\t\t</span>\n\t\t\t\t\t<div className=\"text-xl font-semibold\">{Math.round(combinedPct)}%</div>\n\t\t\t\t</CardContent>\n\t\t\t</Card>\n\t\t\t<Card>\n\t\t\t\t<CardContent>\n\t\t\t\t\t<span className=\"text-xs text-muted-foreground\">Pruned (stale)</span>\n\t\t\t\t\t<div className=\"text-xl font-semibold\">{sessions.pruned}</div>\n\t\t\t\t</CardContent>\n\t\t\t</Card>\n\t\t</div>\n\t);\n}\n\ntype SessionsView = \"active\" | \"turns\";\n\nexport default function SessionsTab(): React.ReactElement {\n\tconst [minutes, setMinutes] = useState(30);\n\tconst [view, setView] = useState<SessionsView>(\"active\");\n\n\tconst {\n\t\tdata: settingsData,\n\t} = useApi<SettingsResponse>(\n\t\tuseCallback(() => fetchSettings(), []),\n\t\t{ pollInterval: 0, maxRetries: 0 },\n\t);\n\tconst dash0bOn = dash0bEnabled(settingsData);\n\n\tconst {\n\t\tdata: sessionsData,\n\t\terror: sessionsErr,\n\t\trefetch: refetchSessions,\n\t} = useApi<SessionsResponse>(\n\t\tuseCallback(() => fetchSessions(), []),\n\t\t{ pollInterval: 2_000 },\n\t);\n\n\tconst {\n\t\tdata: timeseriesData,\n\t\terror: timeseriesErr,\n\t\trefetch: refetchTimeseries,\n\t} = useApi<SessionTimeseriesResponse>(\n\t\tuseCallback(() => fetchSessionTimeseries(minutes), [minutes]),\n\t\t{ pollInterval: 2_000 },\n\t);\n\n\tconst { events } = useSSE();\n\n\t// Filter SSE events for session_sample pushes (Step 5) and trigger an\n\t// immediate refetch when a new sample arrives, so the chart updates\n\t// between the 2s polls. The events array grows as new samples arrive; the\n\t// length-based dependency means the effect re-runs when a new sample event\n\t// lands (not on every poll). We debounce via a microtask guard.\n\tconst sampleEvents = useMemo(\n\t\t() => events.filter(isSessionSample),\n\t\t[events],\n\t);\n\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\trefetchTimeseries();\n\t}, [lastSampleTs, refetchSessions, refetchTimeseries]);\n\n\tif (dash0bOn && view === \"turns\") {\n\t\treturn <TurnMemoryView />;\n\t}\n\n\tif (sessionsErr && !sessionsData) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">\n\t\t\t\tError loading sessions: {sessionsErr.message}\n\t\t\t</div>\n\t\t);\n\t}\n\tif (timeseriesErr && !timeseriesData) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">\n\t\t\t\tError loading timeseries: {timeseriesErr.message}\n\t\t\t</div>\n\t\t);\n\t}\n\tif (!sessionsData) {\n\t\treturn <div className=\"tab-stub\">Loading sessions…</div>;\n\t}\n\n\tconst sessions = sessionsData.sessions;\n\tconst series = timeseriesData?.series ?? [];\n\tconst totals = timeseriesData?.totals ?? [];\n\tconst windowLabel =\n\t\tWINDOWS.find((w) => w.value === minutes)?.label ?? `${minutes}m`;\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<h2 className=\"font-heading text-lg font-semibold\">\n\t\t\t\t\tSession Memory Graph\n\t\t\t\t</h2>\n\t\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t\t{WINDOWS.map((w) => (\n\t\t\t\t\t\t<Toggle\n\t\t\t\t\t\t\tkey={w.value}\n\t\t\t\t\t\t\tpressed={minutes === w.value}\n\t\t\t\t\t\t\tonClick={() => setMinutes(w.value)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{w.label}\n\t\t\t\t\t\t</Toggle>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t{dash0bOn && (\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"flex items-center gap-2\"\n\t\t\t\t\trole=\"tablist\"\n\t\t\t\t\taria-label=\"Sessions views\"\n\t\t\t\t>\n\t\t\t\t\t<Toggle\n\t\t\t\t\t\tpressed={view === \"active\"}\n\t\t\t\t\t\tonClick={() => setView(\"active\")}\n\t\t\t\t\t>\n\t\t\t\t\t\tActive Sessions\n\t\t\t\t\t</Toggle>\n\t\t\t\t\t<Toggle\n\t\t\t\t\t\tpressed={view === \"turns\"}\n\t\t\t\t\t\tonClick={() => setView(\"turns\")}\n\t\t\t\t\t>\n\t\t\t\t\t\tTurn Memory\n\t\t\t\t\t</Toggle>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{sessions.length === 0 ? (\n\t\t\t\t<div className=\"text-sm text-muted-foreground\">No active sessions.</div>\n\t\t\t) : (\n\t\t\t\t<>\n\t\t\t\t\t<SummaryTiles sessions={sessionsData} />\n\t\t\t\t\t<SessionsMemoryChart series={series} totals={totals} />\n\t\t\t\t\t<h2 className=\"font-heading text-lg font-semibold\">\n\t\t\t\t\t\tActive Sessions\n\t\t\t\t\t</h2>\n\t\t\t\t\t<ActiveSessionsTable sessions={sessions} series={series} />\n\t\t\t\t\t<div className=\"text-xs text-muted-foreground\">\n\t\t\t\t\t\t{series.length} series · {totals.length} timestamps ·{\" \"}\n\t\t\t\t\t\t{windowLabel} window · updated{\" \"}\n\t\t\t\t\t\t{timeseriesData?.updatedAt ?? sessionsData.updatedAt}\n\t\t\t\t\t</div>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"],"names":["pivot","series","totals","map","sessionIds","pt","row","sid","t","a","b","fmtTs","ts","fmtTokens","value","n","gradId","sessionId","SessionsMemoryChart","data","useMemo","jsx","Card","CardContent","ResponsiveContainer","jsxs","AreaChart","s","CartesianGrid","XAxis","YAxis","v","Tooltip","Legend","Area","Line","HEADERS","fmtAge","ms","m","pctClass","pct","fmtPct","fmtWindow","tokens","window","Sparkline","points","color","min","range","w","h","stepX","segments","i","x","indexSeries","ActiveSessionsTable","sessions","seriesById","now","srs","sparkPts","d","bandVariant","band","sourceLabel","TurnMemoryView","turns","loading","error","useApi","useCallback","fetchTurns","intents","fetchTurnIntents","expanded","setExpanded","useState","detail","setDetail","detailLoading","setDetailLoading","busy","setBusy","notice","setNotice","expand","conversationId","fetchConversationTurns","onFork","turnIndex","out","postFork","e","onRewind","postTurnIntent","Badge","CardHeader","CardTitle","c","ConversationRow","TurnDetail","active","onExpand","Fragment","r","HydeDetailPanel","Button","isSessionSample","DASH_0B_KEY","dash0bEnabled","settings","cat","WINDOWS","SummaryTiles","combinedTokens","sum","maxWindow","max","combinedPct","SessionsTab","minutes","setMinutes","view","setView","settingsData","fetchSettings","dash0bOn","sessionsData","sessionsErr","refetchSessions","fetchSessions","timeseriesData","timeseriesErr","refetchTimeseries","fetchSessionTimeseries","events","useSSE","sampleEvents","lastSampleTs","useEffect","windowLabel","Toggle"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{r as s,j as e,h as P,i as ee,k as te,p as ce,l as de,m as me,C as ue,n as he,o as se,q as fe,s as ne,t as K,v as ge,u as J,w as re,A as ae}from"./index-BZcYzeCr.js";import{S as pe}from"./switch-DhQfmSFD.js";import{f as xe,p as be,d as ye}from"./client-extra-CgeDg1Md.js";import{V as je}from"./VcStatusBadge-XGMW6u62.js";import{T as ve}from"./toggle-B3gNAVog.js";function Se(t){try{return new Date(t*1e3).toLocaleString()}catch{return"—"}}function le({achievements:t}){const r=s.useRef(0),[n,a]=s.useState(null),l=t.reduce((i,u)=>Math.max(i,u.unlocked_at??0),0),o=r.current;s.useEffect(()=>{l>r.current&&(r.current=l)},[l]),s.useEffect(()=>{if(o>0&&l>o){const i=t.filter(u=>u.unlocked_at!=null&&(u.unlocked_at??0)>o);if(i.length>0){const u=i.map(d=>`${d.icon??""} ${d.title}`.trim()).join(", ")+" unlocked!";a(u);const g=setTimeout(()=>a(null),4e3);return()=>clearTimeout(g)}}},[t,l,o]);const m=t.filter(i=>!(i.hidden===1&&i.unlocked_at==null));return e.jsxs("div",{className:"ach-section",children:[n!=null&&e.jsx("div",{className:"ach-toast show",children:n}),e.jsxs("div",{className:"ach-tiles",children:[m.length===0&&e.jsx("span",{className:"repo-none",children:"no achievements yet"}),m.map(i=>{if(i.unlocked_at!=null){const u=o>0&&(i.unlocked_at??0)>o;return e.jsxs("div",{className:`ach-tile unlocked${u?" just-unlocked":""}`,children:[i.icon??""," ",i.title,e.jsxs("span",{className:"ach-detail",children:["unlocked ",Se(i.unlocked_at)]})]},i.id)}return e.jsxs("div",{className:"ach-tile locked",children:["??? ",i.title]},i.id)})]})]})}function D(t){return(Math.round(t*10)/10).toString()+"%"}function H(t){return t!=null?new Date(t).toLocaleString():"—"}function G(t){return t&&typeof t=="object"?t:{}}function we(t){return t.split("/").pop()||t}function $({title:t,rows:r,badge:n,renderValue:a}){return e.jsxs("div",{className:"lb-card",children:[e.jsxs("h3",{children:[t,n]}),r.length===0?e.jsx("div",{className:"lb-empty",children:"—"}):e.jsx("table",{children:e.jsx("tbody",{children:r.map((l,o)=>e.jsxs("tr",{children:[e.jsx("td",{title:l.repo_root,children:we(l.repo_root)}),e.jsx("td",{className:"num",children:a(l)})]},`${l.repo_root}-${o}`))})})]})}function ke(){const[t,r]=s.useState({}),[n,a]=s.useState(0),[l,o]=s.useState([]),[m,i]=s.useState(!1),[u,g]=s.useState(!0),[d,b]=s.useState(null),c=s.useRef(0),h=s.useCallback(async()=>{try{const[j,x,R,A,W,F]=await Promise.all([P({metric:"cache",limit:25}),P({metric:"dedupe",limit:25}),P({metric:"turns",limit:25}),P({metric:"mega_cache",limit:25}),P({metric:"repos",limit:1}),ee()]),_=A.find(O=>O.ts>c.current&&O.value>100);c.current>0&&_&&(b(`oopsie! cache went to ${Math.round(_.value)}% — MEGA CACHE 🥧`),setTimeout(()=>b(null),4e3)),A.length>0&&(c.current=Math.max(...A.map(O=>O.ts))),r({cache:j,dedupe:x,turns:R,mega_cache:A}),a(W[0]?.value??0),o(F)}catch{}finally{g(!1)}},[]);s.useEffect(()=>{let j=!0;const x=async()=>{j&&await h()};x();const R=setInterval(()=>void x(),15e3);return()=>{j=!1,clearInterval(R)}},[h]),s.useEffect(()=>{let j=!0;const x=async()=>{try{const A=await te();j&&(i(!!A.game_mode_on),A.theme&&(document.documentElement.dataset.theme=A.theme))}catch{}};x();const R=setInterval(()=>void x(),15e3);return()=>{j=!1,clearInterval(R)}},[]);const y=t.mega_cache??[];let v=null,w=null;for(const j of y){(v==null||j.value>v)&&(v=j.value);const x=G(j.meta),R=x.firstSeenTs??x.firstSeen??j.ts;(w==null||R<w)&&(w=R)}const N=v!=null&&v>100,p=t.turns??[],T=p.reduce((j,x)=>Math.max(j,x.value),0),E=Math.floor(Math.log2(T+1))+1,B=(t.cache?.length??0)>0||(t.dedupe?.length??0)>0||p.length>0||y.length>0||n>0;return e.jsxs("div",{className:`game-tab${m?" game-mode-on":""}`,children:[d!=null&&e.jsx("div",{className:"mega-cache-toast show",children:d}),N&&e.jsxs("div",{className:"mega-cache-banner",children:["🥧"," MEGA CACHE! peak ",D(v)," — first reached ",H(w)]}),N&&e.jsxs("div",{className:"achievement-tile unlocked",children:["🏆"," Opie's Wild Ride",e.jsxs("span",{className:"ach-detail",children:["best ",D(v)," · first ",H(w)]})]}),e.jsx("h2",{children:"High Scores"}),!B&&!u&&e.jsx("div",{className:"game-empty",children:"No scores yet — run a session with game mode on."}),B&&e.jsxs("div",{className:"game-leaderboards",children:[e.jsx($,{title:"Cache %",rows:t.cache??[],renderValue:j=>D(j.value)}),e.jsx($,{title:"Dedupe (collapsed)",rows:t.dedupe??[],renderValue:j=>j.value.toLocaleString()}),e.jsx($,{title:"Turns",rows:p,badge:p.length>0?e.jsxs("span",{className:"lvl-badge",children:["LVL ",E]}):void 0,renderValue:j=>j.value.toLocaleString()}),e.jsx($,{title:"MEGA CACHE trophies",rows:y,renderValue:j=>e.jsxs(e.Fragment,{children:[D(j.value),e.jsx("span",{className:"lb-meta",children:H(G(j.meta).firstSeenTs??G(j.meta).firstSeen??j.ts)})]})})]}),n>0&&e.jsx("div",{className:"repos-badge-line",children:e.jsxs("span",{className:"repos-badge",children:[n," repos"]})}),e.jsx("h3",{children:"Achievements"}),e.jsx(le,{achievements:l})]})}function Ce(){const[t,r]=s.useState([]),[n,a]=s.useState(!0),[l,o]=s.useState(null),m=s.useCallback(async()=>{try{const i=await ee();r(i),o(null)}catch(i){o(i instanceof Error?i:new Error(String(i)))}finally{a(!1)}},[]);return s.useEffect(()=>{let i=!0;const u=async()=>{i&&await m()};u();const g=setInterval(()=>void u(),15e3);return()=>{i=!1,clearInterval(g)}},[m]),n&&t.length===0?e.jsx("div",{className:"tab-stub",children:"Loading achievements…"}):l&&t.length===0?e.jsxs("div",{className:"tab-stub",children:["Error: ",l.message]}):e.jsxs("div",{className:"achievements-tab",children:[e.jsx("h2",{children:"Achievements"}),e.jsx(le,{achievements:t})]})}const oe=[{id:"transparent",label:"Transparent (accents only)",css:{bg:null,fg:"#c9d1d9",accent:"#3fb950",mega:"#f0883e"},ansi:{bg:null,fg:"39",accent:"32",mega:"33"}},{id:"retro",label:"Retro 8-bit green",css:{bg:"#003300",fg:"#33ff33",accent:"#00ff41",mega:"#39ff14"},ansi:{bg:"40",fg:"92",accent:"92",mega:"1;92"}},{id:"orange-bold",label:"Orange bold",css:{bg:"#1a0f00",fg:"#ff8c00",accent:"#ff6b00",mega:"#ff4500"},ansi:{bg:"48;5;52",fg:"38;5;208",accent:"38;5;208",mega:"1;38;5;202"}},{id:"cyan-neon",label:"Cyan neon",css:{bg:"#001a1a",fg:"#00ffff",accent:"#22d3ee",mega:"#7df9ff"},ansi:{bg:"48;5;23",fg:"38;5;51",accent:"38;5;51",mega:"1;38;5;51"}},{id:"amber-mono",label:"Amber phosphor",css:{bg:"#1a1200",fg:"#ffb000",accent:"#ff8c00",mega:"#ff5500"},ansi:{bg:"48;5;58",fg:"38;5;214",accent:"38;5;214",mega:"1;38;5;208"}},{id:"grayscale",label:"Grayscale minimal",css:{bg:"#161616",fg:"#b0b0b0",accent:"#8b949e",mega:"#e6edf3"},ansi:{bg:"48;5;235",fg:"38;5;249",accent:"38;5;249",mega:"1;38;5;255"}}],V=oe.map(t=>t.id),z={gameMode:"Turn game mode on/off (themes the widget + dashboard)",theme:"Visual theme (applies instantly)",tuiMode:"TUI widget display density",tier:"Live pressure band — climbs low→mega as context fills the window.",preset:"The env-resolved base compaction preset (low/medium/high/ultra/mega) that set the token threshold.",pressure:"Live pressure = currentTokens / threshold — % of the model context window (threshold fires at the tier's % of window).",threshold:"Compaction threshold = tierPct × model context window — mega-compact trims BELOW pi's native ~80% auto-compact for any model size.",fastGate:"Fast-gate arming floor — the live trim arms once context passes this % of the window."};function Ne(t,r,n){let a=t.toLocaleString();return r!=null&&n>0&&(a+=` (${Math.round(r*100)}% of ${n.toLocaleString()})`),a}function Ee(t){return`${Math.round((t||0)*100)}%`}function Te(){const[t,r]=s.useState(null),[n,a]=s.useState(null),[l,o]=s.useState(!1);s.useEffect(()=>{let c=!0;const h=async()=>{try{const v=await de();c&&r(v)}catch{}};h();const y=setInterval(()=>void h(),5e3);return()=>{c=!1,clearInterval(y)}},[]),s.useEffect(()=>{let c=!0;const h=async()=>{try{const v=await te();c&&(a(v),v.theme&&(document.documentElement.dataset.theme=v.theme))}catch{}};h();const y=setInterval(()=>void h(),5e3);return()=>{c=!1,clearInterval(y)}},[]);const m=s.useCallback(async c=>{o(!0);try{const h=await ce(c);a(h),h.theme&&(document.documentElement.dataset.theme=h.theme)}catch{}o(!1)},[]),i=n?.game_mode_on??!1,u=n?.theme??"transparent",g=n?.tui_display_mode??"full",d=t?.config,b=t?.context.contextWindow??0;return e.jsxs("div",{className:"config-tab",children:[e.jsxs("section",{className:"config-settings",children:[e.jsx("h3",{children:"Settings"}),e.jsx("div",{className:"settings-row",children:e.jsxs("label",{title:z.gameMode,children:[e.jsx("input",{type:"checkbox",checked:i,onChange:c=>m({game_mode_on:c.currentTarget.checked}),disabled:l}),"Game Mode"]})}),e.jsx("div",{className:"settings-row",children:e.jsxs("label",{title:z.theme,children:["Theme",e.jsx("select",{value:u,onChange:c=>m({theme:c.currentTarget.value}),disabled:l,children:oe.map(c=>e.jsx("option",{value:c.id,children:c.label},c.id))}),e.jsx("button",{type:"button",disabled:l,className:"theme-cycle-btn",title:"Cycle to the next theme (P3)",onClick:()=>{const c=V.indexOf(u),h=V[(c<0?0:c+1)%V.length];h&&m({theme:h})},children:"Next theme →"})]})}),e.jsx("div",{className:"settings-row",children:e.jsxs("label",{title:z.tuiMode,children:["TUI Mode",e.jsxs("select",{value:g,onChange:c=>m({tui_display_mode:c.currentTarget.value}),disabled:l,children:[e.jsx("option",{value:"full",children:"Full"}),e.jsx("option",{value:"minimal",children:"Minimal"})]})," ",e.jsx("span",{className:"tui-mode-hint",children:"(affects the in-app TUI widget; not shown here)"})]})})]}),e.jsxs("section",{className:"config-display",children:[e.jsx("h3",{children:"Configuration"}),e.jsxs("div",{className:"config-grid",children:[e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",title:z.tier,children:"Tier"}),e.jsx("span",{className:"config-value",children:t?`${t.tier} (live)`:"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",title:z.preset,children:"Preset"}),e.jsx("span",{className:"config-value",children:t?.presetTier??"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",title:z.pressure,children:"Pressure"}),e.jsx("span",{className:"config-value",children:t?Ee(t.pressure):"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",title:z.threshold,children:"Threshold"}),e.jsx("span",{className:"config-value",children:d?Ne(d.thresholdTokens,d.tierPct,b):"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",title:z.fastGate,children:"Fast Gate"}),e.jsx("span",{className:"config-value",children:d?`${d.fastGatePct}%`:"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",children:"Auto"}),e.jsx("span",{className:"config-value",children:d?d.auto?"enabled":"disabled":"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",children:"Anchor"}),e.jsx("span",{className:"config-value",children:d?.anchorUserMessages??"—"})]})]})]})]})}const I={section:{background:"#1a1a2e",borderRadius:"8px",padding:"1rem",marginBottom:"1rem",border:"1px solid #2a2a4e"},sectionTitle:{fontSize:"1.1rem",fontWeight:700,marginTop:0,marginBottom:"0.75rem",color:"#e0e0e0",borderBottom:"1px solid #333",paddingBottom:"0.5rem"},label:{fontWeight:600,color:"#a0a0c0",marginRight:"0.5rem"},value:{color:"#e0e0e0"},row:{marginBottom:"0.4rem",fontSize:"0.9rem"}};function Re(){const[t,r]=s.useState(null),[n,a]=s.useState(null),l=s.useCallback(()=>{me().then(r).catch(g=>a(g instanceof Error?g.message:String(g)))},[]);s.useEffect(()=>{l()},[l]),s.useEffect(()=>{const g=setInterval(l,3e4);return()=>clearInterval(g)},[l]);const o=t?.status==="ok",m=t?.status==="ok"?"Working":t?.status==="unreachable"?"Unreachable":"Error",i=o?"#4caf50":"#f44336",u=o?"✓":"✗";return e.jsxs("div",{style:I.section,children:[e.jsx("h3",{style:I.sectionTitle,children:"Embedder Health"}),n&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error: ",n]}),!t&&!n&&e.jsx("p",{style:{color:"#888",fontSize:"0.85rem"},children:"Probing embedder..."}),t&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:I.row,children:[e.jsxs("span",{style:{...I.label,color:`${i}`},children:[u," ",m,":"]}),e.jsxs("span",{style:I.value,children:[t.dim," dims"]}),t.latencyMs!==void 0&&e.jsxs("span",{style:{color:"#a0a0c0",marginLeft:"0.5rem"},children:["(",t.latencyMs.toFixed(1)," ms)"]})]}),e.jsxs("div",{style:I.row,children:[e.jsx("span",{style:I.label,children:"Endpoint:"}),e.jsx("span",{style:I.value,children:t.url??e.jsx("span",{style:{color:"#888"},children:"built-in (no URL)"})})]}),t.error&&e.jsx("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:t.error})]})]})}function Me({title:t,children:r}){const[n,a]=s.useState(!0),l=`settings-${t.toLowerCase().replace(/[^a-z0-9]+/g,"-")}`;return e.jsxs("section",{className:"overflow-hidden rounded-xl border border-border bg-bg-elevated/40",children:[e.jsxs("button",{type:"button",onClick:()=>a(o=>!o),className:"flex w-full items-center justify-between rounded-t-xl bg-bg-elevated/60 px-4 py-3 text-left text-sm font-semibold text-foreground transition-colors hover:bg-bg-elevated","aria-expanded":n,"aria-controls":l,children:[e.jsx("span",{children:t}),e.jsx(ue,{className:he("h-4 w-4 text-muted-foreground transition-transform",n&&"rotate-180"),"aria-hidden":"true"})]}),n&&e.jsx("div",{id:l,className:"divide-y divide-border px-4 py-1",children:r})]})}const Be="rounded-md border border-border bg-bg-elevated/50 px-2 py-1 text-sm outline-none transition-colors focus:border-primary disabled:cursor-not-allowed disabled:opacity-50";function Ae(){return e.jsx("span",{className:"ml-2 inline-flex items-center rounded-md border border-warning/40 bg-warning/15 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-warning",title:"Requires an LLM embedder (Ollama/HTTP) to be effective",children:"LLM"})}function ze({setting:t,id:r,llmActive:n,saving:a,onUpdate:l}){const[o,m]=s.useState(null),i=t.requiresLlm&&!n,u=s.useRef(null);s.useEffect(()=>()=>{u.current&&clearTimeout(u.current)},[]);const g=s.useCallback(c=>{l(t.key,c).then(h=>m(h)).catch(h=>m(h instanceof Error?h.message:String(h)))},[l,t.key]),d=s.useCallback(c=>{u.current&&clearTimeout(u.current),u.current=setTimeout(()=>g(c),500)},[g]),b=a||i;return e.jsxs("div",{className:"py-2.5",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center text-sm font-semibold text-foreground",children:[e.jsx("label",{htmlFor:`${r}-input`,className:"cursor-pointer",children:t.label}),t.requiresLlm&&!n&&e.jsx(Ae,{})]}),e.jsx("div",{className:"mt-0.5 text-xs text-muted-foreground",children:t.description})]}),e.jsx("div",{className:"flex shrink-0 items-center gap-2",children:t.type==="boolean"?e.jsx(pe,{id:`${r}-input`,checked:!!t.value,disabled:b||i,onCheckedChange:c=>g(String(c)),"aria-label":t.label}):e.jsxs(e.Fragment,{children:[e.jsx("input",{id:`${r}-input`,type:t.type==="number"?"number":"text",defaultValue:String(t.value??""),min:t.min,max:t.max,disabled:b,onChange:c=>d(c.target.value),className:`${Be} ${t.type==="number"?"w-24":"w-56"}`}),t.unit&&e.jsx("span",{className:"text-xs text-muted-foreground",children:t.unit})]})})]}),o&&e.jsxs("p",{className:"mt-1 text-xs text-danger",children:["Error: ",o]})]})}function Ie(){const[t,r]=s.useState(null),[n,a]=s.useState(null),[l,o]=s.useState(!1),[m,i]=s.useState(null),u=s.useCallback(()=>{se().then(r).catch(d=>a(d instanceof Error?d.message:String(d)))},[]);s.useEffect(()=>{u()},[u]);const g=s.useCallback(async(d,b)=>{o(!0);try{const c=await fe({key:d,value:b});return i(c.restartRequired?"Saved — restart pi to apply changes.":"Saved."),u(),null}catch(c){return c instanceof Error?c.message:String(c)}finally{o(!1)}},[u]);return e.jsxs("div",{className:"flex flex-col gap-3",children:[n&&e.jsxs("p",{className:"text-sm text-danger",children:["Error: ",n]}),!t&&!n&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading settings..."}),t?.categories.map(d=>e.jsx(Me,{title:d.name,children:d.settings.map(b=>e.jsx(ze,{setting:b,id:`${d.name.replace(/[^a-z0-9]+/gi,"-")}-${b.key}`,llmActive:t.llmActive,saving:l,onUpdate:g},b.key))},d.name)),m&&e.jsx("div",{className:"mt-1 rounded-md border border-warning/40 bg-warning/10 p-2 text-xs text-warning",role:"status",children:m})]})}const f={container:{padding:"1rem",maxWidth:"720px",margin:"0 auto",fontFamily:"system-ui, sans-serif",color:"#e0e0e0"},section:{background:"#1a1a2e",borderRadius:"8px",padding:"1rem",marginBottom:"1rem",border:"1px solid #2a2a4e"},sectionTitle:{fontSize:"1.1rem",fontWeight:700,marginTop:0,marginBottom:"0.75rem",color:"#e0e0e0",borderBottom:"1px solid #333",paddingBottom:"0.5rem"},label:{fontWeight:600,color:"#a0a0c0",marginRight:"0.5rem"},value:{color:"#e0e0e0"},row:{marginBottom:"0.4rem",fontSize:"0.9rem"},warning:{background:"#3a2a00",border:"1px solid #665500",borderRadius:"8px",padding:"0.75rem",marginTop:"0.5rem",color:"#ffcc00",fontSize:"0.85rem"},badge:{display:"inline-block",padding:"0.15rem 0.5rem",borderRadius:"4px",fontSize:"0.8rem",fontWeight:600,marginLeft:"0.5rem"},detectRow:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"0.5rem 0",borderBottom:"1px solid #2a2a4e"},button:{background:"#3a5a9f",color:"#fff",border:"none",borderRadius:"6px",padding:"0.5rem 1rem",cursor:"pointer",fontSize:"0.9rem",fontWeight:600}},Oe="Saved; takes effect on next session start";function Le({customUrl:t,setCustomUrl:r,applyEmbedder:n,configuring:a,inputEnabled:l,apiKeySet:o,embeddingDim:m,embeddingHeadersSet:i,allowRemoteEmbedder:u,configureResult:g,configureError:d}){const[b,c]=s.useState(""),[h,y]=s.useState(""),[v,w]=s.useState(!1),[N,p]=s.useState(""),[T,E]=s.useState(!1),[B,j]=s.useState(!1);return l&&!v&&typeof m=="string"&&(y(m),w(!0)),l&&!B&&typeof u=="boolean"&&(E(u),j(!0)),e.jsxs("div",{style:f.section,children:[e.jsx("h3",{style:f.sectionTitle,children:"Custom Endpoint (remote / third-party)"}),e.jsxs("p",{style:{fontSize:"0.85rem",color:"#a0a0c0",marginTop:0},children:["Point at any OpenAI-compatible embeddings API or hosted endpoint. This opts in to a non-loopback connection (sets"," ",e.jsx("code",{children:"MEGACOMPACT_ALLOW_REMOTE_EMBEDDER=1"}),") — your prompts' embedding requests will be sent to the URL you enter. Default is loopback-only."]}),e.jsxs("div",{style:{display:"flex",gap:"0.5rem",flexWrap:"wrap",alignItems:"center"},children:[e.jsx("input",{type:"url",placeholder:"https://api.example.com/v1/embeddings",value:t,onChange:x=>r(x.target.value),style:{flex:"1 1 300px",background:"#12122a",color:"#e0e0e0",border:"1px solid #2a2a4e",borderRadius:"6px",padding:"0.4rem 0.6rem",fontSize:"0.85rem",fontFamily:"monospace"}}),l&&e.jsx("input",{type:"password",autoComplete:"new-password","aria-label":"API key (optional Bearer)",placeholder:"API key (optional Bearer)",value:b,onChange:x=>c(x.target.value),style:{flex:"1 1 300px",background:"#12122a",color:"#e0e0e0",border:"1px solid #2a2a4e",borderRadius:"6px",padding:"0.4rem 0.6rem",fontSize:"0.85rem",fontFamily:"monospace"}}),l&&o&&e.jsx("span",{style:{fontSize:"0.75rem",color:"#81c784",border:"1px solid #2a4e2a",borderRadius:"4px",padding:"0.15rem 0.45rem"},children:"API key saved"}),l&&i&&e.jsx("span",{style:{fontSize:"0.75rem",color:"#81c784",border:"1px solid #2a4e2a",borderRadius:"4px",padding:"0.15rem 0.45rem"},children:"Headers saved"}),e.jsx("button",{style:{...f.button,opacity:t?1:.4},onClick:()=>n("custom",t,b,h,N,T),disabled:!t||a!==null,children:a==="custom"?"Writing...":"Use Custom URL"})]}),l&&e.jsxs("div",{style:{marginTop:"0.75rem"},children:[e.jsxs("div",{style:{marginBottom:"0.5rem"},children:[e.jsx("label",{style:{...f.label,display:"block",marginBottom:"0.25rem"},children:"Embedding dim (optional)"}),e.jsx("input",{type:"number",min:1,placeholder:"e.g. 384",value:h,onChange:x=>y(x.target.value),style:{width:"200px",background:"#12122a",color:"#e0e0e0",border:"1px solid #2a2a4e",borderRadius:"6px",padding:"0.4rem 0.6rem",fontSize:"0.85rem",fontFamily:"monospace"}})]}),e.jsxs("div",{style:{marginBottom:"0.5rem"},children:[e.jsx("label",{style:{...f.label,display:"block",marginBottom:"0.25rem"},children:"Embedding headers (JSON, write-only — never re-displayed)"}),e.jsx("textarea",{placeholder:'{"Authorization": "Bearer ..."}',value:N,onChange:x=>p(x.target.value),"aria-label":"Embedding headers JSON (write-only — never re-displayed)",rows:2,style:{width:"100%",background:"#12122a",color:"#e0e0e0",border:"1px solid #2a2a4e",borderRadius:"6px",padding:"0.4rem 0.6rem",fontSize:"0.85rem",fontFamily:"monospace",resize:"vertical"}})]}),e.jsxs("label",{style:{display:"flex",alignItems:"center",gap:"0.5rem",fontSize:"0.85rem"},children:[e.jsx("input",{type:"checkbox",checked:T,onChange:x=>E(x.target.checked),"aria-label":"Allow remote embedder (skips loopback-only check)"}),"Allow remote embedder (skips loopback-only check)"]})]}),d!==null&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem",marginTop:"0.5rem"},children:["Configure error: ",d]}),g!==null&&g.embedder==="custom"&&e.jsx("div",{style:f.warning,children:Oe}),e.jsxs("div",{style:f.warning,children:[e.jsx("strong",{children:"Heads up:"})," a remote endpoint receives the text you embed (it does NOT receive your full conversation — only the strings passed to",e.jsx("code",{children:" embed()"})," for recall/dedup). Verify the endpoint's privacy policy before use."]})]})}function Q(t){switch(t){case"trigram":return"TrigramEmbedder (heuristic, default)";case"http":return"HTTP Embedder (BYO localhost)";case"minilm":return"MiniLM (experimental)";default:return"Unknown"}}function Pe(t){return t?.currentEmbedder!=="trigram"?null:e.jsxs("div",{style:f.warning,children:[e.jsx("strong",{children:"Note:"})," TrigramEmbedder is a heuristic-strength default embedder. It works without any setup but recall quality may be lower than a dedicated embedding backend. If you notice poor recall results, consider installing Ollama and running the"," ",e.jsx("code",{children:"/megasetup"})," command, or set"," ",e.jsx("code",{children:"MEGACOMPACT_EMBEDDING_URL"})," to point at your own localhost embedding server."]})}function q(t){const r=t?"#1a5a1a":"#3a1a1a",n=t?"#4caf50":"#f44336";return e.jsx("span",{style:{...f.badge,background:r,color:n},children:t?"Detected":"Not found"})}function _e({status:t,statusError:r}){return e.jsxs("div",{style:f.section,children:[e.jsx("h3",{style:f.sectionTitle,children:"Current Embedder Configuration"}),r&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error: ",r]}),t&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:f.row,children:[e.jsx("span",{style:f.label,children:"Active Embedder:"}),e.jsx("span",{style:f.value,children:Q(t.currentEmbedder)})]}),"configuredEmbedder"in t&&t.configuredEmbedder!==t.currentEmbedder&&e.jsxs("div",{style:f.warning,children:[e.jsx("strong",{children:"Configured but not active:"})," ",Q(t.configuredEmbedder)," is configured in .mega-compact.env but not yet loaded."," ",e.jsx("strong",{children:"Restart pi"})," to activate it.",t.configuredUrl&&e.jsxs(e.Fragment,{children:[" (",t.configuredUrl,")"]})]}),"restartRequired"in t&&t.restartRequired&&e.jsxs("div",{style:{...f.row,color:"#ff9800"},children:[e.jsx("span",{style:f.label,children:"Status:"}),e.jsx("span",{style:f.value,children:"Restart required to activate the configured embedder"})]}),e.jsxs("div",{style:f.row,children:[e.jsx("span",{style:f.label,children:"Embedding URL:"}),e.jsx("span",{style:f.value,children:t.embeddingUrl??e.jsx("span",{style:{color:"#888"},children:"not set"})})]}),e.jsxs("div",{style:f.row,children:[e.jsx("span",{style:f.label,children:"Embed Cache:"}),e.jsx("span",{style:f.value,children:t.embedCache??e.jsx("span",{style:{color:"#888"},children:"not set"})})]}),e.jsxs("div",{style:f.row,children:[e.jsx("span",{style:f.label,children:"MiniLM:"}),e.jsx("span",{style:f.value,children:t.minilm?"enabled":"disabled"})]}),Pe(t)]}),!t&&!r&&e.jsx("p",{style:{color:"#888",fontSize:"0.85rem"},children:"Loading configuration..."})]})}function De(){const[t,r]=s.useState(null),[n,a]=s.useState(null),[l,o]=s.useState(null),[m,i]=s.useState(null),[u,g]=s.useState(!1),[d,b]=s.useState(null),[c,h]=s.useState(null),[y,v]=s.useState(null),[w,N]=s.useState(""),[p,T]=s.useState(!1),E=s.useCallback(()=>{ne().then(r).catch(x=>o(x instanceof Error?x.message:String(x)))},[]),B=s.useCallback((x,R,A,W,F,_)=>{b(x),v(null),h(null);const O="embeddingHeadersSet"in(t??{});K({embedder:x,url:R,embeddingEndpointUrl:R,embeddingApiKey:A,...O?{embeddingDim:W,embeddingHeaders:F,allowRemoteEmbedder:_}:{}}).then(L=>{h(L),b(null),E()}).catch(L=>{v(L instanceof Error?L.message:String(L)),b(null)})},[E,t]),j=s.useCallback(()=>{g(!0),i(null),ge().then(x=>{a(x),g(!1)}).catch(x=>{i(x instanceof Error?x.message:String(x)),g(!1)})},[]);return s.useEffect(()=>{E()},[E]),s.useEffect(()=>{p||t&&typeof t.embeddingEndpointUrl=="string"&&t.embeddingEndpointUrl.length>0&&(N(t.embeddingEndpointUrl),T(!0))},[t,p]),s.useEffect(()=>{const x=setInterval(E,5e3);return()=>clearInterval(x)},[E]),s.useEffect(()=>{j();const x=setInterval(j,5e3);return()=>clearInterval(x)},[j]),e.jsxs("div",{style:f.container,children:[e.jsx("h2",{style:{fontSize:"1.3rem",marginTop:0,marginBottom:"1rem"},children:"Embedder Setup"}),e.jsx(Re,{}),e.jsx(_e,{status:t,statusError:l}),e.jsxs("div",{style:f.section,children:[e.jsx("h3",{style:f.sectionTitle,children:"Local Embedder Detection"}),e.jsx("p",{style:{fontSize:"0.85rem",color:"#a0a0c0",marginTop:0},children:"Detect which local embedding backends are available on this machine. No software is installed — detection only."}),n&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:f.detectRow,children:[e.jsx("span",{children:e.jsx("strong",{children:"Ollama"})}),n.ollama!==null?e.jsxs("span",{children:[q(n.ollama.installed),n.ollama.installed&&e.jsx("span",{style:{fontSize:"0.8rem",color:"#a0a0c0",marginLeft:"0.5rem"},children:n.ollama.running?`server running, ${n.ollama.models.length} model(s)`:"server not running"})]}):e.jsx("span",{style:{color:"#888",fontSize:"0.85rem"},children:"not checked"})]}),e.jsxs("div",{style:f.detectRow,children:[e.jsx("span",{children:e.jsx("strong",{children:"llama.cpp"})}),n.llamaCpp!==null?e.jsxs("span",{children:[q(n.llamaCpp.installed),n.llamaCpp.installed&&n.llamaCpp.detail&&e.jsx("span",{style:{fontSize:"0.8rem",color:"#a0a0c0",marginLeft:"0.5rem"},children:n.llamaCpp.detail})]}):e.jsx("span",{style:{color:"#888",fontSize:"0.85rem"},children:"not checked"})]}),e.jsxs("div",{style:f.detectRow,children:[e.jsx("span",{children:e.jsx("strong",{children:"ONNX Runtime"})}),n.onnx!==null?e.jsxs("span",{children:[q(n.onnx.installed),n.onnx.installed&&n.onnx.detail&&e.jsx("span",{style:{fontSize:"0.8rem",color:"#a0a0c0",marginLeft:"0.5rem"},children:n.onnx.detail})]}):e.jsx("span",{style:{color:"#888",fontSize:"0.85rem"},children:"not checked"})]}),n.error&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.8rem",marginTop:"0.5rem"},children:["Detection error: ",n.error]})]}),m&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error: ",m]}),e.jsxs("div",{style:{marginTop:"1rem"},children:[e.jsx("button",{style:f.button,onClick:j,disabled:u,children:u?"Detecting...":"Run Detection"}),e.jsxs("span",{style:{fontSize:"0.8rem",color:"#888",marginLeft:"0.75rem"},children:["Or run ",e.jsx("code",{children:"/megasetup"})," in the chat for an interactive wizard."]})]}),n&&e.jsxs("div",{style:{marginTop:"1rem",paddingTop:"0.75rem",borderTop:"1px solid #2a2a4e"},children:[e.jsx("div",{style:{fontSize:"0.9rem",fontWeight:600,marginBottom:"0.5rem"},children:"Configure"}),e.jsxs("div",{style:{display:"flex",gap:"0.5rem",flexWrap:"wrap"},children:[e.jsx("button",{style:{...f.button,opacity:n.ollama?.installed?1:.4},onClick:()=>B("ollama"),disabled:!n.ollama?.installed||d!==null,children:d==="ollama"?"Writing...":"Use Ollama"}),e.jsx("button",{style:{...f.button,opacity:n.llamaCpp?.installed?1:.4},onClick:()=>B("llama"),disabled:!n.llamaCpp?.installed||d!==null,children:d==="llama"?"Writing...":"Use llama.cpp"}),e.jsx("button",{style:{...f.button,opacity:n.onnx?.installed?1:.4},onClick:()=>B("onnx"),disabled:!n.onnx?.installed||d!==null,children:d==="onnx"?"Writing...":"Use ONNX"}),e.jsx("button",{style:{...f.button,background:"#444"},onClick:()=>B("trigram"),disabled:d!==null,children:d==="trigram"?"Writing...":"Use Trigram (default)"})]}),c&&c.embedder!=="custom"&&e.jsx("div",{style:f.warning,children:c.alreadyActive?"Already active — no restart needed.":`Configured ${c.embedder}. Restart pi to activate (config written to ${c.envPath}).`}),y&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem",marginTop:"0.5rem"},children:["Configure error: ",y]})]})]}),e.jsx(Le,{customUrl:w,setCustomUrl:N,applyEmbedder:B,configuring:d,inputEnabled:t!==null&&"embeddingApiKeySet"in t,apiKeySet:t?.embeddingApiKeySet===!0,embeddingDim:t?.embeddingDim,embeddingHeadersSet:t?.embeddingHeadersSet===!0,allowRemoteEmbedder:t?.allowRemoteEmbedder,configureResult:c,configureError:y}),e.jsxs("div",{style:f.section,children:[e.jsx("h3",{style:f.sectionTitle,children:"How to Upgrade"}),e.jsxs("ul",{style:{fontSize:"0.85rem",lineHeight:1.6,paddingLeft:"1.25rem"},children:[e.jsxs("li",{children:[e.jsx("strong",{children:"Ollama:"})," Install from"," ",e.jsx("a",{href:"https://ollama.com",style:{color:"#6a9fff"},target:"_blank",rel:"noopener noreferrer",children:"ollama.com"}),", then ",e.jsx("code",{children:"ollama pull nomic-embed-text"})," and restart pi. Set ",e.jsx("code",{children:"MEGACOMPACT_EMBEDDING_URL=http://localhost:11434/api/embeddings"}),"."]}),e.jsxs("li",{children:[e.jsx("strong",{children:"llama.cpp:"})," Build or install llama.cpp, run"," ",e.jsx("code",{children:"llama-server"})," with an embedding model, and set the URL accordingly."]}),e.jsxs("li",{children:[e.jsx("strong",{children:"ONNX Runtime:"})," Run a local text-embeddings server (e.g. TEI) and click ",e.jsx("strong",{children:"Use ONNX"})," above. Default URL: ",e.jsx("code",{children:"http://localhost:8081/v1/embeddings"}),"."]})]})]}),e.jsxs("div",{style:f.section,children:[e.jsx("h3",{style:f.sectionTitle,children:"Settings"}),e.jsx(Ie,{})]})]})}function U(t){return t>=1e6?`${(t/1e6).toFixed(2)}M`:t>=1e3?`${Math.round(t/1e3)}K`:String(t)}function $e(t,r,n){if(t<=0)return"—";const l=(r>0?r:Math.ceil(t*.1))+Math.ceil(t*(n/100)),o=t-l;return o<=0?"0 (at risk)":`${U(o)} tokens`}function Y({label:t,value:r,min:n,max:a,step:l=1,onChange:o,warning:m}){return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsxs("div",{className:"flex items-center justify-between text-xs",children:[e.jsx("span",{className:"font-medium text-fg-muted",children:t}),e.jsxs("span",{className:`font-mono ${m?"text-warning":"text-fg"}`,title:m,children:[r,"%"]})]}),e.jsx("input",{type:"range",min:n,max:a,step:l,value:r,onChange:i=>o(Number(i.target.value)),className:"threshold-slider w-full"}),m&&e.jsxs("p",{className:"text-[10px] text-warning",children:["⚠ ",m]})]})}function Ue({model:t,defaults:r,safetyRange:n,fireRange:a,onSave:l,onReset:o,saving:m}){const[i,u]=s.useState(t.threshold.safetyMarginPct),[g,d]=s.useState(t.threshold.firePointPct),[b,c]=s.useState(!1),[h,y]=s.useState(null);s.useEffect(()=>{u(t.threshold.safetyMarginPct),d(t.threshold.firePointPct),c(!1)},[t.threshold.safetyMarginPct,t.threshold.firePointPct]);const v=i<5?'Low safety margin — risks "conversation too long" errors when a single turn injects a large tool output between gate fires.':void 0,w=g>85?"High fire point — compaction may trigger close to the window cap; a single large turn can overshoot before the gate fires.":void 0,N=s.useCallback(async()=>{y(null);try{await l(t.modelId,i,g),c(!1)}catch(p){y(p instanceof Error?p.message:String(p))}},[t.modelId,i,g,l]);return e.jsxs("div",{className:"rounded-md border border-border bg-bg-elevated/30 p-3",children:[e.jsxs("div",{className:"mb-2 flex items-start justify-between",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-sm font-semibold text-fg",children:t.modelName??t.modelId}),t.threshold.isOverride&&e.jsx("span",{className:"rounded border border-primary/40 bg-primary/15 px-1.5 py-0.5 text-[10px] font-semibold uppercase text-primary",title:"This model has a custom override (not the default)",children:"Override"})]}),e.jsxs("div",{className:"text-[11px] text-fg-muted",children:[t.provider," · ",U(t.contextWindow)," window ·"," ",U(t.maxTokens)," output"]})]}),e.jsxs("div",{className:"text-right text-[11px] text-fg-muted",children:[e.jsxs("div",{children:["Usable tail:"," ",e.jsx("span",{className:"font-mono text-fg",children:$e(t.contextWindow,t.maxTokens,i)})]}),e.jsxs("div",{children:["Compaction fires at:"," ",e.jsx("span",{className:"font-mono text-fg",children:U(Math.ceil(t.contextWindow*(g/100)))})]})]})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:[e.jsx(Y,{label:"Safety margin",value:i,min:n[0],max:n[1],onChange:p=>{u(p),c(!0)},warning:v}),e.jsx(Y,{label:"Fire point",value:g,min:a[0],max:a[1],onChange:p=>{d(p),c(!0)},warning:w})]}),e.jsxs("div",{className:"mt-2 flex items-center gap-2",children:[e.jsx("button",{type:"button",onClick:N,disabled:!b||m,className:"rounded-md bg-primary px-2.5 py-1 text-xs font-semibold text-primary-fg disabled:cursor-not-allowed disabled:opacity-50",children:b?"Save override":"Saved"}),t.threshold.isOverride&&e.jsxs("button",{type:"button",onClick:()=>o(t.modelId),disabled:m,className:"rounded-md border border-border px-2.5 py-1 text-xs text-fg-muted disabled:cursor-not-allowed disabled:opacity-50",children:["Reset to default (",r.safetyMarginPct,"% /"," ",r.firePointPct,"%)"]}),h&&e.jsx("span",{className:"text-[11px] text-error",children:h})]})]})}function We(){const[t,r]=s.useState(null),[n,a]=s.useState(!0),[l,o]=s.useState(null),[m,i]=s.useState(!1),u=s.useCallback(async()=>{try{o(null),r(await xe())}catch(b){o(b instanceof Error?b.message:String(b))}finally{a(!1)}},[]);s.useEffect(()=>{u()},[u]);const g=s.useCallback(async(b,c,h)=>{i(!0);try{await be({modelId:b,safetyMarginPct:c,firePointPct:h}),await u()}finally{i(!1)}},[u]),d=s.useCallback(async b=>{i(!0);try{await ye(b),await u()}finally{i(!1)}},[u]);return n?e.jsx("div",{className:"p-4 text-sm text-fg-muted",children:"Loading thresholds…"}):l?e.jsxs("div",{className:"p-4 text-sm text-error",children:["Error: ",l]}):t?e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"rounded-md border border-border bg-bg-elevated/20 p-3",children:[e.jsx("h3",{className:"text-sm font-semibold",children:"Per-Model Compaction Thresholds"}),e.jsxs("p",{className:"mt-1 text-[11px] text-fg-muted",children:["Tune when compaction fires + how much safety margin to reserve,",e.jsx("strong",{children:" per model"}),". Different providers' models range from 8K to 1M+ context — one global % is wrong. Defaults:"," ",e.jsxs("span",{className:"font-mono",children:[t.defaults.safetyMarginPct,"% safety"]})," ","/"," ",e.jsxs("span",{className:"font-mono",children:[t.defaults.firePointPct,"% fire"]}),". Values outside the safe band show warnings."]})]}),t.models.length===0?e.jsx("div",{className:"rounded-md border border-border p-4 text-sm text-fg-muted",children:"No models captured yet. Start a pi session in any repo to populate model snapshots, then return here to tune per-model thresholds."}):e.jsx("div",{className:"flex flex-col gap-3",children:t.models.map(b=>e.jsx(Ue,{model:b,defaults:t.defaults,safetyRange:t.defaults.safetyMarginRange,fireRange:t.defaults.firePointRange,onSave:g,onReset:d,saving:m},b.modelId))})]}):e.jsx("div",{className:"p-4 text-sm text-fg-muted",children:"No data."})}async function Fe(){const t=await fetch("/api/setup-cortex-status");if(!t.ok)throw new Error(`setup-cortex status: ${t.status}`);return t.json()}async function He(t){const r=await fetch("/api/setup-cortex-action",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(r.ok)return{ok:!0,result:await r.json()};let n;try{n=await r.json()}catch{n={error:"disabled"}}return{ok:!1,status:r.status,error:n}}async function Ge(t){const r=await fetch(`/api/setup-cortex-action-log?name=${encodeURIComponent(t)}`);if(!r.ok)throw new Error(`setup-cortex action-log: ${r.status}`);return r.json()}function Ve(t){return t===null?!0:t.enabled&&t.status!=="off"}function ie(){const[t,r]=s.useState({loading:!0,error:null,data:null}),n=s.useCallback(()=>{r(a=>({...a,loading:!0})),Fe().then(a=>r(l=>({...l,data:a,loading:!1,error:null}))).catch(a=>r(l=>({...l,loading:!1,error:a instanceof Error?a.message:String(a)})))},[]);return s.useEffect(()=>{n();const a=setInterval(n,5e3);return()=>clearInterval(a)},[n]),[t,n]}const S={container:{padding:"1rem",maxWidth:"720px",margin:"0 auto",fontFamily:"system-ui, sans-serif",color:"#e0e0e0"},section:{background:"#1a1a2e",borderRadius:"8px",padding:"1rem",marginBottom:"1rem",border:"1px solid #2a2a4e"},sectionTitle:{fontSize:"1.1rem",fontWeight:700,marginTop:0,marginBottom:"0.75rem",color:"#e0e0e0",borderBottom:"1px solid #333",paddingBottom:"0.5rem"},label:{fontWeight:600,color:"#a0a0c0",marginRight:"0.5rem"},value:{color:"#e0e0e0"},row:{marginBottom:"0.4rem",fontSize:"0.9rem"},warning:{background:"#3a2a00",border:"1px solid #665500",borderRadius:"8px",padding:"0.75rem",marginTop:"0.5rem",color:"#ffcc00",fontSize:"0.85rem"},blocked:{background:"#3a1a1a",border:"1px solid #662222",borderRadius:"8px",padding:"0.75rem",marginTop:"0.5rem",color:"#ff6666",fontSize:"0.85rem"},badge:{display:"inline-block",padding:"0.15rem 0.5rem",borderRadius:"4px",fontSize:"0.8rem",fontWeight:600,marginLeft:"0.5rem"},button:{background:"#3a5a9f",color:"#fff",border:"none",borderRadius:"6px",padding:"0.5rem 1rem",cursor:"pointer",fontSize:"0.9rem",fontWeight:600},buttonDanger:{background:"#6a2a2a",color:"#ffb3b3",border:"1px solid #662222",borderRadius:"6px",padding:"0.5rem 1rem",cursor:"pointer",fontSize:"0.9rem",fontWeight:600},blockerRow:{display:"flex",justifyContent:"space-between",alignItems:"center",gap:"0.5rem",padding:"0.5rem 0.6rem",borderRadius:"6px",marginBottom:"0.35rem",fontSize:"0.85rem"},blockerRowHighlighted:{background:"#3a1a1a",border:"1px solid #662222"},mono:{fontFamily:"ui-monospace, monospace",fontSize:"0.8rem"}};function qe(t){switch(t){case"A":return"A — qualified learned encoder asset";case"B":return"B — demoted (heuristic/trigram)";case"C":return"C — absent (asset not verified)";default:return"—"}}function Xe(t){const r=t==="qualified"?"#1a5a1a":t==="demoted"?"#3a3a1a":"#3a1a1a",n=t==="qualified"?"#4caf50":t==="demoted"?"#ffcc00":"#f44336";return e.jsx("span",{style:{...S.badge,background:r,color:n},children:t??"unknown"})}function Ke({data:t,error:r}){return e.jsxs("div",{style:S.section,children:[e.jsxs("h3",{style:S.sectionTitle,children:[e.jsx("span",{style:{marginRight:"0.5rem"},children:"Cortex Encoder"}),e.jsx(je,{status:t?.status})]}),r&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error: ",r]}),!t&&!r&&e.jsx("p",{style:{color:"#888",fontSize:"0.85rem"},children:"Loading cortex status..."}),!t?.enabled&&e.jsx("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:"Cortex status disabled (VC9A off)."}),e.jsxs("div",{style:S.row,children:[e.jsx("span",{style:S.label,children:"Mode:"}),e.jsx("span",{style:S.value,children:qe(t?.encoderHealth.mode)})]}),e.jsxs("div",{style:S.row,children:[e.jsx("span",{style:S.label,children:"Asset digest prefix:"}),e.jsx("span",{style:{...S.value,...S.mono},children:t?.assetDigestPrefix??e.jsx("span",{style:{color:"#888"},children:"not available"})})]}),e.jsxs("div",{style:S.row,children:[e.jsx("span",{style:S.label,children:"Qualification:"}),Xe(t?.qualification.verdict)]}),(t?.qualification.thresholdFailures.length??0)>0&&e.jsxs("div",{style:S.warning,children:[e.jsx("strong",{children:"Threshold failure(s):"})," ",t?.qualification.thresholdFailures.join(", ")]}),t?.status==="awaiting_data"&&e.jsx("p",{style:{color:"#a0a0c0",fontSize:"0.85rem"},children:"Awaiting encoder data. Qualification will appear once an asset is present."}),t?.status==="deferred"&&e.jsx("p",{style:{color:"#a0a0c0",fontSize:"0.85rem"},children:"Encoder status deferred."})]})}function Je(t){switch(t){case"blocker":return"#f44336";case"high":return"#ff9800";default:return"#a0a0c0"}}function Qe({blockers:t,highlight:r,darwinX64:n}){const a=r??[];return e.jsxs("div",{style:S.section,children:[e.jsxs("h3",{style:S.sectionTitle,children:["Open Hard-Gate Blockers",e.jsx("span",{style:{...S.badge,background:"#3a1a1a",color:"#f44336"},children:t.length})]}),t.length===0&&e.jsx("p",{style:{color:"#4caf50",fontSize:"0.85rem"},children:"No open hard-gate blockers."}),n?.demoted===!0&&e.jsxs("div",{style:S.blockerRow,"data-darwin-x64-demoted":"true",children:[e.jsx("span",{style:{...S.mono,fontWeight:700},children:"HG-4"}),e.jsx("span",{style:{flex:1,color:"#e0e0e0"},children:n.reason||"darwin-x64: demoted to WASM (reason unavailable)"}),e.jsx("span",{style:{color:"#ff9800"},children:"high"}),e.jsx("span",{style:{color:"#4caf50",fontStyle:"italic"},children:"diagnosed"})]}),t.map(l=>{const o=a.includes(l.id);return e.jsxs("div",{style:{...S.blockerRow,...o?S.blockerRowHighlighted:{}},children:[e.jsx("span",{style:{...S.mono,fontWeight:700},children:l.id}),e.jsx("span",{style:{flex:1,color:"#e0e0e0"},children:l.title}),e.jsx("span",{style:{color:Je(l.severity)},children:l.severity}),e.jsx("span",{style:{color:"#a0a0c0",fontStyle:"italic"},children:o?"gates this action":l.status})]},l.id)}),a.length>0&&e.jsxs("div",{style:S.blocked,children:[e.jsx("strong",{children:"Blocked:"})," the requested action is gated by the highlighted open hard-gate item(s). It was not run."]})]})}const Ye=[{key:"fetch-model",label:"Fetch Model",desc:"Fetch the qualified encoder model asset",dangerous:!0,confirm:"Fetch the encoder model asset onto this host? (Gated by any open hard gate.)"},{key:"bench",label:"Bench Encoder",desc:"Benchmark the encoder runtime on this host",dangerous:!0,confirm:"Run an encoder benchmark on this host? (Gated by any open hard gate.)"},{key:"verify-asset",label:"Verify Asset",desc:"Re-verify the committed encoder asset",dangerous:!1,confirm:"Re-verify the committed encoder asset?"}];function Ze({data:t,onBlocked:r,onAction:n}){const[a,l]=s.useState(null),[o,m]=s.useState(null),[i,u]=s.useState(null),[g,d]=s.useState(!1),b=s.useCallback(async h=>{l(h.key),u(null),m(null),d(!1),r([]);try{const y=await He({action:h.key,confirm:!0});if(y.ok){const v=y.result;let w=null,N=null;try{const p=await Ge(v.logName);w=p.tail,N=p.complete}catch{}m({action:v.action,logName:v.logName,tail:w,complete:N,message:v.ok?`${v.action} completed (spawned: ${v.spawned})`:`${v.action} did not complete cleanly`}),n()}else y.error.error==="action_blocked_by_open_item"?(r(y.error.blockers),u("The action is blocked by an open hard-gate item and was not run.")):y.error.error==="confirmation_required"?u("The server rejected the action: explicit confirmation is required."):(d(!0),u(y.status===404?"Setup Cortex actions are disabled (off).":`Action failed (${y.status}).`))}catch(y){u(y instanceof Error?y.message:String(y))}finally{l(null)}},[r,n]),c=h=>{window.confirm(h.confirm)&&b(h)};return e.jsxs("div",{style:S.section,children:[e.jsx("h3",{style:S.sectionTitle,children:"Cortex Actions"}),Ye.map(h=>{const y=a===h.key;return e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:"0.5rem",padding:"0.5rem 0",borderBottom:"1px solid #2a2a4e"},children:[e.jsxs("div",{children:[e.jsx("div",{style:{fontWeight:600},children:h.label}),e.jsx("div",{style:{fontSize:"0.8rem",color:"#a0a0c0"},children:h.desc})]}),e.jsx("button",{style:h.dangerous?S.buttonDanger:S.button,disabled:a!==null,onClick:()=>c(h),children:y?"Running…":"Run"})]},h.key)}),g&&e.jsx("div",{style:S.blocked,children:"Setup Cortex actions are disabled. Enable MEGACOMPACT_VC9B to run them."}),i&&!g&&e.jsx("p",{style:{color:"#f44336",fontSize:"0.85rem",marginTop:"0.5rem"},children:i}),o&&e.jsxs("div",{style:S.warning,"data-testid":"cortex-action-result",children:[e.jsxs("strong",{children:["Result (",o.action,"):"]})," ",o.message,o.logName&&e.jsxs("span",{style:{...S.mono,marginLeft:"0.5rem"},children:["log: ",o.logName]}),o.tail!==null&&e.jsxs("pre",{style:{whiteSpace:"pre-wrap",wordBreak:"break-word",fontSize:"0.75rem",maxHeight:"12rem",overflow:"auto",marginTop:"0.5rem"},children:[o.tail,o.complete===!1&&`
|
|
2
|
+
… (truncated)`]})]}),!t?.enabled&&!g&&e.jsx("p",{style:{color:"#a0a0c0",fontSize:"0.8rem",marginTop:"0.5rem"},children:"Cortex status unavailable — actions may not be schedulable."})]})}const M={section:{background:"#1a1a2e",borderRadius:"8px",padding:"1rem",marginBottom:"1rem",border:"1px solid #2a2a4e"},sectionTitle:{fontSize:"1.1rem",fontWeight:700,marginTop:0,marginBottom:"0.25rem",color:"#e0e0e0"},subtitle:{fontSize:"0.85rem",color:"#a0a0c0",marginTop:0,marginBottom:"0.75rem"},row:{marginBottom:"0.4rem",fontSize:"0.9rem"},label:{fontWeight:600,color:"#a0a0c0",marginRight:"0.5rem"},value:{color:"#e0e0e0"},warning:{background:"#3a2a00",border:"1px solid #665500",borderRadius:"8px",padding:"0.75rem",marginTop:"0.5rem",color:"#ffcc00",fontSize:"0.85rem"},toggleRow:{display:"flex",alignItems:"center",gap:"0.5rem",marginBottom:"0.75rem",fontSize:"0.9rem"}},X=8192;function et(){const[t,r]=s.useState(null),[n,a]=s.useState(null),[l,o]=s.useState(!1),[m,i]=s.useState(""),[u,g]=s.useState(!1),d=s.useCallback(()=>{ne().then(r).catch(p=>a(p instanceof Error?p.message:String(p)))},[]);s.useEffect(()=>{d()},[d]),s.useEffect(()=>{const p=setInterval(d,5e3);return()=>clearInterval(p)},[d]);const b=t!==null&&"encoderNativeOptIn"in t,c=t?.nativeOrtBudgetEffectiveMib;s.useEffect(()=>{if(!u&&t&&"nativeOrtBudgetEffectiveMib"in t){const p=t.nativeOrtBudgetMib??t.nativeOrtBudgetEffectiveMib??"";typeof p=="string"&&i(p),g(!0)}},[u,t]);const h=s.useCallback(p=>{o(!0),a(null),K({embedder:"custom",url:t?.embeddingEndpointUrl??void 0,encoderNativeOptIn:p}).then(()=>{o(!1),d()}).catch(T=>{a(T instanceof Error?T.message:String(T)),o(!1)})},[t,d]),y=s.useCallback(()=>{const p=m.trim();if(!/^\d+$/.test(p)){a("Install budget must be a positive integer (MiB)");return}const T=Number(p);if(!Number.isSafeInteger(T)||T<1||T>X){a(`Install budget must be between 1 and ${X} MiB`);return}o(!0),a(null),K({embedder:"custom",url:t?.embeddingEndpointUrl??void 0,nativeOrtBudgetMib:p}).then(()=>{o(!1),d()}).catch(E=>{a(E instanceof Error?E.message:String(E)),o(!1)})},[m,t,d]);if(!b)return e.jsx(e.Fragment,{});const v=t?.encoderBackend??"wasm",w=t?.encoderDemotionReason??null,N=t!==null&&"nativeOrtBudgetEffectiveMib"in t;return e.jsxs("div",{style:M.section,children:[e.jsx("h3",{style:M.sectionTitle,children:"Encoder Runtime"}),e.jsx("p",{style:M.subtitle,children:"ONNX backend selection"}),e.jsxs("div",{style:M.toggleRow,children:[e.jsx("input",{type:"checkbox",checked:t?.encoderNativeOptIn===!0,onChange:p=>h(p.target.checked),disabled:l,"aria-label":"Native ONNX runtime (onnxruntime-node)"}),e.jsx("label",{children:"Native ONNX runtime (onnxruntime-node)"}),l&&e.jsx("span",{style:{fontSize:"0.8rem",color:"#a0a0c0"},children:"saving..."})]}),e.jsxs("div",{style:M.row,children:[e.jsx("span",{style:M.label,children:"Effective backend:"}),e.jsx("span",{style:M.value,children:v})]}),N&&e.jsxs("div",{style:M.row,children:[e.jsx("label",{htmlFor:"enc2-budget-input",style:{...M.label,marginRight:"0.5rem"},children:"Native install budget (MiB):"}),e.jsx("input",{id:"enc2-budget-input",type:"number",min:1,max:X,step:1,value:m,onChange:p=>i(p.target.value),disabled:l,style:{width:"6rem"},"aria-label":"Native onnxruntime install budget in MiB"}),e.jsx("button",{type:"button",onClick:y,disabled:l||m.trim().length===0,style:{marginLeft:"0.5rem"},children:"Save"}),c!==void 0&&e.jsxs("span",{style:{...M.value,marginLeft:"0.5rem"},children:["(effective: ",c," MiB)"]})]}),w!==null&&e.jsxs("div",{style:M.warning,children:[e.jsx("strong",{children:"Demoted:"})," ",w]}),n&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error: ",n]})]})}const k={section:{background:"#1a1a2e",borderRadius:"8px",padding:"1rem",marginBottom:"1rem",border:"1px solid #2a2a4e"},sectionTitle:{fontSize:"1.1rem",fontWeight:700,marginTop:0,marginBottom:"0.25rem",color:"#e0e0e0"},subtitle:{fontSize:"0.85rem",color:"#a0a0c0",marginTop:0,marginBottom:"0.75rem"},row:{marginBottom:"0.4rem",fontSize:"0.9rem"},label:{fontWeight:600,color:"#a0a0c0",marginRight:"0.5rem"},value:{color:"#e0e0e0"},disabled:{background:"#1a1a2e",border:"1px solid #2a2a4e",borderRadius:"8px",padding:"1rem",marginBottom:"1rem",color:"#a0a0c0",fontSize:"0.85rem"}},tt=()=>{const{data:t,error:r,loading:n}=J(s.useMemo(()=>()=>re("/api/cosine-fp-report").catch(a=>{if(a instanceof ae&&a.status===404)return null;throw a}),[]),{pollInterval:5e3});return t===null&&!r&&!n?e.jsx("div",{style:k.disabled,children:"Cosine FP synthetic bench: disabled (MEGACOMPACT_COSINE_FP_BENCH=0)."}):e.jsxs("div",{style:k.section,children:[e.jsx("h3",{style:k.sectionTitle,children:"Cosine FP threshold"}),e.jsx("p",{style:k.subtitle,children:"Last synthetic bench threshold recommendation"}),r!==null?e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error loading report: ",r.message]}):t===null?e.jsx("div",{style:k.value,children:"Loading…"}):e.jsxs("div",{children:[e.jsxs("div",{style:k.row,children:[e.jsx("span",{style:k.label,children:"Recommended default:"}),e.jsxs("span",{style:k.value,children:[t.recommendedDefault??"—"," (shipped"," ",t.shippedDefault,")"]})]}),e.jsxs("div",{style:k.row,children:[e.jsx("span",{style:k.label,children:"Overrides:"}),e.jsxs("span",{style:k.value,children:["CODE ",t.overrides?.code??"—"," · PROSE"," ",t.overrides?.prose??"—"," · MIXED"," ",t.overrides?.mixed??"—"]})]}),e.jsxs("div",{style:k.row,children:[e.jsx("span",{style:k.label,children:"Grid:"}),e.jsx("span",{style:k.value,children:t.grid?`${t.grid.lo} → ${t.grid.hi} (${t.grid.points} points)`:"—"})]}),e.jsxs("div",{style:k.row,children:[e.jsx("span",{style:k.label,children:"Report digest:"}),e.jsx("span",{style:k.value,title:t.digest??void 0,children:t.digest?t.digest.slice(0,16)+"…":"—"})]})]})]})},C={section:{background:"#1a1a2e",borderRadius:"8px",padding:"1rem",marginBottom:"1rem",border:"1px solid #2a2a4e"},sectionTitle:{fontSize:"1.1rem",fontWeight:700,marginTop:0,marginBottom:"0.25rem",color:"#e0e0e0"},subtitle:{fontSize:"0.85rem",color:"#a0a0c0",marginTop:0,marginBottom:"0.75rem"},row:{marginBottom:"0.4rem",fontSize:"0.9rem"},label:{fontWeight:600,color:"#a0a0c0",marginRight:"0.5rem"},value:{color:"#e0e0e0"},disabled:{background:"#1a1a2e",border:"1px solid #2a2a4e",borderRadius:"8px",padding:"1rem",marginBottom:"1rem",color:"#a0a0c0",fontSize:"0.85rem"}},st=()=>{const{data:t,error:r,loading:n}=J(s.useMemo(()=>()=>re("/api/repo-corpus").catch(a=>{if(a instanceof ae&&a.status===404)return null;throw a}),[]),{pollInterval:5e3});return t===null&&!r&&!n?e.jsx("div",{style:C.disabled,children:"Cross-repo corpus: disabled (MEGACOMPACT_REPO_CORPUS=0)."}):e.jsxs("div",{style:C.section,children:[e.jsx("h3",{style:C.sectionTitle,children:"Cross-Repo Corpus"}),e.jsx("p",{style:C.subtitle,children:"Pseudonymous consent status across donated repos"}),r!==null?e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error loading corpus: ",r.message]}):t===null?e.jsx("div",{style:C.value,children:"Loading…"}):e.jsxs("div",{children:[e.jsxs("div",{style:C.row,children:[e.jsx("span",{style:C.label,children:"Status:"}),e.jsx("span",{style:C.value,children:t.status})]}),e.jsxs("div",{style:C.row,children:[e.jsx("span",{style:C.label,children:"Total events:"}),e.jsx("span",{style:C.value,children:t.totalEvents})]}),e.jsxs("div",{style:C.row,children:[e.jsx("span",{style:C.label,children:"Overlap pairs:"}),e.jsx("span",{style:C.value,children:t.corpus?t.corpus.overlaps.length:0})]}),e.jsx("div",{style:{marginTop:"0.5rem"},children:(t.perRepo??[]).map(a=>e.jsxs("div",{style:C.row,children:[e.jsxs("span",{style:C.label,children:[a.repoPseudonym.slice(0,8),":"]}),e.jsxs("span",{style:C.value,children:[a.sessions," sessions ·"," ",a.consentedCrossRepo?a.revokedAt?`revoked ${a.revokedAt}`:"consented":"not consented"]})]},a.repoPseudonym))})]})]})};function nt(){const[t,r]=ie(),[n,a]=s.useState([]),l=s.useCallback(m=>{a(m)},[]),o=s.useCallback(()=>{r()},[r]);return e.jsxs("div",{style:S.container,children:[e.jsx("h2",{style:{fontSize:"1.3rem",marginTop:0,marginBottom:"1rem"},children:"Setup Cortex"}),e.jsx("p",{style:{fontSize:"0.85rem",color:"#a0a0c0",marginTop:0},children:"Vector-cortex encoder gate: mode, qualification, open hard-gate blockers, and the confirmation-gated fetch/bench/verify actions."}),e.jsx(Ke,{data:t.data,error:t.error}),e.jsx(et,{}),e.jsx(tt,{}),e.jsx(st,{}),e.jsx(Qe,{blockers:t.data?.blockers??[],highlight:n,darwinX64:t.data?.darwinX64}),e.jsx(Ze,{data:t.data,onBlocked:l,onAction:o})]})}const rt="MEGACOMPACT_DASH_0C";function at(t){if(!t)return!1;for(const r of t.categories)for(const n of r.settings)if(n.key===rt&&n.type==="boolean")return n.value===!0;return!1}const Z=[{id:"embedder",label:"Embedder"},{id:"thresholds",label:"Thresholds"},{id:"config",label:"Config"},{id:"game",label:"Game Mode"},{id:"achievements",label:"Achievements"}],lt={id:"cortex",label:"Cortex"};function ut(){const[t,r]=s.useState("embedder"),[n]=ie(),{data:a}=J(s.useCallback(()=>se(),[]),{pollInterval:0,maxRetries:0}),l=at(a),o=s.useMemo(()=>{const m=l?Z.filter(i=>i.id!=="config"):[...Z];return Ve(n.data)&&m.push(lt),m},[n.data,l]);return e.jsxs("div",{className:"mx-auto flex max-w-3xl flex-col gap-4 p-4",children:[e.jsx("nav",{className:"flex gap-2 border-b border-border pb-2","aria-label":"Setup sections",children:o.map(m=>e.jsx(ve,{pressed:t===m.id,onClick:()=>r(m.id),children:m.label},m.id))}),t==="embedder"&&e.jsx(De,{}),t==="thresholds"&&e.jsx(We,{}),t==="config"&&!l&&e.jsx(Te,{}),t==="game"&&e.jsx(ke,{}),t==="achievements"&&e.jsx(Ce,{}),t==="cortex"&&e.jsx(nt,{})]})}export{ut as default};
|
|
3
|
+
//# sourceMappingURL=SetupTab-DPrG3s9V.js.map
|