@filsilva/helios-cli 0.10.0

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 (39) hide show
  1. package/README.md +171 -0
  2. package/bin/helios.js +34 -0
  3. package/dist/client/assets/HeliosSessionWorker.browser-BYYjDIKH.js +3 -0
  4. package/dist/client/assets/HeliosSessionWorker.browser-BYYjDIKH.js.map +1 -0
  5. package/dist/client/assets/d3force3dWorker-BKANL9of.js +2 -0
  6. package/dist/client/assets/d3force3dWorker-BKANL9of.js.map +1 -0
  7. package/dist/client/assets/index-CP7mSmLx.js +9530 -0
  8. package/dist/client/assets/index-CP7mSmLx.js.map +1 -0
  9. package/dist/client/assets/layoutWorker-Lc8iIdmf.js +2 -0
  10. package/dist/client/assets/layoutWorker-Lc8iIdmf.js.map +1 -0
  11. package/dist/client/index.html +27 -0
  12. package/package.json +40 -0
  13. package/skills/helios-cli/SKILL.md +118 -0
  14. package/skills/helios-cli/references/behaviors.md +47 -0
  15. package/skills/helios-cli/references/layouts.md +77 -0
  16. package/skills/helios-cli/references/mappers.md +119 -0
  17. package/skills/helios-cli/references/metrics.md +83 -0
  18. package/skills/helios-cli/references/networks.md +53 -0
  19. package/skills/helios-cli/references/persistence.md +136 -0
  20. package/skills/helios-cli/references/positions.md +63 -0
  21. package/skills/helios-cli/references/rendering-export.md +56 -0
  22. package/skills/helios-cli/references/rpc-methods.md +83 -0
  23. package/src/cli.js +488 -0
  24. package/src/client/index.html +27 -0
  25. package/src/client/main.js +2210 -0
  26. package/src/daemon/SessionDaemon.js +1065 -0
  27. package/src/daemon/entry.js +36 -0
  28. package/src/protocol/jsonl.js +88 -0
  29. package/src/shared/cliConfig.js +52 -0
  30. package/src/shared/fileSessionStore.js +202 -0
  31. package/src/shared/fs.js +59 -0
  32. package/src/shared/networkFormats.js +55 -0
  33. package/src/shared/networkInspect.js +81 -0
  34. package/src/shared/paths.js +43 -0
  35. package/src/shared/sessionClient.js +88 -0
  36. package/src/shared/sessionId.js +5 -0
  37. package/src/shared/sessionRegistry.js +53 -0
  38. package/src/shared/sessionSurfaces.js +199 -0
  39. package/vite.config.js +47 -0
