pi-mega-compact 0.20.76 → 0.20.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/config/vector-cortex-vc9b.js +4 -3
  2. package/dist/extensions/dashboard-server/api-contracts/endpoints/registry-ext.js +1 -1
  3. package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +1 -1
  4. package/dist/extensions/dashboard-server/routes-setup-cortex-actions.js +6 -5
  5. package/dist/extensions/dashboard-server/setup-cortex-actions-vc2.js +334 -0
  6. package/dist/extensions/dashboard-server/setup-cortex-actions.js +18 -69
  7. package/dist/src/config/vector-cortex-vc9b.js +4 -3
  8. package/extensions/dashboard-client/dist/assets/{AdminTab-B8JqsA41.js → AdminTab-BsA8-_bX.js} +2 -2
  9. package/extensions/dashboard-client/dist/assets/{AdminTab-B8JqsA41.js.map → AdminTab-BsA8-_bX.js.map} +1 -1
  10. package/extensions/dashboard-client/dist/assets/{AreaChart-CeaexvWO.js → AreaChart-BRHEfWhc.js} +2 -2
  11. package/extensions/dashboard-client/dist/assets/{AreaChart-CeaexvWO.js.map → AreaChart-BRHEfWhc.js.map} +1 -1
  12. package/extensions/dashboard-client/dist/assets/{BarChart-Bhyviy7_.js → BarChart-C-M0LaFc.js} +2 -2
  13. package/extensions/dashboard-client/dist/assets/{BarChart-Bhyviy7_.js.map → BarChart-C-M0LaFc.js.map} +1 -1
  14. package/extensions/dashboard-client/dist/assets/{CacheTab-C6bFdEHq.js → CacheTab-Cj3n59U3.js} +2 -2
  15. package/extensions/dashboard-client/dist/assets/{CacheTab-C6bFdEHq.js.map → CacheTab-Cj3n59U3.js.map} +1 -1
  16. package/extensions/dashboard-client/dist/assets/{ConfigTab-CbsdI5yj.js → ConfigTab-C016XTNC.js} +2 -2
  17. package/extensions/dashboard-client/dist/assets/{ConfigTab-CbsdI5yj.js.map → ConfigTab-C016XTNC.js.map} +1 -1
  18. package/extensions/dashboard-client/dist/assets/{EventsTab-kvB5Znx2.js → EventsTab-DE29fuqe.js} +2 -2
  19. package/extensions/dashboard-client/dist/assets/{EventsTab-kvB5Znx2.js.map → EventsTab-DE29fuqe.js.map} +1 -1
  20. package/extensions/dashboard-client/dist/assets/{HealthTab-DqEUk5LW.js → HealthTab-D4eVI8ar.js} +2 -2
  21. package/extensions/dashboard-client/dist/assets/{HealthTab-DqEUk5LW.js.map → HealthTab-D4eVI8ar.js.map} +1 -1
  22. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-CS5HqDkY.js → MaintenanceTab-4fJ7M4S4.js} +2 -2
  23. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-CS5HqDkY.js.map → MaintenanceTab-4fJ7M4S4.js.map} +1 -1
  24. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-Oq-iqvUq.js → MemoryMapTab-CDbcK9e4.js} +2 -2
  25. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-Oq-iqvUq.js.map → MemoryMapTab-CDbcK9e4.js.map} +1 -1
  26. package/extensions/dashboard-client/dist/assets/{MetricsCards-36RVmtPj.js → MetricsCards-VUEcgGzo.js} +2 -2
  27. package/extensions/dashboard-client/dist/assets/{MetricsCards-36RVmtPj.js.map → MetricsCards-VUEcgGzo.js.map} +1 -1
  28. package/extensions/dashboard-client/dist/assets/MetricsTab-CKqJ0Zl-.js +2 -0
  29. package/extensions/dashboard-client/dist/assets/{MetricsTab-Clkcniuo.js.map → MetricsTab-CKqJ0Zl-.js.map} +1 -1
  30. package/extensions/dashboard-client/dist/assets/{OverviewTab-Cl2Zx7r1.js → OverviewTab-9Kxo79mi.js} +2 -2
  31. package/extensions/dashboard-client/dist/assets/{OverviewTab-Cl2Zx7r1.js.map → OverviewTab-9Kxo79mi.js.map} +1 -1
  32. package/extensions/dashboard-client/dist/assets/{ReposTab-DUoDgjk-.js → ReposTab-C4iveqrP.js} +2 -2
  33. package/extensions/dashboard-client/dist/assets/{ReposTab-DUoDgjk-.js.map → ReposTab-C4iveqrP.js.map} +1 -1
  34. package/extensions/dashboard-client/dist/assets/{SessionsTab-hEQ_OAfB.js → SessionsTab-DSEwkMQm.js} +2 -2
  35. package/extensions/dashboard-client/dist/assets/{SessionsTab-hEQ_OAfB.js.map → SessionsTab-DSEwkMQm.js.map} +1 -1
  36. package/extensions/dashboard-client/dist/assets/{SetupTab-Bqibg0cD.js → SetupTab-CCyWgy4O.js} +2 -2
  37. package/extensions/dashboard-client/dist/assets/{SetupTab-Bqibg0cD.js.map → SetupTab-CCyWgy4O.js.map} +1 -1
  38. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-9QMQUc7L.js → TimeSavedCard-CyD8e_e_.js} +2 -2
  39. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-9QMQUc7L.js.map → TimeSavedCard-CyD8e_e_.js.map} +1 -1
  40. package/extensions/dashboard-client/dist/assets/{TurnMemoryView-DAfqhJqd.js → TurnMemoryView-5tLbWkRv.js} +2 -2
  41. package/extensions/dashboard-client/dist/assets/{TurnMemoryView-DAfqhJqd.js.map → TurnMemoryView-5tLbWkRv.js.map} +1 -1
  42. package/extensions/dashboard-client/dist/assets/TurnsTab-C7pm92Hg.js +2 -0
  43. package/extensions/dashboard-client/dist/assets/{TurnsTab-C-uZNH2F.js.map → TurnsTab-C7pm92Hg.js.map} +1 -1
  44. package/extensions/dashboard-client/dist/assets/{VcStatusBadge-DyOagOVb.js → VcStatusBadge-ObhcIyfN.js} +2 -2
  45. package/extensions/dashboard-client/dist/assets/{VcStatusBadge-DyOagOVb.js.map → VcStatusBadge-ObhcIyfN.js.map} +1 -1
  46. package/extensions/dashboard-client/dist/assets/{VectorCortexTab-BxsbSUGv.js → VectorCortexTab-BtHZb7o7.js} +2 -2
  47. package/extensions/dashboard-client/dist/assets/{VectorCortexTab-BxsbSUGv.js.map → VectorCortexTab-BtHZb7o7.js.map} +1 -1
  48. package/extensions/dashboard-client/dist/assets/{WikiTab-CjefloQb.js → WikiTab-lQ4l3QIK.js} +2 -2
  49. package/extensions/dashboard-client/dist/assets/{WikiTab-CjefloQb.js.map → WikiTab-lQ4l3QIK.js.map} +1 -1
  50. package/extensions/dashboard-client/dist/assets/{button-D-9nb4Bw.js → button-DhQQAJGm.js} +2 -2
  51. package/extensions/dashboard-client/dist/assets/{button-D-9nb4Bw.js.map → button-DhQQAJGm.js.map} +1 -1
  52. package/extensions/dashboard-client/dist/assets/{card-Dvl16_R5.js → card-Cfhz9X31.js} +2 -2
  53. package/extensions/dashboard-client/dist/assets/{card-Dvl16_R5.js.map → card-Cfhz9X31.js.map} +1 -1
  54. package/extensions/dashboard-client/dist/assets/{client-extra-BShDrG99.js → client-extra-CKNOGEz_.js} +2 -2
  55. package/extensions/dashboard-client/dist/assets/{client-extra-BShDrG99.js.map → client-extra-CKNOGEz_.js.map} +1 -1
  56. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-Q_V4fqVi.js → generateCategoricalChart-JKjK9_cB.js} +2 -2
  57. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-Q_V4fqVi.js.map → generateCategoricalChart-JKjK9_cB.js.map} +1 -1
  58. package/extensions/dashboard-client/dist/assets/{index-CL6Af_JZ.js → index-iuxgtzEW.js} +4 -4
  59. package/extensions/dashboard-client/dist/assets/{index-CL6Af_JZ.js.map → index-iuxgtzEW.js.map} +1 -1
  60. package/extensions/dashboard-client/dist/assets/{switch-0MNUTR9I.js → switch-7EHEQMSP.js} +2 -2
  61. package/extensions/dashboard-client/dist/assets/{switch-0MNUTR9I.js.map → switch-7EHEQMSP.js.map} +1 -1
  62. package/extensions/dashboard-client/dist/assets/{toggle-DHbWo-CW.js → toggle-z1lWY4UM.js} +2 -2
  63. package/extensions/dashboard-client/dist/assets/{toggle-DHbWo-CW.js.map → toggle-z1lWY4UM.js.map} +1 -1
  64. package/extensions/dashboard-client/dist/assets/{useSSE-DcBpzKtI.js → useSSE-sctOZuRM.js} +2 -2
  65. package/extensions/dashboard-client/dist/assets/{useSSE-DcBpzKtI.js.map → useSSE-sctOZuRM.js.map} +1 -1
  66. package/extensions/dashboard-client/dist/index.html +1 -1
  67. package/extensions/dashboard-server/api-contracts/endpoints/registry-ext.ts +1 -1
  68. package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +1 -1
  69. package/extensions/dashboard-server/routes-setup-cortex-actions.ts +6 -5
  70. package/extensions/dashboard-server/setup-cortex-actions-vc2.ts +400 -0
  71. package/extensions/dashboard-server/setup-cortex-actions.ts +18 -71
  72. package/package.json +1 -1
  73. package/src/config/vector-cortex-vc9b.ts +4 -3
  74. package/extensions/dashboard-client/dist/assets/MetricsTab-Clkcniuo.js +0 -2
  75. package/extensions/dashboard-client/dist/assets/TurnsTab-C-uZNH2F.js +0 -2
