pi-mega-compact 0.13.2 → 0.13.3

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 (53) hide show
  1. package/dist/extensions/dashboard-server/api-contracts/endpoints/registry.js +13 -0
  2. package/dist/extensions/dashboard-server/api-contracts/rag-settings.js +10 -0
  3. package/dist/extensions/dashboard-server/routes-rag-settings.js +169 -0
  4. package/dist/extensions/dashboard-server/routes.js +1 -0
  5. package/dist/extensions/dashboard-server/server.js +3 -1
  6. package/dist/src/config.js +14 -7
  7. package/dist/src/recall/sync.js +4 -3
  8. package/extensions/dashboard-client/dist/assets/{CacheTab-DPRHjYZ0.js → CacheTab-Cqnc7lMg.js} +2 -2
  9. package/extensions/dashboard-client/dist/assets/{CacheTab-DPRHjYZ0.js.map → CacheTab-Cqnc7lMg.js.map} +1 -1
  10. package/extensions/dashboard-client/dist/assets/{EventsTab-CgwYq-Qf.js → EventsTab-tYk3VFAp.js} +2 -2
  11. package/extensions/dashboard-client/dist/assets/{EventsTab-CgwYq-Qf.js.map → EventsTab-tYk3VFAp.js.map} +1 -1
  12. package/extensions/dashboard-client/dist/assets/{HealthTab-BgOCjVzR.js → HealthTab-D2_kjgxw.js} +2 -2
  13. package/extensions/dashboard-client/dist/assets/{HealthTab-BgOCjVzR.js.map → HealthTab-D2_kjgxw.js.map} +1 -1
  14. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-Yw1yFpsy.js → MaintenanceTab-Bc-uPYrz.js} +2 -2
  15. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-Yw1yFpsy.js.map → MaintenanceTab-Bc-uPYrz.js.map} +1 -1
  16. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-yHUX7Yzi.js → MemoryMapTab-D1V9g_NC.js} +2 -2
  17. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-yHUX7Yzi.js.map → MemoryMapTab-D1V9g_NC.js.map} +1 -1
  18. package/extensions/dashboard-client/dist/assets/{MetricsTab-CcH9fP8P.js → MetricsTab-DT_XfL96.js} +2 -2
  19. package/extensions/dashboard-client/dist/assets/{MetricsTab-CcH9fP8P.js.map → MetricsTab-DT_XfL96.js.map} +1 -1
  20. package/extensions/dashboard-client/dist/assets/{OverviewTab-BOs8ZNev.js → OverviewTab-BY6KZCme.js} +2 -2
  21. package/extensions/dashboard-client/dist/assets/{OverviewTab-BOs8ZNev.js.map → OverviewTab-BY6KZCme.js.map} +1 -1
  22. package/extensions/dashboard-client/dist/assets/{ReposTab-B-MfSPvg.js → ReposTab-CeS-tpDM.js} +2 -2
  23. package/extensions/dashboard-client/dist/assets/{ReposTab-B-MfSPvg.js.map → ReposTab-CeS-tpDM.js.map} +1 -1
  24. package/extensions/dashboard-client/dist/assets/{SessionsTab-BmeN649Q.js → SessionsTab-C30AwyoF.js} +2 -2
  25. package/extensions/dashboard-client/dist/assets/{SessionsTab-BmeN649Q.js.map → SessionsTab-C30AwyoF.js.map} +1 -1
  26. package/extensions/dashboard-client/dist/assets/SetupTab-BJUHOVK2.js +2 -0
  27. package/extensions/dashboard-client/dist/assets/SetupTab-BJUHOVK2.js.map +1 -0
  28. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-DnPg0L0z.js → TimeSavedCard-p55K1tFP.js} +2 -2
  29. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-DnPg0L0z.js.map → TimeSavedCard-p55K1tFP.js.map} +1 -1
  30. package/extensions/dashboard-client/dist/assets/{TopicsTab-BODHOg_b.js → TopicsTab-D8FqyAbK.js} +2 -2
  31. package/extensions/dashboard-client/dist/assets/{TopicsTab-BODHOg_b.js.map → TopicsTab-D8FqyAbK.js.map} +1 -1
  32. package/extensions/dashboard-client/dist/assets/{TurnsTab-BK0I7hKr.js → TurnsTab-ju-nXDys.js} +2 -2
  33. package/extensions/dashboard-client/dist/assets/{TurnsTab-BK0I7hKr.js.map → TurnsTab-ju-nXDys.js.map} +1 -1
  34. package/extensions/dashboard-client/dist/assets/{index-mOlljTFI.js → index-BEj1Zahy.js} +8 -8
  35. package/extensions/dashboard-client/dist/assets/index-BEj1Zahy.js.map +1 -0
  36. package/extensions/dashboard-client/dist/assets/{useSSE-BYOtv1-3.js → useSSE-p1pOI_-P.js} +2 -2
  37. package/extensions/dashboard-client/dist/assets/{useSSE-BYOtv1-3.js.map → useSSE-p1pOI_-P.js.map} +1 -1
  38. package/extensions/dashboard-client/dist/index.html +1 -1
  39. package/extensions/dashboard-client/src/api/client.ts +17 -0
  40. package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderSetup.tsx +2 -0
  41. package/extensions/dashboard-client/src/tabs/SetupTab/RagSettingsCard.tsx +160 -0
  42. package/extensions/dashboard-server/api-contracts/endpoints/registry.ts +23 -0
  43. package/extensions/dashboard-server/api-contracts/index.ts +8 -0
  44. package/extensions/dashboard-server/api-contracts/rag-settings.ts +42 -0
  45. package/extensions/dashboard-server/routes-rag-settings.ts +207 -0
  46. package/extensions/dashboard-server/routes.ts +1 -0
  47. package/extensions/dashboard-server/server.ts +2 -0
  48. package/package.json +1 -1
  49. package/src/config.ts +15 -7
  50. package/src/recall/sync.ts +4 -3
  51. package/extensions/dashboard-client/dist/assets/SetupTab-nOknoph5.js +0 -2
  52. package/extensions/dashboard-client/dist/assets/SetupTab-nOknoph5.js.map +0 -1
  53. package/extensions/dashboard-client/dist/assets/index-mOlljTFI.js.map +0 -1
