mirror of
https://github.com/samvallad33/vestige.git
synced 2026-04-25 00:36: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.
1 line
6.4 KiB
JavaScript
1 line
6.4 KiB
JavaScript
var x=t=>{throw TypeError(t)};var B=(t,e,n)=>e.has(t)||x("Cannot "+n);var a=(t,e,n)=>(B(t,e,"read from private field"),n?n.call(t):e.get(t)),c=(t,e,n)=>e.has(t)?x("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,n);import{o as I}from"./DWVWfZUn.js";import{s as u,g as f,h as d}from"./VE8Jor13.js";import{w as G}from"./CCRrbKqn.js";new URL("sveltekit-internal://");function ae(t,e){return t==="/"||e==="ignore"?t:e==="never"?t.endsWith("/")?t.slice(0,-1):t:e==="always"&&!t.endsWith("/")?t+"/":t}function oe(t){return t.split("%25").map(decodeURI).join("%25")}function ie(t){for(const e in t)t[e]=decodeURIComponent(t[e]);return t}function le({href:t}){return t.split("#")[0]}function W(...t){let e=5381;for(const n of t)if(typeof n=="string"){let r=n.length;for(;r;)e=e*33^n.charCodeAt(--r)}else if(ArrayBuffer.isView(n)){const r=new Uint8Array(n.buffer,n.byteOffset,n.byteLength);let s=r.length;for(;s;)e=e*33^r[--s]}else throw new TypeError("value must be a string or TypedArray");return(e>>>0).toString(36)}new TextEncoder;new TextDecoder;function X(t){const e=atob(t),n=new Uint8Array(e.length);for(let r=0;r<e.length;r++)n[r]=e.charCodeAt(r);return n}const z=window.fetch;window.fetch=(t,e)=>((t instanceof Request?t.method:(e==null?void 0:e.method)||"GET")!=="GET"&&b.delete(U(t)),z(t,e));const b=new Map;function ce(t,e){const n=U(t,e),r=document.querySelector(n);if(r!=null&&r.textContent){r.remove();let{body:s,...l}=JSON.parse(r.textContent);const o=r.getAttribute("data-ttl");return o&&b.set(n,{body:s,init:l,ttl:1e3*Number(o)}),r.getAttribute("data-b64")!==null&&(s=X(s)),Promise.resolve(new Response(s,l))}return window.fetch(t,e)}function ue(t,e,n){if(b.size>0){const r=U(t,n),s=b.get(r);if(s){if(performance.now()<s.ttl&&["default","force-cache","only-if-cached",void 0].includes(n==null?void 0:n.cache))return new Response(s.body,s.init);b.delete(r)}}return window.fetch(e,n)}function U(t,e){let r=`script[data-sveltekit-fetched][data-url=${JSON.stringify(t instanceof Request?t.url:t)}]`;if(e!=null&&e.headers||e!=null&&e.body){const s=[];e.headers&&s.push([...new Headers(e.headers)].join(",")),e.body&&(typeof e.body=="string"||ArrayBuffer.isView(e.body))&&s.push(e.body),r+=`[data-hash="${W(...s)}"]`}return r}var $;const J=(($=globalThis.__sveltekit_1m3s8yh)==null?void 0:$.base)??"/dashboard";var C;const M=((C=globalThis.__sveltekit_1m3s8yh)==null?void 0:C.assets)??J??"",F="1776649505514",fe="sveltekit:snapshot",de="sveltekit:scroll",he="sveltekit:states",ge="sveltekit:pageurl",be="sveltekit:history",_e="sveltekit:navigation",N={tap:1,hover:2,viewport:3,eager:4,off:-1,false:-1},Y=location.origin;function me(t){if(t instanceof URL)return t;let e=document.baseURI;if(!e){const n=document.getElementsByTagName("base");e=n.length?n[0].href:document.URL}return new URL(t,e)}function we(){return{x:pageXOffset,y:pageYOffset}}function g(t,e){return t.getAttribute(`data-sveltekit-${e}`)}const L={...N,"":N.hover};function q(t){let e=t.assignedSlot??t.parentNode;return(e==null?void 0:e.nodeType)===11&&(e=e.host),e}function pe(t,e){for(;t&&t!==e;){if(t.nodeName.toUpperCase()==="A"&&t.hasAttribute("href"))return t;t=q(t)}}function ve(t,e,n){let r;try{if(r=new URL(t instanceof SVGAElement?t.href.baseVal:t.href,document.baseURI),n&&r.hash.match(/^#[^/]/)){const i=location.hash.split("#")[1]||"/";r.hash=`#${i}${r.hash}`}}catch{}const s=t instanceof SVGAElement?t.target.baseVal:t.target,l=!r||!!s||Q(r,e,n)||(t.getAttribute("rel")||"").split(/\s+/).includes("external"),o=(r==null?void 0:r.origin)===Y&&t.hasAttribute("download");return{url:r,external:l,target:s,download:o}}function ye(t){let e=null,n=null,r=null,s=null,l=null,o=null,i=t;for(;i&&i!==document.documentElement;)r===null&&(r=g(i,"preload-code")),s===null&&(s=g(i,"preload-data")),e===null&&(e=g(i,"keepfocus")),n===null&&(n=g(i,"noscroll")),l===null&&(l=g(i,"reload")),o===null&&(o=g(i,"replacestate")),i=q(i);function h(K){switch(K){case"":case"true":return!0;case"off":case"false":return!1;default:return}}return{preload_code:L[r??"off"],preload_data:L[s??"off"],keepfocus:h(e),noscroll:h(n),reload:h(l),replace_state:h(o)}}function Ae(t){const e=G(t);let n=!0;function r(){n=!0,e.update(o=>o)}function s(o){n=!1,e.set(o)}function l(o){let i;return e.subscribe(h=>{(i===void 0||n&&h!==i)&&o(i=h)})}return{notify:r,set:s,subscribe:l}}const D={v:()=>{}};function Re(){const{set:t,subscribe:e}=G(!1);let n;async function r(){clearTimeout(n);try{const s=await fetch(`${M}/_app/version.json`,{headers:{pragma:"no-cache","cache-control":"no-cache"}});if(!s.ok)return!1;const o=(await s.json()).version!==F;return o&&(t(!0),D.v(),clearTimeout(n)),o}catch{return!1}}return{subscribe:e,check:r}}function Q(t,e,n){return t.origin!==Y||!t.pathname.startsWith(e)?!0:n?t.pathname!==location.pathname:!1}function Se(t){}const H=new Set(["load","prerender","csr","ssr","trailingSlash","config"]);[...H];const Z=new Set([...H]);[...Z];let E,O,T;const ee=I.toString().includes("$$")||/function \w+\(\) \{\}/.test(I.toString());var _,m,w,p,v,y,A,R,P,S,V,k,j;ee?(E={data:{},form:null,error:null,params:{},route:{id:null},state:{},status:-1,url:new URL("https://example.com")},O={current:null},T={current:!1}):(E=new(P=class{constructor(){c(this,_,u({}));c(this,m,u(null));c(this,w,u(null));c(this,p,u({}));c(this,v,u({id:null}));c(this,y,u({}));c(this,A,u(-1));c(this,R,u(new URL("https://example.com")))}get data(){return f(a(this,_))}set data(e){d(a(this,_),e)}get form(){return f(a(this,m))}set form(e){d(a(this,m),e)}get error(){return f(a(this,w))}set error(e){d(a(this,w),e)}get params(){return f(a(this,p))}set params(e){d(a(this,p),e)}get route(){return f(a(this,v))}set route(e){d(a(this,v),e)}get state(){return f(a(this,y))}set state(e){d(a(this,y),e)}get status(){return f(a(this,A))}set status(e){d(a(this,A),e)}get url(){return f(a(this,R))}set url(e){d(a(this,R),e)}},_=new WeakMap,m=new WeakMap,w=new WeakMap,p=new WeakMap,v=new WeakMap,y=new WeakMap,A=new WeakMap,R=new WeakMap,P),O=new(V=class{constructor(){c(this,S,u(null))}get current(){return f(a(this,S))}set current(e){d(a(this,S),e)}},S=new WeakMap,V),T=new(j=class{constructor(){c(this,k,u(!1))}get current(){return f(a(this,k))}set current(e){d(a(this,k),e)}},k=new WeakMap,j),D.v=()=>T.current=!0);function Ue(t){Object.assign(E,t)}export{be as H,_e as N,ge as P,he as S,ye as a,J as b,Re as c,le as d,ie as e,pe as f,ve as g,ae as h,Q as i,N as j,oe as k,fe as l,ue as m,O as n,Y as o,E as p,ce as q,me as r,we as s,de as t,Ae as u,Ue as v,Se as w};
|