toolnet-memory 0.3.15 → 0.3.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
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
- `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function fe(){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 n=r.indexOf("=");if(n<=0)continue;let o=r.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(o)&&process.env[o]===void 0&&(process.env[o]=ue(r.slice(n+1)))}}fe();function C(s,e){return s===void 0?e:["1","true","yes","on"].includes(s.toLowerCase())}function E(s,e){if(!s)return e;let t=Number(s);return Number.isFinite(t)?t:e}function B(){return{memory:{autoCapture:C(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:C(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:C(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:C(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:E(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:E(process.env.MEMORY_RERANK_TOP,10),finalContext:E(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:E(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:C(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:E(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as me}from"node:crypto";import{existsSync as M,mkdirSync as ge,readFileSync as he,renameSync as ye,writeFileSync as Se}from"node:fs";import{basename as be,dirname as T,join as w,parse as Y,resolve as b}from"node:path";var J=".toolnet",xe="project.json";function Ce(s){return me("sha256").update(s).digest("hex").slice(0,16)}function A(s){return w(s,J,xe)}function Ee(s){return M(A(s))}function W(s,e){let t=b(s),r=Y(t).root;for(;;){if(Ee(t))return t;if(t===r||e&&t===b(e))break;let n=T(t);if(n===t)break;t=n}return null}function U(s){let e=b(s),t=Y(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>M(w(e,o))))return e;if(e===t)break;let n=T(e);if(n===e)break;e=n}return b(s)}function H(s){let e;try{e=JSON.parse(he(s,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${s}: ${n instanceof Error?n.message:String(n)}`)}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:T(T(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 V(s,e){let t=w(s,J);ge(t,{recursive:!0});let r=A(s),n=`${r}.tmp-${process.pid}`;Se(n,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),ye(n,r)}function $(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 j=class{findExisting(e=process.cwd()){let t=b(e),r=U(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(l=>M(w(r,l))),i=W(t,o?r:void 0);if(!i)return null;let a=H(A(i));return $(a,i)}requireExisting(e=process.cwd()){let t=this.findExisting(e);if(!t)throw new Error("PROJECT_NOT_INITIALIZED");return t}detect(e=process.cwd()){let t=b(e),r=U(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>M(w(r,p))),i=W(t,o?r:void 0);if(i){let p=A(i),u=H(p);return u.rootPath!==i&&(u.rootPath=i,u.updatedAt=new Date().toISOString(),V(i,u)),$(u,i)}let a=new Date().toISOString(),l=be(r),d={version:1,id:Ce(r),name:l,remote:l,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return V(r,d),$(d,r)}};var we=[{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"}],ve=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function q(s){return s.normalize("NFKC").trim().toLowerCase()}function ke(s){if(s.length===0)return 0;let e=new Map;for(let r of s)e.set(r,(e.get(r)??0)+1);let t=0;for(let r of e.values()){let n=r/s.length;t-=n*Math.log2(n)}return t}function Pe(s){return/^[a-f0-9]{32}$/iu.test(s)||/^[a-f0-9]{40}$/iu.test(s)||/^[a-f0-9]{64}$/iu.test(s)}function Re(s,e,t){let r=s.slice(Math.max(0,e-48),e),n=s.slice(t,Math.min(s.length,t+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${r} ${n}`)}function Me(s,e){return s.start<e.end&&e.start<s.end}function Z(s){return s.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var I=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let r=q(t);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let o of we){let i=new RegExp(o.regex.source,o.regex.flags);for(let a of e.matchAll(i))a.index===void 0||!a[0]||this.allowed(a[0])||t.push({type:o.type,value:a[0],start:a.index,end:a.index+a[0].length,confidence:o.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let r=Z(t),n=[];for(let o of r)n.some(i=>Me(i,o))||n.push(o);return Z(n)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=q(e);return ve.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],r=/[A-Za-z0-9_+/=-]{32,160}/g;for(let n of e.matchAll(r)){if(n.index===void 0||!n[0])continue;let o=n[0];this.allowed(o)||Pe(o)||!/[A-Za-z]/u.test(o)||!/[0-9]/u.test(o)||Re(e,n.index,n.index+o.length)&&(ke(o)<3.7||t.push({type:"high_entropy_secret",value:o,start:n.index,end:n.index+o.length,confidence:"heuristic"}))}return t}};var x=class{scanner;constructor(e={}){this.scanner=new I(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let r=e,n=[...t].sort((i,a)=>a.start-i.start),o=new Set;for(let i of n)o.add(i.type),r=r.slice(0,i.start)+`[REDACTED:${i.type}]`+r.slice(i.end);return{text:r,redacted:t.length,secretTypes:[...o].sort()}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[r,n]of Object.entries(e)){let o=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(o.includes("password")||o.includes("passwd")||o==="pwd"||o.includes("secret")||o.includes("token")||o.includes("cookie")||o.includes("authorization")||o.includes("apikey")||o.includes("accesskey")||o.includes("privatekey")||o.includes("clientsecret")||o.includes("credential")){t[r]="[REDACTED]";continue}t[r]=this.sanitizeValue(n)}return t}return e}};var Pt=new x;import{homedir as Ze}from"node:os";import{join as Qe}from"node:path";import{DeleteObjectCommand as Te,GetObjectCommand as Ae,HeadObjectCommand as je,ListObjectsV2Command as Ie,PutObjectCommand as Le,S3Client as Ne}from"@aws-sdk/client-s3";import{getSignedUrl as Oe}from"@aws-sdk/s3-request-presigner";var L=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Ne({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Le({Bucket:this.bucket,Key:e,Body:n,ContentType:r}))}async get(e){let t=await Oe(this.client,new Ae({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 Te({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let n=await this.client.send(new Ie({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of n.Contents??[])o.Key&&t.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=n.IsTruncated?n.NextContinuationToken:void 0}while(r);return t}};import{access as Q,mkdir as _e,readFile as Fe,readdir as De,rm as $e,stat as X,writeFile as Ge}from"node:fs/promises";import{dirname as ze,join as Ke,relative as ee,resolve as Be}from"node:path";var v=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Be(this.root,t)}async put(e,t){let r=this.path(e);await _e(ze(r),{recursive:!0}),await Ge(r,t)}async get(e){try{return await Fe(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 Q(this.path(e)),!0}catch{return!1}}async delete(e){await $e(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await Q(t)}catch{return r}let n=async i=>{let a=await De(i,{withFileTypes:!0});for(let l of a){let d=Ke(i,l.name);if(l.isDirectory()){await n(d);continue}let p=await X(d);r.push({key:ee(this.root,d),size:p.size,updatedAt:p.mtime.toISOString()})}},o=await X(t);return o.isDirectory()?await n(t):r.push({key:ee(this.root,t),size:o.size,updatedAt:o.mtime.toISOString()}),r}};import{DeleteObjectCommand as We,GetObjectCommand as Ue,HeadObjectCommand as He,ListObjectsV2Command as Ve,PutObjectCommand as Ye,S3Client as Je}from"@aws-sdk/client-s3";import{getSignedUrl as qe}from"@aws-sdk/s3-request-presigner";var k=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Je({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Ye({Bucket:this.bucket,Key:e,Body:n,ContentType:r}))}async get(e){let t=await qe(this.client,new Ue({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 He({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 n=await this.client.send(new Ve({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of n.Contents??[])o.Key&&t.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=n.IsTruncated?n.NextContinuationToken:void 0}while(r);return t}};function G(s,e){return console.warn(e),new v(s)}function te(s){let e=s.localRoot??Qe(Ze(),".toolnet-memory","storage");if(s.provider==="r2"){let t=s.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new k({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):G(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 k({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):G(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 L({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):G(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new v(e)}var P=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")}};var N=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","chunks","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 re(s){let e=s.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function se(s){let e=s.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let n=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return n?`${n[1]}memory/records/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),n?`${n[1]}memory/vectors/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),n?`${n[1]}code/graph/${n[2]}`:e))}var O=class{constructor(e,t,r,n){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=re(n??r),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),r=t,n=await this.provider.getText(e);if(n){let i;try{i=JSON.parse(n)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:t};await this.provider.put(e,JSON.stringify(o,null,2)+`
4
- `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=se(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))}};var fs=2*1024*1024;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)}};import*as f from"typescript";import{execFile as rt}from"node:child_process";import{promisify as st}from"node:util";var _s=st(rt);import*as y from"typescript";import{createHash as ot}from"node:crypto";import{readFile as it}from"node:fs/promises";import{join as at}from"node:path";function oe(s){return ot("sha256").update(s).digest("hex")}var _=class{sanitizer=new x;async build(e,t,r,n={}){let o=n.maxLines??80,i=n.overlapLines??10,a=new Map;for(let d of r){let p=a.get(d.filePath)??[];p.push(d),a.set(d.filePath,p)}let l=[];for(let[d,p]of a){let u;try{u=await it(at(t,d),"utf8")}catch{continue}let h=u.split(/\r?\n/),S=p.filter(g=>g.type!=="file"&&typeof g.startLine=="number"&&typeof g.endLine=="number");if(S.length>0)for(let g of S)l.push(...this.chunkRange({projectId:e,filePath:d,lines:h,symbol:g,startLine:g.startLine,endLine:g.endLine,maxLines:o,overlapLines:i}));else l.push(...this.chunkRange({projectId:e,filePath:d,lines:h,startLine:1,endLine:Math.max(1,h.length),maxLines:o,overlapLines:i}))}return l}chunkRange(e){let{projectId:t,filePath:r,lines:n,symbol:o,maxLines:i}=e,a=Math.min(e.overlapLines,Math.max(0,i-1)),l=Math.max(1,e.startLine),d=Math.min(n.length,Math.max(l,e.endLine)),p=[],u=l,h=0;for(;u<=d;){let S=Math.min(d,u+i-1),g=n.slice(u-1,S).join(`
5
- `).trim();if(g){let z=this.sanitizer.sanitize(g).text,K=oe(z),ae=[t,r,o?.id??"file",String(h),K].join(":");p.push({id:oe(ae).slice(0,32),projectId:t,filePath:r,symbolId:o?.id,symbolName:o?.qualifiedName??o?.name,symbolType:o?.type,startLine:u,endLine:S,content:z,contentHash:K})}if(S>=d)break;u=S-a+1,h++}return p}};import{DatabaseSync as ct}from"node:sqlite";var F=class{constructor(e){this.projectId=e;this.db.exec("CREATE VIRTUAL TABLE code_fts USING fts5(id UNINDEXED, projectId UNINDEXED, filePath, symbol, content, tokenize='unicode61')")}projectId;db=new ct(":memory:");chunks=new Map;get size(){return this.chunks.size}build(e){if(this.db.exec("DELETE FROM code_fts"),this.chunks.clear(),e.length===0)return 0;let t=this.db.prepare("INSERT INTO code_fts (id, projectId, filePath, symbol, content) VALUES (?, ?, ?, ?, ?)");this.db.exec("BEGIN");try{for(let r of e)this.chunks.set(r.id,r),t.run(r.id,this.projectId,r.filePath,r.symbolName??"",r.content);this.db.exec("COMMIT")}catch(r){throw this.db.exec("ROLLBACK"),r}return e.length}search(e,t=8){let r=this.toMatchQuery(e);if(!r)return[];let n=this.db.prepare("SELECT id, bm25(code_fts) AS rank FROM code_fts WHERE code_fts MATCH ? ORDER BY rank LIMIT ?").all(r,Math.max(t*4,20)),o=[];for(let i of n){let a=this.chunks.get(i.id);if(!a)continue;let l=1/(1+Math.abs(i.rank));o.push({chunk:a,score:l})}return o.slice(0,t)}toMatchQuery(e){let t=e.toLowerCase().normalize("NFKC").split(/[^\p{L}\p{N}]+/u).map(r=>r.trim()).filter(r=>r.length>0);return t.length===0?null:t.length===1?`"${t[0]}"`:`(${t.map(r=>`"${r}"`).join(" OR ")})`}close(){this.db.close()}};function ie(s,e){let t=s.toLowerCase().replaceAll("\\","/"),r=e.toLowerCase(),n=/\b(test|tests|spec|fixture|mock)\b/.test(r);return(t.startsWith("tests/")||t.includes("/tests/")||t.includes("__tests__")||/\.(test|spec)\.[^.]+$/.test(t))&&!n?.35:t.includes("/generated/")||t.includes(".generated.")?.25:1}var D=class{constructor(e){this.options=e;this.fts=new F(e.projectId)}options;fts;async initialize(e){let{projectId:t,rootPath:r,storage:n,graph:o}=this.options,i=new N(n),a=await new _().build(t,r,o.allSymbols(t)),l=await i.load(t),d=!l||l.chunks.length!==a.length||l.chunks.some(u=>!a.some(h=>h.id===u.id));d&&await i.save({version:1,projectId:t,updatedAt:new Date().toISOString(),chunks:a}),e?.({current:a.length,total:a.length,phase:"index"});let p=this.fts.build(a);return{chunks:a.length,vectorsLoaded:0,vectorsIndexed:p,vectorsRemoved:0,totalVectors:this.fts.size,savedChunks:d,savedVectors:d}}async search(e,t=8){let r=this.fts.search(e,t),n=[];for(let o of r){let i=o.chunk,a=ie(i.filePath,e),l=o.score,d=0,p=l*a;n.push({chunk:i,score:p,vectorScore:d,lexicalScore:l})}return n}size(){return this.fts.size}};import*as m from"typescript";import*as c from"typescript";var Jn=new Set([c.SyntaxKind.EqualsToken,c.SyntaxKind.PlusEqualsToken,c.SyntaxKind.MinusEqualsToken,c.SyntaxKind.AsteriskEqualsToken,c.SyntaxKind.SlashEqualsToken,c.SyntaxKind.PercentEqualsToken,c.SyntaxKind.QuestionQuestionEqualsToken,c.SyntaxKind.AmpersandAmpersandEqualsToken,c.SyntaxKind.BarBarEqualsToken]);async function dt(){let s=B(),e=new j().detect(),t=te({provider:s.storage.provider,huggingface:s.storage.huggingface,localRoot:s.storage.localRoot}),r=new O(t,e.id,e.name,e.remote??e.name),n=new R,o=await new P(r).load(e.id);if(!o)throw new Error("Code graph missing. Run npm run code:index:test first.");n.import(o.symbols,o.edges);let i=new D({projectId:e.id,rootPath:e.rootPath,storage:r,graph:n}),a=await i.initialize(),l=process.argv.slice(2).join(" ")||"memory storage hugging face",d=await i.search(l,5);console.log({ok:!0,query:l,...a,results:d.map(p=>({score:Number(p.score.toFixed(4)),file:p.chunk.filePath,symbol:p.chunk.symbolName,lines:`${p.chunk.startLine}-${p.chunk.endLine}`,preview:p.chunk.content.replace(/\s+/g," ").slice(0,140)}))})}dt().catch(s=>{console.error(s),process.exit(1)});
1
+ import"dotenv/config";import{existsSync as Ce,readFileSync as Ee}from"node:fs";import{homedir as we}from"node:os";import{join as ve}from"node:path";function Re(n){let e=n.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
2
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function ke(){let n=process.env.TOOLNET_GLOBAL_ENV??ve(we(),".config","toolnet-memory",".env");if(!Ce(n))return;let e=Ee(n,"utf8");for(let t of e.split(/\r?\n/)){let r=t.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let s=r.indexOf("=");if(s<=0)continue;let o=r.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(o)&&process.env[o]===void 0&&(process.env[o]=Re(r.slice(s+1)))}}ke();function w(n,e){return n===void 0?e:["1","true","yes","on"].includes(n.toLowerCase())}function v(n,e){if(!n)return e;let t=Number(n);return Number.isFinite(t)?t:e}function Q(){return{memory:{autoCapture:w(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:w(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:w(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:w(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:v(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:v(process.env.MEMORY_RERANK_TOP,10),finalContext:v(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:v(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:w(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:v(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Le}from"node:crypto";import{existsSync as N,mkdirSync as Ne,readFileSync as _e,renameSync as Oe,writeFileSync as Fe}from"node:fs";import{basename as De,dirname as _,join as k,parse as oe,resolve as x}from"node:path";import{createHash as ee}from"node:crypto";import{spawnSync as Pe}from"node:child_process";var R="git-remote-v1",Ae=new Set(["github.com","gitlab.com","bitbucket.org"]);function te(n,e){let t=e.replaceAll("\\","/").replace(/^\/+/u,"").replace(/\/+$/u,"").replace(/\.git$/iu,"").replace(/\/+/gu,"/");return!t||t==="."||t===".."||t.split("/").some(r=>!r||r==="."||r==="..")?null:(Ae.has(n)&&(t=t.toLowerCase()),t)}function Me(n){let e;try{e=new URL(n)}catch{return null}if(!["https:","http:","ssh:","git:"].includes(e.protocol))return null;let t=e.hostname.trim().toLowerCase();if(!t)return null;let r=e.protocol==="https:"&&e.port==="443"||e.protocol==="http:"&&e.port==="80"||e.protocol==="ssh:"&&e.port==="22",s=e.port&&!r?`${t}:${e.port}`:t,o=te(t,e.pathname);return o?`${s}/${o}`:null}function Te(n){let e=n.match(/^(?:[^@\s/:]+@)?([^:/\s]+):(.+)$/u);if(!e)return null;let t=e[1]?.trim().toLowerCase();if(!t||t.length===1)return null;let r=te(t,e[2]??"");return r?`${t}/${r}`:null}function Z(n){let e=n.trim();return e?e.includes("://")?Me(e):Te(e):null}function Ie(n){return ee("sha256").update(`${R}:${n}`).digest("hex")}function re(n){return ee("sha256").update(`toolnet-project:${R}:${n}`).digest("hex").slice(0,16)}function je(n){return n.split("/").filter(Boolean).at(-1)?.trim()||null}function W(n,e){let t=Pe("git",["-C",n,...e],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return t.error||t.status!==0?null:t.stdout?.trim()||null}function X(n,e){let t=je(n);return t?{scheme:R,canonicalRemote:n,fingerprint:Ie(n),repositoryName:t,source:e}:null}function ne(n){let e=W(n,["remote","get-url","origin"]);if(e){let s=Z(e);if(s)return X(s,"origin")}let t=W(n,["remote"]);if(!t)return null;let r=new Set;for(let s of t.split(/\r?\n/u).map(o=>o.trim()).filter(Boolean)){let o=W(n,["remote","get-url",s]);if(!o)continue;let i=Z(o);i&&r.add(i)}return r.size!==1?null:X([...r][0],"unique-remote")}var ie=".toolnet",$e="project.json";function Ge(n){return Le("sha256").update(n).digest("hex").slice(0,16)}function C(n){return k(n,ie,$e)}function ae(n){return N(C(n))}function se(n,e){let t=x(n),r=oe(t).root;for(;;){if(ae(t))return t;if(t===r||e&&t===x(e))break;let s=_(t);if(s===t)break;t=s}return null}function U(n){let e=x(n),t=oe(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(o=>N(k(e,o))))return e;if(e===t)break;let s=_(e);if(s===e)break;e=s}return x(n)}function j(n){let e;try{e=JSON.parse(_e(n,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${n}: ${s instanceof Error?s.message:String(s)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${n}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${n}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${n}`);let r=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:_(_(n)),createdAt:typeof t.createdAt=="string"?t.createdAt:r,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:r,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function L(n,e){let t=k(n,ie);Ne(t,{recursive:!0});let r=C(n),s=`${r}.tmp-${process.pid}`;Fe(s,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),Oe(s,r)}function b(n,e){return{id:n.id,name:n.name,remote:n.remote,rootPath:e,createdAt:n.createdAt,updatedAt:n.updatedAt,graphVersion:n.graphVersion,memoryVersion:n.memoryVersion,metadata:n.metadata}}function V(n){return{version:1,scheme:R,canonicalRemote:n.canonicalRemote,fingerprint:n.fingerprint,repositoryName:n.repositoryName}}function Ke(n){let e=n.metadata?.toolnetIdentity;if(!e||typeof e!="object"||Array.isArray(e))return null;let t=e;return typeof t.fingerprint=="string"?t.fingerprint:null}var O=class{adopt(e,t){let r=U(x(e));if(!t.id.trim())throw new Error("PROJECT_ADOPTION_INVALID_ID");if(!t.name.trim())throw new Error("PROJECT_ADOPTION_INVALID_NAME");if(!t.remote.trim())throw new Error("PROJECT_ADOPTION_INVALID_REMOTE");if(ae(r)){let a=j(C(r));if(a.id!==t.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${a.id}`,`requested=${t.id}`].join(" "));return b(a,r)}let s=new Date().toISOString(),o={...t.metadata};t.gitIdentity&&(o.toolnetIdentity=V(t.gitIdentity));let i={version:1,id:t.id.trim(),name:t.name.trim(),remote:t.remote.trim(),rootPath:r,createdAt:t.createdAt??s,updatedAt:s,graphVersion:t.graphVersion??0,memoryVersion:t.memoryVersion??0,metadata:Object.keys(o).length?o:void 0};return L(r,i),b(i,r)}recordGitIdentity(e,t,r={}){let s=this.requireExisting(e),o=C(s.rootPath),i=j(o),a=Ke(i);if(a&&a!==t.fingerprint&&!r.allowRebind)throw new Error(["PROJECT_GIT_REMOTE_CHANGED",`existing=${a}`,`current=${t.fingerprint}`,"Use explicit rebind only when this repository identity change is intentional."].join(" "));let c=i.metadata?.toolnetIdentity;return c&&typeof c=="object"&&!Array.isArray(c)&&c.fingerprint===t.fingerprint||(i.metadata={...i.metadata,toolnetIdentity:V(t)},i.updatedAt=new Date().toISOString(),L(s.rootPath,i)),b(i,s.rootPath)}findExisting(e=process.cwd()){let t=x(e),r=U(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(c=>N(k(r,c))),i=se(t,o?r:void 0);if(!i)return null;let a=j(C(i));return b(a,i)}requireExisting(e=process.cwd()){let t=this.findExisting(e);if(!t)throw new Error("PROJECT_NOT_INITIALIZED");return t}detect(e=process.cwd()){let t=x(e),r=U(t),o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>N(k(r,m))),i=se(t,o?r:void 0);if(i){let m=C(i),f=j(m);return f.rootPath!==i&&(f.rootPath=i,f.updatedAt=new Date().toISOString(),L(i,f)),b(f,i)}let a=new Date().toISOString(),c=De(r),l=ne(r),p={version:1,id:l?re(l.canonicalRemote):Ge(r),name:c,remote:l?.repositoryName??c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0,metadata:l?{toolnetIdentity:V(l)}:void 0};return L(r,p),b(p,r)}};var ze=[{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"}],Be=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function ce(n){return n.normalize("NFKC").trim().toLowerCase()}function He(n){if(n.length===0)return 0;let e=new Map;for(let r of n)e.set(r,(e.get(r)??0)+1);let t=0;for(let r of e.values()){let s=r/n.length;t-=s*Math.log2(s)}return t}function We(n){return/^[a-f0-9]{32}$/iu.test(n)||/^[a-f0-9]{40}$/iu.test(n)||/^[a-f0-9]{64}$/iu.test(n)}function Ue(n,e,t){let r=n.slice(Math.max(0,e-48),e),s=n.slice(t,Math.min(n.length,t+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${r} ${s}`)}function Ve(n,e){return n.start<e.end&&e.start<n.end}function le(n){return n.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var F=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let r=ce(t);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let o of ze){let i=new RegExp(o.regex.source,o.regex.flags);for(let a of e.matchAll(i))a.index===void 0||!a[0]||this.allowed(a[0])||t.push({type:o.type,value:a[0],start:a.index,end:a.index+a[0].length,confidence:o.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let r=le(t),s=[];for(let o of r)s.some(i=>Ve(i,o))||s.push(o);return le(s)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=ce(e);return Be.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],r=/[A-Za-z0-9_+/=-]{32,160}/g;for(let s of e.matchAll(r)){if(s.index===void 0||!s[0])continue;let o=s[0];this.allowed(o)||We(o)||!/[A-Za-z]/u.test(o)||!/[0-9]/u.test(o)||Ue(e,s.index,s.index+o.length)&&(He(o)<3.7||t.push({type:"high_entropy_secret",value:o,start:s.index,end:s.index+o.length,confidence:"heuristic"}))}return t}};var E=class{scanner;constructor(e={}){this.scanner=new F(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let r=e,s=[...t].sort((i,a)=>a.start-i.start),o=new Set;for(let i of s)o.add(i.type),r=r.slice(0,i.start)+`[REDACTED:${i.type}]`+r.slice(i.end);return{text:r,redacted:t.length,secretTypes:[...o].sort()}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[r,s]of Object.entries(e)){let o=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(o.includes("password")||o.includes("passwd")||o==="pwd"||o.includes("secret")||o.includes("token")||o.includes("cookie")||o.includes("authorization")||o.includes("apikey")||o.includes("accesskey")||o.includes("privatekey")||o.includes("clientsecret")||o.includes("credential")){t[r]="[REDACTED]";continue}t[r]=this.sanitizeValue(s)}return t}return e}};var Jt=new E;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 D=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 s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Ze({Bucket:this.bucket,Key:e,Body:s,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 s=await this.client.send(new Qe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of s.Contents??[])o.Key&&t.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return t}};import{access as de,mkdir as tt,readFile as rt,readdir as nt,rm as st,stat as pe,writeFile as ot}from"node:fs/promises";import{dirname as it,join as at,relative as ue,resolve as ct}from"node:path";var P=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 ot(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 de(this.path(e)),!0}catch{return!1}}async delete(e){await st(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await de(t)}catch{return r}let s=async i=>{let a=await nt(i,{withFileTypes:!0});for(let c of a){let l=at(i,c.name);if(c.isDirectory()){await s(l);continue}let p=await pe(l);r.push({key:ue(this.root,l),size:p.size,updatedAt:p.mtime.toISOString()})}},o=await pe(t);return o.isDirectory()?await s(t):r.push({key:ue(this.root,t),size:o.size,updatedAt:o.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 A=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 s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new mt({Bucket:this.bucket,Key:e,Body:s,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 s=await this.client.send(new ut({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let o of s.Contents??[])o.Key&&t.push({key:o.Key,size:o.Size,updatedAt:o.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return t}};function Y(n,e){return console.warn(e),new P(n)}function me(n){let e=n.localRoot??yt(ht(),".toolnet-memory","storage");if(n.provider==="r2"){let t=n.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new A({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):Y(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(n.provider==="s3"){let t=n.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new A({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):Y(e,"[storage] S3 credentials missing. Using local fallback.")}if(n.provider==="huggingface"){let t=n.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new D({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):Y(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new P(e)}var M=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")}};var $=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","chunks","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 fe(n){let e=n.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function ge(n){let e=n.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let s=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:e))}var G=class{constructor(e,t,r,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=fe(s??r),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),r=t,s=await this.provider.getText(e);if(s){let i;try{i=JSON.parse(s)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let o={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:t};await this.provider.put(e,JSON.stringify(o,null,2)+`
4
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=ge(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))}};var zn=2*1024*1024;var T=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)}};import*as u from"typescript";import{execFile as Ct}from"node:child_process";import{promisify as Et}from"node:util";var ps=Et(Ct);import*as y from"typescript";import{createHash as vt}from"node:crypto";import{readFile as Rt}from"node:fs/promises";import{join as kt}from"node:path";function ye(n){return vt("sha256").update(n).digest("hex")}var K=class{sanitizer=new E;async build(e,t,r,s={}){let o=s.maxLines??80,i=s.overlapLines??10,a=new Map;for(let l of r){let p=a.get(l.filePath)??[];p.push(l),a.set(l.filePath,p)}let c=[];for(let[l,p]of a){let m;try{m=await Rt(kt(t,l),"utf8")}catch{continue}let f=m.split(/\r?\n/),S=p.filter(h=>h.type!=="file"&&typeof h.startLine=="number"&&typeof h.endLine=="number");if(S.length>0)for(let h of S)c.push(...this.chunkRange({projectId:e,filePath:l,lines:f,symbol:h,startLine:h.startLine,endLine:h.endLine,maxLines:o,overlapLines:i}));else c.push(...this.chunkRange({projectId:e,filePath:l,lines:f,startLine:1,endLine:Math.max(1,f.length),maxLines:o,overlapLines:i}))}return c}chunkRange(e){let{projectId:t,filePath:r,lines:s,symbol:o,maxLines:i}=e,a=Math.min(e.overlapLines,Math.max(0,i-1)),c=Math.max(1,e.startLine),l=Math.min(s.length,Math.max(c,e.endLine)),p=[],m=c,f=0;for(;m<=l;){let S=Math.min(l,m+i-1),h=s.slice(m-1,S).join(`
5
+ `).trim();if(h){let q=this.sanitizer.sanitize(h).text,J=ye(q),xe=[t,r,o?.id??"file",String(f),J].join(":");p.push({id:ye(xe).slice(0,32),projectId:t,filePath:r,symbolId:o?.id,symbolName:o?.qualifiedName??o?.name,symbolType:o?.type,startLine:m,endLine:S,content:q,contentHash:J})}if(S>=l)break;m=S-a+1,f++}return p}};import{DatabaseSync as Pt}from"node:sqlite";var z=class{constructor(e){this.projectId=e;this.db.exec("CREATE VIRTUAL TABLE code_fts USING fts5(id UNINDEXED, projectId UNINDEXED, filePath, symbol, content, tokenize='unicode61')")}projectId;db=new Pt(":memory:");chunks=new Map;get size(){return this.chunks.size}build(e){if(this.db.exec("DELETE FROM code_fts"),this.chunks.clear(),e.length===0)return 0;let t=this.db.prepare("INSERT INTO code_fts (id, projectId, filePath, symbol, content) VALUES (?, ?, ?, ?, ?)");this.db.exec("BEGIN");try{for(let r of e)this.chunks.set(r.id,r),t.run(r.id,this.projectId,r.filePath,r.symbolName??"",r.content);this.db.exec("COMMIT")}catch(r){throw this.db.exec("ROLLBACK"),r}return e.length}search(e,t=8){let r=this.toMatchQuery(e);if(!r)return[];let s=this.db.prepare("SELECT id, bm25(code_fts) AS rank FROM code_fts WHERE code_fts MATCH ? ORDER BY rank LIMIT ?").all(r,Math.max(t*4,20)),o=[];for(let i of s){let a=this.chunks.get(i.id);if(!a)continue;let c=1/(1+Math.abs(i.rank));o.push({chunk:a,score:c})}return o.slice(0,t)}toMatchQuery(e){let t=e.toLowerCase().normalize("NFKC").split(/[^\p{L}\p{N}]+/u).map(r=>r.trim()).filter(r=>r.length>0);return t.length===0?null:t.length===1?`"${t[0]}"`:`(${t.map(r=>`"${r}"`).join(" OR ")})`}close(){this.db.close()}};function Se(n,e){let t=n.toLowerCase().replaceAll("\\","/"),r=e.toLowerCase(),s=/\b(test|tests|spec|fixture|mock)\b/.test(r);return(t.startsWith("tests/")||t.includes("/tests/")||t.includes("__tests__")||/\.(test|spec)\.[^.]+$/.test(t))&&!s?.35:t.includes("/generated/")||t.includes(".generated.")?.25:1}var I="sqlite-fts5-bm25",B="lexical",At="Local Code Search \u2014 SQLite FTS5/BM25",be={engine:I,mode:B,displayName:At,semantic:!1,embedding:!1,vectorDatabase:!1,queryExpansion:!1,synonymExpansion:!1,networkRequired:!1,indexBackend:"sqlite-fts5",ranking:"bm25",compatibilityAliases:["SemanticCodeEngine","semantic_code_search","toolnet-memory semantic","semantic-index"]};var H=class{constructor(e){this.options=e;this.fts=new z(e.projectId)}options;fts;get searchContract(){return be}async initialize(e){let{projectId:t,rootPath:r,storage:s,graph:o}=this.options,i=new $(s),a=await new K().build(t,r,o.allSymbols(t)),c=await i.load(t),l=!c||c.chunks.length!==a.length||c.chunks.some(m=>!a.some(f=>f.id===m.id));l&&await i.save({version:1,projectId:t,updatedAt:new Date().toISOString(),chunks:a}),e?.({current:a.length,total:a.length,phase:"index",detail:I});let p=this.fts.build(a);return{chunks:a.length,documentsIndexed:p,indexSize:this.fts.size,engine:I,mode:B,embedding:!1,vectorDatabase:!1,savedChunks:l,vectorsLoaded:0,vectorsIndexed:p,vectorsRemoved:0,totalVectors:this.fts.size,savedVectors:l}}async search(e,t=8){let r=this.fts.search(e,t),s=[];for(let o of r){let i=o.chunk,a=Se(i.filePath,e),c=o.score,l=0,p=c*a;s.push({chunk:i,score:p,lexicalScore:c,vectorScore:l,engine:I,mode:B})}return s}size(){return this.fts.size}};import*as g from"typescript";import*as d from"typescript";var Po=new Set([d.SyntaxKind.EqualsToken,d.SyntaxKind.PlusEqualsToken,d.SyntaxKind.MinusEqualsToken,d.SyntaxKind.AsteriskEqualsToken,d.SyntaxKind.SlashEqualsToken,d.SyntaxKind.PercentEqualsToken,d.SyntaxKind.QuestionQuestionEqualsToken,d.SyntaxKind.AmpersandAmpersandEqualsToken,d.SyntaxKind.BarBarEqualsToken]);async function Tt(){let n=Q(),e=new O().detect(),t=me({provider:n.storage.provider,huggingface:n.storage.huggingface,localRoot:n.storage.localRoot}),r=new G(t,e.id,e.name,e.remote??e.name),s=new T,o=await new M(r).load(e.id);if(!o)throw new Error("Code graph missing. Run npm run code:index:test first.");s.import(o.symbols,o.edges);let i=new H({projectId:e.id,rootPath:e.rootPath,storage:r,graph:s}),a=await i.initialize(),c=process.argv.slice(2).join(" ")||"memory storage hugging face",l=await i.search(c,5);console.log({ok:!0,command:"semantic",legacyCommandName:!0,search:{engine:"sqlite-fts5-bm25",mode:"lexical",semantic:!1,embedding:!1,vectorDatabase:!1},query:c,...a,results:l.map(p=>({score:Number(p.score.toFixed(4)),file:p.chunk.filePath,symbol:p.chunk.symbolName,lines:`${p.chunk.startLine}-${p.chunk.endLine}`,preview:p.chunk.content.replace(/\s+/g," ").slice(0,140)}))})}Tt().catch(n=>{console.error(n),process.exit(1)});
@@ -1,4 +1,4 @@
1
- import"dotenv/config";import{existsSync as W,readFileSync as Z}from"node:fs";import{homedir as G}from"node:os";import{join as Q}from"node:path";function q(s){let e=s.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
2
- `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function X(){let s=process.env.TOOLNET_GLOBAL_ENV??Q(G(),".config","toolnet-memory",".env");if(!W(s))return;let e=Z(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]=q(r.slice(o+1)))}}X();function f(s,e){return s===void 0?e:["1","true","yes","on"].includes(s.toLowerCase())}function g(s,e){if(!s)return e;let t=Number(s);return Number.isFinite(t)?t:e}function E(){return{memory:{autoCapture:f(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:f(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:f(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:f(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:f(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 ee}from"node:crypto";import{existsSync as w,mkdirSync as te,readFileSync as re,renameSync as oe,writeFileSync as se}from"node:fs";import{basename as ne,dirname as v,join as y,parse as $,resolve as l}from"node:path";var N=".toolnet",ie="project.json";function ae(s){return ee("sha256").update(s).digest("hex").slice(0,16)}function b(s){return y(s,N,ie)}function ce(s){return w(b(s))}function T(s,e){let t=l(s),r=$(t).root;for(;;){if(ce(t))return t;if(t===r||e&&t===l(e))break;let o=v(t);if(o===t)break;t=o}return null}function I(s){let e=l(s),t=$(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(n=>w(y(e,n))))return e;if(e===t)break;let o=v(e);if(o===e)break;e=o}return l(s)}function _(s){let e;try{e=JSON.parse(re(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 O(s,e){let t=y(s,N);te(t,{recursive:!0});let r=b(s),o=`${r}.tmp-${process.pid}`;se(o,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),oe(o,r)}function A(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 x=class{findExisting(e=process.cwd()){let t=l(e),r=I(t),n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(c=>w(y(r,c))),i=T(t,n?r:void 0);if(!i)return null;let a=_(b(i));return A(a,i)}requireExisting(e=process.cwd()){let t=this.findExisting(e);if(!t)throw new Error("PROJECT_NOT_INITIALIZED");return t}detect(e=process.cwd()){let t=l(e),r=I(t),n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>w(y(r,p))),i=T(t,n?r:void 0);if(i){let p=b(i),d=_(p);return d.rootPath!==i&&(d.rootPath=i,d.updatedAt=new Date().toISOString(),O(i,d)),A(d,i)}let a=new Date().toISOString(),c=ne(r),u={version:1,id:ae(r),name:c,remote:c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return O(r,u),A(u,r)}};var ue=[{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"}],pe=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function K(s){return s.normalize("NFKC").trim().toLowerCase()}function de(s){if(s.length===0)return 0;let e=new Map;for(let r of s)e.set(r,(e.get(r)??0)+1);let t=0;for(let r of e.values()){let o=r/s.length;t-=o*Math.log2(o)}return t}function le(s){return/^[a-f0-9]{32}$/iu.test(s)||/^[a-f0-9]{40}$/iu.test(s)||/^[a-f0-9]{64}$/iu.test(s)}function me(s,e,t){let r=s.slice(Math.max(0,e-48),e),o=s.slice(t,Math.min(s.length,t+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${r} ${o}`)}function fe(s,e){return s.start<e.end&&e.start<s.end}function D(s){return s.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var j=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let r=K(t);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let n of ue){let i=new RegExp(n.regex.source,n.regex.flags);for(let a of e.matchAll(i))a.index===void 0||!a[0]||this.allowed(a[0])||t.push({type:n.type,value:a[0],start:a.index,end:a.index+a[0].length,confidence:n.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let r=D(t),o=[];for(let n of r)o.some(i=>fe(i,n))||o.push(n);return D(o)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=K(e);return pe.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],r=/[A-Za-z0-9_+/=-]{32,160}/g;for(let o of e.matchAll(r)){if(o.index===void 0||!o[0])continue;let n=o[0];this.allowed(n)||le(n)||!/[A-Za-z]/u.test(n)||!/[0-9]/u.test(n)||me(e,o.index,o.index+n.length)&&(de(n)<3.7||t.push({type:"high_entropy_secret",value:n,start:o.index,end:o.index+n.length,confidence:"heuristic"}))}return t}};var k=class{scanner;constructor(e={}){this.scanner=new j(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let r=e,o=[...t].sort((i,a)=>a.start-i.start),n=new Set;for(let i of o)n.add(i.type),r=r.slice(0,i.start)+`[REDACTED:${i.type}]`+r.slice(i.end);return{text:r,redacted:t.length,secretTypes:[...n].sort()}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[r,o]of Object.entries(e)){let n=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(n.includes("password")||n.includes("passwd")||n==="pwd"||n.includes("secret")||n.includes("token")||n.includes("cookie")||n.includes("authorization")||n.includes("apikey")||n.includes("accesskey")||n.includes("privatekey")||n.includes("clientsecret")||n.includes("credential")){t[r]="[REDACTED]";continue}t[r]=this.sanitizeValue(o)}return t}return e}};var st=new k;import{homedir as Ke}from"node:os";import{join as De}from"node:path";import{DeleteObjectCommand as ge,GetObjectCommand as ye,HeadObjectCommand as he,ListObjectsV2Command as Se,PutObjectCommand as we,S3Client as ve}from"@aws-sdk/client-s3";import{getSignedUrl as be}from"@aws-sdk/s3-request-presigner";var M=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new ve({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 we({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await be(this.client,new ye({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 he({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 ge({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let o=await this.client.send(new Se({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 z,mkdir as xe,readFile as je,readdir as ke,rm as Me,stat as V,writeFile as Re}from"node:fs/promises";import{dirname as Ae,join as Pe,relative as L,resolve as Ce}from"node:path";var h=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Ce(this.root,t)}async put(e,t){let r=this.path(e);await xe(Ae(r),{recursive:!0}),await Re(r,t)}async get(e){try{return await je(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 z(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 z(t)}catch{return r}let o=async i=>{let a=await ke(i,{withFileTypes:!0});for(let c of a){let u=Pe(i,c.name);if(c.isDirectory()){await o(u);continue}let p=await V(u);r.push({key:L(this.root,u),size:p.size,updatedAt:p.mtime.toISOString()})}},n=await V(t);return n.isDirectory()?await o(t):r.push({key:L(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),r}};import{DeleteObjectCommand as Ee,GetObjectCommand as Te,HeadObjectCommand as Ie,ListObjectsV2Command as _e,PutObjectCommand as Oe,S3Client as $e}from"@aws-sdk/client-s3";import{getSignedUrl as Ne}from"@aws-sdk/s3-request-presigner";var S=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new $e({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 Oe({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await Ne(this.client,new Te({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 Ie({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 Ee({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let o=await this.client.send(new _e({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 P(s,e){return console.warn(e),new h(s)}function B(s){let e=s.localRoot??De(Ke(),".toolnet-memory","storage");if(s.provider==="r2"){let t=s.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new S({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):P(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 S({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):P(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 M({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):P(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new h(e)}function ze(s){return new Promise(e=>setTimeout(e,s))}async function F(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(a){if(n=a,i>=t)break;let c=Math.min(o,r*2**(i-1)),u=Math.floor(Math.random()*Math.max(1,c*.2));await ze(c+u)}throw n}var Ve=new Set(["put","get","getText","delete","list"]);function U(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)=>F(()=>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 H(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 R=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(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let 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=H(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))}};var Le=["memories/current.json","vectors/current.json","graph/current.json","graph/manifest.json","graph/resolution/current.json","code/chunks/current.json","code/vectors/current.json","code/architecture/current.json","code/architecture/entry-points.json","code/architecture/hotspots.json","code/architecture/layers.json","code/architecture/clusters.json","code/analysis/current.json","code/analysis/dead-code.json","code/analysis/dependencies.json","code/visualization/graph.json"],m=class{constructor(e){this.storage=e}storage;projectPrefix(e){return`projects/${e}`}snapshotPrefix(e,t){return[this.projectPrefix(e),"snapshots",t].join("/")}async create(e,t="automatic",r){let o=new Date().toISOString(),n=o.replace(/[:.]/g,"-"),i=this.projectPrefix(e),a=this.snapshotPrefix(e,n),c=[];for(let p of Le){let d=`${i}/${p}`,C=await this.storage.get(d);C&&(await this.storage.put(`${a}/${p}`,C,"application/json"),c.push(p))}if(c.length===0)return null;let u={version:1,id:n,projectId:e,createdAt:o,reason:t,objects:c,metadata:r};return await this.storage.put(`${a}/snapshot.json`,JSON.stringify(u,null,2),"application/json"),u}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),o=(await this.storage.list(t)).filter(i=>i.key.endsWith("/snapshot.json")),n=[];for(let i of o){let a=await this.storage.getText(i.key);if(a)try{n.push(JSON.parse(a))}catch{}}return n.sort((i,a)=>a.createdAt.localeCompare(i.createdAt))}async restore(e,t){let r=this.snapshotPrefix(e,t),o=await this.storage.getText(`${r}/snapshot.json`);if(!o)throw new Error(`Snapshot not found: ${t}`);let n=JSON.parse(o);if(n.projectId!==e)throw new Error("Snapshot project mismatch");let i=this.projectPrefix(e),a=[];for(let c of n.objects){let u=await this.storage.get(`${r}/${c}`);u&&(await this.storage.put(`${i}/${c}`,u,"application/json"),a.push(c))}return{restored:a}}async remove(e,t){let r=this.snapshotPrefix(e,t),o=await this.storage.list(r);for(let n of o)await this.storage.delete(n.key);return o.length}async prune(e,t=10){let o=(await this.list(e)).slice(t),n=0;for(let i of o)await this.remove(e,i.id),n++;return n}};async function Y(s,e){let t=new m(s),o=(await t.list(e))[0];if(!o)throw new Error("No snapshot available");let n=await t.restore(e,o.id);return{snapshot:o.id,createdAt:o.createdAt,...n}}async function Be(){let s=process.argv[2],e=E(),t=new x().detect(),r=U(B({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),o=new R(r,t.id,t.name,t.remote??t.name),n=new m(o);if(s==="list"){let i=await n.list(t.id);console.log(i.map(a=>({id:a.id,createdAt:a.createdAt,reason:a.reason})));return}if(s==="create"){let i=process.argv.slice(3).join(" ")||"manual-cli";console.log(await n.create(t.id,i));return}if(s==="restore"){let i=process.argv[3];if(!i)throw new Error("snapshot id required");await n.create(t.id,"before-cli-restore"),console.log(await n.restore(t.id,i));return}if(s==="recover-latest"){console.log(await Y(o,t.id));return}throw new Error("Usage: snapshot-cli list|create|restore|recover-latest")}Be().catch(s=>{console.error(s instanceof Error?s.message:s),process.exit(1)});
1
+ import"dotenv/config";import{existsSync as oe,readFileSync as se}from"node:fs";import{homedir as ie}from"node:os";import{join as ae}from"node:path";function ce(n){let e=n.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
2
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function ue(){let n=process.env.TOOLNET_GLOBAL_ENV??ae(ie(),".config","toolnet-memory",".env");if(!oe(n))return;let e=se(n,"utf8");for(let t of e.split(/\r?\n/)){let r=t.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let o=r.indexOf("=");if(o<=0)continue;let s=r.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=ce(r.slice(o+1)))}}ue();function h(n,e){return n===void 0?e:["1","true","yes","on"].includes(n.toLowerCase())}function S(n,e){if(!n)return e;let t=Number(n);return Number.isFinite(t)?t:e}function K(){return{memory:{autoCapture:h(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:h(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:h(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:h(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:h(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 ye}from"node:crypto";import{existsSync as M,mkdirSync as he,readFileSync as Se,renameSync as ve,writeFileSync as xe}from"node:fs";import{basename as be,dirname as R,join as x,parse as G,resolve as m}from"node:path";import{createHash as L}from"node:crypto";import{spawnSync as de}from"node:child_process";var v="git-remote-v1",pe=new Set(["github.com","gitlab.com","bitbucket.org"]);function z(n,e){let t=e.replaceAll("\\","/").replace(/^\/+/u,"").replace(/\/+$/u,"").replace(/\.git$/iu,"").replace(/\/+/gu,"/");return!t||t==="."||t===".."||t.split("/").some(r=>!r||r==="."||r==="..")?null:(pe.has(n)&&(t=t.toLowerCase()),t)}function le(n){let e;try{e=new URL(n)}catch{return null}if(!["https:","http:","ssh:","git:"].includes(e.protocol))return null;let t=e.hostname.trim().toLowerCase();if(!t)return null;let r=e.protocol==="https:"&&e.port==="443"||e.protocol==="http:"&&e.port==="80"||e.protocol==="ssh:"&&e.port==="22",o=e.port&&!r?`${t}:${e.port}`:t,s=z(t,e.pathname);return s?`${o}/${s}`:null}function me(n){let e=n.match(/^(?:[^@\s/:]+@)?([^:/\s]+):(.+)$/u);if(!e)return null;let t=e[1]?.trim().toLowerCase();if(!t||t.length===1)return null;let r=z(t,e[2]??"");return r?`${t}/${r}`:null}function $(n){let e=n.trim();return e?e.includes("://")?le(e):me(e):null}function fe(n){return L("sha256").update(`${v}:${n}`).digest("hex")}function V(n){return L("sha256").update(`toolnet-project:${v}:${n}`).digest("hex").slice(0,16)}function ge(n){return n.split("/").filter(Boolean).at(-1)?.trim()||null}function T(n,e){let t=de("git",["-C",n,...e],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return t.error||t.status!==0?null:t.stdout?.trim()||null}function D(n,e){let t=ge(n);return t?{scheme:v,canonicalRemote:n,fingerprint:fe(n),repositoryName:t,source:e}:null}function B(n){let e=T(n,["remote","get-url","origin"]);if(e){let o=$(e);if(o)return D(o,"origin")}let t=T(n,["remote"]);if(!t)return null;let r=new Set;for(let o of t.split(/\r?\n/u).map(s=>s.trim()).filter(Boolean)){let s=T(n,["remote","get-url",o]);if(!s)continue;let i=$(s);i&&r.add(i)}return r.size!==1?null:D([...r][0],"unique-remote")}var H=".toolnet",we="project.json";function je(n){return ye("sha256").update(n).digest("hex").slice(0,16)}function f(n){return x(n,H,we)}function J(n){return M(f(n))}function F(n,e){let t=m(n),r=G(t).root;for(;;){if(J(t))return t;if(t===r||e&&t===m(e))break;let o=R(t);if(o===t)break;t=o}return null}function _(n){let e=m(n),t=G(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(s=>M(x(e,s))))return e;if(e===t)break;let o=R(e);if(o===e)break;e=o}return m(n)}function j(n){let e;try{e=JSON.parse(Se(n,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${n}: ${o instanceof Error?o.message:String(o)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${n}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${n}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${n}`);let r=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:R(R(n)),createdAt:typeof t.createdAt=="string"?t.createdAt:r,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:r,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function k(n,e){let t=x(n,H);he(t,{recursive:!0});let r=f(n),o=`${r}.tmp-${process.pid}`;xe(o,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),ve(o,r)}function l(n,e){return{id:n.id,name:n.name,remote:n.remote,rootPath:e,createdAt:n.createdAt,updatedAt:n.updatedAt,graphVersion:n.graphVersion,memoryVersion:n.memoryVersion,metadata:n.metadata}}function O(n){return{version:1,scheme:v,canonicalRemote:n.canonicalRemote,fingerprint:n.fingerprint,repositoryName:n.repositoryName}}function ke(n){let e=n.metadata?.toolnetIdentity;if(!e||typeof e!="object"||Array.isArray(e))return null;let t=e;return typeof t.fingerprint=="string"?t.fingerprint:null}var A=class{adopt(e,t){let r=_(m(e));if(!t.id.trim())throw new Error("PROJECT_ADOPTION_INVALID_ID");if(!t.name.trim())throw new Error("PROJECT_ADOPTION_INVALID_NAME");if(!t.remote.trim())throw new Error("PROJECT_ADOPTION_INVALID_REMOTE");if(J(r)){let a=j(f(r));if(a.id!==t.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${a.id}`,`requested=${t.id}`].join(" "));return l(a,r)}let o=new Date().toISOString(),s={...t.metadata};t.gitIdentity&&(s.toolnetIdentity=O(t.gitIdentity));let i={version:1,id:t.id.trim(),name:t.name.trim(),remote:t.remote.trim(),rootPath:r,createdAt:t.createdAt??o,updatedAt:o,graphVersion:t.graphVersion??0,memoryVersion:t.memoryVersion??0,metadata:Object.keys(s).length?s:void 0};return k(r,i),l(i,r)}recordGitIdentity(e,t,r={}){let o=this.requireExisting(e),s=f(o.rootPath),i=j(s),a=ke(i);if(a&&a!==t.fingerprint&&!r.allowRebind)throw new Error(["PROJECT_GIT_REMOTE_CHANGED",`existing=${a}`,`current=${t.fingerprint}`,"Use explicit rebind only when this repository identity change is intentional."].join(" "));let c=i.metadata?.toolnetIdentity;return c&&typeof c=="object"&&!Array.isArray(c)&&c.fingerprint===t.fingerprint||(i.metadata={...i.metadata,toolnetIdentity:O(t)},i.updatedAt=new Date().toISOString(),k(o.rootPath,i)),l(i,o.rootPath)}findExisting(e=process.cwd()){let t=m(e),r=_(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(c=>M(x(r,c))),i=F(t,s?r:void 0);if(!i)return null;let a=j(f(i));return l(a,i)}requireExisting(e=process.cwd()){let t=this.findExisting(e);if(!t)throw new Error("PROJECT_NOT_INITIALIZED");return t}detect(e=process.cwd()){let t=m(e),r=_(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(y=>M(x(r,y))),i=F(t,s?r:void 0);if(i){let y=f(i),p=j(y);return p.rootPath!==i&&(p.rootPath=i,p.updatedAt=new Date().toISOString(),k(i,p)),l(p,i)}let a=new Date().toISOString(),c=be(r),u=B(r),d={version:1,id:u?V(u.canonicalRemote):je(r),name:c,remote:u?.repositoryName??c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0,metadata:u?{toolnetIdentity:O(u)}:void 0};return k(r,d),l(d,r)}};var Me=[{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"}],Re=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function U(n){return n.normalize("NFKC").trim().toLowerCase()}function Ae(n){if(n.length===0)return 0;let e=new Map;for(let r of n)e.set(r,(e.get(r)??0)+1);let t=0;for(let r of e.values()){let o=r/n.length;t-=o*Math.log2(o)}return t}function Pe(n){return/^[a-f0-9]{32}$/iu.test(n)||/^[a-f0-9]{40}$/iu.test(n)||/^[a-f0-9]{64}$/iu.test(n)}function Ce(n,e,t){let r=n.slice(Math.max(0,e-48),e),o=n.slice(t,Math.min(n.length,t+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${r} ${o}`)}function Ie(n,e){return n.start<e.end&&e.start<n.end}function Y(n){return n.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var P=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let r=U(t);r&&this.allowValues.add(r)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let s of Me){let i=new RegExp(s.regex.source,s.regex.flags);for(let a of e.matchAll(i))a.index===void 0||!a[0]||this.allowed(a[0])||t.push({type:s.type,value:a[0],start:a.index,end:a.index+a[0].length,confidence:s.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let r=Y(t),o=[];for(let s of r)o.some(i=>Ie(i,s))||o.push(s);return Y(o)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=U(e);return Re.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],r=/[A-Za-z0-9_+/=-]{32,160}/g;for(let o of e.matchAll(r)){if(o.index===void 0||!o[0])continue;let s=o[0];this.allowed(s)||Pe(s)||!/[A-Za-z]/u.test(s)||!/[0-9]/u.test(s)||Ce(e,o.index,o.index+s.length)&&(Ae(s)<3.7||t.push({type:"high_entropy_secret",value:s,start:o.index,end:o.index+s.length,confidence:"heuristic"}))}return t}};var C=class{scanner;constructor(e={}){this.scanner=new P(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let r=e,o=[...t].sort((i,a)=>a.start-i.start),s=new Set;for(let i of o)s.add(i.type),r=r.slice(0,i.start)+`[REDACTED:${i.type}]`+r.slice(i.end);return{text:r,redacted:t.length,secretTypes:[...s].sort()}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[r,o]of Object.entries(e)){let s=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(s.includes("password")||s.includes("passwd")||s==="pwd"||s.includes("secret")||s.includes("token")||s.includes("cookie")||s.includes("authorization")||s.includes("apikey")||s.includes("accesskey")||s.includes("privatekey")||s.includes("clientsecret")||s.includes("credential")){t[r]="[REDACTED]";continue}t[r]=this.sanitizeValue(o)}return t}return e}};var kt=new C;import{homedir as Xe}from"node:os";import{join as et}from"node:path";import{DeleteObjectCommand as Ee,GetObjectCommand as Te,HeadObjectCommand as _e,ListObjectsV2Command as Oe,PutObjectCommand as Ne,S3Client as Ke}from"@aws-sdk/client-s3";import{getSignedUrl as $e}from"@aws-sdk/s3-request-presigner";var I=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Ke({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 Ne({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await $e(this.client,new Te({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 _e({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 Ee({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let o=await this.client.send(new Oe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let s of o.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});r=o.IsTruncated?o.NextContinuationToken:void 0}while(r);return t}};import{access as W,mkdir as De,readFile as Le,readdir as ze,rm as Ve,stat as Z,writeFile as Be}from"node:fs/promises";import{dirname as Fe,join as Ge,relative as q,resolve as He}from"node:path";var b=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return He(this.root,t)}async put(e,t){let r=this.path(e);await De(Fe(r),{recursive:!0}),await Be(r,t)}async get(e){try{return await Le(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 Ve(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 a=await ze(i,{withFileTypes:!0});for(let c of a){let u=Ge(i,c.name);if(c.isDirectory()){await o(u);continue}let d=await Z(u);r.push({key:q(this.root,u),size:d.size,updatedAt:d.mtime.toISOString()})}},s=await Z(t);return s.isDirectory()?await o(t):r.push({key:q(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),r}};import{DeleteObjectCommand as Je,GetObjectCommand as Ue,HeadObjectCommand as Ye,ListObjectsV2Command as We,PutObjectCommand as Ze,S3Client as qe}from"@aws-sdk/client-s3";import{getSignedUrl as Qe}from"@aws-sdk/s3-request-presigner";var w=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new qe({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 Ze({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await Qe(this.client,new Ue({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 Ye({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 Je({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let o=await this.client.send(new We({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let s of o.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});r=o.IsTruncated?o.NextContinuationToken:void 0}while(r);return t}};function N(n,e){return console.warn(e),new b(n)}function Q(n){let e=n.localRoot??et(Xe(),".toolnet-memory","storage");if(n.provider==="r2"){let t=n.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new w({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):N(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(n.provider==="s3"){let t=n.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new w({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):N(e,"[storage] S3 credentials missing. Using local fallback.")}if(n.provider==="huggingface"){let t=n.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new I({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):N(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new b(e)}function tt(n){return new Promise(e=>setTimeout(e,n))}async function X(n,e={}){let t=Math.max(1,e.attempts??3),r=e.baseDelayMs??150,o=e.maxDelayMs??2e3,s;for(let i=1;i<=t;i++)try{return await n()}catch(a){if(s=a,i>=t)break;let c=Math.min(o,r*2**(i-1)),u=Math.floor(Math.random()*Math.max(1,c*.2));await tt(c+u)}throw s}var rt=new Set(["put","get","getText","delete","list"]);function ee(n,e={}){return new Proxy(n,{get(t,r){let o=Reflect.get(t,r,t);return typeof o!="function"?o:rt.has(r)?(...s)=>X(()=>Promise.resolve(o.apply(t,s)),e):o.bind(t)}})}function te(n){let e=n.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function re(n){let e=n.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let 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 E=class{constructor(e,t,r,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=te(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(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let s={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:r,updatedAt:t};await this.provider.put(e,JSON.stringify(s,null,2)+`
4
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=re(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))}};var nt=["memories/current.json","vectors/current.json","graph/current.json","graph/manifest.json","graph/resolution/current.json","code/chunks/current.json","code/vectors/current.json","code/architecture/current.json","code/architecture/entry-points.json","code/architecture/hotspots.json","code/architecture/layers.json","code/architecture/clusters.json","code/analysis/current.json","code/analysis/dead-code.json","code/analysis/dependencies.json","code/visualization/graph.json"],g=class{constructor(e){this.storage=e}storage;projectPrefix(e){return`projects/${e}`}snapshotPrefix(e,t){return[this.projectPrefix(e),"snapshots",t].join("/")}async create(e,t="automatic",r){let o=new Date().toISOString(),s=o.replace(/[:.]/g,"-"),i=this.projectPrefix(e),a=this.snapshotPrefix(e,s),c=[];for(let d of nt){let y=`${i}/${d}`,p=await this.storage.get(y);p&&(await this.storage.put(`${a}/${d}`,p,"application/json"),c.push(d))}if(c.length===0)return null;let u={version:1,id:s,projectId:e,createdAt:o,reason:t,objects:c,metadata:r};return await this.storage.put(`${a}/snapshot.json`,JSON.stringify(u,null,2),"application/json"),u}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),o=(await this.storage.list(t)).filter(i=>i.key.endsWith("/snapshot.json")),s=[];for(let i of o){let a=await this.storage.getText(i.key);if(a)try{s.push(JSON.parse(a))}catch{}}return s.sort((i,a)=>a.createdAt.localeCompare(i.createdAt))}async restore(e,t){let r=this.snapshotPrefix(e,t),o=await this.storage.getText(`${r}/snapshot.json`);if(!o)throw new Error(`Snapshot not found: ${t}`);let s=JSON.parse(o);if(s.projectId!==e)throw new Error("Snapshot project mismatch");let i=this.projectPrefix(e),a=[];for(let c of s.objects){let u=await this.storage.get(`${r}/${c}`);u&&(await this.storage.put(`${i}/${c}`,u,"application/json"),a.push(c))}return{restored:a}}async remove(e,t){let r=this.snapshotPrefix(e,t),o=await this.storage.list(r);for(let s of o)await this.storage.delete(s.key);return o.length}async prune(e,t=10){let o=(await this.list(e)).slice(t),s=0;for(let i of o)await this.remove(e,i.id),s++;return s}};async function ne(n,e){let t=new g(n),o=(await t.list(e))[0];if(!o)throw new Error("No snapshot available");let s=await t.restore(e,o.id);return{snapshot:o.id,createdAt:o.createdAt,...s}}async function ot(){let n=process.argv[2],e=K(),t=new A().detect(),r=ee(Q({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),o=new E(r,t.id,t.name,t.remote??t.name),s=new g(o);if(n==="list"){let i=await s.list(t.id);console.log(i.map(a=>({id:a.id,createdAt:a.createdAt,reason:a.reason})));return}if(n==="create"){let i=process.argv.slice(3).join(" ")||"manual-cli";console.log(await s.create(t.id,i));return}if(n==="restore"){let i=process.argv[3];if(!i)throw new Error("snapshot id required");await s.create(t.id,"before-cli-restore"),console.log(await s.restore(t.id,i));return}if(n==="recover-latest"){console.log(await ne(o,t.id));return}throw new Error("Usage: snapshot-cli list|create|restore|recover-latest")}ot().catch(n=>{console.error(n instanceof Error?n.message:n),process.exit(1)});
@@ -1,4 +1,4 @@
1
- import{existsSync as $e,readFileSync as Le}from"node:fs";import{homedir as Ge}from"node:os";import{join as We}from"node:path";function ze(t){let e=t.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
2
- `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Ue(){let t=process.env.TOOLNET_GLOBAL_ENV??We(Ge(),".config","toolnet-memory",".env");if(!$e(t))return;let e=Le(t,"utf8");for(let r of e.split(/\r?\n/)){let o=r.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let n=o.indexOf("=");if(n<=0)continue;let i=o.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=ze(o.slice(n+1)))}}Ue();function k(t,e){return t===void 0?e:["1","true","yes","on"].includes(t.toLowerCase())}function x(t,e){if(!t)return e;let r=Number(t);return Number.isFinite(r)?r:e}function z(){return{memory:{autoCapture:k(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:k(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:k(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:k(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:x(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:x(process.env.MEMORY_RERANK_TOP,10),finalContext:x(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:x(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:k(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:x(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Ve}from"node:crypto";import{existsSync as O,mkdirSync as Je,readFileSync as Be,renameSync as Ye,writeFileSync as Ze}from"node:fs";import{basename as qe,dirname as A,join as S,parse as Y,resolve as m}from"node:path";var Z=".toolnet",Qe="project.json";function Xe(t){return Ve("sha256").update(t).digest("hex").slice(0,16)}function M(t){return S(t,Z,Qe)}function et(t){return O(M(t))}function U(t,e){let r=m(t),o=Y(r).root;for(;;){if(et(r))return r;if(r===o||e&&r===m(e))break;let n=A(r);if(n===r)break;r=n}return null}function V(t){let e=m(t),r=Y(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>O(S(e,i))))return e;if(e===r)break;let n=A(e);if(n===e)break;e=n}return m(t)}function J(t){let e;try{e=JSON.parse(Be(t,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${t}: ${n instanceof Error?n.message:String(n)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${t}`);let r=e;if(typeof r.id!="string"||!r.id.trim())throw new Error(`ToolNet project manifest is missing id: ${t}`);if(typeof r.name!="string"||!r.name.trim())throw new Error(`ToolNet project manifest is missing name: ${t}`);let o=new Date().toISOString();return{version:1,id:r.id,name:r.name,remote:typeof r.remote=="string"&&r.remote.trim()?r.remote:r.name,rootPath:typeof r.rootPath=="string"?r.rootPath:A(A(t)),createdAt:typeof r.createdAt=="string"?r.createdAt:o,updatedAt:typeof r.updatedAt=="string"?r.updatedAt:o,graphVersion:typeof r.graphVersion=="number"?r.graphVersion:0,memoryVersion:typeof r.memoryVersion=="number"?r.memoryVersion:0,metadata:r.metadata&&typeof r.metadata=="object"?r.metadata:void 0}}function B(t,e){let r=S(t,Z);Je(r,{recursive:!0});let o=M(t),n=`${o}.tmp-${process.pid}`;Ze(n,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),Ye(n,o)}function F(t,e){return{id:t.id,name:t.name,remote:t.remote,rootPath:e,createdAt:t.createdAt,updatedAt:t.updatedAt,graphVersion:t.graphVersion,memoryVersion:t.memoryVersion,metadata:t.metadata}}var I=class{findExisting(e=process.cwd()){let r=m(e),o=V(r),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(l=>O(S(o,l))),s=U(r,i?o:void 0);if(!s)return null;let c=J(M(s));return F(c,s)}requireExisting(e=process.cwd()){let r=this.findExisting(e);if(!r)throw new Error("PROJECT_NOT_INITIALIZED");return r}detect(e=process.cwd()){let r=m(e),o=V(r),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>O(S(o,d))),s=U(r,i?o:void 0);if(s){let d=M(s),a=J(d);return a.rootPath!==s&&(a.rootPath=s,a.updatedAt=new Date().toISOString(),B(s,a)),F(a,s)}let c=new Date().toISOString(),l=qe(o),u={version:1,id:Xe(o),name:l,remote:l,rootPath:o,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return B(o,u),F(u,o)}};var tt=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_-]{20,}\b/g,confidence:"exact"},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g,confidence:"exact"},{type:"aws_access_key",regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,confidence:"exact"},{type:"github_token",regex:/\b(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{40,255})\b/g,confidence:"exact"},{type:"stripe_secret_key",regex:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,confidence:"exact"},{type:"google_api_key",regex:/\bAIza[A-Za-z0-9_-]{30,}\b/g,confidence:"exact"},{type:"slack_token",regex:/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/g,confidence:"exact"},{type:"npm_token",regex:/\bnpm_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi,confidence:"high"},{type:"jwt",regex:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,confidence:"exact"},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,confidence:"exact"},{type:"password_assignment",regex:/\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^"' \t\r\n]{6,}["']?/gi,confidence:"high"},{type:"secret_assignment",regex:/\b(?:secret|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\s*[:=]\s*["']?[^"' \t\r\n]{8,}["']?/gi,confidence:"high"},{type:"cookie",regex:/\b(?:cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi,confidence:"high"},{type:"url_credentials",regex:/\bhttps?:\/\/[^:/@\s]+:[^/@\s]{4,}@[^/\s]+/gi,confidence:"high"}],rt=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function q(t){return t.normalize("NFKC").trim().toLowerCase()}function ot(t){if(t.length===0)return 0;let e=new Map;for(let o of t)e.set(o,(e.get(o)??0)+1);let r=0;for(let o of e.values()){let n=o/t.length;r-=n*Math.log2(n)}return r}function nt(t){return/^[a-f0-9]{32}$/iu.test(t)||/^[a-f0-9]{40}$/iu.test(t)||/^[a-f0-9]{64}$/iu.test(t)}function it(t,e,r){let o=t.slice(Math.max(0,e-48),e),n=t.slice(r,Math.min(t.length,r+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${o} ${n}`)}function st(t,e){return t.start<e.end&&e.start<t.end}function Q(t){return t.sort((e,r)=>e.start!==r.start?e.start-r.start:r.end-r.start-(e.end-e.start))}var R=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let r of e.allowValues??[]){let o=q(r);o&&this.allowValues.add(o)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let r=[];for(let i of tt){let s=new RegExp(i.regex.source,i.regex.flags);for(let c of e.matchAll(s))c.index===void 0||!c[0]||this.allowed(c[0])||r.push({type:i.type,value:c[0],start:c.index,end:c.index+c[0].length,confidence:i.confidence})}this.enableEntropyHeuristic&&r.push(...this.entropyMatches(e));let o=Q(r),n=[];for(let i of o)n.some(s=>st(s,i))||n.push(i);return Q(n)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let r=q(e);return rt.has(r)?!0:this.allowValues.has(r)}entropyMatches(e){let r=[],o=/[A-Za-z0-9_+/=-]{32,160}/g;for(let n of e.matchAll(o)){if(n.index===void 0||!n[0])continue;let i=n[0];this.allowed(i)||nt(i)||!/[A-Za-z]/u.test(i)||!/[0-9]/u.test(i)||it(e,n.index,n.index+i.length)&&(ot(i)<3.7||r.push({type:"high_entropy_secret",value:i,start:n.index,end:n.index+i.length,confidence:"heuristic"}))}return r}};var E=class{scanner;constructor(e={}){this.scanner=new R(e)}sanitize(e){let r=this.scanner.scan(e);if(r.length===0)return{text:e,redacted:0,secretTypes:[]};let o=e,n=[...r].sort((s,c)=>c.start-s.start),i=new Set;for(let s of n)i.add(s.type),o=o.slice(0,s.start)+`[REDACTED:${s.type}]`+o.slice(s.end);return{text:o,redacted:r.length,secretTypes:[...i].sort()}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(r=>this.sanitizeValue(r));if(e&&typeof e=="object"){let r={};for(let[o,n]of Object.entries(e)){let i=o.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")){r[o]="[REDACTED]";continue}r[o]=this.sanitizeValue(n)}return r}return e}};var Ur=new E;import{homedir as It}from"node:os";import{join as Rt}from"node:path";import{DeleteObjectCommand as at,GetObjectCommand as ut,HeadObjectCommand as lt,ListObjectsV2Command as dt,PutObjectCommand as pt,S3Client as gt}from"@aws-sdk/client-s3";import{getSignedUrl as ft}from"@aws-sdk/s3-request-presigner";var T=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new gt({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,r,o="application/octet-stream"){let n=typeof r=="string"?Buffer.from(r,"utf8"):r;await this.client.send(new pt({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let r=await ft(this.client,new ut({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(r,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`HF download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let r=await this.get(e);return r?Buffer.from(r).toString("utf8"):null}async exists(e){try{return await this.client.send(new lt({Bucket:this.bucket,Key:e})),!0}catch(r){if(typeof r=="object"&&r!==null&&"$metadata"in r&&r.$metadata?.httpStatusCode===404)return!1;throw r}}async delete(e){await this.client.send(new at({Bucket:this.bucket,Key:e}))}async list(e=""){let r=[],o;do{let n=await this.client.send(new dt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of n.Contents??[])i.Key&&r.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return r}};import{access as X,mkdir as mt,readFile as yt,readdir as ht,rm as kt,stat as ee,writeFile as xt}from"node:fs/promises";import{dirname as St,join as Ct,relative as te,resolve as bt}from"node:path";var C=class{constructor(e){this.root=e}root;name="local";path(e){let r=e.replace(/^\/+/,"");return bt(this.root,r)}async put(e,r){let o=this.path(e);await mt(St(o),{recursive:!0}),await xt(o,r)}async get(e){try{return await yt(this.path(e))}catch(r){if(typeof r=="object"&&r!==null&&"code"in r&&r.code==="ENOENT")return null;throw r}}async getText(e){let r=await this.get(e);return r?Buffer.from(r).toString("utf8"):null}async exists(e){try{return await X(this.path(e)),!0}catch{return!1}}async delete(e){await kt(this.path(e),{force:!0})}async list(e=""){let r=this.path(e),o=[];try{await X(r)}catch{return o}let n=async s=>{let c=await ht(s,{withFileTypes:!0});for(let l of c){let u=Ct(s,l.name);if(l.isDirectory()){await n(u);continue}let d=await ee(u);o.push({key:te(this.root,u),size:d.size,updatedAt:d.mtime.toISOString()})}},i=await ee(r);return i.isDirectory()?await n(r):o.push({key:te(this.root,r),size:i.size,updatedAt:i.mtime.toISOString()}),o}};import{DeleteObjectCommand as vt,GetObjectCommand as wt,HeadObjectCommand as Pt,ListObjectsV2Command as jt,PutObjectCommand as Ot,S3Client as At}from"@aws-sdk/client-s3";import{getSignedUrl as Mt}from"@aws-sdk/s3-request-presigner";var b=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new At({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,r,o="application/octet-stream"){let n=typeof r=="string"?Buffer.from(r,"utf8"):r;await this.client.send(new Ot({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let r=await Mt(this.client,new wt({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(r,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`${this.name} download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let r=await this.get(e);return r?Buffer.from(r).toString("utf8"):null}async exists(e){try{return await this.client.send(new Pt({Bucket:this.bucket,Key:e})),!0}catch(r){if(typeof r=="object"&&r!==null&&"$metadata"in r&&r.$metadata?.httpStatusCode===404)return!1;throw r}}async delete(e){await this.client.send(new vt({Bucket:this.bucket,Key:e}))}async list(e=""){let r=[],o;do{let n=await this.client.send(new jt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of n.Contents??[])i.Key&&r.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return r}};function H(t,e){return console.warn(e),new C(t)}function re(t){let e=t.localRoot??Rt(It(),".toolnet-memory","storage");if(t.provider==="r2"){let r=t.r2;return r?.accountId&&r.bucket&&r.accessKeyId&&r.secretAccessKey?new b({name:"r2",endpoint:`https://${r.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:r.bucket,forcePathStyle:!0,accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey}):H(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(t.provider==="s3"){let r=t.s3;return r?.bucket&&r.accessKeyId&&r.secretAccessKey?new b({name:"s3",endpoint:r.endpoint,region:r.region??"us-east-1",bucket:r.bucket,forcePathStyle:r.forcePathStyle??!1,accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey}):H(e,"[storage] S3 credentials missing. Using local fallback.")}if(t.provider==="huggingface"){let r=t.huggingface;return r?.namespace&&r.bucket&&r.accessKeyId&&r.secretAccessKey?new T({namespace:r.namespace,bucket:r.bucket,accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey}):H(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new C(e)}function Et(t){return new Promise(e=>setTimeout(e,t))}async function oe(t,e={}){let r=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,n=e.maxDelayMs??2e3,i;for(let s=1;s<=r;s++)try{return await t()}catch(c){if(i=c,s>=r)break;let l=Math.min(n,o*2**(s-1)),u=Math.floor(Math.random()*Math.max(1,l*.2));await Et(l+u)}throw i}var Tt=new Set(["put","get","getText","delete","list"]);function ne(t,e={}){return new Proxy(t,{get(r,o){let n=Reflect.get(r,o,r);return typeof n!="function"?n:Tt.has(o)?(...i)=>oe(()=>Promise.resolve(n.apply(r,i)),e):n.bind(r)}})}function ie(t){let e=t.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function se(t){let e=t.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 r=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(o)return`${o[1]}memory/records/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),o)return`${o[1]}memory/vectors/${o[2]}`;if(o=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),o)return`${o[1]}code/graph/${o[2]}`;let n=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return n?`${n[1]}memory/records/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),n?`${n[1]}memory/vectors/${n[2]}`:(n=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),n?`${n[1]}code/graph/${n[2]}`:e))}var D=class{constructor(e,r,o,n){this.provider=e;this.name=e.name,this.projectId=r,this.projectName=o,this.folder=ie(n??o),this.sourcePrefix=`projects/${r}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,r=new Date().toISOString(),o=r,n=await this.provider.getText(e);if(n){let s;try{s=JSON.parse(n)}catch(c){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${c instanceof Error?c.message:String(c)}`)}if(typeof s.id=="string"&&s.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${s.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof s.createdAt=="string"&&(o=s.createdAt)}let i={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:r};await this.provider.put(e,JSON.stringify(i,null,2)+`
4
- `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=se(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,r,o){return await this.ensureRegistered(),this.provider.put(this.key(e),r,o)}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{existsSync as de,readFileSync as Ht,readdirSync as ae}from"node:fs";import{join as v}from"node:path";var Mn=new Int32Array(new SharedArrayBuffer(4));import{closeSync as Dn,existsSync as Dt,fsyncSync as _n,mkdirSync as Nn,openSync as Fn,readFileSync as _t,renameSync as Hn,writeFileSync as Kn}from"node:fs";import{dirname as Ln,join as Nt}from"node:path";function Ft(t){return Nt(t.rootPath,".toolnet","work","current.json")}function ce(t){let e=Ft(t);if(!Dt(e))return null;try{let r=JSON.parse(_t(e,"utf8"));return r.version!==1||r.projectId!==t.id?null:r}catch{return null}}function pe(t){if(!de(t))return null;try{return JSON.parse(Ht(t,"utf8"))}catch{return null}}function ue(t,e){if(!de(t))return[];let r=[];for(let o of ae(t,{withFileTypes:!0})){if(!o.isDirectory())continue;let n=v(t,o.name);for(let i of ae(n,{withFileTypes:!0})){if(!i.isDirectory())continue;let s=pe(v(n,i.name,"state.json"));s&&s.version===1&&s.projectId===e.id&&r.push(s)}}return r}function Kt(t){let e=v(t.rootPath,".toolnet","runtime","sources"),r=v(t.rootPath,".toolnet","sessions"),o=ue(e,t),n=ue(r,t),i=new Map;for(let s of n)i.set(`${s.agent}:${s.nativeSessionId}`,s);for(let s of o)i.set(`${s.agent}:${s.nativeSessionId}`,s);return Array.from(i.values())}function le(t){return t.filter(e=>!!e).sort().at(-1)}function $t(t){let e=pe(v(t.rootPath,".toolnet","runtime","opencode-status.json"));return!e||e.projectRoot&&e.projectRoot!==t.rootPath?null:e}function ge(t){let e=Kt(t),o=[...e].sort((a,p)=>(a.lastLocalEventAt??a.updatedAt).localeCompare(p.lastLocalEventAt??p.updatedAt)).at(-1),n=Array.from(new Set(e.map(a=>a.agent))).sort(),i=e.reduce((a,p)=>a+Math.max(0,p.lastSequence-p.lastRemoteSequence),0),s=$t(t),c=s?.state==="capture-failed",l=s?.state==="sync-failed",u;c?u="degraded":i>0||l?u="pending":e.length>0?u="healthy":u="unknown";let d=ce(t);return{ok:u!=="degraded",agents:n,sessions:e.length,latestAgent:o?.agent,latestSessionId:o?.nativeSessionId,lastCaptureAt:le(e.map(a=>a.lastLocalEventAt??a.updatedAt)),lastFlushAt:le(e.map(a=>a.lastRemoteAt)),pendingWal:i,currentTask:d?.currentTask?.title,currentFile:d?.activeFiles?.at(-1)??d?.filesTouched.at(-1),syncHealth:u,opencode:s?{state:s.state,reason:s.reason,timestamp:s.timestamp,error:s.error}:void 0}}import{existsSync as Te}from"node:fs";import{homedir as ur}from"node:os";import{join as lr}from"node:path";import{spawnSync as dr}from"node:child_process";import{homedir as Lt}from"node:os";import{join as w}from"node:path";function fe(t={}){return w(t.home??Lt(),".gemini")}function Gt(t={}){return w(fe(t),"antigravity-cli")}function me(t={}){return w(fe(t),"config")}function Wt(t={}){return w(me(t),"mcp_config.json")}function zt(t={}){let e=t.cwd??process.cwd();return w(e,".agents","mcp_config.json")}function ye(t={}){return[Gt(t),Wt(t),me(t),zt(t)]}import{homedir as Ut}from"node:os";import{join as he}from"node:path";function ke(t={}){let e=process.env.OPENCODE_CONFIG_DIR?.trim();if(e)return e;let r=t.xdgConfigHome??process.env.XDG_CONFIG_HOME?.trim();return r?he(r,"opencode"):he(t.home??Ut(),".config","opencode")}import{homedir as Vt}from"node:os";import{join as Jt}from"node:path";function xe(t={}){return Jt(t.home??Vt(),".claude")}import{homedir as Bt}from"node:os";import{join as P}from"node:path";function K(t={}){return t.kiroHome??process.env.KIRO_HOME??P(t.home??Bt(),".kiro")}function Yt(t={}){return P(K(t),"settings")}function $(t={}){return P(Yt(t),"mcp.json")}function Zt(t={}){return P(K(t),"hooks")}function Se(t={}){return P(Zt(t),"toolnet-memory.json")}function Ce(t={}){return[K(t),$(t)]}import{homedir as qt}from"node:os";import{join as be}from"node:path";function ve(t={}){return be(t.home??qt(),".toolnetcli")}function Qt(t={}){return be(ve(t),"config.json")}function we(t={}){let e=ve(t),r=Qt(t);return[e,r]}import{homedir as Xt}from"node:os";import{join as L}from"node:path";function Pe(t={}){if(t.kiloHome)return t.kiloHome;if(process.env.KILO_HOME)return process.env.KILO_HOME;let e=t.xdgConfigHome??process.env.XDG_CONFIG_HOME;return e?L(e,"kilo"):L(t.home??Xt(),".config","kilo")}function er(t={}){return L(Pe(t),"kilo.jsonc")}function je(t={}){let e=Pe(t),r=er(t);return[e,r]}import{homedir as tr}from"node:os";import{join as Oe,resolve as fi}from"node:path";function Ae(t={}){return t.cursorHome??Oe(t.home??tr(),".cursor")}function rr(t={}){return t.cursorConfigDir??process.env.CURSOR_CONFIG_DIR??(t.xdgConfigHome??process.env.XDG_CONFIG_HOME?Oe(t.xdgConfigHome??process.env.XDG_CONFIG_HOME,"cursor"):void 0)??Ae(t)}function Me(t={}){return Array.from(new Set([Ae(t),rr(t)]))}import{homedir as or}from"node:os";import{join as nr,resolve as ki}from"node:path";function ir(t={}){return t.copilotHome??process.env.COPILOT_HOME??nr(t.home??or(),".copilot")}function Ie(t={}){return[ir(t)]}import{homedir as sr}from"node:os";import{join as cr,resolve as bi}from"node:path";function ar(t={}){return t.grokHome??process.env.GROK_HOME??cr(t.home??sr(),".grok")}function Re(t={}){return[ar(t)]}function pr(t){return dr("sh",["-lc",`command -v ${JSON.stringify(t)} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}function g(t){let e=t.commandExists(t.command),r=t.configPaths.filter(i=>Te(i)),o=r.length>0,n=[];e&&n.push(`command:${t.command}`);for(let i of r)n.push(`config:${i}`);return{agent:t.agent,detected:e||o,commandDetected:e,configDetected:o,evidence:n}}function Ee(t){let e=t.commands.filter(s=>t.commandExists(s)),r=t.configPaths.filter(s=>Te(s)),o=e.length>0,n=r.length>0,i=[...e.map(s=>`command:${s}`),...r.map(s=>`config:${s}`)];return{agent:t.agent,detected:o||n,commandDetected:o,configDetected:n,evidence:i}}function De(t={}){let e=t.home??ur(),r=t.commandExists??pr,o=t.codexHome??process.env.CODEX_HOME??lr(e,".codex");return[g({agent:"agy",command:"agy",commandExists:r,configPaths:ye({home:e})}),g({agent:"opencode",command:"opencode",commandExists:r,configPaths:[ke({home:e,xdgConfigHome:t.xdgConfigHome})]}),g({agent:"claude",command:"claude",commandExists:r,configPaths:[xe({home:e})]}),g({agent:"kiro",command:"kiro-cli",commandExists:r,configPaths:Ce({home:e,kiroHome:t.kiroHome})}),Ee({agent:"cursor",commands:["agent","cursor-agent"],commandExists:r,configPaths:Me({home:e,cursorHome:t.cursorHome,cursorConfigDir:t.cursorConfigDir,xdgConfigHome:t.xdgConfigHome})}),g({agent:"copilot",command:"copilot",commandExists:r,configPaths:Ie({home:e,copilotHome:t.copilotHome})}),g({agent:"grok",command:"grok",commandExists:r,configPaths:Re({home:e,grokHome:t.grokHome})}),g({agent:"toolnet-cli",command:"toolnet",commandExists:r,configPaths:we({home:e})}),Ee({agent:"kilo",commands:["kilo","kilo-code"],commandExists:r,configPaths:je({home:e,kiloHome:t.kiloHome})}),g({agent:"codex",command:"codex",commandExists:r,configPaths:[o]})]}import{existsSync as G,readFileSync as gr}from"node:fs";var fr="ToolNet Memory - ",mr=["SessionStart","UserPromptSubmit","PreToolUse","PostToolUse","Stop"];function y(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function _e(t){if(!G(t))return{};let e;try{e=JSON.parse(gr(t,"utf8"))}catch(r){return{error:r instanceof Error?r.message:String(r)}}return y(e)?{value:e}:{error:"root must be a JSON object"}}function yr(t){if(!t||!y(t.mcpServers))return!1;let e=t.mcpServers["toolnet-memory"];return y(e)?typeof e.command=="string"&&e.command.trim().length>0&&Array.isArray(e.args)&&e.args.length===1&&e.args[0]==="mcp"&&e.disabled!==!0:!1}function hr(t){if(!(!y(t)||!y(t.action)))return typeof t.action.command=="string"?t.action.command:void 0}function kr(t){if(!t||t.version!=="v1"||!Array.isArray(t.hooks))return[];let e=new Set;for(let r of t.hooks){if(!y(r)||typeof r.name!="string"||!r.name.startsWith(fr))continue;let o=hr(r);!o||!o.includes("session:kiro-hook")||r.enabled!==!1&&typeof r.trigger=="string"&&e.add(r.trigger)}return[...e]}function Ne(t={}){let e=t.configFile??$(),r=t.hooksFile??Se(),o=_e(e),n=_e(r),i=!o.error&&yr(o.value),s=n.error?[]:kr(n.value),c=mr.every(p=>s.includes(p)),l=[];o.error&&l.push(`MCP config: ${o.error}`),n.error&&l.push(`Hooks config: ${n.error}`);let u=i&&c,d=G(e)||G(r),a=l.length>0?"invalid":u?"ready":d?"partial":"not-installed";return{installed:u,state:a,mcp:{configured:i,configFile:e,error:o.error},hooks:{configured:c,hooksFile:r,triggers:s,error:n.error},errors:l}}var xr={spinner:["\xB7","\u2722","\u2733","\u2736","\u273B","\u273D"],barFilled:"\u2588",barEmpty:"\u2591",phaseDone:"\u25C6",phaseActive:"\u25C7",rail:"\u2502",branch:"\u251C",corner:"\u2514",dash:"\u2014"},Sr={spinner:[".","*","+","x","*","+"],barFilled:"#",barEmpty:"-",phaseDone:"[OK]",phaseActive:"[>>]",rail:"|",branch:"|",corner:"\\",dash:"-"};function Cr(){if(process.env.TOOLNET_ASCII==="1")return!1;if(process.env.TOOLNET_UNICODE==="1")return!0;if(process.platform==="win32"){let t=process.env.TERM_PROGRAM,e=process.env.WT_SESSION,r=process.env.VSCODE_PID,o=process.env.ConEmuPID;return!!(e||r||o||t==="vscode")}return process.env.TERM!=="linux"}var W;function Fe(){return W||(W=Cr()?xr:Sr),W}var h={reset:"\x1B[0m",green:"\x1B[32m",cyan:"\x1B[36m",red:"\x1B[31m",yellow:"\x1B[33m",amber:"\x1B[38;5;214m",white:"\x1B[97m",dim:"\x1B[2m",bold:"\x1B[1m"};function br(t){return t.noColor||process.env.NO_COLOR?!1:t.tty??process.stdout.isTTY??!1}function j(t,e,r){return br(r)?`${e}${t}${h.reset}`:t}function _(t,e){return j(t,h.dim,e)}function vr(t,e){return j(t,h.bold,e)}function wr(t,e){return j(t,h.cyan,e)}function Pr(t,e){return j(t,h.red,e)}function jr(t,e){return j(t,h.white,e)}function He(t,e,r){let o=Fe(),n=e?` ${_(`v${e}`,r)}`:"";return`${wr(o.phaseDone,r)} ${t}${n}`}function N(t,e){return vr(t,e)}function f(t,e,r,o){let n=" ".repeat(Math.max(0,r-t.length));return` ${_(t,o)}${n} ${jr(e,o)}`}function Ke(t){return Pr("\u2717",t)}function Or(t){return{tty:t.tty,noColor:t.noColor}}async function Ar(t){let e=Or(t);console.log(""),console.log(He("ToolNet Status",void 0,e)),console.log("");try{let r=new I().detect(),o=z();console.log(N("PROJECT",e)),console.log(f("Name",r.name,8,e));let n=ne(re({provider:o.storage.provider,r2:o.storage.r2,s3:o.storage.s3,huggingface:o.storage.huggingface,localRoot:o.storage.localRoot}),{attempts:3}),i=new D(n,r.id,r.name,r.remote??r.name),s="unknown",c="unknown";try{s=await i.exists(`${r.id}/memory.json`)?"ready":"not initialized"}catch{s="error"}try{c=await i.exists(`${r.id}/code-graph.json`)?"ready":"not built"}catch{c="error"}console.log(f("Memory",s,8,e)),console.log(f("Index",c,8,e)),console.log("");let l=De(),u=l.filter(a=>a.detected).map(a=>a.agent);if(u.length>0){if(console.log(N("INTEGRATIONS",e)),console.log(f("Detected",u.join(", "),8,e)),l.find(p=>p.agent==="kiro")?.detected){let p=Ne();console.log(f("Kiro",p.installed?"ready":p.state,8,e))}console.log("")}let d=ge(r);if(d.agents.length>0){console.log(N("SERVICE",e));let a=d.syncHealth==="healthy"?"running":d.syncHealth==="degraded"?"degraded":"stopped";console.log(f("Daemon",a,8,e)),console.log("")}}catch(r){console.log(Ke(e)+" Failed to get status"),console.log(""),console.log(_(` ${r instanceof Error?r.message:String(r)}`,e)),console.log(""),process.exitCode=1}}async function Mr(){let t=process.argv.slice(2),e={tty:process.stdout.isTTY,noColor:process.env.NO_COLOR!==void 0||t.includes("--no-color")};await Ar(e)}Mr().catch(t=>{console.error(""),console.error(t instanceof Error?t.message:String(t)),console.error(""),process.exitCode=1});
1
+ import{existsSync as qe,readFileSync as Ze}from"node:fs";import{homedir as Qe}from"node:os";import{join as Xe}from"node:path";function et(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
2
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function tt(){let r=process.env.TOOLNET_GLOBAL_ENV??Xe(Qe(),".config","toolnet-memory",".env");if(!qe(r))return;let e=Ze(r,"utf8");for(let t of e.split(/\r?\n/)){let n=t.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let o=n.indexOf("=");if(o<=0)continue;let i=n.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=et(n.slice(o+1)))}}tt();function S(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function C(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function q(){return{memory:{autoCapture:S(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:S(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:S(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:S(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:C(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:C(process.env.MEMORY_RERANK_TOP,10),finalContext:C(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:C(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:S(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:C(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as at}from"node:crypto";import{existsSync as E,mkdirSync as ut,readFileSync as dt,renameSync as lt,writeFileSync as pt}from"node:fs";import{basename as mt,dirname as T,join as v,parse as oe,resolve as f}from"node:path";import{createHash as X}from"node:crypto";import{spawnSync as rt}from"node:child_process";var b="git-remote-v1",nt=new Set(["github.com","gitlab.com","bitbucket.org"]);function ee(r,e){let t=e.replaceAll("\\","/").replace(/^\/+/u,"").replace(/\/+$/u,"").replace(/\.git$/iu,"").replace(/\/+/gu,"/");return!t||t==="."||t===".."||t.split("/").some(n=>!n||n==="."||n==="..")?null:(nt.has(r)&&(t=t.toLowerCase()),t)}function ot(r){let e;try{e=new URL(r)}catch{return null}if(!["https:","http:","ssh:","git:"].includes(e.protocol))return null;let t=e.hostname.trim().toLowerCase();if(!t)return null;let n=e.protocol==="https:"&&e.port==="443"||e.protocol==="http:"&&e.port==="80"||e.protocol==="ssh:"&&e.port==="22",o=e.port&&!n?`${t}:${e.port}`:t,i=ee(t,e.pathname);return i?`${o}/${i}`:null}function it(r){let e=r.match(/^(?:[^@\s/:]+@)?([^:/\s]+):(.+)$/u);if(!e)return null;let t=e[1]?.trim().toLowerCase();if(!t||t.length===1)return null;let n=ee(t,e[2]??"");return n?`${t}/${n}`:null}function Z(r){let e=r.trim();return e?e.includes("://")?ot(e):it(e):null}function st(r){return X("sha256").update(`${b}:${r}`).digest("hex")}function te(r){return X("sha256").update(`toolnet-project:${b}:${r}`).digest("hex").slice(0,16)}function ct(r){return r.split("/").filter(Boolean).at(-1)?.trim()||null}function L(r,e){let t=rt("git",["-C",r,...e],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return t.error||t.status!==0?null:t.stdout?.trim()||null}function Q(r,e){let t=ct(r);return t?{scheme:b,canonicalRemote:r,fingerprint:st(r),repositoryName:t,source:e}:null}function re(r){let e=L(r,["remote","get-url","origin"]);if(e){let o=Z(e);if(o)return Q(o,"origin")}let t=L(r,["remote"]);if(!t)return null;let n=new Set;for(let o of t.split(/\r?\n/u).map(i=>i.trim()).filter(Boolean)){let i=L(r,["remote","get-url",o]);if(!i)continue;let s=Z(i);s&&n.add(s)}return n.size!==1?null:Q([...n][0],"unique-remote")}var ie=".toolnet",gt="project.json";function ft(r){return at("sha256").update(r).digest("hex").slice(0,16)}function h(r){return v(r,ie,gt)}function se(r){return E(h(r))}function ne(r,e){let t=f(r),n=oe(t).root;for(;;){if(se(t))return t;if(t===n||e&&t===f(e))break;let o=T(t);if(o===t)break;t=o}return null}function G(r){let e=f(r),t=oe(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(i=>E(v(e,i))))return e;if(e===t)break;let o=T(e);if(o===e)break;e=o}return f(r)}function I(r){let e;try{e=JSON.parse(dt(r,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${r}: ${o instanceof Error?o.message:String(o)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=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:T(T(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:n,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:n,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 R(r,e){let t=v(r,ie);ut(t,{recursive:!0});let n=h(r),o=`${n}.tmp-${process.pid}`;pt(o,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),lt(o,n)}function g(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}function z(r){return{version:1,scheme:b,canonicalRemote:r.canonicalRemote,fingerprint:r.fingerprint,repositoryName:r.repositoryName}}function yt(r){let e=r.metadata?.toolnetIdentity;if(!e||typeof e!="object"||Array.isArray(e))return null;let t=e;return typeof t.fingerprint=="string"?t.fingerprint:null}var _=class{adopt(e,t){let n=G(f(e));if(!t.id.trim())throw new Error("PROJECT_ADOPTION_INVALID_ID");if(!t.name.trim())throw new Error("PROJECT_ADOPTION_INVALID_NAME");if(!t.remote.trim())throw new Error("PROJECT_ADOPTION_INVALID_REMOTE");if(se(n)){let c=I(h(n));if(c.id!==t.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${c.id}`,`requested=${t.id}`].join(" "));return g(c,n)}let o=new Date().toISOString(),i={...t.metadata};t.gitIdentity&&(i.toolnetIdentity=z(t.gitIdentity));let s={version:1,id:t.id.trim(),name:t.name.trim(),remote:t.remote.trim(),rootPath:n,createdAt:t.createdAt??o,updatedAt:o,graphVersion:t.graphVersion??0,memoryVersion:t.memoryVersion??0,metadata:Object.keys(i).length?i:void 0};return R(n,s),g(s,n)}recordGitIdentity(e,t,n={}){let o=this.requireExisting(e),i=h(o.rootPath),s=I(i),c=yt(s);if(c&&c!==t.fingerprint&&!n.allowRebind)throw new Error(["PROJECT_GIT_REMOTE_CHANGED",`existing=${c}`,`current=${t.fingerprint}`,"Use explicit rebind only when this repository identity change is intentional."].join(" "));let u=s.metadata?.toolnetIdentity;return u&&typeof u=="object"&&!Array.isArray(u)&&u.fingerprint===t.fingerprint||(s.metadata={...s.metadata,toolnetIdentity:z(t)},s.updatedAt=new Date().toISOString(),R(o.rootPath,s)),g(s,o.rootPath)}findExisting(e=process.cwd()){let t=f(e),n=G(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>E(v(n,u))),s=ne(t,i?n:void 0);if(!s)return null;let c=I(h(s));return g(c,s)}requireExisting(e=process.cwd()){let t=this.findExisting(e);if(!t)throw new Error("PROJECT_NOT_INITIALIZED");return t}detect(e=process.cwd()){let t=f(e),n=G(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(a=>E(v(n,a))),s=ne(t,i?n:void 0);if(s){let a=h(s),l=I(a);return l.rootPath!==s&&(l.rootPath=s,l.updatedAt=new Date().toISOString(),R(s,l)),g(l,s)}let c=new Date().toISOString(),u=mt(n),d=re(n),p={version:1,id:d?te(d.canonicalRemote):ft(n),name:u,remote:d?.repositoryName??u,rootPath:n,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0,metadata:d?{toolnetIdentity:z(d)}:void 0};return R(n,p),g(p,n)}};var ht=[{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"}],xt=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function ce(r){return r.normalize("NFKC").trim().toLowerCase()}function kt(r){if(r.length===0)return 0;let e=new Map;for(let n of r)e.set(n,(e.get(n)??0)+1);let t=0;for(let n of e.values()){let o=n/r.length;t-=o*Math.log2(o)}return t}function St(r){return/^[a-f0-9]{32}$/iu.test(r)||/^[a-f0-9]{40}$/iu.test(r)||/^[a-f0-9]{64}$/iu.test(r)}function Ct(r,e,t){let n=r.slice(Math.max(0,e-48),e),o=r.slice(t,Math.min(r.length,t+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${n} ${o}`)}function bt(r,e){return r.start<e.end&&e.start<r.end}function ae(r){return r.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var D=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let n=ce(t);n&&this.allowValues.add(n)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let i of ht){let s=new RegExp(i.regex.source,i.regex.flags);for(let c of e.matchAll(s))c.index===void 0||!c[0]||this.allowed(c[0])||t.push({type:i.type,value:c[0],start:c.index,end:c.index+c[0].length,confidence:i.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let n=ae(t),o=[];for(let i of n)o.some(s=>bt(s,i))||o.push(i);return ae(o)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=ce(e);return xt.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],n=/[A-Za-z0-9_+/=-]{32,160}/g;for(let o of e.matchAll(n)){if(o.index===void 0||!o[0])continue;let i=o[0];this.allowed(i)||St(i)||!/[A-Za-z]/u.test(i)||!/[0-9]/u.test(i)||Ct(e,o.index,o.index+i.length)&&(kt(i)<3.7||t.push({type:"high_entropy_secret",value:i,start:o.index,end:o.index+i.length,confidence:"heuristic"}))}return t}};var N=class{scanner;constructor(e={}){this.scanner=new D(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let n=e,o=[...t].sort((s,c)=>c.start-s.start),i=new Set;for(let s of o)i.add(s.type),n=n.slice(0,s.start)+`[REDACTED:${s.type}]`+n.slice(s.end);return{text:n,redacted:t.length,secretTypes:[...i].sort()}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[n,o]of Object.entries(e)){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")){t[n]="[REDACTED]";continue}t[n]=this.sanitizeValue(o)}return t}return e}};var pn=new N;import{homedir as Ut}from"node:os";import{join as Bt}from"node:path";import{DeleteObjectCommand as wt,GetObjectCommand as Pt,HeadObjectCommand as jt,ListObjectsV2Command as Ot,PutObjectCommand as At,S3Client as Mt}from"@aws-sdk/client-s3";import{getSignedUrl as It}from"@aws-sdk/s3-request-presigner";var K=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Mt({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,n="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new At({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await It(this.client,new Pt({Bucket:this.bucket,Key:e}),{expiresIn:60}),n=await fetch(t,{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(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 jt({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 wt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new Ot({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let i of o.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return t}};import{access as ue,mkdir as Rt,readFile as Et,readdir as Tt,rm as _t,stat as de,writeFile as Dt}from"node:fs/promises";import{dirname as Nt,join as Kt,relative as le,resolve as Ft}from"node:path";var w=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Ft(this.root,t)}async put(e,t){let n=this.path(e);await Rt(Nt(n),{recursive:!0}),await Dt(n,t)}async get(e){try{return await Et(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 ue(this.path(e)),!0}catch{return!1}}async delete(e){await _t(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),n=[];try{await ue(t)}catch{return n}let o=async s=>{let c=await Tt(s,{withFileTypes:!0});for(let u of c){let d=Kt(s,u.name);if(u.isDirectory()){await o(d);continue}let p=await de(d);n.push({key:le(this.root,d),size:p.size,updatedAt:p.mtime.toISOString()})}},i=await de(t);return i.isDirectory()?await o(t):n.push({key:le(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),n}};import{DeleteObjectCommand as $t,GetObjectCommand as Ht,HeadObjectCommand as Lt,ListObjectsV2Command as Gt,PutObjectCommand as zt,S3Client as Wt}from"@aws-sdk/client-s3";import{getSignedUrl as Vt}from"@aws-sdk/s3-request-presigner";var P=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Wt({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,n="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new zt({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await Vt(this.client,new Ht({Bucket:this.bucket,Key:e}),{expiresIn:60}),n=await fetch(t,{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(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 Lt({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 $t({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new Gt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let i of o.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return t}};function W(r,e){return console.warn(e),new w(r)}function pe(r){let e=r.localRoot??Bt(Ut(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new P({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):W(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let t=r.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new P({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):W(e,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new K({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):W(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new w(e)}function Jt(r){return new Promise(e=>setTimeout(e,r))}async function me(r,e={}){let t=Math.max(1,e.attempts??3),n=e.baseDelayMs??150,o=e.maxDelayMs??2e3,i;for(let s=1;s<=t;s++)try{return await r()}catch(c){if(i=c,s>=t)break;let u=Math.min(o,n*2**(s-1)),d=Math.floor(Math.random()*Math.max(1,u*.2));await Jt(u+d)}throw i}var Yt=new Set(["put","get","getText","delete","list"]);function ge(r,e={}){return new Proxy(r,{get(t,n){let o=Reflect.get(t,n,t);return typeof o!="function"?o:Yt.has(n)?(...i)=>me(()=>Promise.resolve(o.apply(t,i)),e):o.bind(t)}})}function fe(r){let e=r.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 ye(r){let e=r.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 n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[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 F=class{constructor(e,t,n,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=n,this.folder=fe(o??n),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(),n=t,o=await this.provider.getText(e);if(o){let s;try{s=JSON.parse(o)}catch(c){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${c instanceof Error?c.message:String(c)}`)}if(typeof s.id=="string"&&s.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${s.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof s.createdAt=="string"&&(n=s.createdAt)}let i={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:n,updatedAt:t};await this.provider.put(e,JSON.stringify(i,null,2)+`
4
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=ye(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,n){return await this.ensureRegistered(),this.provider.put(this.key(e),t,n)}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{existsSync as Ce,readFileSync as er,readdirSync as xe}from"node:fs";import{join as j}from"node:path";var Xo=new Int32Array(new SharedArrayBuffer(4));import{closeSync as oi,existsSync as qt,fsyncSync as ii,mkdirSync as si,openSync as ci,readFileSync as Zt,renameSync as ai,writeFileSync as ui}from"node:fs";import{dirname as li,join as Qt}from"node:path";function Xt(r){return Qt(r.rootPath,".toolnet","work","current.json")}function he(r){let e=Xt(r);if(!qt(e))return null;try{let t=JSON.parse(Zt(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function be(r){if(!Ce(r))return null;try{return JSON.parse(er(r,"utf8"))}catch{return null}}function ke(r,e){if(!Ce(r))return[];let t=[];for(let n of xe(r,{withFileTypes:!0})){if(!n.isDirectory())continue;let o=j(r,n.name);for(let i of xe(o,{withFileTypes:!0})){if(!i.isDirectory())continue;let s=be(j(o,i.name,"state.json"));s&&s.version===1&&s.projectId===e.id&&t.push(s)}}return t}function tr(r){let e=j(r.rootPath,".toolnet","runtime","sources"),t=j(r.rootPath,".toolnet","sessions"),n=ke(e,r),o=ke(t,r),i=new Map;for(let s of o)i.set(`${s.agent}:${s.nativeSessionId}`,s);for(let s of n)i.set(`${s.agent}:${s.nativeSessionId}`,s);return Array.from(i.values())}function Se(r){return r.filter(e=>!!e).sort().at(-1)}function rr(r){let e=be(j(r.rootPath,".toolnet","runtime","opencode-status.json"));return!e||e.projectRoot&&e.projectRoot!==r.rootPath?null:e}function ve(r){let e=tr(r),n=[...e].sort((a,l)=>(a.lastLocalEventAt??a.updatedAt).localeCompare(l.lastLocalEventAt??l.updatedAt)).at(-1),o=Array.from(new Set(e.map(a=>a.agent))).sort(),i=e.reduce((a,l)=>a+Math.max(0,l.lastSequence-l.lastRemoteSequence),0),s=rr(r),c=s?.state==="capture-failed",u=s?.state==="sync-failed",d;c?d="degraded":i>0||u?d="pending":e.length>0?d="healthy":d="unknown";let p=he(r);return{ok:d!=="degraded",agents:o,sessions:e.length,latestAgent:n?.agent,latestSessionId:n?.nativeSessionId,lastCaptureAt:Se(e.map(a=>a.lastLocalEventAt??a.updatedAt)),lastFlushAt:Se(e.map(a=>a.lastRemoteAt)),pendingWal:i,currentTask:p?.currentTask?.title,currentFile:p?.activeFiles?.at(-1)??p?.filesTouched.at(-1),syncHealth:d,opencode:s?{state:s.state,reason:s.reason,timestamp:s.timestamp,error:s.error}:void 0}}import{existsSync as ze}from"node:fs";import{homedir as Pr}from"node:os";import{join as jr}from"node:path";import{spawnSync as Or}from"node:child_process";import{homedir as nr}from"node:os";import{join as O}from"node:path";function we(r={}){return O(r.home??nr(),".gemini")}function or(r={}){return O(we(r),"antigravity-cli")}function Pe(r={}){return O(we(r),"config")}function ir(r={}){return O(Pe(r),"mcp_config.json")}function sr(r={}){let e=r.cwd??process.cwd();return O(e,".agents","mcp_config.json")}function je(r={}){return[or(r),ir(r),Pe(r),sr(r)]}import{homedir as cr}from"node:os";import{join as Oe}from"node:path";function Ae(r={}){let e=process.env.OPENCODE_CONFIG_DIR?.trim();if(e)return e;let t=r.xdgConfigHome??process.env.XDG_CONFIG_HOME?.trim();return t?Oe(t,"opencode"):Oe(r.home??cr(),".config","opencode")}import{homedir as ar}from"node:os";import{join as ur}from"node:path";function Me(r={}){return ur(r.home??ar(),".claude")}import{homedir as dr}from"node:os";import{join as A}from"node:path";function V(r={}){return r.kiroHome??process.env.KIRO_HOME??A(r.home??dr(),".kiro")}function lr(r={}){return A(V(r),"settings")}function U(r={}){return A(lr(r),"mcp.json")}function pr(r={}){return A(V(r),"hooks")}function Ie(r={}){return A(pr(r),"toolnet-memory.json")}function Re(r={}){return[V(r),U(r)]}import{homedir as mr}from"node:os";import{join as Ee}from"node:path";function Te(r={}){return Ee(r.home??mr(),".toolnetcli")}function gr(r={}){return Ee(Te(r),"config.json")}function _e(r={}){let e=Te(r),t=gr(r);return[e,t]}import{homedir as fr}from"node:os";import{join as B}from"node:path";function De(r={}){if(r.kiloHome)return r.kiloHome;if(process.env.KILO_HOME)return process.env.KILO_HOME;let e=r.xdgConfigHome??process.env.XDG_CONFIG_HOME;return e?B(e,"kilo"):B(r.home??fr(),".config","kilo")}function yr(r={}){return B(De(r),"kilo.jsonc")}function Ne(r={}){let e=De(r),t=yr(r);return[e,t]}import{homedir as hr}from"node:os";import{join as Ke,resolve as Fi}from"node:path";function Fe(r={}){return r.cursorHome??Ke(r.home??hr(),".cursor")}function xr(r={}){return r.cursorConfigDir??process.env.CURSOR_CONFIG_DIR??(r.xdgConfigHome??process.env.XDG_CONFIG_HOME?Ke(r.xdgConfigHome??process.env.XDG_CONFIG_HOME,"cursor"):void 0)??Fe(r)}function $e(r={}){return Array.from(new Set([Fe(r),xr(r)]))}import{homedir as kr}from"node:os";import{join as Sr,resolve as Gi}from"node:path";function Cr(r={}){return r.copilotHome??process.env.COPILOT_HOME??Sr(r.home??kr(),".copilot")}function He(r={}){return[Cr(r)]}import{homedir as br}from"node:os";import{join as vr,resolve as Ui}from"node:path";function wr(r={}){return r.grokHome??process.env.GROK_HOME??vr(r.home??br(),".grok")}function Le(r={}){return[wr(r)]}function Ar(r){return Or("sh",["-lc",`command -v ${JSON.stringify(r)} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}function m(r){let e=r.commandExists(r.command),t=r.configPaths.filter(i=>ze(i)),n=t.length>0,o=[];e&&o.push(`command:${r.command}`);for(let i of t)o.push(`config:${i}`);return{agent:r.agent,detected:e||n,commandDetected:e,configDetected:n,evidence:o}}function Ge(r){let e=r.commands.filter(s=>r.commandExists(s)),t=r.configPaths.filter(s=>ze(s)),n=e.length>0,o=t.length>0,i=[...e.map(s=>`command:${s}`),...t.map(s=>`config:${s}`)];return{agent:r.agent,detected:n||o,commandDetected:n,configDetected:o,evidence:i}}function We(r={}){let e=r.home??Pr(),t=r.commandExists??Ar,n=r.codexHome??process.env.CODEX_HOME??jr(e,".codex");return[m({agent:"agy",command:"agy",commandExists:t,configPaths:je({home:e})}),m({agent:"opencode",command:"opencode",commandExists:t,configPaths:[Ae({home:e,xdgConfigHome:r.xdgConfigHome})]}),m({agent:"claude",command:"claude",commandExists:t,configPaths:[Me({home:e})]}),m({agent:"kiro",command:"kiro-cli",commandExists:t,configPaths:Re({home:e,kiroHome:r.kiroHome})}),Ge({agent:"cursor",commands:["agent","cursor-agent"],commandExists:t,configPaths:$e({home:e,cursorHome:r.cursorHome,cursorConfigDir:r.cursorConfigDir,xdgConfigHome:r.xdgConfigHome})}),m({agent:"copilot",command:"copilot",commandExists:t,configPaths:He({home:e,copilotHome:r.copilotHome})}),m({agent:"grok",command:"grok",commandExists:t,configPaths:Le({home:e,grokHome:r.grokHome})}),m({agent:"toolnet-cli",command:"toolnet",commandExists:t,configPaths:_e({home:e})}),Ge({agent:"kilo",commands:["kilo","kilo-code"],commandExists:t,configPaths:Ne({home:e,kiloHome:r.kiloHome})}),m({agent:"codex",command:"codex",commandExists:t,configPaths:[n]})]}import{existsSync as J,readFileSync as Mr}from"node:fs";var Ir="ToolNet Memory - ",Rr=["SessionStart","UserPromptSubmit","PreToolUse","PostToolUse","Stop"];function x(r){return typeof r=="object"&&r!==null&&!Array.isArray(r)}function Ve(r){if(!J(r))return{};let e;try{e=JSON.parse(Mr(r,"utf8"))}catch(t){return{error:t instanceof Error?t.message:String(t)}}return x(e)?{value:e}:{error:"root must be a JSON object"}}function Er(r){if(!r||!x(r.mcpServers))return!1;let e=r.mcpServers["toolnet-memory"];return x(e)?typeof e.command=="string"&&e.command.trim().length>0&&Array.isArray(e.args)&&e.args.length===1&&e.args[0]==="mcp"&&e.disabled!==!0:!1}function Tr(r){if(!(!x(r)||!x(r.action)))return typeof r.action.command=="string"?r.action.command:void 0}function _r(r){if(!r||r.version!=="v1"||!Array.isArray(r.hooks))return[];let e=new Set;for(let t of r.hooks){if(!x(t)||typeof t.name!="string"||!t.name.startsWith(Ir))continue;let n=Tr(t);!n||!n.includes("session:kiro-hook")||t.enabled!==!1&&typeof t.trigger=="string"&&e.add(t.trigger)}return[...e]}function Ue(r={}){let e=r.configFile??U(),t=r.hooksFile??Ie(),n=Ve(e),o=Ve(t),i=!n.error&&Er(n.value),s=o.error?[]:_r(o.value),c=Rr.every(l=>s.includes(l)),u=[];n.error&&u.push(`MCP config: ${n.error}`),o.error&&u.push(`Hooks config: ${o.error}`);let d=i&&c,p=J(e)||J(t),a=u.length>0?"invalid":d?"ready":p?"partial":"not-installed";return{installed:d,state:a,mcp:{configured:i,configFile:e,error:n.error},hooks:{configured:c,hooksFile:t,triggers:s,error:o.error},errors:u}}var Dr={spinner:["\xB7","\u2722","\u2733","\u2736","\u273B","\u273D"],barFilled:"\u2588",barEmpty:"\u2591",phaseDone:"\u25C6",phaseActive:"\u25C7",rail:"\u2502",branch:"\u251C",corner:"\u2514",dash:"\u2014"},Nr={spinner:[".","*","+","x","*","+"],barFilled:"#",barEmpty:"-",phaseDone:"[OK]",phaseActive:"[>>]",rail:"|",branch:"|",corner:"\\",dash:"-"};function Kr(){if(process.env.TOOLNET_ASCII==="1")return!1;if(process.env.TOOLNET_UNICODE==="1")return!0;if(process.platform==="win32"){let r=process.env.TERM_PROGRAM,e=process.env.WT_SESSION,t=process.env.VSCODE_PID,n=process.env.ConEmuPID;return!!(e||t||n||r==="vscode")}return process.env.TERM!=="linux"}var Y;function Be(){return Y||(Y=Kr()?Dr:Nr),Y}var k={reset:"\x1B[0m",green:"\x1B[32m",cyan:"\x1B[36m",red:"\x1B[31m",yellow:"\x1B[33m",amber:"\x1B[38;5;214m",white:"\x1B[97m",dim:"\x1B[2m",bold:"\x1B[1m"};function Fr(r){return r.noColor||process.env.NO_COLOR?!1:r.tty??process.stdout.isTTY??!1}function M(r,e,t){return Fr(t)?`${e}${r}${k.reset}`:r}function $(r,e){return M(r,k.dim,e)}function $r(r,e){return M(r,k.bold,e)}function Hr(r,e){return M(r,k.cyan,e)}function Lr(r,e){return M(r,k.red,e)}function Gr(r,e){return M(r,k.white,e)}function Je(r,e,t){let n=Be(),o=e?` ${$(`v${e}`,t)}`:"";return`${Hr(n.phaseDone,t)} ${r}${o}`}function H(r,e){return $r(r,e)}function y(r,e,t,n){let o=" ".repeat(Math.max(0,t-r.length));return` ${$(r,n)}${o} ${Gr(e,n)}`}function Ye(r){return Lr("\u2717",r)}function zr(r){return{tty:r.tty,noColor:r.noColor}}async function Wr(r){let e=zr(r);console.log(""),console.log(Je("ToolNet Status",void 0,e)),console.log("");try{let t=new _().detect(),n=q();console.log(H("PROJECT",e)),console.log(y("Name",t.name,8,e));let o=ge(pe({provider:n.storage.provider,r2:n.storage.r2,s3:n.storage.s3,huggingface:n.storage.huggingface,localRoot:n.storage.localRoot}),{attempts:3}),i=new F(o,t.id,t.name,t.remote??t.name),s="unknown",c="unknown";try{s=await i.exists(`${t.id}/memory.json`)?"ready":"not initialized"}catch{s="error"}try{c=await i.exists(`${t.id}/code-graph.json`)?"ready":"not built"}catch{c="error"}console.log(y("Memory",s,8,e)),console.log(y("Index",c,8,e)),console.log("");let u=We(),d=u.filter(a=>a.detected).map(a=>a.agent);if(d.length>0){if(console.log(H("INTEGRATIONS",e)),console.log(y("Detected",d.join(", "),8,e)),u.find(l=>l.agent==="kiro")?.detected){let l=Ue();console.log(y("Kiro",l.installed?"ready":l.state,8,e))}console.log("")}let p=ve(t);if(p.agents.length>0){console.log(H("SERVICE",e));let a=p.syncHealth==="healthy"?"running":p.syncHealth==="degraded"?"degraded":"stopped";console.log(y("Daemon",a,8,e)),console.log("")}}catch(t){console.log(Ye(e)+" Failed to get status"),console.log(""),console.log($(` ${t instanceof Error?t.message:String(t)}`,e)),console.log(""),process.exitCode=1}}async function Vr(){let r=process.argv.slice(2),e={tty:process.stdout.isTTY,noColor:process.env.NO_COLOR!==void 0||r.includes("--no-color")};await Wr(e)}Vr().catch(r=>{console.error(""),console.error(r instanceof Error?r.message:String(r)),console.error(""),process.exitCode=1});