mirror of
https://github.com/samvallad33/vestige.git
synced 2026-04-30 03:16:22 +02:00
Closes Agent 1's audit gap #4: FSRS memory state (Active / Dormant / Silent / Unavailable) was computed server-side per query but never rendered in the 3D graph. Spheres always tinted by node type. The new colour mode adds a second channel that users can toggle between at runtime — Type (default, existing behaviour) and State (new). The toggle is a radio-pair pill in the graph page's top-right control bar next to the node-count selector + Dream button. Buckets + palette: - Active ≥ 70% emerald #10b981 easily retrievable - Dormant 40-70% amber #f59e0b retrievable with effort - Silent 10-40% violet #8b5cf6 difficult, needs cues - Unavail. < 10% slate #6b7280 needs reinforcement Thresholds match `execute_system_status` at the backend so the graph colour bands line up exactly with what the Stats page reports in its stateDistribution block. Using retention as the proxy for the full accessibility formula (retention × 0.5 + retrieval × 0.3 + storage × 0.2) is an approximation — retention is the dominant 0.5 weight and it is the only FSRS channel the current GraphNode DTO carries. Swap to the full formula in a future release if the DTO grows. Implementation: - `apps/dashboard/src/lib/graph/nodes.ts` — new `MemoryState` type, `getMemoryState(retention)`, `MEMORY_STATE_COLORS`, `MEMORY_STATE_DESCRIPTIONS`, `ColorMode`, `getNodeColor(node, mode)`. - `NodeManager.colorMode` field (default `'type'`). `createNodeMeshes` now calls `getNodeColor(node, this.colorMode)` so newly-added nodes during the session follow the toggled mode. - New `NodeManager.setColorMode(mode)` mutates every live mesh's material + glow sprite colour in place. Idempotent; cheap. Does NOT touch opacity/emissive-intensity so the v2.0.5 suppression dimming layer keeps working unchanged. - New `MemoryStateLegend.svelte` floating overlay in the bottom-right when state mode is active (hidden in type mode so the legend doesn't compete with the node-type palette). - `Graph3D.svelte` accepts a new `colorMode` prop (default `'type'`) and runs a `$effect` that calls `setColorMode` on every toggle. - Dashboard rebuild picks up the new component + wiring. Tests: 171 vitest, svelte-check 581 files / 0 errors. No backend changes; this is pure dashboard code.
2 lines
9.7 KiB
JavaScript
2 lines
9.7 KiB
JavaScript
import"../chunks/Bzak7iHL.js";import{o as ze}from"../chunks/DWVWfZUn.js";import{p as Je,t as w,a as We,d as r,e as t,g as s,s as S,h as m,r as e,O as b,f as Be,u as j}from"../chunks/VE8Jor13.js";import{d as He,a as X,s as p}from"../chunks/DHnEMX8z.js";import{i as u}from"../chunks/JkhlGLjU.js";import{e as Z,i as ee}from"../chunks/ByItJEsC.js";import{a as v,f as l,t as ue}from"../chunks/7UNxJI5L.js";import{s as ge}from"../chunks/BR2EHpd7.js";import{s as fe}from"../chunks/ussr1V5_.js";import{s as Le,a as te}from"../chunks/AcZBvMXu.js";import{a as O}from"../chunks/DcQGRi49.js";import{m as Ue,a as Ye,i as qe}from"../chunks/XIUN5r_Y.js";var Qe=l('<span class="w-3 h-3 border border-warning/50 border-t-warning rounded-full animate-spin"></span> Running...',1),Xe=l('<div><div class="text-lg text-text font-semibold"> </div> <div class="text-[10px] text-muted">Processed</div></div>'),Ze=l('<div><div class="text-lg text-decay font-semibold"> </div> <div class="text-[10px] text-muted">Decayed</div></div>'),et=l('<div><div class="text-lg text-synapse-glow font-semibold"> </div> <div class="text-[10px] text-muted">Embedded</div></div>'),tt=l('<div class="bg-white/[0.02] p-3 rounded-lg border border-synapse/10"><div class="grid grid-cols-3 gap-3 text-center"><!> <!> <!></div></div>'),st=l('<span class="w-3 h-3 border border-dream/50 border-t-dream rounded-full animate-spin"></span> Dreaming...',1),at=l('<div class="text-xs text-dim bg-dream/5 border border-dream/10 rounded-lg p-2"> </div>'),it=l('<div class="text-xs text-bright font-medium">Insights Discovered:</div> <!>',1),dt=l('<div class="text-xs text-dim">Connections found: <span class="text-dream-glow"> </span></div>'),rt=l('<div class="text-xs text-dim">Memories replayed: <span class="text-text"> </span></div>'),ot=l('<div class="bg-white/[0.02] p-3 rounded-lg border border-synapse/10 space-y-2"><!> <!> <!></div>'),nt=l('<div class="flex-1 flex flex-col items-center gap-1"><div class="text-[9px] text-muted"> </div> <div class="w-full rounded-t transition-all duration-500"></div> <div class="text-[9px] text-muted"></div></div>'),vt=l('<div class="flex items-end gap-1 h-32"></div>'),lt=l('<section class="space-y-4"><h2 class="text-sm text-bright font-semibold flex items-center gap-2"><span class="text-recall">◫</span> Retention Distribution</h2> <div class="p-4 glass rounded-xl"><!></div></section>'),ct=l('<div class="flex items-center gap-2 py-1"><kbd class="px-1.5 py-0.5 bg-white/[0.04] rounded text-[10px] font-mono text-muted min-w-[2rem] text-center"> </kbd> <span class="text-dim"> </span></div>'),xt=l(`<div class="p-6 max-w-4xl mx-auto space-y-8"><div class="flex items-center justify-between"><h1 class="text-xl text-bright font-semibold">Settings & System</h1> <button class="text-xs text-dim hover:text-text transition">Refresh</button></div> <div class="grid grid-cols-2 md:grid-cols-4 gap-3"><div class="p-4 glass rounded-xl text-center"><div class="text-2xl text-bright font-bold"> </div> <div class="text-xs text-dim mt-1">Memories</div></div> <div class="p-4 glass rounded-xl text-center"><div class="text-2xl font-bold"> </div> <div class="text-xs text-dim mt-1">Avg Retention</div></div> <div class="p-4 glass rounded-xl text-center"><div class="text-2xl text-bright font-bold flex items-center justify-center gap-2"><div></div> <span class="text-sm"> </span></div> <div class="text-xs text-dim mt-1">WebSocket</div></div> <div class="p-4 glass rounded-xl text-center"><div class="text-2xl text-synapse-glow font-bold">v2.1</div> <div class="text-xs text-dim mt-1">Vestige</div></div></div> <section class="space-y-4"><h2 class="text-sm text-bright font-semibold flex items-center gap-2"><span class="text-dream">◈</span> Cognitive Operations</h2> <div class="p-4 glass rounded-xl space-y-3"><div class="flex items-center justify-between"><div><div class="text-sm text-text font-medium">FSRS-6 Consolidation</div> <div class="text-xs text-dim">Apply spaced-repetition decay, regenerate embeddings, run maintenance</div></div> <button class="px-4 py-2 bg-warning/20 border border-warning/40 text-warning text-sm rounded-xl hover:bg-warning/30 transition disabled:opacity-50 flex items-center gap-2"><!></button></div> <!></div> <div class="p-4 glass rounded-xl space-y-3"><div class="flex items-center justify-between"><div><div class="text-sm text-text font-medium">Memory Dream Cycle</div> <div class="text-xs text-dim">Replay memories, discover hidden connections, synthesize insights</div></div> <button><!></button></div> <!></div></section> <!> <section class="space-y-4"><h2 class="text-sm text-bright font-semibold flex items-center gap-2"><span class="text-synapse">⌨</span> Keyboard Shortcuts</h2> <div class="p-4 glass-subtle rounded-xl"><div class="grid grid-cols-2 gap-2 text-xs"></div></div></section> <section class="space-y-4"><h2 class="text-sm text-bright font-semibold flex items-center gap-2"><span class="text-memory">◎</span> About</h2> <div class="p-4 glass rounded-xl space-y-3"><div class="flex items-center gap-4"><div class="w-12 h-12 rounded-xl bg-gradient-to-br from-dream to-synapse flex items-center justify-center text-bright text-xl font-bold shadow-lg shadow-synapse/20">V</div> <div><div class="text-sm text-bright font-semibold">Vestige v2.1 "Nuclear Dashboard"</div> <div class="text-xs text-dim">Your AI's long-term memory system</div></div></div> <div class="grid grid-cols-2 gap-2 text-xs text-dim pt-2 border-t border-synapse/10"><div>29 cognitive modules</div> <div>FSRS-6 spaced repetition</div> <div>Nomic Embed v1.5 (256d)</div> <div>Jina Reranker v1 Turbo</div> <div>USearch HNSW (20x FAISS)</div> <div>Local-first, zero cloud</div></div> <div class="text-[10px] text-muted pt-1">Built with Rust + Axum + SvelteKit 2 + Svelte 5 + Three.js + Tailwind CSS 4</div></div></section></div>`);function Ct(_e,be){Je(be,!0);const ye=()=>te(Ue,"$memoryCount",I),P=()=>te(Ye,"$avgRetention",I),se=()=>te(qe,"$isConnected",I),[I,he]=Le();let T=S(!1),A=S(!1),y=S(null),g=S(null),we=S(null),$=S(null),ae=S(!0),Se=S(null);ze(()=>{E()});async function E(){m(ae,!0);try{const[a,o,c]=await Promise.all([O.stats().catch(()=>null),O.health().catch(()=>null),O.retentionDistribution().catch(()=>null)]);m(we,a,!0),m(Se,o,!0),m($,c,!0)}finally{m(ae,!1)}}async function ke(){m(T,!0),m(y,null);try{m(y,await O.consolidate(),!0),await E()}catch{}finally{m(T,!1)}}async function Ce(){m(A,!0),m(g,null);try{m(g,await O.dream(),!0),await E()}catch{}finally{m(A,!1)}}var K=xt(),V=t(K),Re=r(t(V),2);e(V);var z=r(V,2),J=t(z),ie=t(J),$e=t(ie,!0);e(ie),b(2),e(J);var W=r(J,2),B=t(W),Ae=t(B);e(B),b(2),e(W);var de=r(W,2),re=t(de),oe=t(re),ne=r(oe,2),De=t(ne,!0);e(ne),e(re),b(2),e(de),b(2),e(z);var H=r(z,2),L=r(t(H),2),U=t(L),N=r(t(U),2),Ge=t(N);{var Me=a=>{var o=Qe();b(),v(a,o)},Fe=a=>{var o=ue("Consolidate");v(a,o)};u(Ge,a=>{s(T)?a(Me):a(Fe,!1)})}e(N),e(U);var je=r(U,2);{var Oe=a=>{var o=tt(),c=t(o),f=t(c);{var k=d=>{var i=Xe(),n=t(i),x=t(n,!0);e(n),b(2),e(i),w(()=>p(x,s(y).nodesProcessed)),v(d,i)};u(f,d=>{s(y).nodesProcessed!==void 0&&d(k)})}var _=r(f,2);{var h=d=>{var i=Ze(),n=t(i),x=t(n,!0);e(n),b(2),e(i),w(()=>p(x,s(y).decayApplied)),v(d,i)};u(_,d=>{s(y).decayApplied!==void 0&&d(h)})}var C=r(_,2);{var G=d=>{var i=et(),n=t(i),x=t(n,!0);e(n),b(2),e(i),w(()=>p(x,s(y).embeddingsGenerated)),v(d,i)};u(C,d=>{s(y).embeddingsGenerated!==void 0&&d(G)})}e(c),e(o),v(a,o)};u(je,a=>{s(y)&&a(Oe)})}e(L);var ve=r(L,2),Y=t(ve),D=r(t(Y),2),Te=t(D);{var Ee=a=>{var o=st();b(),v(a,o)},Ne=a=>{var o=ue("Dream");v(a,o)};u(Te,a=>{s(A)?a(Ee):a(Ne,!1)})}e(D),e(Y);var Pe=r(Y,2);{var Ie=a=>{var o=ot(),c=t(o);{var f=d=>{var i=it(),n=r(Be(i),2);Z(n,17,()=>s(g).insights,ee,(x,M)=>{var R=at(),F=t(R,!0);e(R),w(q=>p(F,q),[()=>typeof s(M)=="string"?s(M):JSON.stringify(s(M))]),v(x,R)}),v(d,i)},k=j(()=>s(g).insights&&Array.isArray(s(g).insights));u(c,d=>{s(k)&&d(f)})}var _=r(c,2);{var h=d=>{var i=dt(),n=r(t(i)),x=t(n,!0);e(n),e(i),w(()=>p(x,s(g).connections_found)),v(d,i)};u(_,d=>{s(g).connections_found!==void 0&&d(h)})}var C=r(_,2);{var G=d=>{var i=rt(),n=r(t(i)),x=t(n,!0);e(n),e(i),w(()=>p(x,s(g).memories_replayed)),v(d,i)};u(C,d=>{s(g).memories_replayed!==void 0&&d(G)})}e(o),v(a,o)};u(Pe,a=>{s(g)&&a(Ie)})}e(ve),e(H);var le=r(H,2);{var Ke=a=>{var o=lt(),c=r(t(o),2),f=t(c);{var k=h=>{var C=vt();Z(C,21,()=>s($).distribution,ee,(G,d,i)=>{const n=j(()=>Math.max(...s($).distribution.map(Q=>Q.count),1)),x=j(()=>s(d).count/s(n)*100),M=j(()=>i<2?"#ef4444":i<4?"#f59e0b":i<7?"#6366f1":"#10b981");var R=nt(),F=t(R),q=t(F,!0);e(F);var pe=r(F,2),Ve=r(pe,2);Ve.textContent=`${i*10}%`,e(R),w(Q=>{p(q,s(d).count),fe(pe,`height: ${Q??""}%; background: ${s(M)??""}; opacity: 0.7`)},[()=>Math.max(s(x),2)]),v(G,R)}),e(C),v(h,C)},_=j(()=>s($).distribution&&Array.isArray(s($).distribution));u(f,h=>{s(_)&&h(k)})}e(c),e(o),v(a,o)};u(le,a=>{s($)&&a(Ke)})}var ce=r(le,2),xe=r(t(ce),2),me=t(xe);Z(me,20,()=>[{key:"⌘ K",desc:"Command palette"},{key:"/",desc:"Focus search"},{key:"G",desc:"Go to Graph"},{key:"M",desc:"Go to Memories"},{key:"T",desc:"Go to Timeline"},{key:"F",desc:"Go to Feed"},{key:"E",desc:"Go to Explore"},{key:"S",desc:"Go to Stats"}],ee,(a,o)=>{var c=ct(),f=t(c),k=t(f,!0);e(f);var _=r(f,2),h=t(_,!0);e(_),e(c),w(()=>{p(k,o.key),p(h,o.desc)}),v(a,c)}),e(me),e(xe),e(ce),b(2),e(K),w(a=>{p($e,ye()),fe(B,`color: ${P()>.7?"#10b981":P()>.4?"#f59e0b":"#ef4444"}`),p(Ae,`${a??""}%`),ge(oe,1,`w-2.5 h-2.5 rounded-full ${se()?"bg-recall animate-pulse-glow":"bg-decay"}`),p(De,se()?"Online":"Offline"),N.disabled=s(T),D.disabled=s(A),ge(D,1,`px-4 py-2 bg-dream/20 border border-dream/40 text-dream-glow text-sm rounded-xl hover:bg-dream/30 transition disabled:opacity-50 flex items-center gap-2
|
|
${s(A)?"glow-dream animate-pulse-glow":""}`)},[()=>(P()*100).toFixed(1)]),X("click",Re,E),X("click",N,ke),X("click",D,Ce),v(_e,K),We(),he()}He(["click"]);export{Ct as component};
|