@vibgrate/haile 2026.910.2 → 2026.910.3
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 +1 -6
- package/dist/engine/haile.wasm +0 -0
- package/dist/index.d.ts +18 -102
- package/dist/index.js +11 -404
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,12 +32,7 @@ kernel?.classify({
|
|
|
32
32
|
profile: "balanced",
|
|
33
33
|
});
|
|
34
34
|
// { primary, confidence, band, alternatives, purposes, intent, evidence }
|
|
35
|
-
kernel
|
|
36
|
-
kernel?.projectSlice?.(graph, sidecar, { packageId, view: "job" });
|
|
37
|
-
kernel?.renderArchPage?.({ host: "browser" });
|
|
38
|
-
// Hierarchical map HTML (workspace → column slice). Optional `dist/arch-ui/`
|
|
39
|
-
// is a React Flow pack the host serves at /arch-ui/; the page falls back to
|
|
40
|
-
// the built-in script when that pack is absent.
|
|
35
|
+
// Overview, slice, and the map page are kernel WASM exports (not TypeScript).
|
|
41
36
|
```
|
|
42
37
|
|
|
43
38
|
The host CLI auto-provisions this module (silently, on every run; declinable)
|
package/dist/engine/haile.wasm
CHANGED
|
Binary file
|
package/dist/index.d.ts
CHANGED
|
@@ -109,6 +109,8 @@ interface HaileProvider {
|
|
|
109
109
|
renderArchPage?(opts: {
|
|
110
110
|
host: "browser" | "vscode";
|
|
111
111
|
theme?: "dark" | "light" | "hc";
|
|
112
|
+
nonce?: string;
|
|
113
|
+
assetBase?: string;
|
|
112
114
|
}): string;
|
|
113
115
|
archUiAssets?(): string | null;
|
|
114
116
|
}
|
|
@@ -120,116 +122,30 @@ declare const HAILE_ENGINE_VERSION = "haile-fast/2026.903.5";
|
|
|
120
122
|
declare const DEFAULT_PROFILE: HaileProfile;
|
|
121
123
|
declare const DEFAULT_SYMBOL_CAP = 8000;
|
|
122
124
|
|
|
123
|
-
/** Hierarchical architecture map types. Mirror the public CLI seam. */
|
|
124
|
-
declare const ARCH_OVERVIEW_MAGIC: "vg.arch.overview.v1";
|
|
125
|
-
declare const ARCH_SLICE_MAGIC: "vg.arch.slice.v1";
|
|
126
|
-
type ArchSliceView = "job" | "calls" | "missing" | "problems";
|
|
127
|
-
type ArchPolicyId = "layered-v1" | "hexagonal-v1" | "kind";
|
|
128
|
-
interface ArchPackageNode {
|
|
129
|
-
id: string;
|
|
130
|
-
name: string;
|
|
131
|
-
path: string;
|
|
132
|
-
kind: "package" | "area" | "root";
|
|
133
|
-
symbols: number;
|
|
134
|
-
findings: number;
|
|
135
|
-
missingSteps: number;
|
|
136
|
-
job: string;
|
|
137
|
-
policy: string | null;
|
|
138
|
-
}
|
|
139
|
-
interface ArchPackageEdge {
|
|
140
|
-
id: string;
|
|
141
|
-
src: string;
|
|
142
|
-
dst: string;
|
|
143
|
-
kind: string;
|
|
144
|
-
weight: number;
|
|
145
|
-
}
|
|
146
|
-
interface ArchOverview {
|
|
147
|
-
magic: typeof ARCH_OVERVIEW_MAGIC;
|
|
148
|
-
packages: ArchPackageNode[];
|
|
149
|
-
edges: ArchPackageEdge[];
|
|
150
|
-
meta: {
|
|
151
|
-
architectureLoaded: boolean;
|
|
152
|
-
policy: string | null;
|
|
153
|
-
policyLabel: string | null;
|
|
154
|
-
symbols: number;
|
|
155
|
-
packages: number;
|
|
156
|
-
findings: number;
|
|
157
|
-
missingSteps: number;
|
|
158
|
-
title: string;
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
interface ArchCard {
|
|
162
|
-
id: string;
|
|
163
|
-
title: string;
|
|
164
|
-
subtitle: string;
|
|
165
|
-
lane: string;
|
|
166
|
-
file: string;
|
|
167
|
-
line: number | null;
|
|
168
|
-
symbolId: string;
|
|
169
|
-
count: number;
|
|
170
|
-
job: string;
|
|
171
|
-
color: string;
|
|
172
|
-
classified: boolean;
|
|
173
|
-
pulse: boolean;
|
|
174
|
-
missingStep: boolean;
|
|
175
|
-
ghost?: boolean;
|
|
176
|
-
}
|
|
177
|
-
interface ArchSlice {
|
|
178
|
-
magic: typeof ARCH_SLICE_MAGIC;
|
|
179
|
-
packageId: string;
|
|
180
|
-
packageName: string;
|
|
181
|
-
policy: ArchPolicyId;
|
|
182
|
-
columns: Array<{
|
|
183
|
-
id: string;
|
|
184
|
-
title: string;
|
|
185
|
-
cards: ArchCard[];
|
|
186
|
-
}>;
|
|
187
|
-
guards: ArchCard[];
|
|
188
|
-
edges: Array<{
|
|
189
|
-
id: string;
|
|
190
|
-
src: string;
|
|
191
|
-
dst: string;
|
|
192
|
-
kind: string;
|
|
193
|
-
}>;
|
|
194
|
-
overflow: Record<string, number>;
|
|
195
|
-
focusCardId: string | null;
|
|
196
|
-
}
|
|
197
|
-
interface ArchSliceSpec {
|
|
198
|
-
packageId: string;
|
|
199
|
-
view?: ArchSliceView;
|
|
200
|
-
focus?: string;
|
|
201
|
-
cap?: number;
|
|
202
|
-
architecture?: boolean;
|
|
203
|
-
tests?: boolean;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* L0/L1 aggregation over a vg-graph + classify sidecar.
|
|
208
|
-
* Structural only — no lexicon. Mirrors the public CLI fallback so the
|
|
209
|
-
* module can serve the same payloads without the host painting 29k symbols.
|
|
210
|
-
*/
|
|
211
|
-
|
|
212
|
-
declare function projectOverview(graphRaw: unknown, sidecarRaw: unknown): ArchOverview | null;
|
|
213
|
-
declare function projectSlice(graphRaw: unknown, sidecarRaw: unknown, spec: ArchSliceSpec): ArchSlice | null;
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Architecture map HTML. Served by the public CLI host; no CDN, no public-CLI JS.
|
|
217
|
-
* Tries /arch-ui/arch-ui.js (React Flow pack) and falls back to this page's script.
|
|
218
|
-
*/
|
|
219
|
-
declare function renderArchPage(opts: {
|
|
220
|
-
host: "browser" | "vscode";
|
|
221
|
-
theme?: "dark" | "light" | "hc";
|
|
222
|
-
}): string;
|
|
223
|
-
|
|
224
125
|
interface WasmHaileKernel {
|
|
225
126
|
version(): string;
|
|
226
127
|
classifyJson(input: HaileClassifyInput): string;
|
|
128
|
+
overviewJson?(graph: unknown, sidecar: unknown): string;
|
|
129
|
+
sliceJson?(graph: unknown, sidecar: unknown, spec: unknown): string;
|
|
130
|
+
archPage?(opts: {
|
|
131
|
+
host: "browser" | "vscode";
|
|
132
|
+
theme?: string;
|
|
133
|
+
nonce?: string;
|
|
134
|
+
}): string;
|
|
227
135
|
}
|
|
228
136
|
/** Load the wasm engine if the artifact exists; null otherwise. Memoized. */
|
|
229
137
|
declare function loadWasmHaileKernel(): WasmHaileKernel | null;
|
|
230
138
|
/** Reset the memoized engine (tests only). */
|
|
231
139
|
declare function resetWasmHaileKernelCache(): void;
|
|
232
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Factory consumed by the public CLI seam (loadHaileProvider).
|
|
143
|
+
*
|
|
144
|
+
* Returns null when the wasm engine is missing — never a dummy provider,
|
|
145
|
+
* never a TypeScript lexicon. Overview, slice, and the map page are kernel
|
|
146
|
+
* exports; this file only parses JSON at the trust boundary.
|
|
147
|
+
*/
|
|
148
|
+
|
|
233
149
|
declare function createHaileProvider(kernel?: WasmHaileKernel | null): HaileProvider | null;
|
|
234
150
|
|
|
235
151
|
/**
|
|
@@ -302,4 +218,4 @@ interface SidecarDeps {
|
|
|
302
218
|
}
|
|
303
219
|
declare function runSidecarCli(argv?: string[], deps?: SidecarDeps): Promise<number>;
|
|
304
220
|
|
|
305
|
-
export { DEFAULT_POLICY, DEFAULT_PROFILE, DEFAULT_SYMBOL_CAP, HAILE_ENGINE_VERSION, HAILE_IR, HAILE_MAGIC, HAILE_TAXONOMY, type HaileClassification, type HaileClassifyInput, type HailePolicy, type HaileProfile, type HaileProvider, POLICIES, type SidecarDeps, adaptGraph, createHaileProvider, isCallableKind, loadWasmHaileKernel,
|
|
221
|
+
export { DEFAULT_POLICY, DEFAULT_PROFILE, DEFAULT_SYMBOL_CAP, HAILE_ENGINE_VERSION, HAILE_IR, HAILE_MAGIC, HAILE_TAXONOMY, type HaileClassification, type HaileClassifyInput, type HailePolicy, type HaileProfile, type HaileProvider, POLICIES, type SidecarDeps, adaptGraph, createHaileProvider, isCallableKind, loadWasmHaileKernel, resetWasmHaileKernelCache, runSidecarCli, symbolKindOf };
|
package/dist/index.js
CHANGED
|
@@ -1,404 +1,11 @@
|
|
|
1
|
-
import{pathToFileURL as Ve}from"node:url";import*as P from"node:fs";import*as G from"node:path";var j=["hexagonal-v1","layered-v1"],q="hexagonal-v1",U="vg.arch.v1",D="vg.arch.taxonomy.v1",K="vg.arch.ir.v1",S="haile-fast/2026.903.5",F="balanced",V=8e3,oe=new Set(["function","method","route","test","component","job"]);var xe=240,Ae=400,Ie=16,_e=32,Ee=new Set(["public","private","protected","internal","static","async","override","virtual","abstract","final","def","fn","function","func","sub","pub","export","const","let","var","new","sealed","extern","unsafe","readonly","partial","default","synchronized","native","inline","constexpr","friend","explicit","operator","suspend","open","lateinit","get","set"]);function ce(n){return oe.has(n)}function le(n){switch(n){case"method":return"method";case"route":return"route";case"test":return"test";case"job":return"job";case"component":return"handler";default:return"function"}}function Ce(n,a=""){let r=a?n.indexOf(`${a}(`):-1;if(r<0&&(n.startsWith("@")||n.startsWith("[")))return[];let s=r>=0?r+a.length:n.indexOf("("),u=n.lastIndexOf(")");if(s<0||u<=s)return[];let e=n.slice(s+1,u).trim();return!e||e==="void"?[]:e.split(",").map(t=>t.trim()).filter(Boolean).slice(0,16).map(t=>{let o=t.replace(/\b(const|mut|ref|public|private|protected|readonly|final)\b/g,"").trim();if(o.includes(":")){let[d,h]=o.split(":").map(m=>m.trim());return{name:d||"arg",type_name:h||void 0}}let l=o.split(/\s+/);return l.length>=2?{name:l[l.length-1],type_name:l[0]}:{name:o}})}function Le(n,a){let r=n.lastIndexOf("->");if(r>=0)return n.slice(r+2).replace(/[{;].*$/,"").trim()||void 0;let s=n.lastIndexOf(":"),u=n.lastIndexOf(")");if(s>u&&u>=0)return n.slice(s+1).replace(/[{;].*$/,"").replace(/\s*=>.*$/,"").trim()||void 0;let e=a?n.indexOf(`${a}(`):-1;if(e>0){let t=n.slice(0,e).trim(),o=0,l=0;for(let h=t.length-1;h>=0;h--){let m=t[h];if(m===">"||m==="]"||m===")")o++;else if(m==="<"||m==="["||m==="(")o--;else if(/\s/.test(m)&&o===0){l=h+1;break}}let d=t.slice(l).trim();if(d&&!d.startsWith("@")&&!d.startsWith("[")&&!Ee.has(d)&&d!=="void"&&!d.endsWith(")")&&!d.endsWith("]"))return d}}function Se(n,a,r,s){let u=[],e=[],t=new Set,o=new Set;for(let l of a){if(l.src!==n||l.kind!=="call"&&l.kind!=="references")continue;let d=r.get(l.dst);if(!d)continue;let h=d.qualifiedName||d.name;if(!(!h||t.has(h))&&(t.add(h),u.push(h),d.file&&d.file!==s&&!o.has(d.file)&&e.length<Ie&&(o.add(d.file),e.push(d.file)),u.length>=24))break}return{calls:u,calleePaths:e}}function He(n,a,r){let s=new Map;for(let e of n)(e.kind==="file"||e.kind==="module")&&s.set(e.id,e.file);let u=new Map;for(let e of a){if(e.kind!=="import")continue;let t=s.get(e.src);if(!t)continue;let o=r.get(e.dst),l=o?.qualifiedName||o?.name;if(!l)continue;let d=u.get(t);d||(d=[],u.set(t,d)),d.length<_e&&!d.includes(l)&&d.push(l)}return u}function Y(n){let a=n.nodes??[],r=n.edges??[],s=new Map;for(let t of a)s.set(t.id,t);let u=He(a,r,s),e=[];for(let t of a){if(!ce(t.kind))continue;let o=typeof t.decorators=="string"?t.decorators.trim():"",l=`${o?`${o} `:""}${t.signature??""}`.slice(0,Ae),{calls:d,calleePaths:h}=Se(t.id,r,s,t.file),m=typeof t.doc=="string"?t.doc.trim().slice(0,xe):"";e.push({node_id:t.id,file_path:t.file,name:t.name,qualified_name:t.qualifiedName||t.name,symbol_kind:le(t.kind),language:t.lang??"",signature:l,calls:d,parameters:Ce(l,t.name),return_type:Le(l,t.name),...m?{doc:m}:{},callee_paths:h,imports:u.get(t.file)??[],...t.effects&&typeof t.effects=="object"?{effects:t.effects}:{},...Array.isArray(t.duties)?{duties:t.duties.slice(0,48)}:{}})}return e.sort((t,o)=>t.node_id<o.node_id?-1:t.node_id>o.node_id?1:0),e}import{fileURLToPath as ze}from"node:url";import{dirname as Ge,join as $e}from"node:path";import{existsSync as qe}from"node:fs";import*as T from"node:fs";import{fileURLToPath as Pe}from"node:url";var I;function Oe(){return[new URL("./engine/haile.wasm",import.meta.url),new URL("../engine/haile.wasm",import.meta.url),new URL("../crate/target/wasm32-unknown-unknown/release/vibgrate_haile_kernel.wasm",import.meta.url)].map(n=>Pe(n))}function Ne(n){try{let a=new WebAssembly.Module(n),s=new WebAssembly.Instance(a,{}).exports;if(typeof s.vg_alloc!="function"||typeof s.vg_free!="function"||typeof s.vg_version!="function"||typeof s.vg_classify!="function"||!s.memory)return null;let u=t=>{let o=new TextEncoder().encode(t),l=s.vg_alloc(o.length);return new Uint8Array(s.memory.buffer,l,o.length).set(o),{ptr:l,len:o.length}},e=t=>{if(!t)return"";let o=new DataView(s.memory.buffer,t,4).getUint32(0,!0),l=new TextDecoder().decode(new Uint8Array(s.memory.buffer,t+4,o));return s.vg_free(t,4+o),l};return{version:()=>{try{return e(s.vg_version())||S}catch{return S}},classifyJson:t=>{let o=JSON.stringify({name:t.name??"",path:t.path??"",symbolKind:t.symbolKind??"function",fileKind:t.fileKind??"source",calls:t.calls??[],types:t.types??[],idents:t.idents??[],profile:t.profile??"balanced",policy:t.policy??"hexagonal-v1",qualifiedName:t.qualifiedName??"",doc:t.doc??"",signature:t.signature??"",params:t.params??[],returnType:t.returnType??"",calleePaths:t.calleePaths??[],imports:t.imports??[],astRole:t.astRole??"",effects:t.effects??{},duties:t.duties??[]}),{ptr:l,len:d}=u(o);try{return e(s.vg_classify(l,d))}finally{s.vg_free(l,d)}}}}catch{return null}}function J(){if(I!==void 0)return I;I=null;try{let n=Oe().find(a=>T.existsSync(a));return n&&(I=Ne(T.readFileSync(n))),I}catch{return I=null,I}}function Re(){I=void 0}var de="vg.arch.overview.v1",pe="vg.arch.slice.v1";var Me=new Set(["file","document","package","external"]),Be=/(?:^|\/)(?:__tests__|tests|test|spec)(?:\/|$)/i,je=/\.(?:test|spec|tests)\.[^.]+$/i,ge={controller:"ui",transport:"ui",user_interface:"ui",entry_point:"ui",application_service:"app",use_case:"app",port:"app",repository:"io",persistence:"io",infrastructure:"io",adapter:"io",integration:"io",messaging:"io",worker:"io",cross_cutting:"guards",test_support:"guards"},Te={...ge,domain_model:"domain",domain_service:"domain",repository:"infra",persistence:"infra",infrastructure:"infra",adapter:"infra",integration:"infra",messaging:"infra",worker:"infra"},We={controller:"#38bdf8",transport:"#38bdf8",user_interface:"#38bdf8",application_service:"#22c55e",use_case:"#22c55e",domain_model:"#94a3b8",repository:"#a78bfa",persistence:"#a78bfa"},fe={controller:"HTTP handler",transport:"HTTP handler",user_interface:"Interface",application_service:"Service",use_case:"Service",repository:"Data access",persistence:"Data access",domain_model:"Data model",cross_cutting:"Login check"};function me(n){if(!n||typeof n!="object")return null;let a=n;return!Array.isArray(a.nodes)||!Array.isArray(a.edges)?null:a}function he(n){return!n||typeof n!="object"?null:n}function z(n){return String(n||"").replace(/\\/g,"/")}function W(n){let a=z(n),r=a.lastIndexOf("/");return r<=0?".":a.slice(0,r)}function H(n){return!Me.has(n.kind)}function be(n){let a=n.nodes.filter(e=>e.kind==="package"&&!z(e.file).includes("node_modules/")).map(e=>({id:e.id,name:e.name||e.qualifiedName||W(e.file),path:W(e.file),kind:"package",rank:W(e.file)==="."?0:W(e.file).split("/").filter(Boolean).length})).sort((e,t)=>t.rank-e.rank||e.path.localeCompare(t.path)||e.id.localeCompare(t.id)),r=new Map;for(let e of n.nodes){if(!H(e))continue;let t=z(e.file);for(let o of a)if(o.path==="."||t===o.path||t.startsWith(`${o.path}/`)){r.set(e.id,o.id);break}}let s=a.map(({rank:e,...t})=>t),u=n.nodes.filter(e=>H(e)&&!r.has(e.id));if(u.length&&s.length===0&&(n.areas?.length??0)>0){let e=new Map;for(let t of u){let o=t.area??0,l=e.get(o)??[];l.push(t),e.set(o,l)}for(let t of[...e.keys()].sort((o,l)=>o-l)){let o=n.areas?.find(d=>d.id===t),l={id:`area:${t}`,name:o?.label||`Area ${t}`,path:o?.label||".",kind:"area"};s.push(l);for(let d of e.get(t)??[])r.set(d.id,l.id)}}else if(u.length){let e=s.find(t=>t.path===".")??{id:"root",name:n.meta?.root&&n.meta.root!=="."?n.meta.root:"repository",path:".",kind:"root"};s.some(t=>t.id===e.id)||s.push(e);for(let t of u)r.set(t.id,e.id)}if(s.length===0){let e={id:"root",name:n.meta?.root&&n.meta.root!=="."?n.meta.root:"repository",path:".",kind:"root"};s.push(e);for(let t of n.nodes)H(t)&&r.set(t.id,e.id)}return s.sort((e,t)=>e.path.localeCompare(t.path)||e.id.localeCompare(t.id)),{packages:s,packageOf:r}}function ye(n){let a=new Map;for(let r of n?.symbols??[])r&&typeof r.node_id=="string"&&a.set(r.node_id,r);return a}function X(n,a){let r=me(n);if(!r)return null;let s=he(a),{packages:u,packageOf:e}=be(r),t=ye(s),o=[];for(let f of u){let c=0,g=0,y=0;for(let A of r.nodes){if(e.get(A.id)!==f.id||!H(A))continue;c+=1;let _=t.get(A.id);_?.findings?.some(R=>R&&typeof R.message=="string")&&(g+=1),Array.isArray(_?.extract_gaps)&&_.extract_gaps.length>0&&(y+=1)}o.push({id:f.id,name:f.path&&f.path!=="."?f.path:f.name,path:f.path,kind:f.kind,symbols:c,findings:g,missingSteps:y,job:f.kind==="area"?"cluster":f.kind==="root"?"workspace":"package",policy:s?.policy??null})}let l=o.slice(0,200),d=new Set(l.map(f=>f.id)),h=new Map;for(let f of r.edges){let c=e.get(f.src),g=e.get(f.dst);if(!c||!g||c===g||!d.has(c)||!d.has(g)||!["import","depends_on","call","implements","extends","provisions","deploys"].includes(f.kind))continue;let y=f.kind==="call"?"calls":f.kind,A=`${c}|${y}|${g}`,_=h.get(A);_?_.weight+=1:h.set(A,{id:A,src:c,dst:g,kind:y,weight:1})}let m=[...h.values()].sort((f,c)=>f.src.localeCompare(c.src)||f.dst.localeCompare(c.dst)||f.kind.localeCompare(c.kind)),v=r.meta?.root||"repository";return{magic:de,packages:l,edges:m,meta:{architectureLoaded:!!s,policy:s?.policy??null,policyLabel:s?.policy?.startsWith("layered")?"Layered \u2014 handlers talk to services":s?.policy?.startsWith("hexagonal")?"Hexagonal \u2014 handlers only delegate":s?"Architecture rules":null,symbols:r.nodes.filter(H).length,packages:l.length,findings:l.reduce((f,c)=>f+c.findings,0),missingSteps:l.reduce((f,c)=>f+c.missingSteps,0),title:v==="."?"Code map":`Code map \xB7 ${v}`}}}function Z(n,a,r){let s=me(n);if(!s)return null;let u=he(a),{packages:e,packageOf:t}=be(s),o=e.find(i=>i.id===r.packageId)??e[0],l=o?.id??r.packageId,d=o?.path&&o.path!=="."?o.path:o?.name??l,h=r.architecture!==!1,m=h&&u?.policy?.startsWith("layered")?"layered-v1":h&&u?"hexagonal-v1":"kind",v=m==="layered-v1"?[{id:"ui",title:"UI / Endpoint"},{id:"app",title:"Application"},{id:"io",title:"Persistence / IO"}]:m==="kind"?[{id:"ui",title:"UI / Endpoint"},{id:"app",title:"Application"},{id:"io",title:"Types / IO"}]:[{id:"adapters",title:"Adapters / UI"},{id:"app",title:"Application"},{id:"domain",title:"Domain"},{id:"infra",title:"Ports / Infra"}],f=m==="layered-v1"?ge:m==="hexagonal-v1"?Te:null,c=ye(u),g=new Map,y=new Map,A=r.tests===!0;function _(i,p){return p==="cross_cutting"||p==="test_support"?"guards":f&&p&&f[p]?f[p]:i.kind==="route"||i.kind==="component"?v[0].id:i.kind==="function"||i.kind==="method"?v[1]?.id??"app":v[v.length-1].id}for(let i of s.nodes){if(!H(i)||t.get(i.id)!==l)continue;let p=z(i.file);if(!A&&(i.kind==="test"||Be.test(p)||je.test(p)))continue;let b=c.get(i.id),w=h&&b?.role?.primary?b.role.primary:"",k=_(i,w),x=`card:${p}:${k}:${w||i.kind}`,L=g.get(x);L||(L={id:x,lane:k,file:p,role:w||i.kind,members:[],ghost:!1},g.set(x,L)),L.members.push(i),y.set(i.id,x)}let R=v[v.length-1].id;for(let i of s.edges){if(i.kind!=="call"&&i.kind!=="import"||!y.has(i.src))continue;let p=t.get(i.dst);if(!p||p===l)continue;let b=`ghost:${p}`;if(!g.has(b)){let w=e.find(x=>x.id===p),k=s.nodes.find(x=>x.id===i.dst);if(!k)continue;g.set(b,{id:b,lane:R,file:w?.path??k.file,role:"external",members:[k],ghost:!0})}y.set(i.dst,b)}function ke(i){let p=[...i.members].sort((E,N)=>(N.importance??0)-(E.importance??0)||E.name.localeCompare(N.name)),b=p[0],w=c.get(b.id),k=i.ghost?i.file&&i.file!=="."?i.file:b.name:p.length===1?b.name:(i.file.split("/").pop()||b.name).replace(/\.[^.]+$/,""),x=p.some(E=>(c.get(E.id)?.findings??[]).some(N=>typeof N.line=="number"&&N.line>0)),L=p.some(E=>Array.isArray(c.get(E.id)?.extract_gaps)&&(c.get(E.id)?.extract_gaps?.length??0)>0);return{id:i.id,title:k,subtitle:p.length===1?fe[i.role]||i.role:`${p.length} functions`,lane:i.lane,file:i.file,line:b.span?.start??null,symbolId:b.id,count:p.length,job:fe[i.role]||i.role,color:i.ghost?"#64748b":We[i.role]||"#94a3b8",classified:!!w,pulse:x,missingStep:L,...i.ghost?{ghost:!0}:{}}}let C=[...g.values()].map(ke);r.view==="missing"&&(C=C.filter(i=>i.missingStep)),r.view==="problems"&&(C=C.filter(i=>i.pulse));let re=r.focus?s.nodes.find(i=>i.id===r.focus||i.qualifiedName===r.focus||i.name===r.focus):void 0,ie=re?y.get(re.id)??null:null;C.sort((i,p)=>i.title.localeCompare(p.title));let we=Math.max(1,Math.min(r.cap??120,120)),M={};for(let i of v)M[i.id]=0;let B=[];for(let i of C)i.id===ie||B.length<we?B.push(i):M[i.lane]=(M[i.lane]??0)+1;let se=new Set(B.map(i=>i.id)),$=[],ae=new Set;for(let i of s.edges){if(r.view==="calls"&&i.kind!=="call"||i.kind!=="call"&&i.kind!=="import")continue;let p=y.get(i.src),b=y.get(i.dst);if(!p||!b||p===b||!se.has(p)||!se.has(b))continue;let w=i.kind==="call"?"calls":i.kind,k=`${p}|${w}|${b}`;ae.has(k)||(ae.add(k),$.push({id:k,src:p,dst:b,kind:w}))}$.sort((i,p)=>i.src.localeCompare(p.src)||i.dst.localeCompare(p.dst));let O=new Map;for(let i of B){let p=O.get(i.lane)??[];p.push(i),O.set(i.lane,p)}for(let i of O.values())i.sort((p,b)=>p.title.localeCompare(b.title));return{magic:pe,packageId:l,packageName:d,policy:m,columns:v.map(i=>({id:i.id,title:i.title,cards:O.get(i.id)??[]})),guards:(O.get("guards")??[]).sort((i,p)=>i.title.localeCompare(p.title)),edges:$,overflow:M,focusCardId:ie}}function Q(n){let a=n.host==="vscode"?"vscode":"browser",r=n.theme==="light"?"light":n.theme==="hc"?"hc":"dark";return`<!DOCTYPE html>
|
|
2
|
-
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
--panel:280px; --sans:"IBM Plex Sans","Segoe UI",system-ui,sans-serif;
|
|
13
|
-
}
|
|
14
|
-
[data-theme="light"] {
|
|
15
|
-
--bg:#f4f1ea; --s0:#efece4; --s1:#fffdf8; --s2:#fff;
|
|
16
|
-
--line:#d9d3c6; --t:#1c241d; --tm:#5d675f; --tl:#7e877f;
|
|
17
|
-
}
|
|
18
|
-
[data-host="vscode"] {
|
|
19
|
-
--bg:var(--vscode-editor-background, #0b0f0c);
|
|
20
|
-
--s0:var(--vscode-sideBar-background, #0e1510);
|
|
21
|
-
--s1:var(--vscode-editorWidget-background, #141c16);
|
|
22
|
-
--s2:var(--vscode-input-background, #1b241d);
|
|
23
|
-
--line:var(--vscode-widget-border, #2a362c);
|
|
24
|
-
--t:var(--vscode-foreground, #e8f0e9);
|
|
25
|
-
--tm:var(--vscode-descriptionForeground, #9aab9e);
|
|
26
|
-
--sans:var(--vscode-font-family, system-ui);
|
|
27
|
-
}
|
|
28
|
-
* { box-sizing:border-box; }
|
|
29
|
-
html,body { margin:0; height:100%; background:var(--bg); color:var(--t); font-family:var(--sans); }
|
|
30
|
-
body { display:flex; flex-direction:column; overflow:hidden; }
|
|
31
|
-
button,input { font:inherit; color:inherit; }
|
|
32
|
-
button { cursor:pointer; }
|
|
33
|
-
header {
|
|
34
|
-
display:flex; flex-wrap:wrap; gap:8px; align-items:center;
|
|
35
|
-
padding:8px 12px; border-bottom:1px solid var(--line); background:var(--s1);
|
|
36
|
-
}
|
|
37
|
-
.mark { width:10px; height:10px; border-radius:3px; background:var(--green); }
|
|
38
|
-
.brand { font-weight:650; font-size:14px; }
|
|
39
|
-
.brand small { color:var(--tm); font-weight:500; margin-left:6px; }
|
|
40
|
-
.search {
|
|
41
|
-
flex:1 1 160px; min-width:140px; max-width:280px; height:36px;
|
|
42
|
-
border:1px solid var(--line); background:var(--bg); border-radius:8px; padding:0 10px;
|
|
43
|
-
}
|
|
44
|
-
.tools { display:flex; flex-wrap:wrap; gap:6px; }
|
|
45
|
-
.tools button, .seg button {
|
|
46
|
-
height:34px; padding:0 10px; border-radius:8px; border:1px solid var(--line);
|
|
47
|
-
background:var(--s2); color:var(--tm); font-size:13px;
|
|
48
|
-
}
|
|
49
|
-
.tools button[aria-pressed="true"], .seg button[aria-pressed="true"] {
|
|
50
|
-
color:var(--t); border-color:color-mix(in srgb,var(--green) 50%, var(--line));
|
|
51
|
-
background:color-mix(in srgb,var(--green) 12%, var(--s2));
|
|
52
|
-
}
|
|
53
|
-
.seg { display:flex; border:1px solid var(--line); border-radius:8px; overflow:hidden; }
|
|
54
|
-
.seg button { border:0; border-radius:0; background:transparent; }
|
|
55
|
-
.seg button + button { border-left:1px solid var(--line); }
|
|
56
|
-
.note { padding:8px 12px; font-size:13px; color:var(--tm); border-bottom:1px solid var(--line); background:var(--s0); }
|
|
57
|
-
.note b { color:var(--t); }
|
|
58
|
-
.work { flex:1; display:grid; grid-template-columns:1fr var(--panel); min-height:0; }
|
|
59
|
-
.work.closed { grid-template-columns:1fr 0; }
|
|
60
|
-
.stage { position:relative; min-height:0; overflow:hidden; }
|
|
61
|
-
.canvas { height:100%; overflow:auto; background:
|
|
62
|
-
linear-gradient(var(--line) 1px,transparent 1px),
|
|
63
|
-
linear-gradient(90deg,var(--line) 1px,transparent 1px);
|
|
64
|
-
background-size:32px 32px; }
|
|
65
|
-
svg.edges { position:absolute; inset:0; pointer-events:none; overflow:visible; }
|
|
66
|
-
.pkg, .card {
|
|
67
|
-
position:absolute; width:240px; text-align:left; height:auto; padding:10px 12px;
|
|
68
|
-
border-radius:4px; border:1px solid var(--line); background:var(--s1);
|
|
69
|
-
border-left-width:3px; color:var(--t);
|
|
70
|
-
}
|
|
71
|
-
.pkg small, .card small { display:block; color:var(--tm); font-size:12px; margin-top:4px; }
|
|
72
|
-
.pkg:focus, .card:focus { outline:1px solid var(--cyan); }
|
|
73
|
-
.cols { display:flex; gap:20px; align-items:flex-start; padding:20px; min-height:100%; }
|
|
74
|
-
.col { flex:0 0 250px; }
|
|
75
|
-
.col h2 { margin:0 0 10px; font-size:10px; letter-spacing:.12em; text-transform:uppercase; color:var(--tl); }
|
|
76
|
-
.col .stack { display:flex; flex-direction:column; gap:8px; }
|
|
77
|
-
.col .card { position:relative; width:100%; }
|
|
78
|
-
.guards { display:flex; gap:8px; flex-wrap:wrap; padding:8px 20px 0; }
|
|
79
|
-
.more { font-size:12px; color:var(--tl); padding:6px; }
|
|
80
|
-
.zoom {
|
|
81
|
-
position:absolute; right:12px; top:12px; display:flex; z-index:2;
|
|
82
|
-
border:1px solid var(--line); border-radius:8px; overflow:hidden; background:var(--s1);
|
|
83
|
-
}
|
|
84
|
-
.zoom button { height:32px; min-width:36px; border:0; background:transparent; }
|
|
85
|
-
.zoom button + button { border-left:1px solid var(--line); }
|
|
86
|
-
.drawer { background:var(--s1); border-left:1px solid var(--line); overflow:auto; min-height:0; }
|
|
87
|
-
.dh { display:flex; align-items:center; gap:8px; padding:12px 14px; border-bottom:1px solid var(--line); }
|
|
88
|
-
.dh h2 { margin:0; font-size:16px; flex:1; }
|
|
89
|
-
.icon { width:34px; height:34px; border-radius:8px; border:1px solid var(--line); background:transparent; color:var(--tm); }
|
|
90
|
-
.db { padding:12px 14px 28px; }
|
|
91
|
-
.lbl { font-size:11px; letter-spacing:.08em; text-transform:uppercase; color:var(--tl); margin:14px 0 6px; }
|
|
92
|
-
.list { list-style:none; margin:0; padding:0; }
|
|
93
|
-
.list li { padding:6px 0; border-bottom:1px solid var(--line); font-size:14px; }
|
|
94
|
-
.warn,.break { margin-top:14px; padding:12px; border-radius:10px; }
|
|
95
|
-
.warn { border:1px solid color-mix(in srgb,var(--amber) 45%,var(--line)); }
|
|
96
|
-
.break { border:1px solid color-mix(in srgb,var(--rose) 45%,var(--line)); }
|
|
97
|
-
footer { padding:6px 12px; border-top:1px solid var(--line); color:var(--tl); font-size:12px; }
|
|
98
|
-
@media (max-width:860px) {
|
|
99
|
-
.work { grid-template-columns:1fr; }
|
|
100
|
-
.drawer { border-left:0; border-top:1px solid var(--line); max-height:40dvh; }
|
|
101
|
-
}
|
|
102
|
-
</style>
|
|
103
|
-
</head>
|
|
104
|
-
<body>
|
|
105
|
-
<header>
|
|
106
|
-
<div class="mark"></div>
|
|
107
|
-
<div class="brand">Code map<small id="subtitle"></small></div>
|
|
108
|
-
<input id="q" class="search" placeholder="Find a handler or service" autocomplete="off" aria-label="Find a handler or service">
|
|
109
|
-
<div class="tools">
|
|
110
|
-
<button type="button" id="back" hidden>Workspace</button>
|
|
111
|
-
<button type="button" id="arch" aria-pressed="true">Architecture on</button>
|
|
112
|
-
<div class="seg" role="tablist">
|
|
113
|
-
<button type="button" data-view="job" aria-pressed="true">By job</button>
|
|
114
|
-
<button type="button" data-view="cluster">By cluster</button>
|
|
115
|
-
<button type="button" data-view="calls">Who calls whom</button>
|
|
116
|
-
<button type="button" data-view="missing">Missing steps</button>
|
|
117
|
-
<button type="button" data-view="problems">Problems</button>
|
|
118
|
-
</div>
|
|
119
|
-
<button type="button" id="callers">Who calls this</button>
|
|
120
|
-
<button type="button" id="callees">What this calls</button>
|
|
121
|
-
<button type="button" id="theme">Theme</button>
|
|
122
|
-
<button type="button" id="save">Save map</button>
|
|
123
|
-
</div>
|
|
124
|
-
</header>
|
|
125
|
-
<div class="note" id="note">Loading the map\u2026</div>
|
|
126
|
-
<div class="work" id="work">
|
|
127
|
-
<div class="stage">
|
|
128
|
-
<div class="canvas" id="canvas" tabindex="0" aria-label="Architecture map"></div>
|
|
129
|
-
<div class="zoom" role="group" aria-label="Map zoom">
|
|
130
|
-
<button type="button" id="zoom-out" aria-label="Zoom out">\u2212</button>
|
|
131
|
-
<button type="button" id="zoom-fit" aria-label="Reset zoom">100%</button>
|
|
132
|
-
<button type="button" id="zoom-in" aria-label="Zoom in">+</button>
|
|
133
|
-
</div>
|
|
134
|
-
</div>
|
|
135
|
-
<aside class="drawer" id="drawer" aria-label="Details"></aside>
|
|
136
|
-
</div>
|
|
137
|
-
<footer id="foot"></footer>
|
|
138
|
-
<script>
|
|
139
|
-
const HOST = document.documentElement.getAttribute("data-host") || "browser";
|
|
140
|
-
const state = {
|
|
141
|
-
zoom:"workspace", packageId:null, focus:null, view:"job", arch:true,
|
|
142
|
-
overview:null, slice:null, q:"", selected:null, k:1
|
|
143
|
-
};
|
|
144
|
-
function esc(s){
|
|
145
|
-
return String(s==null?"":s).replace(/[&<>"']/g, function(c){
|
|
146
|
-
if (c==="&") return "&";
|
|
147
|
-
if (c==="<") return "<";
|
|
148
|
-
if (c===">") return ">";
|
|
149
|
-
if (c==='"') return """;
|
|
150
|
-
return "'";
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
function readHash(){
|
|
154
|
-
const p = new URLSearchParams((location.hash||"").replace(/^#/,""));
|
|
155
|
-
return { zoom:p.get("zoom")||"workspace", package:p.get("package"), n:p.get("n"), view:p.get("view"), arch:p.get("arch") };
|
|
156
|
-
}
|
|
157
|
-
function writeHash(){
|
|
158
|
-
const p = new URLSearchParams();
|
|
159
|
-
p.set("zoom", state.zoom);
|
|
160
|
-
if (state.packageId) p.set("package", state.packageId);
|
|
161
|
-
if (state.focus) p.set("n", state.focus);
|
|
162
|
-
if (state.view && state.view!=="job") p.set("view", state.view);
|
|
163
|
-
if (!state.arch) p.set("arch","0");
|
|
164
|
-
const next = p.toString();
|
|
165
|
-
if (location.hash.replace(/^#/,"") !== next) history.replaceState(null,"","#"+next);
|
|
166
|
-
}
|
|
167
|
-
async function bootVanilla(){
|
|
168
|
-
const ov = await fetch("/api/overview");
|
|
169
|
-
if (!ov.ok) { document.getElementById("note").textContent = "Could not load the map. Run vg first."; return; }
|
|
170
|
-
state.overview = await ov.json();
|
|
171
|
-
const m = state.overview.meta;
|
|
172
|
-
document.title = m.title || "Code map";
|
|
173
|
-
document.getElementById("subtitle").textContent = " \xB7 " + m.symbols + " symbols \xB7 " + m.packages + " packages";
|
|
174
|
-
document.getElementById("foot").textContent = m.symbols + " symbols in " + m.packages + " packages";
|
|
175
|
-
const h = readHash();
|
|
176
|
-
if (h.view && ["job","calls","missing","problems","cluster"].indexOf(h.view)>=0) {
|
|
177
|
-
state.view = h.view;
|
|
178
|
-
document.querySelectorAll("[data-view]").forEach(b => b.setAttribute("aria-pressed", b.getAttribute("data-view")===h.view ? "true":"false"));
|
|
179
|
-
}
|
|
180
|
-
if (h.arch==="0") { state.arch=false; document.getElementById("arch").setAttribute("aria-pressed","false"); document.getElementById("arch").textContent="Architecture off"; }
|
|
181
|
-
if (h.n) state.focus = h.n;
|
|
182
|
-
if (h.zoom==="slice" && h.package) await openSlice(h.package);
|
|
183
|
-
else drawWorkspace();
|
|
184
|
-
}
|
|
185
|
-
function filteredPackages(){
|
|
186
|
-
const q = state.q.toLowerCase();
|
|
187
|
-
let list = state.overview.packages.slice();
|
|
188
|
-
if (state.view==="problems") list = list.filter(p => p.findings>0);
|
|
189
|
-
if (state.view==="missing") list = list.filter(p => p.missingSteps>0);
|
|
190
|
-
if (q) list = list.filter(p => (p.name+" "+p.path+" "+p.job).toLowerCase().indexOf(q)>=0);
|
|
191
|
-
return list;
|
|
192
|
-
}
|
|
193
|
-
function drawWorkspace(){
|
|
194
|
-
state.zoom="workspace"; state.slice=null; state.packageId=null;
|
|
195
|
-
document.getElementById("back").hidden = true;
|
|
196
|
-
const m = state.overview.meta;
|
|
197
|
-
document.getElementById("note").innerHTML = m.architectureLoaded
|
|
198
|
-
? "<b>How the projects fit together.</b> Double-click a package for UI \u2192 service \u2192 store. "+esc(m.policyLabel||"")
|
|
199
|
-
: "<b>How the projects fit together.</b> Architecture labels appear after the architecture module classifies this project.";
|
|
200
|
-
const pkgs = filteredPackages();
|
|
201
|
-
const COLS = Math.min(4, Math.max(1, pkgs.length));
|
|
202
|
-
const W=240, H=78, GAP=28, OX=32, OY=32;
|
|
203
|
-
const canvas = document.getElementById("canvas");
|
|
204
|
-
canvas.innerHTML = "";
|
|
205
|
-
const world = document.createElement("div");
|
|
206
|
-
world.style.position="relative";
|
|
207
|
-
world.style.transformOrigin="0 0";
|
|
208
|
-
world.style.transform="scale("+state.k+")";
|
|
209
|
-
const pos = {};
|
|
210
|
-
pkgs.forEach((p,i) => {
|
|
211
|
-
const x = OX + (i%COLS)*(W+GAP);
|
|
212
|
-
const y = OY + Math.floor(i/COLS)*(H+GAP);
|
|
213
|
-
pos[p.id] = {x,y,w:W,h:H};
|
|
214
|
-
const b = document.createElement("button");
|
|
215
|
-
b.className="pkg";
|
|
216
|
-
b.type="button";
|
|
217
|
-
b.style.left=x+"px"; b.style.top=y+"px";
|
|
218
|
-
b.style.borderLeftColor = p.findings ? "var(--rose)" : "var(--cyan)";
|
|
219
|
-
b.innerHTML = "<strong>"+esc(p.name)+"</strong><small>"+esc(p.job)+" \xB7 "+p.symbols+" symbols"
|
|
220
|
-
+(p.findings? " \xB7 "+p.findings+" rule break"+(p.findings===1?"":"s"):"")+"</small>";
|
|
221
|
-
b.onclick = () => inspectPackage(p);
|
|
222
|
-
b.ondblclick = () => openSlice(p.id);
|
|
223
|
-
b.onkeydown = ev => { if (ev.key==="Enter") openSlice(p.id); };
|
|
224
|
-
world.appendChild(b);
|
|
225
|
-
});
|
|
226
|
-
const svg = document.createElementNS("http://www.w3.org/2000/svg","svg");
|
|
227
|
-
svg.setAttribute("class","edges");
|
|
228
|
-
const rows = Math.ceil(pkgs.length/COLS)||1;
|
|
229
|
-
svg.setAttribute("width", String(OX+COLS*(W+GAP)));
|
|
230
|
-
svg.setAttribute("height", String(OY+rows*(H+GAP)));
|
|
231
|
-
(state.overview.edges||[]).forEach(e => {
|
|
232
|
-
const a = pos[e.src], b = pos[e.dst];
|
|
233
|
-
if (!a || !b) return;
|
|
234
|
-
const path = document.createElementNS("http://www.w3.org/2000/svg","path");
|
|
235
|
-
const x1=a.x+a.w, y1=a.y+a.h/2, x2=b.x, y2=b.y+b.h/2;
|
|
236
|
-
const mx=(x1+x2)/2;
|
|
237
|
-
path.setAttribute("d","M"+x1+" "+y1+" C "+mx+" "+y1+", "+mx+" "+y2+", "+x2+" "+y2);
|
|
238
|
-
path.setAttribute("fill","none");
|
|
239
|
-
path.setAttribute("stroke","var(--orange)");
|
|
240
|
-
path.setAttribute("stroke-width", e.kind==="calls" ? "1.6" : "1.2");
|
|
241
|
-
path.setAttribute("opacity","0.7");
|
|
242
|
-
if (e.kind!=="calls" && e.kind!=="import") path.setAttribute("stroke-dasharray","5 4");
|
|
243
|
-
svg.appendChild(path);
|
|
244
|
-
});
|
|
245
|
-
world.appendChild(svg);
|
|
246
|
-
world.style.width = (OX+COLS*(W+GAP))+"px";
|
|
247
|
-
world.style.height = (OY+rows*(H+GAP)+40)+"px";
|
|
248
|
-
canvas.appendChild(world);
|
|
249
|
-
writeHash();
|
|
250
|
-
}
|
|
251
|
-
async function openSlice(packageId){
|
|
252
|
-
const params = new URLSearchParams();
|
|
253
|
-
params.set("package", packageId);
|
|
254
|
-
params.set("view", state.view==="cluster" ? "job" : state.view);
|
|
255
|
-
if (state.focus) params.set("focus", state.focus);
|
|
256
|
-
if (!state.arch) params.set("arch","0");
|
|
257
|
-
const res = await fetch("/api/slice?"+params.toString());
|
|
258
|
-
if (!res.ok) { document.getElementById("note").textContent = "Could not open that package."; return; }
|
|
259
|
-
state.slice = await res.json();
|
|
260
|
-
state.zoom="slice";
|
|
261
|
-
state.packageId = state.slice.packageId;
|
|
262
|
-
document.getElementById("back").hidden = false;
|
|
263
|
-
const extra = Object.values(state.slice.overflow||{}).reduce((n,v)=>n+(v||0),0);
|
|
264
|
-
document.getElementById("note").innerHTML = "<b>"+esc(state.slice.packageName)+"</b> \xB7 column slice. Tests hidden."
|
|
265
|
-
+(extra? " \xB7 "+extra+" more folded into lane footers.":"");
|
|
266
|
-
const canvas = document.getElementById("canvas");
|
|
267
|
-
canvas.innerHTML = "";
|
|
268
|
-
if (state.slice.guards && state.slice.guards.length) {
|
|
269
|
-
const band = document.createElement("div");
|
|
270
|
-
band.className="guards";
|
|
271
|
-
state.slice.guards.forEach(card => band.appendChild(cardEl(card)));
|
|
272
|
-
canvas.appendChild(band);
|
|
273
|
-
}
|
|
274
|
-
const cols = document.createElement("div");
|
|
275
|
-
cols.className="cols";
|
|
276
|
-
const q = state.q.toLowerCase();
|
|
277
|
-
state.slice.columns.forEach(col => {
|
|
278
|
-
const wrap = document.createElement("div");
|
|
279
|
-
wrap.className="col";
|
|
280
|
-
wrap.innerHTML = "<h2>"+esc(col.title)+"</h2>";
|
|
281
|
-
const stack = document.createElement("div");
|
|
282
|
-
stack.className="stack";
|
|
283
|
-
col.cards.filter(c => !q || (c.title+" "+c.subtitle+" "+c.file).toLowerCase().indexOf(q)>=0).forEach(card => {
|
|
284
|
-
stack.appendChild(cardEl(card));
|
|
285
|
-
});
|
|
286
|
-
const more = state.slice.overflow && state.slice.overflow[col.id];
|
|
287
|
-
if (more) {
|
|
288
|
-
const d = document.createElement("div");
|
|
289
|
-
d.className="more";
|
|
290
|
-
d.textContent = "+ "+more+" more in this lane";
|
|
291
|
-
stack.appendChild(d);
|
|
292
|
-
}
|
|
293
|
-
wrap.appendChild(stack);
|
|
294
|
-
cols.appendChild(wrap);
|
|
295
|
-
});
|
|
296
|
-
canvas.appendChild(cols);
|
|
297
|
-
writeHash();
|
|
298
|
-
if (state.slice.focusCardId) {
|
|
299
|
-
const card = allCards().find(c => c.id===state.slice.focusCardId);
|
|
300
|
-
if (card) inspectCard(card);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
function allCards(){
|
|
304
|
-
if (!state.slice) return [];
|
|
305
|
-
return state.slice.columns.flatMap(c => c.cards).concat(state.slice.guards||[]);
|
|
306
|
-
}
|
|
307
|
-
function cardEl(card){
|
|
308
|
-
const b = document.createElement("button");
|
|
309
|
-
b.className="card";
|
|
310
|
-
b.type="button";
|
|
311
|
-
b.style.borderLeftColor = card.color || "var(--cyan)";
|
|
312
|
-
if (card.pulse) b.style.boxShadow = "inset 0 0 0 1px var(--rose)";
|
|
313
|
-
if (card.missingStep) b.style.boxShadow = "inset 0 0 0 1px var(--amber)";
|
|
314
|
-
b.innerHTML = "<strong>"+esc(card.title)+"</strong><small>"+esc(card.job)+" \xB7 "+esc(card.subtitle)+"</small>";
|
|
315
|
-
b.onclick = () => inspectCard(card);
|
|
316
|
-
return b;
|
|
317
|
-
}
|
|
318
|
-
function inspectPackage(p){
|
|
319
|
-
state.selected = p.id;
|
|
320
|
-
document.getElementById("drawer").innerHTML =
|
|
321
|
-
'<div class="dh"><h2>'+esc(p.name)+'</h2><button class="icon" id="close" type="button" aria-label="Close">\xD7</button></div>'
|
|
322
|
-
+ '<div class="db"><p>'+esc(p.job)+' \xB7 '+p.symbols+' symbols</p>'
|
|
323
|
-
+ (p.findings? '<div class="break"><h3>Rule breaks</h3><p>'+p.findings+' in this package.</p></div>':'')
|
|
324
|
-
+ '<p class="lbl">Open</p><p><a href="#" id="openslice">Open slice</a></p></div>';
|
|
325
|
-
document.getElementById("close").onclick = () => document.getElementById("work").classList.add("closed");
|
|
326
|
-
document.getElementById("openslice").onclick = ev => { ev.preventDefault(); openSlice(p.id); };
|
|
327
|
-
document.getElementById("work").classList.remove("closed");
|
|
328
|
-
}
|
|
329
|
-
async function inspectCard(card){
|
|
330
|
-
state.focus = card.symbolId;
|
|
331
|
-
state.selected = card.id;
|
|
332
|
-
writeHash();
|
|
333
|
-
const res = await fetch("/api/node/"+encodeURIComponent(card.symbolId));
|
|
334
|
-
if (!res.ok) { document.getElementById("drawer").textContent="Not found."; return; }
|
|
335
|
-
const n = await res.json();
|
|
336
|
-
const calls = (n.calls||[]).slice(0,40);
|
|
337
|
-
const called = (n.calledBy||[]).slice(0,40);
|
|
338
|
-
document.getElementById("drawer").innerHTML =
|
|
339
|
-
'<div class="dh"><h2>'+esc(n.name||card.title)+'</h2><button class="icon" id="close" type="button" aria-label="Close">\xD7</button></div>'
|
|
340
|
-
+ '<div class="db"><p>'+esc((n.view&&n.view.intent)||card.subtitle||"")+'</p>'
|
|
341
|
-
+ '<div class="lbl">Where</div><p>'+esc(n.file)+(n.line? ", line "+n.line:"")+'</p>'
|
|
342
|
-
+ '<div class="lbl">Calls</div>'+(calls.length? '<ul class="list">'+calls.map(x=>'<li>'+esc(x)+'</li>').join("")+'</ul>':'<p>Does not call anything else on this map.</p>')
|
|
343
|
-
+ '<div class="lbl">Called by</div>'+(called.length? '<ul class="list">'+called.map(x=>'<li>'+esc(x)+'</li>').join("")+'</ul>':'<p>Nothing on this map calls this.</p>')
|
|
344
|
-
+ (card.missingStep? '<div class="warn"><h3>This map is missing a step</h3></div>':'')
|
|
345
|
-
+ (card.pulse? '<div class="break"><h3>This breaks an architecture rule</h3></div>':'')
|
|
346
|
-
+ '</div>';
|
|
347
|
-
document.getElementById("close").onclick = () => document.getElementById("work").classList.add("closed");
|
|
348
|
-
document.getElementById("work").classList.remove("closed");
|
|
349
|
-
}
|
|
350
|
-
document.getElementById("back").onclick = () => { state.focus=null; drawWorkspace(); };
|
|
351
|
-
document.getElementById("arch").onclick = () => {
|
|
352
|
-
state.arch = !state.arch;
|
|
353
|
-
document.getElementById("arch").setAttribute("aria-pressed", state.arch);
|
|
354
|
-
document.getElementById("arch").textContent = state.arch ? "Architecture on" : "Architecture off";
|
|
355
|
-
if (state.zoom==="slice" && state.packageId) openSlice(state.packageId); else drawWorkspace();
|
|
356
|
-
};
|
|
357
|
-
document.querySelectorAll("[data-view]").forEach(b => b.onclick = () => {
|
|
358
|
-
document.querySelectorAll("[data-view]").forEach(x => x.setAttribute("aria-pressed","false"));
|
|
359
|
-
b.setAttribute("aria-pressed","true");
|
|
360
|
-
state.view = b.getAttribute("data-view");
|
|
361
|
-
if (state.zoom==="slice" && state.packageId && state.view!=="cluster") openSlice(state.packageId);
|
|
362
|
-
else drawWorkspace();
|
|
363
|
-
});
|
|
364
|
-
document.getElementById("callers").onclick = () => { if (state.focus && state.packageId) openSlice(state.packageId); };
|
|
365
|
-
document.getElementById("callees").onclick = () => { if (state.focus && state.packageId) openSlice(state.packageId); };
|
|
366
|
-
document.getElementById("theme").onclick = () => {
|
|
367
|
-
const light = document.documentElement.getAttribute("data-theme")==="light";
|
|
368
|
-
document.documentElement.setAttribute("data-theme", light? "dark":"light");
|
|
369
|
-
};
|
|
370
|
-
document.getElementById("save").onclick = () => {
|
|
371
|
-
const blob = new Blob([JSON.stringify({zoom:state.zoom,package:state.packageId,n:state.focus,view:state.view},null,2)], {type:"application/json"});
|
|
372
|
-
const a = document.createElement("a"); a.href=URL.createObjectURL(blob); a.download="architecture-map.json"; a.click();
|
|
373
|
-
};
|
|
374
|
-
document.getElementById("q").addEventListener("input", e => {
|
|
375
|
-
state.q = e.target.value;
|
|
376
|
-
if (state.zoom==="slice") openSlice(state.packageId); else drawWorkspace();
|
|
377
|
-
});
|
|
378
|
-
document.getElementById("zoom-in").onclick = () => { state.k=Math.min(2,state.k*1.2); if (state.zoom==="workspace") drawWorkspace(); };
|
|
379
|
-
document.getElementById("zoom-out").onclick = () => { state.k=Math.max(0.4,state.k/1.2); if (state.zoom==="workspace") drawWorkspace(); };
|
|
380
|
-
document.getElementById("zoom-fit").onclick = () => { state.k=1; if (state.zoom==="workspace") drawWorkspace(); };
|
|
381
|
-
document.addEventListener("keydown", e => {
|
|
382
|
-
if (e.key==="Escape" && state.zoom==="slice") { state.focus=null; drawWorkspace(); }
|
|
383
|
-
});
|
|
384
|
-
async function boot(){
|
|
385
|
-
try {
|
|
386
|
-
const mod = await import("/arch-ui/arch-ui.js");
|
|
387
|
-
if (mod && typeof mod.mount==="function") { mod.mount(document.body, { host: HOST }); return; }
|
|
388
|
-
} catch (_e) { /* vanilla */ }
|
|
389
|
-
bootVanilla();
|
|
390
|
-
}
|
|
391
|
-
boot();
|
|
392
|
-
</script>
|
|
393
|
-
</body>
|
|
394
|
-
</html>`}function ve(n){return Array.isArray(n)?n.filter(a=>typeof a=="string"):[]}function Ue(n){if(!n)return null;try{let a=JSON.parse(n);if(!a||typeof a!="object")return null;let r=a.role&&typeof a.role=="object"?a.role:a,s=typeof r.primary=="string"?r.primary:"";if(!s)return null;let u=a.intent&&typeof a.intent=="object"?a.intent:{};return{primary:s,confidence:typeof r.confidence=="number"?r.confidence:0,band:typeof r.band=="string"?r.band:"abstain",alternatives:Array.isArray(r.alternatives)?r.alternatives.filter(e=>typeof e?.role=="string").map(e=>({role:e.role,confidence:typeof e.confidence=="number"?e.confidence:0})):[],purposes:Array.isArray(a.purposes)?a.purposes.filter(e=>typeof e?.purpose=="string").map(e=>({purpose:e.purpose,confidence:typeof e.confidence=="number"?e.confidence:0})):[],intent:{text:typeof u.text=="string"?u.text:"",verbs:ve(u.verbs),objects:ve(u.objects)},findings:Array.isArray(a.findings)?a.findings.filter(e=>typeof e?.rule=="string"&&typeof e?.message=="string").map(e=>({rule:e.rule,severity:typeof e.severity=="string"?e.severity:"warn",message:e.message,...typeof e.line=="number"&&Number.isFinite(e.line)&&e.line>0?{line:Math.floor(e.line)}:{}})).slice(0,8):[],evidence:Array.isArray(a.evidence)?a.evidence.filter(e=>typeof e?.kind=="string"&&typeof e?.signal=="string").map(e=>({kind:e.kind,signal:e.signal,weight:typeof e.weight=="number"?e.weight:0})):[]}}catch{return null}}function ee(n){let a=n===void 0?J():n;return a?{version:()=>a.version(),classify:r=>{try{return Ue(a.classifyJson(r))}catch{return null}},projectOverview:(r,s)=>X(r,s),projectSlice:(r,s,u)=>Z(r,s,u),renderArchPage:r=>Q(r),archUiAssets:()=>{try{let r=Ge(ze(import.meta.url)),s=$e(r,"arch-ui");return qe(s)?s:null}catch{return null}}}:null}var De=new Set(["strict","balanced","exploratory"]),Ke=new Set(j);function te(n,a){let r=n.indexOf(a);if(!(r<0||r+1>=n.length))return n[r+1]}function Fe(){return new Promise((n,a)=>{let r=[];process.stdin.on("data",s=>r.push(Buffer.from(s))),process.stdin.on("end",()=>n(Buffer.concat(r).toString("utf8"))),process.stdin.on("error",a)})}async function ne(n=process.argv.slice(2),a={}){if(n[0]!=="sidecar")return process.stderr.write(`usage: node index.js sidecar --stdin --out <file> --profile <strict|balanced|exploratory> [--policy <hexagonal-v1|layered-v1>]
|
|
395
|
-
`),1;if(!n.includes("--stdin"))return process.stderr.write(`sidecar requires --stdin
|
|
396
|
-
`),1;let r=te(n,"--out");if(!r)return process.stderr.write(`sidecar requires --out <file>
|
|
397
|
-
`),1;let s=te(n,"--profile")??F;if(!De.has(s))return process.stderr.write(`invalid --profile ${s}
|
|
398
|
-
`),1;let u=s,e=te(n,"--policy")??q;if(!Ke.has(e))return process.stderr.write(`invalid --policy ${e} (one of ${j.join(", ")})
|
|
399
|
-
`),1;let t=e,o=a.provider===void 0?ee():a.provider;if(!o)return process.stderr.write(`architecture kernel wasm missing \u2014 refusing to classify
|
|
400
|
-
`),1;let l;try{let c=(await(a.readInput??Fe)()).trim();if(!c)return process.stderr.write(`sidecar stdin was empty
|
|
401
|
-
`),1;l=JSON.parse(c)}catch{return process.stderr.write(`sidecar stdin was not valid JSON
|
|
402
|
-
`),1}let d=Y({nodes:Array.isArray(l.nodes)?l.nodes:[],edges:Array.isArray(l.edges)?l.edges:[]}),h=o.version()||S,m=[],v=!1;for(let c of d){if(m.length>=8e3){v=!0;break}let g=o.classify({name:c.name,path:c.file_path,symbolKind:c.symbol_kind,fileKind:"source",calls:c.calls,types:[...c.parameters.map(y=>y.type_name).filter(y=>!!y),...c.return_type?[c.return_type]:[]],idents:[c.name,...c.calls].slice(0,24),profile:u,policy:t,qualifiedName:c.qualified_name,doc:c.doc??"",signature:c.signature,params:c.parameters.map(y=>y.name),returnType:c.return_type??"",calleePaths:c.callee_paths,imports:c.imports,...c.ast_role?{astRole:c.ast_role}:{},...c.effects?{effects:c.effects}:{},...c.duties?{duties:c.duties}:{}});g&&m.push({node_id:c.node_id,file_path:c.file_path,name:c.name,qualified_name:c.qualified_name,symbol_kind:c.symbol_kind,role:{primary:g.primary,alternatives:g.alternatives,confidence:g.confidence,band:g.band},purposes:g.purposes,intent:g.intent,evidence:g.evidence,...g.findings.length?{findings:g.findings}:{}})}let f={magic:U,taxonomy:D,ir:K,corpus_hash:l.provenance?.corpusHash??"",engine_version:h,profile:u,policy:t,symbols:m,...v?{symbols_capped:!0}:{}};try{P.mkdirSync(G.dirname(G.resolve(r)),{recursive:!0});let c=`${r}.${process.pid}.tmp`;P.writeFileSync(c,`${JSON.stringify(f)}
|
|
403
|
-
`),P.renameSync(c,r)}catch{return process.stderr.write(`sidecar failed to write ${r}
|
|
404
|
-
`),1}return 0}function Ye(){let n=process.argv[1];if(!n)return!1;try{return import.meta.url===Ve(n).href}catch{return!1}}Ye()&&ne().then(n=>{process.exit(n)});export{q as DEFAULT_POLICY,F as DEFAULT_PROFILE,V as DEFAULT_SYMBOL_CAP,S as HAILE_ENGINE_VERSION,K as HAILE_IR,U as HAILE_MAGIC,D as HAILE_TAXONOMY,j as POLICIES,Y as adaptGraph,ee as createHaileProvider,ce as isCallableKind,J as loadWasmHaileKernel,X as projectOverview,Z as projectSlice,Q as renderArchPage,Re as resetWasmHaileKernelCache,ne as runSidecarCli,le as symbolKindOf};
|
|
1
|
+
import{pathToFileURL as re}from"node:url";import*as y from"node:fs";import*as _ from"node:path";var v=["hexagonal-v1","layered-v1"],w="hexagonal-v1",H="vg.arch.v1",x="vg.arch.taxonomy.v1",A="vg.arch.ir.v1",m="haile-fast/2026.903.5",P="balanced",I=8e3,C=new Set(["function","method","route","test","component","job"]);var W=240,F=400,D=16,M=32,U=new Set(["public","private","protected","internal","static","async","override","virtual","abstract","final","def","fn","function","func","sub","pub","export","const","let","var","new","sealed","extern","unsafe","readonly","partial","default","synchronized","native","inline","constexpr","friend","explicit","operator","suspend","open","lateinit","get","set"]);function R(r){return C.has(r)}function K(r){switch(r){case"method":return"method";case"route":return"route";case"test":return"test";case"job":return"job";case"component":return"handler";default:return"function"}}function j(r,t=""){let a=t?r.indexOf(`${t}(`):-1;if(a<0&&(r.startsWith("@")||r.startsWith("[")))return[];let i=a>=0?a+t.length:r.indexOf("("),c=r.lastIndexOf(")");if(i<0||c<=i)return[];let e=r.slice(i+1,c).trim();return!e||e==="void"?[]:e.split(",").map(s=>s.trim()).filter(Boolean).slice(0,16).map(s=>{let f=s.replace(/\b(const|mut|ref|public|private|protected|readonly|final)\b/g,"").trim();if(f.includes(":")){let[o,d]=f.split(":").map(u=>u.trim());return{name:o||"arg",type_name:d||void 0}}let n=f.split(/\s+/);return n.length>=2?{name:n[n.length-1],type_name:n[0]}:{name:f}})}function q(r,t){let a=r.lastIndexOf("->");if(a>=0)return r.slice(a+2).replace(/[{;].*$/,"").trim()||void 0;let i=r.lastIndexOf(":"),c=r.lastIndexOf(")");if(i>c&&c>=0)return r.slice(i+1).replace(/[{;].*$/,"").replace(/\s*=>.*$/,"").trim()||void 0;let e=t?r.indexOf(`${t}(`):-1;if(e>0){let s=r.slice(0,e).trim(),f=0,n=0;for(let d=s.length-1;d>=0;d--){let u=s[d];if(u===">"||u==="]"||u===")")f++;else if(u==="<"||u==="["||u==="(")f--;else if(/\s/.test(u)&&f===0){n=d+1;break}}let o=s.slice(n).trim();if(o&&!o.startsWith("@")&&!o.startsWith("[")&&!U.has(o)&&o!=="void"&&!o.endsWith(")")&&!o.endsWith("]"))return o}}function $(r,t,a,i){let c=[],e=[],s=new Set,f=new Set;for(let n of t){if(n.src!==r||n.kind!=="call"&&n.kind!=="references")continue;let o=a.get(n.dst);if(!o)continue;let d=o.qualifiedName||o.name;if(!(!d||s.has(d))&&(s.add(d),c.push(d),o.file&&o.file!==i&&!f.has(o.file)&&e.length<D&&(f.add(o.file),e.push(o.file)),c.length>=24))break}return{calls:c,calleePaths:e}}function B(r,t,a){let i=new Map;for(let e of r)(e.kind==="file"||e.kind==="module")&&i.set(e.id,e.file);let c=new Map;for(let e of t){if(e.kind!=="import")continue;let s=i.get(e.src);if(!s)continue;let f=a.get(e.dst),n=f?.qualifiedName||f?.name;if(!n)continue;let o=c.get(s);o||(o=[],c.set(s,o)),o.length<M&&!o.includes(n)&&o.push(n)}return c}function k(r){let t=r.nodes??[],a=r.edges??[],i=new Map;for(let s of t)i.set(s.id,s);let c=B(t,a,i),e=[];for(let s of t){if(!R(s.kind))continue;let f=typeof s.decorators=="string"?s.decorators.trim():"",n=`${f?`${f} `:""}${s.signature??""}`.slice(0,F),{calls:o,calleePaths:d}=$(s.id,a,i,s.file),u=typeof s.doc=="string"?s.doc.trim().slice(0,W):"";e.push({node_id:s.id,file_path:s.file,name:s.name,qualified_name:s.qualifiedName||s.name,symbol_kind:K(s.kind),language:s.lang??"",signature:n,calls:o,parameters:j(n,s.name),return_type:q(n,s.name),...u?{doc:u}:{},callee_paths:d,imports:c.get(s.file)??[],...s.effects&&typeof s.effects=="object"?{effects:s.effects}:{},...Array.isArray(s.duties)?{duties:s.duties.slice(0,48)}:{}})}return e.sort((s,f)=>s.node_id<f.node_id?-1:s.node_id>f.node_id?1:0),e}import*as b from"node:fs";import{fileURLToPath as Y}from"node:url";var g;function V(){return[new URL("./engine/haile.wasm",import.meta.url),new URL("../engine/haile.wasm",import.meta.url),new URL("../crate/target/wasm32-unknown-unknown/release/vibgrate_haile_kernel.wasm",import.meta.url)].map(r=>Y(r))}function X(r){try{let t=new WebAssembly.Module(r),i=new WebAssembly.Instance(t,{}).exports;if(typeof i.vg_alloc!="function"||typeof i.vg_free!="function"||typeof i.vg_version!="function"||typeof i.vg_classify!="function"||!i.memory)return null;let c=n=>{let o=new TextEncoder().encode(n),d=i.vg_alloc(o.length);return new Uint8Array(i.memory.buffer,d,o.length).set(o),{ptr:d,len:o.length}},e=n=>{if(!n)return"";let o=new DataView(i.memory.buffer,n,4).getUint32(0,!0),d=new TextDecoder().decode(new Uint8Array(i.memory.buffer,n+4,o));return i.vg_free(n,4+o),d},s=(n,o)=>{let{ptr:d,len:u}=c(o);try{return e(n(d,u))}finally{i.vg_free(d,u)}},f={version:()=>{try{return e(i.vg_version())||m}catch{return m}},classifyJson:n=>{let o=JSON.stringify({name:n.name??"",path:n.path??"",symbolKind:n.symbolKind??"function",fileKind:n.fileKind??"source",calls:n.calls??[],types:n.types??[],idents:n.idents??[],profile:n.profile??"balanced",policy:n.policy??"hexagonal-v1",qualifiedName:n.qualifiedName??"",doc:n.doc??"",signature:n.signature??"",params:n.params??[],returnType:n.returnType??"",calleePaths:n.calleePaths??[],imports:n.imports??[],astRole:n.astRole??"",effects:n.effects??{},duties:n.duties??[]});return s(i.vg_classify,o)}};return typeof i.vg_overview=="function"&&(f.overviewJson=(n,o)=>s(i.vg_overview,JSON.stringify({graph:n,sidecar:o??null}))),typeof i.vg_slice=="function"&&(f.sliceJson=(n,o,d)=>s(i.vg_slice,JSON.stringify({graph:n,sidecar:o??null,spec:d??{}}))),typeof i.vg_arch_page=="function"&&(f.archPage=n=>s(i.vg_arch_page,JSON.stringify({host:n.host??"browser",nonce:n.nonce??"",theme:n.theme??""}))),f}catch{return null}}function L(){if(g!==void 0)return g;g=null;try{let r=V().find(t=>b.existsSync(t));return r&&(g=X(b.readFileSync(r))),g}catch{return g=null,g}}function z(){g=void 0}function T(r){return Array.isArray(r)?r.filter(t=>typeof t=="string"):[]}function G(r){if(!r)return null;try{return JSON.parse(r)}catch{return null}}function Q(r){if(!r)return null;try{let t=JSON.parse(r);if(!t||typeof t!="object")return null;let a=t.role&&typeof t.role=="object"?t.role:t,i=typeof a.primary=="string"?a.primary:"";if(!i)return null;let c=t.intent&&typeof t.intent=="object"?t.intent:{};return{primary:i,confidence:typeof a.confidence=="number"?a.confidence:0,band:typeof a.band=="string"?a.band:"abstain",alternatives:Array.isArray(a.alternatives)?a.alternatives.filter(e=>typeof e?.role=="string").map(e=>({role:e.role,confidence:typeof e.confidence=="number"?e.confidence:0})):[],purposes:Array.isArray(t.purposes)?t.purposes.filter(e=>typeof e?.purpose=="string").map(e=>({purpose:e.purpose,confidence:typeof e.confidence=="number"?e.confidence:0})):[],intent:{text:typeof c.text=="string"?c.text:"",verbs:T(c.verbs),objects:T(c.objects)},findings:Array.isArray(t.findings)?t.findings.filter(e=>typeof e?.rule=="string"&&typeof e?.message=="string").map(e=>({rule:e.rule,severity:typeof e.severity=="string"?e.severity:"warn",message:e.message,...typeof e.line=="number"&&Number.isFinite(e.line)&&e.line>0?{line:Math.floor(e.line)}:{}})).slice(0,8):[],evidence:Array.isArray(t.evidence)?t.evidence.filter(e=>typeof e?.kind=="string"&&typeof e?.signal=="string").map(e=>({kind:e.kind,signal:e.signal,weight:typeof e.weight=="number"?e.weight:0})):[]}}catch{return null}}function E(r){let t=r===void 0?L():r;if(!t)return null;let a={version:()=>t.version(),classify:i=>{try{return Q(t.classifyJson(i))}catch{return null}}};return t.overviewJson&&(a.projectOverview=(i,c)=>{try{return G(t.overviewJson(i,c))}catch{return null}}),t.sliceJson&&(a.projectSlice=(i,c,e)=>{try{return G(t.sliceJson(i,c,e))}catch{return null}}),t.archPage&&(a.renderArchPage=i=>{try{let c=t.archPage({host:i.host,theme:i.theme,nonce:i.nonce});return typeof c=="string"?c:""}catch{return""}}),a}var Z=new Set(["strict","balanced","exploratory"]),ee=new Set(v);function S(r,t){let a=r.indexOf(t);if(!(a<0||a+1>=r.length))return r[a+1]}function ne(){return new Promise((r,t)=>{let a=[];process.stdin.on("data",i=>a.push(Buffer.from(i))),process.stdin.on("end",()=>r(Buffer.concat(a).toString("utf8"))),process.stdin.on("error",t)})}async function O(r=process.argv.slice(2),t={}){if(r[0]!=="sidecar")return process.stderr.write(`usage: node index.js sidecar --stdin --out <file> --profile <strict|balanced|exploratory> [--policy <hexagonal-v1|layered-v1>]
|
|
2
|
+
`),1;if(!r.includes("--stdin"))return process.stderr.write(`sidecar requires --stdin
|
|
3
|
+
`),1;let a=S(r,"--out");if(!a)return process.stderr.write(`sidecar requires --out <file>
|
|
4
|
+
`),1;let i=S(r,"--profile")??P;if(!Z.has(i))return process.stderr.write(`invalid --profile ${i}
|
|
5
|
+
`),1;let c=i,e=S(r,"--policy")??w;if(!ee.has(e))return process.stderr.write(`invalid --policy ${e} (one of ${v.join(", ")})
|
|
6
|
+
`),1;let s=e,f=t.provider===void 0?E():t.provider;if(!f)return process.stderr.write(`architecture kernel wasm missing \u2014 refusing to classify
|
|
7
|
+
`),1;let n;try{let l=(await(t.readInput??ne)()).trim();if(!l)return process.stderr.write(`sidecar stdin was empty
|
|
8
|
+
`),1;n=JSON.parse(l)}catch{return process.stderr.write(`sidecar stdin was not valid JSON
|
|
9
|
+
`),1}let o=k({nodes:Array.isArray(n.nodes)?n.nodes:[],edges:Array.isArray(n.edges)?n.edges:[]}),d=f.version()||m,u=[],N=!1;for(let l of o){if(u.length>=8e3){N=!0;break}let p=f.classify({name:l.name,path:l.file_path,symbolKind:l.symbol_kind,fileKind:"source",calls:l.calls,types:[...l.parameters.map(h=>h.type_name).filter(h=>!!h),...l.return_type?[l.return_type]:[]],idents:[l.name,...l.calls].slice(0,24),profile:c,policy:s,qualifiedName:l.qualified_name,doc:l.doc??"",signature:l.signature,params:l.parameters.map(h=>h.name),returnType:l.return_type??"",calleePaths:l.callee_paths,imports:l.imports,...l.ast_role?{astRole:l.ast_role}:{},...l.effects?{effects:l.effects}:{},...l.duties?{duties:l.duties}:{}});p&&u.push({node_id:l.node_id,file_path:l.file_path,name:l.name,qualified_name:l.qualified_name,symbol_kind:l.symbol_kind,role:{primary:p.primary,alternatives:p.alternatives,confidence:p.confidence,band:p.band},purposes:p.purposes,intent:p.intent,evidence:p.evidence,...p.findings.length?{findings:p.findings}:{}})}let J={magic:H,taxonomy:x,ir:A,corpus_hash:n.provenance?.corpusHash??"",engine_version:d,profile:c,policy:s,symbols:u,...N?{symbols_capped:!0}:{}};try{y.mkdirSync(_.dirname(_.resolve(a)),{recursive:!0});let l=`${a}.${process.pid}.tmp`;y.writeFileSync(l,`${JSON.stringify(J)}
|
|
10
|
+
`),y.renameSync(l,a)}catch{return process.stderr.write(`sidecar failed to write ${a}
|
|
11
|
+
`),1}return 0}function te(){let r=process.argv[1];if(!r)return!1;try{return import.meta.url===re(r).href}catch{return!1}}te()&&O().then(r=>{process.exit(r)});export{w as DEFAULT_POLICY,P as DEFAULT_PROFILE,I as DEFAULT_SYMBOL_CAP,m as HAILE_ENGINE_VERSION,A as HAILE_IR,H as HAILE_MAGIC,x as HAILE_TAXONOMY,v as POLICIES,k as adaptGraph,E as createHaileProvider,R as isCallableKind,L as loadWasmHaileKernel,z as resetWasmHaileKernelCache,O as runSidecarCli,K as symbolKindOf};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibgrate/haile",
|
|
3
|
-
"version": "2026.910.
|
|
3
|
+
"version": "2026.910.3",
|
|
4
4
|
"description": "Vibgrate HAILE architecture kernel: deterministic callable classification (role, purposes, intent, band) over a vg-graph. Proprietary distribution — compiled WASM engine plus a minified loader; the taxonomy is not included.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|