@@ -0,0 +1,2 @@
1
+ import{r as s,j as e,c as L,d as P,e as $,p as q,g as X,h as Y,i as J,k as K,l as Q,m as Z,n as ee}from"./index-BEj1Zahy.js";function te(t){try{return new Date(t*1e3).toLocaleString()}catch{return"—"}}function F({achievements:t}){const h=s.useRef(0),[n,f]=s.useState(null),o=t.reduce((l,d)=>Math.max(l,d.unlocked_at??0),0),u=h.current;s.useEffect(()=>{o>h.current&&(h.current=o)},[o]),s.useEffect(()=>{if(u>0&&o>u){const l=t.filter(d=>d.unlocked_at!=null&&(d.unlocked_at??0)>u);if(l.length>0){const d=l.map(a=>`${a.icon??""} ${a.title}`.trim()).join(", ")+" unlocked!";f(d);const x=setTimeout(()=>f(null),4e3);return()=>clearTimeout(x)}}},[t,o,u]);const p=t.filter(l=>!(l.hidden===1&&l.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:[p.length===0&&e.jsx("span",{className:"repo-none",children:"no achievements yet"}),p.map(l=>{if(l.unlocked_at!=null){const d=u>0&&(l.unlocked_at??0)>u;return e.jsxs("div",{className:`ach-tile unlocked${d?" just-unlocked":""}`,children:[l.icon??""," ",l.title,e.jsxs("span",{className:"ach-detail",children:["unlocked ",te(l.unlocked_at)]})]},l.id)}return e.jsxs("div",{className:"ach-tile locked",children:["??? ",l.title]},l.id)})]})]})}function B(t){return(Math.round(t*10)/10).toString()+"%"}function O(t){return t!=null?new Date(t).toLocaleString():"—"}function U(t){return t&&typeof t=="object"?t:{}}function se(t){return t.split("/").pop()||t}function I({title:t,rows:h,badge:n,renderValue:f}){return e.jsxs("div",{className:"lb-card",children:[e.jsxs("h3",{children:[t,n]}),h.length===0?e.jsx("div",{className:"lb-empty",children:"—"}):e.jsx("table",{children:e.jsx("tbody",{children:h.map((o,u)=>e.jsxs("tr",{children:[e.jsx("td",{title:o.repo_root,children:se(o.repo_root)}),e.jsx("td",{className:"num",children:f(o)})]},`${o.repo_root}-${u}`))})})]})}function ne(){const[t,h]=s.useState({}),[n,f]=s.useState(0),[o,u]=s.useState([]),[p,l]=s.useState(!1),[d,x]=s.useState(!0),[a,b]=s.useState(null),i=s.useRef(0),g=s.useCallback(async()=>{try{const[m,y,c,v,w,V]=await Promise.all([L({metric:"cache",limit:25}),L({metric:"dedupe",limit:25}),L({metric:"turns",limit:25}),L({metric:"mega_cache",limit:25}),L({metric:"repos",limit:1}),P()]),G=v.find(A=>A.ts>i.current&&A.value>100);i.current>0&&G&&(b(`oopsie! cache went to ${Math.round(G.value)}% — MEGA CACHE 🥧`),setTimeout(()=>b(null),4e3)),v.length>0&&(i.current=Math.max(...v.map(A=>A.ts))),h({cache:m,dedupe:y,turns:c,mega_cache:v}),f(w[0]?.value??0),u(V)}catch{}finally{x(!1)}},[]);s.useEffect(()=>{let m=!0;const y=async()=>{m&&await g()};y();const c=setInterval(()=>void y(),15e3);return()=>{m=!1,clearInterval(c)}},[g]),s.useEffect(()=>{let m=!0;const y=async()=>{try{const v=await $();m&&(l(!!v.game_mode_on),v.theme&&(document.documentElement.dataset.theme=v.theme))}catch{}};y();const c=setInterval(()=>void y(),15e3);return()=>{m=!1,clearInterval(c)}},[]);const E=t.mega_cache??[];let j=null,T=null;for(const m of E){(j==null||m.value>j)&&(j=m.value);const y=U(m.meta),c=y.firstSeenTs??y.firstSeen??m.ts;(T==null||c<T)&&(T=c)}const z=j!=null&&j>100,S=t.turns??[],R=S.reduce((m,y)=>Math.max(m,y.value),0),D=Math.floor(Math.log2(R+1))+1,M=(t.cache?.length??0)>0||(t.dedupe?.length??0)>0||S.length>0||E.length>0||n>0;return e.jsxs("div",{className:`game-tab${p?" game-mode-on":""}`,children:[a!=null&&e.jsx("div",{className:"mega-cache-toast show",children:a}),z&&e.jsxs("div",{className:"mega-cache-banner",children:["🥧"," MEGA CACHE! peak ",B(j)," — first reached ",O(T)]}),z&&e.jsxs("div",{className:"achievement-tile unlocked",children:["🏆"," Opie's Wild Ride",e.jsxs("span",{className:"ach-detail",children:["best ",B(j)," · first ",O(T)]})]}),e.jsx("h2",{children:"High Scores"}),!M&&!d&&e.jsx("div",{className:"game-empty",children:"No scores yet — run a session with game mode on."}),M&&e.jsxs("div",{className:"game-leaderboards",children:[e.jsx(I,{title:"Cache %",rows:t.cache??[],renderValue:m=>B(m.value)}),e.jsx(I,{title:"Dedupe (collapsed)",rows:t.dedupe??[],renderValue:m=>m.value.toLocaleString()}),e.jsx(I,{title:"Turns",rows:S,badge:S.length>0?e.jsxs("span",{className:"lvl-badge",children:["LVL ",D]}):void 0,renderValue:m=>m.value.toLocaleString()}),e.jsx(I,{title:"MEGA CACHE trophies",rows:E,renderValue:m=>e.jsxs(e.Fragment,{children:[B(m.value),e.jsx("span",{className:"lb-meta",children:O(U(m.meta).firstSeenTs??U(m.meta).firstSeen??m.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(F,{achievements:o})]})}function ae(){const[t,h]=s.useState([]),[n,f]=s.useState(!0),[o,u]=s.useState(null),p=s.useCallback(async()=>{try{const l=await P();h(l),u(null)}catch(l){u(l instanceof Error?l:new Error(String(l)))}finally{f(!1)}},[]);return s.useEffect(()=>{let l=!0;const d=async()=>{l&&await p()};d();const x=setInterval(()=>void d(),15e3);return()=>{l=!1,clearInterval(x)}},[p]),n&&t.length===0?e.jsx("div",{className:"tab-stub",children:"Loading achievements…"}):o&&t.length===0?e.jsxs("div",{className:"tab-stub",children:["Error: ",o.message]}):e.jsxs("div",{className:"achievements-tab",children:[e.jsx("h2",{children:"Achievements"}),e.jsx(F,{achievements:t})]})}const H=[{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"}}],W=H.map(t=>t.id),k={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 re(t,h,n){let f=t.toLocaleString();return h!=null&&n>0&&(f+=` (${Math.round(h*100)}% of ${n.toLocaleString()})`),f}function le(t){return`${Math.round((t||0)*100)}%`}function ie(){const[t,h]=s.useState(null),[n,f]=s.useState(null),[o,u]=s.useState(!1);s.useEffect(()=>{let i=!0;const g=async()=>{try{const j=await X();i&&h(j)}catch{}};g();const E=setInterval(()=>void g(),5e3);return()=>{i=!1,clearInterval(E)}},[]),s.useEffect(()=>{let i=!0;const g=async()=>{try{const j=await $();i&&(f(j),j.theme&&(document.documentElement.dataset.theme=j.theme))}catch{}};g();const E=setInterval(()=>void g(),5e3);return()=>{i=!1,clearInterval(E)}},[]);const p=s.useCallback(async i=>{u(!0);try{const g=await q(i);f(g),g.theme&&(document.documentElement.dataset.theme=g.theme)}catch{}u(!1)},[]),l=n?.game_mode_on??!1,d=n?.theme??"transparent",x=n?.tui_display_mode??"full",a=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:k.gameMode,children:[e.jsx("input",{type:"checkbox",checked:l,onChange:i=>p({game_mode_on:i.currentTarget.checked}),disabled:o}),"Game Mode"]})}),e.jsx("div",{className:"settings-row",children:e.jsxs("label",{title:k.theme,children:["Theme",e.jsx("select",{value:d,onChange:i=>p({theme:i.currentTarget.value}),disabled:o,children:H.map(i=>e.jsx("option",{value:i.id,children:i.label},i.id))}),e.jsx("button",{type:"button",disabled:o,className:"theme-cycle-btn",title:"Cycle to the next theme (P3)",onClick:()=>{const i=W.indexOf(d),g=W[(i<0?0:i+1)%W.length];g&&p({theme:g})},children:"Next theme →"})]})}),e.jsx("div",{className:"settings-row",children:e.jsxs("label",{title:k.tuiMode,children:["TUI Mode",e.jsxs("select",{value:x,onChange:i=>p({tui_display_mode:i.currentTarget.value}),disabled:o,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:k.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:k.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:k.pressure,children:"Pressure"}),e.jsx("span",{className:"config-value",children:t?le(t.pressure):"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",title:k.threshold,children:"Threshold"}),e.jsx("span",{className:"config-value",children:a?re(a.thresholdTokens,a.tierPct,b):"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",title:k.fastGate,children:"Fast Gate"}),e.jsx("span",{className:"config-value",children:a?`${a.fastGatePct}%`:"—"})]}),e.jsxs("div",{className:"config-item",children:[e.jsx("span",{className:"config-label",children:"Auto"}),e.jsx("span",{className:"config-value",children:a?a.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:a?.anchorUserMessages??"—"})]})]})]})]})}const C={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 oe(){const[t,h]=s.useState(null),[n,f]=s.useState(null),o=s.useCallback(()=>{Y().then(h).catch(x=>f(x instanceof Error?x.message:String(x)))},[]);s.useEffect(()=>{o()},[o]),s.useEffect(()=>{const x=setInterval(o,3e4);return()=>clearInterval(x)},[o]);const u=t?.status==="ok",p=t?.status==="ok"?"Working":t?.status==="unreachable"?"Unreachable":"Error",l=u?"#4caf50":"#f44336",d=u?"✓":"✗";return e.jsxs("div",{style:C.section,children:[e.jsx("h3",{style:C.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:C.row,children:[e.jsxs("span",{style:{...C.label,color:`${l}`},children:[d," ",p,":"]}),e.jsxs("span",{style:C.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:C.row,children:[e.jsx("span",{style:C.label,children:"Endpoint:"}),e.jsx("span",{style:C.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})]})]})}const N={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"},flagRow:{display:"flex",alignItems:"flex-start",gap:"0.5rem",padding:"0.5rem 0",borderBottom:"1px solid #2a2a4e"},checkbox:{marginTop:"0.15rem",cursor:"pointer"},label:{fontWeight:600,color:"#e0e0e0",fontSize:"0.9rem"},description:{fontSize:"0.8rem",color:"#a0a0c0",marginTop:"0.15rem"},hint:{fontSize:"0.75rem",color:"#ff9800",marginTop:"0.15rem"},banner:{background:"#3a2a00",border:"1px solid #665500",borderRadius:"6px",padding:"0.5rem 0.75rem",marginTop:"0.5rem",color:"#ffcc00",fontSize:"0.8rem"}};function ce(){const[t,h]=s.useState(null),[n,f]=s.useState(null),[o,u]=s.useState(!1),[p,l]=s.useState(!1),d=s.useCallback(()=>{J().then(h).catch(a=>f(a instanceof Error?a.message:String(a)))},[]);s.useEffect(()=>{d()},[d]),s.useEffect(()=>{const a=setInterval(d,3e4);return()=>clearInterval(a)},[d]);const x=s.useCallback((a,b)=>{if(!t)return;const i=t.flags.find(g=>g.key===a);!i||i.requiresLlm&&!t.llmActive||(u(!0),K({flags:{[a]:b}}).then(()=>{l(!0),u(!1),d()}).catch(g=>{f(g instanceof Error?g.message:String(g)),u(!1)}))},[t,d]);return e.jsxs("div",{style:N.section,children:[e.jsx("h3",{style:N.sectionTitle,children:"RAG Settings"}),e.jsx("p",{style:{fontSize:"0.8rem",color:"#a0a0c0",marginTop:0},children:"Recall pipeline features. All default ON — toggle off to disable. Changes take effect after restart."}),n&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error: ",n]}),t?.flags.map(a=>{const b=a.requiresLlm&&!t.llmActive;return e.jsxs("div",{style:N.flagRow,children:[e.jsx("input",{type:"checkbox",style:{...N.checkbox,opacity:b?.4:1,cursor:b?"not-allowed":"pointer"},checked:a.enabled&&!b,disabled:b||o,onChange:i=>x(a.key,i.currentTarget.checked)}),e.jsxs("div",{children:[e.jsx("div",{style:N.label,children:a.label}),e.jsx("div",{style:N.description,children:a.description}),b&&e.jsx("div",{style:N.hint,children:"Requires an LLM embedder (Ollama/HTTP). Configure one in the Embedder section above first."})]})]},a.key)}),!t&&!n&&e.jsx("p",{style:{color:"#888",fontSize:"0.85rem"},children:"Loading..."}),p&&e.jsxs("div",{style:N.banner,children:["Settings saved. ",e.jsx("strong",{children:"Restart pi"})," to apply changes."]})]})}const r={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 de(){const[t,h]=s.useState(null),[n,f]=s.useState(null),[o,u]=s.useState(null),[p,l]=s.useState(null),[d,x]=s.useState(!1),[a,b]=s.useState(null),[i,g]=s.useState(null),[E,j]=s.useState(null),[T,z]=s.useState(""),S=s.useCallback(()=>{Q().then(h).catch(c=>u(c instanceof Error?c.message:String(c)))},[]),R=s.useCallback((c,v)=>{b(c),j(null),g(null),Z({embedder:c,url:v}).then(w=>{g(w),b(null),S()}).catch(w=>{j(w instanceof Error?w.message:String(w)),b(null)})},[S]),D=s.useCallback(()=>{x(!0),l(null),ee().then(c=>{f(c),x(!1)}).catch(c=>{l(c instanceof Error?c.message:String(c)),x(!1)})},[]);s.useEffect(()=>{S()},[S]),s.useEffect(()=>{const c=setInterval(S,3e4);return()=>clearInterval(c)},[S]);const M=c=>{switch(c){case"trigram":return"TrigramEmbedder (heuristic, default)";case"http":return"HTTP Embedder (BYO localhost)";case"minilm":return"MiniLM (experimental)";default:return"Unknown"}},m=t?.currentEmbedder==="trigram"&&e.jsxs("div",{style:r.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."]}),y=c=>{const v=c?"#1a5a1a":"#3a1a1a",w=c?"#4caf50":"#f44336";return e.jsx("span",{style:{...r.badge,background:v,color:w},children:c?"Detected":"Not found"})};return e.jsxs("div",{style:r.container,children:[e.jsx("h2",{style:{fontSize:"1.3rem",marginTop:0,marginBottom:"1rem"},children:"Embedder Setup"}),e.jsx(oe,{}),e.jsxs("div",{style:r.section,children:[e.jsx("h3",{style:r.sectionTitle,children:"Current Embedder Configuration"}),o&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error: ",o]}),t&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:r.row,children:[e.jsx("span",{style:r.label,children:"Active Embedder:"}),e.jsx("span",{style:r.value,children:M(t.currentEmbedder)})]}),"configuredEmbedder"in t&&t.configuredEmbedder!==t.currentEmbedder&&e.jsxs("div",{style:r.warning,children:[e.jsx("strong",{children:"Configured but not active:"})," ",M(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:{...r.row,color:"#ff9800"},children:[e.jsx("span",{style:r.label,children:"Status:"}),e.jsx("span",{style:r.value,children:"Restart required to activate the configured embedder"})]}),e.jsxs("div",{style:r.row,children:[e.jsx("span",{style:r.label,children:"Embedding URL:"}),e.jsx("span",{style:r.value,children:t.embeddingUrl??e.jsx("span",{style:{color:"#888"},children:"not set"})})]}),e.jsxs("div",{style:r.row,children:[e.jsx("span",{style:r.label,children:"Embed Cache:"}),e.jsx("span",{style:r.value,children:t.embedCache??e.jsx("span",{style:{color:"#888"},children:"not set"})})]}),e.jsxs("div",{style:r.row,children:[e.jsx("span",{style:r.label,children:"MiniLM:"}),e.jsx("span",{style:r.value,children:t.minilm?"enabled":"disabled"})]}),m]}),!t&&!o&&e.jsx("p",{style:{color:"#888",fontSize:"0.85rem"},children:"Loading configuration..."})]}),e.jsxs("div",{style:r.section,children:[e.jsx("h3",{style:r.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:r.detectRow,children:[e.jsx("span",{children:e.jsx("strong",{children:"Ollama"})}),n.ollama!==null?e.jsxs("span",{children:[y(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:r.detectRow,children:[e.jsx("span",{children:e.jsx("strong",{children:"llama.cpp"})}),n.llamaCpp!==null?e.jsxs("span",{children:[y(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:r.detectRow,children:[e.jsx("span",{children:e.jsx("strong",{children:"ONNX Runtime"})}),n.onnx!==null?e.jsxs("span",{children:[y(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]})]}),p&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem"},children:["Error: ",p]}),e.jsxs("div",{style:{marginTop:"1rem"},children:[e.jsx("button",{style:r.button,onClick:D,disabled:d,children:d?"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:{...r.button,opacity:n.ollama?.installed?1:.4},onClick:()=>R("ollama"),disabled:!n.ollama?.installed||a!==null,children:a==="ollama"?"Writing...":"Use Ollama"}),e.jsx("button",{style:{...r.button,opacity:n.llamaCpp?.installed?1:.4},onClick:()=>R("llama"),disabled:!n.llamaCpp?.installed||a!==null,children:a==="llama"?"Writing...":"Use llama.cpp"}),e.jsx("button",{style:{...r.button,background:"#444"},onClick:()=>R("trigram"),disabled:a!==null,children:a==="trigram"?"Writing...":"Use Trigram (default)"})]}),i&&e.jsx("div",{style:r.warning,children:i.alreadyActive?"Already active — no restart needed.":`Configured ${i.embedder}. Restart pi to activate (config written to ${i.envPath}).`}),E&&e.jsxs("p",{style:{color:"#f44336",fontSize:"0.85rem",marginTop:"0.5rem"},children:["Configure error: ",E]})]})]}),e.jsxs("div",{style:r.section,children:[e.jsx("h3",{style:r.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:c=>z(c.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"}}),e.jsx("button",{style:{...r.button,opacity:T?1:.4},onClick:()=>R("custom",T),disabled:!T||a!==null,children:a==="custom"?"Writing...":"Use Custom URL"})]}),e.jsxs("div",{style:r.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."]})]}),e.jsxs("div",{style:r.section,children:[e.jsx("h3",{style:r.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."]})]})]}),e.jsx(ce,{})]})}const me={padding:"1rem",maxWidth:"720px",margin:"0 auto",fontFamily:"system-ui, sans-serif",color:"#e0e0e0"},he={display:"flex",gap:"0.5rem",marginBottom:"1rem",borderBottom:"1px solid #2a2a4e",paddingBottom:"0.5rem"};function _(t){return{background:t?"#3a5a9f":"transparent",color:t?"#fff":"#a0a0c0",border:"1px solid",borderColor:t?"#3a5a9f":"#2a2a4e",borderRadius:"6px",padding:"0.4rem 0.8rem",cursor:"pointer",fontSize:"0.9rem",fontWeight:t?600:400}}function ge(){const[t,h]=s.useState("embedder");return e.jsxs("div",{style:me,children:[e.jsxs("nav",{style:he,"aria-label":"Setup sections",children:[e.jsx("button",{type:"button",style:_(t==="embedder"),onClick:()=>h("embedder"),children:"Embedder"}),e.jsx("button",{type:"button",style:_(t==="config"),onClick:()=>h("config"),children:"Config"}),e.jsx("button",{type:"button",style:_(t==="game"),onClick:()=>h("game"),children:"Game Mode"}),e.jsx("button",{type:"button",style:_(t==="achievements"),onClick:()=>h("achievements"),children:"Achievements"})]}),t==="embedder"&&e.jsx(de,{}),t==="config"&&e.jsx(ie,{}),t==="game"&&e.jsx(ne,{}),t==="achievements"&&e.jsx(ae,{})]})}export{ge as default};
2
+ //# sourceMappingURL=SetupTab-BJUHOVK2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SetupTab-BJUHOVK2.js","sources":["../../src/components/AchievementTiles.tsx","../../src/tabs/GameTab.tsx","../../src/tabs/AchievementsTab.tsx","../../../../src/config/themes.ts","../../src/tabs/ConfigTab.tsx","../../src/tabs/SetupTab/EmbedderHealthCard.tsx","../../src/tabs/SetupTab/RagSettingsCard.tsx","../../src/tabs/SetupTab/EmbedderSetup.tsx","../../src/tabs/SetupTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/components/AchievementTiles.tsx — shared achievement grid.\n *\n * Renders a grid of achievement tiles from fetchAchievements() data.\n * Tile states: unlocked (icon+title+date), visible-locked (??? teaser),\n * hidden+locked (not rendered). Just-unlocked tiles get a pulse animation.\n * Toast notification fires for newly-unlocked achievements.\n *\n * Used by both GameTab (sub-section) and AchievementsTab (standalone).\n */\n\nimport type React from \"react\";\nimport { useRef, useState, useEffect } from \"react\";\nimport type { AchievementRow } from \"@contracts\";\n\nexport interface AchievementTilesProps {\n\t/** Achievement rows from /api/achievements. */\n\tachievements: AchievementRow[];\n}\n\n/** Format unlock timestamp (seconds → locale string). */\nfunction fmtUnlockDate(ts: number): string {\n\ttry {\n\t\treturn new Date(ts * 1000).toLocaleString();\n\t} catch {\n\t\treturn \"\\u2014\";\n\t}\n}\n\nexport function AchievementTiles({\n\tachievements,\n}: AchievementTilesProps): React.ReactElement {\n\tconst lastMaxTsRef = useRef(0);\n\tconst [toastText, setToastText] = useState<string | null>(null);\n\n\tconst maxTs = achievements.reduce(\n\t\t(mx, a) => Math.max(mx, a.unlocked_at ?? 0),\n\t\t0,\n\t);\n\tconst prevMaxTs = lastMaxTsRef.current;\n\n\t/* Update ref after render so next poll sees previous baseline. */\n\tuseEffect(() => {\n\t\tif (maxTs > lastMaxTsRef.current) {\n\t\t\tlastMaxTsRef.current = maxTs;\n\t\t}\n\t}, [maxTs]);\n\n\t/* Toast for newly-unlocked achievements. */\n\tuseEffect(() => {\n\t\tif (prevMaxTs > 0 && maxTs > prevMaxTs) {\n\t\t\tconst newly = achievements.filter(\n\t\t\t\t(a) => a.unlocked_at != null && (a.unlocked_at ?? 0) > prevMaxTs,\n\t\t\t);\n\t\t\tif (newly.length > 0) {\n\t\t\t\tconst text =\n\t\t\t\t\tnewly\n\t\t\t\t\t\t.map((a) => `${a.icon ?? \"\"} ${a.title}`.trim())\n\t\t\t\t\t\t.join(\", \") + \" unlocked!\";\n\t\t\t\tsetToastText(text);\n\t\t\t\tconst t = setTimeout(() => setToastText(null), 4000);\n\t\t\t\treturn (): void => clearTimeout(t);\n\t\t\t}\n\t\t}\n\t}, [achievements, maxTs, prevMaxTs]);\n\n\t/* Visible tiles: skip hidden+locked (hidden === 1 && unlocked_at == null). */\n\tconst tiles = achievements.filter(\n\t\t(a) => !(a.hidden === 1 && a.unlocked_at == null),\n\t);\n\n\treturn (\n\t\t<div className=\"ach-section\">\n\t\t\t{toastText != null && (\n\t\t\t\t<div className=\"ach-toast show\">{toastText}</div>\n\t\t\t)}\n\t\t\t<div className=\"ach-tiles\">\n\t\t\t\t{tiles.length === 0 && (\n\t\t\t\t\t<span className=\"repo-none\">no achievements yet</span>\n\t\t\t\t)}\n\t\t\t\t{tiles.map((a) => {\n\t\t\t\t\tif (a.unlocked_at != null) {\n\t\t\t\t\t\tconst isNew = prevMaxTs > 0 && (a.unlocked_at ?? 0) > prevMaxTs;\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tkey={a.id}\n\t\t\t\t\t\t\t\tclassName={`ach-tile unlocked${isNew ? \" just-unlocked\" : \"\"}`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{a.icon ?? \"\"} {a.title}\n\t\t\t\t\t\t\t\t<span className=\"ach-detail\">\n\t\t\t\t\t\t\t\t\tunlocked {fmtUnlockDate(a.unlocked_at)}\n\t\t\t\t\t\t\t\t</span>\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\treturn (\n\t\t\t\t\t\t<div key={a.id} className=\"ach-tile locked\">\n\t\t\t\t\t\t\t??? {a.title}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/GameTab.tsx — Game tab (NEW).\n *\n * Renders:\n * (1) MEGA CACHE banner (animated gradient, shown when any mega_cache > 100)\n * (2) Opie unlock tile (shown when mega_cache > 100)\n * (3) High Scores header\n * (4) 4 leaderboards in 2×2 grid: Cache %, Dedupe, Turns (LVL badge),\n * MEGA CACHE trophies (firstSeen date meta)\n * (5) Repos count badge via fetchGameScores({metric:'repos',limit:1})\n * (6) Achievements sub-section (AchievementTiles shared component)\n * (7) Game empty state\n * Polls scores + achievements every 15s, game-state every 15s.\n * Applies data-theme accent vars when game_mode_on.\n */\n\nimport type React from \"react\";\nimport { useState, useEffect, useCallback, useRef } from \"react\";\nimport type { GameScoreRow, AchievementRow } from \"@contracts\";\nimport { fetchGameScores, fetchAchievements, fetchGameState } from \"../api/client\";\nimport { AchievementTiles } from \"../components/AchievementTiles\";\n\n/** Actual flat game state shape from the server (NOT the nested contract). */\ninterface FlatGameState {\n\tgame_mode_on: boolean;\n\ttheme: string;\n\ttui_display_mode: \"full\" | \"minimal\";\n}\n\n/** Metadata object inside a mega_cache GameScoreRow. */\ninterface TrophyMeta {\n\tfirstSeenTs?: number;\n\tfirstSeen?: number;\n}\n\n/* ── Format helpers (matching html.ts logic) ─────────────────────────── */\n\nfunction fmtPct(v: number): string {\n\treturn (Math.round(v * 10) / 10).toString() + \"%\";\n}\n\nfunction fmtDate(ts: number | null | undefined): string {\n\treturn ts != null ? new Date(ts).toLocaleString() : \"\\u2014\";\n}\n\nfunction trophyMeta(m: unknown): TrophyMeta {\n\treturn m && typeof m === \"object\" ? (m as TrophyMeta) : {};\n}\n\nfunction repoBasename(path: string): string {\n\treturn path.split(\"/\").pop() || path;\n}\n\n/* ── Leaderboard card ────────────────────────────────────────────────── */\n\ninterface LeaderboardCardProps {\n\ttitle: string;\n\trows: GameScoreRow[];\n\tbadge?: React.ReactNode;\n\trenderValue: (r: GameScoreRow) => React.ReactNode;\n}\n\nfunction LeaderboardCard({\n\ttitle,\n\trows,\n\tbadge,\n\trenderValue,\n}: LeaderboardCardProps): React.ReactElement {\n\treturn (\n\t\t<div className=\"lb-card\">\n\t\t\t<h3>\n\t\t\t\t{title}\n\t\t\t\t{badge}\n\t\t\t</h3>\n\t\t\t{rows.length === 0 ? (\n\t\t\t\t<div className=\"lb-empty\">—</div>\n\t\t\t) : (\n\t\t\t\t<table>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t{rows.map((r, i) => (\n\t\t\t\t\t\t\t<tr key={`${r.repo_root}-${i}`}>\n\t\t\t\t\t\t\t\t<td title={r.repo_root}>{repoBasename(r.repo_root)}</td>\n\t\t\t\t\t\t\t\t<td className=\"num\">{renderValue(r)}</td>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</tbody>\n\t\t\t\t</table>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\n/* ── Main GameTab component ──────────────────────────────────────────── */\n\nexport default function GameTab(): React.ReactElement {\n\tconst [scores, setScores] = useState<\n\t\tRecord<string, GameScoreRow[]>\n\t>({});\n\tconst [reposCount, setReposCount] = useState(0);\n\tconst [achievements, setAchievements] = useState<AchievementRow[]>([]);\n\tconst [gameModeOn, setGameModeOn] = useState(false);\n\tconst [loading, setLoading] = useState(true);\n\tconst [megaToast, setMegaToast] = useState<string | null>(null);\n\tconst lastMegaTsRef = useRef(0);\n\n\tconst fetchAll = useCallback(async (): Promise<void> => {\n\t\ttry {\n\t\t\tconst [cache, dedupe, turns, megaCache, repos, ach] =\n\t\t\t\tawait Promise.all([\n\t\t\t\t\tfetchGameScores({ metric: \"cache\", limit: 25 }),\n\t\t\t\t\tfetchGameScores({ metric: \"dedupe\", limit: 25 }),\n\t\t\t\t\tfetchGameScores({ metric: \"turns\", limit: 25 }),\n\t\t\t\t\tfetchGameScores({ metric: \"mega_cache\", limit: 25 }),\n\t\t\t\t\tfetchGameScores({ metric: \"repos\", limit: 1 }),\n\t\t\t\t\tfetchAchievements(),\n\t\t\t\t]);\n\n\t\t\t/* Mega-cache toast: new row with value > 100 since last poll */\n\t\t\tconst newRow = megaCache.find(\n\t\t\t\t(r) => r.ts > lastMegaTsRef.current && r.value > 100,\n\t\t\t);\n\t\t\tif (lastMegaTsRef.current > 0 && newRow) {\n\t\t\t\tsetMegaToast(\n\t\t\t\t\t`oopsie! cache went to ${Math.round(newRow.value)}% — MEGA CACHE \\uD83E\\uDD67`,\n\t\t\t\t);\n\t\t\t\tsetTimeout(() => setMegaToast(null), 4000);\n\t\t\t}\n\t\t\tif (megaCache.length > 0) {\n\t\t\t\tlastMegaTsRef.current = Math.max(\n\t\t\t\t\t...megaCache.map((r) => r.ts),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tsetScores({ cache, dedupe, turns, mega_cache: megaCache });\n\t\t\tsetReposCount(repos[0]?.value ?? 0);\n\t\t\tsetAchievements(ach);\n\t\t} catch {\n\t\t\t/* non-fatal */\n\t\t} finally {\n\t\t\tsetLoading(false);\n\t\t}\n\t}, []);\n\n\t/* Poll scores + achievements every 15s. */\n\tuseEffect(() => {\n\t\tlet active = true;\n\t\tconst doFetch = async (): Promise<void> => {\n\t\t\tif (active) await fetchAll();\n\t\t};\n\t\tvoid doFetch();\n\t\tconst timer = setInterval(() => void doFetch(), 15000);\n\t\treturn () => {\n\t\t\tactive = false;\n\t\t\tclearInterval(timer);\n\t\t};\n\t}, [fetchAll]);\n\n\t/* Poll game state every 15s for styling. */\n\tuseEffect(() => {\n\t\tlet active = true;\n\t\tconst doFetch = async (): Promise<void> => {\n\t\t\ttry {\n\t\t\t\tconst gs = (await fetchGameState()) as unknown as FlatGameState;\n\t\t\t\tif (active) {\n\t\t\t\t\tsetGameModeOn(!!gs.game_mode_on);\n\t\t\t\t\tif (gs.theme)\n\t\t\t\t\t\tdocument.documentElement.dataset.theme = gs.theme;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t/* non-fatal */\n\t\t\t}\n\t\t};\n\t\tvoid doFetch();\n\t\tconst timer = setInterval(() => void doFetch(), 15000);\n\t\treturn () => {\n\t\t\tactive = false;\n\t\t\tclearInterval(timer);\n\t\t};\n\t}, []);\n\n\t/* Compute mega-cache banner data */\n\tconst megaRows = scores.mega_cache ?? [];\n\tlet bestMega: number | null = null;\n\tlet firstSeen: number | null = null;\n\tfor (const r of megaRows) {\n\t\tif (bestMega == null || r.value > bestMega) bestMega = r.value;\n\t\tconst m = trophyMeta(r.meta);\n\t\tconst fs = m.firstSeenTs ?? m.firstSeen ?? r.ts;\n\t\tif (firstSeen == null || fs < firstSeen) firstSeen = fs;\n\t}\n\tconst showMega = bestMega != null && bestMega > 100;\n\n\t/* Turns level badge */\n\tconst turnsRows = scores.turns ?? [];\n\tconst maxTurns = turnsRows.reduce((mx, r) => Math.max(mx, r.value), 0);\n\tconst lvl = Math.floor(Math.log2(maxTurns + 1)) + 1;\n\n\t/* Game empty state */\n\tconst hasData =\n\t\t(scores.cache?.length ?? 0) > 0 ||\n\t\t(scores.dedupe?.length ?? 0) > 0 ||\n\t\tturnsRows.length > 0 ||\n\t\tmegaRows.length > 0 ||\n\t\treposCount > 0;\n\n\treturn (\n\t\t<div className={`game-tab${gameModeOn ? \" game-mode-on\" : \"\"}`}>\n\t\t\t{megaToast != null && (\n\t\t\t\t<div className=\"mega-cache-toast show\">{megaToast}</div>\n\t\t\t)}\n\n\t\t\t{showMega && (\n\t\t\t\t<div className=\"mega-cache-banner\">\n\t\t\t\t\t{\"\\uD83E\\uDD67\"} MEGA CACHE! peak {fmtPct(bestMega!)} — first\n\t\t\t\t\treached {fmtDate(firstSeen)}\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{showMega && (\n\t\t\t\t<div className=\"achievement-tile unlocked\">\n\t\t\t\t\t{\"\\uD83C\\uDFC6\"} Opie's Wild Ride\n\t\t\t\t\t<span className=\"ach-detail\">\n\t\t\t\t\t\tbest {fmtPct(bestMega!)} · first {fmtDate(firstSeen)}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t<h2>High Scores</h2>\n\n\t\t\t{!hasData && !loading && (\n\t\t\t\t<div className=\"game-empty\">\n\t\t\t\t\tNo scores yet — run a session with game mode on.\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{hasData && (\n\t\t\t\t<div className=\"game-leaderboards\">\n\t\t\t\t\t<LeaderboardCard\n\t\t\t\t\t\ttitle=\"Cache %\"\n\t\t\t\t\t\trows={scores.cache ?? []}\n\t\t\t\t\t\trenderValue={(r) => fmtPct(r.value)}\n\t\t\t\t\t/>\n\t\t\t\t\t<LeaderboardCard\n\t\t\t\t\t\ttitle=\"Dedupe (collapsed)\"\n\t\t\t\t\t\trows={scores.dedupe ?? []}\n\t\t\t\t\t\trenderValue={(r) => r.value.toLocaleString()}\n\t\t\t\t\t/>\n\t\t\t\t\t<LeaderboardCard\n\t\t\t\t\t\ttitle=\"Turns\"\n\t\t\t\t\t\trows={turnsRows}\n\t\t\t\t\t\tbadge={\n\t\t\t\t\t\t\tturnsRows.length > 0 ? (\n\t\t\t\t\t\t\t\t<span className=\"lvl-badge\">LVL {lvl}</span>\n\t\t\t\t\t\t\t) : undefined\n\t\t\t\t\t\t}\n\t\t\t\t\t\trenderValue={(r) => r.value.toLocaleString()}\n\t\t\t\t\t/>\n\t\t\t\t\t<LeaderboardCard\n\t\t\t\t\t\ttitle=\"MEGA CACHE trophies\"\n\t\t\t\t\t\trows={megaRows}\n\t\t\t\t\t\trenderValue={(r) => (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t{fmtPct(r.value)}\n\t\t\t\t\t\t\t\t<span className=\"lb-meta\">\n\t\t\t\t\t\t\t\t\t{fmtDate(\n\t\t\t\t\t\t\t\t\t\ttrophyMeta(r.meta).firstSeenTs ??\n\t\t\t\t\t\t\t\t\t\t\ttrophyMeta(r.meta).firstSeen ??\n\t\t\t\t\t\t\t\t\t\t\tr.ts,\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)}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{reposCount > 0 && (\n\t\t\t\t<div className=\"repos-badge-line\">\n\t\t\t\t\t<span className=\"repos-badge\">{reposCount} repos</span>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t<h3>Achievements</h3>\n\t\t\t<AchievementTiles achievements={achievements} />\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/AchievementsTab.tsx — Achievements tab (NEW).\n *\n * Renders the shared AchievementTiles component standalone, plus a toast area.\n * Polls /api/achievements every 15s.\n */\n\nimport type React from \"react\";\nimport { useState, useEffect, useCallback } from \"react\";\nimport type { AchievementRow } from \"@contracts\";\nimport { fetchAchievements } from \"../api/client\";\nimport { AchievementTiles } from \"../components/AchievementTiles\";\n\nexport default function AchievementsTab(): React.ReactElement {\n\tconst [achievements, setAchievements] = useState<AchievementRow[]>([]);\n\tconst [loading, setLoading] = useState(true);\n\tconst [error, setError] = useState<Error | null>(null);\n\n\tconst doFetch = useCallback(async (): Promise<void> => {\n\t\ttry {\n\t\t\tconst rows = await fetchAchievements();\n\t\t\tsetAchievements(rows);\n\t\t\tsetError(null);\n\t\t} catch (e) {\n\t\t\tsetError(e instanceof Error ? e : new Error(String(e)));\n\t\t} finally {\n\t\t\tsetLoading(false);\n\t\t}\n\t}, []);\n\n\tuseEffect(() => {\n\t\tlet active = true;\n\t\tconst run = async (): Promise<void> => {\n\t\t\tif (active) await doFetch();\n\t\t};\n\t\tvoid run();\n\t\tconst timer = setInterval(() => void run(), 15000);\n\t\treturn () => {\n\t\t\tactive = false;\n\t\t\tclearInterval(timer);\n\t\t};\n\t}, [doFetch]);\n\n\tif (loading && achievements.length === 0)\n\t\treturn <div className=\"tab-stub\">Loading achievements…</div>;\n\tif (error && achievements.length === 0)\n\t\treturn <div className=\"tab-stub\">Error: {error.message}</div>;\n\n\treturn (\n\t\t<div className=\"achievements-tab\">\n\t\t\t<h2>Achievements</h2>\n\t\t\t<AchievementTiles achievements={achievements} />\n\t\t</div>\n\t);\n}\n","/**\n * themes.ts — SINGLE SOURCE OF TRUTH for game-mode visual-effect themes (S30).\n *\n * Each theme defines BOTH an HTML/CSS palette (dashboard) AND an ANSI accent\n * mapping (TUI widget), since the TUI is ANSI and the dashboard is HTML.\n *\n * Theme scope (QA1 correction): themes restyle the mega-compact statusbar\n * widget + the whole dashboard HTML page. We do NOT theme pi's chrome.\n *\n * `transparent` (default) semantics: no background fill, colored accents only —\n * so game-mode stays visible against any terminal background.\n *\n * PREVENT-PI-004: pure config, no network. Pi-agnostic: no pi runtime types.\n */\n\n/** HTML/CSS palette for the dashboard (hex strings, or `null` for \"no bg\"). */\nexport interface ThemeCss {\n /** Page/cell background hex, or `null` for transparent (no bg fill). */\n bg: string | null;\n /** Default foreground (text) hex. */\n fg: string;\n /** Accent hex (bars, highlights, level numbers). */\n accent: string;\n /** MEGA CACHE highlight hex (fires at cache >= 100%). */\n mega: string;\n}\n\n/** ANSI accent mapping for the TUI widget (SGR parameter strings, no `\\x1b[`).\n * `bg` is `null` for transparent themes (no background fill). */\nexport interface ThemeAnsi {\n /** Background SGR params (e.g. \"48;5;23\"), or `null` for no bg fill. */\n bg: string | null;\n /** Foreground SGR params (e.g. \"39\" for default, \"92\" for bright green). */\n fg: string;\n /** Accent SGR params. */\n accent: string;\n /** MEGA CACHE SGR params (fires at cache >= 100%). */\n mega: string;\n}\n\n/** A complete theme = CSS palette + ANSI mapping + display metadata. */\nexport interface Theme {\n id: string;\n label: string;\n css: ThemeCss;\n ansi: ThemeAnsi;\n}\n\nexport const DEFAULT_THEME = \"transparent\";\n\nexport const THEMES: readonly Theme[] = [\n {\n id: \"transparent\",\n label: \"Transparent (accents only)\",\n css: { bg: null, fg: \"#c9d1d9\", accent: \"#3fb950\", mega: \"#f0883e\" },\n ansi: { bg: null, fg: \"39\", accent: \"32\", mega: \"33\" },\n },\n {\n id: \"retro\",\n label: \"Retro 8-bit green\",\n css: { bg: \"#003300\", fg: \"#33ff33\", accent: \"#00ff41\", mega: \"#39ff14\" },\n ansi: { bg: \"40\", fg: \"92\", accent: \"92\", mega: \"1;92\" },\n },\n {\n id: \"orange-bold\",\n label: \"Orange bold\",\n css: { bg: \"#1a0f00\", fg: \"#ff8c00\", accent: \"#ff6b00\", mega: \"#ff4500\" },\n ansi: { bg: \"48;5;52\", fg: \"38;5;208\", accent: \"38;5;208\", mega: \"1;38;5;202\" },\n },\n {\n id: \"cyan-neon\",\n label: \"Cyan neon\",\n css: { bg: \"#001a1a\", fg: \"#00ffff\", accent: \"#22d3ee\", mega: \"#7df9ff\" },\n ansi: { bg: \"48;5;23\", fg: \"38;5;51\", accent: \"38;5;51\", mega: \"1;38;5;51\" },\n },\n {\n id: \"amber-mono\",\n label: \"Amber phosphor\",\n css: { bg: \"#1a1200\", fg: \"#ffb000\", accent: \"#ff8c00\", mega: \"#ff5500\" },\n ansi: { bg: \"48;5;58\", fg: \"38;5;214\", accent: \"38;5;214\", mega: \"1;38;5;208\" },\n },\n {\n id: \"grayscale\",\n label: \"Grayscale minimal\",\n css: { bg: \"#161616\", fg: \"#b0b0b0\", accent: \"#8b949e\", mega: \"#e6edf3\" },\n ansi: { bg: \"48;5;235\", fg: \"38;5;249\", accent: \"38;5;249\", mega: \"1;38;5;255\" },\n },\n] as const;\n\n/** All valid theme ids, in definition order (used for `theme next` cycling). */\nexport const THEME_IDS: readonly string[] = THEMES.map((t) => t.id);\n\n/** Look up a theme by id; returns `undefined` for an unknown id (caller\n * validates + falls back to DEFAULT_THEME). */\nexport function getTheme(id: string): Theme | undefined {\n return THEMES.find((t) => t.id === id);\n}\n\n/** True if `id` is a known theme id. */\nexport function isValidTheme(id: string): boolean {\n return THEME_IDS.includes(id);\n}\n\n/** Cycle to the next theme id (wraps at the end). Falls back to DEFAULT_THEME\n * if `current` is unknown (defensive — the stored id should always be valid). */\nexport function nextTheme(current: string): string {\n const i = THEME_IDS.indexOf(current);\n if (i < 0) return DEFAULT_THEME;\n return THEME_IDS[(i + 1) % THEME_IDS.length]!;\n}\n\n/** CSS variable declarations for a theme's CSS palette. `bg` is `null` for the\n * transparent theme → `--bg: transparent` (no page fill, accents only). Pure,\n * no pi types. */\nexport function themeCssVars(theme: Theme): string {\n const bg = theme.css.bg ?? \"transparent\";\n return `--bg: ${bg}; --fg: ${theme.css.fg}; --accent: ${theme.css.accent}; --mega: ${theme.css.mega};`;\n}\n\n/** A `:root[data-theme=\"<id>\"]` override block carrying the theme's CSS vars,\n * for client-side instant theme switching. Pure, no pi types. */\nexport function themeDataBlock(theme: Theme): string {\n return `:root[data-theme=\"${theme.id}\"]{ ${themeCssVars(theme)} }`;\n}\n","/**\n * dashboard-client/src/tabs/ConfigTab.tsx — Config tab (C3).\n *\n * Full configuration editor:\n * (1) Game mode toggle (checkbox)\n * (2) Theme selector (dropdown) from src/config/themes.ts THEMES array\n * (3) TUI mode selector (Full/Minimal dropdown)\n * (4) Read-only config display section from snapshot (Tier, Preset, Pressure,\n * Threshold, Fast Gate, Auto, Anchor) with verbatim tooltips from html.ts.\n *\n * Uses fetchGameState() to load current state, putGameState() to save changes.\n * Polls gameState and snapshot every 5s. Applies theme by setting\n * document.documentElement.dataset.theme.\n */\n\nimport type React from \"react\";\nimport { useState, useEffect, useCallback } from \"react\";\nimport type { SnapshotResponse, GameStatePatch } from \"@contracts\";\nimport { fetchSnapshot, fetchGameState, putGameState } from \"../api/client\";\nimport { THEMES, THEME_IDS } from \"../../../../src/config/themes\";\n\n/** Actual flat game state returned by the server (the server returns a flat\n * { game_mode_on, theme, tui_display_mode } shape, NOT the contract's nested\n * { config: { enabled, theme, displayMode }, activeRitual } shape). */\ninterface FlatGameState {\n\tgame_mode_on: boolean;\n\ttheme: string;\n\ttui_display_mode: \"full\" | \"minimal\";\n}\ntype FlatGameStatePatch = Partial<FlatGameState>;\n\n/** Extended snapshot config — the runtime includes tierPct (not in contract).\n * Implemented as a type intersection rather than `interface extends` because\n * TypeScript (TS2499) forbids `interface extends T[\"k\"]` indexed-access\n * parents; the resulting type is structurally identical. */\ntype ConfigExt = SnapshotResponse[\"config\"] & {\n\ttierPct?: number | null;\n};\n\n/* Tooltips copied verbatim from extensions/dashboard-server/html.ts */\nconst TOOLTIPS = {\n\tgameMode: \"Turn game mode on/off (themes the widget + dashboard)\",\n\ttheme: \"Visual theme (applies instantly)\",\n\ttuiMode: \"TUI widget display density\",\n\ttier: \"Live pressure band — climbs low\\u2192mega as context fills the window.\",\n\tpreset:\n\t\t\"The env-resolved base compaction preset (low/medium/high/ultra/mega) that set the token threshold.\",\n\tpressure:\n\t\t\"Live pressure = currentTokens / threshold \\u2014 % of the model context window (threshold fires at the tier's % of window).\",\n\tthreshold:\n\t\t\"Compaction threshold = tierPct \\u00d7 model context window \\u2014 mega-compact trims BELOW pi's native ~80% auto-compact for any model size.\",\n\tfastGate:\n\t\t\"Fast-gate arming floor \\u2014 the live trim arms once context passes this % of the window.\",\n} as const;\n\nfunction formatThreshold(\n\ttokens: number,\n\ttierPct: number | null | undefined,\n\tcw: number,\n): string {\n\tlet txt = tokens.toLocaleString();\n\tif (tierPct != null && cw > 0) {\n\t\ttxt += ` (${Math.round(tierPct * 100)}% of ${cw.toLocaleString()})`;\n\t}\n\treturn txt;\n}\n\nfunction formatPressure(pressure: number): string {\n\t/* Runtime sends 0\\u20131 fraction despite contract saying 0\\u2013100. */\n\treturn `${Math.round((pressure || 0) * 100)}%`;\n}\n\nexport default function ConfigTab(): React.ReactElement {\n\tconst [snapshot, setSnapshot] = useState<SnapshotResponse | null>(null);\n\tconst [gameState, setGameState] = useState<FlatGameState | null>(null);\n\tconst [saving, setSaving] = useState(false);\n\n\t/* Poll snapshot every 5s for config display section. */\n\tuseEffect(() => {\n\t\tlet active = true;\n\t\tconst doFetch = async (): Promise<void> => {\n\t\t\ttry {\n\t\t\t\tconst s = await fetchSnapshot();\n\t\t\t\tif (active) setSnapshot(s);\n\t\t\t} catch {\n\t\t\t\t/* non-fatal */\n\t\t\t}\n\t\t};\n\t\tvoid doFetch();\n\t\tconst timer = setInterval(() => void doFetch(), 5000);\n\t\treturn () => {\n\t\t\tactive = false;\n\t\t\tclearInterval(timer);\n\t\t};\n\t}, []);\n\n\t/* Poll game state every 5s. */\n\tuseEffect(() => {\n\t\tlet active = true;\n\t\tconst doFetch = async (): Promise<void> => {\n\t\t\ttry {\n\t\t\t\tconst gs = (await fetchGameState()) as unknown as FlatGameState;\n\t\t\t\tif (active) {\n\t\t\t\t\tsetGameState(gs);\n\t\t\t\t\tif (gs.theme)\n\t\t\t\t\t\tdocument.documentElement.dataset.theme = gs.theme;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t/* non-fatal */\n\t\t\t}\n\t\t};\n\t\tvoid doFetch();\n\t\tconst timer = setInterval(() => void doFetch(), 5000);\n\t\treturn () => {\n\t\t\tactive = false;\n\t\t\tclearInterval(timer);\n\t\t};\n\t}, []);\n\n\t/* PUT a patch to the server immediately on change. */\n\tconst handlePatch = useCallback(async (patch: FlatGameStatePatch) => {\n\t\tsetSaving(true);\n\t\ttry {\n\t\t\tconst result = (await putGameState(\n\t\t\t\tpatch as unknown as GameStatePatch,\n\t\t\t)) as unknown as FlatGameState;\n\t\t\tsetGameState(result);\n\t\t\tif (result.theme)\n\t\t\t\tdocument.documentElement.dataset.theme = result.theme;\n\t\t} catch {\n\t\t\t/* non-fatal */\n\t\t}\n\t\tsetSaving(false);\n\t}, []);\n\n\tconst gmOn = gameState?.game_mode_on ?? false;\n\tconst themeVal = gameState?.theme ?? \"transparent\";\n\tconst tuiVal = gameState?.tui_display_mode ?? \"full\";\n\n\tconst cfg = snapshot?.config as ConfigExt | undefined;\n\tconst cw = snapshot?.context.contextWindow ?? 0;\n\n\treturn (\n\t\t<div className=\"config-tab\">\n\t\t\t<section className=\"config-settings\">\n\t\t\t\t<h3>Settings</h3>\n\t\t\t\t<div className=\"settings-row\">\n\t\t\t\t\t<label title={TOOLTIPS.gameMode}>\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\tchecked={gmOn}\n\t\t\t\t\t\t\tonChange={(e) =>\n\t\t\t\t\t\t\t\thandlePatch({ game_mode_on: e.currentTarget.checked })\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tdisabled={saving}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\tGame Mode\n\t\t\t\t\t</label>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"settings-row\">\n\t\t\t\t\t<label title={TOOLTIPS.theme}>\n\t\t\t\t\t\tTheme\n\t\t\t\t\t\t<select\n\t\t\t\t\t\t\tvalue={themeVal}\n\t\t\t\t\t\t\tonChange={(e) => handlePatch({ theme: e.currentTarget.value })}\n\t\t\t\t\t\t\tdisabled={saving}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{THEMES.map((t) => (\n\t\t\t\t\t\t\t\t<option key={t.id} value={t.id}>\n\t\t\t\t\t\t\t\t\t{t.label}\n\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</select>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tdisabled={saving}\n\t\t\t\t\t\t\tclassName=\"theme-cycle-btn\"\n\t\t\t\t\t\t\ttitle=\"Cycle to the next theme (P3)\"\n\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\tconst i = THEME_IDS.indexOf(themeVal);\n\t\t\t\t\t\t\t\tconst next =\n\t\t\t\t\t\t\t\t\tTHEME_IDS[(i < 0 ? 0 : i + 1) % THEME_IDS.length];\n\t\t\t\t\t\t\t\tif (next) void handlePatch({ theme: next });\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tNext theme →\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</label>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"settings-row\">\n\t\t\t\t\t<label title={TOOLTIPS.tuiMode}>\n\t\t\t\t\t\tTUI Mode\n\t\t\t\t\t\t<select\n\t\t\t\t\t\t\tvalue={tuiVal}\n\t\t\t\t\t\t\tonChange={(e) =>\n\t\t\t\t\t\t\t\thandlePatch({\n\t\t\t\t\t\t\t\t\ttui_display_mode: e.currentTarget.value as \"full\" | \"minimal\",\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tdisabled={saving}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<option value=\"full\">Full</option>\n\t\t\t\t\t\t\t<option value=\"minimal\">Minimal</option>\n\t\t\t\t\t\t</select>{\" \"}\n\t\t\t\t\t\t\t<span className=\"tui-mode-hint\">\n\t\t\t\t\t\t\t\t(affects the in-app TUI widget; not shown here)\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t</label>\n\t\t\t\t</div>\n\t\t\t</section>\n\n\t\t\t<section className=\"config-display\">\n\t\t\t\t<h3>Configuration</h3>\n\t\t\t\t<div className=\"config-grid\">\n\t\t\t\t\t<div className=\"config-item\">\n\t\t\t\t\t\t<span className=\"config-label\" title={TOOLTIPS.tier}>\n\t\t\t\t\t\t\tTier\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span className=\"config-value\">\n\t\t\t\t\t\t\t{snapshot ? `${snapshot.tier} (live)` : \"\\u2014\"}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"config-item\">\n\t\t\t\t\t\t<span className=\"config-label\" title={TOOLTIPS.preset}>\n\t\t\t\t\t\t\tPreset\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span className=\"config-value\">\n\t\t\t\t\t\t\t{snapshot?.presetTier ?? \"\\u2014\"}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"config-item\">\n\t\t\t\t\t\t<span className=\"config-label\" title={TOOLTIPS.pressure}>\n\t\t\t\t\t\t\tPressure\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span className=\"config-value\">\n\t\t\t\t\t\t\t{snapshot ? formatPressure(snapshot.pressure) : \"\\u2014\"}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"config-item\">\n\t\t\t\t\t\t<span className=\"config-label\" title={TOOLTIPS.threshold}>\n\t\t\t\t\t\t\tThreshold\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span className=\"config-value\">\n\t\t\t\t\t\t\t{cfg ? formatThreshold(cfg.thresholdTokens, cfg.tierPct, cw) : \"\\u2014\"}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"config-item\">\n\t\t\t\t\t\t<span className=\"config-label\" title={TOOLTIPS.fastGate}>\n\t\t\t\t\t\t\tFast Gate\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span className=\"config-value\">\n\t\t\t\t\t\t\t{cfg ? `${cfg.fastGatePct}%` : \"\\u2014\"}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"config-item\">\n\t\t\t\t\t\t<span className=\"config-label\">Auto</span>\n\t\t\t\t\t\t<span className=\"config-value\">\n\t\t\t\t\t\t\t{cfg ? (cfg.auto ? \"enabled\" : \"disabled\") : \"\\u2014\"}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div className=\"config-item\">\n\t\t\t\t\t\t<span className=\"config-label\">Anchor</span>\n\t\t\t\t\t\t<span className=\"config-value\">\n\t\t\t\t\t\t\t{cfg?.anchorUserMessages ?? \"\\u2014\"}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</section>\n\t\t</div>\n\t);\n}\n","/**\n * SetupTab/EmbedderHealthCard.tsx — embedder health probe card (Part A).\n *\n * Round-trips a test embed through the active embedder and shows ✓ working /\n * ✗ unreachable + latency + dimensions. Polls every 30s.\n */\nimport type React from \"react\";\nimport { useState, useEffect, useCallback } from \"react\";\nimport type { EmbedderHealthResponse } from \"@contracts\";\nimport { fetchEmbedderHealth } from \"../../api/client\";\n\nconst styles: Record<string, React.CSSProperties> = {\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};\n\nexport default function EmbedderHealthCard(): React.ReactElement {\n\tconst [health, setHealth] = useState<EmbedderHealthResponse | null>(null);\n\tconst [error, setError] = useState<string | null>(null);\n\n\tconst loadHealth = useCallback(() => {\n\t\tfetchEmbedderHealth()\n\t\t\t.then(setHealth)\n\t\t\t.catch((e: unknown) =>\n\t\t\t\tsetError(e instanceof Error ? e.message : String(e)),\n\t\t\t);\n\t}, []);\n\n\tuseEffect(() => {\n\t\tloadHealth();\n\t}, [loadHealth]);\n\n\t// Poll health every 30s\n\tuseEffect(() => {\n\t\tconst id = setInterval(loadHealth, 30000);\n\t\treturn () => clearInterval(id);\n\t}, [loadHealth]);\n\n\tconst ok = health?.status === \"ok\";\n\tconst statusText =\n\t\thealth?.status === \"ok\"\n\t\t\t? \"Working\"\n\t\t\t: health?.status === \"unreachable\"\n\t\t\t\t? \"Unreachable\"\n\t\t\t\t: \"Error\";\n\tconst color = ok ? \"#4caf50\" : \"#f44336\";\n\tconst icon = ok ? \"✓\" : \"✗\";\n\n\treturn (\n\t\t<div style={styles.section}>\n\t\t\t<h3 style={styles.sectionTitle}>Embedder Health</h3>\n\t\t\t{error && (\n\t\t\t\t<p style={{ color: \"#f44336\", fontSize: \"0.85rem\" }}>\n\t\t\t\t\tError: {error}\n\t\t\t\t</p>\n\t\t\t)}\n\t\t\t{!health && !error && (\n\t\t\t\t<p style={{ color: \"#888\", fontSize: \"0.85rem\" }}>\n\t\t\t\t\tProbing embedder...\n\t\t\t\t</p>\n\t\t\t)}\n\t\t\t{health && (\n\t\t\t\t<>\n\t\t\t\t\t<div style={styles.row}>\n\t\t\t\t\t\t<span style={{ ...styles.label, color: `${color}` }}>\n\t\t\t\t\t\t\t{icon} {statusText}:\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span style={styles.value}>{health.dim} dims</span>\n\t\t\t\t\t\t{health.latencyMs !== undefined && (\n\t\t\t\t\t\t\t<span style={{ color: \"#a0a0c0\", marginLeft: \"0.5rem\" }}>\n\t\t\t\t\t\t\t\t({health.latencyMs.toFixed(1)} ms)\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style={styles.row}>\n\t\t\t\t\t\t<span style={styles.label}>Endpoint:</span>\n\t\t\t\t\t\t<span style={styles.value}>\n\t\t\t\t\t\t\t{health.url ?? (\n\t\t\t\t\t\t\t\t<span style={{ color: \"#888\" }}>built-in (no URL)</span>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t{health.error && (\n\t\t\t\t\t\t<p style={{ color: \"#f44336\", fontSize: \"0.85rem\" }}>\n\t\t\t\t\t\t\t{health.error}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t)}\n\t\t\t\t</>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n","/**\n * SetupTab/RagSettingsCard.tsx — RAG feature flag toggles (S57 B1–B5).\n *\n * Shows each RAG flag as a checkbox toggle. Reads/writes the .mega-compact.env\n * file via the /api/rag-settings endpoint. HyDE (B5) is greyed out when no\n * LLM embedder (HttpEmbedder) is active — it requires an LLM to function.\n *\n * PREVENT-PI-004: all data comes from localhost dashboard API endpoints.\n */\nimport type React from \"react\";\nimport { useState, useEffect, useCallback } from \"react\";\nimport type { RagSettingsResponse } from \"@contracts\";\nimport { fetchRagSettings, postRagSettings } from \"../../api/client\";\n\nconst styles: Record<string, React.CSSProperties> = {\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\tflagRow: {\n\t\tdisplay: \"flex\",\n\t\talignItems: \"flex-start\",\n\t\tgap: \"0.5rem\",\n\t\tpadding: \"0.5rem 0\",\n\t\tborderBottom: \"1px solid #2a2a4e\",\n\t},\n\tcheckbox: {\n\t\tmarginTop: \"0.15rem\",\n\t\tcursor: \"pointer\",\n\t},\n\tlabel: {\n\t\tfontWeight: 600,\n\t\tcolor: \"#e0e0e0\",\n\t\tfontSize: \"0.9rem\",\n\t},\n\tdescription: {\n\t\tfontSize: \"0.8rem\",\n\t\tcolor: \"#a0a0c0\",\n\t\tmarginTop: \"0.15rem\",\n\t},\n\thint: {\n\t\tfontSize: \"0.75rem\",\n\t\tcolor: \"#ff9800\",\n\t\tmarginTop: \"0.15rem\",\n\t},\n\tbanner: {\n\t\tbackground: \"#3a2a00\",\n\t\tborder: \"1px solid #665500\",\n\t\tborderRadius: \"6px\",\n\t\tpadding: \"0.5rem 0.75rem\",\n\t\tmarginTop: \"0.5rem\",\n\t\tcolor: \"#ffcc00\",\n\t\tfontSize: \"0.8rem\",\n\t},\n};\n\nexport default function RagSettingsCard(): React.ReactElement {\n\tconst [settings, setSettings] = useState<RagSettingsResponse | null>(null);\n\tconst [error, setError] = useState<string | null>(null);\n\tconst [saving, setSaving] = useState(false);\n\tconst [restartBanner, setRestartBanner] = useState(false);\n\n\tconst load = useCallback(() => {\n\t\tfetchRagSettings()\n\t\t\t.then(setSettings)\n\t\t\t.catch((e: unknown) =>\n\t\t\t\tsetError(e instanceof Error ? e.message : String(e)),\n\t\t\t);\n\t}, []);\n\n\tuseEffect(() => {\n\t\tload();\n\t}, [load]);\n\n\tuseEffect(() => {\n\t\tconst id = setInterval(load, 30000);\n\t\treturn () => clearInterval(id);\n\t}, [load]);\n\n\tconst toggle = useCallback(\n\t\t(key: string, enabled: boolean) => {\n\t\t\tif (!settings) return;\n\t\t\tconst flag = settings.flags.find((f) => f.key === key);\n\t\t\tif (!flag || (flag.requiresLlm && !settings.llmActive)) return;\n\t\t\tsetSaving(true);\n\t\t\tpostRagSettings({ flags: { [key]: enabled } })\n\t\t\t\t.then(() => {\n\t\t\t\t\tsetRestartBanner(true);\n\t\t\t\t\tsetSaving(false);\n\t\t\t\t\tload();\n\t\t\t\t})\n\t\t\t\t.catch((e: unknown) => {\n\t\t\t\t\tsetError(e instanceof Error ? e.message : String(e));\n\t\t\t\t\tsetSaving(false);\n\t\t\t\t});\n\t\t},\n\t\t[settings, load],\n\t);\n\n\treturn (\n\t\t<div style={styles.section}>\n\t\t\t<h3 style={styles.sectionTitle}>RAG Settings</h3>\n\t\t\t<p style={{ fontSize: \"0.8rem\", color: \"#a0a0c0\", marginTop: 0 }}>\n\t\t\t\tRecall pipeline features. All default ON — toggle off to disable.\n\t\t\t\tChanges take effect after restart.\n\t\t\t</p>\n\t\t\t{error && (\n\t\t\t\t<p style={{ color: \"#f44336\", fontSize: \"0.85rem\" }}>Error: {error}</p>\n\t\t\t)}\n\t\t\t{settings?.flags.map((flag) => {\n\t\t\t\tconst locked = flag.requiresLlm && !settings.llmActive;\n\t\t\t\treturn (\n\t\t\t\t\t<div key={flag.key} style={styles.flagRow}>\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t...styles.checkbox,\n\t\t\t\t\t\t\t\topacity: locked ? 0.4 : 1,\n\t\t\t\t\t\t\t\tcursor: locked ? \"not-allowed\" : \"pointer\",\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tchecked={flag.enabled && !locked}\n\t\t\t\t\t\t\tdisabled={locked || saving}\n\t\t\t\t\t\t\tonChange={(e) => toggle(flag.key, e.currentTarget.checked)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<div style={styles.label}>{flag.label}</div>\n\t\t\t\t\t\t\t<div style={styles.description}>{flag.description}</div>\n\t\t\t\t\t\t\t{locked && (\n\t\t\t\t\t\t\t\t<div style={styles.hint}>\n\t\t\t\t\t\t\t\t\tRequires an LLM embedder (Ollama/HTTP). Configure one in\n\t\t\t\t\t\t\t\t\tthe Embedder section above first.\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t);\n\t\t\t})}\n\t\t\t{!settings && !error && (\n\t\t\t\t<p style={{ color: \"#888\", fontSize: \"0.85rem\" }}>Loading...</p>\n\t\t\t)}\n\t\t\t{restartBanner && (\n\t\t\t\t<div style={styles.banner}>\n\t\t\t\t\tSettings saved. <strong>Restart pi</strong> to apply changes.\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n","/**\n * SetupTab/EmbedderSetup.tsx — Embedder setup section (P0b).\n *\n * Shows current embedder configuration, warns about trigram recall quality,\n * and mirrors the /megasetup command with detection results. Extracted from\n * SetupTab.tsx to respect the extensions/ 500-line file limit.\n *\n * PREVENT-PI-004: all data comes from localhost dashboard API endpoints —\n * no external network calls.\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\";\nimport EmbedderHealthCard from \"./EmbedderHealthCard\";\nimport RagSettingsCard from \"./RagSettingsCard\";\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\nexport default function EmbedderSetup(): 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\tconst [customUrl, setCustomUrl] = useState(\"\");\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\" | \"custom\", url?: string) => {\n\t\tsetConfiguring(embedder);\n\t\tsetConfigError(null);\n\t\tsetConfigResult(null);\n\t\tconfigureEmbedder({ embedder, url })\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\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\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<EmbedderHealthCard />\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{\"configuredEmbedder\" in status && status.configuredEmbedder !== status.currentEmbedder && (\n\t\t\t\t\t\t\t<div style={styles.warning}>\n\t\t\t\t\t\t\t\t<strong>Configured but not active:</strong>{\" \"}\n\t\t\t\t\t\t\t\t{embedderLabel(status.configuredEmbedder)} is configured in\n\t\t\t\t\t\t\t\t.mega-compact.env but not yet loaded.{\" \"}\n\t\t\t\t\t\t\t\t<strong>Restart pi</strong> to activate it.\n\t\t\t\t\t\t\t\t{status.configuredUrl && (\n\t\t\t\t\t\t\t\t\t<> ({status.configuredUrl})</>\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\t{\"restartRequired\" in status && status.restartRequired && (\n\t\t\t\t\t\t\t<div style={{ ...styles.row, color: \"#ff9800\" }}>\n\t\t\t\t\t\t\t\t<span style={styles.label}>Status:</span>\n\t\t\t\t\t\t\t\t<span style={styles.value}>\n\t\t\t\t\t\t\t\t\tRestart required to activate the configured embedder\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t</div>\n\t\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}>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{/* Custom (remote) embedder — third-party / hosted endpoint */}\n\t\t\t<div style={styles.section}>\n\t\t\t\t<h3 style={styles.sectionTitle}>Custom Endpoint (remote / third-party)</h3>\n\t\t\t\t<p style={{ fontSize: \"0.85rem\", color: \"#a0a0c0\", marginTop: 0 }}>\n\t\t\t\t\tPoint at any OpenAI-compatible embeddings API or hosted endpoint.\n\t\t\t\t\tThis opts in to a non-loopback connection (sets{\" \"}\n\t\t\t\t\t<code>MEGACOMPACT_ALLOW_REMOTE_EMBEDDER=1</code>) — your prompts'\n\t\t\t\t\tembedding requests will be sent to the URL you enter. Default is\n\t\t\t\t\tloopback-only.\n\t\t\t\t</p>\n\t\t\t\t<div style={{ display: \"flex\", gap: \"0.5rem\", flexWrap: \"wrap\", alignItems: \"center\" }}>\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"url\"\n\t\t\t\t\t\tplaceholder=\"https://api.example.com/v1/embeddings\"\n\t\t\t\t\t\tvalue={customUrl}\n\t\t\t\t\t\tonChange={(e) => setCustomUrl(e.target.value)}\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tflex: \"1 1 300px\",\n\t\t\t\t\t\t\tbackground: \"#12122a\",\n\t\t\t\t\t\t\tcolor: \"#e0e0e0\",\n\t\t\t\t\t\t\tborder: \"1px solid #2a2a4e\",\n\t\t\t\t\t\t\tborderRadius: \"6px\",\n\t\t\t\t\t\t\tpadding: \"0.4rem 0.6rem\",\n\t\t\t\t\t\t\tfontSize: \"0.85rem\",\n\t\t\t\t\t\t\tfontFamily: \"monospace\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t\t<button\n\t\t\t\t\t\tstyle={{ ...styles.button, opacity: customUrl ? 1 : 0.4 }}\n\t\t\t\t\t\tonClick={() => applyEmbedder(\"custom\", customUrl)}\n\t\t\t\t\t\tdisabled={!customUrl || configuring !== null}\n\t\t\t\t\t>\n\t\t\t\t\t\t{configuring === \"custom\" ? \"Writing...\" : \"Use Custom URL\"}\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t\t<div style={styles.warning}>\n\t\t\t\t\t<strong>Heads up:</strong> a remote endpoint receives the text you embed\n\t\t\t\t\t(it does NOT receive your full conversation — only the strings passed to\n\t\t\t\t\t<code> embed()</code> for recall/dedup). Verify the endpoint's privacy\n\t\t\t\t\tpolicy before use.\n\t\t\t\t</div>\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\t<RagSettingsCard />\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/SetupTab.tsx — Setup wizard tab shell (P0b).\n *\n * Sub-tab shell routing between Embedder / Config / Game Mode / Achievements.\n * The embedder setup section lives in SetupTab/EmbedderSetup.tsx.\n *\n * PREVENT-PI-004: all data comes from localhost dashboard API endpoints —\n * no external network calls.\n */\nimport type React from \"react\";\nimport { useState } from \"react\";\nimport GameTab from \"./GameTab\";\nimport AchievementsTab from \"./AchievementsTab\";\nimport ConfigTab from \"./ConfigTab\";\nimport EmbedderSetup from \"./SetupTab/EmbedderSetup\";\n\nconst containerStyle: React.CSSProperties = {\n\tpadding: \"1rem\",\n\tmaxWidth: \"720px\",\n\tmargin: \"0 auto\",\n\tfontFamily: \"system-ui, sans-serif\",\n\tcolor: \"#e0e0e0\",\n};\n\ntype SetupSubTab = \"embedder\" | \"config\" | \"game\" | \"achievements\";\n\nconst subTabNavStyle: React.CSSProperties = {\n\tdisplay: \"flex\",\n\tgap: \"0.5rem\",\n\tmarginBottom: \"1rem\",\n\tborderBottom: \"1px solid #2a2a4e\",\n\tpaddingBottom: \"0.5rem\",\n};\n\nfunction subTabBtnStyle(active: boolean): React.CSSProperties {\n\treturn {\n\t\tbackground: active ? \"#3a5a9f\" : \"transparent\",\n\t\tcolor: active ? \"#fff\" : \"#a0a0c0\",\n\t\tborder: \"1px solid\",\n\t\tborderColor: active ? \"#3a5a9f\" : \"#2a2a4e\",\n\t\tborderRadius: \"6px\",\n\t\tpadding: \"0.4rem 0.8rem\",\n\t\tcursor: \"pointer\",\n\t\tfontSize: \"0.9rem\",\n\t\tfontWeight: active ? 600 : 400,\n\t};\n}\n\nexport default function SetupTab(): React.ReactElement {\n\tconst [subTab, setSubTab] = useState<SetupSubTab>(\"embedder\");\n\n\treturn (\n\t\t<div style={containerStyle}>\n\t\t\t<nav style={subTabNavStyle} aria-label=\"Setup sections\">\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tstyle={subTabBtnStyle(subTab === \"embedder\")}\n\t\t\t\t\tonClick={() => setSubTab(\"embedder\")}\n\t\t\t\t>\n\t\t\t\t\tEmbedder\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tstyle={subTabBtnStyle(subTab === \"config\")}\n\t\t\t\t\tonClick={() => setSubTab(\"config\")}\n\t\t\t\t>\n\t\t\t\t\tConfig\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tstyle={subTabBtnStyle(subTab === \"game\")}\n\t\t\t\t\tonClick={() => setSubTab(\"game\")}\n\t\t\t\t>\n\t\t\t\t\tGame Mode\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tstyle={subTabBtnStyle(subTab === \"achievements\")}\n\t\t\t\t\tonClick={() => setSubTab(\"achievements\")}\n\t\t\t\t>\n\t\t\t\t\tAchievements\n\t\t\t\t</button>\n\t\t\t</nav>\n\n\t\t\t{subTab === \"embedder\" && <EmbedderSetup />}\n\t\t\t{subTab === \"config\" && <ConfigTab />}\n\t\t\t{subTab === \"game\" && <GameTab />}\n\t\t\t{subTab === \"achievements\" && <AchievementsTab />}\n\t\t</div>\n\t);\n}\n"],"names":["fmtUnlockDate","ts","AchievementTiles","achievements","lastMaxTsRef","useRef","toastText","setToastText","useState","maxTs","mx","a","prevMaxTs","useEffect","newly","text","t","tiles","jsxs","jsx","isNew","fmtPct","v","fmtDate","trophyMeta","m","repoBasename","path","LeaderboardCard","title","rows","badge","renderValue","r","i","GameTab","scores","setScores","reposCount","setReposCount","setAchievements","gameModeOn","setGameModeOn","loading","setLoading","megaToast","setMegaToast","lastMegaTsRef","fetchAll","useCallback","cache","dedupe","turns","megaCache","repos","ach","fetchGameScores","fetchAchievements","newRow","active","doFetch","timer","gs","fetchGameState","megaRows","bestMega","firstSeen","fs","showMega","turnsRows","maxTurns","lvl","hasData","Fragment","AchievementsTab","error","setError","e","run","THEMES","THEME_IDS","TOOLTIPS","formatThreshold","tokens","tierPct","cw","txt","formatPressure","pressure","ConfigTab","snapshot","setSnapshot","gameState","setGameState","saving","setSaving","s","fetchSnapshot","handlePatch","patch","result","putGameState","gmOn","themeVal","tuiVal","cfg","next","styles","EmbedderHealthCard","health","setHealth","loadHealth","fetchEmbedderHealth","id","ok","statusText","color","icon","RagSettingsCard","settings","setSettings","restartBanner","setRestartBanner","load","fetchRagSettings","toggle","key","enabled","flag","f","postRagSettings","locked","EmbedderSetup","status","setStatus","detect","setDetect","statusError","setStatusError","detectError","setDetectError","runningDetect","setRunningDetect","configuring","setConfiguring","configResult","setConfigResult","configError","setConfigError","customUrl","setCustomUrl","loadStatus","fetchSetupStatus","applyEmbedder","embedder","url","configureEmbedder","runDetect","fetchSetupDetect","d","embedderLabel","trigramWarning","detectBadge","installed","bg","containerStyle","subTabNavStyle","subTabBtnStyle","SetupTab","subTab","setSubTab"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{j as a}from"./index-mOlljTFI.js";import{g as t}from"./format-COjDIVGj.js";function s({label:e,value:c}){return a.jsxs("div",{className:"ov-stat-row",children:[a.jsx("span",{className:"ov-stat-label",children:e}),a.jsx("span",{className:"ov-stat-value",children:c})]})}function n(e){return a.jsxs("div",{className:"card cache-hits-card",children:[a.jsx("h3",{children:"💾 Cache Hits & Compactions"}),a.jsx(s,{label:"Cache Hits (session)",value:e.cacheHitsSession.toLocaleString()}),a.jsx(s,{label:"Cache Hits (total)",value:e.cacheHitsTotal.toLocaleString()}),a.jsx(s,{label:"Tokens Saved (session)",value:e.tokensSavedSession.toLocaleString()}),a.jsx(s,{label:"Tokens Saved (total)",value:e.tokensSavedTotal.toLocaleString()}),a.jsx(s,{label:"Compactions (session)",value:e.compactionsSession.toLocaleString()}),a.jsx(s,{label:"Compactions (total)",value:e.compactionsTotal.toLocaleString()})]})}function l({label:e,value:c}){return a.jsxs("div",{className:"ov-stat-row",children:[a.jsx("span",{className:"ov-stat-label",children:e}),a.jsx("span",{className:"ov-stat-value",children:c})]})}function r(e){return a.jsxs("div",{className:"card time-saved-card",children:[a.jsx("h3",{children:"⏱ Time Saved (est.)"}),a.jsx(l,{label:"Compact (session)",value:t(e.compactSessionSec)}),a.jsx(l,{label:"Compact (total)",value:t(e.compactTotalSec)}),a.jsx(l,{label:"Cache Hit (session)",value:t(e.cacheHitSessionSec)}),a.jsx(l,{label:"Cache Hit (total)",value:t(e.cacheHitTotalSec)})]})}export{n as C,r as T};
2
- //# sourceMappingURL=TimeSavedCard-DnPg0L0z.js.map
1
+ import{j as a}from"./index-BEj1Zahy.js";import{g as t}from"./format-COjDIVGj.js";function s({label:e,value:c}){return a.jsxs("div",{className:"ov-stat-row",children:[a.jsx("span",{className:"ov-stat-label",children:e}),a.jsx("span",{className:"ov-stat-value",children:c})]})}function n(e){return a.jsxs("div",{className:"card cache-hits-card",children:[a.jsx("h3",{children:"💾 Cache Hits & Compactions"}),a.jsx(s,{label:"Cache Hits (session)",value:e.cacheHitsSession.toLocaleString()}),a.jsx(s,{label:"Cache Hits (total)",value:e.cacheHitsTotal.toLocaleString()}),a.jsx(s,{label:"Tokens Saved (session)",value:e.tokensSavedSession.toLocaleString()}),a.jsx(s,{label:"Tokens Saved (total)",value:e.tokensSavedTotal.toLocaleString()}),a.jsx(s,{label:"Compactions (session)",value:e.compactionsSession.toLocaleString()}),a.jsx(s,{label:"Compactions (total)",value:e.compactionsTotal.toLocaleString()})]})}function l({label:e,value:c}){return a.jsxs("div",{className:"ov-stat-row",children:[a.jsx("span",{className:"ov-stat-label",children:e}),a.jsx("span",{className:"ov-stat-value",children:c})]})}function r(e){return a.jsxs("div",{className:"card time-saved-card",children:[a.jsx("h3",{children:"⏱ Time Saved (est.)"}),a.jsx(l,{label:"Compact (session)",value:t(e.compactSessionSec)}),a.jsx(l,{label:"Compact (total)",value:t(e.compactTotalSec)}),a.jsx(l,{label:"Cache Hit (session)",value:t(e.cacheHitSessionSec)}),a.jsx(l,{label:"Cache Hit (total)",value:t(e.cacheHitTotalSec)})]})}export{n as C,r as T};
2
+ //# sourceMappingURL=TimeSavedCard-p55K1tFP.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TimeSavedCard-DnPg0L0z.js","sources":["../../src/components/CacheHitsCard.tsx","../../src/components/TimeSavedCard.tsx"],"sourcesContent":["/**\n * dashboard-client/src/components/CacheHitsCard.tsx — Cache Hits & Compactions card.\n *\n * 6 fields: Cache Hits (session), Cache Hits (total),\n * Tokens Saved (session), Tokens Saved (total),\n * Compactions (session), Compactions (total).\n */\n\nimport type React from \"react\";\n\nexport interface CacheHitsCardProps {\n\t/** Cache hits in the current session. */\n\tcacheHitsSession: number;\n\t/** Total cache hits across all sessions. */\n\tcacheHitsTotal: number;\n\t/** Tokens saved by cache hits this session. */\n\ttokensSavedSession: number;\n\t/** Total tokens saved by cache hits. */\n\ttokensSavedTotal: number;\n\t/** Compactions performed this session. */\n\tcompactionsSession: number;\n\t/** Total compactions performed. */\n\tcompactionsTotal: number;\n}\n\nfunction StatRow({\n\tlabel,\n\tvalue,\n}: {\n\tlabel: string;\n\tvalue: string | number;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"ov-stat-row\">\n\t\t\t<span className=\"ov-stat-label\">{label}</span>\n\t\t\t<span className=\"ov-stat-value\">{value}</span>\n\t\t</div>\n\t);\n}\n\nexport function CacheHitsCard(\n\tprops: CacheHitsCardProps,\n): React.ReactElement {\n\treturn (\n\t\t<div className=\"card cache-hits-card\">\n\t\t\t<h3>💾 Cache Hits &amp; Compactions</h3>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Cache Hits (session)\"\n\t\t\t\tvalue={props.cacheHitsSession.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Cache Hits (total)\"\n\t\t\t\tvalue={props.cacheHitsTotal.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Tokens Saved (session)\"\n\t\t\t\tvalue={props.tokensSavedSession.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Tokens Saved (total)\"\n\t\t\t\tvalue={props.tokensSavedTotal.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Compactions (session)\"\n\t\t\t\tvalue={props.compactionsSession.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Compactions (total)\"\n\t\t\t\tvalue={props.compactionsTotal.toLocaleString()}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/components/TimeSavedCard.tsx — Time Saved (est.) card.\n *\n * 4 fields: Compact (session), Compact (total),\n * Cache Hit (session), Cache Hit (total).\n */\n\nimport type React from \"react\";\nimport { fmtSec } from \"../utils/format\";\n\nexport interface TimeSavedCardProps {\n\t/** Seconds saved by compaction this session. */\n\tcompactSessionSec: number;\n\t/** Total seconds saved by compaction. */\n\tcompactTotalSec: number;\n\t/** Seconds saved by cache hits this session. */\n\tcacheHitSessionSec: number;\n\t/** Total seconds saved by cache hits. */\n\tcacheHitTotalSec: number;\n}\n\nfunction StatRow({\n\tlabel,\n\tvalue,\n}: {\n\tlabel: string;\n\tvalue: string;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"ov-stat-row\">\n\t\t\t<span className=\"ov-stat-label\">{label}</span>\n\t\t\t<span className=\"ov-stat-value\">{value}</span>\n\t\t</div>\n\t);\n}\n\nexport function TimeSavedCard(\n\tprops: TimeSavedCardProps,\n): React.ReactElement {\n\treturn (\n\t\t<div className=\"card time-saved-card\">\n\t\t\t<h3>⏱ Time Saved (est.)</h3>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Compact (session)\"\n\t\t\t\tvalue={fmtSec(props.compactSessionSec)}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Compact (total)\"\n\t\t\t\tvalue={fmtSec(props.compactTotalSec)}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Cache Hit (session)\"\n\t\t\t\tvalue={fmtSec(props.cacheHitSessionSec)}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Cache Hit (total)\"\n\t\t\t\tvalue={fmtSec(props.cacheHitTotalSec)}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n"],"names":["StatRow","label","value","jsxs","jsx","CacheHitsCard","props","TimeSavedCard","fmtSec"],"mappings":"iFAyBA,SAASA,EAAQ,CAChB,MAAAC,EACA,MAAAC,CACD,EAGuB,CACtB,OACCC,EAAAA,KAAC,MAAA,CAAI,UAAU,cACd,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAH,EAAM,EACvCG,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAF,CAAA,CAAM,CAAA,EACxC,CAEF,CAEO,SAASG,EACfC,EACqB,CACrB,OACCH,EAAAA,KAAC,MAAA,CAAI,UAAU,uBACd,SAAA,CAAAC,EAAAA,IAAC,MAAG,SAAA,6BAAA,CAA+B,EACnCA,EAAAA,IAACJ,EAAA,CACA,MAAM,uBACN,MAAOM,EAAM,iBAAiB,eAAA,CAAe,CAAA,EAE9CF,EAAAA,IAACJ,EAAA,CACA,MAAM,qBACN,MAAOM,EAAM,eAAe,eAAA,CAAe,CAAA,EAE5CF,EAAAA,IAACJ,EAAA,CACA,MAAM,yBACN,MAAOM,EAAM,mBAAmB,eAAA,CAAe,CAAA,EAEhDF,EAAAA,IAACJ,EAAA,CACA,MAAM,uBACN,MAAOM,EAAM,iBAAiB,eAAA,CAAe,CAAA,EAE9CF,EAAAA,IAACJ,EAAA,CACA,MAAM,wBACN,MAAOM,EAAM,mBAAmB,eAAA,CAAe,CAAA,EAEhDF,EAAAA,IAACJ,EAAA,CACA,MAAM,sBACN,MAAOM,EAAM,iBAAiB,eAAA,CAAe,CAAA,CAC9C,EACD,CAEF,CCnDA,SAASN,EAAQ,CAChB,MAAAC,EACA,MAAAC,CACD,EAGuB,CACtB,OACCC,EAAAA,KAAC,MAAA,CAAI,UAAU,cACd,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAH,EAAM,EACvCG,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAF,CAAA,CAAM,CAAA,EACxC,CAEF,CAEO,SAASK,EACfD,EACqB,CACrB,OACCH,EAAAA,KAAC,MAAA,CAAI,UAAU,uBACd,SAAA,CAAAC,EAAAA,IAAC,MAAG,SAAA,qBAAA,CAAmB,EACvBA,EAAAA,IAACJ,EAAA,CACA,MAAM,oBACN,MAAOQ,EAAOF,EAAM,iBAAiB,CAAA,CAAA,EAEtCF,EAAAA,IAACJ,EAAA,CACA,MAAM,kBACN,MAAOQ,EAAOF,EAAM,eAAe,CAAA,CAAA,EAEpCF,EAAAA,IAACJ,EAAA,CACA,MAAM,sBACN,MAAOQ,EAAOF,EAAM,kBAAkB,CAAA,CAAA,EAEvCF,EAAAA,IAACJ,EAAA,CACA,MAAM,oBACN,MAAOQ,EAAOF,EAAM,gBAAgB,CAAA,CAAA,CACrC,EACD,CAEF"}
1
+ {"version":3,"file":"TimeSavedCard-p55K1tFP.js","sources":["../../src/components/CacheHitsCard.tsx","../../src/components/TimeSavedCard.tsx"],"sourcesContent":["/**\n * dashboard-client/src/components/CacheHitsCard.tsx — Cache Hits & Compactions card.\n *\n * 6 fields: Cache Hits (session), Cache Hits (total),\n * Tokens Saved (session), Tokens Saved (total),\n * Compactions (session), Compactions (total).\n */\n\nimport type React from \"react\";\n\nexport interface CacheHitsCardProps {\n\t/** Cache hits in the current session. */\n\tcacheHitsSession: number;\n\t/** Total cache hits across all sessions. */\n\tcacheHitsTotal: number;\n\t/** Tokens saved by cache hits this session. */\n\ttokensSavedSession: number;\n\t/** Total tokens saved by cache hits. */\n\ttokensSavedTotal: number;\n\t/** Compactions performed this session. */\n\tcompactionsSession: number;\n\t/** Total compactions performed. */\n\tcompactionsTotal: number;\n}\n\nfunction StatRow({\n\tlabel,\n\tvalue,\n}: {\n\tlabel: string;\n\tvalue: string | number;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"ov-stat-row\">\n\t\t\t<span className=\"ov-stat-label\">{label}</span>\n\t\t\t<span className=\"ov-stat-value\">{value}</span>\n\t\t</div>\n\t);\n}\n\nexport function CacheHitsCard(\n\tprops: CacheHitsCardProps,\n): React.ReactElement {\n\treturn (\n\t\t<div className=\"card cache-hits-card\">\n\t\t\t<h3>💾 Cache Hits &amp; Compactions</h3>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Cache Hits (session)\"\n\t\t\t\tvalue={props.cacheHitsSession.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Cache Hits (total)\"\n\t\t\t\tvalue={props.cacheHitsTotal.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Tokens Saved (session)\"\n\t\t\t\tvalue={props.tokensSavedSession.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Tokens Saved (total)\"\n\t\t\t\tvalue={props.tokensSavedTotal.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Compactions (session)\"\n\t\t\t\tvalue={props.compactionsSession.toLocaleString()}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Compactions (total)\"\n\t\t\t\tvalue={props.compactionsTotal.toLocaleString()}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/components/TimeSavedCard.tsx — Time Saved (est.) card.\n *\n * 4 fields: Compact (session), Compact (total),\n * Cache Hit (session), Cache Hit (total).\n */\n\nimport type React from \"react\";\nimport { fmtSec } from \"../utils/format\";\n\nexport interface TimeSavedCardProps {\n\t/** Seconds saved by compaction this session. */\n\tcompactSessionSec: number;\n\t/** Total seconds saved by compaction. */\n\tcompactTotalSec: number;\n\t/** Seconds saved by cache hits this session. */\n\tcacheHitSessionSec: number;\n\t/** Total seconds saved by cache hits. */\n\tcacheHitTotalSec: number;\n}\n\nfunction StatRow({\n\tlabel,\n\tvalue,\n}: {\n\tlabel: string;\n\tvalue: string;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"ov-stat-row\">\n\t\t\t<span className=\"ov-stat-label\">{label}</span>\n\t\t\t<span className=\"ov-stat-value\">{value}</span>\n\t\t</div>\n\t);\n}\n\nexport function TimeSavedCard(\n\tprops: TimeSavedCardProps,\n): React.ReactElement {\n\treturn (\n\t\t<div className=\"card time-saved-card\">\n\t\t\t<h3>⏱ Time Saved (est.)</h3>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Compact (session)\"\n\t\t\t\tvalue={fmtSec(props.compactSessionSec)}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Compact (total)\"\n\t\t\t\tvalue={fmtSec(props.compactTotalSec)}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Cache Hit (session)\"\n\t\t\t\tvalue={fmtSec(props.cacheHitSessionSec)}\n\t\t\t/>\n\t\t\t<StatRow\n\t\t\t\tlabel=\"Cache Hit (total)\"\n\t\t\t\tvalue={fmtSec(props.cacheHitTotalSec)}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n"],"names":["StatRow","label","value","jsxs","jsx","CacheHitsCard","props","TimeSavedCard","fmtSec"],"mappings":"iFAyBA,SAASA,EAAQ,CAChB,MAAAC,EACA,MAAAC,CACD,EAGuB,CACtB,OACCC,EAAAA,KAAC,MAAA,CAAI,UAAU,cACd,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAH,EAAM,EACvCG,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAF,CAAA,CAAM,CAAA,EACxC,CAEF,CAEO,SAASG,EACfC,EACqB,CACrB,OACCH,EAAAA,KAAC,MAAA,CAAI,UAAU,uBACd,SAAA,CAAAC,EAAAA,IAAC,MAAG,SAAA,6BAAA,CAA+B,EACnCA,EAAAA,IAACJ,EAAA,CACA,MAAM,uBACN,MAAOM,EAAM,iBAAiB,eAAA,CAAe,CAAA,EAE9CF,EAAAA,IAACJ,EAAA,CACA,MAAM,qBACN,MAAOM,EAAM,eAAe,eAAA,CAAe,CAAA,EAE5CF,EAAAA,IAACJ,EAAA,CACA,MAAM,yBACN,MAAOM,EAAM,mBAAmB,eAAA,CAAe,CAAA,EAEhDF,EAAAA,IAACJ,EAAA,CACA,MAAM,uBACN,MAAOM,EAAM,iBAAiB,eAAA,CAAe,CAAA,EAE9CF,EAAAA,IAACJ,EAAA,CACA,MAAM,wBACN,MAAOM,EAAM,mBAAmB,eAAA,CAAe,CAAA,EAEhDF,EAAAA,IAACJ,EAAA,CACA,MAAM,sBACN,MAAOM,EAAM,iBAAiB,eAAA,CAAe,CAAA,CAC9C,EACD,CAEF,CCnDA,SAASN,EAAQ,CAChB,MAAAC,EACA,MAAAC,CACD,EAGuB,CACtB,OACCC,EAAAA,KAAC,MAAA,CAAI,UAAU,cACd,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAH,EAAM,EACvCG,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,SAAAF,CAAA,CAAM,CAAA,EACxC,CAEF,CAEO,SAASK,EACfD,EACqB,CACrB,OACCH,EAAAA,KAAC,MAAA,CAAI,UAAU,uBACd,SAAA,CAAAC,EAAAA,IAAC,MAAG,SAAA,qBAAA,CAAmB,EACvBA,EAAAA,IAACJ,EAAA,CACA,MAAM,oBACN,MAAOQ,EAAOF,EAAM,iBAAiB,CAAA,CAAA,EAEtCF,EAAAA,IAACJ,EAAA,CACA,MAAM,kBACN,MAAOQ,EAAOF,EAAM,eAAe,CAAA,CAAA,EAEpCF,EAAAA,IAACJ,EAAA,CACA,MAAM,sBACN,MAAOQ,EAAOF,EAAM,kBAAkB,CAAA,CAAA,EAEvCF,EAAAA,IAACJ,EAAA,CACA,MAAM,oBACN,MAAOQ,EAAOF,EAAM,gBAAgB,CAAA,CAAA,CACrC,EACD,CAEF"}
@@ -1,2 +1,2 @@
1
- import{u as m,r as a,v as u,w as p,j as e}from"./index-mOlljTFI.js";function b(s){return s?new Date(s).toLocaleString():"—"}function f(){const{data:s,loading:h,error:n}=m(a.useCallback(()=>u(),[]),{pollInterval:3e4}),[l,x]=a.useState(""),[i,o]=a.useState(null),r=m(a.useCallback(()=>i?p(i):Promise.reject(),[i]),{pollInterval:0}),d=a.useMemo(()=>{if(!s)return[];const t=l.trim().toLowerCase();return t?s.topics.filter(c=>c.label.toLowerCase().includes(t)||c.termScore.some(j=>j.term.toLowerCase().includes(t))):s.topics},[s,l]);return n&&!s?e.jsxs("div",{className:"tab-stub",children:["Error loading topics: ",n.message]}):h&&!s?e.jsx("div",{className:"tab-stub",children:"Loading topics…"}):s?s.totalTopics===0?e.jsxs("div",{className:"tab-stub",children:[e.jsx("h3",{children:"Wiki"}),e.jsx("p",{children:"No topics yet. Topics are auto-generated after every 3rd compaction from real memory embeddings (k-means + TF-IDF)."}),e.jsx("p",{children:"Check back after a few more compaction cycles."})]}):e.jsxs("div",{className:"tab-content topics-tab",children:[e.jsx("h3",{children:"Wiki"}),e.jsxs("p",{className:"subtitle",children:[s.totalTopics," topic",s.totalTopics!==1?"s":""," ·"," ",s.totalAssigned," assigned memori",s.totalAssigned!==1?"es":"y",s.lastRebuildAt!=null&&e.jsxs(e.Fragment,{children:[" · last rebuild ",new Date(s.lastRebuildAt).toLocaleString()]})]}),e.jsx("input",{type:"search",className:"topics-search",placeholder:"Filter topics by label or term…",value:l,onChange:t=>x(t.target.value)}),i&&e.jsxs("section",{className:"topic-drilldown",children:[e.jsxs("h4",{children:[e.jsx("button",{type:"button",className:"link-btn",onClick:()=>o(null),children:"← back"})," ","Topic ",e.jsx("code",{children:i}),r.data&&e.jsxs(e.Fragment,{children:[" · ",r.data.label]}),r.data&&e.jsxs(e.Fragment,{children:[" · ",r.data.assignments.length," memories"]})]}),r.error?e.jsxs("div",{className:"tab-stub",children:["Error: ",r.error.message]}):r.loading&&!r.data?e.jsx("div",{className:"tab-stub",children:"Loading memories…"}):r.data?e.jsxs("table",{className:"data-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Memory id"}),e.jsx("th",{children:"Confidence"}),e.jsx("th",{children:"Assigned"})]})}),e.jsx("tbody",{children:r.data.assignments.map(t=>e.jsxs("tr",{children:[e.jsx("td",{children:e.jsx("code",{children:t.memoryId})}),e.jsx("td",{children:t.confidence!=null?t.confidence.toFixed(2):"—"}),e.jsx("td",{children:b(t.assignedAt)})]},t.memoryId))})]}):null]}),!i&&e.jsxs("table",{className:"data-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Label"}),e.jsx("th",{children:"Memories"}),e.jsx("th",{children:"Top Terms"}),e.jsx("th",{})]})}),e.jsxs("tbody",{children:[d.map(t=>e.jsxs("tr",{className:"topic-row",onClick:()=>o(t.id),style:{cursor:"pointer"},children:[e.jsx("td",{className:"topic-label",children:t.label}),e.jsx("td",{className:"topic-count",children:t.memoryCount}),e.jsx("td",{className:"topic-terms",children:t.termScore.slice(0,8).map(c=>c.term).join(", ")}),e.jsx("td",{children:e.jsx("button",{type:"button",className:"mini-btn",children:"drill"})})]},t.id)),d.length===0&&e.jsx("tr",{children:e.jsxs("td",{colSpan:4,className:"muted",children:["No topics match “",l,"”."]})})]})]})]}):e.jsx("div",{className:"tab-stub",children:"No topic data available."})}export{f as default};
2
- //# sourceMappingURL=TopicsTab-BODHOg_b.js.map
1
+ import{u as m,r as a,x as u,y as p,j as e}from"./index-BEj1Zahy.js";function b(s){return s?new Date(s).toLocaleString():"—"}function f(){const{data:s,loading:h,error:n}=m(a.useCallback(()=>u(),[]),{pollInterval:3e4}),[l,x]=a.useState(""),[i,o]=a.useState(null),r=m(a.useCallback(()=>i?p(i):Promise.reject(),[i]),{pollInterval:0}),d=a.useMemo(()=>{if(!s)return[];const t=l.trim().toLowerCase();return t?s.topics.filter(c=>c.label.toLowerCase().includes(t)||c.termScore.some(j=>j.term.toLowerCase().includes(t))):s.topics},[s,l]);return n&&!s?e.jsxs("div",{className:"tab-stub",children:["Error loading topics: ",n.message]}):h&&!s?e.jsx("div",{className:"tab-stub",children:"Loading topics…"}):s?s.totalTopics===0?e.jsxs("div",{className:"tab-stub",children:[e.jsx("h3",{children:"Wiki"}),e.jsx("p",{children:"No topics yet. Topics are auto-generated after every 3rd compaction from real memory embeddings (k-means + TF-IDF)."}),e.jsx("p",{children:"Check back after a few more compaction cycles."})]}):e.jsxs("div",{className:"tab-content topics-tab",children:[e.jsx("h3",{children:"Wiki"}),e.jsxs("p",{className:"subtitle",children:[s.totalTopics," topic",s.totalTopics!==1?"s":""," ·"," ",s.totalAssigned," assigned memori",s.totalAssigned!==1?"es":"y",s.lastRebuildAt!=null&&e.jsxs(e.Fragment,{children:[" · last rebuild ",new Date(s.lastRebuildAt).toLocaleString()]})]}),e.jsx("input",{type:"search",className:"topics-search",placeholder:"Filter topics by label or term…",value:l,onChange:t=>x(t.target.value)}),i&&e.jsxs("section",{className:"topic-drilldown",children:[e.jsxs("h4",{children:[e.jsx("button",{type:"button",className:"link-btn",onClick:()=>o(null),children:"← back"})," ","Topic ",e.jsx("code",{children:i}),r.data&&e.jsxs(e.Fragment,{children:[" · ",r.data.label]}),r.data&&e.jsxs(e.Fragment,{children:[" · ",r.data.assignments.length," memories"]})]}),r.error?e.jsxs("div",{className:"tab-stub",children:["Error: ",r.error.message]}):r.loading&&!r.data?e.jsx("div",{className:"tab-stub",children:"Loading memories…"}):r.data?e.jsxs("table",{className:"data-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Memory id"}),e.jsx("th",{children:"Confidence"}),e.jsx("th",{children:"Assigned"})]})}),e.jsx("tbody",{children:r.data.assignments.map(t=>e.jsxs("tr",{children:[e.jsx("td",{children:e.jsx("code",{children:t.memoryId})}),e.jsx("td",{children:t.confidence!=null?t.confidence.toFixed(2):"—"}),e.jsx("td",{children:b(t.assignedAt)})]},t.memoryId))})]}):null]}),!i&&e.jsxs("table",{className:"data-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Label"}),e.jsx("th",{children:"Memories"}),e.jsx("th",{children:"Top Terms"}),e.jsx("th",{})]})}),e.jsxs("tbody",{children:[d.map(t=>e.jsxs("tr",{className:"topic-row",onClick:()=>o(t.id),style:{cursor:"pointer"},children:[e.jsx("td",{className:"topic-label",children:t.label}),e.jsx("td",{className:"topic-count",children:t.memoryCount}),e.jsx("td",{className:"topic-terms",children:t.termScore.slice(0,8).map(c=>c.term).join(", ")}),e.jsx("td",{children:e.jsx("button",{type:"button",className:"mini-btn",children:"drill"})})]},t.id)),d.length===0&&e.jsx("tr",{children:e.jsxs("td",{colSpan:4,className:"muted",children:["No topics match “",l,"”."]})})]})]})]}):e.jsx("div",{className:"tab-stub",children:"No topic data available."})}export{f as default};
2
+ //# sourceMappingURL=TopicsTab-D8FqyAbK.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TopicsTab-BODHOg_b.js","sources":["../../src/tabs/TopicsTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/tabs/TopicsTab.tsx — Auto-categorizing wiki (S51 + S52 polish).\n *\n * Fetches /api/topics and renders the k-means + TF-IDF topic clusters. S52 polish\n * adds: (1) a search box filtering topics by label / discriminative term, and\n * (2) a topic drill-down — click a topic to load its member memories\n * (/api/topics/:id/memories). Read-only; no write operations.\n */\n\nimport type React from \"react\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport { useApi } from \"../hooks/useApi\";\nimport { fetchTopics, fetchTopicMemories } from \"../api/client\";\nimport type { TopicsResponse, TopicMemoriesResponse } from \"@contracts\";\n\nfunction fmtTs(ms: number | null): string {\n\tif (!ms) return \"—\";\n\treturn new Date(ms).toLocaleString();\n}\n\nexport default function TopicsTab(): React.ReactElement {\n\tconst { data, loading, error } = useApi<TopicsResponse>(\n\t\tuseCallback(() => fetchTopics(), []),\n\t\t{ pollInterval: 30_000 },\n\t);\n\tconst [query, setQuery] = useState(\"\");\n\tconst [drillTopicId, setDrillTopicId] = useState<string | null>(null);\n\n\tconst drill = useApi<TopicMemoriesResponse>(\n\t\tuseCallback(\n\t\t\t() =>\n\t\t\t\tdrillTopicId ? fetchTopicMemories(drillTopicId) : Promise.reject(),\n\t\t\t[drillTopicId],\n\t\t),\n\t\t{ pollInterval: 0 },\n\t);\n\n\tconst filtered = useMemo(() => {\n\t\tif (!data) return [];\n\t\tconst q = query.trim().toLowerCase();\n\t\tif (!q) return data.topics;\n\t\treturn data.topics.filter(\n\t\t\t(t) =>\n\t\t\t\tt.label.toLowerCase().includes(q) ||\n\t\t\t\tt.termScore.some((s) => s.term.toLowerCase().includes(q)),\n\t\t);\n\t}, [data, query]);\n\n\tif (error && !data) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">Error loading topics: {error.message}</div>\n\t\t);\n\t}\n\tif (loading && !data) {\n\t\treturn <div className=\"tab-stub\">Loading topics…</div>;\n\t}\n\tif (!data) {\n\t\treturn <div className=\"tab-stub\">No topic data available.</div>;\n\t}\n\n\tif (data.totalTopics === 0) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">\n\t\t\t\t<h3>Wiki</h3>\n\t\t\t\t<p>\n\t\t\t\t\tNo topics yet. Topics are auto-generated after every 3rd compaction\n\t\t\t\t\tfrom real memory embeddings (k-means + TF-IDF).\n\t\t\t\t</p>\n\t\t\t\t<p>Check back after a few more compaction cycles.</p>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"tab-content topics-tab\">\n\t\t\t<h3>Wiki</h3>\n\t\t\t<p className=\"subtitle\">\n\t\t\t\t{data.totalTopics} topic{data.totalTopics !== 1 ? \"s\" : \"\"} ·{\" \"}\n\t\t\t\t{data.totalAssigned} assigned memori\n\t\t\t\t{data.totalAssigned !== 1 ? \"es\" : \"y\"}\n\t\t\t\t{data.lastRebuildAt != null && (\n\t\t\t\t\t<> · last rebuild {new Date(data.lastRebuildAt).toLocaleString()}</>\n\t\t\t\t)}\n\t\t\t</p>\n\n\t\t\t<input\n\t\t\t\ttype=\"search\"\n\t\t\t\tclassName=\"topics-search\"\n\t\t\t\tplaceholder=\"Filter topics by label or term…\"\n\t\t\t\tvalue={query}\n\t\t\t\tonChange={(e) => setQuery(e.target.value)}\n\t\t\t/>\n\n\t\t\t{drillTopicId && (\n\t\t\t\t<section className=\"topic-drilldown\">\n\t\t\t\t\t<h4>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName=\"link-btn\"\n\t\t\t\t\t\t\tonClick={() => setDrillTopicId(null)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t← back\n\t\t\t\t\t\t</button>{\" \"}\n\t\t\t\t\t\tTopic <code>{drillTopicId}</code>\n\t\t\t\t\t\t{drill.data && <> · {drill.data.label}</>}\n\t\t\t\t\t\t{drill.data && <> · {drill.data.assignments.length} memories</>}\n\t\t\t\t\t</h4>\n\t\t\t\t\t{drill.error ? (\n\t\t\t\t\t\t<div className=\"tab-stub\">\n\t\t\t\t\t\t\tError: {(drill.error as Error).message}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : drill.loading && !drill.data ? (\n\t\t\t\t\t\t<div className=\"tab-stub\">Loading memories…</div>\n\t\t\t\t\t) : drill.data ? (\n\t\t\t\t\t\t<table className=\"data-table\">\n\t\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t<th>Memory id</th>\n\t\t\t\t\t\t\t\t\t<th>Confidence</th>\n\t\t\t\t\t\t\t\t\t<th>Assigned</th>\n\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t{drill.data.assignments.map((a) => (\n\t\t\t\t\t\t\t\t\t<tr key={a.memoryId}>\n\t\t\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t\t\t<code>{a.memoryId}</code>\n\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t\t\t{a.confidence != null ? a.confidence.toFixed(2) : \"—\"}\n\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t<td>{fmtTs(a.assignedAt)}</td>\n\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t</table>\n\t\t\t\t\t) : null}\n\t\t\t\t</section>\n\t\t\t)}\n\n\t\t\t{!drillTopicId && (\n\t\t\t\t<table className=\"data-table\">\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<th>Label</th>\n\t\t\t\t\t\t\t<th>Memories</th>\n\t\t\t\t\t\t\t<th>Top Terms</th>\n\t\t\t\t\t\t\t<th></th>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</thead>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t{filtered.map((t) => (\n\t\t\t\t\t\t\t<tr\n\t\t\t\t\t\t\t\tkey={t.id}\n\t\t\t\t\t\t\t\tclassName=\"topic-row\"\n\t\t\t\t\t\t\t\tonClick={() => setDrillTopicId(t.id)}\n\t\t\t\t\t\t\t\tstyle={{ cursor: \"pointer\" }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<td className=\"topic-label\">{t.label}</td>\n\t\t\t\t\t\t\t\t<td className=\"topic-count\">{t.memoryCount}</td>\n\t\t\t\t\t\t\t\t<td className=\"topic-terms\">\n\t\t\t\t\t\t\t\t\t{t.termScore\n\t\t\t\t\t\t\t\t\t\t.slice(0, 8)\n\t\t\t\t\t\t\t\t\t\t.map((s) => s.term)\n\t\t\t\t\t\t\t\t\t\t.join(\", \")}\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t<button type=\"button\" className=\"mini-btn\">\n\t\t\t\t\t\t\t\t\t\tdrill\n\t\t\t\t\t\t\t\t\t</button>\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{filtered.length === 0 && (\n\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t<td colSpan={4} className=\"muted\">\n\t\t\t\t\t\t\t\t\tNo topics match “{query}”.\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</tbody>\n\t\t\t\t</table>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"],"names":["fmtTs","ms","TopicsTab","data","loading","error","useApi","useCallback","fetchTopics","query","setQuery","useState","drillTopicId","setDrillTopicId","drill","fetchTopicMemories","filtered","useMemo","q","t","s","jsxs","jsx","Fragment","e","a"],"mappings":"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"}
1
+ {"version":3,"file":"TopicsTab-D8FqyAbK.js","sources":["../../src/tabs/TopicsTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/tabs/TopicsTab.tsx — Auto-categorizing wiki (S51 + S52 polish).\n *\n * Fetches /api/topics and renders the k-means + TF-IDF topic clusters. S52 polish\n * adds: (1) a search box filtering topics by label / discriminative term, and\n * (2) a topic drill-down — click a topic to load its member memories\n * (/api/topics/:id/memories). Read-only; no write operations.\n */\n\nimport type React from \"react\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport { useApi } from \"../hooks/useApi\";\nimport { fetchTopics, fetchTopicMemories } from \"../api/client\";\nimport type { TopicsResponse, TopicMemoriesResponse } from \"@contracts\";\n\nfunction fmtTs(ms: number | null): string {\n\tif (!ms) return \"—\";\n\treturn new Date(ms).toLocaleString();\n}\n\nexport default function TopicsTab(): React.ReactElement {\n\tconst { data, loading, error } = useApi<TopicsResponse>(\n\t\tuseCallback(() => fetchTopics(), []),\n\t\t{ pollInterval: 30_000 },\n\t);\n\tconst [query, setQuery] = useState(\"\");\n\tconst [drillTopicId, setDrillTopicId] = useState<string | null>(null);\n\n\tconst drill = useApi<TopicMemoriesResponse>(\n\t\tuseCallback(\n\t\t\t() =>\n\t\t\t\tdrillTopicId ? fetchTopicMemories(drillTopicId) : Promise.reject(),\n\t\t\t[drillTopicId],\n\t\t),\n\t\t{ pollInterval: 0 },\n\t);\n\n\tconst filtered = useMemo(() => {\n\t\tif (!data) return [];\n\t\tconst q = query.trim().toLowerCase();\n\t\tif (!q) return data.topics;\n\t\treturn data.topics.filter(\n\t\t\t(t) =>\n\t\t\t\tt.label.toLowerCase().includes(q) ||\n\t\t\t\tt.termScore.some((s) => s.term.toLowerCase().includes(q)),\n\t\t);\n\t}, [data, query]);\n\n\tif (error && !data) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">Error loading topics: {error.message}</div>\n\t\t);\n\t}\n\tif (loading && !data) {\n\t\treturn <div className=\"tab-stub\">Loading topics…</div>;\n\t}\n\tif (!data) {\n\t\treturn <div className=\"tab-stub\">No topic data available.</div>;\n\t}\n\n\tif (data.totalTopics === 0) {\n\t\treturn (\n\t\t\t<div className=\"tab-stub\">\n\t\t\t\t<h3>Wiki</h3>\n\t\t\t\t<p>\n\t\t\t\t\tNo topics yet. Topics are auto-generated after every 3rd compaction\n\t\t\t\t\tfrom real memory embeddings (k-means + TF-IDF).\n\t\t\t\t</p>\n\t\t\t\t<p>Check back after a few more compaction cycles.</p>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"tab-content topics-tab\">\n\t\t\t<h3>Wiki</h3>\n\t\t\t<p className=\"subtitle\">\n\t\t\t\t{data.totalTopics} topic{data.totalTopics !== 1 ? \"s\" : \"\"} ·{\" \"}\n\t\t\t\t{data.totalAssigned} assigned memori\n\t\t\t\t{data.totalAssigned !== 1 ? \"es\" : \"y\"}\n\t\t\t\t{data.lastRebuildAt != null && (\n\t\t\t\t\t<> · last rebuild {new Date(data.lastRebuildAt).toLocaleString()}</>\n\t\t\t\t)}\n\t\t\t</p>\n\n\t\t\t<input\n\t\t\t\ttype=\"search\"\n\t\t\t\tclassName=\"topics-search\"\n\t\t\t\tplaceholder=\"Filter topics by label or term…\"\n\t\t\t\tvalue={query}\n\t\t\t\tonChange={(e) => setQuery(e.target.value)}\n\t\t\t/>\n\n\t\t\t{drillTopicId && (\n\t\t\t\t<section className=\"topic-drilldown\">\n\t\t\t\t\t<h4>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName=\"link-btn\"\n\t\t\t\t\t\t\tonClick={() => setDrillTopicId(null)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t← back\n\t\t\t\t\t\t</button>{\" \"}\n\t\t\t\t\t\tTopic <code>{drillTopicId}</code>\n\t\t\t\t\t\t{drill.data && <> · {drill.data.label}</>}\n\t\t\t\t\t\t{drill.data && <> · {drill.data.assignments.length} memories</>}\n\t\t\t\t\t</h4>\n\t\t\t\t\t{drill.error ? (\n\t\t\t\t\t\t<div className=\"tab-stub\">\n\t\t\t\t\t\t\tError: {(drill.error as Error).message}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : drill.loading && !drill.data ? (\n\t\t\t\t\t\t<div className=\"tab-stub\">Loading memories…</div>\n\t\t\t\t\t) : drill.data ? (\n\t\t\t\t\t\t<table className=\"data-table\">\n\t\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t<th>Memory id</th>\n\t\t\t\t\t\t\t\t\t<th>Confidence</th>\n\t\t\t\t\t\t\t\t\t<th>Assigned</th>\n\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t{drill.data.assignments.map((a) => (\n\t\t\t\t\t\t\t\t\t<tr key={a.memoryId}>\n\t\t\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t\t\t<code>{a.memoryId}</code>\n\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t\t\t{a.confidence != null ? a.confidence.toFixed(2) : \"—\"}\n\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t<td>{fmtTs(a.assignedAt)}</td>\n\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t</table>\n\t\t\t\t\t) : null}\n\t\t\t\t</section>\n\t\t\t)}\n\n\t\t\t{!drillTopicId && (\n\t\t\t\t<table className=\"data-table\">\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<th>Label</th>\n\t\t\t\t\t\t\t<th>Memories</th>\n\t\t\t\t\t\t\t<th>Top Terms</th>\n\t\t\t\t\t\t\t<th></th>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</thead>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t{filtered.map((t) => (\n\t\t\t\t\t\t\t<tr\n\t\t\t\t\t\t\t\tkey={t.id}\n\t\t\t\t\t\t\t\tclassName=\"topic-row\"\n\t\t\t\t\t\t\t\tonClick={() => setDrillTopicId(t.id)}\n\t\t\t\t\t\t\t\tstyle={{ cursor: \"pointer\" }}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<td className=\"topic-label\">{t.label}</td>\n\t\t\t\t\t\t\t\t<td className=\"topic-count\">{t.memoryCount}</td>\n\t\t\t\t\t\t\t\t<td className=\"topic-terms\">\n\t\t\t\t\t\t\t\t\t{t.termScore\n\t\t\t\t\t\t\t\t\t\t.slice(0, 8)\n\t\t\t\t\t\t\t\t\t\t.map((s) => s.term)\n\t\t\t\t\t\t\t\t\t\t.join(\", \")}\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t<button type=\"button\" className=\"mini-btn\">\n\t\t\t\t\t\t\t\t\t\tdrill\n\t\t\t\t\t\t\t\t\t</button>\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{filtered.length === 0 && (\n\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t<td colSpan={4} className=\"muted\">\n\t\t\t\t\t\t\t\t\tNo topics match “{query}”.\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</tbody>\n\t\t\t\t</table>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"],"names":["fmtTs","ms","TopicsTab","data","loading","error","useApi","useCallback","fetchTopics","query","setQuery","useState","drillTopicId","setDrillTopicId","drill","fetchTopicMemories","filtered","useMemo","q","t","s","jsxs","jsx","Fragment","e","a"],"mappings":"oEAeA,SAASA,EAAMC,EAA2B,CACzC,OAAKA,EACE,IAAI,KAAKA,CAAE,EAAE,eAAA,EADJ,GAEjB,CAEA,SAAwBC,GAAgC,CACvD,KAAM,CAAE,KAAAC,EAAM,QAAAC,EAAS,MAAAC,CAAA,EAAUC,EAChCC,cAAY,IAAMC,EAAA,EAAe,EAAE,EACnC,CAAE,aAAc,GAAA,CAAO,EAElB,CAACC,EAAOC,CAAQ,EAAIC,EAAAA,SAAS,EAAE,EAC/B,CAACC,EAAcC,CAAe,EAAIF,EAAAA,SAAwB,IAAI,EAE9DG,EAAQR,EACbC,EAAAA,YACC,IACCK,EAAeG,EAAmBH,CAAY,EAAI,QAAQ,OAAA,EAC3D,CAACA,CAAY,CAAA,EAEd,CAAE,aAAc,CAAA,CAAE,EAGbI,EAAWC,EAAAA,QAAQ,IAAM,CAC9B,GAAI,CAACd,EAAM,MAAO,CAAA,EAClB,MAAMe,EAAIT,EAAM,KAAA,EAAO,YAAA,EACvB,OAAKS,EACEf,EAAK,OAAO,OACjBgB,GACAA,EAAE,MAAM,cAAc,SAASD,CAAC,GAChCC,EAAE,UAAU,KAAMC,GAAMA,EAAE,KAAK,cAAc,SAASF,CAAC,CAAC,CAAA,EAJ3Cf,EAAK,MAMrB,EAAG,CAACA,EAAMM,CAAK,CAAC,EAEhB,OAAIJ,GAAS,CAACF,EAEZkB,EAAAA,KAAC,MAAA,CAAI,UAAU,WAAW,SAAA,CAAA,yBAAuBhB,EAAM,OAAA,EAAQ,EAG7DD,GAAW,CAACD,EACRmB,EAAAA,IAAC,MAAA,CAAI,UAAU,WAAW,SAAA,kBAAe,EAE5CnB,EAIDA,EAAK,cAAgB,EAEvBkB,EAAAA,KAAC,MAAA,CAAI,UAAU,WACd,SAAA,CAAAC,EAAAA,IAAC,MAAG,SAAA,MAAA,CAAI,EACRA,EAAAA,IAAC,KAAE,SAAA,qHAAA,CAGH,EACAA,EAAAA,IAAC,KAAE,SAAA,gDAAA,CAA8C,CAAA,EAClD,EAKDD,EAAAA,KAAC,MAAA,CAAI,UAAU,yBACd,SAAA,CAAAC,EAAAA,IAAC,MAAG,SAAA,MAAA,CAAI,EACRD,EAAAA,KAAC,IAAA,CAAE,UAAU,WACX,SAAA,CAAAlB,EAAK,YAAY,SAAOA,EAAK,cAAgB,EAAI,IAAM,GAAG,KAAG,IAC7DA,EAAK,cAAc,mBACnBA,EAAK,gBAAkB,EAAI,KAAO,IAClCA,EAAK,eAAiB,MACtBkB,EAAAA,KAAAE,EAAAA,SAAA,CAAE,SAAA,CAAA,mBAAiB,IAAI,KAAKpB,EAAK,aAAa,EAAE,eAAA,CAAe,CAAA,CAAE,CAAA,EAEnE,EAEAmB,EAAAA,IAAC,QAAA,CACA,KAAK,SACL,UAAU,gBACV,YAAY,kCACZ,MAAOb,EACP,SAAWe,GAAMd,EAASc,EAAE,OAAO,KAAK,CAAA,CAAA,EAGxCZ,GACAS,EAAAA,KAAC,UAAA,CAAQ,UAAU,kBAClB,SAAA,CAAAA,OAAC,KAAA,CACA,SAAA,CAAAC,EAAAA,IAAC,SAAA,CACA,KAAK,SACL,UAAU,WACV,QAAS,IAAMT,EAAgB,IAAI,EACnC,SAAA,QAAA,CAAA,EAES,IAAI,SACRS,EAAAA,IAAC,QAAM,SAAAV,CAAA,CAAa,EACzBE,EAAM,MAAQO,EAAAA,KAAAE,EAAAA,SAAA,CAAE,SAAA,CAAA,MAAIT,EAAM,KAAK,KAAA,EAAM,EACrCA,EAAM,MAAQO,EAAAA,KAAAE,EAAAA,SAAA,CAAE,SAAA,CAAA,MAAIT,EAAM,KAAK,YAAY,OAAO,WAAA,CAAA,CAAS,CAAA,EAC7D,EACCA,EAAM,MACNO,OAAC,MAAA,CAAI,UAAU,WAAW,SAAA,CAAA,UAChBP,EAAM,MAAgB,OAAA,EAChC,EACGA,EAAM,SAAW,CAACA,EAAM,KAC3BQ,EAAAA,IAAC,MAAA,CAAI,UAAU,WAAW,6BAAiB,EACxCR,EAAM,KACTO,OAAC,QAAA,CAAM,UAAU,aAChB,SAAA,CAAAC,EAAAA,IAAC,QAAA,CACA,gBAAC,KAAA,CACA,SAAA,CAAAA,EAAAA,IAAC,MAAG,SAAA,WAAA,CAAS,EACbA,EAAAA,IAAC,MAAG,SAAA,YAAA,CAAU,EACdA,EAAAA,IAAC,MAAG,SAAA,UAAA,CAAQ,CAAA,CAAA,CACb,CAAA,CACD,EACAA,EAAAA,IAAC,SACC,SAAAR,EAAM,KAAK,YAAY,IAAKW,GAC5BJ,EAAAA,KAAC,KAAA,CACA,SAAA,CAAAC,EAAAA,IAAC,KAAA,CACA,SAAAA,MAAC,OAAA,CAAM,SAAAG,EAAE,SAAS,EACnB,EACAH,EAAAA,IAAC,KAAA,CACC,SAAAG,EAAE,YAAc,KAAOA,EAAE,WAAW,QAAQ,CAAC,EAAI,GAAA,CACnD,EACAH,EAAAA,IAAC,KAAA,CAAI,SAAAtB,EAAMyB,EAAE,UAAU,CAAA,CAAE,CAAA,GAPjBA,EAAE,QAQX,CACA,CAAA,CACF,CAAA,CAAA,CACD,EACG,IAAA,EACL,EAGA,CAACb,GACDS,EAAAA,KAAC,QAAA,CAAM,UAAU,aAChB,SAAA,CAAAC,EAAAA,IAAC,QAAA,CACA,gBAAC,KAAA,CACA,SAAA,CAAAA,EAAAA,IAAC,MAAG,SAAA,OAAA,CAAK,EACTA,EAAAA,IAAC,MAAG,SAAA,UAAA,CAAQ,EACZA,EAAAA,IAAC,MAAG,SAAA,WAAA,CAAS,QACZ,KAAA,CAAA,CAAG,CAAA,CAAA,CACL,CAAA,CACD,SACC,QAAA,CACC,SAAA,CAAAN,EAAS,IAAK,GACdK,EAAAA,KAAC,KAAA,CAEA,UAAU,YACV,QAAS,IAAMR,EAAgB,EAAE,EAAE,EACnC,MAAO,CAAE,OAAQ,SAAA,EAEjB,SAAA,CAAAS,EAAAA,IAAC,KAAA,CAAG,UAAU,cAAe,SAAA,EAAE,MAAM,EACrCA,EAAAA,IAAC,KAAA,CAAG,UAAU,cAAe,WAAE,YAAY,QAC1C,KAAA,CAAG,UAAU,cACZ,SAAA,EAAE,UACD,MAAM,EAAG,CAAC,EACV,IAAKF,GAAMA,EAAE,IAAI,EACjB,KAAK,IAAI,EACZ,EACAE,EAAAA,IAAC,MACA,SAAAA,EAAAA,IAAC,SAAA,CAAO,KAAK,SAAS,UAAU,WAAW,SAAA,OAAA,CAE3C,CAAA,CACD,CAAA,CAAA,EAjBK,EAAE,EAAA,CAmBR,EACAN,EAAS,SAAW,GACpBM,EAAAA,IAAC,KAAA,CACA,gBAAC,KAAA,CAAG,QAAS,EAAG,UAAU,QAAQ,SAAA,CAAA,oBACfb,EAAM,IAAA,CAAA,CACzB,CAAA,CACD,CAAA,CAAA,CAEF,CAAA,CAAA,CACD,CAAA,EAEF,EA9HOa,EAAAA,IAAC,MAAA,CAAI,UAAU,WAAW,SAAA,2BAAwB,CAgI3D"}
@@ -1,2 +1,2 @@
1
- import{u as f,r,x as C,y as w,z as I,A as T,B as $,j as e}from"./index-mOlljTFI.js";function j(n){return n?new Date(n).toLocaleString():"—"}function E(n){return n==="green"?"band band-green":n==="yellow"?"band band-yellow":n==="red"?"band band-red":"band"}function L(n){return n==="checkpoint"?"ckpt":n==="cluster_summary"?"raptor":"mem"}function S(){const{data:n,loading:i,error:d}=f(r.useCallback(()=>C(),[]),{pollInterval:1e4}),{data:c}=f(r.useCallback(()=>w(),[]),{pollInterval:5e3}),[s,l]=r.useState(null),[m,x]=r.useState(null),[v,p]=r.useState(!1),[N,u]=r.useState(null),[b,o]=r.useState(null),g=r.useCallback(async t=>{if(s===t){l(null),x(null);return}l(t),p(!0),x(null);try{const a=await I(t);x(a)}finally{p(!1)}},[s]),y=r.useCallback(async(t,a)=>{u(`fork:${t}:${a}`),o(null);try{const h=await T(t,a);o(`Forked → ${h.childConversationId} (${h.recalledCount} recalled)`)}catch(h){o(`Fork failed: ${h.message}`)}finally{u(null)}},[]),k=r.useCallback(async(t,a)=>{u(`rewind:${t}:${a}`),o(null);try{await $(t,a),o(`Rewind intent queued for turn ${a}`)}catch(h){o(`Rewind failed: ${h.message}`)}finally{u(null)}},[]);return d&&!n?e.jsxs("div",{className:"tab-stub",children:["Error loading turns: ",d.message]}):i&&!n?e.jsx("div",{className:"tab-stub",children:"Loading turns…"}):!n||n.conversations.length===0?e.jsxs("div",{className:"tab-stub",children:[e.jsx("h3",{children:"Turn-by-turn memory"}),e.jsxs("p",{children:["No turns recorded yet. Per-turn tracking starts when"," ",e.jsx("code",{children:"MEGACOMPACT_TURNS_DB=1"})," and the session runs through a compaction. Each turn records its context metrics + the checkpoints recalled into it."]})]}):e.jsxs("div",{className:"turns-tab",children:[e.jsx("h3",{children:"Turn-by-turn memory tracking + recall"}),b&&e.jsx("div",{className:"turns-notice",children:b}),c&&c.intents.length>0&&e.jsxs("section",{className:"turns-intents",children:[e.jsxs("h4",{children:["Pending rewind intents (",c.intents.length,")"]}),e.jsx("ul",{children:c.intents.map(t=>e.jsxs("li",{children:[j(t.createdAt)," — rewind ",e.jsx("code",{children:t.conversationId})," to turn ",t.targetTurnIndex]},t.id))})]}),e.jsxs("section",{className:"turns-conv-list",children:[e.jsxs("h4",{children:["Conversations (",n.conversations.length,")"]}),e.jsxs("table",{className:"turns-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Conversation"}),e.jsx("th",{children:"Turns"}),e.jsx("th",{children:"Recall"}),e.jsx("th",{children:"Epochs"}),e.jsx("th",{children:"Avg ctx%"}),e.jsx("th",{children:"Last turn"}),e.jsx("th",{})]})}),e.jsx("tbody",{children:n.conversations.map(t=>e.jsx(R,{c:t,active:n.activeConversationId===t.conversationId,expanded:s===t.conversationId,onExpand:()=>g(t.conversationId)},t.conversationId))})]})]}),s&&e.jsxs("section",{className:"turns-detail",children:[e.jsxs("h4",{children:["Turns in ",e.jsx("code",{children:s})]}),v?e.jsx("div",{className:"tab-stub",children:"Loading turns…"}):m?e.jsx(A,{detail:m,busy:N,onFork:y,onRewind:k}):e.jsx("div",{className:"tab-stub",children:"No detail."})]})]})}function R({c:n,active:i,expanded:d,onExpand:c}){return e.jsx(e.Fragment,{children:e.jsxs("tr",{className:i?"turns-row active":"turns-row",onClick:c,style:{cursor:"pointer"},children:[e.jsxs("td",{children:[d?"▾":"▸"," ",e.jsx("code",{children:n.conversationId}),i&&e.jsx("span",{className:"pill",children:"active"})]}),e.jsx("td",{children:n.turnCount}),e.jsx("td",{children:n.totalRecall}),e.jsx("td",{children:n.epochCount}),e.jsxs("td",{children:[n.avgCtxPercent.toFixed(0),"%"]}),e.jsx("td",{children:j(n.lastTurnAt)}),e.jsx("td",{})]})})}function A({detail:n,busy:i,onFork:d,onRewind:c}){return e.jsxs("table",{className:"turns-detail-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"#"}),e.jsx("th",{children:"Role"}),e.jsx("th",{children:"Ctx"}),e.jsx("th",{children:"Band"}),e.jsx("th",{children:"Epoch"}),e.jsx("th",{children:"Recalled checkpoints (memory recall)"}),e.jsx("th",{children:"Ended"}),e.jsx("th",{children:"Actions"})]})}),e.jsx("tbody",{children:n.turns.map(s=>e.jsxs("tr",{children:[e.jsx("td",{children:s.turnIndex}),e.jsx("td",{children:s.role}),e.jsxs("td",{children:[s.ctxTokens??"—",s.ctxPercent!=null&&e.jsxs("span",{className:"muted",children:[" ","· ",s.ctxPercent.toFixed(0),"%"]})]}),e.jsx("td",{children:e.jsx("span",{className:E(s.pressureBand),children:s.pressureBand??"—"})}),e.jsx("td",{children:s.epochId?e.jsx("code",{children:s.epochId.slice(0,8)}):"—"}),e.jsx("td",{className:"recall-cell",children:s.recall.length===0?e.jsx("span",{className:"muted",children:"—"}):e.jsx("ul",{className:"recall-list",children:s.recall.map(l=>e.jsxs("li",{children:[e.jsx("code",{children:l.checkpointId.slice(0,12)})," ",e.jsxs("span",{className:"muted",children:[L(l.source)," · ",l.score.toFixed(2),l.raptorLevel!=null?` · L${l.raptorLevel}`:""]})]},l.checkpointId))})}),e.jsx("td",{children:j(s.endedAt)}),e.jsxs("td",{className:"actions-cell",children:[e.jsx("button",{type:"button",className:"mini-btn",disabled:i!==null,onClick:()=>d(s.conversationId,s.turnIndex),children:"fork"}),e.jsx("button",{type:"button",className:"mini-btn",disabled:i!==null,onClick:()=>c(s.conversationId,s.turnIndex),children:"rewind"})]})]},`${s.conversationId}:${s.turnIndex}`))})]})}export{S as default};
2
- //# sourceMappingURL=TurnsTab-BK0I7hKr.js.map
1
+ import{u as f,r,z as C,A as w,B as I,C as T,D as $,j as e}from"./index-BEj1Zahy.js";function j(n){return n?new Date(n).toLocaleString():"—"}function E(n){return n==="green"?"band band-green":n==="yellow"?"band band-yellow":n==="red"?"band band-red":"band"}function L(n){return n==="checkpoint"?"ckpt":n==="cluster_summary"?"raptor":"mem"}function S(){const{data:n,loading:i,error:d}=f(r.useCallback(()=>C(),[]),{pollInterval:1e4}),{data:c}=f(r.useCallback(()=>w(),[]),{pollInterval:5e3}),[s,l]=r.useState(null),[m,x]=r.useState(null),[v,p]=r.useState(!1),[N,u]=r.useState(null),[b,o]=r.useState(null),g=r.useCallback(async t=>{if(s===t){l(null),x(null);return}l(t),p(!0),x(null);try{const a=await I(t);x(a)}finally{p(!1)}},[s]),y=r.useCallback(async(t,a)=>{u(`fork:${t}:${a}`),o(null);try{const h=await T(t,a);o(`Forked → ${h.childConversationId} (${h.recalledCount} recalled)`)}catch(h){o(`Fork failed: ${h.message}`)}finally{u(null)}},[]),k=r.useCallback(async(t,a)=>{u(`rewind:${t}:${a}`),o(null);try{await $(t,a),o(`Rewind intent queued for turn ${a}`)}catch(h){o(`Rewind failed: ${h.message}`)}finally{u(null)}},[]);return d&&!n?e.jsxs("div",{className:"tab-stub",children:["Error loading turns: ",d.message]}):i&&!n?e.jsx("div",{className:"tab-stub",children:"Loading turns…"}):!n||n.conversations.length===0?e.jsxs("div",{className:"tab-stub",children:[e.jsx("h3",{children:"Turn-by-turn memory"}),e.jsxs("p",{children:["No turns recorded yet. Per-turn tracking starts when"," ",e.jsx("code",{children:"MEGACOMPACT_TURNS_DB=1"})," and the session runs through a compaction. Each turn records its context metrics + the checkpoints recalled into it."]})]}):e.jsxs("div",{className:"turns-tab",children:[e.jsx("h3",{children:"Turn-by-turn memory tracking + recall"}),b&&e.jsx("div",{className:"turns-notice",children:b}),c&&c.intents.length>0&&e.jsxs("section",{className:"turns-intents",children:[e.jsxs("h4",{children:["Pending rewind intents (",c.intents.length,")"]}),e.jsx("ul",{children:c.intents.map(t=>e.jsxs("li",{children:[j(t.createdAt)," — rewind ",e.jsx("code",{children:t.conversationId})," to turn ",t.targetTurnIndex]},t.id))})]}),e.jsxs("section",{className:"turns-conv-list",children:[e.jsxs("h4",{children:["Conversations (",n.conversations.length,")"]}),e.jsxs("table",{className:"turns-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Conversation"}),e.jsx("th",{children:"Turns"}),e.jsx("th",{children:"Recall"}),e.jsx("th",{children:"Epochs"}),e.jsx("th",{children:"Avg ctx%"}),e.jsx("th",{children:"Last turn"}),e.jsx("th",{})]})}),e.jsx("tbody",{children:n.conversations.map(t=>e.jsx(R,{c:t,active:n.activeConversationId===t.conversationId,expanded:s===t.conversationId,onExpand:()=>g(t.conversationId)},t.conversationId))})]})]}),s&&e.jsxs("section",{className:"turns-detail",children:[e.jsxs("h4",{children:["Turns in ",e.jsx("code",{children:s})]}),v?e.jsx("div",{className:"tab-stub",children:"Loading turns…"}):m?e.jsx(A,{detail:m,busy:N,onFork:y,onRewind:k}):e.jsx("div",{className:"tab-stub",children:"No detail."})]})]})}function R({c:n,active:i,expanded:d,onExpand:c}){return e.jsx(e.Fragment,{children:e.jsxs("tr",{className:i?"turns-row active":"turns-row",onClick:c,style:{cursor:"pointer"},children:[e.jsxs("td",{children:[d?"▾":"▸"," ",e.jsx("code",{children:n.conversationId}),i&&e.jsx("span",{className:"pill",children:"active"})]}),e.jsx("td",{children:n.turnCount}),e.jsx("td",{children:n.totalRecall}),e.jsx("td",{children:n.epochCount}),e.jsxs("td",{children:[n.avgCtxPercent.toFixed(0),"%"]}),e.jsx("td",{children:j(n.lastTurnAt)}),e.jsx("td",{})]})})}function A({detail:n,busy:i,onFork:d,onRewind:c}){return e.jsxs("table",{className:"turns-detail-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"#"}),e.jsx("th",{children:"Role"}),e.jsx("th",{children:"Ctx"}),e.jsx("th",{children:"Band"}),e.jsx("th",{children:"Epoch"}),e.jsx("th",{children:"Recalled checkpoints (memory recall)"}),e.jsx("th",{children:"Ended"}),e.jsx("th",{children:"Actions"})]})}),e.jsx("tbody",{children:n.turns.map(s=>e.jsxs("tr",{children:[e.jsx("td",{children:s.turnIndex}),e.jsx("td",{children:s.role}),e.jsxs("td",{children:[s.ctxTokens??"—",s.ctxPercent!=null&&e.jsxs("span",{className:"muted",children:[" ","· ",s.ctxPercent.toFixed(0),"%"]})]}),e.jsx("td",{children:e.jsx("span",{className:E(s.pressureBand),children:s.pressureBand??"—"})}),e.jsx("td",{children:s.epochId?e.jsx("code",{children:s.epochId.slice(0,8)}):"—"}),e.jsx("td",{className:"recall-cell",children:s.recall.length===0?e.jsx("span",{className:"muted",children:"—"}):e.jsx("ul",{className:"recall-list",children:s.recall.map(l=>e.jsxs("li",{children:[e.jsx("code",{children:l.checkpointId.slice(0,12)})," ",e.jsxs("span",{className:"muted",children:[L(l.source)," · ",l.score.toFixed(2),l.raptorLevel!=null?` · L${l.raptorLevel}`:""]})]},l.checkpointId))})}),e.jsx("td",{children:j(s.endedAt)}),e.jsxs("td",{className:"actions-cell",children:[e.jsx("button",{type:"button",className:"mini-btn",disabled:i!==null,onClick:()=>d(s.conversationId,s.turnIndex),children:"fork"}),e.jsx("button",{type:"button",className:"mini-btn",disabled:i!==null,onClick:()=>c(s.conversationId,s.turnIndex),children:"rewind"})]})]},`${s.conversationId}:${s.turnIndex}`))})]})}export{S as default};
2
+ //# sourceMappingURL=TurnsTab-ju-nXDys.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TurnsTab-BK0I7hKr.js","sources":["../../src/tabs/TurnsTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/tabs/TurnsTab.tsx — Turn-by-turn memory tracking + recall (S52).\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\";\n\nfunction fmtTs(ms: number): string {\n\tif (!ms) return \"—\";\n\treturn new Date(ms).toLocaleString();\n}\n\nfunction bandClass(band: TurnRow[\"pressureBand\"]): string {\n\tif (band === \"green\") return \"band band-green\";\n\tif (band === \"yellow\") return \"band band-yellow\";\n\tif (band === \"red\") return \"band band-red\";\n\treturn \"band\";\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 default function TurnsTab(): 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=\"turns-tab\">\n\t\t\t<h3>Turn-by-turn memory tracking + recall</h3>\n\t\t\t{notice && <div className=\"turns-notice\">{notice}</div>}\n\n\t\t\t{intents && intents.intents.length > 0 && (\n\t\t\t\t<section className=\"turns-intents\">\n\t\t\t\t\t<h4>Pending rewind intents ({intents.intents.length})</h4>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t{intents.intents.map((i) => (\n\t\t\t\t\t\t\t<li key={i.id}>\n\t\t\t\t\t\t\t\t{fmtTs(i.createdAt)} — rewind <code>{i.conversationId}</code> to\n\t\t\t\t\t\t\t\tturn {i.targetTurnIndex}\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</ul>\n\t\t\t\t</section>\n\t\t\t)}\n\n\t\t\t<section className=\"turns-conv-list\">\n\t\t\t\t<h4>Conversations ({turns.conversations.length})</h4>\n\t\t\t\t<table className=\"turns-table\">\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<th>Conversation</th>\n\t\t\t\t\t\t\t<th>Turns</th>\n\t\t\t\t\t\t\t<th>Recall</th>\n\t\t\t\t\t\t\t<th>Epochs</th>\n\t\t\t\t\t\t\t<th>Avg ctx%</th>\n\t\t\t\t\t\t\t<th>Last turn</th>\n\t\t\t\t\t\t\t<th></th>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</thead>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t{turns.conversations.map((c: ConversationSummary) => (\n\t\t\t\t\t\t\t<ConversationRow\n\t\t\t\t\t\t\t\tkey={c.conversationId}\n\t\t\t\t\t\t\t\tc={c}\n\t\t\t\t\t\t\t\tactive={turns.activeConversationId === c.conversationId}\n\t\t\t\t\t\t\t\texpanded={expanded === c.conversationId}\n\t\t\t\t\t\t\t\tonExpand={() => expand(c.conversationId)}\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</section>\n\n\t\t\t{expanded && (\n\t\t\t\t<section className=\"turns-detail\">\n\t\t\t\t\t<h4>\n\t\t\t\t\t\tTurns in <code>{expanded}</code>\n\t\t\t\t\t</h4>\n\t\t\t\t\t{detailLoading ? (\n\t\t\t\t\t\t<div className=\"tab-stub\">Loading turns…</div>\n\t\t\t\t\t) : detail ? (\n\t\t\t\t\t\t<TurnDetail\n\t\t\t\t\t\t\tdetail={detail}\n\t\t\t\t\t\t\tbusy={busy}\n\t\t\t\t\t\t\tonFork={onFork}\n\t\t\t\t\t\t\tonRewind={onRewind}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<div className=\"tab-stub\">No detail.</div>\n\t\t\t\t\t)}\n\t\t\t\t</section>\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={active ? \"turns-row active\" : \"turns-row\"}\n\t\t\t\tonClick={onExpand}\n\t\t\t\tstyle={{ cursor: \"pointer\" }}\n\t\t\t>\n\t\t\t\t<td>\n\t\t\t\t\t{expanded ? \"▾\" : \"▸\"} <code>{c.conversationId}</code>\n\t\t\t\t\t{active && <span className=\"pill\">active</span>}\n\t\t\t\t</td>\n\t\t\t\t<td>{c.turnCount}</td>\n\t\t\t\t<td>{c.totalRecall}</td>\n\t\t\t\t<td>{c.epochCount}</td>\n\t\t\t\t<td>{c.avgCtxPercent.toFixed(0)}%</td>\n\t\t\t\t<td>{fmtTs(c.lastTurnAt)}</td>\n\t\t\t\t<td />\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=\"turns-detail-table\">\n\t\t\t<thead>\n\t\t\t\t<tr>\n\t\t\t\t\t<th>#</th>\n\t\t\t\t\t<th>Role</th>\n\t\t\t\t\t<th>Ctx</th>\n\t\t\t\t\t<th>Band</th>\n\t\t\t\t\t<th>Epoch</th>\n\t\t\t\t\t<th>Recalled checkpoints (memory recall)</th>\n\t\t\t\t\t<th>Ended</th>\n\t\t\t\t\t<th>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 key={`${t.conversationId}:${t.turnIndex}`}>\n\t\t\t\t\t\t<td>{t.turnIndex}</td>\n\t\t\t\t\t\t<td>{t.role}</td>\n\t\t\t\t\t\t<td>\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=\"muted\">\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>\n\t\t\t\t\t\t\t<span className={bandClass(t.pressureBand)}>\n\t\t\t\t\t\t\t\t{t.pressureBand ?? \"—\"}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>{t.epochId ? <code>{t.epochId.slice(0, 8)}</code> : \"—\"}</td>\n\t\t\t\t\t\t<td className=\"recall-cell\">\n\t\t\t\t\t\t\t{t.recall.length === 0 ? (\n\t\t\t\t\t\t\t\t<span className=\"muted\">—</span>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<ul className=\"recall-list\">\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=\"muted\">\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>{fmtTs(t.endedAt)}</td>\n\t\t\t\t\t\t<td className=\"actions-cell\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"mini-btn\"\n\t\t\t\t\t\t\t\tdisabled={busy !== null}\n\t\t\t\t\t\t\t\tonClick={() => onFork(t.conversationId, t.turnIndex)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tfork\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\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"mini-btn\"\n\t\t\t\t\t\t\t\tdisabled={busy !== null}\n\t\t\t\t\t\t\t\tonClick={() => onRewind(t.conversationId, t.turnIndex)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\trewind\n\t\t\t\t\t\t\t</button>\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"],"names":["fmtTs","ms","bandClass","band","sourceLabel","s","TurnsTab","turns","loading","error","useApi","useCallback","fetchTurns","intents","fetchTurnIntents","expanded","setExpanded","useState","detail","setDetail","detailLoading","setDetailLoading","busy","setBusy","notice","setNotice","expand","conversationId","d","fetchConversationTurns","onFork","turnIndex","out","postFork","e","onRewind","postTurnIntent","jsxs","jsx","i","c","ConversationRow","TurnDetail","active","onExpand","Fragment","t","r"],"mappings":"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"}
1
+ {"version":3,"file":"TurnsTab-ju-nXDys.js","sources":["../../src/tabs/TurnsTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/tabs/TurnsTab.tsx — Turn-by-turn memory tracking + recall (S52).\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\";\n\nfunction fmtTs(ms: number): string {\n\tif (!ms) return \"—\";\n\treturn new Date(ms).toLocaleString();\n}\n\nfunction bandClass(band: TurnRow[\"pressureBand\"]): string {\n\tif (band === \"green\") return \"band band-green\";\n\tif (band === \"yellow\") return \"band band-yellow\";\n\tif (band === \"red\") return \"band band-red\";\n\treturn \"band\";\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 default function TurnsTab(): 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=\"turns-tab\">\n\t\t\t<h3>Turn-by-turn memory tracking + recall</h3>\n\t\t\t{notice && <div className=\"turns-notice\">{notice}</div>}\n\n\t\t\t{intents && intents.intents.length > 0 && (\n\t\t\t\t<section className=\"turns-intents\">\n\t\t\t\t\t<h4>Pending rewind intents ({intents.intents.length})</h4>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t{intents.intents.map((i) => (\n\t\t\t\t\t\t\t<li key={i.id}>\n\t\t\t\t\t\t\t\t{fmtTs(i.createdAt)} — rewind <code>{i.conversationId}</code> to\n\t\t\t\t\t\t\t\tturn {i.targetTurnIndex}\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</ul>\n\t\t\t\t</section>\n\t\t\t)}\n\n\t\t\t<section className=\"turns-conv-list\">\n\t\t\t\t<h4>Conversations ({turns.conversations.length})</h4>\n\t\t\t\t<table className=\"turns-table\">\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<th>Conversation</th>\n\t\t\t\t\t\t\t<th>Turns</th>\n\t\t\t\t\t\t\t<th>Recall</th>\n\t\t\t\t\t\t\t<th>Epochs</th>\n\t\t\t\t\t\t\t<th>Avg ctx%</th>\n\t\t\t\t\t\t\t<th>Last turn</th>\n\t\t\t\t\t\t\t<th></th>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</thead>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t{turns.conversations.map((c: ConversationSummary) => (\n\t\t\t\t\t\t\t<ConversationRow\n\t\t\t\t\t\t\t\tkey={c.conversationId}\n\t\t\t\t\t\t\t\tc={c}\n\t\t\t\t\t\t\t\tactive={turns.activeConversationId === c.conversationId}\n\t\t\t\t\t\t\t\texpanded={expanded === c.conversationId}\n\t\t\t\t\t\t\t\tonExpand={() => expand(c.conversationId)}\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</section>\n\n\t\t\t{expanded && (\n\t\t\t\t<section className=\"turns-detail\">\n\t\t\t\t\t<h4>\n\t\t\t\t\t\tTurns in <code>{expanded}</code>\n\t\t\t\t\t</h4>\n\t\t\t\t\t{detailLoading ? (\n\t\t\t\t\t\t<div className=\"tab-stub\">Loading turns…</div>\n\t\t\t\t\t) : detail ? (\n\t\t\t\t\t\t<TurnDetail\n\t\t\t\t\t\t\tdetail={detail}\n\t\t\t\t\t\t\tbusy={busy}\n\t\t\t\t\t\t\tonFork={onFork}\n\t\t\t\t\t\t\tonRewind={onRewind}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<div className=\"tab-stub\">No detail.</div>\n\t\t\t\t\t)}\n\t\t\t\t</section>\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={active ? \"turns-row active\" : \"turns-row\"}\n\t\t\t\tonClick={onExpand}\n\t\t\t\tstyle={{ cursor: \"pointer\" }}\n\t\t\t>\n\t\t\t\t<td>\n\t\t\t\t\t{expanded ? \"▾\" : \"▸\"} <code>{c.conversationId}</code>\n\t\t\t\t\t{active && <span className=\"pill\">active</span>}\n\t\t\t\t</td>\n\t\t\t\t<td>{c.turnCount}</td>\n\t\t\t\t<td>{c.totalRecall}</td>\n\t\t\t\t<td>{c.epochCount}</td>\n\t\t\t\t<td>{c.avgCtxPercent.toFixed(0)}%</td>\n\t\t\t\t<td>{fmtTs(c.lastTurnAt)}</td>\n\t\t\t\t<td />\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=\"turns-detail-table\">\n\t\t\t<thead>\n\t\t\t\t<tr>\n\t\t\t\t\t<th>#</th>\n\t\t\t\t\t<th>Role</th>\n\t\t\t\t\t<th>Ctx</th>\n\t\t\t\t\t<th>Band</th>\n\t\t\t\t\t<th>Epoch</th>\n\t\t\t\t\t<th>Recalled checkpoints (memory recall)</th>\n\t\t\t\t\t<th>Ended</th>\n\t\t\t\t\t<th>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 key={`${t.conversationId}:${t.turnIndex}`}>\n\t\t\t\t\t\t<td>{t.turnIndex}</td>\n\t\t\t\t\t\t<td>{t.role}</td>\n\t\t\t\t\t\t<td>\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=\"muted\">\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>\n\t\t\t\t\t\t\t<span className={bandClass(t.pressureBand)}>\n\t\t\t\t\t\t\t\t{t.pressureBand ?? \"—\"}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>{t.epochId ? <code>{t.epochId.slice(0, 8)}</code> : \"—\"}</td>\n\t\t\t\t\t\t<td className=\"recall-cell\">\n\t\t\t\t\t\t\t{t.recall.length === 0 ? (\n\t\t\t\t\t\t\t\t<span className=\"muted\">—</span>\n\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t<ul className=\"recall-list\">\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=\"muted\">\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>{fmtTs(t.endedAt)}</td>\n\t\t\t\t\t\t<td className=\"actions-cell\">\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"mini-btn\"\n\t\t\t\t\t\t\t\tdisabled={busy !== null}\n\t\t\t\t\t\t\t\tonClick={() => onFork(t.conversationId, t.turnIndex)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tfork\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\ttype=\"button\"\n\t\t\t\t\t\t\t\tclassName=\"mini-btn\"\n\t\t\t\t\t\t\t\tdisabled={busy !== null}\n\t\t\t\t\t\t\t\tonClick={() => onRewind(t.conversationId, t.turnIndex)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\trewind\n\t\t\t\t\t\t\t</button>\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"],"names":["fmtTs","ms","bandClass","band","sourceLabel","s","TurnsTab","turns","loading","error","useApi","useCallback","fetchTurns","intents","fetchTurnIntents","expanded","setExpanded","useState","detail","setDetail","detailLoading","setDetailLoading","busy","setBusy","notice","setNotice","expand","conversationId","d","fetchConversationTurns","onFork","turnIndex","out","postFork","e","onRewind","postTurnIntent","jsxs","jsx","i","c","ConversationRow","TurnDetail","active","onExpand","Fragment","t","r"],"mappings":"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"}