pi-mega-compact 0.12.0 → 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/extensions/dashboard-server/gather-debug.js +63 -0
  2. package/dist/extensions/dashboard-server/routes-health.js +44 -0
  3. package/dist/extensions/dashboard-server/routes-setup.js +30 -4
  4. package/dist/extensions/dashboard-server/routes.js +1 -1
  5. package/dist/extensions/dashboard-server/server.js +3 -1
  6. package/dist/extensions/mega-events/agent-handlers.js +27 -1
  7. package/dist/extensions/mega-events/health-handler.js +19 -2
  8. package/dist/src/memoryGraph/sources.js +42 -15
  9. package/dist/src/memoryGraph.js +17 -5
  10. package/dist/src/store/sqlite/meta.js +11 -0
  11. package/dist/src/store/turns/schema.js +18 -2
  12. package/extensions/dashboard-client/dist/assets/{AchievementTiles-DeQ0qnBX.js → AchievementTiles-Cntu89Xw.js} +2 -2
  13. package/extensions/dashboard-client/dist/assets/{AchievementTiles-DeQ0qnBX.js.map → AchievementTiles-Cntu89Xw.js.map} +1 -1
  14. package/extensions/dashboard-client/dist/assets/{AchievementsTab-Dtk_RJfs.js → AchievementsTab-4ckY9z4n.js} +2 -2
  15. package/extensions/dashboard-client/dist/assets/{AchievementsTab-Dtk_RJfs.js.map → AchievementsTab-4ckY9z4n.js.map} +1 -1
  16. package/extensions/dashboard-client/dist/assets/{CacheTab-kWcQt3PI.js → CacheTab-BfGJkiaf.js} +2 -2
  17. package/extensions/dashboard-client/dist/assets/{CacheTab-kWcQt3PI.js.map → CacheTab-BfGJkiaf.js.map} +1 -1
  18. package/extensions/dashboard-client/dist/assets/{ConfigTab-UFlo73fR.js → ConfigTab-DV08rHoV.js} +2 -2
  19. package/extensions/dashboard-client/dist/assets/{ConfigTab-UFlo73fR.js.map → ConfigTab-DV08rHoV.js.map} +1 -1
  20. package/extensions/dashboard-client/dist/assets/{EventsTab-BENO2N0y.js → EventsTab-DHytZ0xs.js} +2 -2
  21. package/extensions/dashboard-client/dist/assets/{EventsTab-BENO2N0y.js.map → EventsTab-DHytZ0xs.js.map} +1 -1
  22. package/extensions/dashboard-client/dist/assets/{GameTab-BCJavOML.js → GameTab-Ofpoz-6s.js} +2 -2
  23. package/extensions/dashboard-client/dist/assets/{GameTab-BCJavOML.js.map → GameTab-Ofpoz-6s.js.map} +1 -1
  24. package/extensions/dashboard-client/dist/assets/HealthTab-B0klAxD8.js +2 -0
  25. package/extensions/dashboard-client/dist/assets/HealthTab-B0klAxD8.js.map +1 -0
  26. package/extensions/dashboard-client/dist/assets/MaintenanceTab-CHKh3KPI.js +2 -0
  27. package/extensions/dashboard-client/dist/assets/MaintenanceTab-CHKh3KPI.js.map +1 -0
  28. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-w5BZP3i-.js → MemoryMapTab-B6FLQ-32.js} +2 -2
  29. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-w5BZP3i-.js.map → MemoryMapTab-B6FLQ-32.js.map} +1 -1
  30. package/extensions/dashboard-client/dist/assets/{MetricsTab-BBCXa3xS.js → MetricsTab-DvOjTDkW.js} +2 -2
  31. package/extensions/dashboard-client/dist/assets/{MetricsTab-BBCXa3xS.js.map → MetricsTab-DvOjTDkW.js.map} +1 -1
  32. package/extensions/dashboard-client/dist/assets/{OverviewTab-CzABMSAQ.js → OverviewTab-CqbONEwi.js} +2 -2
  33. package/extensions/dashboard-client/dist/assets/{OverviewTab-CzABMSAQ.js.map → OverviewTab-CqbONEwi.js.map} +1 -1
  34. package/extensions/dashboard-client/dist/assets/{ReposTab-DFiM_Ubg.js → ReposTab-sc1GLn7i.js} +2 -2
  35. package/extensions/dashboard-client/dist/assets/{ReposTab-DFiM_Ubg.js.map → ReposTab-sc1GLn7i.js.map} +1 -1
  36. package/extensions/dashboard-client/dist/assets/{SessionsTab-BtW4bees.js → SessionsTab-C5gB45oc.js} +2 -2
  37. package/extensions/dashboard-client/dist/assets/{SessionsTab-BtW4bees.js.map → SessionsTab-C5gB45oc.js.map} +1 -1
  38. package/extensions/dashboard-client/dist/assets/SetupTab-BEEX4OF5.js +2 -0
  39. package/extensions/dashboard-client/dist/assets/SetupTab-BEEX4OF5.js.map +1 -0
  40. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CC13EXij.js → TimeSavedCard-BBwvb4cC.js} +2 -2
  41. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CC13EXij.js.map → TimeSavedCard-BBwvb4cC.js.map} +1 -1
  42. package/extensions/dashboard-client/dist/assets/{TopicsTab-BrTB8uEK.js → TopicsTab-BsCf512_.js} +2 -2
  43. package/extensions/dashboard-client/dist/assets/{TopicsTab-BrTB8uEK.js.map → TopicsTab-BsCf512_.js.map} +1 -1
  44. package/extensions/dashboard-client/dist/assets/{TurnsTab-BJK7FIHu.js → TurnsTab-C3ti7NB5.js} +2 -2
  45. package/extensions/dashboard-client/dist/assets/{TurnsTab-BJK7FIHu.js.map → TurnsTab-C3ti7NB5.js.map} +1 -1
  46. package/extensions/dashboard-client/dist/assets/health-lSeDFTz7.js +2 -0
  47. package/extensions/dashboard-client/dist/assets/health-lSeDFTz7.js.map +1 -0
  48. package/extensions/dashboard-client/dist/assets/{index-B8k19B9g.js → index-BEeaI9uo.js} +3 -3
  49. package/extensions/dashboard-client/dist/assets/{index-B8k19B9g.js.map → index-BEeaI9uo.js.map} +1 -1
  50. package/extensions/dashboard-client/dist/assets/{useSSE-CWBB4Me7.js → useSSE-BMSSO9wB.js} +2 -2
  51. package/extensions/dashboard-client/dist/assets/{useSSE-CWBB4Me7.js.map → useSSE-BMSSO9wB.js.map} +1 -1
  52. package/extensions/dashboard-client/dist/index.html +1 -1
  53. package/extensions/dashboard-client/src/api/health.ts +16 -0
  54. package/extensions/dashboard-client/src/tabs/MaintenanceTab.tsx +91 -1
  55. package/extensions/dashboard-client/src/tabs/SetupTab.tsx +19 -0
  56. package/extensions/dashboard-server/api-contracts/maintenance.ts +1 -0
  57. package/extensions/dashboard-server/api-contracts/setup.ts +7 -1
  58. package/extensions/dashboard-server/gather-debug.ts +63 -0
  59. package/extensions/dashboard-server/routes-health.ts +51 -0
  60. package/extensions/dashboard-server/routes-setup.ts +28 -4
  61. package/extensions/dashboard-server/routes.ts +1 -1
  62. package/extensions/dashboard-server/server.ts +2 -0
  63. package/extensions/mega-events/agent-handlers.ts +26 -1
  64. package/extensions/mega-events/health-handler.ts +31 -3
  65. package/package.json +1 -1
  66. package/src/memoryGraph/sources.ts +49 -15
  67. package/src/memoryGraph.ts +17 -5
  68. package/src/store/sqlite/meta.ts +16 -0
  69. package/src/store/turns/schema.ts +18 -2
  70. package/extensions/dashboard-client/dist/assets/HealthTab-C7iw7rhx.js +0 -2
  71. package/extensions/dashboard-client/dist/assets/HealthTab-C7iw7rhx.js.map +0 -1
  72. package/extensions/dashboard-client/dist/assets/MaintenanceTab-C0rdAMWc.js +0 -2
  73. package/extensions/dashboard-client/dist/assets/MaintenanceTab-C0rdAMWc.js.map +0 -1
  74. package/extensions/dashboard-client/dist/assets/SetupTab-Duy1LJhg.js +0 -2
  75. package/extensions/dashboard-client/dist/assets/SetupTab-Duy1LJhg.js.map +0 -1
@@ -14,6 +14,7 @@
14
14
  */
15
15
  import { getStateDir } from "./store.js";
16
16
  import { openStore } from "./store/sqlite/utils.js";
17
+ import { openTurnStore } from "./store/turns/connection.js";
17
18
  import type { DatabaseSync } from "node:sqlite";
18
19
  import { Logger } from "./log.js";
19
20
  import { runValidationPipeline } from "./memoryGraph/gates.js";
@@ -182,14 +183,23 @@ function buildUnvalidatedGraph(
182
183
  return { nodes: [], edges: [] };
183
184
  }
184
185
 
