toolnet-memory 0.3.5 → 0.3.6

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.
@@ -1,4 +1,4 @@
1
1
  import"dotenv/config";import{existsSync as ce,readFileSync as le}from"node:fs";import{homedir as de}from"node:os";import{join as pe}from"node:path";function ue(s){let e=s.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
2
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 me(){let s=process.env.TOOLNET_GLOBAL_ENV??pe(de(),".config","toolnet-memory",".env");if(!ce(s))return;let e=le(s,"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 o=r.indexOf("=");if(o<=0)continue;let n=r.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(n)&&process.env[n]===void 0&&(process.env[n]=ue(r.slice(o+1)))}}me();function v(s,e){return s===void 0?e:["1","true","yes","on"].includes(s.toLowerCase())}function P(s,e){if(!s)return e;let t=Number(s);return Number.isFinite(t)?t:e}function V(){return{memory:{autoCapture:v(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:v(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:v(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:v(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:P(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:P(process.env.MEMORY_RERANK_TOP,10),finalContext:P(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:P(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:v(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:P(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as fe}from"node:crypto";import{existsSync as D,mkdirSync as ge,readFileSync as he,renameSync as ye,writeFileSync as Se}from"node:fs";import{basename as be,dirname as N,join as O,parse as J,resolve as k}from"node:path";var Q=".toolnet",xe="project.json";function Ce(s){return fe("sha256").update(s).digest("hex").slice(0,16)}function G(s){return O(s,Q,xe)}function we(s){return D(G(s))}function Ee(s,e){let t=k(s),r=J(t).root;for(;;){if(we(t))return t;if(t===r||e&&t===k(e))break;let o=N(t);if(o===t)break;t=o}return null}function ve(s){let e=k(s),t=J(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(n=>D(O(e,n))))return e;if(e===t)break;let o=N(e);if(o===e)break;e=o}return k(s)}function Pe(s){let e;try{e=JSON.parse(he(s,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${s}: ${o instanceof Error?o.message:String(o)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${s}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${s}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${s}`);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:N(N(s)),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 Y(s,e){let t=O(s,Q);ge(t,{recursive:!0});let r=G(s),o=`${r}.tmp-${process.pid}`;Se(o,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),ye(o,r)}function q(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 I=class{detect(e=process.cwd()){let t=k(e),r=ve(t),n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>D(O(r,m))),i=Ee(t,n?r:void 0);if(i){let m=G(i),u=Pe(m);return u.rootPath!==i&&(u.rootPath=i,u.updatedAt=new Date().toISOString(),Y(i,u)),q(u,i)}let d=new Date().toISOString(),f=be(r),c={version:1,id:Ce(r),name:f,remote:f,rootPath:r,createdAt:d,updatedAt:d,graphVersion:0,memoryVersion:0};return Y(r,c),q(c,r)}};import{readdir as Ae}from"node:fs/promises";import{extname as Le,join as Me,relative as Ne}from"node:path";import{basename as Re}from"node:path";var Te=new Set([".env",".env.local",".env.production",".env.development","id_rsa","id_ed25519","credentials","credentials.json","service-account.json"]),je=new Set([".pem",".key",".p12",".pfx"]);function Z(s){let e=Re(s).toLowerCase();if(Te.has(e))return!0;for(let t of je)if(e.endsWith(t))return!0;return!1}var Ie=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".mts",".cts"]),Oe=new Set(["node_modules",".git","dist","build","coverage",".next",".cache",".toolnet-memory"]);async function K(s){let e=[];async function t(r){let o=await Ae(r,{withFileTypes:!0});for(let n of o){if(Oe.has(n.name))continue;let i=Me(r,n.name);if(n.isDirectory()){await t(i);continue}Ie.has(Le(n.name))&&(Z(i)||e.push(Ne(s,i)))}}return await t(s),e.sort()}import{readFile as _e}from"node:fs/promises";import{join as Fe}from"node:path";import{createHash as $e}from"node:crypto";import*as l from"typescript";function X(s,e){return $e("sha256").update(`${s}:${e}`).digest("hex").slice(0,24)}function z(s,e){return s.getLineAndCharacterOfPosition(e.getStart(s)).line+1}async function B(s,e,t){let r=Fe(e,t),o=await _e(r,"utf8"),n=l.createSourceFile(t,o,l.ScriptTarget.Latest,!0,t.endsWith(".tsx")||t.endsWith(".jsx")?l.ScriptKind.TSX:l.ScriptKind.TS),i=[],d=[],f=[],c=[],m={id:X(s,`file:${t}`),projectId:s,name:t,qualifiedName:t,type:"file",filePath:t,startLine:1,endLine:n.getLineAndCharacterOfPosition(n.end).line+1};i.push(m);let u=[],x=[];function b(a,y,h,g){let C=X(s,`${t}:${h}:${g??y}:${a.pos}`);return i.push({id:C,projectId:s,name:y,qualifiedName:g??y,type:h,filePath:t,startLine:z(n,a),endLine:n.getLineAndCharacterOfPosition(a.end).line+1}),C}function M(a){if(!l.isStringLiteral(a.moduleSpecifier))return;let y=[],h=a.importClause;if(h?.name&&y.push({localName:h.name.text,importedName:"default",kind:"default"}),h?.namedBindings&&l.isNamedImports(h.namedBindings))for(let g of h.namedBindings.elements)y.push({localName:g.name.text,importedName:g.propertyName?.text??g.name.text,kind:"named"});h?.namedBindings&&l.isNamespaceImport(h.namedBindings)&&y.push({localName:h.namedBindings.name.text,importedName:"*",kind:"namespace"}),d.push({source:a.moduleSpecifier.text,bindings:y})}function E(a,y){for(let h of a.heritageClauses??[])for(let g of h.types){let C=g.expression.getText(n).split(".").at(-1)??"";C&&c.push({fromId:y,targetName:C,type:h.token===l.SyntaxKind.ExtendsKeyword?"INHERITS":"IMPLEMENTS"})}}function U(a){let y=!1,h=!1;if(l.isImportDeclaration(a)&&M(a),l.isInterfaceDeclaration(a)&&b(a,a.name.text,"interface",a.name.text),l.isClassDeclaration(a)&&a.name){let g=b(a,a.name.text,"class",a.name.text);E(a,g),x.push({id:g,name:a.name.text}),h=!0}if(l.isFunctionDeclaration(a)&&a.name){let g=b(a,a.name.text,"function",a.name.text);u.push(g),y=!0}if(l.isMethodDeclaration(a)&&a.name){let g=a.name.getText(n),C=x.at(-1)?.name,ae=b(a,g,"method",C?`${C}.${g}`:g);u.push(ae),y=!0}if(l.isCallExpression(a)&&(l.isIdentifier(a.expression)&&f.push({callerId:u.at(-1),calleeName:a.expression.text,line:z(n,a)}),l.isPropertyAccessExpression(a.expression))){let g=a.expression;f.push({callerId:u.at(-1),qualifier:g.expression.getText(n),calleeName:g.name.text,line:z(n,a)})}l.forEachChild(a,U),y&&u.pop(),h&&x.pop()}return U(n),{filePath:t,symbols:i,imports:d,calls:f,heritage:c}}import{createHash as De}from"node:crypto";import{dirname as Ge,extname as Ke,normalize as ze,posix as Be}from"node:path";var R=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 We(s,e,t,r){return De("sha256").update(`${s}:${e}:${t}:${r}`).digest("hex").slice(0,24)}function w(s){return ze(s).replaceAll("\\","/")}function W(s,e,t){if(!e.startsWith("."))return;let r=w(Be.join(Ge(s),e)),o=Ke(r),n;if(o===".js"){let i=r.slice(0,-3);n=[`${i}.ts`,`${i}.tsx`,`${i}.js`,`${i}.jsx`]}else if(o===".mjs"){let i=r.slice(0,-4);n=[`${i}.mts`,`${i}.ts`,`${i}.mjs`]}else if(o===".cjs"){let i=r.slice(0,-4);n=[`${i}.cts`,`${i}.ts`,`${i}.cjs`]}else o?n=[r]:n=[`${r}.ts`,`${r}.tsx`,`${r}.mts`,`${r}.cts`,`${r}.js`,`${r}.jsx`,`${r}.mjs`,`${r}.cjs`,`${r}/index.ts`,`${r}/index.tsx`,`${r}/index.js`,`${r}/index.jsx`];return n.find(i=>t.has(w(i)))}var T=class{build(e,t){let r=new R,o=new Map;for(let i of t)for(let d of i.symbols)r.addSymbol(d),d.type==="file"&&o.set(w(i.filePath),d);let n=new Set(o.keys());for(let i of t){let d=w(i.filePath),f=o.get(d);if(f){for(let c of i.symbols)c.id!==f.id&&r.addEdge(this.edge(e,f.id,"DEFINES",c.id));for(let c of i.imports){let m=W(d,c.source,n);if(!m)continue;let u=o.get(m);u&&r.addEdge(this.edge(e,f.id,"IMPORTS",u.id,{source:c.source}))}for(let c of i.heritage){let m=r.findByName(e,c.targetName).filter(u=>u.type==="class"||u.type==="interface");for(let u of m)r.addEdge(this.edge(e,c.fromId,c.type,u.id))}for(let c of i.calls){if(!c.callerId)continue;let m=this.resolveCallTargets(e,i,c.calleeName,c.qualifier,t,r,n);for(let u of m)u.id!==c.callerId&&r.addEdge(this.edge(e,c.callerId,"CALLS",u.id,{line:c.line,qualifier:c.qualifier}))}}}return r}resolveCallTargets(e,t,r,o,n,i,d){let f=w(t.filePath),c=i.findByName(e,r).filter(m=>w(m.filePath)===f);if(!o&&c.length)return c;if(o)for(let m of t.imports){if(!m.bindings.find(b=>b.kind==="namespace"&&b.localName===o))continue;let x=W(f,m.source,d);if(x)return i.findByName(e,r).filter(b=>w(b.filePath)===x)}for(let m of t.imports){let u=m.bindings.find(E=>E.localName===r);if(!u)continue;let x=W(f,m.source,d);if(!x)continue;let b=u.importedName==="default"?r:u.importedName,M=i.findByName(e,b).filter(E=>w(E.filePath)===x);if(M.length)return M}return i.findByName(e,r).filter(m=>m.type==="function"||m.type==="method")}edge(e,t,r,o,n){return{id:We(e,t,r,o),projectId:e,from:t,to:o,type:r,metadata:n}}};var _=class{async index(e,t,r={}){let o=await K(t);r.onProgress?.({phase:"scan",current:o.length,total:o.length});let n=[],i=0;for(let f of o)try{n.push(await B(e,t,f))}catch(c){console.warn(`[indexer] skipped ${f}:`,c instanceof Error?c.message:c)}finally{i+=1,r.onProgress?.({phase:"parse",current:i,total:o.length,file:f})}let d=new T().build(e,n);return{files:n.length,symbols:d.allSymbols(e).length,edges:d.allEdges(e).length,graph:d}}};function ee(s,e){let t=s.allSymbols(e),r=s.allEdges(e),o=i=>t.filter(d=>d.type===i).length,n=i=>r.filter(d=>d.type===i).length;return{files:o("file"),classes:o("class"),interfaces:o("interface"),functions:o("function"),methods:o("method"),properties:o("property"),routes:o("route"),symbols:t.length,edges:r.length,calls:n("CALLS"),callReferences:n("CALL_REFERENCE"),imports:n("IMPORTS"),inherits:n("INHERITS"),implements:n("IMPLEMENTS"),usesType:n("USES_TYPE"),tests:n("TESTS"),routeEdges:n("ROUTE"),writes:n("WRITES")}}import{execFile as He}from"node:child_process";import{promisify as Ue}from"node:util";var Nr=Ue(He);var j=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 S from"typescript";import*as p from"typescript";var Us=new Set([p.SyntaxKind.EqualsToken,p.SyntaxKind.PlusEqualsToken,p.SyntaxKind.MinusEqualsToken,p.SyntaxKind.AsteriskEqualsToken,p.SyntaxKind.SlashEqualsToken,p.SyntaxKind.PercentEqualsToken,p.SyntaxKind.QuestionQuestionEqualsToken,p.SyntaxKind.AmpersandAmpersandEqualsToken,p.SyntaxKind.BarBarEqualsToken]);import{homedir as ht}from"node:os";import{join as yt}from"node:path";import{DeleteObjectCommand as Ye,GetObjectCommand as qe,HeadObjectCommand as Je,ListObjectsV2Command as Qe,PutObjectCommand as Ze,S3Client as Xe}from"@aws-sdk/client-s3";import{getSignedUrl as et}from"@aws-sdk/s3-request-presigner";var F=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Xe({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 o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Ze({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await et(this.client,new qe({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 Je({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 Ye({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let o=await this.client.send(new Qe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let n of o.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});r=o.IsTruncated?o.NextContinuationToken:void 0}while(r);return t}};import{access as te,mkdir as tt,readFile as rt,readdir as st,rm as ot,stat as re,writeFile as nt}from"node:fs/promises";import{dirname as it,join as at,relative as se,resolve as ct}from"node:path";var A=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return ct(this.root,t)}async put(e,t){let r=this.path(e);await tt(it(r),{recursive:!0}),await nt(r,t)}async get(e){try{return await rt(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 te(this.path(e)),!0}catch{return!1}}async delete(e){await ot(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await te(t)}catch{return r}let o=async i=>{let d=await st(i,{withFileTypes:!0});for(let f of d){let c=at(i,f.name);if(f.isDirectory()){await o(c);continue}let m=await re(c);r.push({key:se(this.root,c),size:m.size,updatedAt:m.mtime.toISOString()})}},n=await re(t);return n.isDirectory()?await o(t):r.push({key:se(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),r}};import{DeleteObjectCommand as lt,GetObjectCommand as dt,HeadObjectCommand as pt,ListObjectsV2Command as ut,PutObjectCommand as mt,S3Client as ft}from"@aws-sdk/client-s3";import{getSignedUrl as gt}from"@aws-sdk/s3-request-presigner";var L=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new ft({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 o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new mt({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await gt(this.client,new dt({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 pt({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 o=await this.client.send(new ut({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let n of o.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});r=o.IsTruncated?o.NextContinuationToken:void 0}while(r);return t}};function H(s,e){return console.warn(e),new A(s)}function oe(s){let e=s.localRoot??yt(ht(),".toolnet-memory","storage");if(s.provider==="r2"){let t=s.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new L({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):H(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 L({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):H(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 F({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):H(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new A(e)}function ne(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 ie(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 o=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return o?`${o[1]}memory/records/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),o?`${o[1]}memory/vectors/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),o?`${o[1]}code/graph/${o[2]}`:e))}var $=class{constructor(e,t,r,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=ne(o??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,o=await this.provider.getText(e);if(o){let i;try{i=JSON.parse(o)}catch(d){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${d instanceof Error?d.message:String(d)}`)}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 n={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:t};await this.provider.put(e,JSON.stringify(n,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),ye(o,r)}function q(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 I=class{detect(e=process.cwd()){let t=k(e),r=ve(t),n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>D(O(r,m))),i=Ee(t,n?r:void 0);if(i){let m=G(i),u=Pe(m);return u.rootPath!==i&&(u.rootPath=i,u.updatedAt=new Date().toISOString(),Y(i,u)),q(u,i)}let d=new Date().toISOString(),f=be(r),c={version:1,id:Ce(r),name:f,remote:f,rootPath:r,createdAt:d,updatedAt:d,graphVersion:0,memoryVersion:0};return Y(r,c),q(c,r)}};import{readdir as Ae}from"node:fs/promises";import{extname as Me,join as Le,relative as Ne}from"node:path";import{basename as Re}from"node:path";var Te=new Set([".env",".env.local",".env.production",".env.development","id_rsa","id_ed25519","credentials","credentials.json","service-account.json"]),je=new Set([".pem",".key",".p12",".pfx"]);function Z(s){let e=Re(s).toLowerCase();if(Te.has(e))return!0;for(let t of je)if(e.endsWith(t))return!0;return!1}var Ie=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".mts",".cts"]),Oe=new Set(["node_modules",".git","dist","build","coverage",".next",".cache",".toolnet-memory"]);async function K(s){let e=[];async function t(r){let o=await Ae(r,{withFileTypes:!0});for(let n of o){if(Oe.has(n.name))continue;let i=Le(r,n.name);if(n.isDirectory()){await t(i);continue}Ie.has(Me(n.name))&&(Z(i)||e.push(Ne(s,i)))}}return await t(s),e.sort()}import{readFile as _e}from"node:fs/promises";import{join as Fe}from"node:path";import{createHash as $e}from"node:crypto";import*as l from"typescript";function X(s,e){return $e("sha256").update(`${s}:${e}`).digest("hex").slice(0,24)}function z(s,e){return s.getLineAndCharacterOfPosition(e.getStart(s)).line+1}async function B(s,e,t){let r=Fe(e,t),o=await _e(r,"utf8"),n=l.createSourceFile(t,o,l.ScriptTarget.Latest,!0,t.endsWith(".tsx")||t.endsWith(".jsx")?l.ScriptKind.TSX:l.ScriptKind.TS),i=[],d=[],f=[],c=[],m={id:X(s,`file:${t}`),projectId:s,name:t,qualifiedName:t,type:"file",filePath:t,startLine:1,endLine:n.getLineAndCharacterOfPosition(n.end).line+1};i.push(m);let u=[],x=[];function b(a,y,h,g){let C=X(s,`${t}:${h}:${g??y}:${a.pos}`);return i.push({id:C,projectId:s,name:y,qualifiedName:g??y,type:h,filePath:t,startLine:z(n,a),endLine:n.getLineAndCharacterOfPosition(a.end).line+1}),C}function L(a){if(!l.isStringLiteral(a.moduleSpecifier))return;let y=[],h=a.importClause;if(h?.name&&y.push({localName:h.name.text,importedName:"default",kind:"default"}),h?.namedBindings&&l.isNamedImports(h.namedBindings))for(let g of h.namedBindings.elements)y.push({localName:g.name.text,importedName:g.propertyName?.text??g.name.text,kind:"named"});h?.namedBindings&&l.isNamespaceImport(h.namedBindings)&&y.push({localName:h.namedBindings.name.text,importedName:"*",kind:"namespace"}),d.push({source:a.moduleSpecifier.text,bindings:y})}function E(a,y){for(let h of a.heritageClauses??[])for(let g of h.types){let C=g.expression.getText(n).split(".").at(-1)??"";C&&c.push({fromId:y,targetName:C,type:h.token===l.SyntaxKind.ExtendsKeyword?"INHERITS":"IMPLEMENTS"})}}function U(a){let y=!1,h=!1;if(l.isImportDeclaration(a)&&L(a),l.isInterfaceDeclaration(a)&&b(a,a.name.text,"interface",a.name.text),l.isClassDeclaration(a)&&a.name){let g=b(a,a.name.text,"class",a.name.text);E(a,g),x.push({id:g,name:a.name.text}),h=!0}if(l.isFunctionDeclaration(a)&&a.name){let g=b(a,a.name.text,"function",a.name.text);u.push(g),y=!0}if(l.isMethodDeclaration(a)&&a.name){let g=a.name.getText(n),C=x.at(-1)?.name,ae=b(a,g,"method",C?`${C}.${g}`:g);u.push(ae),y=!0}if(l.isCallExpression(a)&&(l.isIdentifier(a.expression)&&f.push({callerId:u.at(-1),calleeName:a.expression.text,line:z(n,a)}),l.isPropertyAccessExpression(a.expression))){let g=a.expression;f.push({callerId:u.at(-1),qualifier:g.expression.getText(n),calleeName:g.name.text,line:z(n,a)})}l.forEachChild(a,U),y&&u.pop(),h&&x.pop()}return U(n),{filePath:t,symbols:i,imports:d,calls:f,heritage:c}}import{createHash as De}from"node:crypto";import{dirname as Ge,extname as Ke,normalize as ze,posix as Be}from"node:path";var R=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 We(s,e,t,r){return De("sha256").update(`${s}:${e}:${t}:${r}`).digest("hex").slice(0,24)}function w(s){return ze(s).replaceAll("\\","/")}function W(s,e,t){if(!e.startsWith("."))return;let r=w(Be.join(Ge(s),e)),o=Ke(r),n;if(o===".js"){let i=r.slice(0,-3);n=[`${i}.ts`,`${i}.tsx`,`${i}.js`,`${i}.jsx`]}else if(o===".mjs"){let i=r.slice(0,-4);n=[`${i}.mts`,`${i}.ts`,`${i}.mjs`]}else if(o===".cjs"){let i=r.slice(0,-4);n=[`${i}.cts`,`${i}.ts`,`${i}.cjs`]}else o?n=[r]:n=[`${r}.ts`,`${r}.tsx`,`${r}.mts`,`${r}.cts`,`${r}.js`,`${r}.jsx`,`${r}.mjs`,`${r}.cjs`,`${r}/index.ts`,`${r}/index.tsx`,`${r}/index.js`,`${r}/index.jsx`];return n.find(i=>t.has(w(i)))}var T=class{build(e,t){let r=new R,o=new Map;for(let i of t)for(let d of i.symbols)r.addSymbol(d),d.type==="file"&&o.set(w(i.filePath),d);let n=new Set(o.keys());for(let i of t){let d=w(i.filePath),f=o.get(d);if(f){for(let c of i.symbols)c.id!==f.id&&r.addEdge(this.edge(e,f.id,"DEFINES",c.id));for(let c of i.imports){let m=W(d,c.source,n);if(!m)continue;let u=o.get(m);u&&r.addEdge(this.edge(e,f.id,"IMPORTS",u.id,{source:c.source}))}for(let c of i.heritage){let m=r.findByName(e,c.targetName).filter(u=>u.type==="class"||u.type==="interface");for(let u of m)r.addEdge(this.edge(e,c.fromId,c.type,u.id))}for(let c of i.calls){if(!c.callerId)continue;let m=this.resolveCallTargets(e,i,c.calleeName,c.qualifier,t,r,n);for(let u of m)u.id!==c.callerId&&r.addEdge(this.edge(e,c.callerId,"CALLS",u.id,{line:c.line,qualifier:c.qualifier}))}}}return r}resolveCallTargets(e,t,r,o,n,i,d){let f=w(t.filePath),c=i.findByName(e,r).filter(m=>w(m.filePath)===f);if(!o&&c.length)return c;if(o)for(let m of t.imports){if(!m.bindings.find(b=>b.kind==="namespace"&&b.localName===o))continue;let x=W(f,m.source,d);if(x)return i.findByName(e,r).filter(b=>w(b.filePath)===x)}for(let m of t.imports){let u=m.bindings.find(E=>E.localName===r);if(!u)continue;let x=W(f,m.source,d);if(!x)continue;let b=u.importedName==="default"?r:u.importedName,L=i.findByName(e,b).filter(E=>w(E.filePath)===x);if(L.length)return L}return i.findByName(e,r).filter(m=>m.type==="function"||m.type==="method")}edge(e,t,r,o,n){return{id:We(e,t,r,o),projectId:e,from:t,to:o,type:r,metadata:n}}};var _=class{async index(e,t,r={}){let o=await K(t);r.onProgress?.({phase:"scan",current:o.length,total:o.length});let n=[],i=0;for(let f of o)try{n.push(await B(e,t,f))}catch(c){console.warn(`[indexer] skipped ${f}:`,c instanceof Error?c.message:c)}finally{i+=1,r.onProgress?.({phase:"parse",current:i,total:o.length,file:f})}let d=new T().build(e,n);return{files:n.length,symbols:d.allSymbols(e).length,edges:d.allEdges(e).length,graph:d}}};function ee(s,e){let t=s.allSymbols(e),r=s.allEdges(e),o=i=>t.filter(d=>d.type===i).length,n=i=>r.filter(d=>d.type===i).length;return{files:o("file"),classes:o("class"),interfaces:o("interface"),functions:o("function"),methods:o("method"),properties:o("property"),routes:o("route"),symbols:t.length,edges:r.length,calls:n("CALLS"),callReferences:n("CALL_REFERENCE"),imports:n("IMPORTS"),inherits:n("INHERITS"),implements:n("IMPLEMENTS"),usesType:n("USES_TYPE"),tests:n("TESTS"),routeEdges:n("ROUTE"),writes:n("WRITES")}}import{execFile as He}from"node:child_process";import{promisify as Ue}from"node:util";var Nr=Ue(He);var j=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 S from"typescript";import*as p from"typescript";var Us=new Set([p.SyntaxKind.EqualsToken,p.SyntaxKind.PlusEqualsToken,p.SyntaxKind.MinusEqualsToken,p.SyntaxKind.AsteriskEqualsToken,p.SyntaxKind.SlashEqualsToken,p.SyntaxKind.PercentEqualsToken,p.SyntaxKind.QuestionQuestionEqualsToken,p.SyntaxKind.AmpersandAmpersandEqualsToken,p.SyntaxKind.BarBarEqualsToken]);import{homedir as ht}from"node:os";import{join as yt}from"node:path";import{DeleteObjectCommand as Ye,GetObjectCommand as qe,HeadObjectCommand as Je,ListObjectsV2Command as Qe,PutObjectCommand as Ze,S3Client as Xe}from"@aws-sdk/client-s3";import{getSignedUrl as et}from"@aws-sdk/s3-request-presigner";var F=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Xe({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 o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Ze({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await et(this.client,new qe({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 Je({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 Ye({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let o=await this.client.send(new Qe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let n of o.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});r=o.IsTruncated?o.NextContinuationToken:void 0}while(r);return t}};import{access as te,mkdir as tt,readFile as rt,readdir as st,rm as ot,stat as re,writeFile as nt}from"node:fs/promises";import{dirname as it,join as at,relative as se,resolve as ct}from"node:path";var A=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return ct(this.root,t)}async put(e,t){let r=this.path(e);await tt(it(r),{recursive:!0}),await nt(r,t)}async get(e){try{return await rt(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 te(this.path(e)),!0}catch{return!1}}async delete(e){await ot(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await te(t)}catch{return r}let o=async i=>{let d=await st(i,{withFileTypes:!0});for(let f of d){let c=at(i,f.name);if(f.isDirectory()){await o(c);continue}let m=await re(c);r.push({key:se(this.root,c),size:m.size,updatedAt:m.mtime.toISOString()})}},n=await re(t);return n.isDirectory()?await o(t):r.push({key:se(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),r}};import{DeleteObjectCommand as lt,GetObjectCommand as dt,HeadObjectCommand as pt,ListObjectsV2Command as ut,PutObjectCommand as mt,S3Client as ft}from"@aws-sdk/client-s3";import{getSignedUrl as gt}from"@aws-sdk/s3-request-presigner";var M=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new ft({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 o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new mt({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await gt(this.client,new dt({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 pt({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 o=await this.client.send(new ut({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let n of o.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});r=o.IsTruncated?o.NextContinuationToken:void 0}while(r);return t}};function H(s,e){return console.warn(e),new A(s)}function oe(s){let e=s.localRoot??yt(ht(),".toolnet-memory","storage");if(s.provider==="r2"){let t=s.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new M({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):H(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 M({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):H(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 F({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):H(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new A(e)}function ne(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 ie(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 o=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return o?`${o[1]}memory/records/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),o?`${o[1]}memory/vectors/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),o?`${o[1]}code/graph/${o[2]}`:e))}var $=class{constructor(e,t,r,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=ne(o??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,o=await this.provider.getText(e);if(o){let i;try{i=JSON.parse(o)}catch(d){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${d instanceof Error?d.message:String(d)}`)}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 n={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:t};await this.provider.put(e,JSON.stringify(n,null,2)+`
4
4
  `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=ie(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 St(){let s=V(),e=new I().detect(),t=oe({provider:s.storage.provider,huggingface:s.storage.huggingface,localRoot:s.storage.localRoot}),r=new $(t,e.id,e.name,e.remote??e.name),o=await new _().index(e.id,e.rootPath),n=ee(o.graph,e.id);await new j(r).save({version:1,projectId:e.id,updatedAt:new Date().toISOString(),files:o.files,symbols:o.graph.allSymbols(e.id),edges:o.graph.allEdges(e.id)}),console.log({ok:!0,storage:r.name,...n})}St().catch(s=>{console.error(s),process.exit(1)});
package/bundle/impact.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import"dotenv/config";import{existsSync as se,readFileSync as oe}from"node:fs";import{homedir as ne}from"node:os";import{join as ie}from"node:path";function ae(s){let e=s.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
2
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 ce(){let s=process.env.TOOLNET_GLOBAL_ENV??ie(ne(),".config","toolnet-memory",".env");if(!se(s))return;let e=oe(s,"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 o=r.indexOf("=");if(o<=0)continue;let n=r.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(n)&&process.env[n]===void 0&&(process.env[n]=ae(r.slice(o+1)))}}ce();function y(s,e){return s===void 0?e:["1","true","yes","on"].includes(s.toLowerCase())}function S(s,e){if(!s)return e;let t=Number(s);return Number.isFinite(t)?t:e}function D(){return{memory:{autoCapture:y(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:y(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:y(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:y(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:S(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:S(process.env.MEMORY_RERANK_TOP,10),finalContext:S(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:S(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:y(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:S(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as le}from"node:crypto";import{existsSync as O,mkdirSync as de,readFileSync as pe,renameSync as ue,writeFileSync as me}from"node:fs";import{basename as fe,dirname as v,join as k,parse as z,resolve as b}from"node:path";var B=".toolnet",ge="project.json";function he(s){return le("sha256").update(s).digest("hex").slice(0,16)}function _(s){return k(s,B,ge)}function ye(s){return O(_(s))}function Se(s,e){let t=b(s),r=z(t).root;for(;;){if(ye(t))return t;if(t===r||e&&t===b(e))break;let o=v(t);if(o===t)break;t=o}return null}function be(s){let e=b(s),t=z(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(n=>O(k(e,n))))return e;if(e===t)break;let o=v(e);if(o===e)break;e=o}return b(s)}function xe(s){let e;try{e=JSON.parse(pe(s,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${s}: ${o instanceof Error?o.message:String(o)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${s}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${s}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${s}`);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:v(v(s)),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(s,e){let t=k(s,B);de(t,{recursive:!0});let r=_(s),o=`${r}.tmp-${process.pid}`;me(o,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),ue(o,r)}function K(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 P=class{detect(e=process.cwd()){let t=b(e),r=be(t),n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>O(k(r,d))),i=Se(t,n?r:void 0);if(i){let d=_(i),f=xe(d);return f.rootPath!==i&&(f.rootPath=i,f.updatedAt=new Date().toISOString(),G(i,f)),K(f,i)}let p=new Date().toISOString(),l=fe(r),c={version:1,id:he(r),name:l,remote:l,rootPath:r,createdAt:p,updatedAt:p,graphVersion:0,memoryVersion:0};return G(r,c),K(c,r)}};import{homedir as We}from"node:os";import{join as He}from"node:path";import{DeleteObjectCommand as we,GetObjectCommand as Ee,HeadObjectCommand as ve,ListObjectsV2Command as Pe,PutObjectCommand as ke,S3Client as Re}from"@aws-sdk/client-s3";import{getSignedUrl as Te}from"@aws-sdk/s3-request-presigner";var R=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Re({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 o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new ke({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await Te(this.client,new Ee({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 ve({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 we({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let o=await this.client.send(new Pe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let n of o.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});r=o.IsTruncated?o.NextContinuationToken:void 0}while(r);return t}};import{access as W,mkdir as je,readFile as Ae,readdir as Le,rm as Me,stat as H,writeFile as Ne}from"node:fs/promises";import{dirname as Ie,join as Oe,relative as U,resolve as _e}from"node:path";var x=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return _e(this.root,t)}async put(e,t){let r=this.path(e);await je(Ie(r),{recursive:!0}),await Ne(r,t)}async get(e){try{return await Ae(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 W(this.path(e)),!0}catch{return!1}}async delete(e){await Me(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await W(t)}catch{return r}let o=async i=>{let p=await Le(i,{withFileTypes:!0});for(let l of p){let c=Oe(i,l.name);if(l.isDirectory()){await o(c);continue}let d=await H(c);r.push({key:U(this.root,c),size:d.size,updatedAt:d.mtime.toISOString()})}},n=await H(t);return n.isDirectory()?await o(t):r.push({key:U(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),r}};import{DeleteObjectCommand as Fe,GetObjectCommand as $e,HeadObjectCommand as De,ListObjectsV2Command as Ge,PutObjectCommand as Ke,S3Client as ze}from"@aws-sdk/client-s3";import{getSignedUrl as Be}from"@aws-sdk/s3-request-presigner";var C=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new ze({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 o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Ke({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await Be(this.client,new $e({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 De({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 Fe({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let o=await this.client.send(new Ge({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let n of o.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});r=o.IsTruncated?o.NextContinuationToken:void 0}while(r);return t}};function F(s,e){return console.warn(e),new x(s)}function V(s){let e=s.localRoot??He(We(),".toolnet-memory","storage");if(s.provider==="r2"){let t=s.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new C({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):F(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 C({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):F(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 R({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):F(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new x(e)}var w=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")}};function Ue(s){return new Promise(e=>setTimeout(e,s))}async function Y(s,e={}){let t=Math.max(1,e.attempts??3),r=e.baseDelayMs??150,o=e.maxDelayMs??2e3,n;for(let i=1;i<=t;i++)try{return await s()}catch(p){if(n=p,i>=t)break;let l=Math.min(o,r*2**(i-1)),c=Math.floor(Math.random()*Math.max(1,l*.2));await Ue(l+c)}throw n}var Ve=new Set(["put","get","getText","delete","list"]);function q(s,e={}){return new Proxy(s,{get(t,r){let o=Reflect.get(t,r,t);return typeof o!="function"?o:Ve.has(r)?(...n)=>Y(()=>Promise.resolve(o.apply(t,n)),e):o.bind(t)}})}function J(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 Q(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 o=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return o?`${o[1]}memory/records/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),o?`${o[1]}memory/vectors/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),o?`${o[1]}code/graph/${o[2]}`:e))}var T=class{constructor(e,t,r,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=J(o??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,o=await this.provider.getText(e);if(o){let i;try{i=JSON.parse(o)}catch(p){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${p instanceof Error?p.message:String(p)}`)}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 n={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:t};await this.provider.put(e,JSON.stringify(n,null,2)+`
4
- `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=Q(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))}};import*as u from"typescript";var h=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 Qe(s,e){return e.ranges.length===0?!0:typeof s.startLine!="number"||typeof s.endLine!="number"?!1:e.ranges.some(t=>s.startLine<=t.endLine&&s.endLine>=t.startLine)}var j=class{constructor(e){this.graph=e}graph;map(e,t){let r=this.graph.allSymbols(e),o=[];for(let n of t){let i=r.filter(c=>c.filePath===n.filePath),l=i.filter(c=>c.type!=="file").filter(c=>Qe(c,n));if(l.length===0){let c=i.find(d=>d.type==="file");c&&o.push({symbol:c,fileStatus:n.status,direct:!0});continue}for(let c of l)o.push({symbol:c,fileStatus:n.status,direct:!0})}return o}mapFile(e,t){return this.map(e,[{filePath:t,status:"modified",ranges:[]}])}};var Ze={CALLS:4,CALL_REFERENCE:6,USES_TYPE:4,TESTS:2,ROUTE:4,WRITES:3,IMPORTS:3,INHERITS:5,IMPLEMENTS:5,DEFINES:1};function Xe(s){return s>=30?"CRITICAL":s>=16?"HIGH":s>=6?"MEDIUM":"LOW"}function Z(s){let e=s.toLowerCase().replaceAll("\\","/");return e.startsWith("tests/")||e.includes("/tests/")||e.includes("__tests__")||/\.(test|spec)\.[^.]+$/.test(e)}var A=class{constructor(e){this.graph=e}graph;analyze(e,t,r=4){let o=this.graph.allEdges(e),n=new Map,i=0;for(let d of t){d.fileStatus==="deleted"?i+=8:d.fileStatus==="renamed"?i+=5:i+=2,d.symbol.type==="interface"&&(i+=5),d.symbol.type==="class"&&(i+=3);let f=new Set([d.symbol.id]),M=[{id:d.symbol.id,depth:0}];for(;M.length;){let N=M.shift();if(N.depth>=r)continue;let ee=o.filter(g=>g.to===N.id&&["CALLS","CALL_REFERENCE","USES_TYPE","TESTS","ROUTE","WRITES","IMPORTS","INHERITS","IMPLEMENTS","DEFINES"].includes(g.type));for(let g of ee){if(f.has(g.from))continue;f.add(g.from);let E=this.graph.getSymbol(g.from);if(!E)continue;let I=N.depth+1,te=`${d.symbol.id}:${E.id}`;n.set(te,{symbol:E,relation:g.type,depth:I,sourceSymbolId:d.symbol.id});let re=Ze[g.type]??1;i+=Math.max(1,re-(I-1)),M.push({id:E.id,depth:I})}}}let p=[...n.values()].sort((d,f)=>d.depth-f.depth),l=[...new Set(p.map(d=>d.symbol.filePath))],c=l.filter(Z);return c.length===0&&c.push(...l.filter(d=>!Z(d)).slice(0,10)),{risk:Xe(i),riskScore:i,changedSymbols:t,impacted:p,impactedFiles:l,suggestedTests:c}}};import{execFile as et}from"node:child_process";import{promisify as tt}from"node:util";var $=tt(et);function rt(s){let e=[],t=/^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/gm;for(let r of s.matchAll(t)){let o=Number(r[1]),n=Number(r[2]??1);e.push({startLine:o,endLine:Math.max(o,o+n-1)})}return e}function st(s){return s.startsWith("A")?"added":s.startsWith("D")?"deleted":s.startsWith("R")?"renamed":"modified"}async function X(s){let e="";try{e=(await $("git",["diff","HEAD","--name-status","--no-renames"],{cwd:s,maxBuffer:10485760})).stdout}catch{return[]}let t=[];for(let r of e.split(/\r?\n/).filter(Boolean)){let[o,...n]=r.split(" "),i=n.at(-1);if(!i)continue;let p="";try{p=(await $("git",["diff","HEAD","--unified=0","--",i],{cwd:s,maxBuffer:20971520})).stdout}catch{p=""}t.push({filePath:i,status:st(o),ranges:rt(p)})}try{let r=await $("git",["ls-files","--others","--exclude-standard"],{cwd:s});for(let o of r.stdout.split(/\r?\n/).filter(Boolean))t.some(n=>n.filePath===o)||t.push({filePath:o,status:"added",ranges:[]})}catch{}return t}var L=class{constructor(e){this.graph=e;this.mapper=new j(e),this.blast=new A(e)}graph;mapper;blast;async analyzeGitDiff(e,t,r={}){let o=await X(t),n=this.mapper.map(e,o),i=this.blast.analyze(e,n,r.maxDepth??4);return{mode:"git_diff",changes:o,...i}}analyzeFile(e,t,r={}){let o=this.mapper.mapFile(e,t);return{mode:"planned_file",filePath:t,...this.blast.analyze(e,o,r.maxDepth??4)}}};import*as m from"typescript";import*as a from"typescript";var ko=new Set([a.SyntaxKind.EqualsToken,a.SyntaxKind.PlusEqualsToken,a.SyntaxKind.MinusEqualsToken,a.SyntaxKind.AsteriskEqualsToken,a.SyntaxKind.SlashEqualsToken,a.SyntaxKind.PercentEqualsToken,a.SyntaxKind.QuestionQuestionEqualsToken,a.SyntaxKind.AmpersandAmpersandEqualsToken,a.SyntaxKind.BarBarEqualsToken]);async function nt(){let s=D(),e=new P().detect(),t=q(V({provider:s.storage.provider,huggingface:s.storage.huggingface,localRoot:s.storage.localRoot}),{attempts:3}),r=new T(t,e.id,e.name,e.remote??e.name),o=await new w(r).load(e.id);if(!o)throw new Error("Code graph missing");let n=new h;n.import(o.symbols,o.edges);let i=new L(n),p=process.argv[2],l=p?i.analyzeFile(e.id,p):await i.analyzeGitDiff(e.id,e.rootPath);console.log({risk:l.risk,riskScore:l.riskScore,changedSymbols:l.changedSymbols.map(c=>({symbol:c.symbol.qualifiedName,file:c.symbol.filePath,type:c.symbol.type})),impactedFiles:l.impactedFiles,suggestedTests:l.suggestedTests,impactedCount:l.impacted.length})}nt().catch(s=>{console.error(s),process.exit(1)});
3
+ `,{encoding:"utf8",mode:384}),ue(o,r)}function K(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 P=class{detect(e=process.cwd()){let t=b(e),r=be(t),n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>O(k(r,d))),i=Se(t,n?r:void 0);if(i){let d=_(i),f=xe(d);return f.rootPath!==i&&(f.rootPath=i,f.updatedAt=new Date().toISOString(),G(i,f)),K(f,i)}let p=new Date().toISOString(),l=fe(r),c={version:1,id:he(r),name:l,remote:l,rootPath:r,createdAt:p,updatedAt:p,graphVersion:0,memoryVersion:0};return G(r,c),K(c,r)}};import{homedir as We}from"node:os";import{join as He}from"node:path";import{DeleteObjectCommand as we,GetObjectCommand as Ee,HeadObjectCommand as ve,ListObjectsV2Command as Pe,PutObjectCommand as ke,S3Client as Re}from"@aws-sdk/client-s3";import{getSignedUrl as Te}from"@aws-sdk/s3-request-presigner";var R=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Re({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 o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new ke({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await Te(this.client,new Ee({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 ve({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 we({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let o=await this.client.send(new Pe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let n of o.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});r=o.IsTruncated?o.NextContinuationToken:void 0}while(r);return t}};import{access as W,mkdir as je,readFile as Ae,readdir as Me,rm as Le,stat as H,writeFile as Ne}from"node:fs/promises";import{dirname as Ie,join as Oe,relative as U,resolve as _e}from"node:path";var x=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return _e(this.root,t)}async put(e,t){let r=this.path(e);await je(Ie(r),{recursive:!0}),await Ne(r,t)}async get(e){try{return await Ae(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 W(this.path(e)),!0}catch{return!1}}async delete(e){await Le(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await W(t)}catch{return r}let o=async i=>{let p=await Me(i,{withFileTypes:!0});for(let l of p){let c=Oe(i,l.name);if(l.isDirectory()){await o(c);continue}let d=await H(c);r.push({key:U(this.root,c),size:d.size,updatedAt:d.mtime.toISOString()})}},n=await H(t);return n.isDirectory()?await o(t):r.push({key:U(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),r}};import{DeleteObjectCommand as Fe,GetObjectCommand as $e,HeadObjectCommand as De,ListObjectsV2Command as Ge,PutObjectCommand as Ke,S3Client as ze}from"@aws-sdk/client-s3";import{getSignedUrl as Be}from"@aws-sdk/s3-request-presigner";var C=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new ze({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 o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Ke({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await Be(this.client,new $e({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 De({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 Fe({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let o=await this.client.send(new Ge({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let n of o.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});r=o.IsTruncated?o.NextContinuationToken:void 0}while(r);return t}};function F(s,e){return console.warn(e),new x(s)}function V(s){let e=s.localRoot??He(We(),".toolnet-memory","storage");if(s.provider==="r2"){let t=s.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new C({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):F(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 C({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):F(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 R({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):F(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new x(e)}var w=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")}};function Ue(s){return new Promise(e=>setTimeout(e,s))}async function Y(s,e={}){let t=Math.max(1,e.attempts??3),r=e.baseDelayMs??150,o=e.maxDelayMs??2e3,n;for(let i=1;i<=t;i++)try{return await s()}catch(p){if(n=p,i>=t)break;let l=Math.min(o,r*2**(i-1)),c=Math.floor(Math.random()*Math.max(1,l*.2));await Ue(l+c)}throw n}var Ve=new Set(["put","get","getText","delete","list"]);function q(s,e={}){return new Proxy(s,{get(t,r){let o=Reflect.get(t,r,t);return typeof o!="function"?o:Ve.has(r)?(...n)=>Y(()=>Promise.resolve(o.apply(t,n)),e):o.bind(t)}})}function J(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 Q(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 o=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return o?`${o[1]}memory/records/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),o?`${o[1]}memory/vectors/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),o?`${o[1]}code/graph/${o[2]}`:e))}var T=class{constructor(e,t,r,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=J(o??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,o=await this.provider.getText(e);if(o){let i;try{i=JSON.parse(o)}catch(p){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${p instanceof Error?p.message:String(p)}`)}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 n={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:t};await this.provider.put(e,JSON.stringify(n,null,2)+`
4
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=Q(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))}};import*as u from"typescript";var h=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 Qe(s,e){return e.ranges.length===0?!0:typeof s.startLine!="number"||typeof s.endLine!="number"?!1:e.ranges.some(t=>s.startLine<=t.endLine&&s.endLine>=t.startLine)}var j=class{constructor(e){this.graph=e}graph;map(e,t){let r=this.graph.allSymbols(e),o=[];for(let n of t){let i=r.filter(c=>c.filePath===n.filePath),l=i.filter(c=>c.type!=="file").filter(c=>Qe(c,n));if(l.length===0){let c=i.find(d=>d.type==="file");c&&o.push({symbol:c,fileStatus:n.status,direct:!0});continue}for(let c of l)o.push({symbol:c,fileStatus:n.status,direct:!0})}return o}mapFile(e,t){return this.map(e,[{filePath:t,status:"modified",ranges:[]}])}};var Ze={CALLS:4,CALL_REFERENCE:6,USES_TYPE:4,TESTS:2,ROUTE:4,WRITES:3,IMPORTS:3,INHERITS:5,IMPLEMENTS:5,DEFINES:1};function Xe(s){return s>=30?"CRITICAL":s>=16?"HIGH":s>=6?"MEDIUM":"LOW"}function Z(s){let e=s.toLowerCase().replaceAll("\\","/");return e.startsWith("tests/")||e.includes("/tests/")||e.includes("__tests__")||/\.(test|spec)\.[^.]+$/.test(e)}var A=class{constructor(e){this.graph=e}graph;analyze(e,t,r=4){let o=this.graph.allEdges(e),n=new Map,i=0;for(let d of t){d.fileStatus==="deleted"?i+=8:d.fileStatus==="renamed"?i+=5:i+=2,d.symbol.type==="interface"&&(i+=5),d.symbol.type==="class"&&(i+=3);let f=new Set([d.symbol.id]),L=[{id:d.symbol.id,depth:0}];for(;L.length;){let N=L.shift();if(N.depth>=r)continue;let ee=o.filter(g=>g.to===N.id&&["CALLS","CALL_REFERENCE","USES_TYPE","TESTS","ROUTE","WRITES","IMPORTS","INHERITS","IMPLEMENTS","DEFINES"].includes(g.type));for(let g of ee){if(f.has(g.from))continue;f.add(g.from);let E=this.graph.getSymbol(g.from);if(!E)continue;let I=N.depth+1,te=`${d.symbol.id}:${E.id}`;n.set(te,{symbol:E,relation:g.type,depth:I,sourceSymbolId:d.symbol.id});let re=Ze[g.type]??1;i+=Math.max(1,re-(I-1)),L.push({id:E.id,depth:I})}}}let p=[...n.values()].sort((d,f)=>d.depth-f.depth),l=[...new Set(p.map(d=>d.symbol.filePath))],c=l.filter(Z);return c.length===0&&c.push(...l.filter(d=>!Z(d)).slice(0,10)),{risk:Xe(i),riskScore:i,changedSymbols:t,impacted:p,impactedFiles:l,suggestedTests:c}}};import{execFile as et}from"node:child_process";import{promisify as tt}from"node:util";var $=tt(et);function rt(s){let e=[],t=/^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/gm;for(let r of s.matchAll(t)){let o=Number(r[1]),n=Number(r[2]??1);e.push({startLine:o,endLine:Math.max(o,o+n-1)})}return e}function st(s){return s.startsWith("A")?"added":s.startsWith("D")?"deleted":s.startsWith("R")?"renamed":"modified"}async function X(s){let e="";try{e=(await $("git",["diff","HEAD","--name-status","--no-renames"],{cwd:s,maxBuffer:10485760})).stdout}catch{return[]}let t=[];for(let r of e.split(/\r?\n/).filter(Boolean)){let[o,...n]=r.split(" "),i=n.at(-1);if(!i)continue;let p="";try{p=(await $("git",["diff","HEAD","--unified=0","--",i],{cwd:s,maxBuffer:20971520})).stdout}catch{p=""}t.push({filePath:i,status:st(o),ranges:rt(p)})}try{let r=await $("git",["ls-files","--others","--exclude-standard"],{cwd:s});for(let o of r.stdout.split(/\r?\n/).filter(Boolean))t.some(n=>n.filePath===o)||t.push({filePath:o,status:"added",ranges:[]})}catch{}return t}var M=class{constructor(e){this.graph=e;this.mapper=new j(e),this.blast=new A(e)}graph;mapper;blast;async analyzeGitDiff(e,t,r={}){let o=await X(t),n=this.mapper.map(e,o),i=this.blast.analyze(e,n,r.maxDepth??4);return{mode:"git_diff",changes:o,...i}}analyzeFile(e,t,r={}){let o=this.mapper.mapFile(e,t);return{mode:"planned_file",filePath:t,...this.blast.analyze(e,o,r.maxDepth??4)}}};import*as m from"typescript";import*as a from"typescript";var ko=new Set([a.SyntaxKind.EqualsToken,a.SyntaxKind.PlusEqualsToken,a.SyntaxKind.MinusEqualsToken,a.SyntaxKind.AsteriskEqualsToken,a.SyntaxKind.SlashEqualsToken,a.SyntaxKind.PercentEqualsToken,a.SyntaxKind.QuestionQuestionEqualsToken,a.SyntaxKind.AmpersandAmpersandEqualsToken,a.SyntaxKind.BarBarEqualsToken]);async function nt(){let s=D(),e=new P().detect(),t=q(V({provider:s.storage.provider,huggingface:s.storage.huggingface,localRoot:s.storage.localRoot}),{attempts:3}),r=new T(t,e.id,e.name,e.remote??e.name),o=await new w(r).load(e.id);if(!o)throw new Error("Code graph missing");let n=new h;n.import(o.symbols,o.edges);let i=new M(n),p=process.argv[2],l=p?i.analyzeFile(e.id,p):await i.analyzeGitDiff(e.id,e.rootPath);console.log({risk:l.risk,riskScore:l.riskScore,changedSymbols:l.changedSymbols.map(c=>({symbol:c.symbol.qualifiedName,file:c.symbol.filePath,type:c.symbol.type})),impactedFiles:l.impactedFiles,suggestedTests:l.suggestedTests,impactedCount:l.impacted.length})}nt().catch(s=>{console.error(s),process.exit(1)});