toolnet-memory 0.3.15 → 0.3.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/.env.example +74 -0
  2. package/.release-target +1 -1
  3. package/README.md +316 -6
  4. package/bin/toolnet-memory +12 -0
  5. package/bundle/agy-hook.js +66 -66
  6. package/bundle/agy.js +56 -56
  7. package/bundle/api.js +15 -15
  8. package/bundle/audit.js +2 -0
  9. package/bundle/background-refresh.js +7 -7
  10. package/bundle/claude-hook.js +49 -49
  11. package/bundle/code-capabilities.js +2 -0
  12. package/bundle/codex-context.js +29 -29
  13. package/bundle/codex.js +71 -71
  14. package/bundle/context-runtime.js +39 -39
  15. package/bundle/context.js +15 -15
  16. package/bundle/copilot-hook.js +78 -78
  17. package/bundle/cursor-hook.js +78 -78
  18. package/bundle/docker-healthcheck.js +3 -0
  19. package/bundle/doctor.js +4 -4
  20. package/bundle/full-index.js +22 -21
  21. package/bundle/gc.js +5 -3
  22. package/bundle/graph-cli.js +1 -1
  23. package/bundle/graph-index.js +5 -4
  24. package/bundle/graph-ui.js +4 -3
  25. package/bundle/grok-hook.js +56 -56
  26. package/bundle/handoff-refresh.js +10 -10
  27. package/bundle/help-cli.js +4 -4
  28. package/bundle/impact.js +5 -4
  29. package/bundle/incremental.js +5 -5
  30. package/bundle/init.js +36 -35
  31. package/bundle/kiro-hook.js +85 -85
  32. package/bundle/learner.js +8 -6
  33. package/bundle/mcp.js +19 -17
  34. package/bundle/memory-agent.js +6 -6
  35. package/bundle/memory-query.js +7 -7
  36. package/bundle/opencode.js +77 -77
  37. package/bundle/project-manual.js +7 -7
  38. package/bundle/public/index.html +51 -2
  39. package/bundle/recovery-certify.js +9 -9
  40. package/bundle/runtime.js +16 -13
  41. package/bundle/semantic.js +6 -5
  42. package/bundle/service.js +11 -6
  43. package/bundle/snapshot.js +6 -4
  44. package/bundle/status-cli.js +4 -4
  45. package/bundle/toolnet-cli.js +46 -46
  46. package/bundle/work-continuity.js +7 -7
  47. package/package.json +38 -2
  48. package/release-manifest.json +143 -4