186
+ // Turns live in the isolated turns.db, not the main sqlite.db. Open it
187
+ // separately so buildTurnNodes/buildTurnContentNodes can query it.
188
+ let turnDb: DatabaseSync | null = null;
189
+ try {
190
+ turnDb = openTurnStore(stateDir);
191
+ } catch {
192
+ log.warn("graph_source_unavailable", { detail: "Cannot open turns.db" });
193
+ }
194
+
185
195
  try {
186
196
  // Source: checkpoints (always on)
187
197
  buildCheckpointNodes(db, sessionId, nodes, edges);
188
198
 
189
- // Source A: turns (structural, metadata-only)
190
- if (areTurnsEnabled()) {
199
+ // Source A: turns (structural, metadata-only) — from turns.db, not main db
200
+ if (areTurnsEnabled() && turnDb) {
191
201
  try {
192
- buildTurnNodes(db, sessionId, nodes, edges);
202
+ buildTurnNodes(turnDb, sessionId, nodes, edges);
193
203
  } catch (err) {
194
204
  log.warn("graph_source_unavailable", {
195
205
  source: "turns",
@@ -199,9 +209,11 @@ function buildUnvalidatedGraph(
199
209
  }
200
210
 
201
211
  // Source B: turn content (raw_transcript join, embedding-based)
202
- if (isTurnContentEnabled()) {
212
+ // raw_transcript is in the main db, but turns are in turns.db — the JOIN
213
+ // can't span databases, so we pass both and merge in JS.
214
+ if (isTurnContentEnabled() && turnDb) {
203
215
  try {
204
- buildTurnContentNodes(db, sessionId, nodes, edges);
216
+ buildTurnContentNodes(turnDb, db, sessionId, nodes, edges);
205
217
  } catch (err) {
206
218
  log.warn("graph_source_unavailable", {
207
219
  source: "turn-content",
@@ -79,6 +79,22 @@ export function bumpDedupStats(deduped: boolean, stateDir: string = getStateDir(
79
79
  if (deduped) incMeta("deduped", 1, stateDir);
80
80
  }
81
81
 
82
+ // --- Context health mitigation (runtime-toggleable via dashboard) ----------
83
+
84
+ /** Read the context_health_mitigate flag from meta. Returns false if unset. */
85
+ export function getHealthMitigate(stateDir: string = getStateDir()): boolean {
86
+ return getMeta("context_health_mitigate", stateDir) === "true";
87
+ }
88
+
89
+ /** Set the context_health_mitigate flag in meta (runtime-toggleable). */
90
+ export function setHealthMitigate(enabled: boolean, stateDir: string = getStateDir()): void {
91
+ const db = openStore(stateDir);
92
+ db.prepare(
93
+ `INSERT INTO meta(key, value) VALUES('context_health_mitigate', ?)
94
+ ON CONFLICT(key) DO UPDATE SET value = ?`,
95
+ ).run(enabled ? "true" : "false", enabled ? "true" : "false");
96
+ }
97
+
82
98
  // --- Live dashboard counters (schemaless meta key/value — NO migration) -----
83
99
  // These reuse the private `incMeta` atomically-incrementing integer counter so
84
100
  // all cumulative tallies live in the same `meta` table as tokens_saved etc.
@@ -16,10 +16,26 @@
16
16
  import type { DatabaseSync } from "node:sqlite";
17
17
 
18
18
  /** Schema version stamp (written once into turns_meta). */
19
- const SCHEMA_VERSION = 1;
19
+ const SCHEMA_VERSION = 2;
20
20
 
21
21
  /** Create the unified turn-store schema if absent. Idempotent. */
22
22
  export function initTurnSchema(db: DatabaseSync): void {
23
+ // Migration: v1 had a pressure_band CHECK constraint that only allowed
24
+ // 'green','yellow','red' — but the runtime sends 'low','medium','high',
25
+ // 'ultra','mega'. Every INSERT failed silently. Since the constraint
26
+ // blocked ALL writes, the turns table is guaranteed empty — safe to
27
+ // drop and recreate with the widened constraint.
28
+ try {
29
+ const tableSql = db
30
+ .prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='turns'")
31
+ .get() as { sql?: string } | undefined;
32
+ if (tableSql?.sql && tableSql.sql.includes("'green'") && !tableSql.sql.includes("'low'")) {
33
+ db.exec("DROP TABLE IF EXISTS turns");
34
+ }
35
+ } catch {
36
+ /* non-fatal: table may not exist yet */
37
+ }
38
+
23
39
  // ── Contract tables (master's SqliteTurnStore shape) ──────────────────
24
40
  db.exec(`
25
41
  CREATE TABLE IF NOT EXISTS turns_meta (
@@ -41,7 +57,7 @@ export function initTurnSchema(db: DatabaseSync): void {
41
57
  ended_at INTEGER NOT NULL,
42
58
  ctx_tokens INTEGER,
43
59
  ctx_percent REAL,
44
- pressure_band TEXT CHECK(pressure_band IS NULL OR pressure_band IN ('green','yellow','red')),
60
+ pressure_band TEXT CHECK(pressure_band IS NULL OR pressure_band IN ('low','medium','high','ultra','mega','green','yellow','red')),
45
61
  model TEXT,
46
62
  epoch_id TEXT,
47
63
  UNIQUE(conversation_id, turn_index)
@@ -1,2 +0,0 @@
1
- import{r as o,j as e}from"./index-B8k19B9g.js";async function m(t){const l=await fetch("/api/context-health?minutes=30");if(!l.ok)throw new Error(`context-health: ${l.status}`);return l.json()}function d(t){return t>.8?"#4ade80":t>=.5?"#facc15":"#f87171"}function f({score:t}){const a=2*Math.PI*70,h=a*(1-Math.max(0,Math.min(1,t))),n=d(t);return e.jsxs("div",{className:"health-gauge-wrap",children:[e.jsxs("svg",{width:"180",height:"180",viewBox:"0 0 180 180",children:[e.jsx("circle",{cx:"90",cy:"90",r:70,fill:"none",stroke:"#1e293b",strokeWidth:"14"}),e.jsx("circle",{cx:"90",cy:"90",r:70,fill:"none",stroke:n,strokeWidth:"14",strokeDasharray:a,strokeDashoffset:h,strokeLinecap:"round",transform:"rotate(-90 90 90)",style:{transition:"stroke-dashoffset 0.5s ease"}}),e.jsx("text",{x:"90",y:"85",textAnchor:"middle",fontSize:"32",fontWeight:"bold",fill:n,children:(t*100).toFixed(0)}),e.jsx("text",{x:"90",y:"108",textAnchor:"middle",fontSize:"14",fill:"#94a3b8",children:"/ 100"})]}),e.jsx("div",{className:"health-gauge-label",children:"Context Health"})]})}function p({trend:t}){if(t.length<2)return e.jsx("div",{className:"health-spark-empty",children:"No trend data yet"});const l=400,a=60,h=1,n=0,x=t.map((r,u)=>{const s=u/(t.length-1)*l,j=a-(r-n)/(h-n)*a;return`${s.toFixed(1)},${j.toFixed(1)}`}),c=t[t.length-1];return e.jsx("svg",{width:l,height:a,viewBox:`0 0 ${l} ${a}`,className:"health-spark",children:e.jsx("polyline",{points:x.join(" "),fill:"none",stroke:d(c),strokeWidth:"2"})})}function i({label:t,value:l}){return e.jsxs("div",{className:"health-subscore",children:[e.jsx("span",{className:"health-subscore-label",children:t}),e.jsx("div",{className:"health-subscore-bar",children:e.jsx("div",{className:"health-subscore-fill",style:{width:`${l*100}%`,background:d(l)}})}),e.jsxs("span",{className:"health-subscore-val",children:[(l*100).toFixed(0),"%"]})]})}function g(){const[t,l]=o.useState(null),[a,h]=o.useState(null),[n,x]=o.useState(!0),c=o.useCallback(()=>{m().then(l).catch(s=>h(s instanceof Error?s.message:String(s))).finally(()=>x(!1))},[]);if(o.useEffect(()=>{c();const s=setInterval(c,5e3);return()=>clearInterval(s)},[c]),n&&!t)return e.jsx("div",{className:"health-loading",children:"Loading health data…"});if(a&&!t)return e.jsxs("div",{className:"health-error",children:["Error: ",a]});if(!t)return e.jsx("div",{className:"health-empty",children:"No health data available."});const r=t.latest,u=r?.composite??0;return e.jsxs("div",{className:"health-tab",children:[e.jsxs("div",{className:"health-top-row",children:[e.jsx(f,{score:u}),e.jsxs("div",{className:"health-subscores",children:[e.jsx("h3",{children:"Sub-Scores"}),e.jsx(i,{label:"Drift",value:r?.driftScore??0}),e.jsx(i,{label:"Output Quality",value:r?.outputQuality??0}),e.jsx(i,{label:"Error Rate",value:r?.errorScore??0}),e.jsx(i,{label:"Cache Health",value:r?.cacheHealth??0}),e.jsx(i,{label:"Cache Poison",value:r?.cachePoison??0})]})]}),e.jsxs("div",{className:"health-trend-section",children:[e.jsxs("h3",{children:["Health Trend (last ",t.trend.length," turns)"]}),e.jsx(p,{trend:t.trend})]}),t.alerts.length>0&&e.jsxs("div",{className:"health-alerts",children:[e.jsxs("h3",{children:["Recent Alerts (",t.alerts.length,")"]}),e.jsx("div",{className:"health-alert-list",children:t.alerts.slice(-10).map(s=>e.jsxs("div",{className:"health-alert-row",children:[e.jsx("span",{className:"health-alert-time",children:new Date(s.ts).toLocaleTimeString()}),e.jsx("span",{className:"health-alert-model",children:s.modelId??"(unknown)"}),e.jsx("span",{className:"health-alert-score",style:{color:d(s.composite)},children:(s.composite*100).toFixed(0)}),s.cachePoison<.3&&e.jsx("span",{className:"health-alert-tag",children:"CACHE POISON"})]},`${s.ts}-${s.turnIndex}`))})]}),t.perModel.length>0&&e.jsxs("div",{className:"health-per-model",children:[e.jsx("h3",{children:"Health by Model"}),e.jsxs("table",{className:"health-model-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Model"}),e.jsx("th",{children:"Avg Health"}),e.jsx("th",{children:"Samples"})]})}),e.jsx("tbody",{children:t.perModel.map(s=>e.jsxs("tr",{children:[e.jsx("td",{children:s.modelId}),e.jsxs("td",{style:{color:d(s.avgComposite)},children:[(s.avgComposite*100).toFixed(0),"%"]}),e.jsx("td",{children:s.sampleCount})]},s.modelId))})]})]})]})}export{g as default};
2
- //# sourceMappingURL=HealthTab-C7iw7rhx.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"HealthTab-C7iw7rhx.js","sources":["../../src/api/health.ts","../../src/tabs/HealthTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/api/health.ts — Context Health API client.\n * PREVENT-PI-004: relative paths only (loopback dashboard).\n */\n\nexport interface ContextHealthRow {\n\tts: number;\n\tturnIndex: number;\n\tsessionId: string;\n\tdriftScore: number;\n\toutputQuality: number;\n\terrorScore: number;\n\tcacheHealth: number;\n\tcachePoison: number;\n\tcomposite: number;\n\tmodelId: string | null;\n\trepetitionRatio: number | null;\n\tcoherenceScore: number | null;\n\tprefixHash: string | null;\n}\n\nexport interface ContextHealthResponse {\n\tupdatedAt: string;\n\tlatest: {\n\t\tcomposite: number;\n\t\tdriftScore: number;\n\t\toutputQuality: number;\n\t\terrorScore: number;\n\t\tcacheHealth: number;\n\t\tcachePoison: number;\n\t\tts: number;\n\t\tmodelId: string | null;\n\t} | null;\n\ttrend: number[];\n\trows: ContextHealthRow[];\n\tperModel: Array<{ modelId: string; avgComposite: number; sampleCount: number }>;\n\talerts: ContextHealthRow[];\n}\n\nexport interface CachePoisonEvent {\n\tts: number;\n\tturnIndex: number;\n\tsessionId: string;\n\tlayer: number;\n\tdetail: string;\n\tseverity: string;\n}\n\nexport interface CachePoisonResponse {\n\tupdatedAt: string;\n\tevents: CachePoisonEvent[];\n}\n\nexport async function fetchContextHealth(minutes?: number): Promise<ContextHealthResponse> {\n\tconst r = await fetch(`/api/context-health?minutes=${minutes ?? 30}`);\n\tif (!r.ok) throw new Error(`context-health: ${r.status}`);\n\treturn r.json() as Promise<ContextHealthResponse>;\n}\n\nexport async function fetchCachePoison(): Promise<CachePoisonResponse> {\n\tconst r = await fetch(\"/api/cache-poison\");\n\tif (!r.ok) throw new Error(`cache-poison: ${r.status}`);\n\treturn r.json() as Promise<CachePoisonResponse>;\n}\n","/**\n * HealthTab.tsx — Context Health dashboard tab.\n * Shows composite health gauge, sparkline trend, sub-score bars,\n * alerts, and per-model comparison. Polls /api/context-health every 5s.\n */\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport { fetchContextHealth, type ContextHealthResponse } from \"../api/health\";\n\nfunction healthColor(score: number): string {\n\tif (score > 0.8) return \"#4ade80\";\n\tif (score >= 0.5) return \"#facc15\";\n\treturn \"#f87171\";\n}\n\nfunction HealthGauge({ score }: { score: number }): React.ReactElement {\n\tconst r = 70;\n\tconst circ = 2 * Math.PI * r;\n\tconst offset = circ * (1 - Math.max(0, Math.min(1, score)));\n\tconst color = healthColor(score);\n\treturn (\n\t\t<div className=\"health-gauge-wrap\">\n\t\t\t<svg width=\"180\" height=\"180\" viewBox=\"0 0 180 180\">\n\t\t\t\t<circle cx=\"90\" cy=\"90\" r={r} fill=\"none\" stroke=\"#1e293b\" strokeWidth=\"14\" />\n\t\t\t\t<circle\n\t\t\t\t\tcx=\"90\"\n\t\t\t\t\tcy=\"90\"\n\t\t\t\t\tr={r}\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\tstroke={color}\n\t\t\t\t\tstrokeWidth=\"14\"\n\t\t\t\t\tstrokeDasharray={circ}\n\t\t\t\t\tstrokeDashoffset={offset}\n\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\ttransform=\"rotate(-90 90 90)\"\n\t\t\t\t\tstyle={{ transition: \"stroke-dashoffset 0.5s ease\" }}\n\t\t\t\t/>\n\t\t\t\t<text x=\"90\" y=\"85\" textAnchor=\"middle\" fontSize=\"32\" fontWeight=\"bold\" fill={color}>\n\t\t\t\t\t{(score * 100).toFixed(0)}\n\t\t\t\t</text>\n\t\t\t\t<text x=\"90\" y=\"108\" textAnchor=\"middle\" fontSize=\"14\" fill=\"#94a3b8\">/ 100</text>\n\t\t\t</svg>\n\t\t\t<div className=\"health-gauge-label\">Context Health</div>\n\t\t</div>\n\t);\n}\n\nfunction HealthSparkline({ trend }: { trend: number[] }): React.ReactElement {\n\tif (trend.length < 2) return <div className=\"health-spark-empty\">No trend data yet</div>;\n\tconst w = 400;\n\tconst h = 60;\n\tconst max = 1;\n\tconst min = 0;\n\tconst pts = trend.map((v, i) => {\n\t\tconst x = (i / (trend.length - 1)) * w;\n\t\tconst y = h - ((v - min) / (max - min)) * h;\n\t\treturn `${x.toFixed(1)},${y.toFixed(1)}`;\n\t});\n\tconst last = trend[trend.length - 1];\n\treturn (\n\t\t<svg width={w} height={h} viewBox={`0 0 ${w} ${h}`} className=\"health-spark\">\n\t\t\t<polyline points={pts.join(\" \")} fill=\"none\" stroke={healthColor(last)} strokeWidth=\"2\" />\n\t\t</svg>\n\t);\n}\n\nfunction SubScoreBar({ label, value }: { label: string; value: number }): React.ReactElement {\n\treturn (\n\t\t<div className=\"health-subscore\">\n\t\t\t<span className=\"health-subscore-label\">{label}</span>\n\t\t\t<div className=\"health-subscore-bar\">\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"health-subscore-fill\"\n\t\t\t\t\tstyle={{ width: `${value * 100}%`, background: healthColor(value) }}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<span className=\"health-subscore-val\">{(value * 100).toFixed(0)}%</span>\n\t\t</div>\n\t);\n}\n\nexport default function HealthTab(): React.ReactElement {\n\tconst [data, setData] = useState<ContextHealthResponse | null>(null);\n\tconst [err, setError] = useState<string | null>(null);\n\tconst [loading, setLoading] = useState(true);\n\n\tconst poll = useCallback(() => {\n\t\tfetchContextHealth()\n\t\t\t.then(setData)\n\t\t\t.catch((e: unknown) => setError(e instanceof Error ? e.message : String(e)))\n\t\t\t.finally(() => setLoading(false));\n\t}, []);\n\n\tuseEffect(() => {\n\t\tpoll();\n\t\tconst id = setInterval(poll, 5000);\n\t\treturn () => clearInterval(id);\n\t}, [poll]);\n\n\tif (loading && !data) return <div className=\"health-loading\">Loading health data…</div>;\n\tif (err && !data) return <div className=\"health-error\">Error: {err}</div>;\n\tif (!data) return <div className=\"health-empty\">No health data available.</div>;\n\n\tconst latest = data.latest;\n\tconst composite = latest?.composite ?? 0;\n\n\treturn (\n\t\t<div className=\"health-tab\">\n\t\t\t<div className=\"health-top-row\">\n\t\t\t\t<HealthGauge score={composite} />\n\t\t\t\t<div className=\"health-subscores\">\n\t\t\t\t\t<h3>Sub-Scores</h3>\n\t\t\t\t\t<SubScoreBar label=\"Drift\" value={latest?.driftScore ?? 0} />\n\t\t\t\t\t<SubScoreBar label=\"Output Quality\" value={latest?.outputQuality ?? 0} />\n\t\t\t\t\t<SubScoreBar label=\"Error Rate\" value={latest?.errorScore ?? 0} />\n\t\t\t\t\t<SubScoreBar label=\"Cache Health\" value={latest?.cacheHealth ?? 0} />\n\t\t\t\t\t<SubScoreBar label=\"Cache Poison\" value={latest?.cachePoison ?? 0} />\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div className=\"health-trend-section\">\n\t\t\t\t<h3>Health Trend (last {data.trend.length} turns)</h3>\n\t\t\t\t<HealthSparkline trend={data.trend} />\n\t\t\t</div>\n\n\t\t\t{data.alerts.length > 0 && (\n\t\t\t\t<div className=\"health-alerts\">\n\t\t\t\t\t<h3>Recent Alerts ({data.alerts.length})</h3>\n\t\t\t\t\t<div className=\"health-alert-list\">\n\t\t\t\t\t\t{data.alerts.slice(-10).map((a) => (\n\t\t\t\t\t\t\t<div key={`${a.ts}-${a.turnIndex}`} className=\"health-alert-row\">\n\t\t\t\t\t\t\t\t<span className=\"health-alert-time\">{new Date(a.ts).toLocaleTimeString()}</span>\n\t\t\t\t\t\t\t\t<span className=\"health-alert-model\">{a.modelId ?? \"(unknown)\"}</span>\n\t\t\t\t\t\t\t\t<span className=\"health-alert-score\" style={{ color: healthColor(a.composite) }}>\n\t\t\t\t\t\t\t\t\t{(a.composite * 100).toFixed(0)}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t{a.cachePoison < 0.3 && <span className=\"health-alert-tag\">CACHE POISON</span>}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{data.perModel.length > 0 && (\n\t\t\t\t<div className=\"health-per-model\">\n\t\t\t\t\t<h3>Health by Model</h3>\n\t\t\t\t\t<table className=\"health-model-table\">\n\t\t\t\t\t\t<thead><tr><th>Model</th><th>Avg Health</th><th>Samples</th></tr></thead>\n\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t{data.perModel.map((m) => (\n\t\t\t\t\t\t\t\t<tr key={m.modelId}>\n\t\t\t\t\t\t\t\t\t<td>{m.modelId}</td>\n\t\t\t\t\t\t\t\t\t<td style={{ color: healthColor(m.avgComposite) }}>\n\t\t\t\t\t\t\t\t\t\t{(m.avgComposite * 100).toFixed(0)}%\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td>{m.sampleCount}</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</tbody>\n\t\t\t\t\t</table>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"],"names":["fetchContextHealth","minutes","r","healthColor","score","HealthGauge","circ","offset","color","jsxs","jsx","HealthSparkline","trend","w","h","max","min","pts","v","i","x","y","last","SubScoreBar","label","value","HealthTab","data","setData","useState","err","setError","loading","setLoading","poll","useCallback","e","useEffect","id","latest","composite","a","m"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{u as N,r,B as p,C as v,j as e,D as f,E as C}from"./index-B8k19B9g.js";const k=[{key:"integrity-check",label:"Integrity Check",desc:"Run PRAGMA integrity_check",dangerous:!1},{key:"reconcile-dedup",label:"Reconcile Dedup Mirror",desc:"Fix orphan dedup rows + backfill refs",dangerous:!1,confirm:"Reconcile dedup_mirror (safe read/write)?"},{key:"checkpoint",label:"WAL Checkpoint",desc:"Merge WAL into main DB (read-only)",dangerous:!1},{key:"vacuum",label:"VACUUM",desc:"Rebuild DB reclaiming free pages",dangerous:!0,confirm:"VACUUM rewrites the entire DB. Continue?"},{key:"reindex",label:"REINDEX",desc:"Rebuild all indexes",dangerous:!0,confirm:"REINDEX rebuilds indexes. Continue?"},{key:"fts5-rebuild",label:"FTS5 Rebuild",desc:"Rebuild full-text search index",dangerous:!0,confirm:"Rebuild FTS5 trigram index. Continue?"},{key:"prune",label:"Prune Old Rows",desc:"Delete transcripts + epochs older than N days",dangerous:!0,daysOld:!0,confirm:"Delete old raw_transcript rows. Continue?"}];function x(s){return s<1024?`${s} B`:s<1024*1024?`${(s/1024).toFixed(1)} KB`:`${(s/(1024*1024)).toFixed(1)} MB`}function w({files:s,pageSize:n,pageCount:t,freelistPages:l}){const c=s.dbBytes+s.walBytes+s.shmBytes;return e.jsxs("div",{className:"stat-section",children:[e.jsx("div",{className:"stat-label",children:"File Sizes"}),e.jsx("table",{className:"compact-table",children:e.jsxs("tbody",{children:[e.jsxs("tr",{children:[e.jsx("td",{children:"sqlite.db"}),e.jsx("td",{className:"num",children:x(s.dbBytes)})]}),s.walBytes>0&&e.jsxs("tr",{children:[e.jsx("td",{children:".wal"}),e.jsx("td",{className:"num",children:x(s.walBytes)})]}),s.shmBytes>0&&e.jsxs("tr",{children:[e.jsx("td",{children:".shm"}),e.jsx("td",{className:"num",children:x(s.shmBytes)})]}),e.jsxs("tr",{children:[e.jsx("td",{children:"Total"}),e.jsx("td",{className:"num",children:x(c)})]}),e.jsxs("tr",{children:[e.jsx("td",{children:"Page size"}),e.jsx("td",{className:"num",children:x(n)})]}),e.jsxs("tr",{children:[e.jsx("td",{children:"Pages"}),e.jsxs("td",{className:"num",children:[t.toLocaleString()," (",l.toLocaleString()," ","free)"]})]})]})})]})}function S({tables:s}){const n=s.reduce((t,l)=>t+Math.max(0,l.rowCount),0);return e.jsxs("div",{className:"stat-section",children:[e.jsxs("div",{className:"stat-label",children:["Table Row Counts (",n.toLocaleString()," total)"]}),e.jsxs("table",{className:"compact-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Table"}),e.jsx("th",{className:"num",children:"Rows"})]})}),e.jsx("tbody",{children:s.map(t=>e.jsxs("tr",{children:[e.jsx("td",{children:t.table}),e.jsx("td",{className:"num",children:t.rowCount>=0?t.rowCount.toLocaleString():"—"})]},t.table))})]})]})}function R({data:s,loading:n,error:t}){return e.jsxs("div",{className:"card",children:[e.jsx("div",{className:"card-header",children:"DB Stats"}),e.jsxs("div",{className:"card-body",children:[n&&!s&&e.jsx("span",{className:"text-muted",children:"Loading…"}),t&&!s&&e.jsx("span",{className:"text-error",children:t.message}),s&&e.jsxs(e.Fragment,{children:[e.jsx(w,{files:s.storage.files,pageSize:s.storage.pageSize,pageCount:s.storage.pageCount,freelistPages:s.storage.freelistPages}),e.jsx(S,{tables:s.tables})]})]})]})}function D({columns:s}){const n=s.filter(t=>!t.present);return e.jsxs("div",{className:"stat-section",children:[e.jsxs("div",{className:"stat-label",children:["Column Audit (",s.length," columns, ",n.length," missing)"]}),e.jsxs("table",{className:"compact-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Table"}),e.jsx("th",{children:"Column"}),e.jsx("th",{children:"Decl"}),e.jsx("th",{children:"Status"})]})}),e.jsx("tbody",{children:s.map(t=>e.jsxs("tr",{children:[e.jsx("td",{children:t.table}),e.jsx("td",{children:t.column}),e.jsx("td",{className:"text-mono",children:t.expectedDecl}),e.jsx("td",{className:t.present?"text-ok":"text-error",children:t.present?"✓":"MISSING"})]},`${t.table}.${t.column}`))})]})]})}function B({data:s,loading:n,error:t}){return e.jsxs("div",{className:"card",children:[e.jsxs("div",{className:"card-header",children:["Schema Health",s&&e.jsx("span",{className:`badge ${s.healthy?"badge-ok":"badge-bad"}`,children:s.healthy?"HEALTHY":"DEGRADED"})]}),e.jsxs("div",{className:"card-body",children:[n&&!s&&e.jsx("span",{className:"text-muted",children:"Loading…"}),t&&!s&&e.jsx("span",{className:"text-error",children:t.message}),s&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"stat-row",children:[e.jsx("span",{className:"stat-label",children:"Schema version"}),e.jsx("span",{className:"num",children:s.schemaVersion})]}),e.jsxs("div",{className:"stat-row",children:[e.jsx("span",{className:"stat-label",children:"Integrity"}),e.jsx("span",{className:s.integrity[0]==="ok"?"text-ok":"text-error",children:s.integrity.join("; ")})]}),e.jsx(D,{columns:s.columns}),s.fkCheck.length>0&&e.jsxs("div",{className:"stat-section",children:[e.jsxs("div",{className:"stat-label text-warn",children:["FK Check (",s.fkCheck.length,")"]}),s.fkCheck.map((l,c)=>e.jsx("div",{className:"text-warn text-mono",children:l},c))]})]})]})]})}function E(){const[s,n]=r.useState([]),[t,l]=r.useState(null),[c,h]=r.useState("30"),j=r.useCallback(async a=>{const m=a.daysOld?{action:"prune",daysOld:Number(c)}:{action:a.key};l(a.key);try{const i=await f(m);n(o=>[{...i,timestamp:Date.now()},...o].slice(0,20))}catch(i){n(o=>[{operation:a.key,success:!1,affected:0,reclaimedBytes:0,summary:i instanceof Error?i.message:String(i),timestamp:Date.now()},...o].slice(0,20))}finally{l(null)}},[c]);return e.jsxs("div",{className:"card",children:[e.jsx("div",{className:"card-header",children:"Actions"}),e.jsx("div",{className:"card-body",children:e.jsx("div",{className:"action-grid",children:k.map(a=>{const m=t===a.key,i=s.find(o=>o.operation===a.key);return e.jsxs("div",{className:"action-item",children:[e.jsxs("div",{className:"action-info",children:[e.jsxs("div",{className:"action-label",children:[a.label,a.dangerous&&e.jsx("span",{className:"badge badge-warn",children:"DESTRUCTIVE"})]}),e.jsx("div",{className:"action-desc",children:a.desc}),i&&e.jsx("div",{className:`action-result ${i.success?"text-ok":"text-error"}`,children:i.summary})]}),e.jsxs("div",{className:"action-controls",children:[a.daysOld&&e.jsx("input",{type:"number",min:1,max:365,value:c,onChange:o=>h(o.target.value),className:"days-input",disabled:m}),e.jsx("button",{className:`btn ${a.dangerous?"btn-danger":"btn-primary"}`,disabled:t!==null,onClick:()=>{a.confirm&&!window.confirm(a.confirm)||j(a)},children:m?"Running…":"Run"})]})]},a.key)})})})]})}function L(){const[s,n]=r.useState(null),[t,l]=r.useState(!1),[c,h]=r.useState(null),[j,a]=r.useState(!1),m=r.useCallback(async()=>{l(!0),h(null);try{const d=await C();n(d),a(!0)}catch(d){h(d instanceof Error?d.message:String(d))}finally{l(!1)}},[]),i=r.useCallback(()=>{if(!s)return;const d=JSON.stringify(s,null,2);navigator.clipboard.writeText(d).catch(()=>{})},[s]),o=r.useCallback(()=>{if(!s)return;const d=JSON.stringify(s,null,2),y=new Blob([d],{type:"application/json"}),b=URL.createObjectURL(y),g=document.createElement("a");g.href=b,g.download=`mega-compact-debug-bundle-${s.builtAt}.json`,g.click(),URL.revokeObjectURL(b)},[s]),u=s?.criticalEvents.length??0;return e.jsxs("div",{className:"card",children:[e.jsxs("div",{className:"card-header",children:["Debug Bundle",u>0&&e.jsxs("span",{className:"text-warn",style:{marginLeft:"1em"},children:[u," critical event",u!==1?"s":""," found"]})]}),e.jsxs("div",{className:"card-body",children:[e.jsx("p",{className:"text-muted",style:{marginBottom:"0.75em"},children:"Gather a diagnostic bundle (recent events, config flags, schema health, store stats) to attach to a bug report. Critical/compaction events are highlighted."}),e.jsx("button",{onClick:m,disabled:t,style:{marginRight:"0.5em"},children:t?"Gathering…":"Gather Debug Logs"}),c&&e.jsx("div",{className:"text-error",children:c}),s&&j&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:{marginTop:"0.75em",marginBottom:"0.5em"},children:[e.jsx("button",{onClick:i,style:{marginRight:"0.5em"},children:"Copy to clipboard"}),e.jsx("button",{onClick:o,children:"Download JSON"}),e.jsx("button",{onClick:()=>a(d=>!d),style:{marginLeft:"0.5em"},children:j?"Hide":"Show"})]}),u>0&&e.jsxs("div",{className:"stat-section",children:[e.jsxs("div",{className:"stat-label text-warn",children:["Critical events (",u,")"]}),e.jsx("pre",{className:"text-mono",style:{maxHeight:"12em",overflow:"auto"},children:JSON.stringify(s.criticalEvents,null,2)})]}),e.jsx("pre",{className:"text-mono",style:{maxHeight:"24em",overflow:"auto"},children:JSON.stringify(s,null,2)})]})]})]})}function T(){const{data:s,loading:n,error:t}=N(r.useCallback(()=>p(),[]),{pollInterval:15e3}),{data:l,loading:c,error:h}=N(r.useCallback(()=>v(),[]),{pollInterval:1e4});return e.jsxs("div",{className:"maintenance-tab",children:[e.jsxs("div",{className:"card-grid",children:[e.jsx(B,{data:l,loading:c,error:h}),e.jsx(R,{data:s,loading:n,error:t})]}),e.jsx(E,{}),e.jsx(L,{})]})}export{T as default};
2
- //# sourceMappingURL=MaintenanceTab-C0rdAMWc.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"MaintenanceTab-C0rdAMWc.js","sources":["../../src/tabs/MaintenanceTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/tabs/MaintenanceTab.tsx — Maintenance tab (v0.11.2 S49B).\n *\n * Three cards:\n * 1. Schema Health (schema version + integrity + column audit)\n * 2. DB Stats (file sizes + table row counts)\n * 3. Actions (one-time maintenance operations with results history)\n *\n * All three fetch independently; failures in one do not block the others.\n */\n\nimport type React from \"react\";\nimport { useState, useCallback } from \"react\";\nimport type {\n\tDbStatsResponse,\n\tSchemaHealthResponse,\n\tMaintenanceAction,\n\tMaintenanceActionResult,\n\tDebugBundleResponse,\n} from \"@contracts\";\nimport { useApi } from \"../hooks/useApi\";\nimport {\n\tfetchDbStats,\n\tfetchSchemaHealth,\n\tpostMaintenanceAction,\n\tfetchDebugBundle,\n} from \"../api/client\";\n\n// ---------------------------------------------------------------------------\n// Action config\n// ---------------------------------------------------------------------------\n\ninterface ActionDef {\n\tkey: string;\n\tlabel: string;\n\tdesc: string;\n\tdangerous: boolean;\n\tconfirm?: string;\n\tdaysOld?: boolean;\n}\n\nconst ACTIONS: ActionDef[] = [\n\t{\n\t\tkey: \"integrity-check\",\n\t\tlabel: \"Integrity Check\",\n\t\tdesc: \"Run PRAGMA integrity_check\",\n\t\tdangerous: false,\n\t},\n\t{\n\t\tkey: \"reconcile-dedup\",\n\t\tlabel: \"Reconcile Dedup Mirror\",\n\t\tdesc: \"Fix orphan dedup rows + backfill refs\",\n\t\tdangerous: false,\n\t\tconfirm: \"Reconcile dedup_mirror (safe read/write)?\",\n\t},\n\t{\n\t\tkey: \"checkpoint\",\n\t\tlabel: \"WAL Checkpoint\",\n\t\tdesc: \"Merge WAL into main DB (read-only)\",\n\t\tdangerous: false,\n\t},\n\t{\n\t\tkey: \"vacuum\",\n\t\tlabel: \"VACUUM\",\n\t\tdesc: \"Rebuild DB reclaiming free pages\",\n\t\tdangerous: true,\n\t\tconfirm: \"VACUUM rewrites the entire DB. Continue?\",\n\t},\n\t{\n\t\tkey: \"reindex\",\n\t\tlabel: \"REINDEX\",\n\t\tdesc: \"Rebuild all indexes\",\n\t\tdangerous: true,\n\t\tconfirm: \"REINDEX rebuilds indexes. Continue?\",\n\t},\n\t{\n\t\tkey: \"fts5-rebuild\",\n\t\tlabel: \"FTS5 Rebuild\",\n\t\tdesc: \"Rebuild full-text search index\",\n\t\tdangerous: true,\n\t\tconfirm: \"Rebuild FTS5 trigram index. Continue?\",\n\t},\n\t{\n\t\tkey: \"prune\",\n\t\tlabel: \"Prune Old Rows\",\n\t\tdesc: \"Delete transcripts + epochs older than N days\",\n\t\tdangerous: true,\n\t\tdaysOld: true,\n\t\tconfirm: \"Delete old raw_transcript rows. Continue?\",\n\t},\n];\n\n// ---------------------------------------------------------------------------\n// Format helpers (local — matches html.ts fmtBytes)\n// ---------------------------------------------------------------------------\n\nfunction fmtBytes(b: number): string {\n\tif (b < 1024) return `${b} B`;\n\tif (b < 1024 * 1024) return `${(b / 1024).toFixed(1)} KB`;\n\treturn `${(b / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n// ---------------------------------------------------------------------------\n// DB Stats card\n// ---------------------------------------------------------------------------\n\nfunction FileSizesCard({\n\tfiles,\n\tpageSize,\n\tpageCount,\n\tfreelistPages,\n}: {\n\tfiles: DbStatsResponse[\"storage\"][\"files\"];\n\tpageSize: number;\n\tpageCount: number;\n\tfreelistPages: number;\n}): React.ReactElement {\n\tconst total = files.dbBytes + files.walBytes + files.shmBytes;\n\treturn (\n\t\t<div className=\"stat-section\">\n\t\t\t<div className=\"stat-label\">File Sizes</div>\n\t\t\t<table className=\"compact-table\">\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>sqlite.db</td>\n\t\t\t\t\t\t<td className=\"num\">{fmtBytes(files.dbBytes)}</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t{files.walBytes > 0 && (\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td>.wal</td>\n\t\t\t\t\t\t\t<td className=\"num\">{fmtBytes(files.walBytes)}</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t)}\n\t\t\t\t\t{files.shmBytes > 0 && (\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<td>.shm</td>\n\t\t\t\t\t\t\t<td className=\"num\">{fmtBytes(files.shmBytes)}</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t)}\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>Total</td>\n\t\t\t\t\t\t<td className=\"num\">{fmtBytes(total)}</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>Page size</td>\n\t\t\t\t\t\t<td className=\"num\">{fmtBytes(pageSize)}</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td>Pages</td>\n\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t{pageCount.toLocaleString()} ({freelistPages.toLocaleString()}{\" \"}\n\t\t\t\t\t\t\tfree)\n\t\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>\n\t);\n}\n\nfunction TableRowCountsCard({\n\ttables,\n}: {\n\ttables: DbStatsResponse[\"tables\"];\n}): React.ReactElement {\n\tconst totalRows = tables.reduce((s, t) => s + Math.max(0, t.rowCount), 0);\n\treturn (\n\t\t<div className=\"stat-section\">\n\t\t\t<div className=\"stat-label\">\n\t\t\t\tTable Row Counts ({totalRows.toLocaleString()} total)\n\t\t\t</div>\n\t\t\t<table className=\"compact-table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>Table</th>\n\t\t\t\t\t\t<th className=\"num\">Rows</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t{tables.map((t) => (\n\t\t\t\t\t\t<tr key={t.table}>\n\t\t\t\t\t\t\t<td>{t.table}</td>\n\t\t\t\t\t\t\t<td className=\"num\">\n\t\t\t\t\t\t\t\t{t.rowCount >= 0 ? t.rowCount.toLocaleString() : \"—\"}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t))}\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>\n\t);\n}\n\nfunction DbStatsCard({\n\tdata,\n\tloading,\n\terror,\n}: {\n\tdata: DbStatsResponse | null;\n\tloading: boolean;\n\terror: Error | null;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"card\">\n\t\t\t<div className=\"card-header\">DB Stats</div>\n\t\t\t<div className=\"card-body\">\n\t\t\t\t{loading && !data && <span className=\"text-muted\">Loading…</span>}\n\t\t\t\t{error && !data && <span className=\"text-error\">{error.message}</span>}\n\t\t\t\t{data && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<FileSizesCard\n\t\t\t\t\t\t\tfiles={data.storage.files}\n\t\t\t\t\t\t\tpageSize={data.storage.pageSize}\n\t\t\t\t\t\t\tpageCount={data.storage.pageCount}\n\t\t\t\t\t\t\tfreelistPages={data.storage.freelistPages}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<TableRowCountsCard tables={data.tables} />\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Schema Health card\n// ---------------------------------------------------------------------------\n\nfunction ColumnAuditCard({\n\tcolumns,\n}: {\n\tcolumns: SchemaHealthResponse[\"columns\"];\n}): React.ReactElement {\n\tconst missing = columns.filter((c) => !c.present);\n\treturn (\n\t\t<div className=\"stat-section\">\n\t\t\t<div className=\"stat-label\">\n\t\t\t\tColumn Audit ({columns.length} columns, {missing.length} missing)\n\t\t\t</div>\n\t\t\t<table className=\"compact-table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>Table</th>\n\t\t\t\t\t\t<th>Column</th>\n\t\t\t\t\t\t<th>Decl</th>\n\t\t\t\t\t\t<th>Status</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t{columns.map((c) => (\n\t\t\t\t\t\t<tr key={`${c.table}.${c.column}`}>\n\t\t\t\t\t\t\t<td>{c.table}</td>\n\t\t\t\t\t\t\t<td>{c.column}</td>\n\t\t\t\t\t\t\t<td className=\"text-mono\">{c.expectedDecl}</td>\n\t\t\t\t\t\t\t<td className={c.present ? \"text-ok\" : \"text-error\"}>\n\t\t\t\t\t\t\t\t{c.present ? \"✓\" : \"MISSING\"}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t))}\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>\n\t);\n}\n\nfunction SchemaHealthCard({\n\tdata,\n\tloading,\n\terror,\n}: {\n\tdata: SchemaHealthResponse | null;\n\tloading: boolean;\n\terror: Error | null;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"card\">\n\t\t\t<div className=\"card-header\">\n\t\t\t\tSchema Health\n\t\t\t\t{data && (\n\t\t\t\t\t<span className={`badge ${data.healthy ? \"badge-ok\" : \"badge-bad\"}`}>\n\t\t\t\t\t\t{data.healthy ? \"HEALTHY\" : \"DEGRADED\"}\n\t\t\t\t\t</span>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<div className=\"card-body\">\n\t\t\t\t{loading && !data && <span className=\"text-muted\">Loading…</span>}\n\t\t\t\t{error && !data && <span className=\"text-error\">{error.message}</span>}\n\t\t\t\t{data && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<div className=\"stat-row\">\n\t\t\t\t\t\t\t<span className=\"stat-label\">Schema version</span>\n\t\t\t\t\t\t\t<span className=\"num\">{data.schemaVersion}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div className=\"stat-row\">\n\t\t\t\t\t\t\t<span className=\"stat-label\">Integrity</span>\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tclassName={\n\t\t\t\t\t\t\t\t\tdata.integrity[0] === \"ok\" ? \"text-ok\" : \"text-error\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{data.integrity.join(\"; \")}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<ColumnAuditCard columns={data.columns} />\n\t\t\t\t\t\t{data.fkCheck.length > 0 && (\n\t\t\t\t\t\t\t<div className=\"stat-section\">\n\t\t\t\t\t\t\t\t<div className=\"stat-label text-warn\">\n\t\t\t\t\t\t\t\t\tFK Check ({data.fkCheck.length})\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t{data.fkCheck.map((line, i) => (\n\t\t\t\t\t\t\t\t\t<div key={i} className=\"text-warn text-mono\">\n\t\t\t\t\t\t\t\t\t\t{line}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Actions card\n// ---------------------------------------------------------------------------\n\nfunction ActionsCard(): React.ReactElement {\n\tconst [results, setResults] = useState<MaintenanceActionResult[]>([]);\n\tconst [running, setRunning] = useState<string | null>(null);\n\tconst [days, setDays] = useState(\"30\");\n\n\tconst handleAction = useCallback(\n\t\tasync (def: ActionDef) => {\n\t\t\tconst action: MaintenanceAction = def.daysOld\n\t\t\t\t? { action: \"prune\", daysOld: Number(days) }\n\t\t\t\t: ({ action: def.key } as MaintenanceAction);\n\n\t\t\tsetRunning(def.key);\n\t\t\ttry {\n\t\t\t\tconst res = await postMaintenanceAction(action);\n\t\t\t\tsetResults((prev) =>\n\t\t\t\t\t[{ ...res, timestamp: Date.now() }, ...prev].slice(0, 20),\n\t\t\t\t);\n\t\t\t} catch (err) {\n\t\t\t\tsetResults((prev) =>\n\t\t\t\t\t[\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\toperation: def.key,\n\t\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\t\taffected: 0,\n\t\t\t\t\t\t\treclaimedBytes: 0,\n\t\t\t\t\t\t\tsummary: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t\ttimestamp: Date.now(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...prev,\n\t\t\t\t\t].slice(0, 20),\n\t\t\t\t);\n\t\t\t} finally {\n\t\t\t\tsetRunning(null);\n\t\t\t}\n\t\t},\n\t\t[days],\n\t);\n\n\treturn (\n\t\t<div className=\"card\">\n\t\t\t<div className=\"card-header\">Actions</div>\n\t\t\t<div className=\"card-body\">\n\t\t\t\t<div className=\"action-grid\">\n\t\t\t\t\t{ACTIONS.map((def) => {\n\t\t\t\t\t\tconst isRunning = running === def.key;\n\t\t\t\t\t\tconst lastResult = results.find((r) => r.operation === def.key);\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<div key={def.key} className=\"action-item\">\n\t\t\t\t\t\t\t\t<div className=\"action-info\">\n\t\t\t\t\t\t\t\t\t<div className=\"action-label\">\n\t\t\t\t\t\t\t\t\t\t{def.label}\n\t\t\t\t\t\t\t\t\t\t{def.dangerous && (\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"badge badge-warn\">DESTRUCTIVE</span>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t<div className=\"action-desc\">{def.desc}</div>\n\t\t\t\t\t\t\t\t\t{lastResult && (\n\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\tclassName={`action-result ${lastResult.success ? \"text-ok\" : \"text-error\"}`}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{lastResult.summary}\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"action-controls\">\n\t\t\t\t\t\t\t\t\t{def.daysOld && (\n\t\t\t\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\t\t\t\tmin={1}\n\t\t\t\t\t\t\t\t\t\t\tmax={365}\n\t\t\t\t\t\t\t\t\t\t\tvalue={days}\n\t\t\t\t\t\t\t\t\t\t\tonChange={(e) => setDays(e.target.value)}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"days-input\"\n\t\t\t\t\t\t\t\t\t\t\tdisabled={isRunning}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\tclassName={`btn ${def.dangerous ? \"btn-danger\" : \"btn-primary\"}`}\n\t\t\t\t\t\t\t\t\t\tdisabled={running !== null}\n\t\t\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\t\t\tif (def.confirm && !window.confirm(def.confirm)) return;\n\t\t\t\t\t\t\t\t\t\t\thandleAction(def);\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{isRunning ? \"Running…\" : \"Run\"}\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t);\n\t\t\t\t\t})}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Debug bundle card — gather diagnostic info for bug reports\n// ---------------------------------------------------------------------------\n\nfunction DebugBundleCard(): React.ReactElement {\n\tconst [bundle, setBundle] = useState<DebugBundleResponse | null>(null);\n\tconst [loading, setLoading] = useState(false);\n\tconst [error, setError] = useState<string | null>(null);\n\tconst [showJson, setShowJson] = useState(false);\n\n\tconst gather = useCallback(async () => {\n\t\tsetLoading(true);\n\t\tsetError(null);\n\t\ttry {\n\t\t\tconst res = await fetchDebugBundle();\n\t\t\tsetBundle(res);\n\t\t\tsetShowJson(true);\n\t\t} catch (err) {\n\t\t\tsetError(err instanceof Error ? err.message : String(err));\n\t\t} finally {\n\t\t\tsetLoading(false);\n\t\t}\n\t}, []);\n\n\tconst copyToClipboard = useCallback(() => {\n\t\tif (!bundle) return;\n\t\tconst text = JSON.stringify(bundle, null, 2);\n\t\tvoid navigator.clipboard.writeText(text).catch(() => {});\n\t}, [bundle]);\n\n\tconst downloadJson = useCallback(() => {\n\t\tif (!bundle) return;\n\t\tconst text = JSON.stringify(bundle, null, 2);\n\t\tconst blob = new Blob([text], { type: \"application/json\" });\n\t\tconst url = URL.createObjectURL(blob);\n\t\tconst a = document.createElement(\"a\");\n\t\ta.href = url;\n\t\ta.download = `mega-compact-debug-bundle-${bundle.builtAt}.json`;\n\t\ta.click();\n\t\tURL.revokeObjectURL(url);\n\t}, [bundle]);\n\n\tconst criticalCount = bundle?.criticalEvents.length ?? 0;\n\n\treturn (\n\t\t<div className=\"card\">\n\t\t\t<div className=\"card-header\">\n\t\t\t\tDebug Bundle\n\t\t\t\t{criticalCount > 0 && (\n\t\t\t\t\t<span className=\"text-warn\" style={{ marginLeft: \"1em\" }}>\n\t\t\t\t\t\t{criticalCount} critical event{criticalCount !== 1 ? \"s\" : \"\"} found\n\t\t\t\t\t</span>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t\t<div className=\"card-body\">\n\t\t\t\t<p className=\"text-muted\" style={{ marginBottom: \"0.75em\" }}>\n\t\t\t\t\tGather a diagnostic bundle (recent events, config flags, schema health,\n\t\t\t\t\tstore stats) to attach to a bug report. Critical/compaction events are\n\t\t\t\t\thighlighted.\n\t\t\t\t</p>\n\t\t\t\t<button onClick={gather} disabled={loading} style={{ marginRight: \"0.5em\" }}>\n\t\t\t\t\t{loading ? \"Gathering…\" : \"Gather Debug Logs\"}\n\t\t\t\t</button>\n\t\t\t\t{error && <div className=\"text-error\">{error}</div>}\n\t\t\t\t{bundle && showJson && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<div style={{ marginTop: \"0.75em\", marginBottom: \"0.5em\" }}>\n\t\t\t\t\t\t\t<button onClick={copyToClipboard} style={{ marginRight: \"0.5em\" }}>\n\t\t\t\t\t\t\t\tCopy to clipboard\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t<button onClick={downloadJson}>Download JSON</button>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tonClick={() => setShowJson((v) => !v)}\n\t\t\t\t\t\t\t\tstyle={{ marginLeft: \"0.5em\" }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{showJson ? \"Hide\" : \"Show\"}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t{criticalCount > 0 && (\n\t\t\t\t\t\t\t<div className=\"stat-section\">\n\t\t\t\t\t\t\t\t<div className=\"stat-label text-warn\">\n\t\t\t\t\t\t\t\t\tCritical events ({criticalCount})\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<pre className=\"text-mono\" style={{ maxHeight: \"12em\", overflow: \"auto\" }}>\n\t\t\t\t\t\t\t\t\t{JSON.stringify(bundle.criticalEvents, null, 2)}\n\t\t\t\t\t\t\t\t</pre>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<pre className=\"text-mono\" style={{ maxHeight: \"24em\", overflow: \"auto\" }}>\n\t\t\t\t\t\t\t{JSON.stringify(bundle, null, 2)}\n\t\t\t\t\t\t</pre>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// Main tab component\n// ---------------------------------------------------------------------------\n\nexport default function MaintenanceTab(): React.ReactElement {\n\tconst {\n\t\tdata: dbStats,\n\t\tloading: statsLoading,\n\t\terror: statsError,\n\t} = useApi<DbStatsResponse>(\n\t\tuseCallback(() => fetchDbStats(), []),\n\t\t{ pollInterval: 15000 },\n\t);\n\n\tconst {\n\t\tdata: schemaHealth,\n\t\tloading: healthLoading,\n\t\terror: healthError,\n\t} = useApi<SchemaHealthResponse>(\n\t\tuseCallback(() => fetchSchemaHealth(), []),\n\t\t{ pollInterval: 10000 },\n\t);\n\n\treturn (\n\t\t<div className=\"maintenance-tab\">\n\t\t\t<div className=\"card-grid\">\n\t\t\t\t<SchemaHealthCard\n\t\t\t\t\tdata={schemaHealth}\n\t\t\t\t\tloading={healthLoading}\n\t\t\t\t\terror={healthError}\n\t\t\t\t/>\n\t\t\t\t<DbStatsCard data={dbStats} loading={statsLoading} error={statsError} />\n\t\t\t</div>\n\t\t\t<ActionsCard />\n\t\t\t<DebugBundleCard />\n\t\t</div>\n\t);\n}\n"],"names":["ACTIONS","fmtBytes","b","FileSizesCard","files","pageSize","pageCount","freelistPages","total","jsxs","jsx","TableRowCountsCard","tables","totalRows","s","t","DbStatsCard","data","loading","error","Fragment","ColumnAuditCard","columns","missing","c","SchemaHealthCard","line","i","ActionsCard","results","setResults","useState","running","setRunning","days","setDays","handleAction","useCallback","def","action","res","postMaintenanceAction","prev","err","isRunning","lastResult","r","e","DebugBundleCard","bundle","setBundle","setLoading","setError","showJson","setShowJson","gather","fetchDebugBundle","copyToClipboard","text","downloadJson","blob","url","a","criticalCount","v","MaintenanceTab","dbStats","statsLoading","statsError","useApi","fetchDbStats","schemaHealth","healthLoading","healthError","fetchSchemaHealth"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{r as l,e as k,g as R,h as D,j as e}from"./index-B8k19B9g.js";const t={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}};function B(){const[s,S]=l.useState(null),[n,v]=l.useState(null),[c,E]=l.useState(null),[g,x]=l.useState(null),[f,m]=l.useState(!1),[i,h]=l.useState(null),[d,j]=l.useState(null),[b,y]=l.useState(null),o=l.useCallback(()=>{k().then(S).catch(r=>E(r instanceof Error?r.message:String(r)))},[]),u=l.useCallback(r=>{h(r),y(null),j(null),R({embedder:r}).then(a=>{j(a),h(null),o()}).catch(a=>{y(a instanceof Error?a.message:String(a)),h(null)})},[o]),C=l.useCallback(()=>{m(!0),x(null),D().then(r=>{v(r),m(!1)}).catch(r=>{x(r instanceof Error?r.message:String(r)),m(!1)})},[]);l.useEffect(()=>{o()},[o]),l.useEffect(()=>{const r=setInterval(o,3e4);return()=>clearInterval(r)},[o]);const w=r=>{switch(r){case"trigram":return"TrigramEmbedder (heuristic, default)";case"http":return"HTTP Embedder (BYO localhost)";case"minilm":return"MiniLM (experimental)";default:return"Unknown"}},z=s?.currentEmbedder==="trigram"&&e.jsxs("div",{style:t.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."]}),p=r=>{const a=r?"#1a5a1a":"#3a1a1a",T=r?"#4caf50":"#f44336";return e.jsx("span",{style:{...t.badge,background:a,color:T},children:r?"Detected":"Not found"})};return e.jsxs("div",{style:t.container,children:[e.jsx("h2",{style:{fontSize:"1.3rem",marginTop:0,marginBottom:"1rem"},children:"Embedder Setup"}),e.jsxs("div",{style:t.section,children:[e.jsx("h3",{style:t.sectionTitle,children:"Current Embedder Configuration"}),c&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error: ",c]}),s&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:t.row,children:[e.jsx("span",{style:t.label,children:"Active Embedder:"}),e.jsx("span",{style:t.value,children:w(s.currentEmbedder)})]}),e.jsxs("div",{style:t.row,children:[e.jsx("span",{style:t.label,children:"Embedding URL:"}),e.jsx("span",{style:t.value,children:s.embeddingUrl??e.jsx("span",{style:{color:"#888"},children:"not set"})})]}),e.jsxs("div",{style:t.row,children:[e.jsx("span",{style:t.label,children:"Embed Cache:"}),e.jsx("span",{style:t.value,children:s.embedCache??e.jsx("span",{style:{color:"#888"},children:"not set"})})]}),e.jsxs("div",{style:t.row,children:[e.jsx("span",{style:t.label,children:"MiniLM:"}),e.jsx("span",{style:t.value,children:s.minilm?"enabled":"disabled"})]}),z]}),!s&&!c&&e.jsx("p",{style:{color:"#888",fontSize:"0.85rem"},children:"Loading configuration..."})]}),e.jsxs("div",{style:t.section,children:[e.jsx("h3",{style:t.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:t.detectRow,children:[e.jsx("span",{children:e.jsx("strong",{children:"Ollama"})}),n.ollama!==null?e.jsxs("span",{children:[p(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:t.detectRow,children:[e.jsx("span",{children:e.jsx("strong",{children:"llama.cpp"})}),n.llamaCpp!==null?e.jsxs("span",{children:[p(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:t.detectRow,children:[e.jsx("span",{children:e.jsx("strong",{children:"ONNX Runtime"})}),n.onnx!==null?e.jsxs("span",{children:[p(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]})]}),g&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error: ",g]}),e.jsxs("div",{style:{marginTop:"1rem"},children:[e.jsx("button",{style:t.button,onClick:C,disabled:f,children:f?"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:{...t.button,opacity:n.ollama?.installed?1:.4},onClick:()=>u("ollama"),disabled:!n.ollama?.installed||i!==null,children:i==="ollama"?"Writing...":"Use Ollama"}),e.jsx("button",{style:{...t.button,opacity:n.llamaCpp?.installed?1:.4},onClick:()=>u("llama"),disabled:!n.llamaCpp?.installed||i!==null,children:i==="llama"?"Writing...":"Use llama.cpp"}),e.jsx("button",{style:{...t.button,background:"#444"},onClick:()=>u("trigram"),disabled:i!==null,children:i==="trigram"?"Writing...":"Use Trigram (default)"})]}),d&&e.jsx("div",{style:t.warning,children:d.alreadyActive?"Already active — no restart needed.":`Configured ${d.embedder}. Restart pi to activate (config written to ${d.envPath}).`}),b&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem",marginTop:"0.5rem"},children:["Configure error: ",b]})]})]}),e.jsxs("div",{style:t.section,children:[e.jsx("h3",{style:t.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:"})," Install"," ",e.jsx("code",{children:"onnxruntime-node"})," in the project root. Not yet integrated — see docs for manual setup."]})]})]})]})}export{B as default};
2
- //# sourceMappingURL=SetupTab-Duy1LJhg.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SetupTab-Duy1LJhg.js","sources":["../../src/tabs/SetupTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/tabs/SetupTab.tsx — Setup wizard tab (P0b).\n *\n * Shows current embedder configuration, warns about trigram recall quality,\n * and mirrors the /megasetup command with detection results.\n *\n * PREVENT-PI-004: all data comes from localhost dashboard API endpoints —\n * no external network calls.\n */\n\nimport type React from \"react\";\nimport { useState, useEffect, useCallback } from \"react\";\nimport type { SetupStatusResponse, SetupDetectResponse, SetupConfigureResponse } from \"@contracts\";\nimport { fetchSetupStatus, fetchSetupDetect, configureEmbedder } from \"../api/client\";\n\n// ---------------------------------------------------------------------------\n// Style constants\n// ---------------------------------------------------------------------------\n\nconst styles: Record<string, React.CSSProperties> = {\n\tcontainer: {\n\t\tpadding: \"1rem\",\n\t\tmaxWidth: \"720px\",\n\t\tmargin: \"0 auto\",\n\t\tfontFamily: \"system-ui, sans-serif\",\n\t\tcolor: \"#e0e0e0\",\n\t},\n\tsection: {\n\t\tbackground: \"#1a1a2e\",\n\t\tborderRadius: \"8px\",\n\t\tpadding: \"1rem\",\n\t\tmarginBottom: \"1rem\",\n\t\tborder: \"1px solid #2a2a4e\",\n\t},\n\tsectionTitle: {\n\t\tfontSize: \"1.1rem\",\n\t\tfontWeight: 700,\n\t\tmarginTop: 0,\n\t\tmarginBottom: \"0.75rem\",\n\t\tcolor: \"#e0e0e0\",\n\t\tborderBottom: \"1px solid #333\",\n\t\tpaddingBottom: \"0.5rem\",\n\t},\n\tlabel: { fontWeight: 600, color: \"#a0a0c0\", marginRight: \"0.5rem\" },\n\tvalue: { color: \"#e0e0e0\" },\n\trow: { marginBottom: \"0.4rem\", fontSize: \"0.9rem\" },\n\twarning: {\n\t\tbackground: \"#3a2a00\",\n\t\tborder: \"1px solid #665500\",\n\t\tborderRadius: \"8px\",\n\t\tpadding: \"0.75rem\",\n\t\tmarginTop: \"0.5rem\",\n\t\tcolor: \"#ffcc00\",\n\t\tfontSize: \"0.85rem\",\n\t},\n\tbadge: {\n\t\tdisplay: \"inline-block\",\n\t\tpadding: \"0.15rem 0.5rem\",\n\t\tborderRadius: \"4px\",\n\t\tfontSize: \"0.8rem\",\n\t\tfontWeight: 600,\n\t\tmarginLeft: \"0.5rem\",\n\t},\n\tdetectRow: {\n\t\tdisplay: \"flex\",\n\t\tjustifyContent: \"space-between\",\n\t\talignItems: \"center\",\n\t\tpadding: \"0.5rem 0\",\n\t\tborderBottom: \"1px solid #2a2a4e\",\n\t},\n\tbutton: {\n\t\tbackground: \"#3a5a9f\",\n\t\tcolor: \"#fff\",\n\t\tborder: \"none\",\n\t\tborderRadius: \"6px\",\n\t\tpadding: \"0.5rem 1rem\",\n\t\tcursor: \"pointer\",\n\t\tfontSize: \"0.9rem\",\n\t\tfontWeight: 600,\n\t},\n};\n\n// ---------------------------------------------------------------------------\n// SetupTab component\n// ---------------------------------------------------------------------------\n\nexport default function SetupTab(): React.ReactElement {\n\tconst [status, setStatus] = useState<SetupStatusResponse | null>(null);\n\tconst [detect, setDetect] = useState<SetupDetectResponse | null>(null);\n\tconst [statusError, setStatusError] = useState<string | null>(null);\n\tconst [detectError, setDetectError] = useState<string | null>(null);\n\tconst [runningDetect, setRunningDetect] = useState(false);\n\tconst [configuring, setConfiguring] = useState<string | null>(null);\n\tconst [configResult, setConfigResult] = useState<SetupConfigureResponse | null>(null);\n\tconst [configError, setConfigError] = useState<string | null>(null);\n\n\tconst loadStatus = useCallback(() => {\n\t\tfetchSetupStatus()\n\t\t\t.then(setStatus)\n\t\t\t.catch((e: unknown) =>\n\t\t\t\tsetStatusError(e instanceof Error ? e.message : String(e)),\n\t\t\t);\n\t}, []);\n\n\tconst applyEmbedder = useCallback((embedder: \"ollama\" | \"llama\" | \"trigram\") => {\n\t\tsetConfiguring(embedder);\n\t\tsetConfigError(null);\n\t\tsetConfigResult(null);\n\t\tconfigureEmbedder({ embedder })\n\t\t\t.then((r) => {\n\t\t\t\tsetConfigResult(r);\n\t\t\t\tsetConfiguring(null);\n\t\t\t\tloadStatus();\n\t\t\t})\n\t\t\t.catch((e: unknown) => {\n\t\t\t\tsetConfigError(e instanceof Error ? e.message : String(e));\n\t\t\t\tsetConfiguring(null);\n\t\t\t});\n\t}, [loadStatus]);\n\n\tconst runDetect = useCallback(() => {\n\t\tsetRunningDetect(true);\n\t\tsetDetectError(null);\n\t\tfetchSetupDetect()\n\t\t\t.then((d) => {\n\t\t\t\tsetDetect(d);\n\t\t\t\tsetRunningDetect(false);\n\t\t\t})\n\t\t\t.catch((e: unknown) => {\n\t\t\t\tsetDetectError(e instanceof Error ? e.message : String(e));\n\t\t\t\tsetRunningDetect(false);\n\t\t\t});\n\t}, []);\n\n\tuseEffect(() => {\n\t\tloadStatus();\n\t}, [loadStatus]);\n\n\t// Poll status every 30s\n\tuseEffect(() => {\n\t\tconst id = setInterval(loadStatus, 30000);\n\t\treturn () => clearInterval(id);\n\t}, [loadStatus]);\n\n\t// -----------------------------------------------------------------------\n\t// Render helpers\n\t// -----------------------------------------------------------------------\n\n\tconst embedderLabel = (e: string): string => {\n\t\tswitch (e) {\n\t\t\tcase \"trigram\":\n\t\t\t\treturn \"TrigramEmbedder (heuristic, default)\";\n\t\t\tcase \"http\":\n\t\t\t\treturn \"HTTP Embedder (BYO localhost)\";\n\t\t\tcase \"minilm\":\n\t\t\t\treturn \"MiniLM (experimental)\";\n\t\t\tdefault:\n\t\t\t\treturn \"Unknown\";\n\t\t}\n\t};\n\n\tconst trigramWarning = status?.currentEmbedder === \"trigram\" && (\n\t\t<div style={styles.warning}>\n\t\t\t<strong>Note:</strong> TrigramEmbedder is a heuristic-strength default\n\t\t\tembedder. It works without any setup but recall quality may be lower\n\t\t\tthan a dedicated embedding backend. If you notice poor recall results,\n\t\t\tconsider installing Ollama and running the{\" \"}\n\t\t\t<code>/megasetup</code> command, or set{\" \"}\n\t\t\t<code>MEGACOMPACT_EMBEDDING_URL</code> to point at your own localhost\n\t\t\tembedding server.\n\t\t</div>\n\t);\n\n\tconst detectBadge = (installed: boolean): React.ReactElement => {\n\t\tconst bg = installed ? \"#1a5a1a\" : \"#3a1a1a\";\n\t\tconst color = installed ? \"#4caf50\" : \"#f44336\";\n\t\treturn (\n\t\t\t<span style={{ ...styles.badge, background: bg, color }}>\n\t\t\t\t{installed ? \"Detected\" : \"Not found\"}\n\t\t\t</span>\n\t\t);\n\t};\n\n\t// -----------------------------------------------------------------------\n\t// Main render\n\t// -----------------------------------------------------------------------\n\n\treturn (\n\t\t<div style={styles.container}>\n\t\t\t<h2 style={{ fontSize: \"1.3rem\", marginTop: 0, marginBottom: \"1rem\" }}>\n\t\t\t\tEmbedder Setup\n\t\t\t</h2>\n\n\t\t\t{/* Current Config Section */}\n\t\t\t<div style={styles.section}>\n\t\t\t\t<h3 style={styles.sectionTitle}>Current Embedder Configuration</h3>\n\t\t\t\t{statusError && (\n\t\t\t\t\t<p style={{ color: \"#f44336\", fontSize: \"0.85rem\" }}>\n\t\t\t\t\t\tError: {statusError}\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t\t{status && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<div style={styles.row}>\n\t\t\t\t\t\t\t<span style={styles.label}>Active Embedder:</span>\n\t\t\t\t\t\t\t<span style={styles.value}>\n\t\t\t\t\t\t\t\t{embedderLabel(status.currentEmbedder)}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div style={styles.row}>\n\t\t\t\t\t\t\t<span style={styles.label}>Embedding URL:</span>\n\t\t\t\t\t\t\t<span style={styles.value}>\n\t\t\t\t\t\t\t\t{status.embeddingUrl ?? (\n\t\t\t\t\t\t\t\t\t<span style={{ color: \"#888\" }}>not set</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div style={styles.row}>\n\t\t\t\t\t\t\t<span style={styles.label}>Embed Cache:</span>\n\t\t\t\t\t\t\t<span style={styles.value}>\n\t\t\t\t\t\t\t\t{status.embedCache ?? (\n\t\t\t\t\t\t\t\t\t<span style={{ color: \"#888\" }}>not set</span>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div style={styles.row}>\n\t\t\t\t\t\t\t<span style={styles.label}>MiniLM:</span>\n\t\t\t\t\t\t\t<span style={styles.value}>{status.minilm ? \"enabled\" : \"disabled\"}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t{trigramWarning}\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t\t{!status && !statusError && (\n\t\t\t\t\t<p style={{ color: \"#888\", fontSize: \"0.85rem\" }}>\n\t\t\t\t\t\tLoading configuration...\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\t\t\t</div>\n\n\t\t\t{/* Detection Section */}\n\t\t\t<div style={styles.section}>\n\t\t\t\t<h3 style={styles.sectionTitle}>Local Embedder Detection</h3>\n\t\t\t\t<p style={{ fontSize: \"0.85rem\", color: \"#a0a0c0\", marginTop: 0 }}>\n\t\t\t\t\tDetect which local embedding backends are available on this machine.\n\t\t\t\t\tNo software is installed — detection only.\n\t\t\t\t</p>\n\n\t\t\t\t{detect && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t{/* Ollama */}\n\t\t\t\t\t\t<div style={styles.detectRow}>\n\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t<strong>Ollama</strong>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t{detect.ollama !== null ? (\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t{detectBadge(detect.ollama.installed)}\n\t\t\t\t\t\t\t\t\t{detect.ollama.installed && (\n\t\t\t\t\t\t\t\t\t\t<span style={{ fontSize: \"0.8rem\", color: \"#a0a0c0\", marginLeft: \"0.5rem\" }}>\n\t\t\t\t\t\t\t\t\t\t\t{detect.ollama.running\n\t\t\t\t\t\t\t\t\t\t\t\t? `server running, ${detect.ollama.models.length} model(s)`\n\t\t\t\t\t\t\t\t\t\t\t\t: \"server not running\"}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t)}\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\t\t<span style={{ color: \"#888\", fontSize: \"0.85rem\" }}>\n\t\t\t\t\t\t\t\t\tnot checked\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</div>\n\n\t\t\t\t\t\t{/* llama.cpp */}\n\t\t\t\t\t\t<div style={styles.detectRow}>\n\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t<strong>llama.cpp</strong>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t{detect.llamaCpp !== null ? (\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t{detectBadge(detect.llamaCpp.installed)}\n\t\t\t\t\t\t\t\t\t{detect.llamaCpp.installed && detect.llamaCpp.detail && (\n\t\t\t\t\t\t\t\t\t\t<span style={{ fontSize: \"0.8rem\", color: \"#a0a0c0\", marginLeft: \"0.5rem\" }}>\n\t\t\t\t\t\t\t\t\t\t\t{detect.llamaCpp.detail}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t)}\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\t\t<span style={{ color: \"#888\", fontSize: \"0.85rem\" }}>\n\t\t\t\t\t\t\t\t\tnot checked\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</div>\n\n\t\t\t\t\t\t{/* ONNX */}\n\t\t\t\t\t\t<div style={styles.detectRow}>\n\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t<strong>ONNX Runtime</strong>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t{detect.onnx !== null ? (\n\t\t\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\t\t\t{detectBadge(detect.onnx.installed)}\n\t\t\t\t\t\t\t\t\t{detect.onnx.installed && detect.onnx.detail && (\n\t\t\t\t\t\t\t\t\t\t<span style={{ fontSize: \"0.8rem\", color: \"#a0a0c0\", marginLeft: \"0.5rem\" }}>\n\t\t\t\t\t\t\t\t\t\t\t{detect.onnx.detail}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t)}\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\t\t<span style={{ color: \"#888\", fontSize: \"0.85rem\" }}>\n\t\t\t\t\t\t\t\t\tnot checked\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</div>\n\n\t\t\t\t\t\t{detect.error && (\n\t\t\t\t\t\t\t<p style={{ color: \"#f44336\", fontSize: \"0.8rem\", marginTop: \"0.5rem\" }}>\n\t\t\t\t\t\t\t\tDetection error: {detect.error}\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</>\n\t\t\t\t)}\n\n\t\t\t\t{detectError && (\n\t\t\t\t\t<p style={{ color: \"#f44336\", fontSize: \"0.85rem\" }}>\n\t\t\t\t\t\tError: {detectError}\n\t\t\t\t\t</p>\n\t\t\t\t)}\n\n\t\t\t\t<div style={{ marginTop: \"1rem\" }}>\n\t\t\t\t\t<button\n\t\t\t\t\t\tstyle={styles.button}\n\t\t\t\t\t\tonClick={runDetect}\n\t\t\t\t\t\tdisabled={runningDetect}\n\t\t\t\t\t>\n\t\t\t\t\t\t{runningDetect ? \"Detecting...\" : \"Run Detection\"}\n\t\t\t\t\t</button>\n\t\t\t\t\t<span style={{ fontSize: \"0.8rem\", color: \"#888\", marginLeft: \"0.75rem\" }}>\n\t\t\t\t\t\tOr run <code>/megasetup</code> in the chat for an interactive wizard.\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\n\t\t\t\t{/* Configure buttons — appear after detection runs */}\n\t\t\t\t{detect && (\n\t\t\t\t\t<div style={{ marginTop: \"1rem\", paddingTop: \"0.75rem\", borderTop: \"1px solid #2a2a4e\" }}>\n\t\t\t\t\t\t<div style={{ fontSize: \"0.9rem\", fontWeight: 600, marginBottom: \"0.5rem\" }}>\n\t\t\t\t\t\t\tConfigure\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div style={{ display: \"flex\", gap: \"0.5rem\", flexWrap: \"wrap\" }}>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tstyle={{ ...styles.button, opacity: detect.ollama?.installed ? 1 : 0.4 }}\n\t\t\t\t\t\t\t\tonClick={() => applyEmbedder(\"ollama\")}\n\t\t\t\t\t\t\t\tdisabled={!detect.ollama?.installed || configuring !== null}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{configuring === \"ollama\" ? \"Writing...\" : \"Use Ollama\"}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tstyle={{ ...styles.button, opacity: detect.llamaCpp?.installed ? 1 : 0.4 }}\n\t\t\t\t\t\t\t\tonClick={() => applyEmbedder(\"llama\")}\n\t\t\t\t\t\t\t\tdisabled={!detect.llamaCpp?.installed || configuring !== null}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{configuring === \"llama\" ? \"Writing...\" : \"Use llama.cpp\"}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\tstyle={{ ...styles.button, background: \"#444\" }}\n\t\t\t\t\t\t\t\tonClick={() => applyEmbedder(\"trigram\")}\n\t\t\t\t\t\t\t\tdisabled={configuring !== null}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{configuring === \"trigram\" ? \"Writing...\" : \"Use Trigram (default)\"}\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t{configResult && (\n\t\t\t\t\t\t\t<div style={styles.warning}>\n\t\t\t\t\t\t\t\t{configResult.alreadyActive\n\t\t\t\t\t\t\t\t\t? \"Already active — no restart needed.\"\n\t\t\t\t\t\t\t\t\t: `Configured ${configResult.embedder}. Restart pi to activate (config written to ${configResult.envPath}).`}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t{configError && (\n\t\t\t\t\t\t\t<p style={{ color: \"#f44336\", fontSize: \"0.85rem\", marginTop: \"0.5rem\" }}>\n\t\t\t\t\t\t\t\tConfigure error: {configError}\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t</div>\n\n\t\t\t{/* Help Section */}\n\t\t\t<div style={styles.section}>\n\t\t\t\t<h3 style={styles.sectionTitle}>How to Upgrade</h3>\n\t\t\t\t<ul style={{ fontSize: \"0.85rem\", lineHeight: 1.6, paddingLeft: \"1.25rem\" }}>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<strong>Ollama:</strong> Install from{\" \"}\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\thref=\"https://ollama.com\"\n\t\t\t\t\t\t\tstyle={{ color: \"#6a9fff\" }}\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tollama.com\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t, then <code>ollama pull nomic-embed-text</code> and restart pi.\n\t\t\t\t\t\tSet <code>MEGACOMPACT_EMBEDDING_URL=http://localhost:11434/api/embeddings</code>.\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<strong>llama.cpp:</strong> Build or install llama.cpp, run{\" \"}\n\t\t\t\t\t\t<code>llama-server</code> with an embedding model, and set\n\t\t\t\t\t\tthe URL accordingly.\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<strong>ONNX Runtime:</strong> Install{\" \"}\n\t\t\t\t\t\t<code>onnxruntime-node</code> in the project root. Not yet\n\t\t\t\t\t\tintegrated — see docs for manual setup.\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n"],"names":["styles","SetupTab","status","setStatus","useState","detect","setDetect","statusError","setStatusError","detectError","setDetectError","runningDetect","setRunningDetect","configuring","setConfiguring","configResult","setConfigResult","configError","setConfigError","loadStatus","useCallback","fetchSetupStatus","e","applyEmbedder","embedder","configureEmbedder","r","runDetect","fetchSetupDetect","d","useEffect","id","embedderLabel","trigramWarning","jsx","detectBadge","installed","bg","color","jsxs","Fragment"],"mappings":"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"}