toolnet-memory 0.3.15 → 0.3.16
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/.release-target +1 -1
- package/README.md +158 -6
- package/bundle/agy-hook.js +66 -66
- package/bundle/agy.js +59 -59
- package/bundle/api.js +15 -15
- package/bundle/background-refresh.js +7 -7
- package/bundle/claude-hook.js +49 -49
- package/bundle/codex-context.js +29 -29
- package/bundle/codex.js +71 -71
- package/bundle/context-runtime.js +44 -44
- package/bundle/context.js +14 -14
- package/bundle/copilot-hook.js +77 -77
- package/bundle/cursor-hook.js +78 -78
- package/bundle/doctor.js +4 -4
- package/bundle/full-index.js +19 -19
- package/bundle/graph-index.js +4 -4
- package/bundle/graph-ui.js +3 -3
- package/bundle/grok-hook.js +55 -55
- package/bundle/handoff-refresh.js +10 -10
- package/bundle/help-cli.js +3 -3
- package/bundle/impact.js +4 -4
- package/bundle/incremental.js +5 -5
- package/bundle/init.js +36 -35
- package/bundle/kiro-hook.js +86 -86
- package/bundle/learner.js +6 -6
- package/bundle/mcp.js +17 -17
- package/bundle/memory-agent.js +6 -6
- package/bundle/memory-query.js +7 -7
- package/bundle/opencode.js +73 -73
- package/bundle/project-manual.js +7 -7
- package/bundle/recovery-certify.js +9 -9
- package/bundle/runtime.js +13 -13
- package/bundle/semantic.js +5 -5
- package/bundle/snapshot.js +4 -4
- package/bundle/status-cli.js +4 -4
- package/bundle/toolnet-cli.js +48 -48
- package/bundle/work-continuity.js +7 -7
- package/package.json +14 -2
- package/release-manifest.json +51 -1
package/bundle/graph-index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import"dotenv/config";import{existsSync as
|
|
2
|
-
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function
|
|
3
|
-
`,{encoding:"utf8",mode:384}),Te(n,r)}function H(s,e){return{id:s.id,name:s.name,remote:s.remote,rootPath:e,createdAt:s.createdAt,updatedAt:s.updatedAt,graphVersion:s.graphVersion,memoryVersion:s.memoryVersion,metadata:s.metadata}}var $=class{findExisting(e=process.cwd()){let t=R(e),r=X(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>_(A(r,p))),i=Q(t,o?r:void 0);if(!i)return null;let a=ee(D(i));return H(a,i)}requireExisting(e=process.cwd()){let t=this.findExisting(e);if(!t)throw new Error("PROJECT_NOT_INITIALIZED");return t}detect(e=process.cwd()){let t=R(e),r=X(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(l=>_(A(r,l))),i=Q(t,o?r:void 0);if(i){let l=D(i),u=ee(l);return u.rootPath!==i&&(u.rootPath=i,u.updatedAt=new Date().toISOString(),te(i,u)),H(u,i)}let a=new Date().toISOString(),p=je(r),c={version:1,id:Le(r),name:p,remote:p,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return te(r,c),H(c,r)}};var Oe=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_-]{20,}\b/g,confidence:"exact"},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g,confidence:"exact"},{type:"aws_access_key",regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,confidence:"exact"},{type:"github_token",regex:/\b(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{40,255})\b/g,confidence:"exact"},{type:"stripe_secret_key",regex:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,confidence:"exact"},{type:"google_api_key",regex:/\bAIza[A-Za-z0-9_-]{30,}\b/g,confidence:"exact"},{type:"slack_token",regex:/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/g,confidence:"exact"},{type:"npm_token",regex:/\bnpm_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi,confidence:"high"},{type:"jwt",regex:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,confidence:"exact"},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,confidence:"exact"},{type:"password_assignment",regex:/\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^"' \t\r\n]{6,}["']?/gi,confidence:"high"},{type:"secret_assignment",regex:/\b(?:secret|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\s*[:=]\s*["']?[^"' \t\r\n]{8,}["']?/gi,confidence:"high"},{type:"cookie",regex:/\b(?:cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi,confidence:"high"},{type:"url_credentials",regex:/\bhttps?:\/\/[^:/@\s]+:[^/@\s]{4,}@[^/\s]+/gi,confidence:"high"}],_e=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function ne(s){return s.normalize("NFKC").trim().toLowerCase()}function Fe(s){if(s.length===0)return 0;let e=new Map;for(let r of s)e.set(r,(e.get(r)??0)+1);let t=0;for(let r of e.values()){let n=r/s.length;t-=n*Math.log2(n)}return t}function De(s){return/^[a-f0-9]{32}$/iu.test(s)||/^[a-f0-9]{40}$/iu.test(s)||/^[a-f0-9]{64}$/iu.test(s)}function $e(s,e,t){let r=s.slice(Math.max(0,e-48),e),n=s.slice(t,Math.min(s.length,t+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${r} ${n}`)}function Ge(s,e){return s.start<e.end&&e.start<s.end}function oe(s){return s.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var G=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let r=ne(t);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let o of Oe){let i=new RegExp(o.regex.source,o.regex.flags);for(let a of e.matchAll(i))a.index===void 0||!a[0]||this.allowed(a[0])||t.push({type:o.type,value:a[0],start:a.index,end:a.index+a[0].length,confidence:o.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let r=oe(t),n=[];for(let o of r)n.some(i=>Ge(i,o))||n.push(o);return oe(n)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=ne(e);return _e.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],r=/[A-Za-z0-9_+/=-]{32,160}/g;for(let n of e.matchAll(r)){if(n.index===void 0||!n[0])continue;let o=n[0];this.allowed(o)||De(o)||!/[A-Za-z]/u.test(o)||!/[0-9]/u.test(o)||$e(e,n.index,n.index+o.length)&&(Fe(o)<3.7||t.push({type:"high_entropy_secret",value:o,start:n.index,end:n.index+o.length,confidence:"heuristic"}))}return t}};var j=class{scanner;constructor(e={}){this.scanner=new G(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let r=e,n=[...t].sort((i,a)=>a.start-i.start),o=new Set;for(let i of n)o.add(i.type),r=r.slice(0,i.start)+`[REDACTED:${i.type}]`+r.slice(i.end);return{text:r,redacted:t.length,secretTypes:[...o].sort()}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[r,n]of Object.entries(e)){let o=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(o.includes("password")||o.includes("passwd")||o==="pwd"||o.includes("secret")||o.includes("token")||o.includes("cookie")||o.includes("authorization")||o.includes("apikey")||o.includes("accesskey")||o.includes("privatekey")||o.includes("clientsecret")||o.includes("credential")){t[r]="[REDACTED]";continue}t[r]=this.sanitizeValue(n)}return t}return e}};var nr=new j;import{lstat as We,readdir as Ue}from"node:fs/promises";import{extname as He,join as Ve,relative as Ye,resolve as Je}from"node:path";import{basename as ze}from"node:path";var Ke=new Set([".env",".env.local",".env.production",".env.development","id_rsa","id_ed25519","credentials","credentials.json","service-account.json"]),Be=new Set([".pem",".key",".p12",".pfx"]);function ie(s){let e=ze(s).toLowerCase();if(Ke.has(e))return!0;for(let t of Be)if(e.endsWith(t))return!0;return!1}var qe=2*1024*1024,Ze=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".mts",".cts"]),Qe=new Set(["node_modules",".git",".toolnet",".toolnet-memory","dist","build","out","coverage",".next",".nuxt",".cache",".parcel-cache",".turbo","vendor","target"]);function ae(s,e){if(!Number.isSafeInteger(s)||s<1)throw new Error(`${e} must be a positive integer`);return s}function ce(s){if(s?.aborted)throw new Error("Repository scan aborted")}function Xe(s){let e=s.trim().toLowerCase();if(!e)throw new Error("Repository scan extension cannot be empty");return e.startsWith(".")?e:`.${e}`}function et(s){let e=s.toLowerCase();return/\.min\.(?:js|mjs|cjs)$/u.test(e)||/\.bundle\.(?:js|mjs|cjs)$/u.test(e)}function tt(s){return s.replaceAll("\\","/")}async function le(s,e={}){let t=Je(s),r=e.maxFileBytes??qe;if(!Number.isSafeInteger(r)||r<1)throw new Error("maxFileBytes must be a positive integer");let n=e.maxFiles??Number.MAX_SAFE_INTEGER;ae(n,"maxFiles");let o=e.progressInterval??1e3;ae(o,"progressInterval");let i=new Set(e.extensions?[...e.extensions].map(Xe):Ze),a=new Set(Qe);for(let u of e.extraIgnoredDirectories??[]){let f=u.trim();f&&a.add(f)}let p=[],c={directories:0,entries:0,accepted:0,skippedIgnoredDirectories:0,skippedSymlinks:0,skippedGenerated:0,skippedSensitive:0,skippedOversized:0,skippedUnreadable:0},l=[t];for(;l.length>0;){ce(e.signal);let u=l.pop(),f;try{f=await Ue(u,{withFileTypes:!0})}catch{c.skippedUnreadable+=1;continue}c.directories+=1;for(let h of f){ce(e.signal),c.entries+=1,c.entries%o===0&&e.onProgress?.({directories:c.directories,entries:c.entries,accepted:c.accepted});let C=Ve(u,h.name);if(h.isSymbolicLink()){c.skippedSymlinks+=1;continue}if(h.isDirectory()){if(a.has(h.name)){c.skippedIgnoredDirectories+=1;continue}l.push(C);continue}if(!h.isFile())continue;let k=He(h.name).toLowerCase();if(!i.has(k))continue;if(et(h.name)){c.skippedGenerated+=1;continue}if(ie(C)){c.skippedSensitive+=1;continue}let P;try{P=await We(C)}catch{c.skippedUnreadable+=1;continue}if(P.isSymbolicLink()){c.skippedSymlinks+=1;continue}if(P.isFile()){if(P.size>r){c.skippedOversized+=1;continue}if(p.length>=n)throw new Error(`Repository scan file limit exceeded: ${n}`);p.push(tt(Ye(t,C))),c.accepted+=1}}}return p.sort(),e.onProgress?.({directories:c.directories,entries:c.entries,accepted:c.accepted}),{files:p,stats:c}}import{createHash as rt}from"node:crypto";import{dirname as st,extname as nt,normalize as ot,posix as it}from"node:path";var z=class{symbols=new Map;edges=new Map;addSymbol(e){this.symbols.set(e.id,e)}addEdge(e){this.edges.set(e.id,e)}getSymbol(e){return this.symbols.get(e)}findByName(e,t){return[...this.symbols.values()].filter(r=>r.projectId===e&&(r.name===t||r.qualifiedName===t))}allSymbols(e){return[...this.symbols.values()].filter(t=>t.projectId===e)}allEdges(e){return[...this.edges.values()].filter(t=>t.projectId===e)}import(e,t){for(let r of e)this.addSymbol(r);for(let r of t)this.addEdge(r)}clearProject(e){for(let[t,r]of this.symbols)r.projectId===e&&this.symbols.delete(t);for(let[t,r]of this.edges)r.projectId===e&&this.edges.delete(t)}};function at(s,e,t,r){return rt("sha256").update(`${s}:${e}:${t}:${r}`).digest("hex").slice(0,24)}function E(s){return ot(s).replaceAll("\\","/")}function ct(s,e,t){if(!e.startsWith("."))return;let r=E(it.join(st(s),e)),n=nt(r),o;if(n===".js"){let i=r.slice(0,-3);o=[`${i}.ts`,`${i}.tsx`,`${i}.js`,`${i}.jsx`]}else if(n===".mjs"){let i=r.slice(0,-4);o=[`${i}.mts`,`${i}.ts`,`${i}.mjs`]}else if(n===".cjs"){let i=r.slice(0,-4);o=[`${i}.cts`,`${i}.ts`,`${i}.cjs`]}else n?o=[r]:o=[`${r}.ts`,`${r}.tsx`,`${r}.mts`,`${r}.cts`,`${r}.js`,`${r}.jsx`,`${r}.mjs`,`${r}.cjs`,`${r}/index.ts`,`${r}/index.tsx`,`${r}/index.mts`,`${r}/index.cts`,`${r}/index.js`,`${r}/index.jsx`,`${r}/index.mjs`,`${r}/index.cjs`];return o.find(i=>t.has(E(i)))}function V(s,e,t,r){let n=r?.(s,e,t);if(n){let o=E(n);if(t.has(o))return o}return ct(s,e,t)}var I=class{build(e,t,r={}){let n=new z;for(let a of r.seedSymbols??[])n.addSymbol(a);for(let a of t)for(let p of a.symbols)n.addSymbol(p);let o=new Map;for(let a of n.allSymbols(e))a.type==="file"&&o.set(E(a.filePath),a);let i=new Set(o.keys());for(let a of t){let p=E(a.filePath),c=o.get(p);if(c){for(let l of a.symbols)l.id!==c.id&&n.addEdge(this.edge(e,c.id,"DEFINES",l.id));for(let l of a.imports){let u=V(p,l.source,i,r.resolveModule);if(!u)continue;let f=o.get(u);f&&n.addEdge(this.edge(e,c.id,"IMPORTS",f.id,{source:l.source,resolvedFile:u}))}for(let l of a.heritage){let u=n.findByName(e,l.targetName).filter(f=>f.type==="class"||f.type==="interface");for(let f of u)n.addEdge(this.edge(e,l.fromId,l.type,f.id))}for(let l of a.calls){if(!l.callerId)continue;let u=this.resolveCallTargets(e,a,l.calleeName,l.qualifier,n,i,r.resolveModule);for(let f of u)f.id!==l.callerId&&n.addEdge(this.edge(e,l.callerId,"CALLS",f.id,{line:l.line,qualifier:l.qualifier}))}}}return n}resolveCallTargets(e,t,r,n,o,i,a){let p=E(t.filePath),c=o.findByName(e,r).filter(l=>E(l.filePath)===p);if(!n&&c.length)return c;if(n)for(let l of t.imports){if(!l.bindings.find(h=>h.kind==="namespace"&&h.localName===n))continue;let f=V(p,l.source,i,a);if(f)return o.findByName(e,r).filter(h=>E(h.filePath)===f)}for(let l of t.imports){let u=l.bindings.find(k=>k.localName===r);if(!u)continue;let f=V(p,l.source,i,a);if(!f)continue;let h=u.importedName==="default"?r:u.importedName,C=o.findByName(e,h).filter(k=>E(k.filePath)===f);if(C.length)return C}return o.findByName(e,r).filter(l=>l.type==="function"||l.type==="method")}edge(e,t,r,n,o){return{id:at(e,t,r,n),projectId:e,from:t,to:n,type:r,metadata:o}}};import{readFile as lt}from"node:fs/promises";import{join as dt}from"node:path";import{createHash as pt}from"node:crypto";import*as m from"typescript";function de(s,e){return pt("sha256").update(`${s}:${e}`).digest("hex").slice(0,24)}function Y(s,e){return s.getLineAndCharacterOfPosition(e.getStart(s)).line+1}async function J(s,e,t){let r=dt(e,t),n=await lt(r,"utf8"),o=m.createSourceFile(t,n,m.ScriptTarget.Latest,!0,t.endsWith(".tsx")||t.endsWith(".jsx")?m.ScriptKind.TSX:m.ScriptKind.TS),i=[],a=[],p=[],c=[],l={id:de(s,`file:${t}`),projectId:s,name:t,qualifiedName:t,type:"file",filePath:t,startLine:1,endLine:o.getLineAndCharacterOfPosition(o.end).line+1};i.push(l);let u=[],f=[];function h(d,b,S,y){let w=de(s,`${t}:${S}:${y??b}:${d.pos}`);return i.push({id:w,projectId:s,name:b,qualifiedName:y??b,type:S,filePath:t,startLine:Y(o,d),endLine:o.getLineAndCharacterOfPosition(d.end).line+1}),w}function C(d){if(!m.isStringLiteral(d.moduleSpecifier))return;let b=[],S=d.importClause;if(S?.name&&b.push({localName:S.name.text,importedName:"default",kind:"default"}),S?.namedBindings&&m.isNamedImports(S.namedBindings))for(let y of S.namedBindings.elements)b.push({localName:y.name.text,importedName:y.propertyName?.text??y.name.text,kind:"named"});S?.namedBindings&&m.isNamespaceImport(S.namedBindings)&&b.push({localName:S.namedBindings.name.text,importedName:"*",kind:"namespace"}),a.push({source:d.moduleSpecifier.text,bindings:b})}function k(d,b){for(let S of d.heritageClauses??[])for(let y of S.types){let w=y.expression.getText(o).split(".").at(-1)??"";w&&c.push({fromId:b,targetName:w,type:S.token===m.SyntaxKind.ExtendsKeyword?"INHERITS":"IMPLEMENTS"})}}function P(d){let b=!1,S=!1;if(m.isImportDeclaration(d)&&C(d),m.isInterfaceDeclaration(d)&&h(d,d.name.text,"interface",d.name.text),m.isClassDeclaration(d)&&d.name){let y=h(d,d.name.text,"class",d.name.text);k(d,y),f.push({id:y,name:d.name.text}),S=!0}if(m.isFunctionDeclaration(d)&&d.name){let y=h(d,d.name.text,"function",d.name.text);u.push(y),b=!0}if(m.isMethodDeclaration(d)&&d.name){let y=d.name.getText(o),w=f.at(-1)?.name,be=h(d,y,"method",w?`${w}.${y}`:y);u.push(be),b=!0}if(m.isCallExpression(d)&&(m.isIdentifier(d.expression)&&p.push({callerId:u.at(-1),calleeName:d.expression.text,line:Y(o,d)}),m.isPropertyAccessExpression(d.expression))){let y=d.expression;p.push({callerId:u.at(-1),qualifier:y.expression.getText(o),calleeName:y.name.text,line:Y(o,d)})}m.forEachChild(d,P),b&&u.pop(),S&&f.pop()}return P(o),{filePath:t,symbols:i,imports:a,calls:p,heritage:c}}function ut(s){let e=s??4;if(!Number.isSafeInteger(e)||e<1||e>64)throw new Error("concurrency must be an integer between 1 and 64");return e}function ft(s){if(s?.aborted)throw new Error("Operation aborted")}async function K(s,e,t={}){if(s.length===0)return[];let r=Math.min(ut(t.concurrency),s.length),n=new Array(s.length),o=0,i=0,a=async()=>{for(;;){ft(t.signal);let c=o;if(o+=1,c>=s.length)return;n[c]=await e(s[c],c),i+=1,t.onProgress?.({completed:i,total:s.length,index:c})}},p=Array.from({length:r},()=>a());return await Promise.all(p),n}var B=class{async index(e,t,r={}){let n={...r.scan};r.signal&&(n.signal=r.signal);let o=await le(t,n),i=o.files;r.onProgress?.({phase:"scan",current:i.length,total:i.length});let a=r.maxWarnings??20;if(!Number.isSafeInteger(a)||a<0)throw new Error("maxWarnings must be a non-negative integer");let p=0,c=await K(i,async f=>{try{return await J(e,t,f)}catch(h){return p+=1,p<=a&&console.warn(`[indexer] skipped ${f}:`,h instanceof Error?h.message:h),null}},{concurrency:r.concurrency??4,signal:r.signal,onProgress:({completed:f,total:h,index:C})=>{r.onProgress?.({phase:"parse",current:f,total:h,file:i[C]})}});p>a&&console.warn(`[indexer] ${p-a} additional parse warnings suppressed`);let l=c.filter(f=>f!==null),u=new I().build(e,l);return{files:l.length,symbols:u.allSymbols(e).length,edges:u.allEdges(e).length,parseFailures:p,scan:o.stats,graph:u}}};function ue(s,e){let t=s.allSymbols(e),r=s.allEdges(e),n=i=>t.filter(a=>a.type===i).length,o=i=>r.filter(a=>a.type===i).length;return{files:n("file"),classes:n("class"),interfaces:n("interface"),functions:n("function"),methods:n("method"),properties:n("property"),routes:n("route"),symbols:t.length,edges:r.length,calls:o("CALLS"),callReferences:o("CALL_REFERENCE"),imports:o("IMPORTS"),inherits:o("INHERITS"),implements:o("IMPLEMENTS"),usesType:o("USES_TYPE"),tests:o("TESTS"),routeEdges:o("ROUTE"),writes:o("WRITES")}}import{execFile as mt}from"node:child_process";import{promisify as gt}from"node:util";var ps=gt(mt);var L=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};import*as v from"typescript";import{DatabaseSync as an}from"node:sqlite";import*as x from"typescript";import*as g from"typescript";var Tn=new Set([g.SyntaxKind.EqualsToken,g.SyntaxKind.PlusEqualsToken,g.SyntaxKind.MinusEqualsToken,g.SyntaxKind.AsteriskEqualsToken,g.SyntaxKind.SlashEqualsToken,g.SyntaxKind.PercentEqualsToken,g.SyntaxKind.QuestionQuestionEqualsToken,g.SyntaxKind.AmpersandAmpersandEqualsToken,g.SyntaxKind.BarBarEqualsToken]);import{homedir as Gt}from"node:os";import{join as zt}from"node:path";import{DeleteObjectCommand as St,GetObjectCommand as bt,HeadObjectCommand as xt,ListObjectsV2Command as Ct,PutObjectCommand as Et,S3Client as wt}from"@aws-sdk/client-s3";import{getSignedUrl as vt}from"@aws-sdk/s3-request-presigner";var W=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new wt({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Et({Bucket:this.bucket,Key:e,Body:n,ContentType:r}))}async get(e){let t=await vt(this.client,new bt({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(t,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`HF download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new xt({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new St({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let n=await this.client.send(new Ct({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of n.Contents??[])o.Key&&t.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=n.IsTruncated?n.NextContinuationToken:void 0}while(r);return t}};import{access as fe,mkdir as kt,readFile as Pt,readdir as Rt,rm as Mt,stat as me,writeFile as Tt}from"node:fs/promises";import{dirname as At,join as jt,relative as ge,resolve as It}from"node:path";var N=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return It(this.root,t)}async put(e,t){let r=this.path(e);await kt(At(r),{recursive:!0}),await Tt(r,t)}async get(e){try{return await Pt(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await fe(this.path(e)),!0}catch{return!1}}async delete(e){await Mt(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await fe(t)}catch{return r}let n=async i=>{let a=await Rt(i,{withFileTypes:!0});for(let p of a){let c=jt(i,p.name);if(p.isDirectory()){await n(c);continue}let l=await me(c);r.push({key:ge(this.root,c),size:l.size,updatedAt:l.mtime.toISOString()})}},o=await me(t);return o.isDirectory()?await n(t):r.push({key:ge(this.root,t),size:o.size,updatedAt:o.mtime.toISOString()}),r}};import{DeleteObjectCommand as Lt,GetObjectCommand as Nt,HeadObjectCommand as Ot,ListObjectsV2Command as _t,PutObjectCommand as Ft,S3Client as Dt}from"@aws-sdk/client-s3";import{getSignedUrl as $t}from"@aws-sdk/s3-request-presigner";var O=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Dt({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Ft({Bucket:this.bucket,Key:e,Body:n,ContentType:r}))}async get(e){let t=await $t(this.client,new Nt({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(t,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`${this.name} download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Ot({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new Lt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let n=await this.client.send(new _t({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of n.Contents??[])o.Key&&t.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=n.IsTruncated?n.NextContinuationToken:void 0}while(r);return t}};function q(s,e){return console.warn(e),new N(s)}function he(s){let e=s.localRoot??zt(Gt(),".toolnet-memory","storage");if(s.provider==="r2"){let t=s.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new O({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):q(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(s.provider==="s3"){let t=s.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new O({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):q(e,"[storage] S3 credentials missing. Using local fallback.")}if(s.provider==="huggingface"){let t=s.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new W({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):q(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new N(e)}function ye(s){let e=s.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function Se(s){let e=s.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let n=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return n?`${n[1]}memory/records/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),n?`${n[1]}memory/vectors/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),n?`${n[1]}code/graph/${n[2]}`:e))}var U=class{constructor(e,t,r,n){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=ye(n??r),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),r=t,n=await this.provider.getText(e);if(n){let i;try{i=JSON.parse(n)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:t};await this.provider.put(e,JSON.stringify(o,null,2)+`
|
|
4
|
-
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=
|
|
1
|
+
import"dotenv/config";import{existsSync as Te,readFileSync as Ie}from"node:fs";import{homedir as je}from"node:os";import{join as Le}from"node:path";function Ne(n){let e=n.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
|
|
2
|
+
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function _e(){let n=process.env.TOOLNET_GLOBAL_ENV??Le(je(),".config","toolnet-memory",".env");if(!Te(n))return;let e=Ie(n,"utf8");for(let t of e.split(/\r?\n/)){let r=t.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let s=r.indexOf("=");if(s<=0)continue;let o=r.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(o)&&process.env[o]===void 0&&(process.env[o]=Ne(r.slice(s+1)))}}_e();function T(n,e){return n===void 0?e:["1","true","yes","on"].includes(n.toLowerCase())}function I(n,e){if(!n)return e;let t=Number(n);return Number.isFinite(t)?t:e}function ne(){return{memory:{autoCapture:T(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:T(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:T(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:T(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:I(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:I(process.env.MEMORY_RERANK_TOP,10),finalContext:I(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:I(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",r2:{accountId:process.env.R2_ACCOUNT_ID,bucket:process.env.R2_BUCKET,accessKeyId:process.env.R2_ACCESS_KEY_ID,secretAccessKey:process.env.R2_SECRET_ACCESS_KEY},s3:{endpoint:process.env.S3_ENDPOINT,region:process.env.S3_REGION,bucket:process.env.S3_BUCKET,accessKeyId:process.env.S3_ACCESS_KEY_ID,secretAccessKey:process.env.S3_SECRET_ACCESS_KEY,forcePathStyle:T(process.env.S3_FORCE_PATH_STYLE,!1)},huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:I(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as ze}from"node:crypto";import{existsSync as K,mkdirSync as Be,readFileSync as He,renameSync as We,writeFileSync as Ue}from"node:fs";import{basename as Ve,dirname as z,join as L,parse as pe,resolve as A}from"node:path";import{createHash as ie}from"node:crypto";import{spawnSync as Oe}from"node:child_process";var j="git-remote-v1",Fe=new Set(["github.com","gitlab.com","bitbucket.org"]);function ae(n,e){let t=e.replaceAll("\\","/").replace(/^\/+/u,"").replace(/\/+$/u,"").replace(/\.git$/iu,"").replace(/\/+/gu,"/");return!t||t==="."||t===".."||t.split("/").some(r=>!r||r==="."||r==="..")?null:(Fe.has(n)&&(t=t.toLowerCase()),t)}function De(n){let e;try{e=new URL(n)}catch{return null}if(!["https:","http:","ssh:","git:"].includes(e.protocol))return null;let t=e.hostname.trim().toLowerCase();if(!t)return null;let r=e.protocol==="https:"&&e.port==="443"||e.protocol==="http:"&&e.port==="80"||e.protocol==="ssh:"&&e.port==="22",s=e.port&&!r?`${t}:${e.port}`:t,o=ae(t,e.pathname);return o?`${s}/${o}`:null}function $e(n){let e=n.match(/^(?:[^@\s/:]+@)?([^:/\s]+):(.+)$/u);if(!e)return null;let t=e[1]?.trim().toLowerCase();if(!t||t.length===1)return null;let r=ae(t,e[2]??"");return r?`${t}/${r}`:null}function se(n){let e=n.trim();return e?e.includes("://")?De(e):$e(e):null}function Ge(n){return ie("sha256").update(`${j}:${n}`).digest("hex")}function ce(n){return ie("sha256").update(`toolnet-project:${j}:${n}`).digest("hex").slice(0,16)}function Ke(n){return n.split("/").filter(Boolean).at(-1)?.trim()||null}function J(n,e){let t=Oe("git",["-C",n,...e],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return t.error||t.status!==0?null:t.stdout?.trim()||null}function oe(n,e){let t=Ke(n);return t?{scheme:j,canonicalRemote:n,fingerprint:Ge(n),repositoryName:t,source:e}:null}function le(n){let e=J(n,["remote","get-url","origin"]);if(e){let s=se(e);if(s)return oe(s,"origin")}let t=J(n,["remote"]);if(!t)return null;let r=new Set;for(let s of t.split(/\r?\n/u).map(o=>o.trim()).filter(Boolean)){let o=J(n,["remote","get-url",s]);if(!o)continue;let i=se(o);i&&r.add(i)}return r.size!==1?null:oe([...r][0],"unique-remote")}var ue=".toolnet",Ye="project.json";function qe(n){return ze("sha256").update(n).digest("hex").slice(0,16)}function M(n){return L(n,ue,Ye)}function me(n){return K(M(n))}function de(n,e){let t=A(n),r=pe(t).root;for(;;){if(me(t))return t;if(t===r||e&&t===A(e))break;let s=z(t);if(s===t)break;t=s}return null}function Q(n){let e=A(n),t=pe(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>K(L(e,o))))return e;if(e===t)break;let s=z(e);if(s===e)break;e=s}return A(n)}function $(n){let e;try{e=JSON.parse(He(n,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${n}: ${s instanceof Error?s.message:String(s)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${n}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${n}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${n}`);let r=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:z(z(n)),createdAt:typeof t.createdAt=="string"?t.createdAt:r,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:r,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function G(n,e){let t=L(n,ue);Be(t,{recursive:!0});let r=M(n),s=`${r}.tmp-${process.pid}`;Ue(s,JSON.stringify(e,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),We(s,r)}function P(n,e){return{id:n.id,name:n.name,remote:n.remote,rootPath:e,createdAt:n.createdAt,updatedAt:n.updatedAt,graphVersion:n.graphVersion,memoryVersion:n.memoryVersion,metadata:n.metadata}}function Z(n){return{version:1,scheme:j,canonicalRemote:n.canonicalRemote,fingerprint:n.fingerprint,repositoryName:n.repositoryName}}function Je(n){let e=n.metadata?.toolnetIdentity;if(!e||typeof e!="object"||Array.isArray(e))return null;let t=e;return typeof t.fingerprint=="string"?t.fingerprint:null}var B=class{adopt(e,t){let r=Q(A(e));if(!t.id.trim())throw new Error("PROJECT_ADOPTION_INVALID_ID");if(!t.name.trim())throw new Error("PROJECT_ADOPTION_INVALID_NAME");if(!t.remote.trim())throw new Error("PROJECT_ADOPTION_INVALID_REMOTE");if(me(r)){let a=$(M(r));if(a.id!==t.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${a.id}`,`requested=${t.id}`].join(" "));return P(a,r)}let s=new Date().toISOString(),o={...t.metadata};t.gitIdentity&&(o.toolnetIdentity=Z(t.gitIdentity));let i={version:1,id:t.id.trim(),name:t.name.trim(),remote:t.remote.trim(),rootPath:r,createdAt:t.createdAt??s,updatedAt:s,graphVersion:t.graphVersion??0,memoryVersion:t.memoryVersion??0,metadata:Object.keys(o).length?o:void 0};return G(r,i),P(i,r)}recordGitIdentity(e,t,r={}){let s=this.requireExisting(e),o=M(s.rootPath),i=$(o),a=Je(i);if(a&&a!==t.fingerprint&&!r.allowRebind)throw new Error(["PROJECT_GIT_REMOTE_CHANGED",`existing=${a}`,`current=${t.fingerprint}`,"Use explicit rebind only when this repository identity change is intentional."].join(" "));let u=i.metadata?.toolnetIdentity;return u&&typeof u=="object"&&!Array.isArray(u)&&u.fingerprint===t.fingerprint||(i.metadata={...i.metadata,toolnetIdentity:Z(t)},i.updatedAt=new Date().toISOString(),G(s.rootPath,i)),P(i,s.rootPath)}findExisting(e=process.cwd()){let t=A(e),r=Q(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>K(L(r,u))),i=de(t,o?r:void 0);if(!i)return null;let a=$(M(i));return P(a,i)}requireExisting(e=process.cwd()){let t=this.findExisting(e);if(!t)throw new Error("PROJECT_NOT_INITIALIZED");return t}detect(e=process.cwd()){let t=A(e),r=Q(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(f=>K(L(r,f))),i=de(t,o?r:void 0);if(i){let f=M(i),p=$(f);return p.rootPath!==i&&(p.rootPath=i,p.updatedAt=new Date().toISOString(),G(i,p)),P(p,i)}let a=new Date().toISOString(),u=Ve(r),c=le(r),l={version:1,id:c?ce(c.canonicalRemote):qe(r),name:u,remote:c?.repositoryName??u,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0,metadata:c?{toolnetIdentity:Z(c)}:void 0};return G(r,l),P(l,r)}};var Qe=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_-]{20,}\b/g,confidence:"exact"},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g,confidence:"exact"},{type:"aws_access_key",regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,confidence:"exact"},{type:"github_token",regex:/\b(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{40,255})\b/g,confidence:"exact"},{type:"stripe_secret_key",regex:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,confidence:"exact"},{type:"google_api_key",regex:/\bAIza[A-Za-z0-9_-]{30,}\b/g,confidence:"exact"},{type:"slack_token",regex:/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/g,confidence:"exact"},{type:"npm_token",regex:/\bnpm_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi,confidence:"high"},{type:"jwt",regex:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,confidence:"exact"},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,confidence:"exact"},{type:"password_assignment",regex:/\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^"' \t\r\n]{6,}["']?/gi,confidence:"high"},{type:"secret_assignment",regex:/\b(?:secret|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\s*[:=]\s*["']?[^"' \t\r\n]{8,}["']?/gi,confidence:"high"},{type:"cookie",regex:/\b(?:cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi,confidence:"high"},{type:"url_credentials",regex:/\bhttps?:\/\/[^:/@\s]+:[^/@\s]{4,}@[^/\s]+/gi,confidence:"high"}],Ze=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function fe(n){return n.normalize("NFKC").trim().toLowerCase()}function Xe(n){if(n.length===0)return 0;let e=new Map;for(let r of n)e.set(r,(e.get(r)??0)+1);let t=0;for(let r of e.values()){let s=r/n.length;t-=s*Math.log2(s)}return t}function et(n){return/^[a-f0-9]{32}$/iu.test(n)||/^[a-f0-9]{40}$/iu.test(n)||/^[a-f0-9]{64}$/iu.test(n)}function tt(n,e,t){let r=n.slice(Math.max(0,e-48),e),s=n.slice(t,Math.min(n.length,t+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${r} ${s}`)}function rt(n,e){return n.start<e.end&&e.start<n.end}function ge(n){return n.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var H=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let r=fe(t);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let o of Qe){let i=new RegExp(o.regex.source,o.regex.flags);for(let a of e.matchAll(i))a.index===void 0||!a[0]||this.allowed(a[0])||t.push({type:o.type,value:a[0],start:a.index,end:a.index+a[0].length,confidence:o.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let r=ge(t),s=[];for(let o of r)s.some(i=>rt(i,o))||s.push(o);return ge(s)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=fe(e);return Ze.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],r=/[A-Za-z0-9_+/=-]{32,160}/g;for(let s of e.matchAll(r)){if(s.index===void 0||!s[0])continue;let o=s[0];this.allowed(o)||et(o)||!/[A-Za-z]/u.test(o)||!/[0-9]/u.test(o)||tt(e,s.index,s.index+o.length)&&(Xe(o)<3.7||t.push({type:"high_entropy_secret",value:o,start:s.index,end:s.index+o.length,confidence:"heuristic"}))}return t}};var N=class{scanner;constructor(e={}){this.scanner=new H(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let r=e,s=[...t].sort((i,a)=>a.start-i.start),o=new Set;for(let i of s)o.add(i.type),r=r.slice(0,i.start)+`[REDACTED:${i.type}]`+r.slice(i.end);return{text:r,redacted:t.length,secretTypes:[...o].sort()}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[r,s]of Object.entries(e)){let o=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(o.includes("password")||o.includes("passwd")||o==="pwd"||o.includes("secret")||o.includes("token")||o.includes("cookie")||o.includes("authorization")||o.includes("apikey")||o.includes("accesskey")||o.includes("privatekey")||o.includes("clientsecret")||o.includes("credential")){t[r]="[REDACTED]";continue}t[r]=this.sanitizeValue(s)}return t}return e}};var vr=new N;import{lstat as it,readdir as at}from"node:fs/promises";import{extname as ct,join as lt,relative as dt,resolve as pt}from"node:path";import{basename as nt}from"node:path";var st=new Set([".env",".env.local",".env.production",".env.development","id_rsa","id_ed25519","credentials","credentials.json","service-account.json"]),ot=new Set([".pem",".key",".p12",".pfx"]);function he(n){let e=nt(n).toLowerCase();if(st.has(e))return!0;for(let t of ot)if(e.endsWith(t))return!0;return!1}var ut=2*1024*1024,mt=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".mts",".cts"]),ft=new Set(["node_modules",".git",".toolnet",".toolnet-memory","dist","build","out","coverage",".next",".nuxt",".cache",".parcel-cache",".turbo","vendor","target"]);function ye(n,e){if(!Number.isSafeInteger(n)||n<1)throw new Error(`${e} must be a positive integer`);return n}function Se(n){if(n?.aborted)throw new Error("Repository scan aborted")}function gt(n){let e=n.trim().toLowerCase();if(!e)throw new Error("Repository scan extension cannot be empty");return e.startsWith(".")?e:`.${e}`}function ht(n){let e=n.toLowerCase();return/\.min\.(?:js|mjs|cjs)$/u.test(e)||/\.bundle\.(?:js|mjs|cjs)$/u.test(e)}function yt(n){return n.replaceAll("\\","/")}async function be(n,e={}){let t=pt(n),r=e.maxFileBytes??ut;if(!Number.isSafeInteger(r)||r<1)throw new Error("maxFileBytes must be a positive integer");let s=e.maxFiles??Number.MAX_SAFE_INTEGER;ye(s,"maxFiles");let o=e.progressInterval??1e3;ye(o,"progressInterval");let i=new Set(e.extensions?[...e.extensions].map(gt):mt),a=new Set(ft);for(let f of e.extraIgnoredDirectories??[]){let p=f.trim();p&&a.add(p)}let u=[],c={directories:0,entries:0,accepted:0,skippedIgnoredDirectories:0,skippedSymlinks:0,skippedGenerated:0,skippedSensitive:0,skippedOversized:0,skippedUnreadable:0},l=[t];for(;l.length>0;){Se(e.signal);let f=l.pop(),p;try{p=await at(f,{withFileTypes:!0})}catch{c.skippedUnreadable+=1;continue}c.directories+=1;for(let h of p){Se(e.signal),c.entries+=1,c.entries%o===0&&e.onProgress?.({directories:c.directories,entries:c.entries,accepted:c.accepted});let C=lt(f,h.name);if(h.isSymbolicLink()){c.skippedSymlinks+=1;continue}if(h.isDirectory()){if(a.has(h.name)){c.skippedIgnoredDirectories+=1;continue}l.push(C);continue}if(!h.isFile())continue;let R=ct(h.name).toLowerCase();if(!i.has(R))continue;if(ht(h.name)){c.skippedGenerated+=1;continue}if(he(C)){c.skippedSensitive+=1;continue}let k;try{k=await it(C)}catch{c.skippedUnreadable+=1;continue}if(k.isSymbolicLink()){c.skippedSymlinks+=1;continue}if(k.isFile()){if(k.size>r){c.skippedOversized+=1;continue}if(u.length>=s)throw new Error(`Repository scan file limit exceeded: ${s}`);u.push(yt(dt(t,C))),c.accepted+=1}}}return u.sort(),e.onProgress?.({directories:c.directories,entries:c.entries,accepted:c.accepted}),{files:u,stats:c}}import{createHash as St}from"node:crypto";import{dirname as bt,extname as xt,normalize as Ct,posix as Et}from"node:path";var W=class{symbols=new Map;edges=new Map;addSymbol(e){this.symbols.set(e.id,e)}addEdge(e){this.edges.set(e.id,e)}getSymbol(e){return this.symbols.get(e)}findByName(e,t){return[...this.symbols.values()].filter(r=>r.projectId===e&&(r.name===t||r.qualifiedName===t))}allSymbols(e){return[...this.symbols.values()].filter(t=>t.projectId===e)}allEdges(e){return[...this.edges.values()].filter(t=>t.projectId===e)}import(e,t){for(let r of e)this.addSymbol(r);for(let r of t)this.addEdge(r)}clearProject(e){for(let[t,r]of this.symbols)r.projectId===e&&this.symbols.delete(t);for(let[t,r]of this.edges)r.projectId===e&&this.edges.delete(t)}};function wt(n,e,t,r){return St("sha256").update(`${n}:${e}:${t}:${r}`).digest("hex").slice(0,24)}function E(n){return Ct(n).replaceAll("\\","/")}function vt(n,e,t){if(!e.startsWith("."))return;let r=E(Et.join(bt(n),e)),s=xt(r),o;if(s===".js"){let i=r.slice(0,-3);o=[`${i}.ts`,`${i}.tsx`,`${i}.js`,`${i}.jsx`]}else if(s===".mjs"){let i=r.slice(0,-4);o=[`${i}.mts`,`${i}.ts`,`${i}.mjs`]}else if(s===".cjs"){let i=r.slice(0,-4);o=[`${i}.cts`,`${i}.ts`,`${i}.cjs`]}else s?o=[r]:o=[`${r}.ts`,`${r}.tsx`,`${r}.mts`,`${r}.cts`,`${r}.js`,`${r}.jsx`,`${r}.mjs`,`${r}.cjs`,`${r}/index.ts`,`${r}/index.tsx`,`${r}/index.mts`,`${r}/index.cts`,`${r}/index.js`,`${r}/index.jsx`,`${r}/index.mjs`,`${r}/index.cjs`];return o.find(i=>t.has(E(i)))}function X(n,e,t,r){let s=r?.(n,e,t);if(s){let o=E(s);if(t.has(o))return o}return vt(n,e,t)}var _=class{build(e,t,r={}){let s=new W;for(let a of r.seedSymbols??[])s.addSymbol(a);for(let a of t)for(let u of a.symbols)s.addSymbol(u);let o=new Map;for(let a of s.allSymbols(e))a.type==="file"&&o.set(E(a.filePath),a);let i=new Set(o.keys());for(let a of t){let u=E(a.filePath),c=o.get(u);if(c){for(let l of a.symbols)l.id!==c.id&&s.addEdge(this.edge(e,c.id,"DEFINES",l.id));for(let l of a.imports){let f=X(u,l.source,i,r.resolveModule);if(!f)continue;let p=o.get(f);p&&s.addEdge(this.edge(e,c.id,"IMPORTS",p.id,{source:l.source,resolvedFile:f}))}for(let l of a.heritage){let f=s.findByName(e,l.targetName).filter(p=>p.type==="class"||p.type==="interface");for(let p of f)s.addEdge(this.edge(e,l.fromId,l.type,p.id))}for(let l of a.calls){if(!l.callerId)continue;let f=this.resolveCallTargets(e,a,l.calleeName,l.qualifier,s,i,r.resolveModule);for(let p of f)p.id!==l.callerId&&s.addEdge(this.edge(e,l.callerId,"CALLS",p.id,{line:l.line,qualifier:l.qualifier}))}}}return s}resolveCallTargets(e,t,r,s,o,i,a){let u=E(t.filePath),c=o.findByName(e,r).filter(l=>E(l.filePath)===u);if(!s&&c.length)return c;if(s)for(let l of t.imports){if(!l.bindings.find(h=>h.kind==="namespace"&&h.localName===s))continue;let p=X(u,l.source,i,a);if(p)return o.findByName(e,r).filter(h=>E(h.filePath)===p)}for(let l of t.imports){let f=l.bindings.find(R=>R.localName===r);if(!f)continue;let p=X(u,l.source,i,a);if(!p)continue;let h=f.importedName==="default"?r:f.importedName,C=o.findByName(e,h).filter(R=>E(R.filePath)===p);if(C.length)return C}return o.findByName(e,r).filter(l=>l.type==="function"||l.type==="method")}edge(e,t,r,s,o){return{id:wt(e,t,r,s),projectId:e,from:t,to:s,type:r,metadata:o}}};import{readFile as Rt}from"node:fs/promises";import{join as kt}from"node:path";import{createHash as Pt}from"node:crypto";import*as m from"typescript";function xe(n,e){return Pt("sha256").update(`${n}:${e}`).digest("hex").slice(0,24)}function ee(n,e){return n.getLineAndCharacterOfPosition(e.getStart(n)).line+1}async function te(n,e,t){let r=kt(e,t),s=await Rt(r,"utf8"),o=m.createSourceFile(t,s,m.ScriptTarget.Latest,!0,t.endsWith(".tsx")||t.endsWith(".jsx")?m.ScriptKind.TSX:m.ScriptKind.TS),i=[],a=[],u=[],c=[],l={id:xe(n,`file:${t}`),projectId:n,name:t,qualifiedName:t,type:"file",filePath:t,startLine:1,endLine:o.getLineAndCharacterOfPosition(o.end).line+1};i.push(l);let f=[],p=[];function h(d,b,S,y){let w=xe(n,`${t}:${S}:${y??b}:${d.pos}`);return i.push({id:w,projectId:n,name:b,qualifiedName:y??b,type:S,filePath:t,startLine:ee(o,d),endLine:o.getLineAndCharacterOfPosition(d.end).line+1}),w}function C(d){if(!m.isStringLiteral(d.moduleSpecifier))return;let b=[],S=d.importClause;if(S?.name&&b.push({localName:S.name.text,importedName:"default",kind:"default"}),S?.namedBindings&&m.isNamedImports(S.namedBindings))for(let y of S.namedBindings.elements)b.push({localName:y.name.text,importedName:y.propertyName?.text??y.name.text,kind:"named"});S?.namedBindings&&m.isNamespaceImport(S.namedBindings)&&b.push({localName:S.namedBindings.name.text,importedName:"*",kind:"namespace"}),a.push({source:d.moduleSpecifier.text,bindings:b})}function R(d,b){for(let S of d.heritageClauses??[])for(let y of S.types){let w=y.expression.getText(o).split(".").at(-1)??"";w&&c.push({fromId:b,targetName:w,type:S.token===m.SyntaxKind.ExtendsKeyword?"INHERITS":"IMPLEMENTS"})}}function k(d){let b=!1,S=!1;if(m.isImportDeclaration(d)&&C(d),m.isInterfaceDeclaration(d)&&h(d,d.name.text,"interface",d.name.text),m.isClassDeclaration(d)&&d.name){let y=h(d,d.name.text,"class",d.name.text);R(d,y),p.push({id:y,name:d.name.text}),S=!0}if(m.isFunctionDeclaration(d)&&d.name){let y=h(d,d.name.text,"function",d.name.text);f.push(y),b=!0}if(m.isMethodDeclaration(d)&&d.name){let y=d.name.getText(o),w=p.at(-1)?.name,Me=h(d,y,"method",w?`${w}.${y}`:y);f.push(Me),b=!0}if(m.isCallExpression(d)&&(m.isIdentifier(d.expression)&&u.push({callerId:f.at(-1),calleeName:d.expression.text,line:ee(o,d)}),m.isPropertyAccessExpression(d.expression))){let y=d.expression;u.push({callerId:f.at(-1),qualifier:y.expression.getText(o),calleeName:y.name.text,line:ee(o,d)})}m.forEachChild(d,k),b&&f.pop(),S&&p.pop()}return k(o),{filePath:t,symbols:i,imports:a,calls:u,heritage:c}}function At(n){let e=n??4;if(!Number.isSafeInteger(e)||e<1||e>64)throw new Error("concurrency must be an integer between 1 and 64");return e}function Mt(n){if(n?.aborted)throw new Error("Operation aborted")}async function U(n,e,t={}){if(n.length===0)return[];let r=Math.min(At(t.concurrency),n.length),s=new Array(n.length),o=0,i=0,a=async()=>{for(;;){Mt(t.signal);let c=o;if(o+=1,c>=n.length)return;s[c]=await e(n[c],c),i+=1,t.onProgress?.({completed:i,total:n.length,index:c})}},u=Array.from({length:r},()=>a());return await Promise.all(u),s}var V=class{async index(e,t,r={}){let s={...r.scan};r.signal&&(s.signal=r.signal);let o=await be(t,s),i=o.files;r.onProgress?.({phase:"scan",current:i.length,total:i.length});let a=r.maxWarnings??20;if(!Number.isSafeInteger(a)||a<0)throw new Error("maxWarnings must be a non-negative integer");let u=0,c=await U(i,async p=>{try{return await te(e,t,p)}catch(h){return u+=1,u<=a&&console.warn(`[indexer] skipped ${p}:`,h instanceof Error?h.message:h),null}},{concurrency:r.concurrency??4,signal:r.signal,onProgress:({completed:p,total:h,index:C})=>{r.onProgress?.({phase:"parse",current:p,total:h,file:i[C]})}});u>a&&console.warn(`[indexer] ${u-a} additional parse warnings suppressed`);let l=c.filter(p=>p!==null),f=new _().build(e,l);return{files:l.length,symbols:f.allSymbols(e).length,edges:f.allEdges(e).length,parseFailures:u,scan:o.stats,graph:f}}};function Ee(n,e){let t=n.allSymbols(e),r=n.allEdges(e),s=i=>t.filter(a=>a.type===i).length,o=i=>r.filter(a=>a.type===i).length;return{files:s("file"),classes:s("class"),interfaces:s("interface"),functions:s("function"),methods:s("method"),properties:s("property"),routes:s("route"),symbols:t.length,edges:r.length,calls:o("CALLS"),callReferences:o("CALL_REFERENCE"),imports:o("IMPORTS"),inherits:o("INHERITS"),implements:o("IMPLEMENTS"),usesType:o("USES_TYPE"),tests:o("TESTS"),routeEdges:o("ROUTE"),writes:o("WRITES")}}import{execFile as Tt}from"node:child_process";import{promisify as It}from"node:util";var On=It(Tt);var O=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};import*as v from"typescript";import{DatabaseSync as Is}from"node:sqlite";import*as x from"typescript";import*as g from"typescript";var oo=new Set([g.SyntaxKind.EqualsToken,g.SyntaxKind.PlusEqualsToken,g.SyntaxKind.MinusEqualsToken,g.SyntaxKind.AsteriskEqualsToken,g.SyntaxKind.SlashEqualsToken,g.SyntaxKind.PercentEqualsToken,g.SyntaxKind.QuestionQuestionEqualsToken,g.SyntaxKind.AmpersandAmpersandEqualsToken,g.SyntaxKind.BarBarEqualsToken]);import{homedir as rr}from"node:os";import{join as nr}from"node:path";import{DeleteObjectCommand as Nt,GetObjectCommand as _t,HeadObjectCommand as Ot,ListObjectsV2Command as Ft,PutObjectCommand as Dt,S3Client as $t}from"@aws-sdk/client-s3";import{getSignedUrl as Gt}from"@aws-sdk/s3-request-presigner";var Y=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new $t({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Dt({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let t=await Gt(this.client,new _t({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(t,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`HF download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Ot({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new Nt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let s=await this.client.send(new Ft({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of s.Contents??[])o.Key&&t.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return t}};import{access as we,mkdir as Kt,readFile as zt,readdir as Bt,rm as Ht,stat as ve,writeFile as Wt}from"node:fs/promises";import{dirname as Ut,join as Vt,relative as Re,resolve as Yt}from"node:path";var F=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Yt(this.root,t)}async put(e,t){let r=this.path(e);await Kt(Ut(r),{recursive:!0}),await Wt(r,t)}async get(e){try{return await zt(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await we(this.path(e)),!0}catch{return!1}}async delete(e){await Ht(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await we(t)}catch{return r}let s=async i=>{let a=await Bt(i,{withFileTypes:!0});for(let u of a){let c=Vt(i,u.name);if(u.isDirectory()){await s(c);continue}let l=await ve(c);r.push({key:Re(this.root,c),size:l.size,updatedAt:l.mtime.toISOString()})}},o=await ve(t);return o.isDirectory()?await s(t):r.push({key:Re(this.root,t),size:o.size,updatedAt:o.mtime.toISOString()}),r}};import{DeleteObjectCommand as qt,GetObjectCommand as Jt,HeadObjectCommand as Qt,ListObjectsV2Command as Zt,PutObjectCommand as Xt,S3Client as er}from"@aws-sdk/client-s3";import{getSignedUrl as tr}from"@aws-sdk/s3-request-presigner";var D=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new er({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Xt({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let t=await tr(this.client,new Jt({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(t,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`${this.name} download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Qt({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new qt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let s=await this.client.send(new Zt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of s.Contents??[])o.Key&&t.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return t}};function re(n,e){return console.warn(e),new F(n)}function ke(n){let e=n.localRoot??nr(rr(),".toolnet-memory","storage");if(n.provider==="r2"){let t=n.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new D({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):re(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(n.provider==="s3"){let t=n.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new D({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):re(e,"[storage] S3 credentials missing. Using local fallback.")}if(n.provider==="huggingface"){let t=n.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new Y({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):re(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new F(e)}function Pe(n){let e=n.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function Ae(n){let e=n.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let s=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:e))}var q=class{constructor(e,t,r,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=Pe(s??r),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),r=t,s=await this.provider.getText(e);if(s){let i;try{i=JSON.parse(s)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:t};await this.provider.put(e,JSON.stringify(o,null,2)+`
|
|
4
|
+
`,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=Ae(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,r){return await this.ensureRegistered(),this.provider.put(this.key(e),t,r)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};async function sr(){let n=ne(),e=new B().detect(),t=ke({provider:n.storage.provider,huggingface:n.storage.huggingface,localRoot:n.storage.localRoot}),r=new q(t,e.id,e.name,e.remote??e.name),s=await new V().index(e.id,e.rootPath),o=Ee(s.graph,e.id);await new O(r).save({version:1,projectId:e.id,updatedAt:new Date().toISOString(),files:s.files,symbols:s.graph.allSymbols(e.id),edges:s.graph.allEdges(e.id)}),console.log({ok:!0,storage:r.name,...o})}sr().catch(n=>{console.error(n),process.exit(1)});
|
package/bundle/graph-ui.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import"dotenv/config";import{createReadStream as
|
|
2
|
-
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):t.length>=2&&t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function
|
|
3
|
-
`,{encoding:"utf8",mode:384}),Ie(a,r)}function X(s,t){return{id:s.id,name:s.name,remote:s.remote,rootPath:t,createdAt:s.createdAt,updatedAt:s.updatedAt,graphVersion:s.graphVersion,memoryVersion:s.memoryVersion,metadata:s.metadata}}var V=class{findExisting(t=process.cwd()){let e=T(t),r=ae(e),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(b=>H(O(r,b))),l=ie(e,o?r:void 0);if(!l)return null;let h=ce(U(l));return X(h,l)}requireExisting(t=process.cwd()){let e=this.findExisting(t);if(!e)throw new Error("PROJECT_NOT_INITIALIZED");return e}detect(t=process.cwd()){let e=T(t),r=ae(e),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(k=>H(O(r,k))),l=ie(e,o?r:void 0);if(l){let k=U(l),R=ce(k);return R.rootPath!==l&&(R.rootPath=l,R.updatedAt=new Date().toISOString(),le(l,R)),X(R,l)}let h=new Date().toISOString(),b=Oe(r),v={version:1,id:Fe(r),name:b,remote:b,rootPath:r,createdAt:h,updatedAt:h,graphVersion:0,memoryVersion:0};return le(r,v),X(v,r)}};var De=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_-]{20,}\b/g,confidence:"exact"},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g,confidence:"exact"},{type:"aws_access_key",regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,confidence:"exact"},{type:"github_token",regex:/\b(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{40,255})\b/g,confidence:"exact"},{type:"stripe_secret_key",regex:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,confidence:"exact"},{type:"google_api_key",regex:/\bAIza[A-Za-z0-9_-]{30,}\b/g,confidence:"exact"},{type:"slack_token",regex:/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/g,confidence:"exact"},{type:"npm_token",regex:/\bnpm_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi,confidence:"high"},{type:"jwt",regex:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,confidence:"exact"},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,confidence:"exact"},{type:"password_assignment",regex:/\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^"' \t\r\n]{6,}["']?/gi,confidence:"high"},{type:"secret_assignment",regex:/\b(?:secret|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\s*[:=]\s*["']?[^"' \t\r\n]{8,}["']?/gi,confidence:"high"},{type:"cookie",regex:/\b(?:cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi,confidence:"high"},{type:"url_credentials",regex:/\bhttps?:\/\/[^:/@\s]+:[^/@\s]{4,}@[^/\s]+/gi,confidence:"high"}],Ge=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function ue(s){return s.normalize("NFKC").trim().toLowerCase()}function Ke(s){if(s.length===0)return 0;let t=new Map;for(let r of s)t.set(r,(t.get(r)??0)+1);let e=0;for(let r of t.values()){let a=r/s.length;e-=a*Math.log2(a)}return e}function ze(s){return/^[a-f0-9]{32}$/iu.test(s)||/^[a-f0-9]{40}$/iu.test(s)||/^[a-f0-9]{64}$/iu.test(s)}function Be(s,t,e){let r=s.slice(Math.max(0,t-48),t),a=s.slice(e,Math.min(s.length,e+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${r} ${a}`)}function He(s,t){return s.start<t.end&&t.start<s.end}function fe(s){return s.sort((t,e)=>t.start!==e.start?t.start-e.start:e.end-e.start-(t.end-t.start))}var J=class{allowValues=new Set;enableEntropyHeuristic;constructor(t={}){for(let e of t.allowValues??[]){let r=ue(e);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=t.enableEntropyHeuristic??!0}scan(t){let e=[];for(let o of De){let l=new RegExp(o.regex.source,o.regex.flags);for(let h of t.matchAll(l))h.index===void 0||!h[0]||this.allowed(h[0])||e.push({type:o.type,value:h[0],start:h.index,end:h.index+h[0].length,confidence:o.confidence})}this.enableEntropyHeuristic&&e.push(...this.entropyMatches(t));let r=fe(e),a=[];for(let o of r)a.some(l=>He(l,o))||a.push(o);return fe(a)}hasSecrets(t){return this.scan(t).length>0}allowed(t){let e=ue(t);return Ge.has(e)?!0:this.allowValues.has(e)}entropyMatches(t){let e=[],r=/[A-Za-z0-9_+/=-]{32,160}/g;for(let a of t.matchAll(r)){if(a.index===void 0||!a[0])continue;let o=a[0];this.allowed(o)||ze(o)||!/[A-Za-z]/u.test(o)||!/[0-9]/u.test(o)||Be(t,a.index,a.index+o.length)&&(Ke(o)<3.7||e.push({type:"high_entropy_secret",value:o,start:a.index,end:a.index+o.length,confidence:"heuristic"}))}return e}};var _=class{scanner;constructor(t={}){this.scanner=new J(t)}sanitize(t){let e=this.scanner.scan(t);if(e.length===0)return{text:t,redacted:0,secretTypes:[]};let r=t,a=[...e].sort((l,h)=>h.start-l.start),o=new Set;for(let l of a)o.add(l.type),r=r.slice(0,l.start)+`[REDACTED:${l.type}]`+r.slice(l.end);return{text:r,redacted:e.length,secretTypes:[...o].sort()}}sanitizeValue(t){if(typeof t=="string")return this.sanitize(t).text;if(Array.isArray(t))return t.map(e=>this.sanitizeValue(e));if(t&&typeof t=="object"){let e={};for(let[r,a]of Object.entries(t)){let o=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(o.includes("password")||o.includes("passwd")||o==="pwd"||o.includes("secret")||o.includes("token")||o.includes("cookie")||o.includes("authorization")||o.includes("apikey")||o.includes("accesskey")||o.includes("privatekey")||o.includes("clientsecret")||o.includes("credential")){e[r]="[REDACTED]";continue}e[r]=this.sanitizeValue(a)}return e}return t}};var Ut=new _;var kr=2*1024*1024;var F=class{symbols=new Map;edges=new Map;addSymbol(t){this.symbols.set(t.id,t)}addEdge(t){this.edges.set(t.id,t)}getSymbol(t){return this.symbols.get(t)}findByName(t,e){return[...this.symbols.values()].filter(r=>r.projectId===t&&(r.name===e||r.qualifiedName===e))}allSymbols(t){return[...this.symbols.values()].filter(e=>e.projectId===t)}allEdges(t){return[...this.edges.values()].filter(e=>e.projectId===t)}import(t,e){for(let r of t)this.addSymbol(r);for(let r of e)this.addEdge(r)}clearProject(t){for(let[e,r]of this.symbols)r.projectId===t&&this.symbols.delete(e);for(let[e,r]of this.edges)r.projectId===t&&this.edges.delete(e)}};import*as E from"typescript";import{execFile as Je}from"node:child_process";import{promisify as Ye}from"node:util";var Jr=Ye(Je);import*as j from"typescript";import{DatabaseSync as Hs}from"node:sqlite";import*as P from"typescript";import*as f from"typescript";var fn=new Set([f.SyntaxKind.EqualsToken,f.SyntaxKind.PlusEqualsToken,f.SyntaxKind.MinusEqualsToken,f.SyntaxKind.AsteriskEqualsToken,f.SyntaxKind.SlashEqualsToken,f.SyntaxKind.PercentEqualsToken,f.SyntaxKind.QuestionQuestionEqualsToken,f.SyntaxKind.AmpersandAmpersandEqualsToken,f.SyntaxKind.BarBarEqualsToken]);var Y=class{constructor(t){this.graph=t}graph;build(t,e,r,a){let o=this.graph.allSymbols(t),l=this.graph.allEdges(t),h=new Map(e?.layers.map(i=>[i.filePath,i.layer])??[]),b=new Map;for(let i of e?.clusters??[])for(let n of i.files)b.set(n,{id:i.id,label:i.label});let v=new Map(e?.hotspots.map(i=>[i.filePath,i.score])??[]),k=new Map(r?.deadCode.map(i=>[i.symbolId,{confidence:i.confidence,score:i.score}])??[]),R=new Map,N=new Map;for(let i of l)N.set(i.from,(N.get(i.from)??0)+1),R.set(i.to,(R.get(i.to)??0)+1);let A=[];for(let i=0;i<o.length;i++){let n=o[i],d=b.get(n.filePath);A.push({id:n.id,name:n.name,qualifiedName:n.qualifiedName,type:n.type,filePath:n.filePath,layer:h.get(n.filePath),cluster:d?.id,clusterLabel:d?.label,hotspotScore:v.get(n.filePath),deadCode:k.get(n.id),incoming:R.get(n.id)??0,outgoing:N.get(n.id)??0}),((i+1)%100===0||i===o.length-1)&&a?.({current:i+1,total:o.length,phase:"nodes"})}let K=new Set(A.map(i=>i.id)),M=l.filter(i=>K.has(i.from)&&K.has(i.to)),z=[];for(let i=0;i<M.length;i++){let n=M[i];z.push({source:n.from,target:n.to,type:n.type,confidence:typeof n.metadata?.confidence=="string"?n.metadata.confidence:void 0,resolver:typeof n.metadata?.resolver=="string"?n.metadata.resolver:void 0}),((i+1)%100===0||i===M.length-1)&&a?.({current:i+1,total:M.length,phase:"links"})}return{version:1,projectId:t,generatedAt:new Date().toISOString(),summary:{nodes:A.length,links:z.length,files:new Set(A.map(i=>i.filePath)).size,clusters:new Set(A.map(i=>i.cluster).filter(Boolean)).size},nodes:A,links:z}}};import{homedir as xt}from"node:os";import{join as Ct}from"node:path";import{DeleteObjectCommand as Qe,GetObjectCommand as Xe,HeadObjectCommand as et,ListObjectsV2Command as tt,PutObjectCommand as rt,S3Client as st}from"@aws-sdk/client-s3";import{getSignedUrl as nt}from"@aws-sdk/s3-request-presigner";var q=class{name="huggingface";client;bucket;constructor(t){this.bucket=t.bucket,this.client=new st({region:"us-east-1",endpoint:`https://s3.hf.co/${t.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,r="application/octet-stream"){let a=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new rt({Bucket:this.bucket,Key:t,Body:a,ContentType:r}))}async get(t){let e=await nt(this.client,new Xe({Bucket:this.bucket,Key:t}),{expiresIn:60}),r=await fetch(e,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`HF download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new et({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new Qe({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],r;do{let a=await this.client.send(new tt({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:r}));for(let o of a.Contents??[])o.Key&&e.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=a.IsTruncated?a.NextContinuationToken:void 0}while(r);return e}};import{access as ge,mkdir as ot,readFile as it,readdir as at,rm as ct,stat as he,writeFile as lt}from"node:fs/promises";import{dirname as dt,join as pt,relative as ye,resolve as ut}from"node:path";var $=class{constructor(t){this.root=t}root;name="local";path(t){let e=t.replace(/^\/+/,"");return ut(this.root,e)}async put(t,e){let r=this.path(t);await ot(dt(r),{recursive:!0}),await lt(r,e)}async get(t){try{return await it(this.path(t))}catch(e){if(typeof e=="object"&&e!==null&&"code"in e&&e.code==="ENOENT")return null;throw e}}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await ge(this.path(t)),!0}catch{return!1}}async delete(t){await ct(this.path(t),{force:!0})}async list(t=""){let e=this.path(t),r=[];try{await ge(e)}catch{return r}let a=async l=>{let h=await at(l,{withFileTypes:!0});for(let b of h){let v=pt(l,b.name);if(b.isDirectory()){await a(v);continue}let k=await he(v);r.push({key:ye(this.root,v),size:k.size,updatedAt:k.mtime.toISOString()})}},o=await he(e);return o.isDirectory()?await a(e):r.push({key:ye(this.root,e),size:o.size,updatedAt:o.mtime.toISOString()}),r}};import{DeleteObjectCommand as ft,GetObjectCommand as mt,HeadObjectCommand as gt,ListObjectsV2Command as ht,PutObjectCommand as yt,S3Client as St}from"@aws-sdk/client-s3";import{getSignedUrl as bt}from"@aws-sdk/s3-request-presigner";var D=class{name;client;bucket;constructor(t){this.name=t.name??"s3",this.bucket=t.bucket,this.client=new St({region:t.region??"us-east-1",endpoint:t.endpoint||void 0,forcePathStyle:t.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,r="application/octet-stream"){let a=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new yt({Bucket:this.bucket,Key:t,Body:a,ContentType:r}))}async get(t){let e=await bt(this.client,new mt({Bucket:this.bucket,Key:t}),{expiresIn:60}),r=await fetch(e,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`${this.name} download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new gt({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new ft({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],r;do{let a=await this.client.send(new ht({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:r}));for(let o of a.Contents??[])o.Key&&e.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=a.IsTruncated?a.NextContinuationToken:void 0}while(r);return e}};function ee(s,t){return console.warn(t),new $(s)}function Se(s){let t=s.localRoot??Ct(xt(),".toolnet-memory","storage");if(s.provider==="r2"){let e=s.r2;return e?.accountId&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new D({name:"r2",endpoint:`https://${e.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:e.bucket,forcePathStyle:!0,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):ee(t,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(s.provider==="s3"){let e=s.s3;return e?.bucket&&e.accessKeyId&&e.secretAccessKey?new D({name:"s3",endpoint:e.endpoint,region:e.region??"us-east-1",bucket:e.bucket,forcePathStyle:e.forcePathStyle??!1,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):ee(t,"[storage] S3 credentials missing. Using local fallback.")}if(s.provider==="huggingface"){let e=s.huggingface;return e?.namespace&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new q({namespace:e.namespace,bucket:e.bucket,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):ee(t,"[storage] Hugging Face credentials missing. Using local fallback.")}return new $(t)}function wt(s){return new Promise(t=>setTimeout(t,s))}async function be(s,t={}){let e=Math.max(1,t.attempts??3),r=t.baseDelayMs??150,a=t.maxDelayMs??2e3,o;for(let l=1;l<=e;l++)try{return await s()}catch(h){if(o=h,l>=e)break;let b=Math.min(a,r*2**(l-1)),v=Math.floor(Math.random()*Math.max(1,b*.2));await wt(b+v)}throw o}var Et=new Set(["put","get","getText","delete","list"]);function xe(s,t={}){return new Proxy(s,{get(e,r){let a=Reflect.get(e,r,e);return typeof a!="function"?a:Et.has(r)?(...o)=>be(()=>Promise.resolve(a.apply(e,o)),t):a.bind(e)}})}var we=Number(process.env.TOOLNET_GRAPH_PORT??9749),Ee=process.env.TOOLNET_GRAPH_HOST??"127.0.0.1";function Rt(s){if(typeof s=="string")return s;if(!s||typeof s!="object")return null;let t=s;for(let e of["key","Key","path","name"])if(typeof t[e]=="string")return t[e];return null}async function At(s,t){return(await s.list(t)).map(Rt).filter(r=>!!r)}async function G(s,t){let e=await s.getText(t);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async function jt(s){let t=await At(s,"projects/"),e=[...new Set(t.filter(o=>/^projects\/[^/]+\/project\.json$/.test(o)).map(o=>o.split("/")[1]))],r=new Set(t),a=[];for(let o of e){let l=await G(s,`projects/${o}/project.json`);!l||typeof l.id!="string"||a.push({id:l.id,name:typeof l.name=="string"?l.name:o,remote:o,hasGraph:r.has(`projects/${o}/code/graph/current.json`),hasArchitecture:r.has(`projects/${o}/code/architecture/current.json`),hasAnalysis:r.has(`projects/${o}/code/analysis/current.json`),hasVisualization:r.has(`projects/${o}/code/visualization/graph.json`)})}return a.sort((o,l)=>o.name.localeCompare(l.name))}async function Mt(){let s=oe(),t=new V().detect(),e=xe(Se({provider:s.storage.provider,huggingface:s.storage.huggingface,localRoot:s.storage.localRoot}),{attempts:3});e.name!=="huggingface"&&console.warn("[graph-ui] Remote Hugging Face storage is not active.");let r=kt(Pt(import.meta.url)),a=te(r,"public"),o=te(a,"vendor","3d-force-graph.min.js");async function l(){let i=await jt(e),n=t.remote??t.name,d=i.find(m=>m.remote===n&&m.hasGraph),x=i.find(m=>m.hasGraph);return{projects:i,defaultProject:d?.remote??x?.remote??null}}let h=new Map;function b(i){return String(typeof i=="object"&&i!==null?i.id:i)}function v(i){return i.clusterLabel||i.cluster||i.layer||"Unclustered"}function k(i,n={}){return{id:i.id,name:i.name,remote:i.remote,hasArchitecture:i.hasArchitecture,hasAnalysis:i.hasAnalysis,...n}}async function R(i){let n=`projects/${i.remote}`,d=await G(e,`${n}/code/graph/current.json`);if(!d||!Array.isArray(d.symbols)||!Array.isArray(d.edges))throw new Error(`Code graph missing for project ${i.name}`);let x=await G(e,`${n}/code/architecture/current.json`),m=await G(e,`${n}/code/analysis/current.json`),S=new F;S.import(d.symbols,d.edges);let C=new Y(S).build(i.id,x,m);return await e.put(`${n}/code/visualization/graph.json`,JSON.stringify(C),"application/json"),{...C,dashboard:k(i)}}async function N(i,n=!1){n&&h.delete(i.remote);let d=h.get(i.remote);if(d)return d;let x=`projects/${i.remote}`,m=await G(e,`${x}/code/visualization/graph.json`);if(m&&Array.isArray(m.nodes)&&Array.isArray(m.links)){let C={...m,dashboard:k(i)};return h.set(i.remote,C),C}let S=await R(i);return h.set(i.remote,S),S}function A(i,n){let d=new Map,x=new Map;for(let p of n.nodes){let u=v(p),g=`cluster:${u}`;x.set(p.id,g);let c=d.get(g);c||(c={id:g,name:u,qualifiedName:u,type:"subsystem",filePath:"",clusterLabel:u,incoming:0,outgoing:0,memberCount:0,files:new Set,viewKind:"cluster"},d.set(g,c)),c.memberCount+=1,p.filePath&&c.files.add(p.filePath)}let m=new Map;for(let p of n.links){let u=x.get(b(p.source)),g=x.get(b(p.target));if(!u||!g||u===g)continue;let c=`${u}\0${g}`,y=m.get(c);y||(y={source:u,target:g,type:"SUBSYSTEM_DEPENDENCY",count:0},m.set(c,y)),y.count+=1}for(let p of m.values()){let u=d.get(p.source),g=d.get(p.target);u&&(u.outgoing+=p.count),g&&(g.incoming+=p.count)}let S=[...d.values()].map(p=>({...p,filePath:`${p.files.size} files \xB7 ${p.memberCount} symbols`,files:void 0})),C=[...m.values()];return{version:2,projectId:n.projectId,generatedAt:n.generatedAt,summary:{nodes:S.length,links:C.length,files:n.summary?.files??0,clusters:S.length},nodes:S,links:C,dashboard:k(i,{viewMode:"overview",totalNodes:n.nodes.length,totalLinks:n.links.length})}}function K(i,n,d){let x=n.nodes.filter(c=>!d||v(c)===d),m=new Set(x.map(c=>c.id)),S=new Map,C=new Map;for(let c of x){let y=c.filePath||"(unknown)";S.set(c.id,y);let w=C.get(y);w||(w={id:`file:${y}`,name:y.split("/").pop()||y,qualifiedName:y,type:"file",filePath:y,clusterLabel:v(c),incoming:0,outgoing:0,memberCount:0,viewKind:"file"},C.set(y,w)),w.memberCount+=1}let p=new Map;for(let c of n.links){let y=b(c.source),w=b(c.target);if(!m.has(y)||!m.has(w))continue;let Z=S.get(y),Q=S.get(w);if(!Z||!Q||Z===Q)continue;let re=`file:${Z}`,se=`file:${Q}`,ne=`${re}\0${se}`,B=p.get(ne);B||(B={source:re,target:se,type:"FILE_DEPENDENCY",count:0},p.set(ne,B)),B.count+=1}for(let c of p.values()){let y=C.get(String(c.source).slice(5)),w=C.get(String(c.target).slice(5));y&&(y.outgoing+=c.count),w&&(w.incoming+=c.count)}let u=[...C.values()],g=[...p.values()];return{version:2,projectId:n.projectId,generatedAt:n.generatedAt,summary:{nodes:u.length,links:g.length,files:u.length,clusters:d?1:0},nodes:u,links:g,dashboard:k(i,{viewMode:"files",selection:d,totalNodes:n.nodes.length,totalLinks:n.links.length})}}function M(i,n,d){let S=n.nodes.filter(c=>c.filePath===d),C=new Set(S.map(c=>c.id)),p=new Set;for(let c of S.slice(0,1800))p.add(c.id);for(let c of n.links){if(p.size>=1800)break;let y=b(c.source),w=b(c.target);(C.has(y)||C.has(w))&&(p.add(y),p.size<1800&&p.add(w))}let u=n.nodes.filter(c=>p.has(c.id)).map(c=>({...c,viewKind:"symbol"})),g=[];for(let c of n.links){if(g.length>=12e3)break;let y=b(c.source),w=b(c.target);p.has(y)&&p.has(w)&&g.push({...c,source:y,target:w})}return{version:2,projectId:n.projectId,generatedAt:n.generatedAt,summary:{nodes:u.length,links:g.length,files:new Set(u.map(c=>c.filePath)).size,clusters:new Set(u.map(c=>v(c))).size},nodes:u,links:g,dashboard:k(i,{viewMode:"symbols",selection:d,focused:!0,truncated:u.length>=1800||g.length>=12e3,totalNodes:n.nodes.length,totalLinks:n.links.length})}}vt(async(i,n)=>{try{let d=new URL(i.url??"/",`http://${i.headers.host??"localhost"}`);if(d.pathname==="/api/health"){let x=await l();n.setHeader("content-type","application/json; charset=utf-8"),n.setHeader("cache-control","no-store"),n.end(JSON.stringify({ok:!0,mode:"multi-project",projects:x.projects.length,indexedProjects:x.projects.filter(m=>m.hasGraph).length,defaultProject:x.defaultProject}));return}if(d.pathname==="/api/projects"){let x=await l();n.setHeader("content-type","application/json; charset=utf-8"),n.setHeader("cache-control","no-store"),n.end(JSON.stringify(x));return}if(d.pathname==="/api/graph"){let x=await l(),m=d.searchParams.get("project")??x.defaultProject;if(!m){n.statusCode=404,n.setHeader("content-type","application/json; charset=utf-8"),n.end(JSON.stringify({error:"No indexed ToolNet project found."}));return}let S=x.projects.find(c=>c.remote===m);if(!S){n.statusCode=404,n.setHeader("content-type","application/json; charset=utf-8"),n.end(JSON.stringify({error:"Project not found.",project:m}));return}if(!S.hasGraph){n.statusCode=409,n.setHeader("content-type","application/json; charset=utf-8"),n.end(JSON.stringify({error:"Project is registered but has not been indexed yet.",project:S}));return}let C=d.searchParams.get("refresh")==="1",p=await N(S,C),u=d.searchParams.get("mode")??"full",g=p;if(u==="overview")g=A(S,p);else if(u==="files")g=K(S,p,d.searchParams.get("cluster")??"");else if(u==="symbols"){let c=d.searchParams.get("file");if(!c){n.statusCode=400,n.setHeader("content-type","application/json; charset=utf-8"),n.end(JSON.stringify({error:"file is required for symbols mode."}));return}g=M(S,p,c)}else if(u!=="full"){n.statusCode=400,n.setHeader("content-type","application/json; charset=utf-8"),n.end(JSON.stringify({error:`Unknown graph mode: ${u}`}));return}n.setHeader("content-type","application/json; charset=utf-8"),n.setHeader("cache-control","no-store"),n.end(JSON.stringify(g));return}if(d.pathname==="/vendor/3d-force-graph.min.js"){n.setHeader("content-type","application/javascript; charset=utf-8"),Ce(o).pipe(n);return}if(d.pathname==="/"||d.pathname==="/index.html"){n.setHeader("content-type","text/html; charset=utf-8"),n.setHeader("cache-control","no-store"),Ce(te(a,"index.html")).pipe(n);return}n.statusCode=404,n.end("Not found")}catch(d){console.error(d),n.statusCode=500,n.setHeader("content-type","application/json; charset=utf-8"),n.end(JSON.stringify({error:d instanceof Error?d.message:String(d)}))}}).listen(we,Ee,()=>{console.log("ToolNet Multi-Project 3D Graph"),console.log(`Listening: http://${Ee}:${we}`)})}Mt().catch(s=>{console.error(s),process.exit(1)});
|
|
1
|
+
import"dotenv/config";import{createReadStream as je}from"node:fs";import{createServer as Gt}from"node:http";import{dirname as Kt,resolve as ae}from"node:path";import{fileURLToPath as zt}from"node:url";import{existsSync as Le,readFileSync as Oe}from"node:fs";import{homedir as _e}from"node:os";import{join as De}from"node:path";function Fe(n){let t=n.trim();return t.length>=2&&t.startsWith('"')&&t.endsWith('"')?(t=t.slice(1,-1),t.replace(/\\n/g,`
|
|
2
|
+
`).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):t.length>=2&&t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function $e(){let n=process.env.TOOLNET_GLOBAL_ENV??De(_e(),".config","toolnet-memory",".env");if(!Le(n))return;let t=Oe(n,"utf8");for(let e of t.split(/\r?\n/)){let r=e.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let i=r.indexOf("=");if(i<=0)continue;let s=r.slice(0,i).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=Fe(r.slice(i+1)))}}$e();function O(n,t){return n===void 0?t:["1","true","yes","on"].includes(n.toLowerCase())}function _(n,t){if(!n)return t;let e=Number(n);return Number.isFinite(e)?e:t}function pe(){return{memory:{autoCapture:O(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:O(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:O(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:O(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:_(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:_(process.env.MEMORY_RERANK_TOP,10),finalContext:_(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:_(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",r2:{accountId:process.env.R2_ACCOUNT_ID,bucket:process.env.R2_BUCKET,accessKeyId:process.env.R2_ACCESS_KEY_ID,secretAccessKey:process.env.R2_SECRET_ACCESS_KEY},s3:{endpoint:process.env.S3_ENDPOINT,region:process.env.S3_REGION,bucket:process.env.S3_BUCKET,accessKeyId:process.env.S3_ACCESS_KEY_ID,secretAccessKey:process.env.S3_SECRET_ACCESS_KEY,forcePathStyle:O(process.env.S3_FORCE_PATH_STYLE,!1)},huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:_(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Ue}from"node:crypto";import{existsSync as J,mkdirSync as Ve,readFileSync as Ye,renameSync as Je,writeFileSync as qe}from"node:fs";import{basename as Qe,dirname as q,join as F,parse as be,resolve as I}from"node:path";import{createHash as me}from"node:crypto";import{spawnSync as Ge}from"node:child_process";var D="git-remote-v1",Ke=new Set(["github.com","gitlab.com","bitbucket.org"]);function ge(n,t){let e=t.replaceAll("\\","/").replace(/^\/+/u,"").replace(/\/+$/u,"").replace(/\.git$/iu,"").replace(/\/+/gu,"/");return!e||e==="."||e===".."||e.split("/").some(r=>!r||r==="."||r==="..")?null:(Ke.has(n)&&(e=e.toLowerCase()),e)}function ze(n){let t;try{t=new URL(n)}catch{return null}if(!["https:","http:","ssh:","git:"].includes(t.protocol))return null;let e=t.hostname.trim().toLowerCase();if(!e)return null;let r=t.protocol==="https:"&&t.port==="443"||t.protocol==="http:"&&t.port==="80"||t.protocol==="ssh:"&&t.port==="22",i=t.port&&!r?`${e}:${t.port}`:e,s=ge(e,t.pathname);return s?`${i}/${s}`:null}function Be(n){let t=n.match(/^(?:[^@\s/:]+@)?([^:/\s]+):(.+)$/u);if(!t)return null;let e=t[1]?.trim().toLowerCase();if(!e||e.length===1)return null;let r=ge(e,t[2]??"");return r?`${e}/${r}`:null}function ue(n){let t=n.trim();return t?t.includes("://")?ze(t):Be(t):null}function He(n){return me("sha256").update(`${D}:${n}`).digest("hex")}function he(n){return me("sha256").update(`toolnet-project:${D}:${n}`).digest("hex").slice(0,16)}function We(n){return n.split("/").filter(Boolean).at(-1)?.trim()||null}function ne(n,t){let e=Ge("git",["-C",n,...t],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return e.error||e.status!==0?null:e.stdout?.trim()||null}function fe(n,t){let e=We(n);return e?{scheme:D,canonicalRemote:n,fingerprint:He(n),repositoryName:e,source:t}:null}function ye(n){let t=ne(n,["remote","get-url","origin"]);if(t){let i=ue(t);if(i)return fe(i,"origin")}let e=ne(n,["remote"]);if(!e)return null;let r=new Set;for(let i of e.split(/\r?\n/u).map(s=>s.trim()).filter(Boolean)){let s=ne(n,["remote","get-url",i]);if(!s)continue;let c=ue(s);c&&r.add(c)}return r.size!==1?null:fe([...r][0],"unique-remote")}var xe=".toolnet",Ze="project.json";function Xe(n){return Ue("sha256").update(n).digest("hex").slice(0,16)}function L(n){return F(n,xe,Ze)}function Ce(n){return J(L(n))}function Se(n,t){let e=I(n),r=be(e).root;for(;;){if(Ce(e))return e;if(e===r||t&&e===I(t))break;let i=q(e);if(i===e)break;e=i}return null}function se(n){let t=I(n),e=be(t).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(s=>J(F(t,s))))return t;if(t===e)break;let i=q(t);if(i===t)break;t=i}return I(n)}function V(n){let t;try{t=JSON.parse(Ye(n,"utf8"))}catch(i){throw new Error(`Invalid ToolNet project manifest: ${n}: ${i instanceof Error?i.message:String(i)}`)}if(!t||typeof t!="object")throw new Error(`Invalid ToolNet project manifest: ${n}`);let e=t;if(typeof e.id!="string"||!e.id.trim())throw new Error(`ToolNet project manifest is missing id: ${n}`);if(typeof e.name!="string"||!e.name.trim())throw new Error(`ToolNet project manifest is missing name: ${n}`);let r=new Date().toISOString();return{version:1,id:e.id,name:e.name,remote:typeof e.remote=="string"&&e.remote.trim()?e.remote:e.name,rootPath:typeof e.rootPath=="string"?e.rootPath:q(q(n)),createdAt:typeof e.createdAt=="string"?e.createdAt:r,updatedAt:typeof e.updatedAt=="string"?e.updatedAt:r,graphVersion:typeof e.graphVersion=="number"?e.graphVersion:0,memoryVersion:typeof e.memoryVersion=="number"?e.memoryVersion:0,metadata:e.metadata&&typeof e.metadata=="object"?e.metadata:void 0}}function Y(n,t){let e=F(n,xe);Ve(e,{recursive:!0});let r=L(n),i=`${r}.tmp-${process.pid}`;qe(i,JSON.stringify(t,null,2)+`
|
|
3
|
+
`,{encoding:"utf8",mode:384}),Je(i,r)}function j(n,t){return{id:n.id,name:n.name,remote:n.remote,rootPath:t,createdAt:n.createdAt,updatedAt:n.updatedAt,graphVersion:n.graphVersion,memoryVersion:n.memoryVersion,metadata:n.metadata}}function oe(n){return{version:1,scheme:D,canonicalRemote:n.canonicalRemote,fingerprint:n.fingerprint,repositoryName:n.repositoryName}}function et(n){let t=n.metadata?.toolnetIdentity;if(!t||typeof t!="object"||Array.isArray(t))return null;let e=t;return typeof e.fingerprint=="string"?e.fingerprint:null}var Q=class{adopt(t,e){let r=se(I(t));if(!e.id.trim())throw new Error("PROJECT_ADOPTION_INVALID_ID");if(!e.name.trim())throw new Error("PROJECT_ADOPTION_INVALID_NAME");if(!e.remote.trim())throw new Error("PROJECT_ADOPTION_INVALID_REMOTE");if(Ce(r)){let u=V(L(r));if(u.id!==e.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${u.id}`,`requested=${e.id}`].join(" "));return j(u,r)}let i=new Date().toISOString(),s={...e.metadata};e.gitIdentity&&(s.toolnetIdentity=oe(e.gitIdentity));let c={version:1,id:e.id.trim(),name:e.name.trim(),remote:e.remote.trim(),rootPath:r,createdAt:e.createdAt??i,updatedAt:i,graphVersion:e.graphVersion??0,memoryVersion:e.memoryVersion??0,metadata:Object.keys(s).length?s:void 0};return Y(r,c),j(c,r)}recordGitIdentity(t,e,r={}){let i=this.requireExisting(t),s=L(i.rootPath),c=V(s),u=et(c);if(u&&u!==e.fingerprint&&!r.allowRebind)throw new Error(["PROJECT_GIT_REMOTE_CHANGED",`existing=${u}`,`current=${e.fingerprint}`,"Use explicit rebind only when this repository identity change is intentional."].join(" "));let g=c.metadata?.toolnetIdentity;return g&&typeof g=="object"&&!Array.isArray(g)&&g.fingerprint===e.fingerprint||(c.metadata={...c.metadata,toolnetIdentity:oe(e)},c.updatedAt=new Date().toISOString(),Y(i.rootPath,c)),j(c,i.rootPath)}findExisting(t=process.cwd()){let e=I(t),r=se(e),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(g=>J(F(r,g))),c=Se(e,s?r:void 0);if(!c)return null;let u=V(L(c));return j(u,c)}requireExisting(t=process.cwd()){let e=this.findExisting(t);if(!e)throw new Error("PROJECT_NOT_INITIALIZED");return e}detect(t=process.cwd()){let e=I(t),r=se(e),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(A=>J(F(r,A))),c=Se(e,s?r:void 0);if(c){let A=L(c),R=V(A);return R.rootPath!==c&&(R.rootPath=c,R.updatedAt=new Date().toISOString(),Y(c,R)),j(R,c)}let u=new Date().toISOString(),g=Qe(r),E=ye(r),P={version:1,id:E?he(E.canonicalRemote):Xe(r),name:g,remote:E?.repositoryName??g,rootPath:r,createdAt:u,updatedAt:u,graphVersion:0,memoryVersion:0,metadata:E?{toolnetIdentity:oe(E)}:void 0};return Y(r,P),j(P,r)}};var tt=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_-]{20,}\b/g,confidence:"exact"},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g,confidence:"exact"},{type:"aws_access_key",regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,confidence:"exact"},{type:"github_token",regex:/\b(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{40,255})\b/g,confidence:"exact"},{type:"stripe_secret_key",regex:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,confidence:"exact"},{type:"google_api_key",regex:/\bAIza[A-Za-z0-9_-]{30,}\b/g,confidence:"exact"},{type:"slack_token",regex:/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/g,confidence:"exact"},{type:"npm_token",regex:/\bnpm_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi,confidence:"high"},{type:"jwt",regex:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,confidence:"exact"},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,confidence:"exact"},{type:"password_assignment",regex:/\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^"' \t\r\n]{6,}["']?/gi,confidence:"high"},{type:"secret_assignment",regex:/\b(?:secret|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\s*[:=]\s*["']?[^"' \t\r\n]{8,}["']?/gi,confidence:"high"},{type:"cookie",regex:/\b(?:cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi,confidence:"high"},{type:"url_credentials",regex:/\bhttps?:\/\/[^:/@\s]+:[^/@\s]{4,}@[^/\s]+/gi,confidence:"high"}],rt=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function Ee(n){return n.normalize("NFKC").trim().toLowerCase()}function nt(n){if(n.length===0)return 0;let t=new Map;for(let r of n)t.set(r,(t.get(r)??0)+1);let e=0;for(let r of t.values()){let i=r/n.length;e-=i*Math.log2(i)}return e}function st(n){return/^[a-f0-9]{32}$/iu.test(n)||/^[a-f0-9]{40}$/iu.test(n)||/^[a-f0-9]{64}$/iu.test(n)}function ot(n,t,e){let r=n.slice(Math.max(0,t-48),t),i=n.slice(e,Math.min(n.length,e+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${r} ${i}`)}function it(n,t){return n.start<t.end&&t.start<n.end}function we(n){return n.sort((t,e)=>t.start!==e.start?t.start-e.start:e.end-e.start-(t.end-t.start))}var Z=class{allowValues=new Set;enableEntropyHeuristic;constructor(t={}){for(let e of t.allowValues??[]){let r=Ee(e);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=t.enableEntropyHeuristic??!0}scan(t){let e=[];for(let s of tt){let c=new RegExp(s.regex.source,s.regex.flags);for(let u of t.matchAll(c))u.index===void 0||!u[0]||this.allowed(u[0])||e.push({type:s.type,value:u[0],start:u.index,end:u.index+u[0].length,confidence:s.confidence})}this.enableEntropyHeuristic&&e.push(...this.entropyMatches(t));let r=we(e),i=[];for(let s of r)i.some(c=>it(c,s))||i.push(s);return we(i)}hasSecrets(t){return this.scan(t).length>0}allowed(t){let e=Ee(t);return rt.has(e)?!0:this.allowValues.has(e)}entropyMatches(t){let e=[],r=/[A-Za-z0-9_+/=-]{32,160}/g;for(let i of t.matchAll(r)){if(i.index===void 0||!i[0])continue;let s=i[0];this.allowed(s)||st(s)||!/[A-Za-z]/u.test(s)||!/[0-9]/u.test(s)||ot(t,i.index,i.index+s.length)&&(nt(s)<3.7||e.push({type:"high_entropy_secret",value:s,start:i.index,end:i.index+s.length,confidence:"heuristic"}))}return e}};var $=class{scanner;constructor(t={}){this.scanner=new Z(t)}sanitize(t){let e=this.scanner.scan(t);if(e.length===0)return{text:t,redacted:0,secretTypes:[]};let r=t,i=[...e].sort((c,u)=>u.start-c.start),s=new Set;for(let c of i)s.add(c.type),r=r.slice(0,c.start)+`[REDACTED:${c.type}]`+r.slice(c.end);return{text:r,redacted:e.length,secretTypes:[...s].sort()}}sanitizeValue(t){if(typeof t=="string")return this.sanitize(t).text;if(Array.isArray(t))return t.map(e=>this.sanitizeValue(e));if(t&&typeof t=="object"){let e={};for(let[r,i]of Object.entries(t)){let s=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(s.includes("password")||s.includes("passwd")||s==="pwd"||s.includes("secret")||s.includes("token")||s.includes("cookie")||s.includes("authorization")||s.includes("apikey")||s.includes("accesskey")||s.includes("privatekey")||s.includes("clientsecret")||s.includes("credential")){e[r]="[REDACTED]";continue}e[r]=this.sanitizeValue(i)}return e}return t}};var ur=new $;var Jr=2*1024*1024;var G=class{symbols=new Map;edges=new Map;addSymbol(t){this.symbols.set(t.id,t)}addEdge(t){this.edges.set(t.id,t)}getSymbol(t){return this.symbols.get(t)}findByName(t,e){return[...this.symbols.values()].filter(r=>r.projectId===t&&(r.name===e||r.qualifiedName===e))}allSymbols(t){return[...this.symbols.values()].filter(e=>e.projectId===t)}allEdges(t){return[...this.edges.values()].filter(e=>e.projectId===t)}import(t,e){for(let r of t)this.addSymbol(r);for(let r of e)this.addEdge(r)}clearProject(t){for(let[e,r]of this.symbols)r.projectId===t&&this.symbols.delete(e);for(let[e,r]of this.edges)r.projectId===t&&this.edges.delete(e)}};import*as v from"typescript";import{execFile as dt}from"node:child_process";import{promisify as pt}from"node:util";var bn=pt(dt);import*as T from"typescript";import{DatabaseSync as gs}from"node:sqlite";import*as k from"typescript";import*as m from"typescript";var Bs=new Set([m.SyntaxKind.EqualsToken,m.SyntaxKind.PlusEqualsToken,m.SyntaxKind.MinusEqualsToken,m.SyntaxKind.AsteriskEqualsToken,m.SyntaxKind.SlashEqualsToken,m.SyntaxKind.PercentEqualsToken,m.SyntaxKind.QuestionQuestionEqualsToken,m.SyntaxKind.AmpersandAmpersandEqualsToken,m.SyntaxKind.BarBarEqualsToken]);var X=class{constructor(t){this.graph=t}graph;build(t,e,r,i){let s=this.graph.allSymbols(t),c=this.graph.allEdges(t),u=new Map(e?.layers.map(a=>[a.filePath,a.layer])??[]),g=new Map;for(let a of e?.clusters??[])for(let o of a.files)g.set(o,{id:a.id,label:a.label});let E=new Map(e?.hotspots.map(a=>[a.filePath,a.score])??[]),P=new Map(r?.deadCode.map(a=>[a.symbolId,{confidence:a.confidence,score:a.score}])??[]),A=new Map,R=new Map;for(let a of c)R.set(a.from,(R.get(a.from)??0)+1),A.set(a.to,(A.get(a.to)??0)+1);let M=[];for(let a=0;a<s.length;a++){let o=s[a],d=g.get(o.filePath);M.push({id:o.id,name:o.name,qualifiedName:o.qualifiedName,type:o.type,filePath:o.filePath,layer:u.get(o.filePath),cluster:d?.id,clusterLabel:d?.label,hotspotScore:E.get(o.filePath),deadCode:P.get(o.id),incoming:A.get(o.id)??0,outgoing:R.get(o.id)??0}),((a+1)%100===0||a===s.length-1)&&i?.({current:a+1,total:s.length,phase:"nodes"})}let H=new Set(M.map(a=>a.id)),N=c.filter(a=>H.has(a.from)&&H.has(a.to)),W=[];for(let a=0;a<N.length;a++){let o=N[a];W.push({source:o.from,target:o.to,type:o.type,confidence:typeof o.metadata?.confidence=="string"?o.metadata.confidence:void 0,resolver:typeof o.metadata?.resolver=="string"?o.metadata.resolver:void 0}),((a+1)%100===0||a===N.length-1)&&i?.({current:a+1,total:N.length,phase:"links"})}return{version:1,projectId:t,generatedAt:new Date().toISOString(),summary:{nodes:M.length,links:W.length,files:new Set(M.map(a=>a.filePath)).size,clusters:new Set(M.map(a=>a.cluster).filter(Boolean)).size},nodes:M,links:W}}};import{homedir as _t}from"node:os";import{join as Dt}from"node:path";import{DeleteObjectCommand as mt,GetObjectCommand as gt,HeadObjectCommand as ht,ListObjectsV2Command as yt,PutObjectCommand as St,S3Client as bt}from"@aws-sdk/client-s3";import{getSignedUrl as xt}from"@aws-sdk/s3-request-presigner";var ee=class{name="huggingface";client;bucket;constructor(t){this.bucket=t.bucket,this.client=new bt({region:"us-east-1",endpoint:`https://s3.hf.co/${t.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,r="application/octet-stream"){let i=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new St({Bucket:this.bucket,Key:t,Body:i,ContentType:r}))}async get(t){let e=await xt(this.client,new gt({Bucket:this.bucket,Key:t}),{expiresIn:60}),r=await fetch(e,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`HF download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new ht({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new mt({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],r;do{let i=await this.client.send(new yt({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:r}));for(let s of i.Contents??[])s.Key&&e.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});r=i.IsTruncated?i.NextContinuationToken:void 0}while(r);return e}};import{access as ke,mkdir as Ct,readFile as Et,readdir as wt,rm as vt,stat as Pe,writeFile as kt}from"node:fs/promises";import{dirname as Pt,join as Rt,relative as Re,resolve as At}from"node:path";var K=class{constructor(t){this.root=t}root;name="local";path(t){let e=t.replace(/^\/+/,"");return At(this.root,e)}async put(t,e){let r=this.path(t);await Ct(Pt(r),{recursive:!0}),await kt(r,e)}async get(t){try{return await Et(this.path(t))}catch(e){if(typeof e=="object"&&e!==null&&"code"in e&&e.code==="ENOENT")return null;throw e}}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await ke(this.path(t)),!0}catch{return!1}}async delete(t){await vt(this.path(t),{force:!0})}async list(t=""){let e=this.path(t),r=[];try{await ke(e)}catch{return r}let i=async c=>{let u=await wt(c,{withFileTypes:!0});for(let g of u){let E=Rt(c,g.name);if(g.isDirectory()){await i(E);continue}let P=await Pe(E);r.push({key:Re(this.root,E),size:P.size,updatedAt:P.mtime.toISOString()})}},s=await Pe(e);return s.isDirectory()?await i(e):r.push({key:Re(this.root,e),size:s.size,updatedAt:s.mtime.toISOString()}),r}};import{DeleteObjectCommand as Mt,GetObjectCommand as Tt,HeadObjectCommand as jt,ListObjectsV2Command as It,PutObjectCommand as Nt,S3Client as Lt}from"@aws-sdk/client-s3";import{getSignedUrl as Ot}from"@aws-sdk/s3-request-presigner";var z=class{name;client;bucket;constructor(t){this.name=t.name??"s3",this.bucket=t.bucket,this.client=new Lt({region:t.region??"us-east-1",endpoint:t.endpoint||void 0,forcePathStyle:t.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,r="application/octet-stream"){let i=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new Nt({Bucket:this.bucket,Key:t,Body:i,ContentType:r}))}async get(t){let e=await Ot(this.client,new Tt({Bucket:this.bucket,Key:t}),{expiresIn:60}),r=await fetch(e,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`${this.name} download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new jt({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new Mt({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],r;do{let i=await this.client.send(new It({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:r}));for(let s of i.Contents??[])s.Key&&e.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});r=i.IsTruncated?i.NextContinuationToken:void 0}while(r);return e}};function ie(n,t){return console.warn(t),new K(n)}function Ae(n){let t=n.localRoot??Dt(_t(),".toolnet-memory","storage");if(n.provider==="r2"){let e=n.r2;return e?.accountId&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new z({name:"r2",endpoint:`https://${e.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:e.bucket,forcePathStyle:!0,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):ie(t,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(n.provider==="s3"){let e=n.s3;return e?.bucket&&e.accessKeyId&&e.secretAccessKey?new z({name:"s3",endpoint:e.endpoint,region:e.region??"us-east-1",bucket:e.bucket,forcePathStyle:e.forcePathStyle??!1,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):ie(t,"[storage] S3 credentials missing. Using local fallback.")}if(n.provider==="huggingface"){let e=n.huggingface;return e?.namespace&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new ee({namespace:e.namespace,bucket:e.bucket,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):ie(t,"[storage] Hugging Face credentials missing. Using local fallback.")}return new K(t)}function Ft(n){return new Promise(t=>setTimeout(t,n))}async function Me(n,t={}){let e=Math.max(1,t.attempts??3),r=t.baseDelayMs??150,i=t.maxDelayMs??2e3,s;for(let c=1;c<=e;c++)try{return await n()}catch(u){if(s=u,c>=e)break;let g=Math.min(i,r*2**(c-1)),E=Math.floor(Math.random()*Math.max(1,g*.2));await Ft(g+E)}throw s}var $t=new Set(["put","get","getText","delete","list"]);function Te(n,t={}){return new Proxy(n,{get(e,r){let i=Reflect.get(e,r,e);return typeof i!="function"?i:$t.has(r)?(...s)=>Me(()=>Promise.resolve(i.apply(e,s)),t):i.bind(e)}})}var Ie=Number(process.env.TOOLNET_GRAPH_PORT??9749),Ne=process.env.TOOLNET_GRAPH_HOST??"127.0.0.1";function Bt(n){if(typeof n=="string")return n;if(!n||typeof n!="object")return null;let t=n;for(let e of["key","Key","path","name"])if(typeof t[e]=="string")return t[e];return null}async function Ht(n,t){return(await n.list(t)).map(Bt).filter(r=>!!r)}async function B(n,t){let e=await n.getText(t);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async function Wt(n){let t=await Ht(n,"projects/"),e=[...new Set(t.filter(s=>/^projects\/[^/]+\/project\.json$/.test(s)).map(s=>s.split("/")[1]))],r=new Set(t),i=[];for(let s of e){let c=await B(n,`projects/${s}/project.json`);!c||typeof c.id!="string"||i.push({id:c.id,name:typeof c.name=="string"?c.name:s,remote:s,hasGraph:r.has(`projects/${s}/code/graph/current.json`),hasArchitecture:r.has(`projects/${s}/code/architecture/current.json`),hasAnalysis:r.has(`projects/${s}/code/analysis/current.json`),hasVisualization:r.has(`projects/${s}/code/visualization/graph.json`)})}return i.sort((s,c)=>s.name.localeCompare(c.name))}async function Ut(){let n=pe(),t=new Q().detect(),e=Te(Ae({provider:n.storage.provider,huggingface:n.storage.huggingface,localRoot:n.storage.localRoot}),{attempts:3});e.name!=="huggingface"&&console.warn("[graph-ui] Remote Hugging Face storage is not active.");let r=Kt(zt(import.meta.url)),i=ae(r,"public"),s=ae(i,"vendor","3d-force-graph.min.js");async function c(){let a=await Wt(e),o=t.remote??t.name,d=a.find(h=>h.remote===o&&h.hasGraph),x=a.find(h=>h.hasGraph);return{projects:a,defaultProject:d?.remote??x?.remote??null}}let u=new Map;function g(a){return String(typeof a=="object"&&a!==null?a.id:a)}function E(a){return a.clusterLabel||a.cluster||a.layer||"Unclustered"}function P(a,o={}){return{id:a.id,name:a.name,remote:a.remote,hasArchitecture:a.hasArchitecture,hasAnalysis:a.hasAnalysis,...o}}async function A(a){let o=`projects/${a.remote}`,d=await B(e,`${o}/code/graph/current.json`);if(!d||!Array.isArray(d.symbols)||!Array.isArray(d.edges))throw new Error(`Code graph missing for project ${a.name}`);let x=await B(e,`${o}/code/architecture/current.json`),h=await B(e,`${o}/code/analysis/current.json`),b=new G;b.import(d.symbols,d.edges);let C=new X(b).build(a.id,x,h);return await e.put(`${o}/code/visualization/graph.json`,JSON.stringify(C),"application/json"),{...C,dashboard:P(a)}}async function R(a,o=!1){o&&u.delete(a.remote);let d=u.get(a.remote);if(d)return d;let x=`projects/${a.remote}`,h=await B(e,`${x}/code/visualization/graph.json`);if(h&&Array.isArray(h.nodes)&&Array.isArray(h.links)){let C={...h,dashboard:P(a)};return u.set(a.remote,C),C}let b=await A(a);return u.set(a.remote,b),b}function M(a,o){let d=new Map,x=new Map;for(let p of o.nodes){let f=E(p),y=`cluster:${f}`;x.set(p.id,y);let l=d.get(y);l||(l={id:y,name:f,qualifiedName:f,type:"subsystem",filePath:"",clusterLabel:f,incoming:0,outgoing:0,memberCount:0,files:new Set,viewKind:"cluster"},d.set(y,l)),l.memberCount+=1,p.filePath&&l.files.add(p.filePath)}let h=new Map;for(let p of o.links){let f=x.get(g(p.source)),y=x.get(g(p.target));if(!f||!y||f===y)continue;let l=`${f}\0${y}`,S=h.get(l);S||(S={source:f,target:y,type:"SUBSYSTEM_DEPENDENCY",count:0},h.set(l,S)),S.count+=1}for(let p of h.values()){let f=d.get(p.source),y=d.get(p.target);f&&(f.outgoing+=p.count),y&&(y.incoming+=p.count)}let b=[...d.values()].map(p=>({...p,filePath:`${p.files.size} files \xB7 ${p.memberCount} symbols`,files:void 0})),C=[...h.values()];return{version:2,projectId:o.projectId,generatedAt:o.generatedAt,summary:{nodes:b.length,links:C.length,files:o.summary?.files??0,clusters:b.length},nodes:b,links:C,dashboard:P(a,{viewMode:"overview",totalNodes:o.nodes.length,totalLinks:o.links.length})}}function H(a,o,d){let x=o.nodes.filter(l=>!d||E(l)===d),h=new Set(x.map(l=>l.id)),b=new Map,C=new Map;for(let l of x){let S=l.filePath||"(unknown)";b.set(l.id,S);let w=C.get(S);w||(w={id:`file:${S}`,name:S.split("/").pop()||S,qualifiedName:S,type:"file",filePath:S,clusterLabel:E(l),incoming:0,outgoing:0,memberCount:0,viewKind:"file"},C.set(S,w)),w.memberCount+=1}let p=new Map;for(let l of o.links){let S=g(l.source),w=g(l.target);if(!h.has(S)||!h.has(w))continue;let te=b.get(S),re=b.get(w);if(!te||!re||te===re)continue;let ce=`file:${te}`,le=`file:${re}`,de=`${ce}\0${le}`,U=p.get(de);U||(U={source:ce,target:le,type:"FILE_DEPENDENCY",count:0},p.set(de,U)),U.count+=1}for(let l of p.values()){let S=C.get(String(l.source).slice(5)),w=C.get(String(l.target).slice(5));S&&(S.outgoing+=l.count),w&&(w.incoming+=l.count)}let f=[...C.values()],y=[...p.values()];return{version:2,projectId:o.projectId,generatedAt:o.generatedAt,summary:{nodes:f.length,links:y.length,files:f.length,clusters:d?1:0},nodes:f,links:y,dashboard:P(a,{viewMode:"files",selection:d,totalNodes:o.nodes.length,totalLinks:o.links.length})}}function N(a,o,d){let b=o.nodes.filter(l=>l.filePath===d),C=new Set(b.map(l=>l.id)),p=new Set;for(let l of b.slice(0,1800))p.add(l.id);for(let l of o.links){if(p.size>=1800)break;let S=g(l.source),w=g(l.target);(C.has(S)||C.has(w))&&(p.add(S),p.size<1800&&p.add(w))}let f=o.nodes.filter(l=>p.has(l.id)).map(l=>({...l,viewKind:"symbol"})),y=[];for(let l of o.links){if(y.length>=12e3)break;let S=g(l.source),w=g(l.target);p.has(S)&&p.has(w)&&y.push({...l,source:S,target:w})}return{version:2,projectId:o.projectId,generatedAt:o.generatedAt,summary:{nodes:f.length,links:y.length,files:new Set(f.map(l=>l.filePath)).size,clusters:new Set(f.map(l=>E(l))).size},nodes:f,links:y,dashboard:P(a,{viewMode:"symbols",selection:d,focused:!0,truncated:f.length>=1800||y.length>=12e3,totalNodes:o.nodes.length,totalLinks:o.links.length})}}Gt(async(a,o)=>{try{let d=new URL(a.url??"/",`http://${a.headers.host??"localhost"}`);if(d.pathname==="/api/health"){let x=await c();o.setHeader("content-type","application/json; charset=utf-8"),o.setHeader("cache-control","no-store"),o.end(JSON.stringify({ok:!0,mode:"multi-project",projects:x.projects.length,indexedProjects:x.projects.filter(h=>h.hasGraph).length,defaultProject:x.defaultProject}));return}if(d.pathname==="/api/projects"){let x=await c();o.setHeader("content-type","application/json; charset=utf-8"),o.setHeader("cache-control","no-store"),o.end(JSON.stringify(x));return}if(d.pathname==="/api/graph"){let x=await c(),h=d.searchParams.get("project")??x.defaultProject;if(!h){o.statusCode=404,o.setHeader("content-type","application/json; charset=utf-8"),o.end(JSON.stringify({error:"No indexed ToolNet project found."}));return}let b=x.projects.find(l=>l.remote===h);if(!b){o.statusCode=404,o.setHeader("content-type","application/json; charset=utf-8"),o.end(JSON.stringify({error:"Project not found.",project:h}));return}if(!b.hasGraph){o.statusCode=409,o.setHeader("content-type","application/json; charset=utf-8"),o.end(JSON.stringify({error:"Project is registered but has not been indexed yet.",project:b}));return}let C=d.searchParams.get("refresh")==="1",p=await R(b,C),f=d.searchParams.get("mode")??"full",y=p;if(f==="overview")y=M(b,p);else if(f==="files")y=H(b,p,d.searchParams.get("cluster")??"");else if(f==="symbols"){let l=d.searchParams.get("file");if(!l){o.statusCode=400,o.setHeader("content-type","application/json; charset=utf-8"),o.end(JSON.stringify({error:"file is required for symbols mode."}));return}y=N(b,p,l)}else if(f!=="full"){o.statusCode=400,o.setHeader("content-type","application/json; charset=utf-8"),o.end(JSON.stringify({error:`Unknown graph mode: ${f}`}));return}o.setHeader("content-type","application/json; charset=utf-8"),o.setHeader("cache-control","no-store"),o.end(JSON.stringify(y));return}if(d.pathname==="/vendor/3d-force-graph.min.js"){o.setHeader("content-type","application/javascript; charset=utf-8"),je(s).pipe(o);return}if(d.pathname==="/"||d.pathname==="/index.html"){o.setHeader("content-type","text/html; charset=utf-8"),o.setHeader("cache-control","no-store"),je(ae(i,"index.html")).pipe(o);return}o.statusCode=404,o.end("Not found")}catch(d){console.error(d),o.statusCode=500,o.setHeader("content-type","application/json; charset=utf-8"),o.end(JSON.stringify({error:d instanceof Error?d.message:String(d)}))}}).listen(Ie,Ne,()=>{console.log("ToolNet Multi-Project 3D Graph"),console.log(`Listening: http://${Ne}:${Ie}`)})}Ut().catch(n=>{console.error(n),process.exit(1)});
|