@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.
- package/README.md +171 -0
- package/bin/helios.js +34 -0
- package/dist/client/assets/HeliosSessionWorker.browser-BYYjDIKH.js +3 -0
- package/dist/client/assets/HeliosSessionWorker.browser-BYYjDIKH.js.map +1 -0
- package/dist/client/assets/d3force3dWorker-BKANL9of.js +2 -0
- package/dist/client/assets/d3force3dWorker-BKANL9of.js.map +1 -0
- package/dist/client/assets/index-CP7mSmLx.js +9530 -0
- package/dist/client/assets/index-CP7mSmLx.js.map +1 -0
- package/dist/client/assets/layoutWorker-Lc8iIdmf.js +2 -0
- package/dist/client/assets/layoutWorker-Lc8iIdmf.js.map +1 -0
- package/dist/client/index.html +27 -0
- package/package.json +40 -0
- package/skills/helios-cli/SKILL.md +118 -0
- package/skills/helios-cli/references/behaviors.md +47 -0
- package/skills/helios-cli/references/layouts.md +77 -0
- package/skills/helios-cli/references/mappers.md +119 -0
- package/skills/helios-cli/references/metrics.md +83 -0
- package/skills/helios-cli/references/networks.md +53 -0
- package/skills/helios-cli/references/persistence.md +136 -0
- package/skills/helios-cli/references/positions.md +63 -0
- package/skills/helios-cli/references/rendering-export.md +56 -0
- package/skills/helios-cli/references/rpc-methods.md +83 -0
- package/src/cli.js +488 -0
- package/src/client/index.html +27 -0
- package/src/client/main.js +2210 -0
- package/src/daemon/SessionDaemon.js +1065 -0
- package/src/daemon/entry.js +36 -0
- package/src/protocol/jsonl.js +88 -0
- package/src/shared/cliConfig.js +52 -0
- package/src/shared/fileSessionStore.js +202 -0
- package/src/shared/fs.js +59 -0
- package/src/shared/networkFormats.js +55 -0
- package/src/shared/networkInspect.js +81 -0
- package/src/shared/paths.js +43 -0
- package/src/shared/sessionClient.js +88 -0
- package/src/shared/sessionId.js +5 -0
- package/src/shared/sessionRegistry.js +53 -0
- package/src/shared/sessionSurfaces.js +199 -0
- 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
|
+
```
|