@@ -0,0 +1,2 @@
1
+ const A={layout:"force3d",mode:"2d",center:[0,0,0],radius:150,depth:0,jitter:3,repulsionExponent:2,attractionExponent:1,kRepulsion:6,kAttraction:.0035,kGravity:5e-4,epsilon:.25,minDistance:.25,maxForce:50,maxStep:3,eta:.04,damping:.9,theta:.6,leafSize:16,repulsionStrategy:"barnes-hut",negativeSampling:!1,negativesPerNode:48,recenter:!0},F=3,n={nodeCount:0,options:{...A},seeded:!1,lastTimestamp:0,velocities:null,forces:null,edges:new Uint32Array(0),nodeIndices:null};self.onmessage=t=>{var s;const o=t.data;if(o){if(o.type==="init"){n.nodeCount=o.nodeCount??0,n.options={...A,...n.options,...o.options},n.seeded=!1,n.lastTimestamp=0,n.velocities=new Float32Array(n.nodeCount*3),n.forces=new Float32Array(n.nodeCount*3),self.postMessage({type:"ready"});return}if(o.type==="resize"){const i=o.center??n.options.center??[0,0];n.options.center=[i[0]??0,i[1]??0,((s=n.options.center)==null?void 0:s[2])??0];return}if(o.type==="settings"){n.options={...n.options,...o.options??{}};return}o.type==="tick"&&o.positions instanceof Float32Array&&X(o)}};function X(t){if(!(t.positions instanceof Float32Array))return;if(t.options&&(n.options={...n.options,...t.options}),t.edges instanceof Uint32Array&&(n.edges=t.edges),t.nodeIndices instanceof Uint32Array&&(n.nodeIndices=t.nodeIndices),(n.options.layout||"force3d").toLowerCase()==="jitter"){Y(t.positions,t.timestamp??performance.now());return}Z(t.positions,t.timestamp??performance.now())}function Y(t,o){const{radius:s,jitter:i,center:e=[0,0],depth:a=0,mode:r="2d"}=n.options,x=F,l=t.length/x,p=e[0]??0,c=e[1]??0,d=r==="3d"?a:0;if(!n.seeded){for(let w=0;w<l;w+=1){const g=w*x;t[g]=p+(Math.random()-.5)*s,t[g+1]=c+(Math.random()-.5)*s,t[g+2]=(Math.random()-.5)*d}n.seeded=!0,n.lastTimestamp=o??performance.now(),self.postMessage({type:"positions",positions:t,timestamp:n.lastTimestamp},[t.buffer]);return}const y=o||performance.now(),f=n.lastTimestamp||y,m=Math.max(1,y-f);n.lastTimestamp=y;const u=Math.min(.1,Math.max(.008,m*.001))*60,h=i*u,z=0*u;for(let w=0;w<l;w+=1){const g=w*x;t[g]+=(Math.random()-.5)*h+(p-t[g])*z,t[g+1]+=(Math.random()-.5)*h+(c-t[g+1])*z,t[g+2]+=(Math.random()-.5)*h*(d?1:0)-t[g+2]*z}self.postMessage({type:"positions",positions:t,timestamp:n.lastTimestamp},[t.buffer])}function Z(t,o){const s=F,i=t.length/s;(!n.velocities||n.velocities.length<i*3)&&(n.velocities=new Float32Array(i*3)),(!n.forces||n.forces.length<i*3)&&(n.forces=new Float32Array(i*3));const e=(n.options.mode??"2d")==="3d",a=B(n.nodeIndices,i);if(!n.seeded){H(t,a,e),n.seeded=!0,n.lastTimestamp=o??performance.now(),self.postMessage({type:"positions",positions:t,timestamp:n.lastTimestamp},[t.buffer]);return}const{timeScale:r}=J(o),x=(n.options.eta??A.eta)*r,l=ot(n.options.damping??A.damping);_(n.forces,i),K(t,a,e),N(t,a,e),b(t,a,e),tt(t,a,e,x,l),n.options.recenter!==!1&&nt(t,a,e),n.lastTimestamp=o,self.postMessage({type:"positions",positions:t,timestamp:n.lastTimestamp},[t.buffer])}function B(t,o){if(t instanceof Uint32Array||Array.isArray(t))return t;const s=new Uint32Array(o);for(let i=0;i<o;i+=1)s[i]=i;return s}function H(t,o,s){const i=F,{radius:e,depth:a,center:r}=n.options,x=(r==null?void 0:r[2])??0;for(let l=0;l<o.length;l+=1){const c=o[l]*i;t[c]=((r==null?void 0:r[0])??0)+(Math.random()-.5)*e,t[c+1]=((r==null?void 0:r[1])??0)+(Math.random()-.5)*e,t[c+2]=x+(Math.random()-.5)*(s?a:0)}}function J(t){const o=t||performance.now(),s=n.lastTimestamp||o,i=Math.max(1,o-s),e=Math.min(.05,Math.max(.008,i*.001));return{dt:e,timeScale:e*60}}function _(t,o){const s=o*3;if(!(t.length<s))for(let i=0;i<s;i+=1)t[i]=0}function K(t,o,s){if(o.length<2)return;const i=(n.options.repulsionStrategy||A.repulsionStrategy).toLowerCase();if(i==="negative"){G(t,o,s,1);return}if(i==="full"||o.length<=32){Q(t,o,s);return}V(t,o,s),n.options.negativeSampling&&G(t,o,s,.5)}function Q(t,o,s){const i=F,e=n.options.repulsionExponent??A.repulsionExponent,a=n.options.kRepulsion??A.kRepulsion,r=n.options.epsilon??A.epsilon,x=n.options.minDistance??A.minDistance;for(let l=0;l<o.length;l+=1){const p=o[l],c=p*i,d=t[c],y=t[c+1],f=s?t[c+2]:0;for(let m=l+1;m<o.length;m+=1){const M=o[m],u=M*i,h=d-t[u],z=y-t[u+1],w=s?f-t[u+2]:0,g=h*h+z*z+w*w,R=Math.max(Math.sqrt(g),x)+r,S=a/Math.pow(R,e+1),E=h*S,k=z*S,L=w*S,I=p*3,T=M*3;n.forces[I]+=E,n.forces[I+1]+=k,n.forces[I+2]+=L,n.forces[T]-=E,n.forces[T+1]-=k,n.forces[T+2]-=L}}}function G(t,o,s,i){const e=F,a=n.options.repulsionExponent??A.repulsionExponent,r=(n.options.kRepulsion??A.kRepulsion)*i,x=n.options.epsilon??A.epsilon,l=n.options.minDistance??A.minDistance,p=Math.max(1,Math.floor(n.options.negativesPerNode??A.negativesPerNode)),c=o.length;for(let d=0;d<c;d+=1){const y=o[d],f=y*e,m=t[f],M=t[f+1],u=s?t[f+2]:0;let h=0,z=0,w=0;for(let R=0;R<p;R+=1){let S=Math.floor(Math.random()*c);S===d&&(S=(S+1)%c);const k=o[S]*e,L=m-t[k],I=M-t[k+1],T=s?u-t[k+2]:0,v=L*L+I*I+T*T,C=Math.max(Math.sqrt(v),l)+x,q=r/Math.pow(C,a+1);h+=L*q,z+=I*q,w+=T*q}const g=(c-1)/p,j=y*3;n.forces[j]+=h*g,n.forces[j+1]+=z*g,n.forces[j+2]+=w*g}}function V(t,o,s){if(o.length===0)return;const i=W(t,o,s),e=F,a=n.options.repulsionExponent??A.repulsionExponent,r=n.options.kRepulsion??A.kRepulsion,x=n.options.epsilon??A.epsilon,l=n.options.minDistance??A.minDistance;for(let p=0;p<o.length;p+=1){const c=o[p],d=c*e,y=t[d],f=t[d+1],m=s?t[d+2]:0,M=[0];for(;M.length>0;){const u=M.pop(),h=i[u];if(!h||h.mass===0)continue;if(h.isLeaf){for(let S=0;S<h.indices.length;S+=1){const E=h.indices[S];if(E===c)continue;const k=E*e,L=y-t[k],I=f-t[k+1],T=s?m-t[k+2]:0,P=Math.max(Math.sqrt(L*L+I*I+T*T),l)+x,C=r/Math.pow(P,a+1),q=c*3;n.forces[q]+=L*C,n.forces[q+1]+=I*C,n.forces[q+2]+=T*C}continue}const z=y-h.com[0],w=f-h.com[1],g=s?m-h.com[2]:0,j=Math.max(Math.sqrt(z*z+w*w+g*g),l);if((h.size||1)/j<(n.options.theta??A.theta)){const S=j+x,E=r*h.mass/Math.pow(S,a+1),k=c*3;n.forces[k]+=z*E,n.forces[k+1]+=w*E,n.forces[k+2]+=g*E}else for(let S=0;S<h.children.length;S+=1){const E=h.children[S];E!==-1&&M.push(E)}}}}function W(t,o,s){const i=F;let e=1/0,a=1/0,r=1/0,x=-1/0,l=-1/0,p=-1/0;for(let m=0;m<o.length;m+=1){const M=o[m]*i,u=t[M],h=t[M+1],z=s?t[M+2]:0;u<e&&(e=u),h<a&&(a=h),z<r&&(r=z),u>x&&(x=u),h>l&&(l=h),z>p&&(p=z)}const c=Math.max(x-e,l-a,p-r,n.options.minDistance||1),d=c*.5||1,f=[{center:[(e+x)*.5||0,(a+l)*.5||0,(r+p)*.5||0],half:d,size:c,children:new Array(8).fill(-1),indices:[],isLeaf:!0,mass:0,com:[0,0,0]}];for(let m=0;m<o.length;m+=1)O(f,0,o[m],t,s,0);return U(0,f,t,s),f}function O(t,o,s,i,e,a){const r=t[o];if(r.isLeaf&&(r.indices.length<(n.options.leafSize??A.leafSize)||a>18)){r.indices.push(s);return}if(r.isLeaf){$(t,o);const l=r.indices.slice();r.indices.length=0;for(let p=0;p<l.length;p+=1)O(t,o,l[p],i,e,a+1)}const x=D(r,s,i,e);O(t,x,s,i,e,a+1)}function $(t,o){const s=t[o],i=s.half*.5,e=[[-1,-1,-1],[1,-1,-1],[-1,1,-1],[1,1,-1],[-1,-1,1],[1,-1,1],[-1,1,1],[1,1,1]];for(let a=0;a<8;a+=1){const[r,x,l]=e[a],p=[s.center[0]+r*i,s.center[1]+x*i,s.center[2]+l*i];t.push({center:p,half:i,size:s.half,children:new Array(8).fill(-1),indices:[],isLeaf:!0,mass:0,com:[0,0,0]}),s.children[a]=t.length-1}s.isLeaf=!1}function D(t,o,s,i){const a=o*F,r=s[a],x=s[a+1],l=i?s[a+2]:0,p=r>=t.center[0]?1:0,c=x>=t.center[1]?1:0,y=(l>=t.center[2]?1:0)<<2|c<<1|p;return t.children[y]}function U(t,o,s,i){const e=o[t];if(e.isLeaf){const p=F,c=e.indices.length;if(!c)return e.mass=0,e.com=[0,0,0],0;let d=0,y=0,f=0;for(let m=0;m<c;m+=1){const M=e.indices[m]*p;d+=s[M],y+=s[M+1],f+=i?s[M+2]:0}return e.mass=c,e.com=[d/c,y/c,f/c],c}let a=0,r=0,x=0,l=0;for(let p=0;p<e.children.length;p+=1){const c=e.children[p];if(c===-1)continue;const d=U(c,o,s,i),y=o[c];d>0&&(a+=d,r+=y.com[0]*d,x+=y.com[1]*d,l+=y.com[2]*d)}return e.mass=a,a>0?e.com=[r/a,x/a,l/a]:e.com=[0,0,0],a}function N(t,o,s){if(!n.edges||n.edges.length===0)return;const i=F,e=n.options.attractionExponent??A.attractionExponent,a=n.options.kAttraction??A.kAttraction,r=n.options.minDistance??A.minDistance,x=n.edges.length/2,l=n.nodeActivity;for(let p=0;p<x;p+=1){const c=n.edges[p*2],d=n.edges[p*2+1];if(l&&(!l[c]||!l[d]))continue;const y=c*i,f=d*i,m=t[y]-t[f],M=t[y+1]-t[f+1],u=s?t[y+2]-t[f+2]:0,h=Math.max(Math.sqrt(m*m+M*M+u*u),r),z=-a*Math.pow(h,e-1),w=m*z,g=M*z,j=u*z,R=c*3,S=d*3;n.forces[R]+=w,n.forces[R+1]+=g,n.forces[R+2]+=j,n.forces[S]-=w,n.forces[S+1]-=g,n.forces[S+2]-=j}}function b(t,o,s){var l,p,c;const i=n.options.kGravity??A.kGravity;if(!i)return;const e=((l=n.options.center)==null?void 0:l[0])??0,a=((p=n.options.center)==null?void 0:p[1])??0,r=((c=n.options.center)==null?void 0:c[2])??0,x=F;for(let d=0;d<o.length;d+=1){const y=o[d],f=y*x,m=t[f]-e,M=t[f+1]-a,u=s?t[f+2]-r:0,h=y*3;n.forces[h]-=i*m,n.forces[h+1]-=i*M,n.forces[h+2]-=i*u}}function tt(t,o,s,i,e){const a=n.options.maxForce??A.maxForce,r=n.options.maxStep??A.maxStep,x=F;for(let l=0;l<o.length;l+=1){const p=o[l],c=p*3;let d=n.forces[c],y=n.forces[c+1],f=s?n.forces[c+2]:0;const m=Math.sqrt(d*d+y*y+f*f);if(a>0&&m>a){const g=a/(m+1e-9);d*=g,y*=g,f*=g}let M=(n.velocities[c]??0)*e+i*d,u=(n.velocities[c+1]??0)*e+i*y,h=s?(n.velocities[c+2]??0)*e+i*f:0;const z=Math.sqrt(M*M+u*u+h*h);if(r>0&&z>r){const g=r/(z+1e-9);M*=g,u*=g,h*=g}n.velocities[c]=M,n.velocities[c+1]=u,n.velocities[c+2]=h;const w=p*x;t[w]+=M,t[w+1]+=u,t[w+2]=s?t[w+2]+h:0}}function nt(t,o,s){var c,d,y;if(!o.length)return;const i=F;let e=0,a=0,r=0;for(let f=0;f<o.length;f+=1){const m=o[f]*i;e+=t[m],a+=t[m+1],r+=s?t[m+2]:0}e/=o.length,a/=o.length,r=s?r/o.length:0;const x=((c=n.options.center)==null?void 0:c[0])??0,l=((d=n.options.center)==null?void 0:d[1])??0,p=((y=n.options.center)==null?void 0:y[2])??0;for(let f=0;f<o.length;f+=1){const m=o[f]*i;t[m]+=x-e,t[m+1]+=l-a,t[m+2]=s?t[m+2]+p-r:0}}function ot(t){return Math.min(1,Math.max(0,t))}
2
+ //# sourceMappingURL=layoutWorker-Lc8iIdmf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layoutWorker-Lc8iIdmf.js","sources":["../../helios-web-next/src/workers/layoutWorker.js"],"sourcesContent":["const defaultOptions = {\n layout: 'force3d', // 'force3d' | 'jitter'\n mode: '2d', // '2d' | '3d'\n center: [0, 0, 0],\n radius: 150,\n depth: 0,\n jitter: 3,\n // Force-directed controls\n repulsionExponent: 2,\n attractionExponent: 1,\n kRepulsion: 6,\n kAttraction: 0.0035,\n kGravity: 0.0005,\n epsilon: 0.25,\n minDistance: 0.25,\n maxForce: 50,\n maxStep: 3,\n eta: 0.04,\n damping: 0.9,\n theta: 0.6,\n leafSize: 16,\n repulsionStrategy: 'barnes-hut', // 'barnes-hut' | 'negative' | 'full'\n negativeSampling: false,\n negativesPerNode: 48,\n recenter: true,\n};\n\nconst POSITION_STRIDE = 3;\n\nconst state = {\n nodeCount: 0,\n options: { ...defaultOptions },\n seeded: false,\n lastTimestamp: 0,\n velocities: null,\n forces: null,\n edges: new Uint32Array(0),\n nodeIndices: null,\n};\n\nself.onmessage = (event) => {\n const data = event.data;\n if (!data) return;\n if (data.type === 'init') {\n state.nodeCount = data.nodeCount ?? 0;\n state.options = { ...defaultOptions, ...state.options, ...data.options };\n state.seeded = false;\n state.lastTimestamp = 0;\n state.velocities = new Float32Array(state.nodeCount * 3);\n state.forces = new Float32Array(state.nodeCount * 3);\n self.postMessage({ type: 'ready' });\n return;\n }\n if (data.type === 'resize') {\n const center = data.center ?? state.options.center ?? [0, 0];\n state.options.center = [center[0] ?? 0, center[1] ?? 0, state.options.center?.[2] ?? 0];\n return;\n }\n if (data.type === 'settings') {\n state.options = { ...state.options, ...(data.options ?? {}) };\n return;\n }\n if (data.type === 'tick' && data.positions instanceof Float32Array) {\n stepLayout(data);\n }\n};\n\nfunction stepLayout(message) {\n if (!(message.positions instanceof Float32Array)) return;\n if (message.options) {\n state.options = { ...state.options, ...message.options };\n }\n if (message.edges instanceof Uint32Array) {\n state.edges = message.edges;\n }\n if (message.nodeIndices instanceof Uint32Array) {\n state.nodeIndices = message.nodeIndices;\n }\n\n const layoutMode = (state.options.layout || 'force3d').toLowerCase();\n if (layoutMode === 'jitter') {\n runJitterLayout(message.positions, message.timestamp ?? performance.now());\n return;\n }\n runForceDirectedLayout(message.positions, message.timestamp ?? performance.now());\n}\n\nfunction runJitterLayout(buffer, timestamp) {\n const { radius, jitter, center = [0, 0], depth = 0, mode = '2d' } = state.options;\n const stride = POSITION_STRIDE;\n const count = buffer.length / stride;\n const cx = center[0] ?? 0;\n const cy = center[1] ?? 0;\n const useDepth = mode === '3d' ? depth : 0;\n\n if (!state.seeded) {\n for (let index = 0; index < count; index += 1) {\n const pos = index * stride;\n buffer[pos] = cx + (Math.random() - 0.5) * radius;\n buffer[pos + 1] = cy + (Math.random() - 0.5) * radius;\n buffer[pos + 2] = (Math.random() - 0.5) * useDepth;\n // no w component; positions are xyz\n }\n state.seeded = true;\n state.lastTimestamp = timestamp ?? performance.now();\n self.postMessage({ type: 'positions', positions: buffer, timestamp: state.lastTimestamp }, [buffer.buffer]);\n return;\n }\n\n const now = timestamp || performance.now();\n const last = state.lastTimestamp || now;\n const dtMs = Math.max(1, now - last);\n state.lastTimestamp = now;\n const dt = Math.min(0.1, Math.max(0.008, dtMs * 0.001));\n const timeScale = dt * 60;\n const jitterScale = jitter * timeScale;\n const spring = 0.0 * timeScale;\n\n for (let index = 0; index < count; index += 1) {\n const pos = index * stride;\n buffer[pos] += (Math.random() - 0.5) * jitterScale + (cx - buffer[pos]) * spring;\n buffer[pos + 1] += (Math.random() - 0.5) * jitterScale + (cy - buffer[pos + 1]) * spring;\n buffer[pos + 2] += (Math.random() - 0.5) * jitterScale * (useDepth ? 1 : 0) - buffer[pos + 2] * spring;\n // keep positions bounded without a w component\n }\n self.postMessage({ type: 'positions', positions: buffer, timestamp: state.lastTimestamp }, [buffer.buffer]);\n}\n\nfunction runForceDirectedLayout(buffer, timestamp) {\n const stride = POSITION_STRIDE;\n const count = buffer.length / stride;\n if (!state.velocities || state.velocities.length < count * 3) {\n state.velocities = new Float32Array(count * 3);\n }\n if (!state.forces || state.forces.length < count * 3) {\n state.forces = new Float32Array(count * 3);\n }\n const useDepth = (state.options.mode ?? '2d') === '3d';\n const activeNodes = collectActiveNodes(state.nodeIndices, count);\n\n if (!state.seeded) {\n seedPositions(buffer, activeNodes, useDepth);\n state.seeded = true;\n state.lastTimestamp = timestamp ?? performance.now();\n self.postMessage({ type: 'positions', positions: buffer, timestamp: state.lastTimestamp }, [buffer.buffer]);\n return;\n }\n\n const { dt, timeScale } = computeTimestep(timestamp);\n const effectiveEta = (state.options.eta ?? defaultOptions.eta) * timeScale;\n const damping = clamp01(state.options.damping ?? defaultOptions.damping);\n\n zeroForces(state.forces, count);\n applyRepulsion(buffer, activeNodes, useDepth);\n applyAttraction(buffer, activeNodes, useDepth);\n applyGravity(buffer, activeNodes, useDepth);\n\n integrate(buffer, activeNodes, useDepth, effectiveEta, damping);\n if (state.options.recenter !== false) {\n recenter(buffer, activeNodes, useDepth);\n }\n state.lastTimestamp = timestamp;\n self.postMessage({ type: 'positions', positions: buffer, timestamp: state.lastTimestamp }, [buffer.buffer]);\n}\n\nfunction collectActiveNodes(activity, count) {\n if (activity instanceof Uint32Array || Array.isArray(activity)) {\n return activity;\n }\n const active = new Uint32Array(count);\n for (let i = 0; i < count; i += 1) {\n active[i] = i;\n }\n return active;\n}\n\nfunction seedPositions(buffer, activeNodes, useDepth) {\n const stride = POSITION_STRIDE;\n const { radius, depth, center } = state.options;\n const cz = center?.[2] ?? 0;\n for (let i = 0; i < activeNodes.length; i += 1) {\n const index = activeNodes[i];\n const pos = index * stride;\n buffer[pos] = (center?.[0] ?? 0) + (Math.random() - 0.5) * radius;\n buffer[pos + 1] = (center?.[1] ?? 0) + (Math.random() - 0.5) * radius;\n buffer[pos + 2] = cz + (Math.random() - 0.5) * (useDepth ? depth : 0);\n }\n}\n\nfunction computeTimestep(timestamp) {\n const now = timestamp || performance.now();\n const last = state.lastTimestamp || now;\n const dtMs = Math.max(1, now - last);\n const dt = Math.min(0.05, Math.max(0.008, dtMs * 0.001));\n return {\n dt,\n timeScale: dt * 60,\n };\n}\n\nfunction zeroForces(forces, count) {\n const needed = count * 3;\n if (forces.length < needed) return;\n for (let i = 0; i < needed; i += 1) {\n forces[i] = 0;\n }\n}\n\nfunction applyRepulsion(buffer, activeNodes, useDepth) {\n if (activeNodes.length < 2) return;\n const strategy = (state.options.repulsionStrategy || defaultOptions.repulsionStrategy).toLowerCase();\n if (strategy === 'negative') {\n repulsionByNegativeSampling(buffer, activeNodes, useDepth, 1);\n return;\n }\n if (strategy === 'full' || activeNodes.length <= 32) {\n repulsionAllPairs(buffer, activeNodes, useDepth);\n return;\n }\n repulsionBarnesHut(buffer, activeNodes, useDepth);\n if (state.options.negativeSampling) {\n repulsionByNegativeSampling(buffer, activeNodes, useDepth, 0.5);\n }\n}\n\nfunction repulsionAllPairs(buffer, activeNodes, useDepth) {\n const stride = POSITION_STRIDE;\n const rExp = state.options.repulsionExponent ?? defaultOptions.repulsionExponent;\n const kRep = state.options.kRepulsion ?? defaultOptions.kRepulsion;\n const eps = state.options.epsilon ?? defaultOptions.epsilon;\n const dMin = state.options.minDistance ?? defaultOptions.minDistance;\n for (let idx = 0; idx < activeNodes.length; idx += 1) {\n const i = activeNodes[idx];\n const io = i * stride;\n const ix = buffer[io];\n const iy = buffer[io + 1];\n const iz = useDepth ? buffer[io + 2] : 0;\n for (let jdx = idx + 1; jdx < activeNodes.length; jdx += 1) {\n const j = activeNodes[jdx];\n const jo = j * stride;\n const dx = ix - buffer[jo];\n const dy = iy - buffer[jo + 1];\n const dz = useDepth ? iz - buffer[jo + 2] : 0;\n const distSq = dx * dx + dy * dy + dz * dz;\n const dist = Math.max(Math.sqrt(distSq), dMin);\n const dEff = dist + eps;\n const scale = kRep / Math.pow(dEff, rExp + 1);\n const fx = dx * scale;\n const fy = dy * scale;\n const fz = dz * scale;\n const fi = i * 3;\n const fj = j * 3;\n state.forces[fi] += fx;\n state.forces[fi + 1] += fy;\n state.forces[fi + 2] += fz;\n state.forces[fj] -= fx;\n state.forces[fj + 1] -= fy;\n state.forces[fj + 2] -= fz;\n }\n }\n}\n\nfunction repulsionByNegativeSampling(buffer, activeNodes, useDepth, scaleFactor) {\n const stride = POSITION_STRIDE;\n const rExp = state.options.repulsionExponent ?? defaultOptions.repulsionExponent;\n const kRep = (state.options.kRepulsion ?? defaultOptions.kRepulsion) * scaleFactor;\n const eps = state.options.epsilon ?? defaultOptions.epsilon;\n const dMin = state.options.minDistance ?? defaultOptions.minDistance;\n const samples = Math.max(1, Math.floor(state.options.negativesPerNode ?? defaultOptions.negativesPerNode));\n const total = activeNodes.length;\n for (let idx = 0; idx < total; idx += 1) {\n const i = activeNodes[idx];\n const io = i * stride;\n const ix = buffer[io];\n const iy = buffer[io + 1];\n const iz = useDepth ? buffer[io + 2] : 0;\n let fx = 0;\n let fy = 0;\n let fz = 0;\n for (let s = 0; s < samples; s += 1) {\n let jIdx = Math.floor(Math.random() * total);\n if (jIdx === idx) {\n jIdx = (jIdx + 1) % total;\n }\n const j = activeNodes[jIdx];\n const jo = j * stride;\n const dx = ix - buffer[jo];\n const dy = iy - buffer[jo + 1];\n const dz = useDepth ? iz - buffer[jo + 2] : 0;\n const distSq = dx * dx + dy * dy + dz * dz;\n const dist = Math.max(Math.sqrt(distSq), dMin);\n const dEff = dist + eps;\n const scale = kRep / Math.pow(dEff, rExp + 1);\n fx += dx * scale;\n fy += dy * scale;\n fz += dz * scale;\n }\n const weight = (total - 1) / samples;\n const fo = i * 3;\n state.forces[fo] += fx * weight;\n state.forces[fo + 1] += fy * weight;\n state.forces[fo + 2] += fz * weight;\n }\n}\n\nfunction repulsionBarnesHut(buffer, activeNodes, useDepth) {\n if (activeNodes.length === 0) return;\n const tree = buildOctree(buffer, activeNodes, useDepth);\n const stride = POSITION_STRIDE;\n const rExp = state.options.repulsionExponent ?? defaultOptions.repulsionExponent;\n const kRep = state.options.kRepulsion ?? defaultOptions.kRepulsion;\n const eps = state.options.epsilon ?? defaultOptions.epsilon;\n const dMin = state.options.minDistance ?? defaultOptions.minDistance;\n for (let idx = 0; idx < activeNodes.length; idx += 1) {\n const i = activeNodes[idx];\n const io = i * stride;\n const px = buffer[io];\n const py = buffer[io + 1];\n const pz = useDepth ? buffer[io + 2] : 0;\n const stack = [0];\n while (stack.length > 0) {\n const nodeIndex = stack.pop();\n const cell = tree[nodeIndex];\n if (!cell || cell.mass === 0) continue;\n if (cell.isLeaf) {\n for (let j = 0; j < cell.indices.length; j += 1) {\n const target = cell.indices[j];\n if (target === i) continue;\n const to = target * stride;\n const dx = px - buffer[to];\n const dy = py - buffer[to + 1];\n const dz = useDepth ? pz - buffer[to + 2] : 0;\n const dist = Math.max(Math.sqrt(dx * dx + dy * dy + dz * dz), dMin);\n const dEff = dist + eps;\n const scale = kRep / Math.pow(dEff, rExp + 1);\n const fo = i * 3;\n state.forces[fo] += dx * scale;\n state.forces[fo + 1] += dy * scale;\n state.forces[fo + 2] += dz * scale;\n }\n continue;\n }\n const dx = px - cell.com[0];\n const dy = py - cell.com[1];\n const dz = useDepth ? pz - cell.com[2] : 0;\n const dist = Math.max(Math.sqrt(dx * dx + dy * dy + dz * dz), dMin);\n const open = (cell.size || 1) / dist;\n if (open < (state.options.theta ?? defaultOptions.theta)) {\n const dEff = dist + eps;\n const scale = (kRep * cell.mass) / Math.pow(dEff, rExp + 1);\n const fo = i * 3;\n state.forces[fo] += dx * scale;\n state.forces[fo + 1] += dy * scale;\n state.forces[fo + 2] += dz * scale;\n } else {\n for (let c = 0; c < cell.children.length; c += 1) {\n const childIndex = cell.children[c];\n if (childIndex !== -1) {\n stack.push(childIndex);\n }\n }\n }\n }\n }\n}\n\nfunction buildOctree(buffer, activeNodes, useDepth) {\n const stride = POSITION_STRIDE;\n let minX = Infinity;\n let minY = Infinity;\n let minZ = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n let maxZ = -Infinity;\n for (let i = 0; i < activeNodes.length; i += 1) {\n const idx = activeNodes[i] * stride;\n const x = buffer[idx];\n const y = buffer[idx + 1];\n const z = useDepth ? buffer[idx + 2] : 0;\n if (x < minX) minX = x;\n if (y < minY) minY = y;\n if (z < minZ) minZ = z;\n if (x > maxX) maxX = x;\n if (y > maxY) maxY = y;\n if (z > maxZ) maxZ = z;\n }\n const size = Math.max(maxX - minX, maxY - minY, maxZ - minZ, state.options.minDistance || 1);\n const half = size * 0.5 || 1;\n const center = [(minX + maxX) * 0.5 || 0, (minY + maxY) * 0.5 || 0, (minZ + maxZ) * 0.5 || 0];\n const tree = [\n {\n center,\n half,\n size,\n children: new Array(8).fill(-1),\n indices: [],\n isLeaf: true,\n mass: 0,\n com: [0, 0, 0],\n },\n ];\n for (let i = 0; i < activeNodes.length; i += 1) {\n insertIntoOctree(tree, 0, activeNodes[i], buffer, useDepth, 0);\n }\n computeMass(0, tree, buffer, useDepth);\n return tree;\n}\n\nfunction insertIntoOctree(tree, nodeIndex, pointIndex, buffer, useDepth, depth) {\n const node = tree[nodeIndex];\n if (node.isLeaf && (node.indices.length < (state.options.leafSize ?? defaultOptions.leafSize) || depth > 18)) {\n node.indices.push(pointIndex);\n return;\n }\n if (node.isLeaf) {\n subdivide(tree, nodeIndex);\n const existing = node.indices.slice();\n node.indices.length = 0;\n for (let i = 0; i < existing.length; i += 1) {\n insertIntoOctree(tree, nodeIndex, existing[i], buffer, useDepth, depth + 1);\n }\n }\n const child = selectOctant(node, pointIndex, buffer, useDepth);\n insertIntoOctree(tree, child, pointIndex, buffer, useDepth, depth + 1);\n}\n\nfunction subdivide(tree, nodeIndex) {\n const node = tree[nodeIndex];\n const quarter = node.half * 0.5;\n const offsets = [\n [-1, -1, -1],\n [1, -1, -1],\n [-1, 1, -1],\n [1, 1, -1],\n [-1, -1, 1],\n [1, -1, 1],\n [-1, 1, 1],\n [1, 1, 1],\n ];\n for (let i = 0; i < 8; i += 1) {\n const [ox, oy, oz] = offsets[i];\n const center = [node.center[0] + ox * quarter, node.center[1] + oy * quarter, node.center[2] + oz * quarter];\n tree.push({\n center,\n half: quarter,\n size: node.half,\n children: new Array(8).fill(-1),\n indices: [],\n isLeaf: true,\n mass: 0,\n com: [0, 0, 0],\n });\n node.children[i] = tree.length - 1;\n }\n node.isLeaf = false;\n}\n\nfunction selectOctant(node, pointIndex, buffer, useDepth) {\n const stride = POSITION_STRIDE;\n const offset = pointIndex * stride;\n const x = buffer[offset];\n const y = buffer[offset + 1];\n const z = useDepth ? buffer[offset + 2] : 0;\n const right = x >= node.center[0] ? 1 : 0;\n const top = y >= node.center[1] ? 1 : 0;\n const front = z >= node.center[2] ? 1 : 0;\n const octant = (front << 2) | (top << 1) | right;\n return node.children[octant];\n}\n\nfunction computeMass(index, tree, buffer, useDepth) {\n const node = tree[index];\n if (node.isLeaf) {\n const stride = POSITION_STRIDE;\n const len = node.indices.length;\n if (!len) {\n node.mass = 0;\n node.com = [0, 0, 0];\n return 0;\n }\n let sx = 0;\n let sy = 0;\n let sz = 0;\n for (let i = 0; i < len; i += 1) {\n const idx = node.indices[i] * stride;\n sx += buffer[idx];\n sy += buffer[idx + 1];\n sz += useDepth ? buffer[idx + 2] : 0;\n }\n node.mass = len;\n node.com = [sx / len, sy / len, sz / len];\n return len;\n }\n let mass = 0;\n let cx = 0;\n let cy = 0;\n let cz = 0;\n for (let i = 0; i < node.children.length; i += 1) {\n const childIndex = node.children[i];\n if (childIndex === -1) continue;\n const childMass = computeMass(childIndex, tree, buffer, useDepth);\n const child = tree[childIndex];\n if (childMass > 0) {\n mass += childMass;\n cx += child.com[0] * childMass;\n cy += child.com[1] * childMass;\n cz += child.com[2] * childMass;\n }\n }\n node.mass = mass;\n if (mass > 0) {\n node.com = [cx / mass, cy / mass, cz / mass];\n } else {\n node.com = [0, 0, 0];\n }\n return mass;\n}\n\nfunction applyAttraction(buffer, activeNodes, useDepth) {\n if (!state.edges || state.edges.length === 0) return;\n const stride = POSITION_STRIDE;\n const aExp = state.options.attractionExponent ?? defaultOptions.attractionExponent;\n const kAtt = state.options.kAttraction ?? defaultOptions.kAttraction;\n const dMin = state.options.minDistance ?? defaultOptions.minDistance;\n const edgeCount = state.edges.length / 2;\n const activity = state.nodeActivity;\n for (let e = 0; e < edgeCount; e += 1) {\n const from = state.edges[e * 2];\n const to = state.edges[e * 2 + 1];\n if (activity && (!activity[from] || !activity[to])) continue;\n const fo = from * stride;\n const toOff = to * stride;\n const dx = buffer[fo] - buffer[toOff];\n const dy = buffer[fo + 1] - buffer[toOff + 1];\n const dz = useDepth ? buffer[fo + 2] - buffer[toOff + 2] : 0;\n const dist = Math.max(Math.sqrt(dx * dx + dy * dy + dz * dz), dMin);\n const scale = -kAtt * Math.pow(dist, aExp - 1);\n const fx = dx * scale;\n const fy = dy * scale;\n const fz = dz * scale;\n const fromF = from * 3;\n const toF = to * 3;\n state.forces[fromF] += fx;\n state.forces[fromF + 1] += fy;\n state.forces[fromF + 2] += fz;\n state.forces[toF] -= fx;\n state.forces[toF + 1] -= fy;\n state.forces[toF + 2] -= fz;\n }\n}\n\nfunction applyGravity(buffer, activeNodes, useDepth) {\n const kGrav = state.options.kGravity ?? defaultOptions.kGravity;\n if (!kGrav) return;\n const cx = state.options.center?.[0] ?? 0;\n const cy = state.options.center?.[1] ?? 0;\n const cz = state.options.center?.[2] ?? 0;\n const stride = POSITION_STRIDE;\n for (let i = 0; i < activeNodes.length; i += 1) {\n const index = activeNodes[i];\n const offset = index * stride;\n const dx = buffer[offset] - cx;\n const dy = buffer[offset + 1] - cy;\n const dz = useDepth ? buffer[offset + 2] - cz : 0;\n const fo = index * 3;\n state.forces[fo] -= kGrav * dx;\n state.forces[fo + 1] -= kGrav * dy;\n state.forces[fo + 2] -= kGrav * dz;\n }\n}\n\nfunction integrate(buffer, activeNodes, useDepth, eta, damping) {\n const maxForce = state.options.maxForce ?? defaultOptions.maxForce;\n const maxStep = state.options.maxStep ?? defaultOptions.maxStep;\n const stride = POSITION_STRIDE;\n for (let i = 0; i < activeNodes.length; i += 1) {\n const index = activeNodes[i];\n const fo = index * 3;\n let fx = state.forces[fo];\n let fy = state.forces[fo + 1];\n let fz = useDepth ? state.forces[fo + 2] : 0;\n const normF = Math.sqrt(fx * fx + fy * fy + fz * fz);\n if (maxForce > 0 && normF > maxForce) {\n const s = maxForce / (normF + 1e-9);\n fx *= s;\n fy *= s;\n fz *= s;\n }\n let vx = (state.velocities[fo] ?? 0) * damping + eta * fx;\n let vy = (state.velocities[fo + 1] ?? 0) * damping + eta * fy;\n let vz = useDepth ? (state.velocities[fo + 2] ?? 0) * damping + eta * fz : 0;\n const stepNorm = Math.sqrt(vx * vx + vy * vy + vz * vz);\n if (maxStep > 0 && stepNorm > maxStep) {\n const s = maxStep / (stepNorm + 1e-9);\n vx *= s;\n vy *= s;\n vz *= s;\n }\n state.velocities[fo] = vx;\n state.velocities[fo + 1] = vy;\n state.velocities[fo + 2] = vz;\n\n const pos = index * stride;\n buffer[pos] += vx;\n buffer[pos + 1] += vy;\n buffer[pos + 2] = useDepth ? buffer[pos + 2] + vz : 0;\n }\n}\n\nfunction recenter(buffer, activeNodes, useDepth) {\n if (!activeNodes.length) return;\n const stride = POSITION_STRIDE;\n let cx = 0;\n let cy = 0;\n let cz = 0;\n for (let i = 0; i < activeNodes.length; i += 1) {\n const offset = activeNodes[i] * stride;\n cx += buffer[offset];\n cy += buffer[offset + 1];\n cz += useDepth ? buffer[offset + 2] : 0;\n }\n cx /= activeNodes.length;\n cy /= activeNodes.length;\n cz = useDepth ? cz / activeNodes.length : 0;\n\n const targetX = state.options.center?.[0] ?? 0;\n const targetY = state.options.center?.[1] ?? 0;\n const targetZ = state.options.center?.[2] ?? 0;\n for (let i = 0; i < activeNodes.length; i += 1) {\n const offset = activeNodes[i] * stride;\n buffer[offset] += targetX - cx;\n buffer[offset + 1] += targetY - cy;\n buffer[offset + 2] = useDepth ? buffer[offset + 2] + targetZ - cz : 0;\n }\n}\n\nfunction clamp01(value) {\n return Math.min(1, Math.max(0, value));\n}\n"],"names":["defaultOptions","POSITION_STRIDE","state","event","_a","data","center","stepLayout","message","runJitterLayout","runForceDirectedLayout","buffer","timestamp","radius","jitter","depth","mode","stride","count","cx","cy","useDepth","index","pos","now","last","dtMs","timeScale","jitterScale","spring","activeNodes","collectActiveNodes","seedPositions","computeTimestep","effectiveEta","damping","clamp01","zeroForces","applyRepulsion","applyAttraction","applyGravity","integrate","recenter","activity","active","cz","i","dt","forces","needed","strategy","repulsionByNegativeSampling","repulsionAllPairs","repulsionBarnesHut","rExp","kRep","eps","dMin","idx","io","ix","iy","iz","jdx","j","jo","dx","dy","dz","distSq","dEff","scale","fx","fy","fz","fi","fj","scaleFactor","samples","total","s","jIdx","weight","fo","tree","buildOctree","px","py","pz","stack","nodeIndex","cell","target","to","dist","c","childIndex","minX","minY","minZ","maxX","maxY","maxZ","x","y","size","half","insertIntoOctree","computeMass","pointIndex","node","subdivide","existing","child","selectOctant","quarter","offsets","ox","oy","oz","offset","z","right","top","octant","len","sx","sy","sz","mass","childMass","aExp","kAtt","edgeCount","e","from","toOff","fromF","toF","_b","_c","kGrav","eta","maxForce","maxStep","normF","vx","vy","vz","stepNorm","targetX","targetY","targetZ","value"],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Helios CLI Session</title>
7
+ <style>
8
+ html, body {
9
+ margin: 0;
10
+ padding: 0;
11
+ width: 100%;
12
+ height: 100%;
13
+ overflow: hidden;
14
+ background: #050505;
15
+ color: #f6f4ef;
16
+ }
17
+ #app {
18
+ width: 100%;
19
+ height: 100%;
20
+ }
21
+ </style>
22
+ <script type="module" crossorigin src="/assets/index-CP7mSmLx.js"></script>
23
+ </head>
24
+ <body>
25
+ <div id="app"></div>
26
+ </body>
27
+ </html>
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@filsilva/helios-cli",
3
+ "version": "0.10.0",
4
+ "description": "Agent-friendly CLI for running and controlling Helios Web sessions.",
5
+ "private": false,
6
+ "type": "module",
7
+ "bin": {
8
+ "helios": "bin/helios.js"
9
+ },
10
+ "scripts": {
11
+ "build-client": "vite build",
12
+ "build": "npm run build-client",
13
+ "test": "npm run build-client && node --test tests/*.test.js"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+ssh://git@github.com/filipinascimento/helios-cli.git"
18
+ },
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "license": "MIT",
23
+ "files": [
24
+ "bin",
25
+ "dist",
26
+ "skills",
27
+ "src",
28
+ "README.md",
29
+ "vite.config.js"
30
+ ],
31
+ "dependencies": {
32
+ "helios-network": "^0.10.0",
33
+ "playwright": "^1.56.1",
34
+ "ws": "^8.18.0",
35
+ "helios-web": "^0.10.0"
36
+ },
37
+ "devDependencies": {
38
+ "vite": "^5.4.10"
39
+ }
40
+ }
@@ -0,0 +1,118 @@
1
+ # Helios CLI Skill
2
+
3
+ Use this skill when an agent needs to create, inspect, render, manipulate, or export Helios visualizations through the `helios` command-line session daemon.
4
+
5
+ ## Install
6
+
7
+ Check that Node.js is available before using the CLI:
8
+
9
+ ```sh
10
+ node --version
11
+ npm --version
12
+ ```
13
+
14
+ If `node` or `npm` is missing, install Node.js 18 or newer first. On macOS with Homebrew:
15
+
16
+ ```sh
17
+ brew install node
18
+ ```
19
+
20
+ On Linux, use the distribution package manager or NodeSource packages. On Windows, install the current LTS build from the official Node.js installer.
21
+
22
+ Install the published CLI and its managed browser:
23
+
24
+ ```sh
25
+ npm install -g @filsilva/helios-cli
26
+ helios browser install
27
+ helios version
28
+ ```
29
+
30
+ Use `helios browser install --with-deps` on Linux when Playwright reports missing system dependencies.
31
+
32
+ To install this skill for Codex, copy the `skills/helios-cli` directory into the local Codex skills directory:
33
+
34
+ ```sh
35
+ mkdir -p "${CODEX_HOME:-$HOME/.codex}/skills"
36
+ cp -R skills/helios-cli "${CODEX_HOME:-$HOME/.codex}/skills/helios-cli"
37
+ ```
38
+
39
+ To install this skill for Claude, copy the same `skills/helios-cli` directory into the Claude skills location used by your Claude client or project. The skill is plain Markdown plus reference files, so it does not require Codex-specific tooling.
40
+
41
+ For source checkout development, clone `helios-network`, `helios-web`, and `helios-cli` next to each other, run `npm install`, `npm run build`, and `npm link` inside `helios-cli`. The published package depends on `helios-network` and `helios-web`; source checkouts can still alias adjacent local sources during development.
42
+
43
+ ## Basic Usage
44
+
45
+ Start an interactive session in the OS/default browser:
46
+
47
+ ```sh
48
+ helios session start
49
+ ```
50
+
51
+ Start a managed automation session:
52
+
53
+ ```sh
54
+ helios session start --mode headless --renderer webgpu
55
+ ```
56
+
57
+ Use a custom daemon-owned storage root when a workflow must be isolated or reproducible:
58
+
59
+ ```sh
60
+ helios --storage-dir /tmp/helios-run session start --mode headless --renderer webgpu
61
+ ```
62
+
63
+ Save the returned `sessionId`, then call methods:
64
+
65
+ ```sh
66
+ helios call <sessionId> scene.getState
67
+ helios state set <sessionId> appearance.shaded.enabled true
68
+ helios state get <sessionId> appearance.shaded.enabled
69
+ helios call <sessionId> camera.frame --json '{"animate":true,"durationMs":500}'
70
+ helios call <sessionId> export.figure --json '{"format":"png","preset":"window","outputPath":"./figure.png"}'
71
+ helios session stop <sessionId>
72
+ ```
73
+
74
+ For interactive inspection with a network file, prefer the default OS/browser path:
75
+
76
+ ```sh
77
+ helios session start --network ./graph.bxnet
78
+ ```
79
+
80
+ ## Agent Workflow
81
+
82
+ 1. Run `helios version` to confirm the CLI and visible Helios package versions.
83
+ 2. Use plain `session start` for human visual inspection in the OS/default browser; use `--mode headless` for automated rendering/export. Reserve explicit `--mode headed` for Playwright-managed debugging.
84
+ 3. Capture the JSON session metadata from `session start`; all subsequent calls need `sessionId`.
85
+ 4. Use `scene.getState` before changes and after changes to confirm renderer, network counts, layout state, mapper state, labels, legends, density, filters, and camera state.
86
+ 5. Prefer `helios state set/get/reset` or the `state.*` RPC methods for tracked Helios Web parameters. These calls flow through `helios.states` and are saved by `helios.storage`.
87
+ 6. Use `persistence.save` before intentional reloads or handoff points when the current visual state matters. Full saves capture a session thumbnail by default; pass `{"captureThumbnail":false}` only when preserving an older preview is intentional.
88
+ 7. Stop sessions with `helios session stop <sessionId>` when finished.
89
+
90
+ ## Persistence Validation
91
+
92
+ When changing CLI session or persistence behavior, run the full test script and include at least one managed-session smoke that saves, reloads, restores, and clears persistence:
93
+
94
+ ```sh
95
+ npm test
96
+ helios --storage-dir /tmp/helios-run session start --mode headless --renderer webgl --no-gpu
97
+ helios state set <sessionId> scene.dimension '"3d"'
98
+ helios call <sessionId> persistence.save --json '{"fullSession":true}'
99
+ helios call <sessionId> persistence.save --json '{"fullSession":true,"captureThumbnail":true}'
100
+ helios call <sessionId> browser.reload --json '{"timeoutMs":30000}'
101
+ helios call <sessionId> persistence.clear
102
+ helios --storage-dir /tmp/helios-run session stop <sessionId>
103
+ ```
104
+
105
+ The CLI daemon is the storage owner. Do not rely on browser localStorage or IndexedDB for CLI persistence tests; use the daemon storage API and the filesystem under the active storage root.
106
+ Session thumbnails are private session payload metadata, not browser storage. Full saves should return thumbnail metadata with a true `dataUrl` flag, and the saved session record should contain `payload.thumbnail.dataUrl`.
107
+
108
+ ## References
109
+
110
+ - `references/rpc-methods.md` lists available JSON-RPC methods and payload shapes.
111
+ - `references/mappers.md` explains mapper descriptors for node and edge visual channels.
112
+ - `references/networks.md` covers loading, replacing, saving, and synthetic test networks.
113
+ - `references/rendering-export.md` covers renderer choices, GPU policy, screenshots, and figure export.
114
+ - `references/layouts.md` covers layout choices and parameter updates.
115
+ - `references/metrics.md` covers graph/aesthetic measurements and writing results into node attributes.
116
+ - `references/behaviors.md` covers enabling, disabling, updating, detaching, restoring, and invoking Helios behaviors.
117
+ - `references/positions.md` covers custom positions, positions from attributes, and position snapshots.
118
+ - `references/persistence.md` covers automatic session persistence, browser reload recovery, and explicit save/restore calls.
@@ -0,0 +1,47 @@
1
+ # Behaviors
2
+
3
+ Behaviors expose the same interaction and UI-backed control layer used by Helios Web.
4
+
5
+ Inspect current behavior state:
6
+
7
+ ```sh
8
+ helios call "$SESSION" behaviors.get
9
+ ```
10
+
11
+ Update a built-in behavior:
12
+
13
+ ```sh
14
+ helios call "$SESSION" behaviors.update --json '{
15
+ "id": "hover",
16
+ "options": {
17
+ "hoverConnectedEdges": false,
18
+ "hoverAffectsOtherElements": true
19
+ }
20
+ }'
21
+ ```
22
+
23
+ Enable or disable a behavior that exposes `enabled(...)`:
24
+
25
+ ```sh
26
+ helios call "$SESSION" behaviors.setEnabled --json '{"id":"legends","enabled":false}'
27
+ helios call "$SESSION" behaviors.setEnabled --json '{"id":"legends","enabled":true}'
28
+ ```
29
+
30
+ Detach and reattach a behavior:
31
+
32
+ ```sh
33
+ helios call "$SESSION" behaviors.detach --json '{"id":"selection"}'
34
+ helios call "$SESSION" behaviors.use --json '{"id":"selection","options":{"nodeClick":true}}'
35
+ ```
36
+
37
+ Call an advanced behavior method directly:
38
+
39
+ ```sh
40
+ helios call "$SESSION" behaviors.call --json '{
41
+ "id": "selection",
42
+ "method": "selectNodes",
43
+ "args": [[0, 2, 4], {"mode": "replace"}]
44
+ }'
45
+ ```
46
+
47
+ Use `behaviors.restore` with a snapshot from `behaviors.get.serialized` when replaying a saved behavior state.
@@ -0,0 +1,77 @@
1
+ # Layouts
2
+
3
+ The CLI supports headed, headless, and server sessions:
4
+
5
+ ```sh
6
+ helios session start --mode headless --renderer webgpu --layout gpu-force
7
+ helios session start --layout d3force3d
8
+ helios session start --mode server --no-open
9
+ ```
10
+
11
+ ## Choices
12
+
13
+ Supported layout keys:
14
+
15
+ - `gpu-force`
16
+ - `static`
17
+ - `d3force3d`
18
+ - `worker:jitter`
19
+ - `worker:force3d`
20
+
21
+ Switch layout:
22
+
23
+ ```sh
24
+ helios call "$SESSION" layout.set --json '{"layout":"gpu-force"}'
25
+ ```
26
+
27
+ Inspect writable parameters:
28
+
29
+ ```sh
30
+ helios call "$SESSION" layout.get
31
+ ```
32
+
33
+ The response includes `descriptor.bindings`. Bindings with a writable `type` such as `number`, `boolean`, or `select` can be changed with `layout.setParameters`.
34
+
35
+ ## Parameter Updates
36
+
37
+ ```sh
38
+ helios call "$SESSION" layout.setParameters --json '{
39
+ "outputScale": 7,
40
+ "maxNeighborsPerNode": 64
41
+ }'
42
+ ```
43
+
44
+ For D3 force:
45
+
46
+ ```sh
47
+ helios call "$SESSION" layout.set --json '{"layout":"d3force3d"}'
48
+ helios call "$SESSION" layout.setParameters --json '{
49
+ "forcesStrength": 1.4,
50
+ "gravity": 0.04,
51
+ "linkDistance": 35
52
+ }'
53
+ ```
54
+
55
+ Run control:
56
+
57
+ ```sh
58
+ helios call "$SESSION" layout.start
59
+ helios call "$SESSION" layout.stop --json '{"reason":"agent"}'
60
+ ```
61
+
62
+ ## Positions From Attributes
63
+
64
+ Use a numeric 2D or 3D node attribute as layout positions:
65
+
66
+ ```sh
67
+ helios call "$SESSION" positions.fromAttribute --json '{
68
+ "attribute": "umap_position",
69
+ "stopLayout": true
70
+ }'
71
+ ```
72
+
73
+ `layout.applyPositionAttribute` is an alias for the same workflow:
74
+
75
+ ```sh
76
+ helios call "$SESSION" layout.applyPositionAttribute --json '{"attribute":"embedding3d"}'
77
+ ```
@@ -0,0 +1,119 @@
1
+ # Mappers
2
+
3
+ Mapper descriptors configure Helios Web visual channels from attributes, constants, or rules.
4
+
5
+ Use:
6
+
7
+ ```sh
8
+ helios call <sessionId> mappers.set --json '<payload>'
9
+ ```
10
+
11
+ ## Shape
12
+
13
+ The CLI accepts `nodeMapper` and `edgeMapper` descriptors. Each descriptor can be either:
14
+
15
+ ```json
16
+ {
17
+ "channels": [
18
+ { "name": "color", "config": { "type": "attribute", "attribute": "community" } },
19
+ { "name": "size", "config": { "type": "constant", "value": 8 } }
20
+ ]
21
+ }
22
+ ```
23
+
24
+ or an object keyed by channel:
25
+
26
+ ```json
27
+ {
28
+ "color": { "type": "attribute", "attribute": "community" },
29
+ "size": { "type": "constant", "value": 8 }
30
+ }
31
+ ```
32
+
33
+ ## Node Example
34
+
35
+ ```sh
36
+ helios call "$SESSION" mappers.set --json '{
37
+ "nodeMapper": {
38
+ "color": {
39
+ "type": "attribute",
40
+ "attribute": "community",
41
+ "colormap": "CET_L08-NeonBurst"
42
+ },
43
+ "size": {
44
+ "type": "attribute",
45
+ "attribute": "degree",
46
+ "range": [4, 18]
47
+ }
48
+ }
49
+ }'
50
+ ```
51
+
52
+ ## Edge Example
53
+
54
+ ```sh
55
+ helios call "$SESSION" mappers.set --json '{
56
+ "edgeMapper": {
57
+ "edgeColor": {
58
+ "type": "constant",
59
+ "value": [0.35, 0.55, 1.0, 0.55]
60
+ },
61
+ "edgeWidth": {
62
+ "type": "attribute",
63
+ "attribute": "weight",
64
+ "range": [0.5, 4]
65
+ }
66
+ }
67
+ }'
68
+ ```
69
+
70
+ ## Agent Checks
71
+
72
+ After setting mappers, call:
73
+
74
+ ```sh
75
+ helios call "$SESSION" mappers.get
76
+ helios call "$SESSION" scene.getState
77
+ ```
78
+
79
+ Use `mappers.reset` when you need to return to Helios defaults.
80
+
81
+ ## Function-Like Custom Mappers
82
+
83
+ JSON cannot carry JavaScript functions, so the CLI accepts code strings and compiles them in the browser session:
84
+
85
+ - `transformCode`: becomes `transform(inputs, item, context)`.
86
+ - `scaleCode`: becomes `scale(value, inputs, item, context)`.
87
+ - rule `whenCode`: becomes `when(inputs, item, context)`.
88
+ - rule `transformCode`: becomes that rule's transform callback.
89
+
90
+ Expression strings are allowed:
91
+
92
+ ```sh
93
+ helios call "$SESSION" mappers.set --json '{
94
+ "nodeMapper": {
95
+ "size": {
96
+ "type": "attribute",
97
+ "attributes": "degree",
98
+ "transformCode": "Math.max(4, inputs[0] * 2)"
99
+ }
100
+ }
101
+ }'
102
+ ```
103
+
104
+ Function bodies with `return` are also allowed:
105
+
106
+ ```sh
107
+ helios call "$SESSION" mappers.set --json '{
108
+ "nodeMapper": {
109
+ "color": {
110
+ "type": "attribute",
111
+ "attributes": ["degree", "community"],
112
+ "transformCode": "const degree = inputs[0] ?? 0; const group = inputs[1] ?? 0; return degree > 10 ? group : 0;",
113
+ "colormap": "CET_L08-NeonBurst"
114
+ }
115
+ }
116
+ }'
117
+ ```
118
+
119
+ Use code-backed mappers only for trusted local agent workflows. They execute in the browser session.
@@ -0,0 +1,83 @@
1
+ # Metrics And Aesthetic Measures
2
+
3
+ Use `metrics.measure` for graph measurements and `aesthetic.measure` as an alias when the metric is being used as an aesthetic signal for styling.
4
+
5
+ ```sh
6
+ helios call "$SESSION" metrics.measure --json '{"metric":"degree"}'
7
+ helios call "$SESSION" aesthetic.measure --json '{"metric":"dimension","options":{"maxLevel":8}}'
8
+ ```
9
+
10
+ ## Supported Metrics
11
+
12
+ - `degree`
13
+ - `strength`
14
+ - `localClustering` / `localClusteringCoefficient`
15
+ - `coreness`
16
+ - `eigenvectorCentrality`
17
+ - `betweennessCentrality`
18
+ - `connectedComponents`
19
+ - `dimension`
20
+ - `nodeDimension`
21
+ - `leiden` / `leidenModularity`
22
+ - `corenessSession`
23
+ - `connectedComponentsSession`
24
+ - `dimensionSession`
25
+
26
+ By default, large `valuesByNode` arrays are omitted for node-vector metrics. Add `"includeValuesByNode": true` if the full node-capacity vector is required.
27
+
28
+ ## Write Metric To Attribute
29
+
30
+ ```sh
31
+ helios call "$SESSION" metrics.measure --json '{
32
+ "metric": "degree",
33
+ "options": {
34
+ "direction": "both",
35
+ "outNodeAttribute": "degree"
36
+ }
37
+ }'
38
+ ```
39
+
40
+ Then map it:
41
+
42
+ ```sh
43
+ helios call "$SESSION" mappers.set --json '{
44
+ "nodeMapper": {
45
+ "size": {
46
+ "type": "attribute",
47
+ "attributes": "degree",
48
+ "domain": [0, 20],
49
+ "range": [4, 18]
50
+ }
51
+ }
52
+ }'
53
+ ```
54
+
55
+ ## Dimension As Aesthetic Signal
56
+
57
+ ```sh
58
+ helios call "$SESSION" aesthetic.measure --json '{
59
+ "metric": "dimensionSession",
60
+ "options": {
61
+ "maxLevel": 8,
62
+ "method": "leastsquares",
63
+ "captureNodeDimensionProfiles": true,
64
+ "outNodeMaxDimensionAttribute": "dim_max"
65
+ },
66
+ "budget": 500,
67
+ "maxSteps": 10000
68
+ }'
69
+ ```
70
+
71
+ Map the output:
72
+
73
+ ```sh
74
+ helios call "$SESSION" mappers.set --json '{
75
+ "nodeMapper": {
76
+ "color": {
77
+ "type": "attribute",
78
+ "attributes": "dim_max",
79
+ "colormap": "CET_L08-NeonBurst"
80
+ }
81
+ }
82
+ }'
83
+ ```