@@ -1,3 +1,4 @@
1
- import"dotenv/config";import{createReadStream as Ce}from"node:fs";import{createServer as vt}from"node:http";import{dirname as kt,resolve as te}from"node:path";import{fileURLToPath as Pt}from"node:url";import{existsSync as ve,readFileSync as ke}from"node:fs";import{homedir as Pe}from"node:os";import{join as Re}from"node:path";function Ae(s){let t=s.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 je(){let s=process.env.TOOLNET_GLOBAL_ENV??Re(Pe(),".config","toolnet-memory",".env");if(!ve(s))return;let t=ke(s,"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 a=r.indexOf("=");if(a<=0)continue;let o=r.slice(0,a).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(o)&&process.env[o]===void 0&&(process.env[o]=Ae(r.slice(a+1)))}}je();function I(s,t){return s===void 0?t:["1","true","yes","on"].includes(s.toLowerCase())}function L(s,t){if(!s)return t;let e=Number(s);return Number.isFinite(e)?e:t}function oe(){return{memory:{autoCapture:I(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:I(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:I(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:I(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:L(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:L(process.env.MEMORY_RERANK_TOP,10),finalContext:L(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:L(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:I(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:L(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Me}from"node:crypto";import{existsSync as H,mkdirSync as Te,readFileSync as Ne,renameSync as Ie,writeFileSync as Le}from"node:fs";import{basename as Oe,dirname as W,join as O,parse as de,resolve as T}from"node:path";var pe=".toolnet",_e="project.json";function Fe(s){return Me("sha256").update(s).digest("hex").slice(0,16)}function U(s){return O(s,pe,_e)}function $e(s){return H(U(s))}function ie(s,t){let e=T(s),r=de(e).root;for(;;){if($e(e))return e;if(e===r||t&&e===T(t))break;let a=W(e);if(a===e)break;e=a}return null}function ae(s){let t=T(s),e=de(t).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>H(O(t,o))))return t;if(t===e)break;let a=W(t);if(a===t)break;t=a}return T(s)}function ce(s){let t;try{t=JSON.parse(Ne(s,"utf8"))}catch(a){throw new Error(`Invalid ToolNet project manifest: ${s}: ${a instanceof Error?a.message:String(a)}`)}if(!t||typeof t!="object")throw new Error(`Invalid ToolNet project manifest: ${s}`);let e=t;if(typeof e.id!="string"||!e.id.trim())throw new Error(`ToolNet project manifest is missing id: ${s}`);if(typeof e.name!="string"||!e.name.trim())throw new Error(`ToolNet project manifest is missing name: ${s}`);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:W(W(s)),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 le(s,t){let e=O(s,pe);Te(e,{recursive:!0});let r=U(s),a=`${r}.tmp-${process.pid}`;Le(a,JSON.stringify(t,null,2)+`
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 gt}from"node:fs";import{createServer as Kr}from"node:http";import{dirname as Hr,resolve as Re}from"node:path";import{fileURLToPath as Br}from"node:url";import{existsSync as yt,readFileSync as St}from"node:fs";import{homedir as bt}from"node:os";import{join as xt}from"node:path";function Et(r){let t=r.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 Ct(){let r=process.env.TOOLNET_GLOBAL_ENV??xt(bt(),".config","toolnet-memory",".env");if(!yt(r))return;let t=St(r,"utf8");for(let e of t.split(/\r?\n/)){let n=e.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let s=n.indexOf("=");if(s<=0)continue;let i=n.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=Et(n.slice(s+1)))}}Ct();function $(r,t){return r===void 0?t:["1","true","yes","on"].includes(r.toLowerCase())}function G(r,t){if(!r)return t;let e=Number(r);return Number.isFinite(e)?e:t}function Ae(){return{memory:{autoCapture:$(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:$(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:$(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:$(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:G(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:G(process.env.MEMORY_RERANK_TOP,10),finalContext:G(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:G(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:$(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:G(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as At}from"node:crypto";import{existsSync as oe,mkdirSync as Nt,readFileSync as Mt,renameSync as It,writeFileSync as Lt}from"node:fs";import{basename as _t,dirname as ie,join as H,parse as De,resolve as _}from"node:path";import{createHash as Ie}from"node:crypto";import{spawnSync as wt}from"node:child_process";var K="git-remote-v1",Rt=new Set(["github.com","gitlab.com","bitbucket.org"]);function Le(r,t){let e=t.replaceAll("\\","/").replace(/^\/+/u,"").replace(/\/+$/u,"").replace(/\.git$/iu,"").replace(/\/+/gu,"/");return!e||e==="."||e===".."||e.split("/").some(n=>!n||n==="."||n==="..")?null:(Rt.has(r)&&(e=e.toLowerCase()),e)}function vt(r){let t;try{t=new URL(r)}catch{return null}if(!["https:","http:","ssh:","git:"].includes(t.protocol))return null;let e=t.hostname.trim().toLowerCase();if(!e)return null;let n=t.protocol==="https:"&&t.port==="443"||t.protocol==="http:"&&t.port==="80"||t.protocol==="ssh:"&&t.port==="22",s=t.port&&!n?`${e}:${t.port}`:e,i=Le(e,t.pathname);return i?`${s}/${i}`:null}function Pt(r){let t=r.match(/^(?:[^@\s/:]+@)?([^:/\s]+):(.+)$/u);if(!t)return null;let e=t[1]?.trim().toLowerCase();if(!e||e.length===1)return null;let n=Le(e,t[2]??"");return n?`${e}/${n}`:null}function Ne(r){let t=r.trim();return t?t.includes("://")?vt(t):Pt(t):null}function kt(r){return Ie("sha256").update(`${K}:${r}`).digest("hex")}function _e(r){return Ie("sha256").update(`toolnet-project:${K}:${r}`).digest("hex").slice(0,16)}function Tt(r){return r.split("/").filter(Boolean).at(-1)?.trim()||null}function ge(r,t){let e=wt("git",["-C",r,...t],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return e.error||e.status!==0?null:e.stdout?.trim()||null}function Me(r,t){let e=Tt(r);return e?{scheme:K,canonicalRemote:r,fingerprint:kt(r),repositoryName:e,source:t}:null}function Oe(r){let t=ge(r,["remote","get-url","origin"]);if(t){let s=Ne(t);if(s)return Me(s,"origin")}let e=ge(r,["remote"]);if(!e)return null;let n=new Set;for(let s of e.split(/\r?\n/u).map(i=>i.trim()).filter(Boolean)){let i=ge(r,["remote","get-url",s]);if(!i)continue;let c=Ne(i);c&&n.add(c)}return n.size!==1?null:Me([...n][0],"unique-remote")}var Fe=".toolnet",Ot="project.json";function jt(r){return At("sha256").update(r).digest("hex").slice(0,16)}function D(r){return H(r,Fe,Ot)}function $e(r){return oe(D(r))}function je(r,t){let e=_(r),n=De(e).root;for(;;){if($e(e))return e;if(e===n||t&&e===_(t))break;let s=ie(e);if(s===e)break;e=s}return null}function he(r){let t=_(r),e=De(t).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(i=>oe(H(t,i))))return t;if(t===e)break;let s=ie(t);if(s===t)break;t=s}return _(r)}function ne(r){let t;try{t=JSON.parse(Mt(r,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${r}: ${s instanceof Error?s.message:String(s)}`)}if(!t||typeof t!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let e=t;if(typeof e.id!="string"||!e.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof e.name!="string"||!e.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=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:ie(ie(r)),createdAt:typeof e.createdAt=="string"?e.createdAt:n,updatedAt:typeof e.updatedAt=="string"?e.updatedAt:n,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 se(r,t){let e=H(r,Fe);Nt(e,{recursive:!0});let n=D(r),s=`${n}.tmp-${process.pid}`;Lt(s,JSON.stringify(t,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),It(s,n)}function L(r,t){return{id:r.id,name:r.name,remote:r.remote,rootPath:t,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}function ye(r){return{version:1,scheme:K,canonicalRemote:r.canonicalRemote,fingerprint:r.fingerprint,repositoryName:r.repositoryName}}function Dt(r){let t=r.metadata?.toolnetIdentity;if(!t||typeof t!="object"||Array.isArray(t))return null;let e=t;return typeof e.fingerprint=="string"?e.fingerprint:null}var ae=class{adopt(t,e){let n=he(_(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($e(n)){let u=ne(D(n));if(u.id!==e.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${u.id}`,`requested=${e.id}`].join(" "));return L(u,n)}let s=new Date().toISOString(),i={...e.metadata};e.gitIdentity&&(i.toolnetIdentity=ye(e.gitIdentity));let c={version:1,id:e.id.trim(),name:e.name.trim(),remote:e.remote.trim(),rootPath:n,createdAt:e.createdAt??s,updatedAt:s,graphVersion:e.graphVersion??0,memoryVersion:e.memoryVersion??0,metadata:Object.keys(i).length?i:void 0};return se(n,c),L(c,n)}recordGitIdentity(t,e,n={}){let s=this.requireExisting(t),i=D(s.rootPath),c=ne(i),u=Dt(c);if(u&&u!==e.fingerprint&&!n.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 p=c.metadata?.toolnetIdentity;return p&&typeof p=="object"&&!Array.isArray(p)&&p.fingerprint===e.fingerprint||(c.metadata={...c.metadata,toolnetIdentity:ye(e)},c.updatedAt=new Date().toISOString(),se(s.rootPath,c)),L(c,s.rootPath)}findExisting(t=process.cwd()){let e=_(t),n=he(e),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>oe(H(n,p))),c=je(e,i?n:void 0);if(!c)return null;let u=ne(D(c));return L(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=_(t),n=he(e),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(k=>oe(H(n,k))),c=je(e,i?n:void 0);if(c){let k=D(c),A=ne(k);return A.rootPath!==c&&(A.rootPath=c,A.updatedAt=new Date().toISOString(),se(c,A)),L(A,c)}let u=new Date().toISOString(),p=_t(n),m=Oe(n),P={version:1,id:m?_e(m.canonicalRemote):jt(n),name:p,remote:m?.repositoryName??p,rootPath:n,createdAt:u,updatedAt:u,graphVersion:0,memoryVersion:0,metadata:m?{toolnetIdentity:ye(m)}:void 0};return se(n,P),L(P,n)}};var Ft=[{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"}],$t=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function Ge(r){return r.normalize("NFKC").trim().toLowerCase()}function Gt(r){if(r.length===0)return 0;let t=new Map;for(let n of r)t.set(n,(t.get(n)??0)+1);let e=0;for(let n of t.values()){let s=n/r.length;e-=s*Math.log2(s)}return e}function Kt(r){return/^[a-f0-9]{32}$/iu.test(r)||/^[a-f0-9]{40}$/iu.test(r)||/^[a-f0-9]{64}$/iu.test(r)}function Ht(r,t,e){let n=r.slice(Math.max(0,t-48),t),s=r.slice(e,Math.min(r.length,e+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${n} ${s}`)}function Bt(r,t){return r.start<t.end&&t.start<r.end}function Ke(r){return r.sort((t,e)=>t.start!==e.start?t.start-e.start:e.end-e.start-(t.end-t.start))}var ce=class{allowValues=new Set;enableEntropyHeuristic;constructor(t={}){for(let e of t.allowValues??[]){let n=Ge(e);n&&this.allowValues.add(n)}this.enableEntropyHeuristic=t.enableEntropyHeuristic??!0}scan(t){let e=[];for(let i of Ft){let c=new RegExp(i.regex.source,i.regex.flags);for(let u of t.matchAll(c))u.index===void 0||!u[0]||this.allowed(u[0])||e.push({type:i.type,value:u[0],start:u.index,end:u.index+u[0].length,confidence:i.confidence})}this.enableEntropyHeuristic&&e.push(...this.entropyMatches(t));let n=Ke(e),s=[];for(let i of n)s.some(c=>Bt(c,i))||s.push(i);return Ke(s)}hasSecrets(t){return this.scan(t).length>0}allowed(t){let e=Ge(t);return $t.has(e)?!0:this.allowValues.has(e)}entropyMatches(t){let e=[],n=/[A-Za-z0-9_+/=-]{32,160}/g;for(let s of t.matchAll(n)){if(s.index===void 0||!s[0])continue;let i=s[0];this.allowed(i)||Kt(i)||!/[A-Za-z]/u.test(i)||!/[0-9]/u.test(i)||Ht(t,s.index,s.index+i.length)&&(Gt(i)<3.7||e.push({type:"high_entropy_secret",value:i,start:s.index,end:s.index+i.length,confidence:"heuristic"}))}return e}};var B=class{scanner;constructor(t={}){this.scanner=new ce(t)}sanitize(t){let e=this.scanner.scan(t);if(e.length===0)return{text:t,redacted:0,secretTypes:[]};let n=t,s=[...e].sort((c,u)=>u.start-c.start),i=new Set;for(let c of s)i.add(c.type),n=n.slice(0,c.start)+`[REDACTED:${c.type}]`+n.slice(c.end);return{text:n,redacted:e.length,secretTypes:[...i].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[n,s]of Object.entries(t)){let i=n.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(i.includes("password")||i.includes("passwd")||i==="pwd"||i.includes("secret")||i.includes("token")||i.includes("cookie")||i.includes("authorization")||i.includes("apikey")||i.includes("accesskey")||i.includes("privatekey")||i.includes("clientsecret")||i.includes("credential")){e[n]="[REDACTED]";continue}e[n]=this.sanitizeValue(s)}return e}return t}};var mn=new B;var Qn=2*1024*1024;var z=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(n=>n.projectId===t&&(n.name===e||n.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 n of t)this.addSymbol(n);for(let n of e)this.addEdge(n)}clearProject(t){for(let[e,n]of this.symbols)n.projectId===t&&this.symbols.delete(e);for(let[e,n]of this.edges)n.projectId===t&&this.edges.delete(e)}};var M={supported:!0,structural:!0,lexicalSearch:!0,engine:"typescript-compiler-api",lexicalEngine:"file-chunk-fts5-bm25"},U={supported:!1,structural:!1,lexicalSearch:!0,engine:"unsupported",lexicalEngine:"file-chunk-fts5-bm25"},le=[{language:"typescript",extensions:[".ts"],...M},{language:"tsx",extensions:[".tsx"],...M},{language:"javascript",extensions:[".js"],...M},{language:"jsx",extensions:[".jsx"],...M},{language:"mts",extensions:[".mts"],...M},{language:"cts",extensions:[".cts"],...M},{language:"mjs",extensions:[".mjs"],...M},{language:"cjs",extensions:[".cjs"],...M},{language:"python",extensions:[".py"],...U,lspServer:"pyright-langserver"},{language:"go",extensions:[".go"],...U,lspServer:"gopls"},{language:"rust",extensions:[".rs"],...U,lspServer:"rust-analyzer"},{language:"c",extensions:[".c",".h"],...U,lspServer:"clangd"},{language:"cpp",extensions:[".cc",".cpp",".cxx",".hpp",".hh"],...U,lspServer:"clangd"}];import*as v from"typescript";import{execFile as Yt}from"node:child_process";import{promisify as Vt}from"node:util";var ks=Vt(Yt);import*as I from"typescript";import{DatabaseSync as Ro}from"node:sqlite";import*as T from"typescript";import*as h from"typescript";var Zo=new Set([h.SyntaxKind.EqualsToken,h.SyntaxKind.PlusEqualsToken,h.SyntaxKind.MinusEqualsToken,h.SyntaxKind.AsteriskEqualsToken,h.SyntaxKind.SlashEqualsToken,h.SyntaxKind.PercentEqualsToken,h.SyntaxKind.QuestionQuestionEqualsToken,h.SyntaxKind.AmpersandAmpersandEqualsToken,h.SyntaxKind.BarBarEqualsToken]);var de=class{constructor(t){this.graph=t}graph;build(t,e,n,s){let i=this.graph.allSymbols(t),c=this.graph.allEdges(t),u=new Map(e?.layers.map(a=>[a.filePath,a.layer])??[]),p=new Map;for(let a of e?.clusters??[])for(let o of a.files)p.set(o,{id:a.id,label:a.label});let m=new Map(e?.hotspots.map(a=>[a.filePath,a.score])??[]),P=new Map(n?.deadCode.map(a=>[a.symbolId,{confidence:a.confidence,score:a.score}])??[]),k=new Map,A=new Map;for(let a of c)A.set(a.from,(A.get(a.from)??0)+1),k.set(a.to,(k.get(a.to)??0)+1);let N=[];for(let a=0;a<i.length;a++){let o=i[a],d=p.get(o.filePath);N.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:m.get(o.filePath),deadCode:P.get(o.id),incoming:k.get(o.id)??0,outgoing:A.get(o.id)??0}),((a+1)%100===0||a===i.length-1)&&s?.({current:a+1,total:i.length,phase:"nodes"})}let ee=new Set(N.map(a=>a.id)),j=c.filter(a=>ee.has(a.from)&&ee.has(a.to)),te=[];for(let a=0;a<j.length;a++){let o=j[a];te.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===j.length-1)&&s?.({current:a+1,total:j.length,phase:"links"})}return{version:1,projectId:t,generatedAt:new Date().toISOString(),summary:{nodes:N.length,links:te.length,files:new Set(N.map(a=>a.filePath)).size,clusters:new Set(N.map(a=>a.cluster).filter(Boolean)).size},nodes:N,links:te}}};import{spawnSync as Qt}from"node:child_process";var Zt=[{language:"python",command:"pyright-langserver"},{language:"go",command:"gopls"},{language:"rust",command:"rust-analyzer"},{language:"c",command:"clangd"},{language:"cpp",command:"clangd"}];function Xt(r){return r.split(/\r?\n/u).map(e=>e.trim()).find(Boolean)||void 0}function er(r,t){let e=Qt(t,["--version"],{encoding:"utf8",timeout:2e3,windowsHide:!0}),n=!e.error&&e.status===0,s=[e.stdout??"",e.stderr??""].join(`
4
+ `);return{language:r,command:t,installed:n,...n?{version:Xt(s)}:{},mode:"external-optional",activeInStructuralGraph:!1}}function Be(){return Zt.map(r=>er(r.language,r.command))}var tr=process.argv.includes("--json"),ze=Be(),rr={structuralParser:{engine:"typescript-compiler-api",languages:le.filter(r=>r.structural).map(r=>r.language)},lexicalSearch:{engine:"sqlite-fts5-bm25",languages:le.filter(r=>r.lexicalSearch).map(r=>r.language)},lspFoundation:{mode:"detection-only",automaticDownload:!1,structuralGraphIntegration:!1,servers:ze}};if(tr)console.log(JSON.stringify(rr,null,2));else{console.log("ToolNet Code Intelligence Capabilities"),console.log(""),console.log("Structural parser: TypeScript Compiler API");for(let r of le)console.log([r.language.padEnd(12),r.structural?"structural=yes":"structural=no",r.lexicalSearch?"lexical=yes":"lexical=no",r.lspServer?`lsp=${r.lspServer}`:""].filter(Boolean).join(" "));console.log(""),console.log("LSP detection:");for(let r of ze)console.log([r.language.padEnd(12),r.command.padEnd(22),r.installed?"available":"not-installed"].join(" "))}import{homedir as Lr}from"node:os";import{join as _r}from"node:path";import{DeleteObjectCommand as nr,GetObjectCommand as sr,HeadObjectCommand as or,ListObjectsV2Command as ir,PutObjectCommand as ar,S3Client as cr}from"@aws-sdk/client-s3";import{getSignedUrl as lr}from"@aws-sdk/s3-request-presigner";var ue=class{name="huggingface";client;bucket;constructor(t){this.bucket=t.bucket,this.client=new cr({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,n="application/octet-stream"){let s=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new ar({Bucket:this.bucket,Key:t,Body:s,ContentType:n}))}async get(t){let e=await lr(this.client,new sr({Bucket:this.bucket,Key:t}),{expiresIn:60}),n=await fetch(e,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`HF download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.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 or({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 nr({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],n;do{let s=await this.client.send(new ir({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:n}));for(let i of s.Contents??[])i.Key&&e.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});n=s.IsTruncated?s.NextContinuationToken:void 0}while(n);return e}};import{access as Ue,mkdir as dr,readFile as ur,readdir as pr,rm as fr,stat as We,writeFile as mr}from"node:fs/promises";import{dirname as gr,join as hr,relative as Ye,resolve as yr}from"node:path";var W=class{constructor(t){this.root=t}root;name="local";path(t){let e=t.replace(/^\/+/,"");return yr(this.root,e)}async put(t,e){let n=this.path(t);await dr(gr(n),{recursive:!0}),await mr(n,e)}async get(t){try{return await ur(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 Ue(this.path(t)),!0}catch{return!1}}async delete(t){await fr(this.path(t),{force:!0})}async list(t=""){let e=this.path(t),n=[];try{await Ue(e)}catch{return n}let s=async c=>{let u=await pr(c,{withFileTypes:!0});for(let p of u){let m=hr(c,p.name);if(p.isDirectory()){await s(m);continue}let P=await We(m);n.push({key:Ye(this.root,m),size:P.size,updatedAt:P.mtime.toISOString()})}},i=await We(e);return i.isDirectory()?await s(e):n.push({key:Ye(this.root,e),size:i.size,updatedAt:i.mtime.toISOString()}),n}};import{DeleteObjectCommand as Sr,GetObjectCommand as br,HeadObjectCommand as xr,ListObjectsV2Command as Er,PutObjectCommand as Cr,S3Client as wr}from"@aws-sdk/client-s3";import{getSignedUrl as Rr}from"@aws-sdk/s3-request-presigner";var Y=class{name;client;bucket;constructor(t){this.name=t.name??"s3",this.bucket=t.bucket,this.client=new wr({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,n="application/octet-stream"){let s=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new Cr({Bucket:this.bucket,Key:t,Body:s,ContentType:n}))}async get(t){let e=await Rr(this.client,new br({Bucket:this.bucket,Key:t}),{expiresIn:60}),n=await fetch(e,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`${this.name} download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.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 xr({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 Sr({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],n;do{let s=await this.client.send(new Er({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:n}));for(let i of s.Contents??[])i.Key&&e.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});n=s.IsTruncated?s.NextContinuationToken:void 0}while(n);return e}};import{createCipheriv as vr,createDecipheriv as Pr,createHash as kr,randomBytes as Tr,timingSafeEqual as Ar}from"node:crypto";import{readFileSync as Nr}from"node:fs";var O=Buffer.from("TNMEME01","ascii"),Je=1,V=8,J=12,Se=16,qe=O.length+1+V+J+Se,Mr="toolnet-memory:remote-encryption:v1:",Qe="aes-256-gcm",be=32,C=class extends Error{constructor(e,n){super(n);this.code=e;this.name="RemoteEncryptionError"}code};function Ir(r){return r?["1","true","yes","on","enabled"].includes(r.trim().toLowerCase()):!1}function xe(r=process.env){return Ir(r.TOOLNET_REMOTE_ENCRYPTION)}function Ve(r){let t=r.trim();if(!t)throw new C("REMOTE_ENCRYPTION_KEY_EMPTY","Remote encryption key is empty.");let e;if(t.startsWith("hex:")){let n=t.slice(4);if(!/^[0-9a-f]{64}$/iu.test(n))throw new C("REMOTE_ENCRYPTION_KEY_INVALID","hex: remote encryption key must contain exactly 64 hexadecimal characters.");e=Buffer.from(n,"hex")}else if(/^[0-9a-f]{64}$/iu.test(t))e=Buffer.from(t,"hex");else{let n=t.startsWith("base64:")?t.slice(7):t;if(!/^[A-Za-z0-9+/_-]+={0,2}$/u.test(n))throw new C("REMOTE_ENCRYPTION_KEY_INVALID","Remote encryption key must be 32 raw bytes encoded as hexadecimal or base64.");e=Buffer.from(n,n.includes("-")||n.includes("_")?"base64url":"base64")}if(e.length!==be)throw new C("REMOTE_ENCRYPTION_KEY_INVALID_LENGTH",`Remote encryption key must decode to exactly ${be} bytes.`);return e}function Ze(r=process.env){let t=r.TOOLNET_REMOTE_ENCRYPTION_KEY?.trim(),e=r.TOOLNET_REMOTE_ENCRYPTION_KEY_FILE?.trim();if(t&&e)throw new C("REMOTE_ENCRYPTION_KEY_AMBIGUOUS","Configure either TOOLNET_REMOTE_ENCRYPTION_KEY or TOOLNET_REMOTE_ENCRYPTION_KEY_FILE, not both.");if(t)return Ve(t);if(e){let n;try{n=Nr(e,"utf8")}catch(s){throw new C("REMOTE_ENCRYPTION_KEY_FILE_READ_FAILED",[`Unable to read remote encryption key file: ${e}.`,s instanceof Error?s.message:String(s)].join(" "))}return Ve(n)}}function Xe(r){return kr("sha256").update(r).digest().subarray(0,V)}function et(r){return Buffer.from(`${Mr}${r}`,"utf8")}function Ee(r){return r.byteLength<O.length?!1:Buffer.from(r).subarray(0,O.length).equals(O)}function tt(r,t,e){if(e.byteLength!==be)throw new C("REMOTE_ENCRYPTION_KEY_INVALID_LENGTH","AES-256-GCM requires a 32-byte key.");let n=typeof t=="string"?Buffer.from(t,"utf8"):Buffer.from(t),s=Tr(J),i=vr(Qe,e,s);i.setAAD(et(r));let c=Buffer.concat([i.update(n),i.final()]),u=i.getAuthTag(),p=Buffer.alloc(qe),m=0;return O.copy(p,m),m+=O.length,p.writeUInt8(Je,m),m+=1,Xe(e).copy(p,m),m+=V,s.copy(p,m),m+=J,u.copy(p,m),Buffer.concat([p,c])}function rt(r,t,e){let n=Buffer.from(t);if(!Ee(n))throw new C("REMOTE_ENCRYPTION_ENVELOPE_REQUIRED","Payload is not a ToolNet encrypted remote object.");if(n.length<qe)throw new C("REMOTE_ENCRYPTION_ENVELOPE_TRUNCATED","Encrypted remote payload is truncated.");let s=O.length,i=n.readUInt8(s);if(s+=1,i!==Je)throw new C("REMOTE_ENCRYPTION_VERSION_UNSUPPORTED",`Unsupported remote encryption envelope version: ${i}.`);let c=n.subarray(s,s+V);s+=V;let u=Xe(e);if(!Ar(c,u))throw new C("REMOTE_ENCRYPTION_KEY_MISMATCH","Configured remote encryption key does not match this encrypted object.");let p=n.subarray(s,s+J);s+=J;let m=n.subarray(s,s+Se);s+=Se;let P=n.subarray(s),k=Pr(Qe,e,p);k.setAAD(et(r)),k.setAuthTag(m);try{return Buffer.concat([k.update(P),k.final()])}catch{throw new C("REMOTE_ENCRYPTION_AUTH_FAILED","Encrypted remote object failed AES-GCM authentication.")}}var Ce=class{constructor(t,e){this.inner=t;this.options=e;if(this.name=t.name,e.enabled&&!e.key)throw new C("REMOTE_ENCRYPTION_KEY_REQUIRED","Remote client-side encryption is enabled but no encryption key is configured.")}inner;options;name;async put(t,e,n){if(!this.options.enabled){await this.inner.put(t,e,n);return}let s=this.options.key;if(!s)throw new C("REMOTE_ENCRYPTION_KEY_REQUIRED","Remote encryption key is unavailable.");let i=tt(t,e,s);await this.inner.put(t,i,"application/octet-stream")}async get(t){let e=await this.inner.get(t);if(!e)return null;if(!Ee(e))return e;if(!this.options.enabled)throw new C("REMOTE_ENCRYPTION_REQUIRED",["Remote object is client-side encrypted.","Enable TOOLNET_REMOTE_ENCRYPTION and configure the matching key."].join(" "));let n=this.options.key;if(!n)throw new C("REMOTE_ENCRYPTION_KEY_REQUIRED","Remote object is encrypted but no decryption key is configured.");return rt(t,e,n)}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){return this.inner.exists(t)}async delete(t){await this.inner.delete(t)}async list(t=""){return this.inner.list(t)}};function nt(r,t=process.env){if(r.name==="local")return xe(t)&&console.warn("[storage] Remote encryption requested but active storage provider is local; local data remains unchanged."),r;let e=xe(t),n=e?Ze(t):void 0;return new Ce(r,{enabled:e,key:n})}function q(r){return nt(r)}function we(r,t){return console.warn(t),q(new W(r))}function st(r){let t=r.localRoot??_r(Lr(),".toolnet-memory","storage");if(r.provider==="r2"){let e=r.r2;return e?.accountId&&e.bucket&&e.accessKeyId&&e.secretAccessKey?q(new Y({name:"r2",endpoint:`https://${e.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:e.bucket,forcePathStyle:!0,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey})):we(t,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let e=r.s3;return e?.bucket&&e.accessKeyId&&e.secretAccessKey?q(new Y({name:"s3",endpoint:e.endpoint,region:e.region??"us-east-1",bucket:e.bucket,forcePathStyle:e.forcePathStyle??!1,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey})):we(t,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let e=r.huggingface;return e?.namespace&&e.bucket&&e.accessKeyId&&e.secretAccessKey?q(new ue({namespace:e.namespace,bucket:e.bucket,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey})):we(t,"[storage] Hugging Face credentials missing. Using local fallback.")}return q(new W(t))}function Or(r){return new Promise(t=>setTimeout(t,r))}async function ot(r,t={}){let e=Math.max(1,t.attempts??3),n=t.baseDelayMs??150,s=t.maxDelayMs??2e3,i;for(let c=1;c<=e;c++)try{return await r()}catch(u){if(i=u,c>=e)break;let p=Math.min(s,n*2**(c-1)),m=Math.floor(Math.random()*Math.max(1,p*.2));await Or(p+m)}throw i}var jr=new Set(["put","get","getText","delete","list"]);function it(r,t={}){return new Proxy(r,{get(e,n){let s=Reflect.get(e,n,e);return typeof s!="function"?s:jr.has(n)?(...i)=>ot(()=>Promise.resolve(s.apply(e,i)),t):s.bind(e)}})}import{timingSafeEqual as Dr}from"node:crypto";var Fr=24;function F(r){return r.trim().toLowerCase().replace(/^\[/u,"").replace(/\]$/u,"")}function $r(r){let t=F(r);return t==="0.0.0.0"||t==="::"||t==="0:0:0:0:0:0:0:0"}function Q(r){let t=F(r);return!!(t==="localhost"||t==="::1"||t==="0:0:0:0:0:0:0:1"||/^127(?:\.\d{1,3}){3}$/u.test(t)||t==="::ffff:127.0.0.1")}function ct(r){let t=r.trim();if(!t)return null;try{let e=new URL(t.includes("://")?t:`http://${t}`);return F(e.hostname)}catch{return null}}function at(r){let t=r.trim();if(!t)return null;try{let e=new URL(t.includes("://")?t:`http://${t}`),n=F(e.hostname);return n?e.port?`${n}:${e.port}`:n:null}catch{return null}}function lt(r){if(!r?.trim())return[];let t=new Set;for(let e of r.split(",")){let n=ct(e);n&&t.add(n)}return[...t].sort()}function dt(r,t,e=[]){if(!t)return!1;let n=ct(t);if(!n)return!1;let s=new Set(e.map(F));return s.has(n)?!0:Q(r)?Q(n):$r(r)?s.size>0?Q(n):!0:F(r)===n}function ut(r,t){if(!r)return!0;if(!t)return!1;let e=at(r),n=at(t);return!e||!n?!1:e===n}function Gr(r,t){let e=Buffer.from(r,"utf8"),n=Buffer.from(t,"utf8");return e.length!==n.length?!1:Dr(e,n)}function pt(r,t){if(!t)return!0;if(!r)return!1;let e=r.match(/^Bearer[ \t]+(.+)$/iu);return e?.[1]?Gr(e[1].trim(),t):!1}function ft(r){return r?Buffer.byteLength(r,"utf8")>=Fr:!1}function mt(r){r.setHeader("x-content-type-options","nosniff"),r.setHeader("x-frame-options","DENY"),r.setHeader("referrer-policy","no-referrer"),r.setHeader("cross-origin-resource-policy","same-origin"),r.setHeader("permissions-policy",["camera=()","microphone=()","geolocation=()"].join(", ")),r.setHeader("content-security-policy",["default-src 'self'","script-src 'self' 'unsafe-inline'","style-src 'self' 'unsafe-inline'","connect-src 'self'","img-src 'self' data:","object-src 'none'","base-uri 'none'","frame-ancestors 'none'","form-action 'none'"].join("; "))}var ve=Number(process.env.TOOLNET_GRAPH_PORT??9749),Z=process.env.TOOLNET_GRAPH_HOST??"127.0.0.1",pe=process.env.TOOLNET_GRAPH_TOKEN?.trim()||void 0,ht=lt(process.env.TOOLNET_GRAPH_ALLOWED_HOSTS);function zr(r){if(typeof r=="string")return r;if(!r||typeof r!="object")return null;let t=r;for(let e of["key","Key","path","name"])if(typeof t[e]=="string")return t[e];return null}async function Ur(r,t){return(await r.list(t)).map(zr).filter(n=>!!n)}async function X(r,t){let e=await r.getText(t);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async function Wr(r){let t=await Ur(r,"projects/"),e=[...new Set(t.filter(i=>/^projects\/[^/]+\/project\.json$/.test(i)).map(i=>i.split("/")[1]))],n=new Set(t),s=[];for(let i of e){let c=await X(r,`projects/${i}/project.json`);!c||typeof c.id!="string"||s.push({id:c.id,name:typeof c.name=="string"?c.name:i,remote:i,hasGraph:n.has(`projects/${i}/code/graph/current.json`),hasArchitecture:n.has(`projects/${i}/code/architecture/current.json`),hasAnalysis:n.has(`projects/${i}/code/analysis/current.json`),hasVisualization:n.has(`projects/${i}/code/visualization/graph.json`)})}return s.sort((i,c)=>i.name.localeCompare(c.name))}async function Yr(){Q(Z)||(console.warn(`[graph-ui] WARNING: Graph UI is exposed on non-loopback host ${Z}:${ve}.`),console.warn(pe?"[graph-ui] Bearer authentication is enabled for Graph API endpoints.":"[graph-ui] WARNING: Graph API has no bearer token. Set TOOLNET_GRAPH_TOKEN before exposing this port to an untrusted network."),ht.length===0&&console.warn("[graph-ui] TIP: Set TOOLNET_GRAPH_ALLOWED_HOSTS to restrict accepted Host headers when using a public/reverse-proxy endpoint.")),pe&&!ft(pe)&&console.warn("[graph-ui] WARNING: TOOLNET_GRAPH_TOKEN is short. Use at least 24 random bytes.");let r=Ae(),t=new ae().detect(),e=it(st({provider:r.storage.provider,huggingface:r.storage.huggingface,localRoot:r.storage.localRoot}),{attempts:3});e.name!=="huggingface"&&console.warn("[graph-ui] Remote Hugging Face storage is not active.");let n=Hr(Br(import.meta.url)),s=Re(n,"public"),i=Re(s,"vendor","3d-force-graph.min.js");async function c(){let a=await Wr(e),o=t.remote??t.name,d=a.find(b=>b.remote===o&&b.hasGraph),w=a.find(b=>b.hasGraph);return{projects:a,defaultProject:d?.remote??w?.remote??null}}let u=new Map;function p(a){return String(typeof a=="object"&&a!==null?a.id:a)}function m(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 k(a){let o=`projects/${a.remote}`,d=await X(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 w=await X(e,`${o}/code/architecture/current.json`),b=await X(e,`${o}/code/analysis/current.json`),x=new z;x.import(d.symbols,d.edges);let E=new de(x).build(a.id,w,b);return await e.put(`${o}/code/visualization/graph.json`,JSON.stringify(E),"application/json"),{...E,dashboard:P(a)}}async function A(a,o=!1){o&&u.delete(a.remote);let d=u.get(a.remote);if(d)return d;let w=`projects/${a.remote}`,b=await X(e,`${w}/code/visualization/graph.json`);if(b&&Array.isArray(b.nodes)&&Array.isArray(b.links)){let E={...b,dashboard:P(a)};return u.set(a.remote,E),E}let x=await k(a);return u.set(a.remote,x),x}function N(a,o){let d=new Map,w=new Map;for(let f of o.nodes){let g=m(f),y=`cluster:${g}`;w.set(f.id,y);let l=d.get(y);l||(l={id:y,name:g,qualifiedName:g,type:"subsystem",filePath:"",clusterLabel:g,incoming:0,outgoing:0,memberCount:0,files:new Set,viewKind:"cluster"},d.set(y,l)),l.memberCount+=1,f.filePath&&l.files.add(f.filePath)}let b=new Map;for(let f of o.links){let g=w.get(p(f.source)),y=w.get(p(f.target));if(!g||!y||g===y)continue;let l=`${g}\0${y}`,S=b.get(l);S||(S={source:g,target:y,type:"SUBSYSTEM_DEPENDENCY",count:0},b.set(l,S)),S.count+=1}for(let f of b.values()){let g=d.get(f.source),y=d.get(f.target);g&&(g.outgoing+=f.count),y&&(y.incoming+=f.count)}let x=[...d.values()].map(f=>({...f,filePath:`${f.files.size} files \xB7 ${f.memberCount} symbols`,files:void 0})),E=[...b.values()];return{version:2,projectId:o.projectId,generatedAt:o.generatedAt,summary:{nodes:x.length,links:E.length,files:o.summary?.files??0,clusters:x.length},nodes:x,links:E,dashboard:P(a,{viewMode:"overview",totalNodes:o.nodes.length,totalLinks:o.links.length})}}function ee(a,o,d){let w=o.nodes.filter(l=>!d||m(l)===d),b=new Set(w.map(l=>l.id)),x=new Map,E=new Map;for(let l of w){let S=l.filePath||"(unknown)";x.set(l.id,S);let R=E.get(S);R||(R={id:`file:${S}`,name:S.split("/").pop()||S,qualifiedName:S,type:"file",filePath:S,clusterLabel:m(l),incoming:0,outgoing:0,memberCount:0,viewKind:"file"},E.set(S,R)),R.memberCount+=1}let f=new Map;for(let l of o.links){let S=p(l.source),R=p(l.target);if(!b.has(S)||!b.has(R))continue;let fe=x.get(S),me=x.get(R);if(!fe||!me||fe===me)continue;let Pe=`file:${fe}`,ke=`file:${me}`,Te=`${Pe}\0${ke}`,re=f.get(Te);re||(re={source:Pe,target:ke,type:"FILE_DEPENDENCY",count:0},f.set(Te,re)),re.count+=1}for(let l of f.values()){let S=E.get(String(l.source).slice(5)),R=E.get(String(l.target).slice(5));S&&(S.outgoing+=l.count),R&&(R.incoming+=l.count)}let g=[...E.values()],y=[...f.values()];return{version:2,projectId:o.projectId,generatedAt:o.generatedAt,summary:{nodes:g.length,links:y.length,files:g.length,clusters:d?1:0},nodes:g,links:y,dashboard:P(a,{viewMode:"files",selection:d,totalNodes:o.nodes.length,totalLinks:o.links.length})}}function j(a,o,d){let x=o.nodes.filter(l=>l.filePath===d),E=new Set(x.map(l=>l.id)),f=new Set;for(let l of x.slice(0,1800))f.add(l.id);for(let l of o.links){if(f.size>=1800)break;let S=p(l.source),R=p(l.target);(E.has(S)||E.has(R))&&(f.add(S),f.size<1800&&f.add(R))}let g=o.nodes.filter(l=>f.has(l.id)).map(l=>({...l,viewKind:"symbol"})),y=[];for(let l of o.links){if(y.length>=12e3)break;let S=p(l.source),R=p(l.target);f.has(S)&&f.has(R)&&y.push({...l,source:S,target:R})}return{version:2,projectId:o.projectId,generatedAt:o.generatedAt,summary:{nodes:g.length,links:y.length,files:new Set(g.map(l=>l.filePath)).size,clusters:new Set(g.map(l=>m(l))).size},nodes:g,links:y,dashboard:P(a,{viewMode:"symbols",selection:d,focused:!0,truncated:g.length>=1800||y.length>=12e3,totalNodes:o.nodes.length,totalLinks:o.links.length})}}Kr(async(a,o)=>{try{mt(o);let d=new URL(a.url??"/",`http://${a.headers.host??"localhost"}`);if(!dt(Z,a.headers.host,ht)){o.statusCode=421,o.setHeader("content-type","application/json; charset=utf-8"),o.setHeader("cache-control","no-store"),o.end(JSON.stringify({error:"misdirected_request"}));return}if(d.pathname==="/api/health"){o.setHeader("content-type","application/json; charset=utf-8"),o.setHeader("cache-control","no-store"),o.end(JSON.stringify({ok:!0,service:"toolnet-memory-graph"}));return}if(d.pathname.startsWith("/api/")){if(a.method!=="GET"&&a.method!=="HEAD"){o.statusCode=405,o.setHeader("allow","GET, HEAD"),o.setHeader("content-type","application/json; charset=utf-8"),o.setHeader("cache-control","no-store"),o.end(JSON.stringify({error:"method_not_allowed"}));return}if(!ut(a.headers.origin,a.headers.host)){o.statusCode=403,o.setHeader("content-type","application/json; charset=utf-8"),o.setHeader("cache-control","no-store"),o.end(JSON.stringify({error:"forbidden_origin"}));return}if(!pt(a.headers.authorization,pe)){o.statusCode=401,o.setHeader("www-authenticate",'Bearer realm="ToolNet Graph"'),o.setHeader("content-type","application/json; charset=utf-8"),o.setHeader("cache-control","no-store"),o.end(JSON.stringify({error:"unauthorized"}));return}}if(d.pathname==="/api/projects"){let w=await c();o.setHeader("content-type","application/json; charset=utf-8"),o.setHeader("cache-control","no-store"),o.end(JSON.stringify(w));return}if(d.pathname==="/api/graph"){let w=await c(),b=d.searchParams.get("project")??w.defaultProject;if(!b){o.statusCode=404,o.setHeader("content-type","application/json; charset=utf-8"),o.end(JSON.stringify({error:"No indexed ToolNet project found."}));return}let x=w.projects.find(l=>l.remote===b);if(!x){o.statusCode=404,o.setHeader("content-type","application/json; charset=utf-8"),o.end(JSON.stringify({error:"Project not found.",project:b}));return}if(!x.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:x}));return}let E=d.searchParams.get("refresh")==="1",f=await A(x,E),g=d.searchParams.get("mode")??"full",y=f;if(g==="overview")y=N(x,f);else if(g==="files")y=ee(x,f,d.searchParams.get("cluster")??"");else if(g==="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=j(x,f,l)}else if(g!=="full"){o.statusCode=400,o.setHeader("content-type","application/json; charset=utf-8"),o.end(JSON.stringify({error:`Unknown graph mode: ${g}`}));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"),gt(i).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"),gt(Re(s,"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(ve,Z,()=>{console.log("ToolNet Multi-Project 3D Graph"),console.log(`Listening: http://${Z}:${ve}`)})}Yr().catch(r=>{console.error(r),process.exit(1)});