@@ -1,2 +1,2 @@
1
- import{r as c,j as e,M as H,O as K,P as U,u as w,Q,S as Y,T as z,B as y,U as X}from"./index-CL6Af_JZ.js";import{B as v}from"./button-D-9nb4Bw.js";import{T as A}from"./toggle-DHbWo-CW.js";import{C as N,c as k}from"./card-Dvl16_R5.js";import{u as J}from"./useSSE-DcBpzKtI.js";function Z(t,o){const m=t.length>14?t.slice(0,14)+"…":t;return o?`${m} (${o})`:m}function ee({topicId:t,others:o,members:m,onMutated:i}){const[n,a]=c.useState(null),[d,h]=c.useState(""),[l,u]=c.useState(""),[r,s]=c.useState([]),[p,b]=c.useState(!1),[g,f]=c.useState(null);function j(x){a(x),f(null),h(""),u(""),s([])}async function q(){b(!0),f(null);try{if(n==="rename")await H(t,d);else if(n==="merge"){if(!l){f("Pick a target topic."),b(!1);return}await K(t,l)}else if(n==="split"){if(r.length===0){f("Pick at least one memory."),b(!1);return}await U(t,r)}a(null),i()}catch(x){f(x instanceof Error?x.message:String(x))}finally{b(!1)}}return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex gap-2",children:[e.jsx(v,{variant:"outline",size:"sm",onClick:()=>j("rename"),children:"Rename"}),e.jsx(v,{variant:"outline",size:"sm",onClick:()=>j("merge"),children:"Merge into…"}),e.jsx(v,{variant:"outline",size:"sm",onClick:()=>j("split"),children:"Split"})]}),n&&e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4",onClick:()=>a(null),children:e.jsxs("div",{className:"w-full max-w-md rounded-lg border border-border bg-bg-card p-5 shadow-xl",role:"dialog","aria-modal":"true","aria-label":n,onClick:x=>x.stopPropagation(),children:[e.jsx("h3",{className:"mb-3 font-heading text-base font-semibold text-foreground",children:n==="rename"?"Rename topic":n==="merge"?"Merge into…":"Split topic"}),n==="rename"&&e.jsx("input",{type:"text",value:d,placeholder:"New label (empty = back to auto)","aria-label":"New topic label",autoFocus:!0,onChange:x=>h(x.target.value),className:"w-full rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary"}),n==="merge"&&e.jsxs("select",{value:l,"aria-label":"Target topic",onChange:x=>u(x.target.value),className:"w-full rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary",children:[e.jsx("option",{value:"",children:"Pick a target topic…"}),o.map(x=>e.jsx("option",{value:x.id,children:x.label},x.id))]}),n==="split"&&e.jsx("div",{className:"max-h-56 overflow-auto rounded-md border border-border/60",children:m.map(x=>e.jsxs("label",{className:"flex cursor-pointer items-center gap-2 border-b border-border/40 px-3 py-2 text-sm last:border-0 hover:bg-bg-elevated/40",children:[e.jsx("input",{type:"checkbox",checked:r.includes(x.memoryId),onChange:G=>{s(I=>G.target.checked?[...I,x.memoryId]:I.filter(V=>V!==x.memoryId))},className:"accent-primary"}),e.jsx("span",{className:"font-mono text-xs text-muted-foreground",children:Z(x.memoryId,x.method)})]},x.memoryId))}),g&&e.jsx("p",{className:"mt-3 text-sm text-danger",children:g}),e.jsxs("div",{className:"mt-4 flex justify-end gap-2",children:[e.jsx(v,{variant:"ghost",size:"sm",onClick:()=>a(null),children:"Cancel"}),e.jsx(v,{size:"sm",onClick:q,disabled:p,children:p?"…":"Confirm"})]})]})})]})}const L=720,M=56,T=10,R=3;function C(t){return t?new Date(t).toLocaleDateString():"—"}function te({topicId:t}){const{data:o,error:m}=w(c.useCallback(()=>Q(t),[t]),{});if(m)return e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-4 text-sm text-muted-foreground",children:"Timeline unavailable."});if(!o)return e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-4 text-sm text-muted-foreground",children:"Loading timeline…"});const{buckets:i,total:n}=o,a=Math.max(...i.map(l=>l.count),1),d=i.length*(T+R),h=Math.min(1,(L-24)/Math.max(d,1));return e.jsxs("div",{className:"rounded-lg border border-border bg-bg-card p-4",children:[e.jsxs("h3",{className:"mb-2 font-heading text-sm font-semibold text-muted-foreground",children:["Memory timeline"," ",e.jsxs("span",{className:"font-normal text-xs",children:["(",n," memory",n!==1?"ies":"y"," · daily buckets)"]})]}),i.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No timeline data yet."}):e.jsxs(e.Fragment,{children:[e.jsx("svg",{width:"100%",height:M,viewBox:`0 0 ${Math.max(L,d*h)} ${M}`,role:"img","aria-label":"Memory additions over time",children:i.map((l,u)=>{const r=u*(T+R)*h,s=Math.max(3,l.count/a*(M-20));return e.jsx("rect",{x:r,y:M-6-s,width:Math.max(2,T*h),height:s,rx:2,fill:"hsl(var(--primary))",opacity:.85,children:e.jsx("title",{children:`${C(l.bucket)}: ${l.count}`})},`${l.bucket}-${u}`)})}),e.jsxs("p",{className:"mt-1 text-xs text-muted-foreground",children:["First display: ",C(i[0].bucket)," · last:",C(i[i.length-1].bucket)]})]})]})}function B(t){return t?new Date(t).toLocaleString():"—"}const re={"kmeans+tfidf":"kmeans",merge:"merge",split:"split",manual:"manual"};function se({topicId:t,onBack:o}){const[m,i]=c.useState(0),n=c.useCallback(()=>i(s=>s+1),[]),{data:a,error:d,loading:h}=w(c.useCallback(()=>Y(t),[t,m]),{}),{data:l}=w(c.useCallback(()=>z(),[]),{}),u=c.useMemo(()=>{const s=new Map;for(const p of l?.topics??[])s.set(p.id,p.label);return s},[l]);if(d&&!a)return e.jsxs("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger",children:["Error loading topic: ",d.message]});if(h&&!a)return e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"Loading topic…"});if(!a)return e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"No topic data available."});const r=(l?.topics??[]).filter(s=>s.id!==t).map(s=>({id:s.id,label:s.label}));return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(v,{variant:"outline",size:"sm",onClick:o,children:"← Wiki"}),e.jsx("h2",{className:"font-heading text-lg font-semibold",children:a.topic.label}),a.topic.edited&&e.jsx(y,{variant:"outline",children:"edited"}),e.jsxs(y,{variant:"default",children:[a.provenance.length," memories"]})]}),e.jsx(ee,{topicId:t,others:r,members:a.provenance,onMutated:n})]}),a.summary&&e.jsx(N,{children:e.jsxs(k,{children:[e.jsx("h3",{className:"mb-1 font-heading text-sm font-semibold text-muted-foreground",children:"Summary"}),e.jsx("p",{className:"text-sm leading-relaxed text-foreground/90",children:a.summary})]})}),a.keyMemories.length>0&&e.jsx(N,{children:e.jsxs(k,{children:[e.jsx("h3",{className:"mb-2 font-heading text-sm font-semibold text-muted-foreground",children:"Key memories"}),e.jsx("ul",{className:"flex flex-col gap-2",children:a.keyMemories.map(s=>e.jsxs("li",{className:"rounded-md border border-border/60 bg-bg-elevated/40 p-3 text-sm",children:[e.jsx("p",{className:"line-clamp-3 text-foreground/90",children:s.content}),e.jsxs("p",{className:"mt-1 text-xs text-muted-foreground",children:[s.memoryId," · ",B(s.timestamp)]})]},s.memoryId))})]})}),e.jsx(te,{topicId:t}),a.provenance.length>0&&e.jsx(N,{children:e.jsxs(k,{children:[e.jsx("h3",{className:"mb-2 font-heading text-sm font-semibold text-muted-foreground",children:"Provenance"}),e.jsx("div",{className:"max-h-72 overflow-auto rounded-md border border-border/60",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"sticky top-0 bg-bg-card",children:e.jsxs("tr",{className:"border-b border-border text-left text-xs uppercase text-muted-foreground",children:[e.jsx("th",{className:"px-3 py-2 font-medium",children:"Memory"}),e.jsx("th",{className:"px-3 py-2 font-medium",children:"Session"}),e.jsx("th",{className:"px-3 py-2 font-medium",children:"Assigned"}),e.jsx("th",{className:"px-3 py-2 font-medium",children:"Method"})]})}),e.jsx("tbody",{children:a.provenance.map(s=>e.jsxs("tr",{className:"border-b border-border/40 last:border-0",children:[e.jsx("td",{className:"px-3 py-1.5 font-mono text-xs",children:s.memoryId}),e.jsx("td",{className:"px-3 py-1.5 text-xs text-muted-foreground",children:s.sessionId||"unknown"}),e.jsx("td",{className:"px-3 py-1.5 text-xs text-muted-foreground",children:B(s.assignedAt)}),e.jsx("td",{className:"px-3 py-1.5",children:e.jsx(y,{variant:"outline",children:re[s.method]??s.method})})]},s.memoryId))})]})})]})}),a.relatedTopicIds.length>0&&e.jsx(N,{children:e.jsxs(k,{children:[e.jsx("h3",{className:"mb-2 font-heading text-sm font-semibold text-muted-foreground",children:"Related topics"}),e.jsx("div",{className:"flex flex-wrap gap-2",children:a.relatedTopicIds.map(s=>e.jsx(y,{variant:"accent",children:u.get(s)??s},s))})]})})]})}const O=900,E=560,F=6e4,W=.012,$=.012,D=.8,S=2,ne=.02,oe=250;function ae(t){return t==="merge"?"#f59e0b":"#22c55e"}function le(t){return t.map((o,m)=>{const i=2*Math.PI*m/Math.max(t.length,1);return{id:o.id,label:o.label,memoryCount:o.memoryCount,pos:{x:Math.cos(i)*220+O/2,y:Math.sin(i)*220+E/2},vx:0,vy:0}})}function ie(t){const{nodes:o,edges:m}=t;for(let i=0;i<o.length;i++){const n=o[i];let a=0,d=0;for(let l=0;l<o.length;l++){if(i===l)continue;const u=n.pos.x-o[l].pos.x,r=n.pos.y-o[l].pos.y,s=u*u+r*r||1,p=Math.sqrt(s);a+=u/p*(F/s),d+=r/p*(F/s)}for(const l of m){let u;if(l.source===i)u=l.target;else if(l.target===i)u=l.source;else continue;const r=o[u].pos.x-n.pos.x,s=o[u].pos.y-n.pos.y;a+=r*W,d+=s*W}a-=n.pos.x*$,d-=n.pos.y*$,n.vx=(n.vx+a)*D,n.vy=(n.vy+d)*D;const h=Math.sqrt(n.vx*n.vx+n.vy*n.vy);h>S&&(n.vx=n.vx/h*S,n.vy=n.vy/h*S),h>ne&&(n.pos.x+=n.vx,n.pos.y+=n.vy)}}function de({data:t}){const o=c.useRef(null),m=c.useRef(0),[,i]=c.useState(0),[n,a]=c.useState(0);c.useEffect(()=>{const r=le(t.nodes),s=new Map(r.map((g,f)=>[g.id,f])),p=t.edges.map(g=>{const f=s.get(g.source),j=s.get(g.target);return f===void 0||j===void 0||f===j?null:{source:f,target:j,kind:g.kind}}).filter(g=>g!==null),b=new Map;for(const g of t.edges)b.set(g.source,Math.max(b.get(g.source)??0,g.at)),b.set(g.target,Math.max(b.get(g.target)??0,g.at));return o.current={nodes:r,edges:p,timeByActivity:b},i(1),()=>cancelAnimationFrame(m.current)},[t]),c.useEffect(()=>{if(!o.current)return;let r=0;const s=()=>{!o.current||r>=oe||(ie(o.current),r++,i(r),m.current=requestAnimationFrame(s))};return m.current=requestAnimationFrame(s),()=>cancelAnimationFrame(m.current)},[t]);const d=o.current,h=Math.max(t.buckets.length-1,0),l=c.useMemo(()=>{if(t.buckets.length===0)return null;const r=Math.min(n,t.buckets.length-1);return t.buckets[r].bucket},[n,t.buckets]);if(!d||t.nodes.length===0)return e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"No evolution data yet. Merge or split topics to see connections, then check back after a rebuild."});const u=l==null||!d.timeByActivity?null:new Set([...d.timeByActivity.entries()].filter(([,r])=>r<=l).map(([r])=>r));return e.jsxs("div",{className:"flex flex-col gap-3",children:[t.buckets.length>1&&e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("input",{type:"range",min:0,max:h,value:n,onChange:r=>a(Number(r.target.value)),className:"w-full accent-primary","aria-label":"Scrub through topic activity time"}),e.jsx("span",{className:"whitespace-nowrap text-xs text-muted-foreground",children:l?new Date(l).toLocaleDateString():"all"})]}),e.jsxs("svg",{width:"100%",height:E,viewBox:`0 0 ${O} ${E}`,role:"img","aria-label":"Topic evolution graph",className:"rounded-lg border border-border/60 bg-bg-card",children:[d.edges.map((r,s)=>{const p=d.nodes[r.source],b=d.nodes[r.target];return e.jsx("line",{x1:p.pos.x,y1:p.pos.y,x2:b.pos.x,y2:b.pos.y,stroke:ae(r.kind),strokeWidth:1.5,strokeDasharray:r.kind==="split"?"4 3":void 0,opacity:.5},`edge-${s}`)}),d.nodes.map((r,s)=>{const p=u==null||u.size===0||u.has(r.id),b=Math.min(32,8+r.memoryCount*3);return e.jsxs("g",{opacity:p?1:.15,children:[e.jsx("circle",{cx:r.pos.x,cy:r.pos.y,r:b,fill:"hsl(var(--primary) / 0.18)",stroke:"hsl(var(--primary))",strokeWidth:1.5}),e.jsx("text",{x:r.pos.x,y:r.pos.y+4,textAnchor:"middle",fontSize:"10px",fill:"hsl(var(--foreground))",className:"pointer-events-none",children:r.label.length>16?r.label.slice(0,15)+"…":r.label})]},`node-${s}`)})]}),e.jsxs("div",{className:"flex items-center gap-4 text-xs text-muted-foreground",children:[e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"inline-block h-0.5 w-6 bg-amber-500"})," merge"]}),e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"inline-block h-0.5 w-6 border-t border-dashed border-green-500"}),"split"]}),e.jsxs("span",{children:[t.nodes.length," nodes · ",t.edges.length," curation events"]})]})]})}function ce(t){return t.type==="wiki_rebuilt"}function me(){const{data:t,error:o,loading:m,refetch:i}=w(c.useCallback(()=>X(),[]),{pollInterval:6e4}),{events:n}=J(),a=c.useMemo(()=>{const d=n.filter(ce);return d.length===0?null:d[d.length-1].ts},[n]);return c.useEffect(()=>{a!=null&&i()},[a,i]),o&&!t?e.jsxs("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger",children:["Error loading evolution graph: ",o.message]}):m&&!t?e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"Loading evolution graph…"}):e.jsx(N,{children:e.jsxs(k,{children:[e.jsx("h3",{className:"mb-2 font-heading text-sm font-semibold text-muted-foreground",children:"Topic evolution"}),t?e.jsx(de,{data:t}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"No data yet."})]})})}const ue={label:"accent",merge:"warning",split:"default"};function _(t){return t?new Date(t).toLocaleString():"—"}function P({view:t,onChange:o}){return e.jsxs("div",{className:"flex gap-1",children:[e.jsx(A,{pressed:t==="list",onClick:()=>o("list"),children:"Topics"}),e.jsx(A,{pressed:t==="evolution",onClick:()=>o("evolution"),children:"Evolution"})]})}function xe({entry:t,onOpen:o}){return e.jsxs("tr",{className:"border-b border-border/60 last:border-0 hover:bg-bg-elevated/40",children:[e.jsx("td",{className:"py-2 pr-3",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"font-medium text-foreground",children:t.label}),t.edited&&e.jsx(y,{variant:"outline",children:"edited"})]})}),e.jsx("td",{className:"py-2 pr-3 text-sm text-muted-foreground",children:t.memoryCount}),e.jsx("td",{className:"py-2 pr-3",children:e.jsx("div",{className:"flex flex-wrap gap-1",children:t.overrideKinds.map(m=>e.jsx(y,{variant:ue[m]??"default",children:m},m))})}),e.jsx("td",{className:"py-2 pr-3 text-xs text-muted-foreground",children:_(t.lastUpdated)}),e.jsx("td",{className:"py-2 text-right",children:e.jsx(v,{variant:"outline",size:"sm",onClick:()=>o(t.id),children:"Open"})})]})}function je(){const{data:t,loading:o,error:m}=w(c.useCallback(()=>z(),[]),{pollInterval:3e4}),[i,n]=c.useState("list"),[a,d]=c.useState(""),[h,l]=c.useState(null),u=c.useMemo(()=>{if(!t)return[];const r=a.trim().toLowerCase();return r?t.topics.filter(s=>s.label.toLowerCase().includes(r)):t.topics},[t,a]);return h?e.jsx(se,{topicId:h,onBack:()=>l(null)}):i==="evolution"?e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx(P,{view:i,onChange:n}),e.jsx(me,{})]}):m&&!t?e.jsxs("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger",children:["Error loading wiki: ",m.message]}):o&&!t?e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"Loading wiki…"}):t?t.totalTopics===0?e.jsxs("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:[e.jsx("h3",{className:"mb-2 font-heading text-base text-foreground",children:"Wiki"}),e.jsx("p",{children:"No topics yet. Topics are auto-generated after every Nth compaction from real memory embeddings (k-means + TF-IDF)."}),e.jsx("p",{className:"mt-2",children:"Check back after a few more compaction cycles."})]}):e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex flex-wrap items-end justify-between gap-2",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(P,{view:i,onChange:n}),e.jsxs("div",{children:[e.jsx("h2",{className:"font-heading text-lg font-semibold",children:"Wiki"}),e.jsxs("p",{className:"text-sm text-muted-foreground",children:[t.totalTopics," topic",t.totalTopics!==1?"s":""," ·"," ",t.totalMemories," assigned memori",t.totalMemories!==1?"es":"y",t.lastRebuildAt!=null&&e.jsxs(e.Fragment,{children:[" · last rebuild ",_(t.lastRebuildAt)]})]})]})]}),e.jsx("input",{type:"search",placeholder:"Filter topics by label…","aria-label":"Filter topics by label",value:a,onChange:r=>d(r.target.value),className:"w-64 rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary"})]}),e.jsx("div",{className:"overflow-x-auto rounded-lg border border-border bg-bg-card",children:e.jsxs("table",{className:"w-full table-fixed text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-border text-left text-xs uppercase text-muted-foreground",children:[e.jsx("th",{className:"w-1/3 px-4 py-2 font-medium",children:"Label"}),e.jsx("th",{className:"w-16 py-2 font-medium",children:"Memories"}),e.jsx("th",{className:"w-40 py-2 font-medium",children:"Badges"}),e.jsx("th",{className:"w-40 py-2 font-medium",children:"Last updated"}),e.jsx("th",{className:"w-20 py-2"})]})}),e.jsxs("tbody",{children:[u.map(r=>e.jsx(xe,{entry:r,onOpen:l},r.id)),u.length===0&&e.jsx("tr",{children:e.jsxs("td",{colSpan:5,className:"px-4 py-6 text-center text-muted-foreground",children:['No topics match "',a,'".']})})]})]})})]}):e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"No wiki data available."})}export{je as default};
2
- //# sourceMappingURL=WikiTab-CjefloQb.js.map
1
+ import{r as c,j as e,M as H,O as K,P as U,u as w,Q,S as Y,T as z,B as y,U as X}from"./index-iuxgtzEW.js";import{B as v}from"./button-DhQQAJGm.js";import{T as A}from"./toggle-z1lWY4UM.js";import{C as N,c as k}from"./card-Cfhz9X31.js";import{u as J}from"./useSSE-sctOZuRM.js";function Z(t,o){const m=t.length>14?t.slice(0,14)+"…":t;return o?`${m} (${o})`:m}function ee({topicId:t,others:o,members:m,onMutated:i}){const[n,a]=c.useState(null),[d,h]=c.useState(""),[l,u]=c.useState(""),[r,s]=c.useState([]),[p,b]=c.useState(!1),[g,f]=c.useState(null);function j(x){a(x),f(null),h(""),u(""),s([])}async function q(){b(!0),f(null);try{if(n==="rename")await H(t,d);else if(n==="merge"){if(!l){f("Pick a target topic."),b(!1);return}await K(t,l)}else if(n==="split"){if(r.length===0){f("Pick at least one memory."),b(!1);return}await U(t,r)}a(null),i()}catch(x){f(x instanceof Error?x.message:String(x))}finally{b(!1)}}return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex gap-2",children:[e.jsx(v,{variant:"outline",size:"sm",onClick:()=>j("rename"),children:"Rename"}),e.jsx(v,{variant:"outline",size:"sm",onClick:()=>j("merge"),children:"Merge into…"}),e.jsx(v,{variant:"outline",size:"sm",onClick:()=>j("split"),children:"Split"})]}),n&&e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4",onClick:()=>a(null),children:e.jsxs("div",{className:"w-full max-w-md rounded-lg border border-border bg-bg-card p-5 shadow-xl",role:"dialog","aria-modal":"true","aria-label":n,onClick:x=>x.stopPropagation(),children:[e.jsx("h3",{className:"mb-3 font-heading text-base font-semibold text-foreground",children:n==="rename"?"Rename topic":n==="merge"?"Merge into…":"Split topic"}),n==="rename"&&e.jsx("input",{type:"text",value:d,placeholder:"New label (empty = back to auto)","aria-label":"New topic label",autoFocus:!0,onChange:x=>h(x.target.value),className:"w-full rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary"}),n==="merge"&&e.jsxs("select",{value:l,"aria-label":"Target topic",onChange:x=>u(x.target.value),className:"w-full rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary",children:[e.jsx("option",{value:"",children:"Pick a target topic…"}),o.map(x=>e.jsx("option",{value:x.id,children:x.label},x.id))]}),n==="split"&&e.jsx("div",{className:"max-h-56 overflow-auto rounded-md border border-border/60",children:m.map(x=>e.jsxs("label",{className:"flex cursor-pointer items-center gap-2 border-b border-border/40 px-3 py-2 text-sm last:border-0 hover:bg-bg-elevated/40",children:[e.jsx("input",{type:"checkbox",checked:r.includes(x.memoryId),onChange:G=>{s(I=>G.target.checked?[...I,x.memoryId]:I.filter(V=>V!==x.memoryId))},className:"accent-primary"}),e.jsx("span",{className:"font-mono text-xs text-muted-foreground",children:Z(x.memoryId,x.method)})]},x.memoryId))}),g&&e.jsx("p",{className:"mt-3 text-sm text-danger",children:g}),e.jsxs("div",{className:"mt-4 flex justify-end gap-2",children:[e.jsx(v,{variant:"ghost",size:"sm",onClick:()=>a(null),children:"Cancel"}),e.jsx(v,{size:"sm",onClick:q,disabled:p,children:p?"…":"Confirm"})]})]})})]})}const L=720,M=56,T=10,R=3;function C(t){return t?new Date(t).toLocaleDateString():"—"}function te({topicId:t}){const{data:o,error:m}=w(c.useCallback(()=>Q(t),[t]),{});if(m)return e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-4 text-sm text-muted-foreground",children:"Timeline unavailable."});if(!o)return e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-4 text-sm text-muted-foreground",children:"Loading timeline…"});const{buckets:i,total:n}=o,a=Math.max(...i.map(l=>l.count),1),d=i.length*(T+R),h=Math.min(1,(L-24)/Math.max(d,1));return e.jsxs("div",{className:"rounded-lg border border-border bg-bg-card p-4",children:[e.jsxs("h3",{className:"mb-2 font-heading text-sm font-semibold text-muted-foreground",children:["Memory timeline"," ",e.jsxs("span",{className:"font-normal text-xs",children:["(",n," memory",n!==1?"ies":"y"," · daily buckets)"]})]}),i.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No timeline data yet."}):e.jsxs(e.Fragment,{children:[e.jsx("svg",{width:"100%",height:M,viewBox:`0 0 ${Math.max(L,d*h)} ${M}`,role:"img","aria-label":"Memory additions over time",children:i.map((l,u)=>{const r=u*(T+R)*h,s=Math.max(3,l.count/a*(M-20));return e.jsx("rect",{x:r,y:M-6-s,width:Math.max(2,T*h),height:s,rx:2,fill:"hsl(var(--primary))",opacity:.85,children:e.jsx("title",{children:`${C(l.bucket)}: ${l.count}`})},`${l.bucket}-${u}`)})}),e.jsxs("p",{className:"mt-1 text-xs text-muted-foreground",children:["First display: ",C(i[0].bucket)," · last:",C(i[i.length-1].bucket)]})]})]})}function B(t){return t?new Date(t).toLocaleString():"—"}const re={"kmeans+tfidf":"kmeans",merge:"merge",split:"split",manual:"manual"};function se({topicId:t,onBack:o}){const[m,i]=c.useState(0),n=c.useCallback(()=>i(s=>s+1),[]),{data:a,error:d,loading:h}=w(c.useCallback(()=>Y(t),[t,m]),{}),{data:l}=w(c.useCallback(()=>z(),[]),{}),u=c.useMemo(()=>{const s=new Map;for(const p of l?.topics??[])s.set(p.id,p.label);return s},[l]);if(d&&!a)return e.jsxs("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger",children:["Error loading topic: ",d.message]});if(h&&!a)return e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"Loading topic…"});if(!a)return e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"No topic data available."});const r=(l?.topics??[]).filter(s=>s.id!==t).map(s=>({id:s.id,label:s.label}));return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(v,{variant:"outline",size:"sm",onClick:o,children:"← Wiki"}),e.jsx("h2",{className:"font-heading text-lg font-semibold",children:a.topic.label}),a.topic.edited&&e.jsx(y,{variant:"outline",children:"edited"}),e.jsxs(y,{variant:"default",children:[a.provenance.length," memories"]})]}),e.jsx(ee,{topicId:t,others:r,members:a.provenance,onMutated:n})]}),a.summary&&e.jsx(N,{children:e.jsxs(k,{children:[e.jsx("h3",{className:"mb-1 font-heading text-sm font-semibold text-muted-foreground",children:"Summary"}),e.jsx("p",{className:"text-sm leading-relaxed text-foreground/90",children:a.summary})]})}),a.keyMemories.length>0&&e.jsx(N,{children:e.jsxs(k,{children:[e.jsx("h3",{className:"mb-2 font-heading text-sm font-semibold text-muted-foreground",children:"Key memories"}),e.jsx("ul",{className:"flex flex-col gap-2",children:a.keyMemories.map(s=>e.jsxs("li",{className:"rounded-md border border-border/60 bg-bg-elevated/40 p-3 text-sm",children:[e.jsx("p",{className:"line-clamp-3 text-foreground/90",children:s.content}),e.jsxs("p",{className:"mt-1 text-xs text-muted-foreground",children:[s.memoryId," · ",B(s.timestamp)]})]},s.memoryId))})]})}),e.jsx(te,{topicId:t}),a.provenance.length>0&&e.jsx(N,{children:e.jsxs(k,{children:[e.jsx("h3",{className:"mb-2 font-heading text-sm font-semibold text-muted-foreground",children:"Provenance"}),e.jsx("div",{className:"max-h-72 overflow-auto rounded-md border border-border/60",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"sticky top-0 bg-bg-card",children:e.jsxs("tr",{className:"border-b border-border text-left text-xs uppercase text-muted-foreground",children:[e.jsx("th",{className:"px-3 py-2 font-medium",children:"Memory"}),e.jsx("th",{className:"px-3 py-2 font-medium",children:"Session"}),e.jsx("th",{className:"px-3 py-2 font-medium",children:"Assigned"}),e.jsx("th",{className:"px-3 py-2 font-medium",children:"Method"})]})}),e.jsx("tbody",{children:a.provenance.map(s=>e.jsxs("tr",{className:"border-b border-border/40 last:border-0",children:[e.jsx("td",{className:"px-3 py-1.5 font-mono text-xs",children:s.memoryId}),e.jsx("td",{className:"px-3 py-1.5 text-xs text-muted-foreground",children:s.sessionId||"unknown"}),e.jsx("td",{className:"px-3 py-1.5 text-xs text-muted-foreground",children:B(s.assignedAt)}),e.jsx("td",{className:"px-3 py-1.5",children:e.jsx(y,{variant:"outline",children:re[s.method]??s.method})})]},s.memoryId))})]})})]})}),a.relatedTopicIds.length>0&&e.jsx(N,{children:e.jsxs(k,{children:[e.jsx("h3",{className:"mb-2 font-heading text-sm font-semibold text-muted-foreground",children:"Related topics"}),e.jsx("div",{className:"flex flex-wrap gap-2",children:a.relatedTopicIds.map(s=>e.jsx(y,{variant:"accent",children:u.get(s)??s},s))})]})})]})}const O=900,E=560,F=6e4,W=.012,$=.012,D=.8,S=2,ne=.02,oe=250;function ae(t){return t==="merge"?"#f59e0b":"#22c55e"}function le(t){return t.map((o,m)=>{const i=2*Math.PI*m/Math.max(t.length,1);return{id:o.id,label:o.label,memoryCount:o.memoryCount,pos:{x:Math.cos(i)*220+O/2,y:Math.sin(i)*220+E/2},vx:0,vy:0}})}function ie(t){const{nodes:o,edges:m}=t;for(let i=0;i<o.length;i++){const n=o[i];let a=0,d=0;for(let l=0;l<o.length;l++){if(i===l)continue;const u=n.pos.x-o[l].pos.x,r=n.pos.y-o[l].pos.y,s=u*u+r*r||1,p=Math.sqrt(s);a+=u/p*(F/s),d+=r/p*(F/s)}for(const l of m){let u;if(l.source===i)u=l.target;else if(l.target===i)u=l.source;else continue;const r=o[u].pos.x-n.pos.x,s=o[u].pos.y-n.pos.y;a+=r*W,d+=s*W}a-=n.pos.x*$,d-=n.pos.y*$,n.vx=(n.vx+a)*D,n.vy=(n.vy+d)*D;const h=Math.sqrt(n.vx*n.vx+n.vy*n.vy);h>S&&(n.vx=n.vx/h*S,n.vy=n.vy/h*S),h>ne&&(n.pos.x+=n.vx,n.pos.y+=n.vy)}}function de({data:t}){const o=c.useRef(null),m=c.useRef(0),[,i]=c.useState(0),[n,a]=c.useState(0);c.useEffect(()=>{const r=le(t.nodes),s=new Map(r.map((g,f)=>[g.id,f])),p=t.edges.map(g=>{const f=s.get(g.source),j=s.get(g.target);return f===void 0||j===void 0||f===j?null:{source:f,target:j,kind:g.kind}}).filter(g=>g!==null),b=new Map;for(const g of t.edges)b.set(g.source,Math.max(b.get(g.source)??0,g.at)),b.set(g.target,Math.max(b.get(g.target)??0,g.at));return o.current={nodes:r,edges:p,timeByActivity:b},i(1),()=>cancelAnimationFrame(m.current)},[t]),c.useEffect(()=>{if(!o.current)return;let r=0;const s=()=>{!o.current||r>=oe||(ie(o.current),r++,i(r),m.current=requestAnimationFrame(s))};return m.current=requestAnimationFrame(s),()=>cancelAnimationFrame(m.current)},[t]);const d=o.current,h=Math.max(t.buckets.length-1,0),l=c.useMemo(()=>{if(t.buckets.length===0)return null;const r=Math.min(n,t.buckets.length-1);return t.buckets[r].bucket},[n,t.buckets]);if(!d||t.nodes.length===0)return e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"No evolution data yet. Merge or split topics to see connections, then check back after a rebuild."});const u=l==null||!d.timeByActivity?null:new Set([...d.timeByActivity.entries()].filter(([,r])=>r<=l).map(([r])=>r));return e.jsxs("div",{className:"flex flex-col gap-3",children:[t.buckets.length>1&&e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("input",{type:"range",min:0,max:h,value:n,onChange:r=>a(Number(r.target.value)),className:"w-full accent-primary","aria-label":"Scrub through topic activity time"}),e.jsx("span",{className:"whitespace-nowrap text-xs text-muted-foreground",children:l?new Date(l).toLocaleDateString():"all"})]}),e.jsxs("svg",{width:"100%",height:E,viewBox:`0 0 ${O} ${E}`,role:"img","aria-label":"Topic evolution graph",className:"rounded-lg border border-border/60 bg-bg-card",children:[d.edges.map((r,s)=>{const p=d.nodes[r.source],b=d.nodes[r.target];return e.jsx("line",{x1:p.pos.x,y1:p.pos.y,x2:b.pos.x,y2:b.pos.y,stroke:ae(r.kind),strokeWidth:1.5,strokeDasharray:r.kind==="split"?"4 3":void 0,opacity:.5},`edge-${s}`)}),d.nodes.map((r,s)=>{const p=u==null||u.size===0||u.has(r.id),b=Math.min(32,8+r.memoryCount*3);return e.jsxs("g",{opacity:p?1:.15,children:[e.jsx("circle",{cx:r.pos.x,cy:r.pos.y,r:b,fill:"hsl(var(--primary) / 0.18)",stroke:"hsl(var(--primary))",strokeWidth:1.5}),e.jsx("text",{x:r.pos.x,y:r.pos.y+4,textAnchor:"middle",fontSize:"10px",fill:"hsl(var(--foreground))",className:"pointer-events-none",children:r.label.length>16?r.label.slice(0,15)+"…":r.label})]},`node-${s}`)})]}),e.jsxs("div",{className:"flex items-center gap-4 text-xs text-muted-foreground",children:[e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"inline-block h-0.5 w-6 bg-amber-500"})," merge"]}),e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"inline-block h-0.5 w-6 border-t border-dashed border-green-500"}),"split"]}),e.jsxs("span",{children:[t.nodes.length," nodes · ",t.edges.length," curation events"]})]})]})}function ce(t){return t.type==="wiki_rebuilt"}function me(){const{data:t,error:o,loading:m,refetch:i}=w(c.useCallback(()=>X(),[]),{pollInterval:6e4}),{events:n}=J(),a=c.useMemo(()=>{const d=n.filter(ce);return d.length===0?null:d[d.length-1].ts},[n]);return c.useEffect(()=>{a!=null&&i()},[a,i]),o&&!t?e.jsxs("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger",children:["Error loading evolution graph: ",o.message]}):m&&!t?e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"Loading evolution graph…"}):e.jsx(N,{children:e.jsxs(k,{children:[e.jsx("h3",{className:"mb-2 font-heading text-sm font-semibold text-muted-foreground",children:"Topic evolution"}),t?e.jsx(de,{data:t}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"No data yet."})]})})}const ue={label:"accent",merge:"warning",split:"default"};function _(t){return t?new Date(t).toLocaleString():"—"}function P({view:t,onChange:o}){return e.jsxs("div",{className:"flex gap-1",children:[e.jsx(A,{pressed:t==="list",onClick:()=>o("list"),children:"Topics"}),e.jsx(A,{pressed:t==="evolution",onClick:()=>o("evolution"),children:"Evolution"})]})}function xe({entry:t,onOpen:o}){return e.jsxs("tr",{className:"border-b border-border/60 last:border-0 hover:bg-bg-elevated/40",children:[e.jsx("td",{className:"py-2 pr-3",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"font-medium text-foreground",children:t.label}),t.edited&&e.jsx(y,{variant:"outline",children:"edited"})]})}),e.jsx("td",{className:"py-2 pr-3 text-sm text-muted-foreground",children:t.memoryCount}),e.jsx("td",{className:"py-2 pr-3",children:e.jsx("div",{className:"flex flex-wrap gap-1",children:t.overrideKinds.map(m=>e.jsx(y,{variant:ue[m]??"default",children:m},m))})}),e.jsx("td",{className:"py-2 pr-3 text-xs text-muted-foreground",children:_(t.lastUpdated)}),e.jsx("td",{className:"py-2 text-right",children:e.jsx(v,{variant:"outline",size:"sm",onClick:()=>o(t.id),children:"Open"})})]})}function je(){const{data:t,loading:o,error:m}=w(c.useCallback(()=>z(),[]),{pollInterval:3e4}),[i,n]=c.useState("list"),[a,d]=c.useState(""),[h,l]=c.useState(null),u=c.useMemo(()=>{if(!t)return[];const r=a.trim().toLowerCase();return r?t.topics.filter(s=>s.label.toLowerCase().includes(r)):t.topics},[t,a]);return h?e.jsx(se,{topicId:h,onBack:()=>l(null)}):i==="evolution"?e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx(P,{view:i,onChange:n}),e.jsx(me,{})]}):m&&!t?e.jsxs("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger",children:["Error loading wiki: ",m.message]}):o&&!t?e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"Loading wiki…"}):t?t.totalTopics===0?e.jsxs("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:[e.jsx("h3",{className:"mb-2 font-heading text-base text-foreground",children:"Wiki"}),e.jsx("p",{children:"No topics yet. Topics are auto-generated after every Nth compaction from real memory embeddings (k-means + TF-IDF)."}),e.jsx("p",{className:"mt-2",children:"Check back after a few more compaction cycles."})]}):e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex flex-wrap items-end justify-between gap-2",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(P,{view:i,onChange:n}),e.jsxs("div",{children:[e.jsx("h2",{className:"font-heading text-lg font-semibold",children:"Wiki"}),e.jsxs("p",{className:"text-sm text-muted-foreground",children:[t.totalTopics," topic",t.totalTopics!==1?"s":""," ·"," ",t.totalMemories," assigned memori",t.totalMemories!==1?"es":"y",t.lastRebuildAt!=null&&e.jsxs(e.Fragment,{children:[" · last rebuild ",_(t.lastRebuildAt)]})]})]})]}),e.jsx("input",{type:"search",placeholder:"Filter topics by label…","aria-label":"Filter topics by label",value:a,onChange:r=>d(r.target.value),className:"w-64 rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary"})]}),e.jsx("div",{className:"overflow-x-auto rounded-lg border border-border bg-bg-card",children:e.jsxs("table",{className:"w-full table-fixed text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-border text-left text-xs uppercase text-muted-foreground",children:[e.jsx("th",{className:"w-1/3 px-4 py-2 font-medium",children:"Label"}),e.jsx("th",{className:"w-16 py-2 font-medium",children:"Memories"}),e.jsx("th",{className:"w-40 py-2 font-medium",children:"Badges"}),e.jsx("th",{className:"w-40 py-2 font-medium",children:"Last updated"}),e.jsx("th",{className:"w-20 py-2"})]})}),e.jsxs("tbody",{children:[u.map(r=>e.jsx(xe,{entry:r,onOpen:l},r.id)),u.length===0&&e.jsx("tr",{children:e.jsxs("td",{colSpan:5,className:"px-4 py-6 text-center text-muted-foreground",children:['No topics match "',a,'".']})})]})]})})]}):e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"No wiki data available."})}export{je as default};
2
+ //# sourceMappingURL=WikiTab-lQ4l3QIK.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WikiTab-CjefloQb.js","sources":["../../src/tabs/WikiTab/WikiPageControls.tsx","../../src/tabs/WikiTab/TopicTimeline.tsx","../../src/tabs/WikiTab/WikiPage.tsx","../../src/tabs/WikiTab/TopicEvolutionGraph.tsx","../../src/tabs/WikiTab/TopicEvolutionView.tsx","../../src/tabs/WikiTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/tabs/WikiTab/WikiPageControls.tsx — rename/merge/split.\n *\n * Controlled dialogs for the three curation mutations. Non-destructive: on\n * success the parent refetches and paints the returned CurationResult; on\n * failure the pre-mutation snapshot stays (no local partial apply).\n *\n * Styling: Tailwind + shadcn (Button). No legacy CSS classes.\n */\n\nimport type React from \"react\";\nimport { useState } from \"react\";\nimport { renameTopic, mergeTopics, splitTopic } from \"../../api/client\";\nimport type { MemoryProvenance } from \"@contracts\";\nimport { Button } from \"../../components/ui/button\";\n\ninterface ControlsProps {\n\ttopicId: string;\n\tothers: Array<{ id: string; label: string }>;\n\tmembers: MemoryProvenance[];\n\tonMutated: () => void;\n}\n\ntype Mode = \"rename\" | \"merge\" | \"split\" | null;\n\nfunction memberSnippet(id: string, method: string): string {\n\tconst base = id.length > 14 ? id.slice(0, 14) + \"…\" : id;\n\treturn method ? `${base} (${method})` : base;\n}\n\nexport default function WikiPageControls({\n\ttopicId,\n\tothers,\n\tmembers,\n\tonMutated,\n}: ControlsProps): React.ReactElement {\n\tconst [mode, setMode] = useState<Mode>(null);\n\tconst [label, setLabel] = useState(\"\");\n\tconst [target, setTarget] = useState(\"\");\n\tconst [picked, setPicked] = useState<string[]>([]);\n\tconst [busy, setBusy] = useState(false);\n\tconst [error, setError] = useState<string | null>(null);\n\n\tfunction open(m: Exclude<Mode, null>): void {\n\t\tsetMode(m);\n\t\tsetError(null);\n\t\tsetLabel(\"\");\n\t\tsetTarget(\"\");\n\t\tsetPicked([]);\n\t}\n\n\tasync function submit(): Promise<void> {\n\t\tsetBusy(true);\n\t\tsetError(null);\n\t\ttry {\n\t\t\tif (mode === \"rename\") {\n\t\t\t\tawait renameTopic(topicId, label);\n\t\t\t} else if (mode === \"merge\") {\n\t\t\t\tif (!target) {\n\t\t\t\t\tsetError(\"Pick a target topic.\");\n\t\t\t\t\tsetBusy(false);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tawait mergeTopics(topicId, target);\n\t\t\t} else if (mode === \"split\") {\n\t\t\t\tif (picked.length === 0) {\n\t\t\t\t\tsetError(\"Pick at least one memory.\");\n\t\t\t\t\tsetBusy(false);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tawait splitTopic(topicId, picked);\n\t\t\t}\n\t\t\tsetMode(null);\n\t\t\tonMutated();\n\t\t} catch (e) {\n\t\t\tsetError(e instanceof Error ? e.message : String(e));\n\t\t} finally {\n\t\t\tsetBusy(false);\n\t\t}\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t<Button variant=\"outline\" size=\"sm\" onClick={() => open(\"rename\")}>\n\t\t\t\t\tRename\n\t\t\t\t</Button>\n\t\t\t\t<Button variant=\"outline\" size=\"sm\" onClick={() => open(\"merge\")}>\n\t\t\t\t\tMerge into…\n\t\t\t\t</Button>\n\t\t\t\t<Button variant=\"outline\" size=\"sm\" onClick={() => open(\"split\")}>\n\t\t\t\t\tSplit\n\t\t\t\t</Button>\n\t\t\t</div>\n\n\t\t\t{mode && (\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\"\n\t\t\t\t\tonClick={() => setMode(null)}\n\t\t\t\t>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName=\"w-full max-w-md rounded-lg border border-border bg-bg-card p-5 shadow-xl\"\n\t\t\t\t\t\trole=\"dialog\"\n\t\t\t\t\t\taria-modal=\"true\"\n\t\t\t\t\t\taria-label={mode}\n\t\t\t\t\t\tonClick={(e) => e.stopPropagation()}\n\t\t\t\t\t>\n\t\t\t\t\t\t<h3 className=\"mb-3 font-heading text-base font-semibold text-foreground\">\n\t\t\t\t\t\t\t{mode === \"rename\"\n\t\t\t\t\t\t\t\t? \"Rename topic\"\n\t\t\t\t\t\t\t\t: mode === \"merge\"\n\t\t\t\t\t\t\t\t\t? \"Merge into…\"\n\t\t\t\t\t\t\t\t\t: \"Split topic\"}\n\t\t\t\t\t\t</h3>\n\n\t\t\t\t\t\t{mode === \"rename\" && (\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\tvalue={label}\n\t\t\t\t\t\t\t\tplaceholder=\"New label (empty = back to auto)\"\n\t\t\t\t\t\t\t\taria-label=\"New topic label\"\n\t\t\t\t\t\t\t\tautoFocus\n\t\t\t\t\t\t\t\tonChange={(e) => setLabel(e.target.value)}\n\t\t\t\t\t\t\t\tclassName=\"w-full rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t{mode === \"merge\" && (\n\t\t\t\t\t\t\t<select\n\t\t\t\t\t\t\t\tvalue={target}\n\t\t\t\t\t\t\t\taria-label=\"Target topic\"\n\t\t\t\t\t\t\t\tonChange={(e) => setTarget(e.target.value)}\n\t\t\t\t\t\t\t\tclassName=\"w-full rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<option value=\"\">Pick a target topic…</option>\n\t\t\t\t\t\t\t\t{others.map((o) => (\n\t\t\t\t\t\t\t\t\t<option key={o.id} value={o.id}>\n\t\t\t\t\t\t\t\t\t\t{o.label}\n\t\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t{mode === \"split\" && (\n\t\t\t\t\t\t\t<div className=\"max-h-56 overflow-auto rounded-md border border-border/60\">\n\t\t\t\t\t\t\t\t{members.map((m) => (\n\t\t\t\t\t\t\t\t\t<label\n\t\t\t\t\t\t\t\t\t\tkey={m.memoryId}\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex cursor-pointer items-center gap-2 border-b border-border/40 px-3 py-2 text-sm last:border-0 hover:bg-bg-elevated/40\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\t\t\t\tchecked={picked.includes(m.memoryId)}\n\t\t\t\t\t\t\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\t\t\t\t\t\t\tsetPicked((prev) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\te.target.checked\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t? [...prev, m.memoryId]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t: prev.filter((x) => x !== m.memoryId),\n\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"accent-primary\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-mono text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t{memberSnippet(m.memoryId, m.method)}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t</label>\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\n\t\t\t\t\t\t{error && (\n\t\t\t\t\t\t\t<p className=\"mt-3 text-sm text-danger\">{error}</p>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t<div className=\"mt-4 flex justify-end gap-2\">\n\t\t\t\t\t\t\t<Button variant=\"ghost\" size=\"sm\" onClick={() => setMode(null)}>\n\t\t\t\t\t\t\t\tCancel\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t<Button size=\"sm\" onClick={submit} disabled={busy}>\n\t\t\t\t\t\t\t\t{busy ? \"…\" : \"Confirm\"}\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/WikiTab/TopicTimeline.tsx — per-topic timeline.\n *\n * Renders topic memory-addition buckets as a lightweight SVG bar strip (no\n * chart library needed). X = time bucket, bar height = memories added.\n * Fetches GET /api/wiki/topic/:topicId/timeline.\n *\n * Styling: Tailwind + shadcn (Card). No legacy CSS classes.\n */\n\nimport type React from \"react\";\nimport { useCallback } from \"react\";\nimport { useApi } from \"../../hooks/useApi\";\nimport { fetchTopicTimeline } from \"../../api/client\";\nimport type { TopicTimelineResponse } from \"@contracts\";\n\nconst W = 720;\nconst H = 56;\nconst BAR_W = 10;\nconst GAP = 3;\n\ninterface Props {\n\ttopicId: string;\n}\n\nfunction fmtBucket(ts: number): string {\n\tif (!ts) return \"—\";\n\treturn new Date(ts).toLocaleDateString();\n}\n\nexport default function TopicTimeline({ topicId }: Props): React.ReactElement {\n\tconst { data, error } = useApi<TopicTimelineResponse>(\n\t\tuseCallback(() => fetchTopicTimeline(topicId), [topicId]),\n\t\t{},\n\t);\n\n\tif (error) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-4 text-sm text-muted-foreground\">\n\t\t\t\tTimeline unavailable.\n\t\t\t</div>\n\t\t);\n\t}\n\tif (!data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-4 text-sm text-muted-foreground\">\n\t\t\t\tLoading timeline…\n\t\t\t</div>\n\t\t);\n\t}\n\n\tconst { buckets, total } = data;\n\tconst max = Math.max(...buckets.map((b) => b.count), 1);\n\tconst totalWidth = buckets.length * (BAR_W + GAP);\n\tconst scale = Math.min(1, (W - 24) / Math.max(totalWidth, 1));\n\n\treturn (\n\t\t<div className=\"rounded-lg border border-border bg-bg-card p-4\">\n\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\tMemory timeline{\" \"}\n\t\t\t\t<span className=\"font-normal text-xs\">\n\t\t\t\t\t({total} memory{total !== 1 ? \"ies\" : \"y\"} · daily buckets)\n\t\t\t\t</span>\n\t\t\t</h3>\n\t\t\t{buckets.length === 0 ? (\n\t\t\t\t<p className=\"text-sm text-muted-foreground\">No timeline data yet.</p>\n\t\t\t) : (\n\t\t\t\t<>\n\t\t\t\t\t<svg\n\t\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\t\theight={H}\n\t\t\t\t\t\tviewBox={`0 0 ${Math.max(W, totalWidth * scale)} ${H}`}\n\t\t\t\t\t\trole=\"img\"\n\t\t\t\t\t\taria-label=\"Memory additions over time\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{buckets.map((b, i) => {\n\t\t\t\t\t\t\tconst x = i * (BAR_W + GAP) * scale;\n\t\t\t\t\t\t\tconst h = Math.max(3, (b.count / max) * (H - 20));\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\t\t\tkey={`${b.bucket}-${i}`}\n\t\t\t\t\t\t\t\t\tx={x}\n\t\t\t\t\t\t\t\t\ty={H - 6 - h}\n\t\t\t\t\t\t\t\t\twidth={Math.max(2, BAR_W * scale)}\n\t\t\t\t\t\t\t\t\theight={h}\n\t\t\t\t\t\t\t\t\trx={2}\n\t\t\t\t\t\t\t\t\tfill=\"hsl(var(--primary))\"\n\t\t\t\t\t\t\t\t\topacity={0.85}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<title>{`${fmtBucket(b.bucket)}: ${b.count}`}</title>\n\t\t\t\t\t\t\t\t</rect>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</svg>\n\t\t\t\t\t<p className=\"mt-1 text-xs text-muted-foreground\">\n\t\t\t\t\t\tFirst display: {fmtBucket(buckets[0].bucket)} · last:\n\t\t\t\t\t\t{fmtBucket(buckets[buckets.length - 1].bucket)}\n\t\t\t\t\t</p>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/WikiTab/WikiPage.tsx — single wiki topic page.\n *\n * Renders the extractive summary, key member memories, the member provenance\n * table (memory → session/assigned-at/method), related topics (resolved from\n * the wiki index), and the per-topic memory timeline. Mutations\n * (rename/merge/split) delegate to WikiPageControls; on mutation success the\n * page + index are refetched.\n *\n * Styling: Tailwind + shadcn (Card, Badge, Button) — no legacy CSS.\n */\n\nimport type React from \"react\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport { useApi } from \"../../hooks/useApi\";\nimport { fetchWikiTopic, fetchWikiIndex } from \"../../api/client\";\nimport type { WikiPageResponse, WikiIndexResponse } from \"@contracts\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { Card, CardContent } from \"../../components/ui/card\";\nimport WikiPageControls from \"./WikiPageControls\";\nimport TopicTimeline from \"./TopicTimeline\";\n\ninterface WikiPageProps {\n\ttopicId: string;\n\tonBack: () => void;\n}\n\nfunction fmtTs(ms: number): string {\n\tif (!ms) return \"—\";\n\treturn new Date(ms).toLocaleString();\n}\n\nconst METHOD_LABELS: Record<string, string> = {\n\t\"kmeans+tfidf\": \"kmeans\",\n\tmerge: \"merge\",\n\tsplit: \"split\",\n\tmanual: \"manual\",\n};\n\nexport default function WikiPage({\n\ttopicId,\n\tonBack,\n}: WikiPageProps): React.ReactElement {\n\tconst [dirty, setDirty] = useState(0);\n\tconst bump = useCallback(() => setDirty((d) => d + 1), []);\n\n\tconst { data: page, error, loading } = useApi<WikiPageResponse>(\n\t\tuseCallback(() => fetchWikiTopic(topicId), [topicId, dirty]),\n\t\t{},\n\t);\n\tconst { data: index } = useApi<WikiIndexResponse>(\n\t\tuseCallback(() => fetchWikiIndex(), []),\n\t\t{},\n\t);\n\n\tconst labelOf = useMemo(() => {\n\t\tconst map = new Map<string, string>();\n\t\tfor (const t of index?.topics ?? []) map.set(t.id, t.label);\n\t\treturn map;\n\t}, [index]);\n\n\tif (error && !page) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger\">\n\t\t\t\tError loading topic: {error.message}\n\t\t\t</div>\n\t\t);\n\t}\n\tif (loading && !page) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tLoading topic…\n\t\t\t</div>\n\t\t);\n\t}\n\tif (!page) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tNo topic data available.\n\t\t\t</div>\n\t\t);\n\t}\n\n\tconst otherTopics = (index?.topics ?? [])\n\t\t.filter((t) => t.id !== topicId)\n\t\t.map((t) => ({ id: t.id, label: t.label }));\n\n\treturn (\n\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t<Button variant=\"outline\" size=\"sm\" onClick={onBack}>\n\t\t\t\t\t\t← Wiki\n\t\t\t\t\t</Button>\n\t\t\t\t\t<h2 className=\"font-heading text-lg font-semibold\">\n\t\t\t\t\t\t{page.topic.label}\n\t\t\t\t\t</h2>\n\t\t\t\t\t{page.topic.edited && <Badge variant=\"outline\">edited</Badge>}\n\t\t\t\t\t<Badge variant=\"default\">\n\t\t\t\t\t\t{page.provenance.length} memories\n\t\t\t\t\t</Badge>\n\t\t\t\t</div>\n\t\t\t\t<WikiPageControls\n\t\t\t\t\ttopicId={topicId}\n\t\t\t\t\tothers={otherTopics}\n\t\t\t\t\tmembers={page.provenance}\n\t\t\t\t\tonMutated={bump}\n\t\t\t\t/>\n\t\t\t</div>\n\n\t\t\t{page.summary && (\n\t\t\t\t<Card>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<h3 className=\"mb-1 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\t\t\t\tSummary\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<p className=\"text-sm leading-relaxed text-foreground/90\">\n\t\t\t\t\t\t\t{page.summary}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t)}\n\n\t\t\t{page.keyMemories.length > 0 && (\n\t\t\t\t<Card>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\t\t\t\tKey memories\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<ul className=\"flex flex-col gap-2\">\n\t\t\t\t\t\t\t{page.keyMemories.map((m) => (\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tkey={m.memoryId}\n\t\t\t\t\t\t\t\t\tclassName=\"rounded-md border border-border/60 bg-bg-elevated/40 p-3 text-sm\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<p className=\"line-clamp-3 text-foreground/90\">{m.content}</p>\n\t\t\t\t\t\t\t\t\t<p className=\"mt-1 text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t{m.memoryId} · {fmtTs(m.timestamp)}\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t)}\n\n\t\t\t<TopicTimeline topicId={topicId} />\n\n\t\t\t{page.provenance.length > 0 && (\n\t\t\t\t<Card>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\t\t\t\tProvenance\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<div className=\"max-h-72 overflow-auto rounded-md border border-border/60\">\n\t\t\t\t\t\t\t<table className=\"w-full text-sm\">\n\t\t\t\t\t\t\t\t<thead className=\"sticky top-0 bg-bg-card\">\n\t\t\t\t\t\t\t\t\t<tr className=\"border-b border-border text-left text-xs uppercase text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t<th className=\"px-3 py-2 font-medium\">Memory</th>\n\t\t\t\t\t\t\t\t\t\t<th className=\"px-3 py-2 font-medium\">Session</th>\n\t\t\t\t\t\t\t\t\t\t<th className=\"px-3 py-2 font-medium\">Assigned</th>\n\t\t\t\t\t\t\t\t\t\t<th className=\"px-3 py-2 font-medium\">Method</th>\n\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t{page.provenance.map((p) => (\n\t\t\t\t\t\t\t\t\t\t<tr\n\t\t\t\t\t\t\t\t\t\t\tkey={p.memoryId}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"border-b border-border/40 last:border-0\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-1.5 font-mono text-xs\">\n\t\t\t\t\t\t\t\t\t\t\t\t{p.memoryId}\n\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-1.5 text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t{p.sessionId || \"unknown\"}\n\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-1.5 text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t{fmtTs(p.assignedAt)}\n\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-1.5\">\n\t\t\t\t\t\t\t\t\t\t\t\t<Badge variant=\"outline\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t{METHOD_LABELS[p.method] ?? p.method}\n\t\t\t\t\t\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t)}\n\n\t\t\t{page.relatedTopicIds.length > 0 && (\n\t\t\t\t<Card>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\t\t\t\tRelated topics\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<div className=\"flex flex-wrap gap-2\">\n\t\t\t\t\t\t\t{page.relatedTopicIds.map((id) => (\n\t\t\t\t\t\t\t\t<Badge key={id} variant=\"accent\">\n\t\t\t\t\t\t\t\t\t{labelOf.get(id) ?? id}\n\t\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/WikiTab/TopicEvolutionGraph.tsx — D3 evolution.\n *\n * Force-directed graph of wiki topics over time. Nodes are topics (radius scales\n * with memoryCount); edges are merge/split curation events. A bucket scrubber\n * (from the response buckets) dims nodes that had no activity up to the selected\n * time window — a lightweight \"growth over time\" view.\n *\n * Self-contained force simulation (Coulomb repulsion + Hooke attraction +\n * center gravity) — the codebase deliberately avoids external graph libraries\n * (see memory-map-layout.ts). No data is fabricated: only real node/edge/bucket\n * fields from the contract are used. Styling is Tailwind.\n */\n\nimport type React from \"react\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { TopicEvolutionResponse } from \"@contracts\";\n\n// ── Simulation constants ────────────────────────────────────────────────\nconst W = 900;\nconst H = 560;\nconst REPULSION = 60_000;\nconst ATTRACTION = 0.012;\nconst CENTER_GRAVITY = 0.012;\nconst DAMPING = 0.8;\nconst SPEED_LIMIT = 2;\nconst MIN_VELOCITY = 0.02;\nconst MAX_ITERATIONS = 250;\n\ninterface SimNode {\n\tid: string;\n\tlabel: string;\n\tmemoryCount: number;\n\tpos: { x: number; y: number };\n\tvx: number;\n\tvy: number;\n}\n\ninterface SimEdge {\n\tsource: number;\n\ttarget: number;\n\tkind: \"merge\" | \"split\";\n}\n\nfunction edgeColor(kind: \"merge\" | \"split\"): string {\n\treturn kind === \"merge\" ? \"#f59e0b\" : \"#22c55e\"; // amber / green\n}\n\nfunction initialLayout(nodes: TopicEvolutionResponse[\"nodes\"]): SimNode[] {\n\treturn nodes.map((n, i) => {\n\t\tconst angle = (2 * Math.PI * i) / Math.max(nodes.length, 1);\n\t\treturn {\n\t\t\tid: n.id,\n\t\t\tlabel: n.label,\n\t\t\tmemoryCount: n.memoryCount,\n\t\t\tpos: { x: Math.cos(angle) * 220 + W / 2, y: Math.sin(angle) * 220 + H / 2 },\n\t\t\tvx: 0,\n\t\t\tvy: 0,\n\t\t};\n\t});\n}\n\nfunction applyForces(sim: { nodes: SimNode[]; edges: SimEdge[] }): void {\n\tconst { nodes, edges } = sim;\n\tfor (let i = 0; i < nodes.length; i++) {\n\t\tconst n = nodes[i];\n\t\tlet fx = 0;\n\t\tlet fy = 0;\n\t\tfor (let j = 0; j < nodes.length; j++) {\n\t\t\tif (i === j) continue;\n\t\t\tconst dx = n.pos.x - nodes[j].pos.x;\n\t\t\tconst dy = n.pos.y - nodes[j].pos.y;\n\t\t\tconst distSq = dx * dx + dy * dy || 1;\n\t\t\tconst dist = Math.sqrt(distSq);\n\t\t\tfx += (dx / dist) * (REPULSION / distSq);\n\t\t\tfy += (dy / dist) * (REPULSION / distSq);\n\t\t}\n\t\tfor (const e of edges) {\n\t\t\tlet other: number;\n\t\t\tif (e.source === i) other = e.target;\n\t\t\telse if (e.target === i) other = e.source;\n\t\t\telse continue;\n\t\t\tconst dx = nodes[other].pos.x - n.pos.x;\n\t\t\tconst dy = nodes[other].pos.y - n.pos.y;\n\t\t\tfx += dx * ATTRACTION;\n\t\t\tfy += dy * ATTRACTION;\n\t\t}\n\t\tfx -= n.pos.x * CENTER_GRAVITY;\n\t\tfy -= n.pos.y * CENTER_GRAVITY;\n\t\tn.vx = (n.vx + fx) * DAMPING;\n\t\tn.vy = (n.vy + fy) * DAMPING;\n\t\tconst speed = Math.sqrt(n.vx * n.vx + n.vy * n.vy);\n\t\tif (speed > SPEED_LIMIT) {\n\t\t\tn.vx = (n.vx / speed) * SPEED_LIMIT;\n\t\t\tn.vy = (n.vy / speed) * SPEED_LIMIT;\n\t\t}\n\t\tif (speed > MIN_VELOCITY) {\n\t\t\tn.pos.x += n.vx;\n\t\t\tn.pos.y += n.vy;\n\t\t}\n\t}\n}\n\ninterface Props {\n\tdata: TopicEvolutionResponse;\n}\n\nexport default function TopicEvolutionGraph({\n\tdata,\n}: Props): React.ReactElement {\n\tconst simRef = useRef<{\n\t\tnodes: SimNode[];\n\t\tedges: SimEdge[];\n\t\ttimeByActivity: Map<string, number> | null;\n\t} | null>(null);\n\tconst animRef = useRef(0);\n\tconst [, setFrame] = useState(0);\n\tconst [scrub, setScrub] = useState<number>(0);\n\n\t// Initialize simulation from data (re-run when data changes).\n\tuseEffect(() => {\n\t\tconst nodes = initialLayout(data.nodes);\n\t\tconst indexById = new Map(nodes.map((n, i) => [n.id, i]));\n\t\tconst edges: SimEdge[] = data.edges\n\t\t\t.map((e) => {\n\t\t\t\tconst si = indexById.get(e.source);\n\t\t\t\tconst ti = indexById.get(e.target);\n\t\t\t\tif (si === undefined || ti === undefined || si === ti) return null;\n\t\t\t\treturn { source: si, target: ti, kind: e.kind };\n\t\t\t})\n\t\t\t.filter((e): e is SimEdge => e !== null);\n\t\t// Latest activity per node (from merge/split edge timestamps).\n\t\tconst timeByActivity = new Map<string, number>();\n\t\tfor (const e of data.edges) {\n\t\t\ttimeByActivity.set(e.source, Math.max(timeByActivity.get(e.source) ?? 0, e.at));\n\t\t\ttimeByActivity.set(e.target, Math.max(timeByActivity.get(e.target) ?? 0, e.at));\n\t\t}\n\t\tsimRef.current = { nodes, edges, timeByActivity };\n\t\tsetFrame(1);\n\t\treturn () => cancelAnimationFrame(animRef.current);\n\t}, [data]);\n\n\t// Run the force simulation to stable layout.\n\tuseEffect(() => {\n\t\tif (!simRef.current) return;\n\t\tlet iter = 0;\n\t\tconst tick = () => {\n\t\t\tif (!simRef.current || iter >= MAX_ITERATIONS) return;\n\t\t\tapplyForces(simRef.current);\n\t\t\titer++;\n\t\t\tsetFrame(iter);\n\t\t\tanimRef.current = requestAnimationFrame(tick);\n\t\t};\n\t\tanimRef.current = requestAnimationFrame(tick);\n\t\treturn () => cancelAnimationFrame(animRef.current);\n\t}, [data]);\n\n\tconst sim = simRef.current;\n\n\tconst scrubMax = Math.max(data.buckets.length - 1, 0);\n\tconst scrubBucket = useMemo(() => {\n\t\tif (data.buckets.length === 0) return null;\n\t\tconst idx = Math.min(scrub, data.buckets.length - 1);\n\t\treturn data.buckets[idx].bucket;\n\t}, [scrub, data.buckets]);\n\n\tif (!sim || data.nodes.length === 0) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tNo evolution data yet. Merge or split topics to see connections, then\n\t\t\t\tcheck back after a rebuild.\n\t\t\t</div>\n\t\t);\n\t}\n\n\tconst activeSet =\n\t\tscrubBucket == null || !sim.timeByActivity\n\t\t\t? null\n\t\t\t: new Set(\n\t\t\t\t\t[...sim.timeByActivity.entries()]\n\t\t\t\t\t\t.filter(([, t]) => t <= scrubBucket)\n\t\t\t\t\t\t.map(([id]) => id),\n\t\t\t\t);\n\n\treturn (\n\t\t<div className=\"flex flex-col gap-3\">\n\t\t\t{/* Scrubber */}\n\t\t\t{data.buckets.length > 1 && (\n\t\t\t\t<div className=\"flex items-center gap-3\">\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"range\"\n\t\t\t\t\t\tmin={0}\n\t\t\t\t\t\tmax={scrubMax}\n\t\t\t\t\t\tvalue={scrub}\n\t\t\t\t\t\tonChange={(e) => setScrub(Number(e.target.value))}\n\t\t\t\t\t\tclassName=\"w-full accent-primary\"\n\t\t\t\t\t\taria-label=\"Scrub through topic activity time\"\n\t\t\t\t\t/>\n\t\t\t\t\t<span className=\"whitespace-nowrap text-xs text-muted-foreground\">\n\t\t\t\t\t\t{scrubBucket ? new Date(scrubBucket).toLocaleDateString() : \"all\"}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* SVG graph */}\n\t\t\t<svg\n\t\t\t\twidth=\"100%\"\n\t\t\t\theight={H}\n\t\t\t\tviewBox={`0 0 ${W} ${H}`}\n\t\t\t\trole=\"img\"\n\t\t\t\taria-label=\"Topic evolution graph\"\n\t\t\t\tclassName=\"rounded-lg border border-border/60 bg-bg-card\"\n\t\t\t>\n\t\t\t\t{sim.edges.map((e, i) => {\n\t\t\t\t\tconst a = sim.nodes[e.source];\n\t\t\t\t\tconst b = sim.nodes[e.target];\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<line\n\t\t\t\t\t\t\tkey={`edge-${i}`}\n\t\t\t\t\t\t\tx1={a.pos.x}\n\t\t\t\t\t\t\ty1={a.pos.y}\n\t\t\t\t\t\t\tx2={b.pos.x}\n\t\t\t\t\t\t\ty2={b.pos.y}\n\t\t\t\t\t\t\tstroke={edgeColor(e.kind)}\n\t\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t\t\tstrokeDasharray={e.kind === \"split\" ? \"4 3\" : undefined}\n\t\t\t\t\t\t\topacity={0.5}\n\t\t\t\t\t\t/>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t\t{sim.nodes.map((n, i) => {\n\t\t\t\t\tconst active =\n\t\t\t\t\t\tactiveSet == null || activeSet.size === 0 || activeSet.has(n.id);\n\t\t\t\t\tconst r = Math.min(32, 8 + n.memoryCount * 3);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<g key={`node-${i}`} opacity={active ? 1 : 0.15}>\n\t\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\t\tcx={n.pos.x}\n\t\t\t\t\t\t\t\tcy={n.pos.y}\n\t\t\t\t\t\t\t\tr={r}\n\t\t\t\t\t\t\t\tfill=\"hsl(var(--primary) / 0.18)\"\n\t\t\t\t\t\t\t\tstroke=\"hsl(var(--primary))\"\n\t\t\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t\tx={n.pos.x}\n\t\t\t\t\t\t\t\ty={n.pos.y + 4}\n\t\t\t\t\t\t\t\ttextAnchor=\"middle\"\n\t\t\t\t\t\t\t\tfontSize=\"10px\"\n\t\t\t\t\t\t\t\tfill=\"hsl(var(--foreground))\"\n\t\t\t\t\t\t\t\tclassName=\"pointer-events-none\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{n.label.length > 16 ? n.label.slice(0, 15) + \"…\" : n.label}\n\t\t\t\t\t\t\t</text>\n\t\t\t\t\t\t</g>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</svg>\n\n\t\t\t<div className=\"flex items-center gap-4 text-xs text-muted-foreground\">\n\t\t\t\t<span className=\"flex items-center gap-1.5\">\n\t\t\t\t\t<span className=\"inline-block h-0.5 w-6 bg-amber-500\" /> merge\n\t\t\t\t</span>\n\t\t\t\t<span className=\"flex items-center gap-1.5\">\n\t\t\t\t\t<span className=\"inline-block h-0.5 w-6 border-t border-dashed border-green-500\" />\n\t\t\t\t\tsplit\n\t\t\t\t</span>\n\t\t\t\t<span>\n\t\t\t\t\t{data.nodes.length} nodes · {data.edges.length} curation events\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/WikiTab/TopicEvolutionView.tsx — planet evolution.\n *\n * Thin shell over TopicEvolutionGraph: fetches GET /api/wiki/evolution via\n * useApi and refetches when a `wiki_rebuilt` SSE event lands (emitted by the\n * extension after a topic-model rebuild), so the graph + scrubber stay live\n * between polls. No data is fabricated — only the contract fields are used.\n *\n * Styling: Tailwind + shadcn (Card). No legacy CSS classes.\n */\n\nimport type React from \"react\";\nimport { useCallback, useEffect, useMemo } from \"react\";\nimport { useApi } from \"../../hooks/useApi\";\nimport { useSSE } from \"../../hooks/useSSE\";\nimport { fetchTopicEvolution } from \"../../api/client\";\nimport type { TopicEvolutionResponse, SseEvent } from \"@contracts\";\nimport { Card, CardContent } from \"../../components/ui/card\";\nimport TopicEvolutionGraph from \"./TopicEvolutionGraph\";\n\nfunction isWikiRebuilt(e: SseEvent): e is Extract<SseEvent, { type: \"wiki_rebuilt\" }> {\n\treturn e.type === \"wiki_rebuilt\";\n}\n\nexport default function TopicEvolutionView(): React.ReactElement {\n\tconst { data, error, loading, refetch } = useApi<TopicEvolutionResponse>(\n\t\tuseCallback(() => fetchTopicEvolution(), []),\n\t\t{ pollInterval: 60_000 },\n\t);\n\n\tconst { events } = useSSE();\n\tconst lastRebuiltTs = useMemo(() => {\n\t\tconst rebuilt = events.filter(isWikiRebuilt);\n\t\tif (rebuilt.length === 0) return null;\n\t\treturn rebuilt[rebuilt.length - 1].ts;\n\t}, [events]);\n\n\tuseEffect(() => {\n\t\tif (lastRebuiltTs != null) refetch();\n\t}, [lastRebuiltTs, refetch]);\n\n\tif (error && !data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger\">\n\t\t\t\tError loading evolution graph: {error.message}\n\t\t\t</div>\n\t\t);\n\t}\n\tif (loading && !data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tLoading evolution graph…\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<Card>\n\t\t\t<CardContent>\n\t\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\t\tTopic evolution\n\t\t\t\t</h3>\n\t\t\t\t{data ? (\n\t\t\t\t\t<TopicEvolutionGraph data={data} />\n\t\t\t\t) : (\n\t\t\t\t\t<p className=\"text-sm text-muted-foreground\">No data yet.</p>\n\t\t\t\t)}\n\t\t\t</CardContent>\n\t\t</Card>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/WikiTab.tsx — Wiki Revival (W3): wiki landing list.\n *\n * Replaces TopicsTab in the App registry (TopicsTab.tsx kept, unused). Renders\n * the wiki index: each auto-categorized topic with its resolved label (edited\n * badge when user-renamed), member count, curation badges (label/merge/split),\n * and a click-to-open that pushes a client-side page state to WikiPage.\n *\n * Styling is Tailwind + shadcn (Card, Badge, Button) — no legacy CSS classes.\n */\n\nimport type React from \"react\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport { useApi } from \"../hooks/useApi\";\nimport { fetchWikiIndex } from \"../api/client\";\nimport type { WikiIndexEntry, WikiIndexResponse } from \"@contracts\";\nimport { Badge } from \"../components/ui/badge\";\nimport { Button } from \"../components/ui/button\";\nimport { Toggle } from \"../components/ui/toggle\";\nimport WikiPage from \"./WikiTab/WikiPage\";\nimport TopicEvolutionView from \"./WikiTab/TopicEvolutionView\";\n\ntype WikiView = \"list\" | \"evolution\";\n\nconst KIND_BADGES: Record<string, \"default\" | \"accent\" | \"warning\"> = {\n\tlabel: \"accent\",\n\tmerge: \"warning\",\n\tsplit: \"default\",\n};\n\nfunction fmtTs(ms: number | null): string {\n\tif (!ms) return \"—\";\n\treturn new Date(ms).toLocaleString();\n}\n\nfunction ViewToggle({\n\tview,\n\tonChange,\n}: {\n\tview: WikiView;\n\tonChange: (v: WikiView) => void;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"flex gap-1\">\n\t\t\t<Toggle pressed={view === \"list\"} onClick={() => onChange(\"list\")}>\n\t\t\t\tTopics\n\t\t\t</Toggle>\n\t\t\t<Toggle\n\t\t\t\tpressed={view === \"evolution\"}\n\t\t\t\tonClick={() => onChange(\"evolution\")}\n\t\t\t>\n\t\t\t\tEvolution\n\t\t\t</Toggle>\n\t\t</div>\n\t);\n}\n\ninterface RowProps {\n\tentry: WikiIndexEntry;\n\tonOpen: (id: string) => void;\n}\n\nfunction TopicRow({ entry, onOpen }: RowProps): React.ReactElement {\n\treturn (\n\t\t<tr className=\"border-b border-border/60 last:border-0 hover:bg-bg-elevated/40\">\n\t\t\t<td className=\"py-2 pr-3\">\n\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t<span className=\"font-medium text-foreground\">{entry.label}</span>\n\t\t\t\t\t{entry.edited && <Badge variant=\"outline\">edited</Badge>}\n\t\t\t\t</div>\n\t\t\t</td>\n\t\t\t<td className=\"py-2 pr-3 text-sm text-muted-foreground\">\n\t\t\t\t{entry.memoryCount}\n\t\t\t</td>\n\t\t\t<td className=\"py-2 pr-3\">\n\t\t\t\t<div className=\"flex flex-wrap gap-1\">\n\t\t\t\t\t{entry.overrideKinds.map((k) => (\n\t\t\t\t\t\t<Badge key={k} variant={KIND_BADGES[k] ?? \"default\"}>\n\t\t\t\t\t\t\t{k}\n\t\t\t\t\t\t</Badge>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</td>\n\t\t\t<td className=\"py-2 pr-3 text-xs text-muted-foreground\">\n\t\t\t\t{fmtTs(entry.lastUpdated)}\n\t\t\t</td>\n\t\t\t<td className=\"py-2 text-right\">\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\tonClick={() => onOpen(entry.id)}\n\t\t\t\t>\n\t\t\t\t\tOpen\n\t\t\t\t</Button>\n\t\t\t</td>\n\t\t</tr>\n\t);\n}\n\nexport default function WikiTab(): React.ReactElement {\n\tconst { data, loading, error } = useApi<WikiIndexResponse>(\n\t\tuseCallback(() => fetchWikiIndex(), []),\n\t\t{ pollInterval: 30_000 },\n\t);\n\tconst [view, setView] = useState<WikiView>(\"list\");\n\tconst [query, setQuery] = useState(\"\");\n\tconst [openId, setOpenId] = useState<string | null>(null);\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((t) =>\n\t\t\tt.label.toLowerCase().includes(q),\n\t\t);\n\t}, [data, query]);\n\n\tif (openId) {\n\t\treturn <WikiPage topicId={openId} onBack={() => setOpenId(null)} />;\n\t}\n\n\tif (view === \"evolution\") {\n\t\treturn (\n\t\t\t<div className=\"flex flex-col gap-3\">\n\t\t\t\t<ViewToggle view={view} onChange={setView} />\n\t\t\t\t<TopicEvolutionView />\n\t\t\t</div>\n\t\t);\n\t}\n\n\tif (error && !data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger\">\n\t\t\t\tError loading wiki: {error.message}\n\t\t\t</div>\n\t\t);\n\t}\n\tif (loading && !data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tLoading wiki…\n\t\t\t</div>\n\t\t);\n\t}\n\tif (!data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tNo wiki data available.\n\t\t\t</div>\n\t\t);\n\t}\n\tif (data.totalTopics === 0) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\t<h3 className=\"mb-2 font-heading text-base text-foreground\">Wiki</h3>\n\t\t\t\t<p>\n\t\t\t\t\tNo topics yet. Topics are auto-generated after every Nth 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 className=\"mt-2\">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=\"flex flex-col gap-4\">\n\t\t\t<div className=\"flex flex-wrap items-end justify-between gap-2\">\n\t\t\t\t<div className=\"flex items-center gap-3\">\n\t\t\t\t\t<ViewToggle view={view} onChange={setView} />\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2 className=\"font-heading text-lg font-semibold\">Wiki</h2>\n\t\t\t\t\t\t<p className=\"text-sm text-muted-foreground\">\n\t\t\t\t\t\t\t{data.totalTopics} topic{data.totalTopics !== 1 ? \"s\" : \"\"} ·{\" \"}\n\t\t\t\t\t\t\t{data.totalMemories} assigned memori\n\t\t\t\t\t\t\t{data.totalMemories !== 1 ? \"es\" : \"y\"}\n\t\t\t\t\t\t\t{data.lastRebuildAt != null && (\n\t\t\t\t\t\t\t\t<> · last rebuild {fmtTs(data.lastRebuildAt)}</>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<input\n\t\t\t\t\ttype=\"search\"\n\t\t\t\t\tplaceholder=\"Filter topics by label…\"\n\t\t\t\t\taria-label=\"Filter topics by label\"\n\t\t\t\t\tvalue={query}\n\t\t\t\t\tonChange={(e) => setQuery(e.target.value)}\n\t\t\t\t\tclassName=\"w-64 rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary\"\n\t\t\t\t/>\n\t\t\t</div>\n\n\t\t\t<div className=\"overflow-x-auto rounded-lg border border-border bg-bg-card\">\n\t\t\t\t<table className=\"w-full table-fixed text-sm\">\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr className=\"border-b border-border text-left text-xs uppercase text-muted-foreground\">\n\t\t\t\t\t\t\t<th className=\"w-1/3 px-4 py-2 font-medium\">Label</th>\n\t\t\t\t\t\t\t<th className=\"w-16 py-2 font-medium\">Memories</th>\n\t\t\t\t\t\t\t<th className=\"w-40 py-2 font-medium\">Badges</th>\n\t\t\t\t\t\t\t<th className=\"w-40 py-2 font-medium\">Last updated</th>\n\t\t\t\t\t\t\t<th className=\"w-20 py-2\" />\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<TopicRow key={t.id} entry={t} onOpen={setOpenId} />\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\n\t\t\t\t\t\t\t\t\tcolSpan={5}\n\t\t\t\t\t\t\t\t\tclassName=\"px-4 py-6 text-center text-muted-foreground\"\n\t\t\t\t\t\t\t\t>\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</div>\n\t\t</div>\n\t);\n}\n"],"names":["memberSnippet","id","method","base","WikiPageControls","topicId","others","members","onMutated","mode","setMode","useState","label","setLabel","target","setTarget","picked","setPicked","busy","setBusy","error","setError","open","m","submit","renameTopic","mergeTopics","splitTopic","e","jsxs","Fragment","jsx","Button","o","prev","x","W","H","BAR_W","GAP","fmtBucket","ts","TopicTimeline","data","useApi","useCallback","fetchTopicTimeline","buckets","total","max","b","totalWidth","scale","i","h","fmtTs","ms","METHOD_LABELS","WikiPage","onBack","dirty","setDirty","bump","d","page","loading","fetchWikiTopic","index","fetchWikiIndex","labelOf","useMemo","map","t","otherTopics","Badge","Card","CardContent","p","REPULSION","ATTRACTION","CENTER_GRAVITY","DAMPING","SPEED_LIMIT","MIN_VELOCITY","MAX_ITERATIONS","edgeColor","kind","initialLayout","nodes","n","angle","applyForces","sim","edges","fx","fy","j","dx","dy","distSq","dist","other","speed","TopicEvolutionGraph","simRef","useRef","animRef","setFrame","scrub","setScrub","useEffect","indexById","si","ti","timeByActivity","iter","tick","scrubMax","scrubBucket","idx","activeSet","a","active","r","isWikiRebuilt","TopicEvolutionView","refetch","fetchTopicEvolution","events","useSSE","lastRebuiltTs","rebuilt","KIND_BADGES","ViewToggle","view","onChange","Toggle","TopicRow","entry","onOpen","k","WikiTab","setView","query","setQuery","openId","setOpenId","filtered","q"],"mappings":"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"}
1
+ {"version":3,"file":"WikiTab-lQ4l3QIK.js","sources":["../../src/tabs/WikiTab/WikiPageControls.tsx","../../src/tabs/WikiTab/TopicTimeline.tsx","../../src/tabs/WikiTab/WikiPage.tsx","../../src/tabs/WikiTab/TopicEvolutionGraph.tsx","../../src/tabs/WikiTab/TopicEvolutionView.tsx","../../src/tabs/WikiTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/tabs/WikiTab/WikiPageControls.tsx — rename/merge/split.\n *\n * Controlled dialogs for the three curation mutations. Non-destructive: on\n * success the parent refetches and paints the returned CurationResult; on\n * failure the pre-mutation snapshot stays (no local partial apply).\n *\n * Styling: Tailwind + shadcn (Button). No legacy CSS classes.\n */\n\nimport type React from \"react\";\nimport { useState } from \"react\";\nimport { renameTopic, mergeTopics, splitTopic } from \"../../api/client\";\nimport type { MemoryProvenance } from \"@contracts\";\nimport { Button } from \"../../components/ui/button\";\n\ninterface ControlsProps {\n\ttopicId: string;\n\tothers: Array<{ id: string; label: string }>;\n\tmembers: MemoryProvenance[];\n\tonMutated: () => void;\n}\n\ntype Mode = \"rename\" | \"merge\" | \"split\" | null;\n\nfunction memberSnippet(id: string, method: string): string {\n\tconst base = id.length > 14 ? id.slice(0, 14) + \"…\" : id;\n\treturn method ? `${base} (${method})` : base;\n}\n\nexport default function WikiPageControls({\n\ttopicId,\n\tothers,\n\tmembers,\n\tonMutated,\n}: ControlsProps): React.ReactElement {\n\tconst [mode, setMode] = useState<Mode>(null);\n\tconst [label, setLabel] = useState(\"\");\n\tconst [target, setTarget] = useState(\"\");\n\tconst [picked, setPicked] = useState<string[]>([]);\n\tconst [busy, setBusy] = useState(false);\n\tconst [error, setError] = useState<string | null>(null);\n\n\tfunction open(m: Exclude<Mode, null>): void {\n\t\tsetMode(m);\n\t\tsetError(null);\n\t\tsetLabel(\"\");\n\t\tsetTarget(\"\");\n\t\tsetPicked([]);\n\t}\n\n\tasync function submit(): Promise<void> {\n\t\tsetBusy(true);\n\t\tsetError(null);\n\t\ttry {\n\t\t\tif (mode === \"rename\") {\n\t\t\t\tawait renameTopic(topicId, label);\n\t\t\t} else if (mode === \"merge\") {\n\t\t\t\tif (!target) {\n\t\t\t\t\tsetError(\"Pick a target topic.\");\n\t\t\t\t\tsetBusy(false);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tawait mergeTopics(topicId, target);\n\t\t\t} else if (mode === \"split\") {\n\t\t\t\tif (picked.length === 0) {\n\t\t\t\t\tsetError(\"Pick at least one memory.\");\n\t\t\t\t\tsetBusy(false);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tawait splitTopic(topicId, picked);\n\t\t\t}\n\t\t\tsetMode(null);\n\t\t\tonMutated();\n\t\t} catch (e) {\n\t\t\tsetError(e instanceof Error ? e.message : String(e));\n\t\t} finally {\n\t\t\tsetBusy(false);\n\t\t}\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t<Button variant=\"outline\" size=\"sm\" onClick={() => open(\"rename\")}>\n\t\t\t\t\tRename\n\t\t\t\t</Button>\n\t\t\t\t<Button variant=\"outline\" size=\"sm\" onClick={() => open(\"merge\")}>\n\t\t\t\t\tMerge into…\n\t\t\t\t</Button>\n\t\t\t\t<Button variant=\"outline\" size=\"sm\" onClick={() => open(\"split\")}>\n\t\t\t\t\tSplit\n\t\t\t\t</Button>\n\t\t\t</div>\n\n\t\t\t{mode && (\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\"\n\t\t\t\t\tonClick={() => setMode(null)}\n\t\t\t\t>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName=\"w-full max-w-md rounded-lg border border-border bg-bg-card p-5 shadow-xl\"\n\t\t\t\t\t\trole=\"dialog\"\n\t\t\t\t\t\taria-modal=\"true\"\n\t\t\t\t\t\taria-label={mode}\n\t\t\t\t\t\tonClick={(e) => e.stopPropagation()}\n\t\t\t\t\t>\n\t\t\t\t\t\t<h3 className=\"mb-3 font-heading text-base font-semibold text-foreground\">\n\t\t\t\t\t\t\t{mode === \"rename\"\n\t\t\t\t\t\t\t\t? \"Rename topic\"\n\t\t\t\t\t\t\t\t: mode === \"merge\"\n\t\t\t\t\t\t\t\t\t? \"Merge into…\"\n\t\t\t\t\t\t\t\t\t: \"Split topic\"}\n\t\t\t\t\t\t</h3>\n\n\t\t\t\t\t\t{mode === \"rename\" && (\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\tvalue={label}\n\t\t\t\t\t\t\t\tplaceholder=\"New label (empty = back to auto)\"\n\t\t\t\t\t\t\t\taria-label=\"New topic label\"\n\t\t\t\t\t\t\t\tautoFocus\n\t\t\t\t\t\t\t\tonChange={(e) => setLabel(e.target.value)}\n\t\t\t\t\t\t\t\tclassName=\"w-full rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t{mode === \"merge\" && (\n\t\t\t\t\t\t\t<select\n\t\t\t\t\t\t\t\tvalue={target}\n\t\t\t\t\t\t\t\taria-label=\"Target topic\"\n\t\t\t\t\t\t\t\tonChange={(e) => setTarget(e.target.value)}\n\t\t\t\t\t\t\t\tclassName=\"w-full rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<option value=\"\">Pick a target topic…</option>\n\t\t\t\t\t\t\t\t{others.map((o) => (\n\t\t\t\t\t\t\t\t\t<option key={o.id} value={o.id}>\n\t\t\t\t\t\t\t\t\t\t{o.label}\n\t\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t{mode === \"split\" && (\n\t\t\t\t\t\t\t<div className=\"max-h-56 overflow-auto rounded-md border border-border/60\">\n\t\t\t\t\t\t\t\t{members.map((m) => (\n\t\t\t\t\t\t\t\t\t<label\n\t\t\t\t\t\t\t\t\t\tkey={m.memoryId}\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex cursor-pointer items-center gap-2 border-b border-border/40 px-3 py-2 text-sm last:border-0 hover:bg-bg-elevated/40\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\t\t\t\tchecked={picked.includes(m.memoryId)}\n\t\t\t\t\t\t\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\t\t\t\t\t\t\tsetPicked((prev) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\te.target.checked\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t? [...prev, m.memoryId]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t: prev.filter((x) => x !== m.memoryId),\n\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"accent-primary\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-mono text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t{memberSnippet(m.memoryId, m.method)}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t</label>\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\n\t\t\t\t\t\t{error && (\n\t\t\t\t\t\t\t<p className=\"mt-3 text-sm text-danger\">{error}</p>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t<div className=\"mt-4 flex justify-end gap-2\">\n\t\t\t\t\t\t\t<Button variant=\"ghost\" size=\"sm\" onClick={() => setMode(null)}>\n\t\t\t\t\t\t\t\tCancel\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t<Button size=\"sm\" onClick={submit} disabled={busy}>\n\t\t\t\t\t\t\t\t{busy ? \"…\" : \"Confirm\"}\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/WikiTab/TopicTimeline.tsx — per-topic timeline.\n *\n * Renders topic memory-addition buckets as a lightweight SVG bar strip (no\n * chart library needed). X = time bucket, bar height = memories added.\n * Fetches GET /api/wiki/topic/:topicId/timeline.\n *\n * Styling: Tailwind + shadcn (Card). No legacy CSS classes.\n */\n\nimport type React from \"react\";\nimport { useCallback } from \"react\";\nimport { useApi } from \"../../hooks/useApi\";\nimport { fetchTopicTimeline } from \"../../api/client\";\nimport type { TopicTimelineResponse } from \"@contracts\";\n\nconst W = 720;\nconst H = 56;\nconst BAR_W = 10;\nconst GAP = 3;\n\ninterface Props {\n\ttopicId: string;\n}\n\nfunction fmtBucket(ts: number): string {\n\tif (!ts) return \"—\";\n\treturn new Date(ts).toLocaleDateString();\n}\n\nexport default function TopicTimeline({ topicId }: Props): React.ReactElement {\n\tconst { data, error } = useApi<TopicTimelineResponse>(\n\t\tuseCallback(() => fetchTopicTimeline(topicId), [topicId]),\n\t\t{},\n\t);\n\n\tif (error) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-4 text-sm text-muted-foreground\">\n\t\t\t\tTimeline unavailable.\n\t\t\t</div>\n\t\t);\n\t}\n\tif (!data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-4 text-sm text-muted-foreground\">\n\t\t\t\tLoading timeline…\n\t\t\t</div>\n\t\t);\n\t}\n\n\tconst { buckets, total } = data;\n\tconst max = Math.max(...buckets.map((b) => b.count), 1);\n\tconst totalWidth = buckets.length * (BAR_W + GAP);\n\tconst scale = Math.min(1, (W - 24) / Math.max(totalWidth, 1));\n\n\treturn (\n\t\t<div className=\"rounded-lg border border-border bg-bg-card p-4\">\n\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\tMemory timeline{\" \"}\n\t\t\t\t<span className=\"font-normal text-xs\">\n\t\t\t\t\t({total} memory{total !== 1 ? \"ies\" : \"y\"} · daily buckets)\n\t\t\t\t</span>\n\t\t\t</h3>\n\t\t\t{buckets.length === 0 ? (\n\t\t\t\t<p className=\"text-sm text-muted-foreground\">No timeline data yet.</p>\n\t\t\t) : (\n\t\t\t\t<>\n\t\t\t\t\t<svg\n\t\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\t\theight={H}\n\t\t\t\t\t\tviewBox={`0 0 ${Math.max(W, totalWidth * scale)} ${H}`}\n\t\t\t\t\t\trole=\"img\"\n\t\t\t\t\t\taria-label=\"Memory additions over time\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{buckets.map((b, i) => {\n\t\t\t\t\t\t\tconst x = i * (BAR_W + GAP) * scale;\n\t\t\t\t\t\t\tconst h = Math.max(3, (b.count / max) * (H - 20));\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\t\t\tkey={`${b.bucket}-${i}`}\n\t\t\t\t\t\t\t\t\tx={x}\n\t\t\t\t\t\t\t\t\ty={H - 6 - h}\n\t\t\t\t\t\t\t\t\twidth={Math.max(2, BAR_W * scale)}\n\t\t\t\t\t\t\t\t\theight={h}\n\t\t\t\t\t\t\t\t\trx={2}\n\t\t\t\t\t\t\t\t\tfill=\"hsl(var(--primary))\"\n\t\t\t\t\t\t\t\t\topacity={0.85}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<title>{`${fmtBucket(b.bucket)}: ${b.count}`}</title>\n\t\t\t\t\t\t\t\t</rect>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</svg>\n\t\t\t\t\t<p className=\"mt-1 text-xs text-muted-foreground\">\n\t\t\t\t\t\tFirst display: {fmtBucket(buckets[0].bucket)} · last:\n\t\t\t\t\t\t{fmtBucket(buckets[buckets.length - 1].bucket)}\n\t\t\t\t\t</p>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/WikiTab/WikiPage.tsx — single wiki topic page.\n *\n * Renders the extractive summary, key member memories, the member provenance\n * table (memory → session/assigned-at/method), related topics (resolved from\n * the wiki index), and the per-topic memory timeline. Mutations\n * (rename/merge/split) delegate to WikiPageControls; on mutation success the\n * page + index are refetched.\n *\n * Styling: Tailwind + shadcn (Card, Badge, Button) — no legacy CSS.\n */\n\nimport type React from \"react\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport { useApi } from \"../../hooks/useApi\";\nimport { fetchWikiTopic, fetchWikiIndex } from \"../../api/client\";\nimport type { WikiPageResponse, WikiIndexResponse } from \"@contracts\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { Card, CardContent } from \"../../components/ui/card\";\nimport WikiPageControls from \"./WikiPageControls\";\nimport TopicTimeline from \"./TopicTimeline\";\n\ninterface WikiPageProps {\n\ttopicId: string;\n\tonBack: () => void;\n}\n\nfunction fmtTs(ms: number): string {\n\tif (!ms) return \"—\";\n\treturn new Date(ms).toLocaleString();\n}\n\nconst METHOD_LABELS: Record<string, string> = {\n\t\"kmeans+tfidf\": \"kmeans\",\n\tmerge: \"merge\",\n\tsplit: \"split\",\n\tmanual: \"manual\",\n};\n\nexport default function WikiPage({\n\ttopicId,\n\tonBack,\n}: WikiPageProps): React.ReactElement {\n\tconst [dirty, setDirty] = useState(0);\n\tconst bump = useCallback(() => setDirty((d) => d + 1), []);\n\n\tconst { data: page, error, loading } = useApi<WikiPageResponse>(\n\t\tuseCallback(() => fetchWikiTopic(topicId), [topicId, dirty]),\n\t\t{},\n\t);\n\tconst { data: index } = useApi<WikiIndexResponse>(\n\t\tuseCallback(() => fetchWikiIndex(), []),\n\t\t{},\n\t);\n\n\tconst labelOf = useMemo(() => {\n\t\tconst map = new Map<string, string>();\n\t\tfor (const t of index?.topics ?? []) map.set(t.id, t.label);\n\t\treturn map;\n\t}, [index]);\n\n\tif (error && !page) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger\">\n\t\t\t\tError loading topic: {error.message}\n\t\t\t</div>\n\t\t);\n\t}\n\tif (loading && !page) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tLoading topic…\n\t\t\t</div>\n\t\t);\n\t}\n\tif (!page) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tNo topic data available.\n\t\t\t</div>\n\t\t);\n\t}\n\n\tconst otherTopics = (index?.topics ?? [])\n\t\t.filter((t) => t.id !== topicId)\n\t\t.map((t) => ({ id: t.id, label: t.label }));\n\n\treturn (\n\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t<Button variant=\"outline\" size=\"sm\" onClick={onBack}>\n\t\t\t\t\t\t← Wiki\n\t\t\t\t\t</Button>\n\t\t\t\t\t<h2 className=\"font-heading text-lg font-semibold\">\n\t\t\t\t\t\t{page.topic.label}\n\t\t\t\t\t</h2>\n\t\t\t\t\t{page.topic.edited && <Badge variant=\"outline\">edited</Badge>}\n\t\t\t\t\t<Badge variant=\"default\">\n\t\t\t\t\t\t{page.provenance.length} memories\n\t\t\t\t\t</Badge>\n\t\t\t\t</div>\n\t\t\t\t<WikiPageControls\n\t\t\t\t\ttopicId={topicId}\n\t\t\t\t\tothers={otherTopics}\n\t\t\t\t\tmembers={page.provenance}\n\t\t\t\t\tonMutated={bump}\n\t\t\t\t/>\n\t\t\t</div>\n\n\t\t\t{page.summary && (\n\t\t\t\t<Card>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<h3 className=\"mb-1 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\t\t\t\tSummary\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<p className=\"text-sm leading-relaxed text-foreground/90\">\n\t\t\t\t\t\t\t{page.summary}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t)}\n\n\t\t\t{page.keyMemories.length > 0 && (\n\t\t\t\t<Card>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\t\t\t\tKey memories\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<ul className=\"flex flex-col gap-2\">\n\t\t\t\t\t\t\t{page.keyMemories.map((m) => (\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tkey={m.memoryId}\n\t\t\t\t\t\t\t\t\tclassName=\"rounded-md border border-border/60 bg-bg-elevated/40 p-3 text-sm\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<p className=\"line-clamp-3 text-foreground/90\">{m.content}</p>\n\t\t\t\t\t\t\t\t\t<p className=\"mt-1 text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t{m.memoryId} · {fmtTs(m.timestamp)}\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t)}\n\n\t\t\t<TopicTimeline topicId={topicId} />\n\n\t\t\t{page.provenance.length > 0 && (\n\t\t\t\t<Card>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\t\t\t\tProvenance\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<div className=\"max-h-72 overflow-auto rounded-md border border-border/60\">\n\t\t\t\t\t\t\t<table className=\"w-full text-sm\">\n\t\t\t\t\t\t\t\t<thead className=\"sticky top-0 bg-bg-card\">\n\t\t\t\t\t\t\t\t\t<tr className=\"border-b border-border text-left text-xs uppercase text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t<th className=\"px-3 py-2 font-medium\">Memory</th>\n\t\t\t\t\t\t\t\t\t\t<th className=\"px-3 py-2 font-medium\">Session</th>\n\t\t\t\t\t\t\t\t\t\t<th className=\"px-3 py-2 font-medium\">Assigned</th>\n\t\t\t\t\t\t\t\t\t\t<th className=\"px-3 py-2 font-medium\">Method</th>\n\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t{page.provenance.map((p) => (\n\t\t\t\t\t\t\t\t\t\t<tr\n\t\t\t\t\t\t\t\t\t\t\tkey={p.memoryId}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"border-b border-border/40 last:border-0\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-1.5 font-mono text-xs\">\n\t\t\t\t\t\t\t\t\t\t\t\t{p.memoryId}\n\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-1.5 text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t{p.sessionId || \"unknown\"}\n\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-1.5 text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t{fmtTs(p.assignedAt)}\n\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-1.5\">\n\t\t\t\t\t\t\t\t\t\t\t\t<Badge variant=\"outline\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t{METHOD_LABELS[p.method] ?? p.method}\n\t\t\t\t\t\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t)}\n\n\t\t\t{page.relatedTopicIds.length > 0 && (\n\t\t\t\t<Card>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\t\t\t\tRelated topics\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<div className=\"flex flex-wrap gap-2\">\n\t\t\t\t\t\t\t{page.relatedTopicIds.map((id) => (\n\t\t\t\t\t\t\t\t<Badge key={id} variant=\"accent\">\n\t\t\t\t\t\t\t\t\t{labelOf.get(id) ?? id}\n\t\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/WikiTab/TopicEvolutionGraph.tsx — D3 evolution.\n *\n * Force-directed graph of wiki topics over time. Nodes are topics (radius scales\n * with memoryCount); edges are merge/split curation events. A bucket scrubber\n * (from the response buckets) dims nodes that had no activity up to the selected\n * time window — a lightweight \"growth over time\" view.\n *\n * Self-contained force simulation (Coulomb repulsion + Hooke attraction +\n * center gravity) — the codebase deliberately avoids external graph libraries\n * (see memory-map-layout.ts). No data is fabricated: only real node/edge/bucket\n * fields from the contract are used. Styling is Tailwind.\n */\n\nimport type React from \"react\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { TopicEvolutionResponse } from \"@contracts\";\n\n// ── Simulation constants ────────────────────────────────────────────────\nconst W = 900;\nconst H = 560;\nconst REPULSION = 60_000;\nconst ATTRACTION = 0.012;\nconst CENTER_GRAVITY = 0.012;\nconst DAMPING = 0.8;\nconst SPEED_LIMIT = 2;\nconst MIN_VELOCITY = 0.02;\nconst MAX_ITERATIONS = 250;\n\ninterface SimNode {\n\tid: string;\n\tlabel: string;\n\tmemoryCount: number;\n\tpos: { x: number; y: number };\n\tvx: number;\n\tvy: number;\n}\n\ninterface SimEdge {\n\tsource: number;\n\ttarget: number;\n\tkind: \"merge\" | \"split\";\n}\n\nfunction edgeColor(kind: \"merge\" | \"split\"): string {\n\treturn kind === \"merge\" ? \"#f59e0b\" : \"#22c55e\"; // amber / green\n}\n\nfunction initialLayout(nodes: TopicEvolutionResponse[\"nodes\"]): SimNode[] {\n\treturn nodes.map((n, i) => {\n\t\tconst angle = (2 * Math.PI * i) / Math.max(nodes.length, 1);\n\t\treturn {\n\t\t\tid: n.id,\n\t\t\tlabel: n.label,\n\t\t\tmemoryCount: n.memoryCount,\n\t\t\tpos: { x: Math.cos(angle) * 220 + W / 2, y: Math.sin(angle) * 220 + H / 2 },\n\t\t\tvx: 0,\n\t\t\tvy: 0,\n\t\t};\n\t});\n}\n\nfunction applyForces(sim: { nodes: SimNode[]; edges: SimEdge[] }): void {\n\tconst { nodes, edges } = sim;\n\tfor (let i = 0; i < nodes.length; i++) {\n\t\tconst n = nodes[i];\n\t\tlet fx = 0;\n\t\tlet fy = 0;\n\t\tfor (let j = 0; j < nodes.length; j++) {\n\t\t\tif (i === j) continue;\n\t\t\tconst dx = n.pos.x - nodes[j].pos.x;\n\t\t\tconst dy = n.pos.y - nodes[j].pos.y;\n\t\t\tconst distSq = dx * dx + dy * dy || 1;\n\t\t\tconst dist = Math.sqrt(distSq);\n\t\t\tfx += (dx / dist) * (REPULSION / distSq);\n\t\t\tfy += (dy / dist) * (REPULSION / distSq);\n\t\t}\n\t\tfor (const e of edges) {\n\t\t\tlet other: number;\n\t\t\tif (e.source === i) other = e.target;\n\t\t\telse if (e.target === i) other = e.source;\n\t\t\telse continue;\n\t\t\tconst dx = nodes[other].pos.x - n.pos.x;\n\t\t\tconst dy = nodes[other].pos.y - n.pos.y;\n\t\t\tfx += dx * ATTRACTION;\n\t\t\tfy += dy * ATTRACTION;\n\t\t}\n\t\tfx -= n.pos.x * CENTER_GRAVITY;\n\t\tfy -= n.pos.y * CENTER_GRAVITY;\n\t\tn.vx = (n.vx + fx) * DAMPING;\n\t\tn.vy = (n.vy + fy) * DAMPING;\n\t\tconst speed = Math.sqrt(n.vx * n.vx + n.vy * n.vy);\n\t\tif (speed > SPEED_LIMIT) {\n\t\t\tn.vx = (n.vx / speed) * SPEED_LIMIT;\n\t\t\tn.vy = (n.vy / speed) * SPEED_LIMIT;\n\t\t}\n\t\tif (speed > MIN_VELOCITY) {\n\t\t\tn.pos.x += n.vx;\n\t\t\tn.pos.y += n.vy;\n\t\t}\n\t}\n}\n\ninterface Props {\n\tdata: TopicEvolutionResponse;\n}\n\nexport default function TopicEvolutionGraph({\n\tdata,\n}: Props): React.ReactElement {\n\tconst simRef = useRef<{\n\t\tnodes: SimNode[];\n\t\tedges: SimEdge[];\n\t\ttimeByActivity: Map<string, number> | null;\n\t} | null>(null);\n\tconst animRef = useRef(0);\n\tconst [, setFrame] = useState(0);\n\tconst [scrub, setScrub] = useState<number>(0);\n\n\t// Initialize simulation from data (re-run when data changes).\n\tuseEffect(() => {\n\t\tconst nodes = initialLayout(data.nodes);\n\t\tconst indexById = new Map(nodes.map((n, i) => [n.id, i]));\n\t\tconst edges: SimEdge[] = data.edges\n\t\t\t.map((e) => {\n\t\t\t\tconst si = indexById.get(e.source);\n\t\t\t\tconst ti = indexById.get(e.target);\n\t\t\t\tif (si === undefined || ti === undefined || si === ti) return null;\n\t\t\t\treturn { source: si, target: ti, kind: e.kind };\n\t\t\t})\n\t\t\t.filter((e): e is SimEdge => e !== null);\n\t\t// Latest activity per node (from merge/split edge timestamps).\n\t\tconst timeByActivity = new Map<string, number>();\n\t\tfor (const e of data.edges) {\n\t\t\ttimeByActivity.set(e.source, Math.max(timeByActivity.get(e.source) ?? 0, e.at));\n\t\t\ttimeByActivity.set(e.target, Math.max(timeByActivity.get(e.target) ?? 0, e.at));\n\t\t}\n\t\tsimRef.current = { nodes, edges, timeByActivity };\n\t\tsetFrame(1);\n\t\treturn () => cancelAnimationFrame(animRef.current);\n\t}, [data]);\n\n\t// Run the force simulation to stable layout.\n\tuseEffect(() => {\n\t\tif (!simRef.current) return;\n\t\tlet iter = 0;\n\t\tconst tick = () => {\n\t\t\tif (!simRef.current || iter >= MAX_ITERATIONS) return;\n\t\t\tapplyForces(simRef.current);\n\t\t\titer++;\n\t\t\tsetFrame(iter);\n\t\t\tanimRef.current = requestAnimationFrame(tick);\n\t\t};\n\t\tanimRef.current = requestAnimationFrame(tick);\n\t\treturn () => cancelAnimationFrame(animRef.current);\n\t}, [data]);\n\n\tconst sim = simRef.current;\n\n\tconst scrubMax = Math.max(data.buckets.length - 1, 0);\n\tconst scrubBucket = useMemo(() => {\n\t\tif (data.buckets.length === 0) return null;\n\t\tconst idx = Math.min(scrub, data.buckets.length - 1);\n\t\treturn data.buckets[idx].bucket;\n\t}, [scrub, data.buckets]);\n\n\tif (!sim || data.nodes.length === 0) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tNo evolution data yet. Merge or split topics to see connections, then\n\t\t\t\tcheck back after a rebuild.\n\t\t\t</div>\n\t\t);\n\t}\n\n\tconst activeSet =\n\t\tscrubBucket == null || !sim.timeByActivity\n\t\t\t? null\n\t\t\t: new Set(\n\t\t\t\t\t[...sim.timeByActivity.entries()]\n\t\t\t\t\t\t.filter(([, t]) => t <= scrubBucket)\n\t\t\t\t\t\t.map(([id]) => id),\n\t\t\t\t);\n\n\treturn (\n\t\t<div className=\"flex flex-col gap-3\">\n\t\t\t{/* Scrubber */}\n\t\t\t{data.buckets.length > 1 && (\n\t\t\t\t<div className=\"flex items-center gap-3\">\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"range\"\n\t\t\t\t\t\tmin={0}\n\t\t\t\t\t\tmax={scrubMax}\n\t\t\t\t\t\tvalue={scrub}\n\t\t\t\t\t\tonChange={(e) => setScrub(Number(e.target.value))}\n\t\t\t\t\t\tclassName=\"w-full accent-primary\"\n\t\t\t\t\t\taria-label=\"Scrub through topic activity time\"\n\t\t\t\t\t/>\n\t\t\t\t\t<span className=\"whitespace-nowrap text-xs text-muted-foreground\">\n\t\t\t\t\t\t{scrubBucket ? new Date(scrubBucket).toLocaleDateString() : \"all\"}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* SVG graph */}\n\t\t\t<svg\n\t\t\t\twidth=\"100%\"\n\t\t\t\theight={H}\n\t\t\t\tviewBox={`0 0 ${W} ${H}`}\n\t\t\t\trole=\"img\"\n\t\t\t\taria-label=\"Topic evolution graph\"\n\t\t\t\tclassName=\"rounded-lg border border-border/60 bg-bg-card\"\n\t\t\t>\n\t\t\t\t{sim.edges.map((e, i) => {\n\t\t\t\t\tconst a = sim.nodes[e.source];\n\t\t\t\t\tconst b = sim.nodes[e.target];\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<line\n\t\t\t\t\t\t\tkey={`edge-${i}`}\n\t\t\t\t\t\t\tx1={a.pos.x}\n\t\t\t\t\t\t\ty1={a.pos.y}\n\t\t\t\t\t\t\tx2={b.pos.x}\n\t\t\t\t\t\t\ty2={b.pos.y}\n\t\t\t\t\t\t\tstroke={edgeColor(e.kind)}\n\t\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t\t\tstrokeDasharray={e.kind === \"split\" ? \"4 3\" : undefined}\n\t\t\t\t\t\t\topacity={0.5}\n\t\t\t\t\t\t/>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t\t{sim.nodes.map((n, i) => {\n\t\t\t\t\tconst active =\n\t\t\t\t\t\tactiveSet == null || activeSet.size === 0 || activeSet.has(n.id);\n\t\t\t\t\tconst r = Math.min(32, 8 + n.memoryCount * 3);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<g key={`node-${i}`} opacity={active ? 1 : 0.15}>\n\t\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\t\tcx={n.pos.x}\n\t\t\t\t\t\t\t\tcy={n.pos.y}\n\t\t\t\t\t\t\t\tr={r}\n\t\t\t\t\t\t\t\tfill=\"hsl(var(--primary) / 0.18)\"\n\t\t\t\t\t\t\t\tstroke=\"hsl(var(--primary))\"\n\t\t\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t\tx={n.pos.x}\n\t\t\t\t\t\t\t\ty={n.pos.y + 4}\n\t\t\t\t\t\t\t\ttextAnchor=\"middle\"\n\t\t\t\t\t\t\t\tfontSize=\"10px\"\n\t\t\t\t\t\t\t\tfill=\"hsl(var(--foreground))\"\n\t\t\t\t\t\t\t\tclassName=\"pointer-events-none\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{n.label.length > 16 ? n.label.slice(0, 15) + \"…\" : n.label}\n\t\t\t\t\t\t\t</text>\n\t\t\t\t\t\t</g>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</svg>\n\n\t\t\t<div className=\"flex items-center gap-4 text-xs text-muted-foreground\">\n\t\t\t\t<span className=\"flex items-center gap-1.5\">\n\t\t\t\t\t<span className=\"inline-block h-0.5 w-6 bg-amber-500\" /> merge\n\t\t\t\t</span>\n\t\t\t\t<span className=\"flex items-center gap-1.5\">\n\t\t\t\t\t<span className=\"inline-block h-0.5 w-6 border-t border-dashed border-green-500\" />\n\t\t\t\t\tsplit\n\t\t\t\t</span>\n\t\t\t\t<span>\n\t\t\t\t\t{data.nodes.length} nodes · {data.edges.length} curation events\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/WikiTab/TopicEvolutionView.tsx — planet evolution.\n *\n * Thin shell over TopicEvolutionGraph: fetches GET /api/wiki/evolution via\n * useApi and refetches when a `wiki_rebuilt` SSE event lands (emitted by the\n * extension after a topic-model rebuild), so the graph + scrubber stay live\n * between polls. No data is fabricated — only the contract fields are used.\n *\n * Styling: Tailwind + shadcn (Card). No legacy CSS classes.\n */\n\nimport type React from \"react\";\nimport { useCallback, useEffect, useMemo } from \"react\";\nimport { useApi } from \"../../hooks/useApi\";\nimport { useSSE } from \"../../hooks/useSSE\";\nimport { fetchTopicEvolution } from \"../../api/client\";\nimport type { TopicEvolutionResponse, SseEvent } from \"@contracts\";\nimport { Card, CardContent } from \"../../components/ui/card\";\nimport TopicEvolutionGraph from \"./TopicEvolutionGraph\";\n\nfunction isWikiRebuilt(e: SseEvent): e is Extract<SseEvent, { type: \"wiki_rebuilt\" }> {\n\treturn e.type === \"wiki_rebuilt\";\n}\n\nexport default function TopicEvolutionView(): React.ReactElement {\n\tconst { data, error, loading, refetch } = useApi<TopicEvolutionResponse>(\n\t\tuseCallback(() => fetchTopicEvolution(), []),\n\t\t{ pollInterval: 60_000 },\n\t);\n\n\tconst { events } = useSSE();\n\tconst lastRebuiltTs = useMemo(() => {\n\t\tconst rebuilt = events.filter(isWikiRebuilt);\n\t\tif (rebuilt.length === 0) return null;\n\t\treturn rebuilt[rebuilt.length - 1].ts;\n\t}, [events]);\n\n\tuseEffect(() => {\n\t\tif (lastRebuiltTs != null) refetch();\n\t}, [lastRebuiltTs, refetch]);\n\n\tif (error && !data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger\">\n\t\t\t\tError loading evolution graph: {error.message}\n\t\t\t</div>\n\t\t);\n\t}\n\tif (loading && !data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tLoading evolution graph…\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<Card>\n\t\t\t<CardContent>\n\t\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\t\tTopic evolution\n\t\t\t\t</h3>\n\t\t\t\t{data ? (\n\t\t\t\t\t<TopicEvolutionGraph data={data} />\n\t\t\t\t) : (\n\t\t\t\t\t<p className=\"text-sm text-muted-foreground\">No data yet.</p>\n\t\t\t\t)}\n\t\t\t</CardContent>\n\t\t</Card>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/WikiTab.tsx — Wiki Revival (W3): wiki landing list.\n *\n * Replaces TopicsTab in the App registry (TopicsTab.tsx kept, unused). Renders\n * the wiki index: each auto-categorized topic with its resolved label (edited\n * badge when user-renamed), member count, curation badges (label/merge/split),\n * and a click-to-open that pushes a client-side page state to WikiPage.\n *\n * Styling is Tailwind + shadcn (Card, Badge, Button) — no legacy CSS classes.\n */\n\nimport type React from \"react\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport { useApi } from \"../hooks/useApi\";\nimport { fetchWikiIndex } from \"../api/client\";\nimport type { WikiIndexEntry, WikiIndexResponse } from \"@contracts\";\nimport { Badge } from \"../components/ui/badge\";\nimport { Button } from \"../components/ui/button\";\nimport { Toggle } from \"../components/ui/toggle\";\nimport WikiPage from \"./WikiTab/WikiPage\";\nimport TopicEvolutionView from \"./WikiTab/TopicEvolutionView\";\n\ntype WikiView = \"list\" | \"evolution\";\n\nconst KIND_BADGES: Record<string, \"default\" | \"accent\" | \"warning\"> = {\n\tlabel: \"accent\",\n\tmerge: \"warning\",\n\tsplit: \"default\",\n};\n\nfunction fmtTs(ms: number | null): string {\n\tif (!ms) return \"—\";\n\treturn new Date(ms).toLocaleString();\n}\n\nfunction ViewToggle({\n\tview,\n\tonChange,\n}: {\n\tview: WikiView;\n\tonChange: (v: WikiView) => void;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"flex gap-1\">\n\t\t\t<Toggle pressed={view === \"list\"} onClick={() => onChange(\"list\")}>\n\t\t\t\tTopics\n\t\t\t</Toggle>\n\t\t\t<Toggle\n\t\t\t\tpressed={view === \"evolution\"}\n\t\t\t\tonClick={() => onChange(\"evolution\")}\n\t\t\t>\n\t\t\t\tEvolution\n\t\t\t</Toggle>\n\t\t</div>\n\t);\n}\n\ninterface RowProps {\n\tentry: WikiIndexEntry;\n\tonOpen: (id: string) => void;\n}\n\nfunction TopicRow({ entry, onOpen }: RowProps): React.ReactElement {\n\treturn (\n\t\t<tr className=\"border-b border-border/60 last:border-0 hover:bg-bg-elevated/40\">\n\t\t\t<td className=\"py-2 pr-3\">\n\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t<span className=\"font-medium text-foreground\">{entry.label}</span>\n\t\t\t\t\t{entry.edited && <Badge variant=\"outline\">edited</Badge>}\n\t\t\t\t</div>\n\t\t\t</td>\n\t\t\t<td className=\"py-2 pr-3 text-sm text-muted-foreground\">\n\t\t\t\t{entry.memoryCount}\n\t\t\t</td>\n\t\t\t<td className=\"py-2 pr-3\">\n\t\t\t\t<div className=\"flex flex-wrap gap-1\">\n\t\t\t\t\t{entry.overrideKinds.map((k) => (\n\t\t\t\t\t\t<Badge key={k} variant={KIND_BADGES[k] ?? \"default\"}>\n\t\t\t\t\t\t\t{k}\n\t\t\t\t\t\t</Badge>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</td>\n\t\t\t<td className=\"py-2 pr-3 text-xs text-muted-foreground\">\n\t\t\t\t{fmtTs(entry.lastUpdated)}\n\t\t\t</td>\n\t\t\t<td className=\"py-2 text-right\">\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\tonClick={() => onOpen(entry.id)}\n\t\t\t\t>\n\t\t\t\t\tOpen\n\t\t\t\t</Button>\n\t\t\t</td>\n\t\t</tr>\n\t);\n}\n\nexport default function WikiTab(): React.ReactElement {\n\tconst { data, loading, error } = useApi<WikiIndexResponse>(\n\t\tuseCallback(() => fetchWikiIndex(), []),\n\t\t{ pollInterval: 30_000 },\n\t);\n\tconst [view, setView] = useState<WikiView>(\"list\");\n\tconst [query, setQuery] = useState(\"\");\n\tconst [openId, setOpenId] = useState<string | null>(null);\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((t) =>\n\t\t\tt.label.toLowerCase().includes(q),\n\t\t);\n\t}, [data, query]);\n\n\tif (openId) {\n\t\treturn <WikiPage topicId={openId} onBack={() => setOpenId(null)} />;\n\t}\n\n\tif (view === \"evolution\") {\n\t\treturn (\n\t\t\t<div className=\"flex flex-col gap-3\">\n\t\t\t\t<ViewToggle view={view} onChange={setView} />\n\t\t\t\t<TopicEvolutionView />\n\t\t\t</div>\n\t\t);\n\t}\n\n\tif (error && !data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger\">\n\t\t\t\tError loading wiki: {error.message}\n\t\t\t</div>\n\t\t);\n\t}\n\tif (loading && !data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tLoading wiki…\n\t\t\t</div>\n\t\t);\n\t}\n\tif (!data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tNo wiki data available.\n\t\t\t</div>\n\t\t);\n\t}\n\tif (data.totalTopics === 0) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\t<h3 className=\"mb-2 font-heading text-base text-foreground\">Wiki</h3>\n\t\t\t\t<p>\n\t\t\t\t\tNo topics yet. Topics are auto-generated after every Nth 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 className=\"mt-2\">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=\"flex flex-col gap-4\">\n\t\t\t<div className=\"flex flex-wrap items-end justify-between gap-2\">\n\t\t\t\t<div className=\"flex items-center gap-3\">\n\t\t\t\t\t<ViewToggle view={view} onChange={setView} />\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2 className=\"font-heading text-lg font-semibold\">Wiki</h2>\n\t\t\t\t\t\t<p className=\"text-sm text-muted-foreground\">\n\t\t\t\t\t\t\t{data.totalTopics} topic{data.totalTopics !== 1 ? \"s\" : \"\"} ·{\" \"}\n\t\t\t\t\t\t\t{data.totalMemories} assigned memori\n\t\t\t\t\t\t\t{data.totalMemories !== 1 ? \"es\" : \"y\"}\n\t\t\t\t\t\t\t{data.lastRebuildAt != null && (\n\t\t\t\t\t\t\t\t<> · last rebuild {fmtTs(data.lastRebuildAt)}</>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<input\n\t\t\t\t\ttype=\"search\"\n\t\t\t\t\tplaceholder=\"Filter topics by label…\"\n\t\t\t\t\taria-label=\"Filter topics by label\"\n\t\t\t\t\tvalue={query}\n\t\t\t\t\tonChange={(e) => setQuery(e.target.value)}\n\t\t\t\t\tclassName=\"w-64 rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary\"\n\t\t\t\t/>\n\t\t\t</div>\n\n\t\t\t<div className=\"overflow-x-auto rounded-lg border border-border bg-bg-card\">\n\t\t\t\t<table className=\"w-full table-fixed text-sm\">\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr className=\"border-b border-border text-left text-xs uppercase text-muted-foreground\">\n\t\t\t\t\t\t\t<th className=\"w-1/3 px-4 py-2 font-medium\">Label</th>\n\t\t\t\t\t\t\t<th className=\"w-16 py-2 font-medium\">Memories</th>\n\t\t\t\t\t\t\t<th className=\"w-40 py-2 font-medium\">Badges</th>\n\t\t\t\t\t\t\t<th className=\"w-40 py-2 font-medium\">Last updated</th>\n\t\t\t\t\t\t\t<th className=\"w-20 py-2\" />\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<TopicRow key={t.id} entry={t} onOpen={setOpenId} />\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\n\t\t\t\t\t\t\t\t\tcolSpan={5}\n\t\t\t\t\t\t\t\t\tclassName=\"px-4 py-6 text-center text-muted-foreground\"\n\t\t\t\t\t\t\t\t>\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</div>\n\t\t</div>\n\t);\n}\n"],"names":["memberSnippet","id","method","base","WikiPageControls","topicId","others","members","onMutated","mode","setMode","useState","label","setLabel","target","setTarget","picked","setPicked","busy","setBusy","error","setError","open","m","submit","renameTopic","mergeTopics","splitTopic","e","jsxs","Fragment","jsx","Button","o","prev","x","W","H","BAR_W","GAP","fmtBucket","ts","TopicTimeline","data","useApi","useCallback","fetchTopicTimeline","buckets","total","max","b","totalWidth","scale","i","h","fmtTs","ms","METHOD_LABELS","WikiPage","onBack","dirty","setDirty","bump","d","page","loading","fetchWikiTopic","index","fetchWikiIndex","labelOf","useMemo","map","t","otherTopics","Badge","Card","CardContent","p","REPULSION","ATTRACTION","CENTER_GRAVITY","DAMPING","SPEED_LIMIT","MIN_VELOCITY","MAX_ITERATIONS","edgeColor","kind","initialLayout","nodes","n","angle","applyForces","sim","edges","fx","fy","j","dx","dy","distSq","dist","other","speed","TopicEvolutionGraph","simRef","useRef","animRef","setFrame","scrub","setScrub","useEffect","indexById","si","ti","timeByActivity","iter","tick","scrubMax","scrubBucket","idx","activeSet","a","active","r","isWikiRebuilt","TopicEvolutionView","refetch","fetchTopicEvolution","events","useSSE","lastRebuiltTs","rebuilt","KIND_BADGES","ViewToggle","view","onChange","Toggle","TopicRow","entry","onOpen","k","WikiTab","setView","query","setQuery","openId","setOpenId","filtered","q"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{r as s,j as n,t as i,a4 as d}from"./index-CL6Af_JZ.js";const l=d("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",{variants:{variant:{default:"bg-primary text-primary-foreground hover:bg-primary/90 glow-primary",outline:"border border-border bg-transparent hover:bg-bg-elevated hover:text-foreground",ghost:"hover:bg-bg-elevated hover:text-foreground",glass:"glass-panel electric-hover"},size:{default:"h-9 px-4 py-2",sm:"h-8 rounded-md px-3 text-xs",lg:"h-10 rounded-md px-8",icon:"h-9 w-9"}},defaultVariants:{variant:"default",size:"default"}}),u=s.forwardRef(({className:e,variant:t,size:r,...a},o)=>n.jsx("button",{ref:o,className:i(l({variant:t,size:r,className:e})),...a}));u.displayName="Button";export{u as B};
2
- //# sourceMappingURL=button-D-9nb4Bw.js.map
1
+ import{r as s,j as n,t as i,a4 as d}from"./index-iuxgtzEW.js";const l=d("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",{variants:{variant:{default:"bg-primary text-primary-foreground hover:bg-primary/90 glow-primary",outline:"border border-border bg-transparent hover:bg-bg-elevated hover:text-foreground",ghost:"hover:bg-bg-elevated hover:text-foreground",glass:"glass-panel electric-hover"},size:{default:"h-9 px-4 py-2",sm:"h-8 rounded-md px-3 text-xs",lg:"h-10 rounded-md px-8",icon:"h-9 w-9"}},defaultVariants:{variant:"default",size:"default"}}),u=s.forwardRef(({className:e,variant:t,size:r,...a},o)=>n.jsx("button",{ref:o,className:i(l({variant:t,size:r,className:e})),...a}));u.displayName="Button";export{u as B};
2
+ //# sourceMappingURL=button-DhQQAJGm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"button-D-9nb4Bw.js","sources":["../../src/components/ui/button.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"../../utils/cn\";\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90 glow-primary\",\n outline: \"border border-border bg-transparent hover:bg-bg-elevated hover:text-foreground\",\n ghost: \"hover:bg-bg-elevated hover:text-foreground\",\n glass: \"glass-panel electric-hover\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 rounded-md px-3 text-xs\",\n lg: \"h-10 rounded-md px-8\",\n icon: \"h-9 w-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, ...props }, ref) => (\n <button\n ref={ref}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n ),\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n"],"names":["buttonVariants","cva","Button","React.forwardRef","className","variant","size","props","ref","jsx","cn"],"mappings":"8DAIA,MAAMA,EAAiBC,EACrB,2SACA,CACE,SAAU,CACR,QAAS,CACP,QAAS,sEACT,QAAS,iFACT,MAAO,6CACP,MAAO,4BAAA,EAET,KAAM,CACJ,QAAS,gBACT,GAAI,8BACJ,GAAI,uBACJ,KAAM,SAAA,CACR,EAEF,gBAAiB,CACf,QAAS,UACT,KAAM,SAAA,CACR,CAEJ,EAMMC,EAASC,EAAAA,WACb,CAAC,CAAE,UAAAC,EAAW,QAAAC,EAAS,KAAAC,EAAM,GAAGC,CAAA,EAASC,IACvCC,EAAAA,IAAC,SAAA,CACC,IAAAD,EACA,UAAWE,EAAGV,EAAe,CAAE,QAAAK,EAAS,KAAAC,EAAM,UAAAF,CAAA,CAAW,CAAC,EACzD,GAAGG,CAAA,CAAA,CAGV,EACAL,EAAO,YAAc"}
1
+ {"version":3,"file":"button-DhQQAJGm.js","sources":["../../src/components/ui/button.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"../../utils/cn\";\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90 glow-primary\",\n outline: \"border border-border bg-transparent hover:bg-bg-elevated hover:text-foreground\",\n ghost: \"hover:bg-bg-elevated hover:text-foreground\",\n glass: \"glass-panel electric-hover\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 rounded-md px-3 text-xs\",\n lg: \"h-10 rounded-md px-8\",\n icon: \"h-9 w-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, ...props }, ref) => (\n <button\n ref={ref}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n ),\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n"],"names":["buttonVariants","cva","Button","React.forwardRef","className","variant","size","props","ref","jsx","cn"],"mappings":"8DAIA,MAAMA,EAAiBC,EACrB,2SACA,CACE,SAAU,CACR,QAAS,CACP,QAAS,sEACT,QAAS,iFACT,MAAO,6CACP,MAAO,4BAAA,EAET,KAAM,CACJ,QAAS,gBACT,GAAI,8BACJ,GAAI,uBACJ,KAAM,SAAA,CACR,EAEF,gBAAiB,CACf,QAAS,UACT,KAAM,SAAA,CACR,CAEJ,EAMMC,EAASC,EAAAA,WACb,CAAC,CAAE,UAAAC,EAAW,QAAAC,EAAS,KAAAC,EAAM,GAAGC,CAAA,EAASC,IACvCC,EAAAA,IAAC,SAAA,CACC,IAAAD,EACA,UAAWE,EAAGV,EAAe,CAAE,QAAAK,EAAS,KAAAC,EAAM,UAAAF,CAAA,CAAW,CAAC,EACzD,GAAGG,CAAA,CAAA,CAGV,EACAL,EAAO,YAAc"}
@@ -1,2 +1,2 @@
1
- import{r,j as t,t as d}from"./index-CL6Af_JZ.js";const o=r.forwardRef(({className:a,...s},e)=>t.jsx("div",{ref:e,className:d("glass-panel p-4",a),...s}));o.displayName="Card";const n=r.forwardRef(({className:a,...s},e)=>t.jsx("div",{ref:e,className:d("mb-3 flex flex-col space-y-1.5",a),...s}));n.displayName="CardHeader";const l=r.forwardRef(({className:a,...s},e)=>t.jsx("h3",{ref:e,className:d("font-heading text-sm font-semibold leading-none tracking-tight",a),...s}));l.displayName="CardTitle";const i=r.forwardRef(({className:a,...s},e)=>t.jsx("div",{ref:e,className:d("text-sm",a),...s}));i.displayName="CardContent";export{o as C,n as a,l as b,i as c};
2
- //# sourceMappingURL=card-Dvl16_R5.js.map
1
+ import{r,j as t,t as d}from"./index-iuxgtzEW.js";const o=r.forwardRef(({className:a,...s},e)=>t.jsx("div",{ref:e,className:d("glass-panel p-4",a),...s}));o.displayName="Card";const n=r.forwardRef(({className:a,...s},e)=>t.jsx("div",{ref:e,className:d("mb-3 flex flex-col space-y-1.5",a),...s}));n.displayName="CardHeader";const l=r.forwardRef(({className:a,...s},e)=>t.jsx("h3",{ref:e,className:d("font-heading text-sm font-semibold leading-none tracking-tight",a),...s}));l.displayName="CardTitle";const i=r.forwardRef(({className:a,...s},e)=>t.jsx("div",{ref:e,className:d("text-sm",a),...s}));i.displayName="CardContent";export{o as C,n as a,l as b,i as c};
2
+ //# sourceMappingURL=card-Cfhz9X31.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"card-Dvl16_R5.js","sources":["../../src/components/ui/card.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\nconst Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"glass-panel p-4\", className)} {...props} />\n ),\n);\nCard.displayName = \"Card\";\n\nconst CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"mb-3 flex flex-col space-y-1.5\", className)} {...props} />\n ),\n);\nCardHeader.displayName = \"CardHeader\";\n\nconst CardTitle = React.forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(\n ({ className, ...props }, ref) => (\n <h3 ref={ref} className={cn(\"font-heading text-sm font-semibold leading-none tracking-tight\", className)} {...props} />\n ),\n);\nCardTitle.displayName = \"CardTitle\";\n\nconst CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"text-sm\", className)} {...props} />\n ),\n);\nCardContent.displayName = \"CardContent\";\n\nexport { Card, CardHeader, CardTitle, CardContent };\n"],"names":["Card","React.forwardRef","className","props","ref","jsx","cn","CardHeader","CardTitle","CardContent"],"mappings":"iDAGA,MAAMA,EAAOC,EAAAA,WACX,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,MAAA,CAAI,IAAAD,EAAU,UAAWE,EAAG,kBAAmBJ,CAAS,EAAI,GAAGC,CAAA,CAAO,CAE3E,EACAH,EAAK,YAAc,OAEnB,MAAMO,EAAaN,EAAAA,WACjB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,MAAA,CAAI,IAAAD,EAAU,UAAWE,EAAG,iCAAkCJ,CAAS,EAAI,GAAGC,CAAA,CAAO,CAE1F,EACAI,EAAW,YAAc,aAEzB,MAAMC,EAAYP,EAAAA,WAChB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,KAAA,CAAG,IAAAD,EAAU,UAAWE,EAAG,iEAAkEJ,CAAS,EAAI,GAAGC,CAAA,CAAO,CAEzH,EACAK,EAAU,YAAc,YAExB,MAAMC,EAAcR,EAAAA,WAClB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,MAAA,CAAI,IAAAD,EAAU,UAAWE,EAAG,UAAWJ,CAAS,EAAI,GAAGC,CAAA,CAAO,CAEnE,EACAM,EAAY,YAAc"}
1
+ {"version":3,"file":"card-Cfhz9X31.js","sources":["../../src/components/ui/card.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\nconst Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"glass-panel p-4\", className)} {...props} />\n ),\n);\nCard.displayName = \"Card\";\n\nconst CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"mb-3 flex flex-col space-y-1.5\", className)} {...props} />\n ),\n);\nCardHeader.displayName = \"CardHeader\";\n\nconst CardTitle = React.forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(\n ({ className, ...props }, ref) => (\n <h3 ref={ref} className={cn(\"font-heading text-sm font-semibold leading-none tracking-tight\", className)} {...props} />\n ),\n);\nCardTitle.displayName = \"CardTitle\";\n\nconst CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"text-sm\", className)} {...props} />\n ),\n);\nCardContent.displayName = \"CardContent\";\n\nexport { Card, CardHeader, CardTitle, CardContent };\n"],"names":["Card","React.forwardRef","className","props","ref","jsx","cn","CardHeader","CardTitle","CardContent"],"mappings":"iDAGA,MAAMA,EAAOC,EAAAA,WACX,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,MAAA,CAAI,IAAAD,EAAU,UAAWE,EAAG,kBAAmBJ,CAAS,EAAI,GAAGC,CAAA,CAAO,CAE3E,EACAH,EAAK,YAAc,OAEnB,MAAMO,EAAaN,EAAAA,WACjB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,MAAA,CAAI,IAAAD,EAAU,UAAWE,EAAG,iCAAkCJ,CAAS,EAAI,GAAGC,CAAA,CAAO,CAE1F,EACAI,EAAW,YAAc,aAEzB,MAAMC,EAAYP,EAAAA,WAChB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,KAAA,CAAG,IAAAD,EAAU,UAAWE,EAAG,iEAAkEJ,CAAS,EAAI,GAAGC,CAAA,CAAO,CAEzH,EACAK,EAAU,YAAc,YAExB,MAAMC,EAAcR,EAAAA,WAClB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,MAAA,CAAI,IAAAD,EAAU,UAAWE,EAAG,UAAWJ,CAAS,EAAI,GAAGC,CAAA,CAAO,CAEnE,EACAM,EAAY,YAAc"}
@@ -1,2 +1,2 @@
1
- import{z as r,E as t,D as s,F as n}from"./index-CL6Af_JZ.js";function h(){return r(t.modelThresholds.path)}function i(e){return s(t.modelThresholds.path,e)}async function d(e){const o=await fetch(`${t.modelThresholds.path}/${encodeURIComponent(e)}`,{method:"DELETE"});if(!o.ok)throw new Error(`deleteModelThreshold ${o.status}`);return o.json()}function l(e=50){return r(`${t.prefixStability.path}?limit=${e}`)}function p(){return n(t.improveCortex.path,{confirm:!0})}function u(e){return r(t.improveCortexStatus.path.replace(":jobId",encodeURIComponent(e)))}export{u as a,h as b,d,l as f,p as i,i as p};
2
- //# sourceMappingURL=client-extra-BShDrG99.js.map
1
+ import{z as r,E as t,D as s,F as n}from"./index-iuxgtzEW.js";function h(){return r(t.modelThresholds.path)}function i(e){return s(t.modelThresholds.path,e)}async function d(e){const o=await fetch(`${t.modelThresholds.path}/${encodeURIComponent(e)}`,{method:"DELETE"});if(!o.ok)throw new Error(`deleteModelThreshold ${o.status}`);return o.json()}function l(e=50){return r(`${t.prefixStability.path}?limit=${e}`)}function p(){return n(t.improveCortex.path,{confirm:!0})}function u(e){return r(t.improveCortexStatus.path.replace(":jobId",encodeURIComponent(e)))}export{u as a,h as b,d,l as f,p as i,i as p};
2
+ //# sourceMappingURL=client-extra-CKNOGEz_.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-extra-BShDrG99.js","sources":["../../src/api/client-extra.ts"],"sourcesContent":["/**\n * dashboard-client/src/api/client-extra.ts — newer dashboard API wrappers.\n *\n * Extracted from client.ts (delegate-shell split) so client.ts stays under the\n * 400-line extension soft limit. Holds the newest endpoint groups: per-model\n * compaction thresholds (S52) and the PC-C prefix-stability trend. client.ts\n * re-exports these so downstream imports are unchanged.\n */\n\nimport { ENDPOINTS } from \"@contracts\";\nimport type {\n\tModelThresholdsResponse,\n\tModelThresholdPutRequest,\n\tModelThresholdPutResponse,\n\tPrefixStabilityResponse,\n\tCortexImproveStart,\n\tCortexImproveStatus,\n} from \"@contracts\";\nimport { getJson, postJson, putJson } from \"./client-http.js\";\n\n/** GET /api/model-thresholds — list known models with their thresholds. */\nexport function fetchModelThresholds(): Promise<ModelThresholdsResponse> {\n\treturn getJson<ModelThresholdsResponse>(ENDPOINTS.modelThresholds.path);\n}\n\n/** PUT /api/model-thresholds — upsert a per-model override. */\nexport function putModelThreshold(\n\tbody: ModelThresholdPutRequest,\n): Promise<ModelThresholdPutResponse> {\n\treturn putJson<ModelThresholdPutResponse>(\n\t\tENDPOINTS.modelThresholds.path,\n\t\tbody,\n\t);\n}\n\n/** DELETE /api/model-thresholds/:modelId — delete an override (revert). */\nexport async function deleteModelThreshold(\n\tmodelId: string,\n): Promise<{ deleted: boolean }> {\n\tconst res = await fetch(\n\t\t`${ENDPOINTS.modelThresholds.path}/${encodeURIComponent(modelId)}`,\n\t\t{ method: \"DELETE\" },\n\t);\n\tif (!res.ok) throw new Error(`deleteModelThreshold ${res.status}`);\n\treturn res.json() as Promise<{ deleted: boolean }>;\n}\n\n/** Prompt-cache per-turn stable-prefix ratio trend (PC-C). */\nexport function fetchPrefixStability(\n\tlimit = 50,\n): Promise<PrefixStabilityResponse> {\n\treturn getJson<PrefixStabilityResponse>(\n\t\t`${ENDPOINTS.prefixStability.path}?limit=${limit}`,\n\t);\n}\n\n/** Launch a local ML5-A improve job (POST /api/cortex/improve, ML5-D). */\nexport function improveCortex(): Promise<CortexImproveStart> {\n\treturn postJson<CortexImproveStart>(ENDPOINTS.improveCortex.path, {\n\t\tconfirm: true,\n\t});\n}\n\n/** Poll an improve job (GET /api/cortex/improve/status/:jobId, ML5-D). */\nexport function fetchCortexImproveStatus(\n\tjobId: string,\n): Promise<CortexImproveStatus> {\n\treturn getJson<CortexImproveStatus>(\n\t\tENDPOINTS.improveCortexStatus.path.replace(\":jobId\", encodeURIComponent(jobId)),\n\t);\n}\n"],"names":["fetchModelThresholds","getJson","ENDPOINTS","putModelThreshold","body","putJson","deleteModelThreshold","modelId","res","fetchPrefixStability","limit","improveCortex","postJson","fetchCortexImproveStatus","jobId"],"mappings":"6DAqBO,SAASA,GAAyD,CACxE,OAAOC,EAAiCC,EAAU,gBAAgB,IAAI,CACvE,CAGO,SAASC,EACfC,EACqC,CACrC,OAAOC,EACNH,EAAU,gBAAgB,KAC1BE,CAAA,CAEF,CAGA,eAAsBE,EACrBC,EACgC,CAChC,MAAMC,EAAM,MAAM,MACjB,GAAGN,EAAU,gBAAgB,IAAI,IAAI,mBAAmBK,CAAO,CAAC,GAChE,CAAE,OAAQ,QAAA,CAAS,EAEpB,GAAI,CAACC,EAAI,GAAI,MAAM,IAAI,MAAM,wBAAwBA,EAAI,MAAM,EAAE,EACjE,OAAOA,EAAI,KAAA,CACZ,CAGO,SAASC,EACfC,EAAQ,GAC2B,CACnC,OAAOT,EACN,GAAGC,EAAU,gBAAgB,IAAI,UAAUQ,CAAK,EAAA,CAElD,CAGO,SAASC,GAA6C,CAC5D,OAAOC,EAA6BV,EAAU,cAAc,KAAM,CACjE,QAAS,EAAA,CACT,CACF,CAGO,SAASW,EACfC,EAC+B,CAC/B,OAAOb,EACNC,EAAU,oBAAoB,KAAK,QAAQ,SAAU,mBAAmBY,CAAK,CAAC,CAAA,CAEhF"}
1
+ {"version":3,"file":"client-extra-CKNOGEz_.js","sources":["../../src/api/client-extra.ts"],"sourcesContent":["/**\n * dashboard-client/src/api/client-extra.ts — newer dashboard API wrappers.\n *\n * Extracted from client.ts (delegate-shell split) so client.ts stays under the\n * 400-line extension soft limit. Holds the newest endpoint groups: per-model\n * compaction thresholds (S52) and the PC-C prefix-stability trend. client.ts\n * re-exports these so downstream imports are unchanged.\n */\n\nimport { ENDPOINTS } from \"@contracts\";\nimport type {\n\tModelThresholdsResponse,\n\tModelThresholdPutRequest,\n\tModelThresholdPutResponse,\n\tPrefixStabilityResponse,\n\tCortexImproveStart,\n\tCortexImproveStatus,\n} from \"@contracts\";\nimport { getJson, postJson, putJson } from \"./client-http.js\";\n\n/** GET /api/model-thresholds — list known models with their thresholds. */\nexport function fetchModelThresholds(): Promise<ModelThresholdsResponse> {\n\treturn getJson<ModelThresholdsResponse>(ENDPOINTS.modelThresholds.path);\n}\n\n/** PUT /api/model-thresholds — upsert a per-model override. */\nexport function putModelThreshold(\n\tbody: ModelThresholdPutRequest,\n): Promise<ModelThresholdPutResponse> {\n\treturn putJson<ModelThresholdPutResponse>(\n\t\tENDPOINTS.modelThresholds.path,\n\t\tbody,\n\t);\n}\n\n/** DELETE /api/model-thresholds/:modelId — delete an override (revert). */\nexport async function deleteModelThreshold(\n\tmodelId: string,\n): Promise<{ deleted: boolean }> {\n\tconst res = await fetch(\n\t\t`${ENDPOINTS.modelThresholds.path}/${encodeURIComponent(modelId)}`,\n\t\t{ method: \"DELETE\" },\n\t);\n\tif (!res.ok) throw new Error(`deleteModelThreshold ${res.status}`);\n\treturn res.json() as Promise<{ deleted: boolean }>;\n}\n\n/** Prompt-cache per-turn stable-prefix ratio trend (PC-C). */\nexport function fetchPrefixStability(\n\tlimit = 50,\n): Promise<PrefixStabilityResponse> {\n\treturn getJson<PrefixStabilityResponse>(\n\t\t`${ENDPOINTS.prefixStability.path}?limit=${limit}`,\n\t);\n}\n\n/** Launch a local ML5-A improve job (POST /api/cortex/improve, ML5-D). */\nexport function improveCortex(): Promise<CortexImproveStart> {\n\treturn postJson<CortexImproveStart>(ENDPOINTS.improveCortex.path, {\n\t\tconfirm: true,\n\t});\n}\n\n/** Poll an improve job (GET /api/cortex/improve/status/:jobId, ML5-D). */\nexport function fetchCortexImproveStatus(\n\tjobId: string,\n): Promise<CortexImproveStatus> {\n\treturn getJson<CortexImproveStatus>(\n\t\tENDPOINTS.improveCortexStatus.path.replace(\":jobId\", encodeURIComponent(jobId)),\n\t);\n}\n"],"names":["fetchModelThresholds","getJson","ENDPOINTS","putModelThreshold","body","putJson","deleteModelThreshold","modelId","res","fetchPrefixStability","limit","improveCortex","postJson","fetchCortexImproveStatus","jobId"],"mappings":"6DAqBO,SAASA,GAAyD,CACxE,OAAOC,EAAiCC,EAAU,gBAAgB,IAAI,CACvE,CAGO,SAASC,EACfC,EACqC,CACrC,OAAOC,EACNH,EAAU,gBAAgB,KAC1BE,CAAA,CAEF,CAGA,eAAsBE,EACrBC,EACgC,CAChC,MAAMC,EAAM,MAAM,MACjB,GAAGN,EAAU,gBAAgB,IAAI,IAAI,mBAAmBK,CAAO,CAAC,GAChE,CAAE,OAAQ,QAAA,CAAS,EAEpB,GAAI,CAACC,EAAI,GAAI,MAAM,IAAI,MAAM,wBAAwBA,EAAI,MAAM,EAAE,EACjE,OAAOA,EAAI,KAAA,CACZ,CAGO,SAASC,EACfC,EAAQ,GAC2B,CACnC,OAAOT,EACN,GAAGC,EAAU,gBAAgB,IAAI,UAAUQ,CAAK,EAAA,CAElD,CAGO,SAASC,GAA6C,CAC5D,OAAOC,EAA6BV,EAAU,cAAc,KAAM,CACjE,QAAS,EAAA,CACT,CACF,CAGO,SAASW,EACfC,EAC+B,CAC/B,OAAOb,EACNC,EAAU,oBAAoB,KAAK,QAAQ,SAAU,mBAAmBY,CAAK,CAAC,CAAA,CAEhF"}