toolnet-memory 0.3.12 → 0.3.13

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,6 +1,5 @@
1
- import"dotenv/config";import{existsSync as Te,readFileSync as _e}from"node:fs";import{homedir as Me}from"node:os";import{join as Ne}from"node:path";function Oe(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 je(){let r=process.env.TOOLNET_GLOBAL_ENV??Ne(Me(),".config","toolnet-memory",".env");if(!Te(r))return;let e=_e(r,"utf8");for(let t of e.split(/\r?\n/)){let s=t.trim();if(!s||s.startsWith("#"))continue;s.startsWith("export ")&&(s=s.slice(7));let o=s.indexOf("=");if(o<=0)continue;let n=s.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(n)&&process.env[n]===void 0&&(process.env[n]=Oe(s.slice(o+1)))}}je();function I(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function T(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function ue(){return{memory:{autoCapture:I(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:I(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:I(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:I(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:T(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:T(process.env.MEMORY_RERANK_TOP,10),finalContext:T(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:T(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",r2:{accountId:process.env.R2_ACCOUNT_ID,bucket:process.env.R2_BUCKET,accessKeyId:process.env.R2_ACCESS_KEY_ID,secretAccessKey:process.env.R2_SECRET_ACCESS_KEY},s3:{endpoint:process.env.S3_ENDPOINT,region:process.env.S3_REGION,bucket:process.env.S3_BUCKET,accessKeyId:process.env.S3_ACCESS_KEY_ID,secretAccessKey:process.env.S3_SECRET_ACCESS_KEY,forcePathStyle:I(process.env.S3_FORCE_PATH_STYLE,!1)},huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:T(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as De}from"node:crypto";import{existsSync as oe,mkdirSync as Fe,readFileSync as Ke,renameSync as $e,writeFileSync as Ge}from"node:fs";import{basename as Ue,dirname as D,join as K,parse as ge,resolve as _}from"node:path";var he=".toolnet",Be="project.json";function ze(r){return De("sha256").update(r).digest("hex").slice(0,16)}function ne(r){return K(r,he,Be)}function He(r){return oe(ne(r))}function Ve(r,e){let t=_(r),s=ge(t).root;for(;;){if(He(t))return t;if(t===s||e&&t===_(e))break;let o=D(t);if(o===t)break;t=o}return null}function We(r){let e=_(r),t=ge(e).root,s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(s.some(n=>oe(K(e,n))))return e;if(e===t)break;let o=D(e);if(o===e)break;e=o}return _(r)}function Ye(r){let e;try{e=JSON.parse(Ke(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 s=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:D(D(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:s,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:s,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 me(r,e){let t=K(r,he);Fe(t,{recursive:!0});let s=ne(r),o=`${s}.tmp-${process.pid}`;Ge(o,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),$e(o,s)}function fe(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}}var F=class{detect(e=process.cwd()){let t=_(e),s=We(t),n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(l=>oe(K(s,l))),a=Ve(t,n?s:void 0);if(a){let l=ne(a),f=Ye(l);return f.rootPath!==a&&(f.rootPath=a,f.updatedAt=new Date().toISOString(),me(a,f)),fe(f,a)}let c=new Date().toISOString(),d=Ue(s),m={version:1,id:ze(s),name:d,remote:d,rootPath:s,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return me(s,m),fe(m,s)}};var qe=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_\-]{20,}\b/g},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._\-]{16,}\b/gi},{type:"jwt",regex:/\beyJ[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\b/g},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/g},{type:"password_assignment",regex:/\b(password|passwd|pwd)\s*[:=]\s*["']?[^"'\s]{6,}["']?/gi},{type:"secret_assignment",regex:/\b(secret|api[_-]?key|access[_-]?token|refresh[_-]?token)\s*[:=]\s*["']?[^"'\s]{8,}["']?/gi},{type:"cookie",regex:/\b(cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi}],$=class{scan(e){let t=[];for(let s of qe){let o=new RegExp(s.regex.source,s.regex.flags);for(let n of e.matchAll(o))t.push({type:s.type,value:n[0]})}return t}hasSecrets(e){return this.scan(e).length>0}};var M=class{scanner=new $;sanitize(e){let t=e,s=this.scanner.scan(e),o=new Set;for(let n of s)o.add(n.type),t=t.split(n.value).join(`[REDACTED:${n.type}]`);return{text:t,redacted:s.length,secretTypes:[...o]}}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[s,o]of Object.entries(e)){let n=s.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");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[s]="[REDACTED]":t[s]=this.sanitizeValue(o)}return t}return e}};import{homedir as bt}from"node:os";import{join as St}from"node:path";import{DeleteObjectCommand as Je,GetObjectCommand as Qe,HeadObjectCommand as Ze,ListObjectsV2Command as Xe,PutObjectCommand as et,S3Client as tt}from"@aws-sdk/client-s3";import{getSignedUrl as rt}from"@aws-sdk/s3-request-presigner";var G=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new tt({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,s="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new et({Bucket:this.bucket,Key:e,Body:o,ContentType:s}))}async get(e){let t=await rt(this.client,new Qe({Bucket:this.bucket,Key:e}),{expiresIn:60}),s=await fetch(t,{redirect:"follow"});if(s.status===404)return null;if(!s.ok)throw new Error(`HF download failed: ${s.status} ${s.statusText}`);return new Uint8Array(await s.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 Ze({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=[],s;do{let o=await this.client.send(new Xe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:s}));for(let n of o.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});s=o.IsTruncated?o.NextContinuationToken:void 0}while(s);return t}};import{access as ye,mkdir as st,readFile as ot,readdir as nt,rm as it,stat as be,writeFile as at}from"node:fs/promises";import{dirname as ct,join as lt,relative as Se,resolve as dt}from"node:path";var N=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return dt(this.root,t)}async put(e,t){let s=this.path(e);await st(ct(s),{recursive:!0}),await at(s,t)}async get(e){try{return await ot(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 ye(this.path(e)),!0}catch{return!1}}async delete(e){await it(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),s=[];try{await ye(t)}catch{return s}let o=async a=>{let c=await nt(a,{withFileTypes:!0});for(let d of c){let m=lt(a,d.name);if(d.isDirectory()){await o(m);continue}let l=await be(m);s.push({key:Se(this.root,m),size:l.size,updatedAt:l.mtime.toISOString()})}},n=await be(t);return n.isDirectory()?await o(t):s.push({key:Se(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),s}};import{DeleteObjectCommand as pt,GetObjectCommand as ut,HeadObjectCommand as mt,ListObjectsV2Command as ft,PutObjectCommand as gt,S3Client as ht}from"@aws-sdk/client-s3";import{getSignedUrl as yt}from"@aws-sdk/s3-request-presigner";var O=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new ht({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,s="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new gt({Bucket:this.bucket,Key:e,Body:o,ContentType:s}))}async get(e){let t=await yt(this.client,new ut({Bucket:this.bucket,Key:e}),{expiresIn:60}),s=await fetch(t,{redirect:"follow"});if(s.status===404)return null;if(!s.ok)throw new Error(`${this.name} download failed: ${s.status} ${s.statusText}`);return new Uint8Array(await s.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 mt({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 pt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],s;do{let o=await this.client.send(new ft({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:s}));for(let n of o.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});s=o.IsTruncated?o.NextContinuationToken:void 0}while(s);return t}};function ie(r,e){return console.warn(e),new N(r)}function Ee(r){let e=r.localRoot??St(bt(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new O({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):ie(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 O({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):ie(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 G({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):ie(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new N(e)}var j=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var U=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")}};var B=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","vectors","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 Ce(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 ve(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 s=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(s)return`${s[1]}memory/records/${s[2]}`;if(s=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),s)return`${s[1]}memory/vectors/${s[2]}`;if(s=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),s)return`${s[1]}code/graph/${s[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 z=class{constructor(e,t,s,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=s,this.folder=Ce(o??s),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(),s=t,o=await this.provider.getText(e);if(o){let a;try{a=JSON.parse(o)}catch(c){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${c instanceof Error?c.message:String(c)}`)}if(typeof a.id=="string"&&a.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${a.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof a.createdAt=="string"&&(s=a.createdAt)}let n={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:s,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=ve(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,s){return await this.ensureRegistered(),this.provider.put(this.key(e),t,s)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import*as h from"typescript";var L=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(s=>s.projectId===e&&(s.name===t||s.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 s of e)this.addSymbol(s);for(let s of t)this.addEdge(s)}clearProject(e){for(let[t,s]of this.symbols)s.projectId===e&&this.symbols.delete(t);for(let[t,s]of this.edges)s.projectId===e&&this.edges.delete(t)}};import{execFile as xt}from"node:child_process";import{promisify as wt}from"node:util";var eo=wt(xt);import{createHash as Pt}from"node:crypto";import{readFile as At}from"node:fs/promises";import{join as Lt}from"node:path";function xe(r){return Pt("sha256").update(r).digest("hex")}var H=class{sanitizer=new M;async build(e,t,s,o={}){let n=o.maxLines??80,a=o.overlapLines??10,c=new Map;for(let m of s){let l=c.get(m.filePath)??[];l.push(m),c.set(m.filePath,l)}let d=[];for(let[m,l]of c){let f;try{f=await At(Lt(t,m),"utf8")}catch{continue}let E=f.split(/\r?\n/),y=l.filter(b=>b.type!=="file"&&typeof b.startLine=="number"&&typeof b.endLine=="number");if(y.length>0)for(let b of y)d.push(...this.chunkRange({projectId:e,filePath:m,lines:E,symbol:b,startLine:b.startLine,endLine:b.endLine,maxLines:n,overlapLines:a}));else d.push(...this.chunkRange({projectId:e,filePath:m,lines:E,startLine:1,endLine:Math.max(1,E.length),maxLines:n,overlapLines:a}))}return d}chunkRange(e){let{projectId:t,filePath:s,lines:o,symbol:n,maxLines:a}=e,c=Math.min(e.overlapLines,Math.max(0,a-1)),d=Math.max(1,e.startLine),m=Math.min(o.length,Math.max(d,e.endLine)),l=[],f=d,E=0;for(;f<=m;){let y=Math.min(m,f+a-1),b=o.slice(f-1,y).join(`
5
- `).trim();if(b){let x=this.sanitizer.sanitize(b).text,w=xe(x),R=[t,s,n?.id??"file",String(E),w].join(":");l.push({id:xe(R).slice(0,32),projectId:t,filePath:s,symbolId:n?.id,symbolName:n?.qualifiedName??n?.name,symbolType:n?.type,startLine:f,endLine:y,content:x,contentHash:w})}if(y>=m)break;f=y-c+1,E++}return l}};var V=class{records=new Map;upsert(e){this.records.set(e.id,e)}get(e){return this.records.get(e)}has(e){return this.records.has(e)}remove(e){return this.records.delete(e)}clearProject(e){let t=0;for(let[s,o]of this.records)o.projectId===e&&(this.records.delete(s),t++);return t}exportProject(e){return[...this.records.values()].filter(t=>t.projectId===e)}importRecords(e){let t=0;for(let s of e)!s?.id||!s?.projectId||!Array.isArray(s.vector)||(this.records.set(s.id,s),t++);return t}search(e,t,s=10){let o=[];for(let n of this.records.values()){if(n.projectId!==e)continue;let a=Rt(t,n.vector);o.push({id:n.id,score:a,metadata:n.metadata})}return o.sort((n,a)=>a.score-n.score).slice(0,s)}size(){return this.records.size}};function Rt(r,e){if(r.length===0||e.length===0||r.length!==e.length)return 0;let t=0,s=0,o=0;for(let n=0;n<r.length;n++){let a=r[n]??0,c=e[n]??0;t+=a*c,s+=a*a,o+=c*c}return s===0||o===0?0:t/(Math.sqrt(s)*Math.sqrt(o))}function ae(r){return r.toLowerCase().normalize("NFKC").replace(/[^\p{L}\p{N}_\-./]+/gu," ").split(/\s+/).map(e=>e.trim()).filter(e=>e.length>1)}function we(r,e){let t=r.toLowerCase().replaceAll("\\","/"),s=e.toLowerCase(),o=/\b(test|tests|spec|fixture|mock)\b/.test(s);return(t.startsWith("tests/")||t.includes("/tests/")||t.includes("__tests__")||/\.(test|spec)\.[^.]+$/.test(t))&&!o?.35:t.includes("/generated/")||t.includes(".generated.")?.25:1}var W=class{constructor(e){this.options=e}options;vectors=new V;chunks=new Map;async initialize(e){let{projectId:t,rootPath:s,storage:o,embeddings:n,graph:a,model:c}=this.options,d=new U(o),m=new B(o),l=await new H().build(t,s,a.allSymbols(t));this.chunks.clear();for(let g of l)this.chunks.set(g.id,g);let f=await d.load(t),E=!f||f.chunks.length!==l.length||f.chunks.some(g=>!this.chunks.has(g.id));E&&await d.save({version:1,projectId:t,updatedAt:new Date().toISOString(),chunks:l});let y=await m.load(t),b=0;y&&y.model===c&&(b=this.vectors.importRecords(y.records));let x=new Set(l.map(g=>g.id)),w=0;for(let g of this.vectors.exportProject(t))x.has(g.id)||this.vectors.remove(g.id)&&w++;let R=l.filter(g=>{let P=this.vectors.get(g.id);return P?P.metadata?.contentHash!==g.contentHash:!0}),ee=0,te=8,k=this.vectors.exportProject(t)[0]?.vector.length,re=Math.ceil(R.length/te),de=0;for(let g=0;g<R.length;g+=te){let P=R.slice(g,g+te),ke=P.map(C=>[`file: ${C.filePath}`,C.symbolName?`symbol: ${C.symbolName}`:"",C.symbolType?`type: ${C.symbolType}`:"",C.content].filter(Boolean).join(`
6
- `)),Ie=await n.embedMany(ke);for(let C=0;C<P.length;C++){let v=P[C],A=Ie[C];if(!(!v||!A||A.length===0)){if(k===void 0&&(k=A.length),A.length!==k){console.warn(`[code-semantic] skip dimension mismatch: ${A.length} != ${k}`);continue}this.vectors.upsert({id:v.id,projectId:t,vector:A,metadata:{contentHash:v.contentHash,filePath:v.filePath,symbolName:v.symbolName,symbolType:v.symbolType,startLine:v.startLine,endLine:v.endLine}}),ee++}}de++,e?.({current:de,total:re,phase:"embedding"})}let se=this.vectors.exportProject(t),pe=ee>0||w>0||!y||y.model!==c;return pe&&(e?.({current:re,total:re,phase:"saving"}),await m.save({version:1,projectId:t,model:c,dimensions:se[0]?.vector.length??k??0,updatedAt:new Date().toISOString(),records:se})),{chunks:l.length,vectorsLoaded:b,vectorsIndexed:ee,vectorsRemoved:w,totalVectors:se.length,savedChunks:E,savedVectors:pe}}async search(e,t=8){let s=await this.options.embeddings.embed(e),o=this.vectors.search(this.options.projectId,s,Math.max(t*4,20)),n=new Set(ae(e)),a=[];for(let c of o){let d=this.chunks.get(c.id);if(!d)continue;let m=new Set(ae([d.filePath,d.symbolName??"",d.symbolType??"",d.content].join(" "))),l=0;for(let x of n)m.has(x)&&l++;let f=n.size===0?0:l/n.size,E=Math.max(0,c.score),y=we(d.filePath,e),b=(E*.75+f*.25)*y;a.push({chunk:d,score:b,vectorScore:E,lexicalScore:f})}return a.sort((c,d)=>d.score-c.score).slice(0,t)}size(){return this.chunks.size}};import*as S from"typescript";import*as p from"typescript";var cn=new Set([p.SyntaxKind.EqualsToken,p.SyntaxKind.PlusEqualsToken,p.SyntaxKind.MinusEqualsToken,p.SyntaxKind.AsteriskEqualsToken,p.SyntaxKind.SlashEqualsToken,p.SyntaxKind.PercentEqualsToken,p.SyntaxKind.QuestionQuestionEqualsToken,p.SyntaxKind.AmpersandAmpersandEqualsToken,p.SyntaxKind.BarBarEqualsToken]);var Pe=[{id:"openai-compatible",label:"OpenAI-compatible",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"alibaba",label:"Alibaba / DashScope",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"openrouter",label:"OpenRouter",defaultBaseUrl:"https://openrouter.ai/api/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"groq",label:"Groq",defaultBaseUrl:"https://api.groq.com/openai/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"deepseek",label:"DeepSeek",defaultBaseUrl:"https://api.deepseek.com",defaultModel:"deepseek-v4-flash",requiresApiKey:!0,transport:"openai-compatible"},{id:"nvidia",label:"NVIDIA NIM",defaultBaseUrl:"https://integrate.api.nvidia.com/v1",defaultModel:"deepseek-ai/deepseek-v4-pro",requiresApiKey:!0,transport:"openai-compatible"},{id:"gemini",label:"Gemini",defaultBaseUrl:"https://generativelanguage.googleapis.com/v1beta",requiresApiKey:!0,transport:"gemini"},{id:"huggingface",label:"Hugging Face",defaultBaseUrl:"https://router.huggingface.co/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"ollama",label:"Ollama / Local",defaultBaseUrl:"http://127.0.0.1:11434/v1",requiresApiKey:!1,transport:"openai-compatible"},{id:"custom",label:"Custom endpoint",requiresApiKey:!1,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"cloudflare",label:"Cloudflare Workers AI",requiresApiKey:!0,requiresAccountId:!0,transport:"cloudflare"}];function Y(r){let e=Pe.find(t=>t.id===r);if(!e)throw new Error(`Unsupported AI provider: ${r}`);return e}function q(r){return Pe.some(e=>e.id===r)}function i(r){return process.env[r]?.trim()||void 0}function u(...r){return r.find(e=>!!e?.trim())}function Ae(){if(i("GROQ_API_KEY"))return"groq";if(i("DEEPSEEK_API_KEY"))return"deepseek";if(i("NVIDIA_API_KEY")||i("NVIDIA_NIM_API_KEY"))return"nvidia";if(i("OPENROUTER_API_KEY"))return"openrouter";if(i("ALIBABA_API_KEY")||i("DASHSCOPE_API_KEY"))return"alibaba";if(i("GEMINI_API_KEY")||i("GOOGLE_API_KEY"))return"gemini";if(i("CLOUDFLARE_API_TOKEN")&&i("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(i("HF_TOKEN"))return"huggingface";if(i("OLLAMA_MODEL")||i("OLLAMA_BASE_URL"))return"ollama"}function It(){let r=i("TOOLNET_LLM_PROVIDER");return r&&q(r)?r:Ae()??"openai-compatible"}function ce(r){let e=Y(r);switch(r){case"alibaba":return{provider:r,apiKey:u(i("ALIBABA_API_KEY"),i("DASHSCOPE_API_KEY")),baseUrl:u(i("ALIBABA_BASE_URL"),i("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:u(i("ALIBABA_MODEL"),i("DASHSCOPE_MODEL"))};case"openrouter":return{provider:r,apiKey:i("OPENROUTER_API_KEY"),baseUrl:u(i("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:i("OPENROUTER_MODEL")};case"groq":return{provider:r,apiKey:i("GROQ_API_KEY"),baseUrl:u(i("GROQ_BASE_URL"),e.defaultBaseUrl),model:i("GROQ_MODEL")};case"deepseek":return{provider:r,apiKey:i("DEEPSEEK_API_KEY"),baseUrl:u(i("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:u(i("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:r,apiKey:u(i("NVIDIA_API_KEY"),i("NVIDIA_NIM_API_KEY")),baseUrl:u(i("NVIDIA_BASE_URL"),i("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:u(i("NVIDIA_MODEL"),i("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:r,apiKey:u(i("GEMINI_API_KEY"),i("GOOGLE_API_KEY")),baseUrl:u(i("GEMINI_BASE_URL"),e.defaultBaseUrl),model:i("GEMINI_MODEL")};case"huggingface":return{provider:r,apiKey:i("HF_TOKEN"),baseUrl:u(i("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:u(i("HF_LLM_MODEL"),i("HF_MODEL"))};case"ollama":return{provider:r,apiKey:i("OLLAMA_API_KEY"),baseUrl:u(i("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:i("OLLAMA_MODEL")};case"cloudflare":return{provider:r,accountId:i("CLOUDFLARE_ACCOUNT_ID"),apiKey:i("CLOUDFLARE_API_TOKEN"),baseUrl:i("CLOUDFLARE_AI_BASE_URL"),model:i("CLOUDFLARE_MODEL")};case"custom":return{provider:r,apiKey:i("CUSTOM_AI_API_KEY"),baseUrl:i("CUSTOM_AI_BASE_URL"),model:i("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:u(i("OPENAI_API_KEY"),i("MODEL_API_KEY")),baseUrl:u(i("OPENAI_BASE_URL"),i("MODEL_BASE_URL")),model:u(i("OPENAI_MODEL"),i("MODEL_NAME"))}}}function Tt(){let r=i("TOOLNET_LLM_PROVIDER"),e=r&&q(r)?r:It(),t=Y(e),s=ce(e);return{provider:e,apiKey:u(i("TOOLNET_LLM_API_KEY"),s.apiKey),baseUrl:u(i("TOOLNET_LLM_BASE_URL"),s.baseUrl,t.defaultBaseUrl),model:u(i("TOOLNET_LLM_MODEL"),s.model,t.defaultModel),accountId:u(i("TOOLNET_LLM_ACCOUNT_ID"),s.accountId)}}function _t(){let r=i("TOOLNET_EMBEDDING_PROVIDER");return r==="local"?"local":r&&q(r)?r:i("HF_TOKEN")||i("HF_EMBEDDING_MODEL")?"huggingface":"local"}function Mt(){let r=_t();if(r==="local")return{provider:"local",model:u(i("TOOLNET_EMBEDDING_MODEL"),i("LOCAL_EMBEDDING_MODEL"))};let e=Y(r),t,s,o,n;switch(r){case"huggingface":t=i("HF_TOKEN"),s=i("HF_INFERENCE_BASE_URL"),o=i("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=i("OPENAI_API_KEY"),s=i("OPENAI_BASE_URL"),o=i("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=i("CLOUDFLARE_API_TOKEN"),s=i("CLOUDFLARE_AI_BASE_URL"),o=i("CLOUDFLARE_EMBEDDING_MODEL"),n=i("CLOUDFLARE_ACCOUNT_ID");break;default:t=ce(r).apiKey,s=ce(r).baseUrl,o=i(`${r.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let a=u(i("TOOLNET_EMBEDDING_ACCOUNT_ID"),n),c=u(i("TOOLNET_EMBEDDING_BASE_URL"),s,e.defaultBaseUrl),d=r==="cloudflare"&&!c&&a?`https://api.cloudflare.com/client/v4/accounts/${a}/ai/v1`:c;return{provider:r,apiKey:u(i("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:d,model:u(i("TOOLNET_EMBEDDING_MODEL"),o),accountId:a}}function Le(){let r=Tt(),e=Mt();return{llm:r,embedding:e,legacy:{llm:!i("TOOLNET_LLM_PROVIDER")&&!!Ae(),embedding:!i("TOOLNET_EMBEDDING_PROVIDER")&&!!(i("HF_TOKEN")||i("HF_EMBEDDING_MODEL"))}}}var J=class{constructor(e){this.options=e}options;name="gemini";async embed(e){let t=this.options.model.replace(/^models\//,""),o=`${this.options.baseUrl?.replace(/\/+$/,"")||"https://generativelanguage.googleapis.com/v1beta"}/models/${encodeURIComponent(t)}:embedContent?key=${encodeURIComponent(this.options.apiKey)}`,n=await fetch(o,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({model:`models/${t}`,content:{parts:[{text:e}]}})});if(!n.ok)throw new Error(`Gemini embedding failed: ${n.status} ${await n.text()}`);let c=(await n.json()).embedding?.values;if(!Array.isArray(c)||c.length===0)throw new Error("Gemini embedding returned invalid response");return c}async embedMany(e){let t=[];for(let s of e)t.push(await this.embed(s));return t}};import{createHash as Nt}from"node:crypto";var Q=class{name="hash-fallback";dimensions=128;async embed(e){let t=new Array(this.dimensions).fill(0),s=e.toLowerCase().split(/\s+/).filter(Boolean);for(let o of s){let a=Nt("sha256").update(o).digest().readUInt32BE(0)%this.dimensions;t[a]+=1}return Ot(t)}async embedMany(e){return Promise.all(e.map(t=>this.embed(t)))}};function Ot(r){let e=Math.sqrt(r.reduce((t,s)=>t+s*s,0));return e===0?r:r.map(t=>t/e)}var Z=class{constructor(e){this.options=e;this.dimensions=e.dimensions}options;name="openai-compatible";dimensions;async embed(e){let[t]=await this.embedMany([e]);return t}async embedMany(e){if(e.length===0)return[];let t=this.options.baseUrl.replace(/\/+$/,""),s=await fetch(`${t}/embeddings`,{method:"POST",headers:{"content-type":"application/json",...this.options.apiKey?{authorization:`Bearer ${this.options.apiKey}`}:{}},body:JSON.stringify({model:this.options.model,input:e})});if(!s.ok)throw new Error(`Embedding failed: ${s.status} ${await s.text()}`);let n=(await s.json()).data?.sort((a,c)=>(a.index??0)-(c.index??0)).map(a=>a.embedding);if(!n||n.length!==e.length||n.some(a=>!Array.isArray(a)))throw new Error("Embedding provider returned invalid response");return n}};var X=class{constructor(e){this.options=e}options;name="huggingface";dimensions=384;async embed(e){let[t]=await this.embedMany([e]);return t}async embedMany(e){if(e.length===0)return[];let t=`https://router.huggingface.co/hf-inference/models/${this.options.model}/pipeline/feature-extraction`,s=await fetch(t,{method:"POST",headers:{Authorization:`Bearer ${this.options.token}`,"Content-Type":"application/json"},body:JSON.stringify({inputs:e,options:{wait_for_model:!0}})});if(!s.ok)throw new Error(`HF embedding failed: ${s.status} ${await s.text()}`);let o=await s.json();if(!Array.isArray(o))throw new Error("HF embedding returned invalid response");return o.map(n=>jt(n))}};function jt(r){if(!Array.isArray(r))throw new Error("Invalid embedding");if(r.length>0&&typeof r[0]=="number")return r;if(r.length>0&&Array.isArray(r[0])){let e=r;if(e.length===0)return[];let t=e[0].length,s=new Array(t).fill(0);for(let o of e)for(let n=0;n<t;n++)s[n]+=o[n]??0;for(let o=0;o<t;o++)s[o]/=e.length;return s}throw new Error("Unsupported embedding shape")}var le=class{constructor(e,t=new Q){this.primary=e;this.fallback=t}primary;fallback;name="resilient";async embed(e){if(this.primary)try{return await this.primary.embed(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embed(e)}async embedMany(e){if(this.primary)try{return await this.primary.embedMany(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embedMany(e)}};function Dt(r){return`https://api.cloudflare.com/client/v4/accounts/${r}/ai/v1`}function Ft(){let r=Le().embedding;if(r.provider==="local")return null;if(r.provider==="huggingface")return!r.apiKey||!r.model?null:new X({token:r.apiKey,model:r.model});if(r.provider==="gemini")return!r.apiKey||!r.model?null:new J({apiKey:r.apiKey,model:r.model,baseUrl:r.baseUrl});let e=r.baseUrl;return r.provider==="cloudflare"&&!e&&r.accountId&&(e=Dt(r.accountId)),e&&r.model?new Z({apiKey:r.apiKey,baseUrl:e,model:r.model}):null}function Re(){return new le(Ft())}async function Kt(){let r=ue(),e=new F().detect(),t=Ee({provider:r.storage.provider,huggingface:r.storage.huggingface,localRoot:r.storage.localRoot}),s=new z(t,e.id,e.name,e.remote??e.name),o=new L,n=await new j(s).load(e.id);if(!n)throw new Error("Code graph missing. Run npm run code:index:test first.");o.import(n.symbols,n.edges);let a=new W({projectId:e.id,rootPath:e.rootPath,model:process.env.HF_EMBEDDING_MODEL??"sentence-transformers/all-MiniLM-L6-v2",storage:s,embeddings:Re(),graph:o}),c=await a.initialize(),d=process.argv.slice(2).join(" ")||"memory storage hugging face",m=await a.search(d,5);console.log({ok:!0,query:d,...c,results:m.map(l=>({score:Number(l.score.toFixed(4)),file:l.chunk.filePath,symbol:l.chunk.symbolName,lines:`${l.chunk.startLine}-${l.chunk.endLine}`,preview:l.chunk.content.replace(/\s+/g," ").slice(0,140)}))})}Kt().catch(r=>{console.error(r),process.exit(1)});
1
+ import"dotenv/config";import{existsSync as te,readFileSync as re}from"node:fs";import{homedir as se}from"node:os";import{join as oe}from"node:path";function ne(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 ie(){let s=process.env.TOOLNET_GLOBAL_ENV??oe(se(),".config","toolnet-memory",".env");if(!te(s))return;let e=re(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]=ne(r.slice(o+1)))}}ie();function b(s,e){return s===void 0?e:["1","true","yes","on"].includes(s.toLowerCase())}function C(s,e){if(!s)return e;let t=Number(s);return Number.isFinite(t)?t:e}function K(){return{memory:{autoCapture:b(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:b(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:b(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:b(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:b(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 ae}from"node:crypto";import{existsSync as _,mkdirSync as ce,readFileSync as le,renameSync as de,writeFileSync as pe}from"node:fs";import{basename as ue,dirname as P,join as T,parse as W,resolve as x}from"node:path";var U=".toolnet",me="project.json";function fe(s){return ae("sha256").update(s).digest("hex").slice(0,16)}function F(s){return T(s,U,me)}function ge(s){return _(F(s))}function he(s,e){let t=x(s),r=W(t).root;for(;;){if(ge(t))return t;if(t===r||e&&t===x(e))break;let o=P(t);if(o===t)break;t=o}return null}function ye(s){let e=x(s),t=W(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(n=>_(T(e,n))))return e;if(e===t)break;let o=P(e);if(o===e)break;e=o}return x(s)}function Se(s){let e;try{e=JSON.parse(le(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:P(P(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 z(s,e){let t=T(s,U);ce(t,{recursive:!0});let r=F(s),o=`${r}.tmp-${process.pid}`;pe(o,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),de(o,r)}function B(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 R=class{detect(e=process.cwd()){let t=x(e),r=ye(t),n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>_(T(r,d))),i=he(t,n?r:void 0);if(i){let d=F(i),u=Se(d);return u.rootPath!==i&&(u.rootPath=i,u.updatedAt=new Date().toISOString(),z(i,u)),B(u,i)}let a=new Date().toISOString(),p=ue(r),l={version:1,id:fe(r),name:p,remote:p,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return z(r,l),B(l,r)}};var be=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_\-]{20,}\b/g},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._\-]{16,}\b/gi},{type:"jwt",regex:/\beyJ[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\b/g},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/g},{type:"password_assignment",regex:/\b(password|passwd|pwd)\s*[:=]\s*["']?[^"'\s]{6,}["']?/gi},{type:"secret_assignment",regex:/\b(secret|api[_-]?key|access[_-]?token|refresh[_-]?token)\s*[:=]\s*["']?[^"'\s]{8,}["']?/gi},{type:"cookie",regex:/\b(cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi}],A=class{scan(e){let t=[];for(let r of be){let o=new RegExp(r.regex.source,r.regex.flags);for(let n of e.matchAll(o))t.push({type:r.type,value:n[0]})}return t}hasSecrets(e){return this.scan(e).length>0}};var E=class{scanner=new A;sanitize(e){let t=e,r=this.scanner.scan(e),o=new Set;for(let n of r)o.add(n.type),t=t.split(n.value).join(`[REDACTED:${n.type}]`);return{text:t,redacted:r.length,secretTypes:[...o]}}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,"");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]":t[r]=this.sanitizeValue(o)}return t}return e}};import{homedir as ze}from"node:os";import{join as Be}from"node:path";import{DeleteObjectCommand as Ce,GetObjectCommand as xe,HeadObjectCommand as Ee,ListObjectsV2Command as we,PutObjectCommand as ve,S3Client as ke}from"@aws-sdk/client-s3";import{getSignedUrl as Pe}from"@aws-sdk/s3-request-presigner";var j=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 ve({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await Pe(this.client,new xe({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 Ee({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 Ce({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 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 H,mkdir as Re,readFile as Te,readdir as Ae,rm as je,stat as V,writeFile as Le}from"node:fs/promises";import{dirname as Me,join as Ne,relative as Y,resolve as Ie}from"node:path";var w=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Ie(this.root,t)}async put(e,t){let r=this.path(e);await Re(Me(r),{recursive:!0}),await Le(r,t)}async get(e){try{return await Te(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 H(this.path(e)),!0}catch{return!1}}async delete(e){await je(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await H(t)}catch{return r}let o=async i=>{let a=await Ae(i,{withFileTypes:!0});for(let p of a){let l=Ne(i,p.name);if(p.isDirectory()){await o(l);continue}let d=await V(l);r.push({key:Y(this.root,l),size:d.size,updatedAt:d.mtime.toISOString()})}},n=await V(t);return n.isDirectory()?await o(t):r.push({key:Y(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),r}};import{DeleteObjectCommand as Oe,GetObjectCommand as _e,HeadObjectCommand as Fe,ListObjectsV2Command as $e,PutObjectCommand as De,S3Client as Ge}from"@aws-sdk/client-s3";import{getSignedUrl as Ke}from"@aws-sdk/s3-request-presigner";var v=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Ge({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 De({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await Ke(this.client,new _e({Bucket:this.bucket,Key:e}),{expiresIn:60}),r=await fetch(t,{redirect:"follow"});if(r.status===404)return null;if(!r.ok)throw new Error(`${this.name} download failed: ${r.status} ${r.statusText}`);return new Uint8Array(await r.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Fe({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 Oe({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 $(s,e){return console.warn(e),new w(s)}function J(s){let e=s.localRoot??Be(ze(),".toolnet-memory","storage");if(s.provider==="r2"){let t=s.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new v({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):$(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 v({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):$(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 j({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):$(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new w(e)}var k=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 L=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 q(s){let e=s.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!e||e==="."||e==="..")throw new Error("Invalid project storage folder");return e}function Q(s){let e=s.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let o=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return o?`${o[1]}memory/records/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),o?`${o[1]}memory/vectors/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),o?`${o[1]}code/graph/${o[2]}`:e))}var M=class{constructor(e,t,r,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=q(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=Q(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,r){return await this.ensureRegistered(),this.provider.put(this.key(e),t,r)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import*as m from"typescript";var S=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{execFile as Ve}from"node:child_process";import{promisify as Ye}from"node:util";var gs=Ye(Ve);import{createHash as Je}from"node:crypto";import{readFile as qe}from"node:fs/promises";import{join as Qe}from"node:path";function Z(s){return Je("sha256").update(s).digest("hex")}var N=class{sanitizer=new E;async build(e,t,r,o={}){let n=o.maxLines??80,i=o.overlapLines??10,a=new Map;for(let l of r){let d=a.get(l.filePath)??[];d.push(l),a.set(l.filePath,d)}let p=[];for(let[l,d]of a){let u;try{u=await qe(Qe(t,l),"utf8")}catch{continue}let h=u.split(/\r?\n/),y=d.filter(g=>g.type!=="file"&&typeof g.startLine=="number"&&typeof g.endLine=="number");if(y.length>0)for(let g of y)p.push(...this.chunkRange({projectId:e,filePath:l,lines:h,symbol:g,startLine:g.startLine,endLine:g.endLine,maxLines:n,overlapLines:i}));else p.push(...this.chunkRange({projectId:e,filePath:l,lines:h,startLine:1,endLine:Math.max(1,h.length),maxLines:n,overlapLines:i}))}return p}chunkRange(e){let{projectId:t,filePath:r,lines:o,symbol:n,maxLines:i}=e,a=Math.min(e.overlapLines,Math.max(0,i-1)),p=Math.max(1,e.startLine),l=Math.min(o.length,Math.max(p,e.endLine)),d=[],u=p,h=0;for(;u<=l;){let y=Math.min(l,u+i-1),g=o.slice(u-1,y).join(`
5
+ `).trim();if(g){let D=this.sanitizer.sanitize(g).text,G=Z(D),ee=[t,r,n?.id??"file",String(h),G].join(":");d.push({id:Z(ee).slice(0,32),projectId:t,filePath:r,symbolId:n?.id,symbolName:n?.qualifiedName??n?.name,symbolType:n?.type,startLine:u,endLine:y,content:D,contentHash:G})}if(y>=l)break;u=y-a+1,h++}return d}};import{DatabaseSync as Ze}from"node:sqlite";var I=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 Ze(":memory:");chunks=new Map;get size(){return this.chunks.size}build(e){if(e.length===0)return 0;this.db.exec("DELETE FROM code_fts"),this.chunks.clear();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 o=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)),n=[];for(let i of o){let a=this.chunks.get(i.id);if(!a)continue;let p=1/(1+Math.abs(i.rank));n.push({chunk:a,score:p})}return n.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 X(s,e){let t=s.toLowerCase().replaceAll("\\","/"),r=e.toLowerCase(),o=/\b(test|tests|spec|fixture|mock)\b/.test(r);return(t.startsWith("tests/")||t.includes("/tests/")||t.includes("__tests__")||/\.(test|spec)\.[^.]+$/.test(t))&&!o?.35:t.includes("/generated/")||t.includes(".generated.")?.25:1}var O=class{constructor(e){this.options=e;this.fts=new I(e.projectId)}options;fts;async initialize(e){let{projectId:t,rootPath:r,storage:o,graph:n}=this.options,i=new L(o),a=await new N().build(t,r,n.allSymbols(t)),p=await i.load(t),l=!p||p.chunks.length!==a.length||p.chunks.some(u=>!a.some(h=>h.id===u.id));l&&await i.save({version:1,projectId:t,updatedAt:new Date().toISOString(),chunks:a}),e?.({current:a.length,total:a.length,phase:"index"});let d=this.fts.build(a);return{chunks:a.length,vectorsLoaded:0,vectorsIndexed:d,vectorsRemoved:0,totalVectors:this.fts.size,savedChunks:l,savedVectors:l}}async search(e,t=8){let r=this.fts.search(e,t),o=[];for(let n of r){let i=n.chunk,a=X(i.filePath,e),p=n.score,l=0,d=p*a;o.push({chunk:i,score:d,vectorScore:l,lexicalScore:p})}return o}size(){return this.fts.size}};import*as f from"typescript";import*as c from"typescript";var Co=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 et(){let s=K(),e=new R().detect(),t=J({provider:s.storage.provider,huggingface:s.storage.huggingface,localRoot:s.storage.localRoot}),r=new M(t,e.id,e.name,e.remote??e.name),o=new S,n=await new k(r).load(e.id);if(!n)throw new Error("Code graph missing. Run npm run code:index:test first.");o.import(n.symbols,n.edges);let i=new O({projectId:e.id,rootPath:e.rootPath,storage:r,graph:o}),a=await i.initialize(),p=process.argv.slice(2).join(" ")||"memory storage hugging face",l=await i.search(p,5);console.log({ok:!0,query:p,...a,results:l.map(d=>({score:Number(d.score.toFixed(4)),file:d.chunk.filePath,symbol:d.chunk.symbolName,lines:`${d.chunk.startLine}-${d.chunk.endLine}`,preview:d.chunk.content.replace(/\s+/g," ").slice(0,140)}))})}et().catch(s=>{console.error(s),process.exit(1)});
@@ -1,4 +1,4 @@
1
1
  import"dotenv/config";import{existsSync as B,readFileSync as V}from"node:fs";import{homedir as U}from"node:os";import{join as F}from"node:path";function J(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 Y(){let s=process.env.TOOLNET_GLOBAL_ENV??F(U(),".config","toolnet-memory",".env");if(!B(s))return;let e=V(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]=J(r.slice(o+1)))}}Y();function m(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 A(){return{memory:{autoCapture:m(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:m(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:m(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:m(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:m(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 H}from"node:crypto";import{existsSync as b,mkdirSync as G,readFileSync as W,renameSync as Q,writeFileSync as Z}from"node:fs";import{basename as q,dirname as S,join as w,parse as T,resolve as f}from"node:path";var E=".toolnet",X="project.json";function ee(s){return H("sha256").update(s).digest("hex").slice(0,16)}function k(s){return w(s,E,X)}function te(s){return b(k(s))}function re(s,e){let t=f(s),r=T(t).root;for(;;){if(te(t))return t;if(t===r||e&&t===f(e))break;let o=S(t);if(o===t)break;t=o}return null}function se(s){let e=f(s),t=T(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(n=>b(w(e,n))))return e;if(e===t)break;let o=S(e);if(o===e)break;e=o}return f(s)}function oe(s){let e;try{e=JSON.parse(W(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:S(S(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 M(s,e){let t=w(s,E);G(t,{recursive:!0});let r=k(s),o=`${r}.tmp-${process.pid}`;Z(o,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),Q(o,r)}function C(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 v=class{detect(e=process.cwd()){let t=f(e),r=se(t),n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>b(w(r,u))),i=re(t,n?r:void 0);if(i){let u=k(i),d=oe(u);return d.rootPath!==i&&(d.rootPath=i,d.updatedAt=new Date().toISOString(),M(i,d)),C(d,i)}let a=new Date().toISOString(),c=q(r),p={version:1,id:ee(r),name:c,remote:c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return M(r,p),C(p,r)}};import{homedir as Ae}from"node:os";import{join as Me}from"node:path";import{DeleteObjectCommand as ne,GetObjectCommand as ie,HeadObjectCommand as ae,ListObjectsV2Command as ce,PutObjectCommand as pe,S3Client as ue}from"@aws-sdk/client-s3";import{getSignedUrl as de}from"@aws-sdk/s3-request-presigner";var j=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new ue({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 pe({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await de(this.client,new ie({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 ae({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 ne({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let o=await this.client.send(new ce({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 I,mkdir as le,readFile as me,readdir as ge,rm as fe,stat as O,writeFile as ye}from"node:fs/promises";import{dirname as he,join as Se,relative as _,resolve as ve}from"node:path";var y=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return ve(this.root,t)}async put(e,t){let r=this.path(e);await le(he(r),{recursive:!0}),await ye(r,t)}async get(e){try{return await me(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 I(this.path(e)),!0}catch{return!1}}async delete(e){await fe(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await I(t)}catch{return r}let o=async i=>{let a=await ge(i,{withFileTypes:!0});for(let c of a){let p=Se(i,c.name);if(c.isDirectory()){await o(p);continue}let u=await O(p);r.push({key:_(this.root,p),size:u.size,updatedAt:u.mtime.toISOString()})}},n=await O(t);return n.isDirectory()?await o(t):r.push({key:_(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),r}};import{DeleteObjectCommand as we,GetObjectCommand as je,HeadObjectCommand as xe,ListObjectsV2Command as be,PutObjectCommand as ke,S3Client as Pe}from"@aws-sdk/client-s3";import{getSignedUrl as Re}from"@aws-sdk/s3-request-presigner";var h=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Pe({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new ke({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await Re(this.client,new je({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 xe({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new we({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let o=await this.client.send(new be({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 y(s)}function $(s){let e=s.localRoot??Me(Ae(),".toolnet-memory","storage");if(s.provider==="r2"){let t=s.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new h({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 h({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 j({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):P(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new y(e)}function Ce(s){return new Promise(e=>setTimeout(e,s))}async function K(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)),p=Math.floor(Math.random()*Math.max(1,c*.2));await Ce(c+p)}throw n}var Te=new Set(["put","get","getText","delete","list"]);function N(s,e={}){return new Proxy(s,{get(t,r){let o=Reflect.get(t,r,t);return typeof o!="function"?o:Te.has(r)?(...n)=>K(()=>Promise.resolve(o.apply(t,n)),e):o.bind(t)}})}function D(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 z(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 x=class{constructor(e,t,r,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=D(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=z(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 Ee=["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"],l=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 u of Ee){let d=`${i}/${u}`,R=await this.storage.get(d);R&&(await this.storage.put(`${a}/${u}`,R,"application/json"),c.push(u))}if(c.length===0)return null;let p={version:1,id:n,projectId:e,createdAt:o,reason:t,objects:c,metadata:r};return await this.storage.put(`${a}/snapshot.json`,JSON.stringify(p,null,2),"application/json"),p}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 p=await this.storage.get(`${r}/${c}`);p&&(await this.storage.put(`${i}/${c}`,p,"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 L(s,e){let t=new l(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 Ie(){let s=process.argv[2],e=A(),t=new v().detect(),r=N($({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),o=new x(r,t.id,t.name,t.remote??t.name),n=new l(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 L(o,t.id));return}throw new Error("Usage: snapshot-cli list|create|restore|recover-latest")}Ie().catch(s=>{console.error(s instanceof Error?s.message:s),process.exit(1)});
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 Y(){let s=process.env.TOOLNET_GLOBAL_ENV??F(U(),".config","toolnet-memory",".env");if(!B(s))return;let e=V(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]=J(r.slice(o+1)))}}Y();function m(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 A(){return{memory:{autoCapture:m(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:m(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:m(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:m(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:m(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 H}from"node:crypto";import{existsSync as x,mkdirSync as G,readFileSync as W,renameSync as Q,writeFileSync as Z}from"node:fs";import{basename as q,dirname as S,join as v,parse as T,resolve as f}from"node:path";var E=".toolnet",X="project.json";function ee(s){return H("sha256").update(s).digest("hex").slice(0,16)}function k(s){return v(s,E,X)}function te(s){return x(k(s))}function re(s,e){let t=f(s),r=T(t).root;for(;;){if(te(t))return t;if(t===r||e&&t===f(e))break;let o=S(t);if(o===t)break;t=o}return null}function se(s){let e=f(s),t=T(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(n=>x(v(e,n))))return e;if(e===t)break;let o=S(e);if(o===e)break;e=o}return f(s)}function oe(s){let e;try{e=JSON.parse(W(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:S(S(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 M(s,e){let t=v(s,E);G(t,{recursive:!0});let r=k(s),o=`${r}.tmp-${process.pid}`;Z(o,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),Q(o,r)}function C(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 w=class{detect(e=process.cwd()){let t=f(e),r=se(t),n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>x(v(r,u))),i=re(t,n?r:void 0);if(i){let u=k(i),d=oe(u);return d.rootPath!==i&&(d.rootPath=i,d.updatedAt=new Date().toISOString(),M(i,d)),C(d,i)}let a=new Date().toISOString(),c=q(r),p={version:1,id:ee(r),name:c,remote:c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return M(r,p),C(p,r)}};import{homedir as Ae}from"node:os";import{join as Me}from"node:path";import{DeleteObjectCommand as ne,GetObjectCommand as ie,HeadObjectCommand as ae,ListObjectsV2Command as ce,PutObjectCommand as pe,S3Client as ue}from"@aws-sdk/client-s3";import{getSignedUrl as de}from"@aws-sdk/s3-request-presigner";var j=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new ue({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 pe({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await de(this.client,new ie({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 ae({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 ne({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let o=await this.client.send(new ce({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 I,mkdir as le,readFile as me,readdir as ge,rm as fe,stat as O,writeFile as ye}from"node:fs/promises";import{dirname as he,join as Se,relative as _,resolve as we}from"node:path";var y=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return we(this.root,t)}async put(e,t){let r=this.path(e);await le(he(r),{recursive:!0}),await ye(r,t)}async get(e){try{return await me(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 I(this.path(e)),!0}catch{return!1}}async delete(e){await fe(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await I(t)}catch{return r}let o=async i=>{let a=await ge(i,{withFileTypes:!0});for(let c of a){let p=Se(i,c.name);if(c.isDirectory()){await o(p);continue}let u=await O(p);r.push({key:_(this.root,p),size:u.size,updatedAt:u.mtime.toISOString()})}},n=await O(t);return n.isDirectory()?await o(t):r.push({key:_(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),r}};import{DeleteObjectCommand as ve,GetObjectCommand as je,HeadObjectCommand as be,ListObjectsV2Command as xe,PutObjectCommand as ke,S3Client as Pe}from"@aws-sdk/client-s3";import{getSignedUrl as Re}from"@aws-sdk/s3-request-presigner";var h=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Pe({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new ke({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await Re(this.client,new je({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 be({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 ve({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let o=await this.client.send(new xe({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 y(s)}function $(s){let e=s.localRoot??Me(Ae(),".toolnet-memory","storage");if(s.provider==="r2"){let t=s.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new h({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 h({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 j({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):P(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new y(e)}function Ce(s){return new Promise(e=>setTimeout(e,s))}async function K(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)),p=Math.floor(Math.random()*Math.max(1,c*.2));await Ce(c+p)}throw n}var Te=new Set(["put","get","getText","delete","list"]);function N(s,e={}){return new Proxy(s,{get(t,r){let o=Reflect.get(t,r,t);return typeof o!="function"?o:Te.has(r)?(...n)=>K(()=>Promise.resolve(o.apply(t,n)),e):o.bind(t)}})}function D(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 z(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 b=class{constructor(e,t,r,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=D(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=z(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 Ee=["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"],l=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 u of Ee){let d=`${i}/${u}`,R=await this.storage.get(d);R&&(await this.storage.put(`${a}/${u}`,R,"application/json"),c.push(u))}if(c.length===0)return null;let p={version:1,id:n,projectId:e,createdAt:o,reason:t,objects:c,metadata:r};return await this.storage.put(`${a}/snapshot.json`,JSON.stringify(p,null,2),"application/json"),p}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 p=await this.storage.get(`${r}/${c}`);p&&(await this.storage.put(`${i}/${c}`,p,"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 L(s,e){let t=new l(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 Ie(){let s=process.argv[2],e=A(),t=new w().detect(),r=N($({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),o=new b(r,t.id,t.name,t.remote??t.name),n=new l(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 L(o,t.id));return}throw new Error("Usage: snapshot-cli list|create|restore|recover-latest")}Ie().catch(s=>{console.error(s instanceof Error?s.message:s),process.exit(1)});
@@ -1,4 +1,4 @@
1
- import{existsSync as Re,readFileSync as De}from"node:fs";import{homedir as Te}from"node:os";import{join as Le}from"node:path";function Ne(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 Ke(){let t=process.env.TOOLNET_GLOBAL_ENV??Le(Te(),".config","toolnet-memory",".env");if(!Re(t))return;let e=De(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 i=o.indexOf("=");if(i<=0)continue;let a=o.slice(0,i).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(a)&&process.env[a]===void 0&&(process.env[a]=Ne(o.slice(i+1)))}}Ke();function k(t,e){return t===void 0?e:["1","true","yes","on"].includes(t.toLowerCase())}function C(t,e){if(!t)return e;let r=Number(t);return Number.isFinite(r)?r:e}function V(){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: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: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:C(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Ue}from"node:crypto";import{existsSync as N,mkdirSync as Fe,readFileSync as $e,renameSync as Be,writeFileSync as He}from"node:fs";import{basename as Ge,dirname as I,join as j,parse as z,resolve as A}from"node:path";var J=".toolnet",Ve="project.json";function We(t){return Ue("sha256").update(t).digest("hex").slice(0,16)}function K(t){return j(t,J,Ve)}function Ye(t){return N(K(t))}function ze(t,e){let r=A(t),o=z(r).root;for(;;){if(Ye(r))return r;if(r===o||e&&r===A(e))break;let i=I(r);if(i===r)break;r=i}return null}function Je(t){let e=A(t),r=z(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(a=>N(j(e,a))))return e;if(e===r)break;let i=I(e);if(i===e)break;e=i}return A(t)}function qe(t){let e;try{e=JSON.parse($e(t,"utf8"))}catch(i){throw new Error(`Invalid ToolNet project manifest: ${t}: ${i instanceof Error?i.message:String(i)}`)}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:I(I(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 W(t,e){let r=j(t,J);Fe(r,{recursive:!0});let o=K(t),i=`${o}.tmp-${process.pid}`;He(i,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),Be(i,o)}function Y(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 _=class{detect(e=process.cwd()){let r=A(e),o=Je(r),a=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>N(j(o,m))),s=ze(r,a?o:void 0);if(s){let m=K(s),u=qe(m);return u.rootPath!==s&&(u.rootPath=s,u.updatedAt=new Date().toISOString(),W(s,u)),Y(u,s)}let l=new Date().toISOString(),p=Ge(o),d={version:1,id:We(o),name:p,remote:p,rootPath:o,createdAt:l,updatedAt:l,graphVersion:0,memoryVersion:0};return W(o,d),Y(d,o)}};var q=[{id:"openai-compatible",label:"OpenAI-compatible",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"alibaba",label:"Alibaba / DashScope",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"openrouter",label:"OpenRouter",defaultBaseUrl:"https://openrouter.ai/api/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"groq",label:"Groq",defaultBaseUrl:"https://api.groq.com/openai/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"deepseek",label:"DeepSeek",defaultBaseUrl:"https://api.deepseek.com",defaultModel:"deepseek-v4-flash",requiresApiKey:!0,transport:"openai-compatible"},{id:"nvidia",label:"NVIDIA NIM",defaultBaseUrl:"https://integrate.api.nvidia.com/v1",defaultModel:"deepseek-ai/deepseek-v4-pro",requiresApiKey:!0,transport:"openai-compatible"},{id:"gemini",label:"Gemini",defaultBaseUrl:"https://generativelanguage.googleapis.com/v1beta",requiresApiKey:!0,transport:"gemini"},{id:"huggingface",label:"Hugging Face",defaultBaseUrl:"https://router.huggingface.co/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"ollama",label:"Ollama / Local",defaultBaseUrl:"http://127.0.0.1:11434/v1",requiresApiKey:!1,transport:"openai-compatible"},{id:"custom",label:"Custom endpoint",requiresApiKey:!1,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"cloudflare",label:"Cloudflare Workers AI",requiresApiKey:!0,requiresAccountId:!0,transport:"cloudflare"}];function M(t){let e=q.find(r=>r.id===t);if(!e)throw new Error(`Unsupported AI provider: ${t}`);return e}function w(t){return q.some(e=>e.id===t)}function n(t){return process.env[t]?.trim()||void 0}function c(...t){return t.find(e=>!!e?.trim())}function Q(){if(n("GROQ_API_KEY"))return"groq";if(n("DEEPSEEK_API_KEY"))return"deepseek";if(n("NVIDIA_API_KEY")||n("NVIDIA_NIM_API_KEY"))return"nvidia";if(n("OPENROUTER_API_KEY"))return"openrouter";if(n("ALIBABA_API_KEY")||n("DASHSCOPE_API_KEY"))return"alibaba";if(n("GEMINI_API_KEY")||n("GOOGLE_API_KEY"))return"gemini";if(n("CLOUDFLARE_API_TOKEN")&&n("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(n("HF_TOKEN"))return"huggingface";if(n("OLLAMA_MODEL")||n("OLLAMA_BASE_URL"))return"ollama"}function Qe(){let t=n("TOOLNET_LLM_PROVIDER");return t&&w(t)?t:Q()??"openai-compatible"}function U(t){let e=M(t);switch(t){case"alibaba":return{provider:t,apiKey:c(n("ALIBABA_API_KEY"),n("DASHSCOPE_API_KEY")),baseUrl:c(n("ALIBABA_BASE_URL"),n("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:c(n("ALIBABA_MODEL"),n("DASHSCOPE_MODEL"))};case"openrouter":return{provider:t,apiKey:n("OPENROUTER_API_KEY"),baseUrl:c(n("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:n("OPENROUTER_MODEL")};case"groq":return{provider:t,apiKey:n("GROQ_API_KEY"),baseUrl:c(n("GROQ_BASE_URL"),e.defaultBaseUrl),model:n("GROQ_MODEL")};case"deepseek":return{provider:t,apiKey:n("DEEPSEEK_API_KEY"),baseUrl:c(n("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:c(n("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:t,apiKey:c(n("NVIDIA_API_KEY"),n("NVIDIA_NIM_API_KEY")),baseUrl:c(n("NVIDIA_BASE_URL"),n("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:c(n("NVIDIA_MODEL"),n("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:t,apiKey:c(n("GEMINI_API_KEY"),n("GOOGLE_API_KEY")),baseUrl:c(n("GEMINI_BASE_URL"),e.defaultBaseUrl),model:n("GEMINI_MODEL")};case"huggingface":return{provider:t,apiKey:n("HF_TOKEN"),baseUrl:c(n("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:c(n("HF_LLM_MODEL"),n("HF_MODEL"))};case"ollama":return{provider:t,apiKey:n("OLLAMA_API_KEY"),baseUrl:c(n("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:n("OLLAMA_MODEL")};case"cloudflare":return{provider:t,accountId:n("CLOUDFLARE_ACCOUNT_ID"),apiKey:n("CLOUDFLARE_API_TOKEN"),baseUrl:n("CLOUDFLARE_AI_BASE_URL"),model:n("CLOUDFLARE_MODEL")};case"custom":return{provider:t,apiKey:n("CUSTOM_AI_API_KEY"),baseUrl:n("CUSTOM_AI_BASE_URL"),model:n("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:c(n("OPENAI_API_KEY"),n("MODEL_API_KEY")),baseUrl:c(n("OPENAI_BASE_URL"),n("MODEL_BASE_URL")),model:c(n("OPENAI_MODEL"),n("MODEL_NAME"))}}}function Ze(){let t=n("TOOLNET_LLM_PROVIDER"),e=t&&w(t)?t:Qe(),r=M(e),o=U(e);return{provider:e,apiKey:c(n("TOOLNET_LLM_API_KEY"),o.apiKey),baseUrl:c(n("TOOLNET_LLM_BASE_URL"),o.baseUrl,r.defaultBaseUrl),model:c(n("TOOLNET_LLM_MODEL"),o.model,r.defaultModel),accountId:c(n("TOOLNET_LLM_ACCOUNT_ID"),o.accountId)}}function Xe(){let t=n("TOOLNET_EMBEDDING_PROVIDER");return t==="local"?"local":t&&w(t)?t:n("HF_TOKEN")||n("HF_EMBEDDING_MODEL")?"huggingface":"local"}function et(){let t=Xe();if(t==="local")return{provider:"local",model:c(n("TOOLNET_EMBEDDING_MODEL"),n("LOCAL_EMBEDDING_MODEL"))};let e=M(t),r,o,i,a;switch(t){case"huggingface":r=n("HF_TOKEN"),o=n("HF_INFERENCE_BASE_URL"),i=n("HF_EMBEDDING_MODEL");break;case"openai-compatible":r=n("OPENAI_API_KEY"),o=n("OPENAI_BASE_URL"),i=n("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":r=n("CLOUDFLARE_API_TOKEN"),o=n("CLOUDFLARE_AI_BASE_URL"),i=n("CLOUDFLARE_EMBEDDING_MODEL"),a=n("CLOUDFLARE_ACCOUNT_ID");break;default:r=U(t).apiKey,o=U(t).baseUrl,i=n(`${t.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let s=c(n("TOOLNET_EMBEDDING_ACCOUNT_ID"),a),l=c(n("TOOLNET_EMBEDDING_BASE_URL"),o,e.defaultBaseUrl),p=t==="cloudflare"&&!l&&s?`https://api.cloudflare.com/client/v4/accounts/${s}/ai/v1`:l;return{provider:t,apiKey:c(n("TOOLNET_EMBEDDING_API_KEY"),r),baseUrl:p,model:c(n("TOOLNET_EMBEDDING_MODEL"),i),accountId:s}}function Z(){let t=Ze(),e=et();return{llm:t,embedding:e,legacy:{llm:!n("TOOLNET_LLM_PROVIDER")&&!!Q(),embedding:!n("TOOLNET_EMBEDDING_PROVIDER")&&!!(n("HF_TOKEN")||n("HF_EMBEDDING_MODEL"))}}}import{homedir as xt}from"node:os";import{join as Et}from"node:path";import{DeleteObjectCommand as tt,GetObjectCommand as rt,HeadObjectCommand as ot,ListObjectsV2Command as nt,PutObjectCommand as it,S3Client as st}from"@aws-sdk/client-s3";import{getSignedUrl as at}from"@aws-sdk/s3-request-presigner";var R=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new st({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 i=typeof r=="string"?Buffer.from(r,"utf8"):r;await this.client.send(new it({Bucket:this.bucket,Key:e,Body:i,ContentType:o}))}async get(e){let r=await at(this.client,new rt({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 ot({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 tt({Bucket:this.bucket,Key:e}))}async list(e=""){let r=[],o;do{let i=await this.client.send(new nt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let a of i.Contents??[])a.Key&&r.push({key:a.Key,size:a.Size,updatedAt:a.LastModified?.toISOString()});o=i.IsTruncated?i.NextContinuationToken:void 0}while(o);return r}};import{access as X,mkdir as ct,readFile as ut,readdir as lt,rm as pt,stat as ee,writeFile as dt}from"node:fs/promises";import{dirname as gt,join as mt,relative as te,resolve as ft}from"node:path";var O=class{constructor(e){this.root=e}root;name="local";path(e){let r=e.replace(/^\/+/,"");return ft(this.root,r)}async put(e,r){let o=this.path(e);await ct(gt(o),{recursive:!0}),await dt(o,r)}async get(e){try{return await ut(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 pt(this.path(e),{force:!0})}async list(e=""){let r=this.path(e),o=[];try{await X(r)}catch{return o}let i=async s=>{let l=await lt(s,{withFileTypes:!0});for(let p of l){let d=mt(s,p.name);if(p.isDirectory()){await i(d);continue}let m=await ee(d);o.push({key:te(this.root,d),size:m.size,updatedAt:m.mtime.toISOString()})}},a=await ee(r);return a.isDirectory()?await i(r):o.push({key:te(this.root,r),size:a.size,updatedAt:a.mtime.toISOString()}),o}};import{DeleteObjectCommand as yt,GetObjectCommand as ht,HeadObjectCommand as St,ListObjectsV2Command as kt,PutObjectCommand as Ct,S3Client as At}from"@aws-sdk/client-s3";import{getSignedUrl as Ot}from"@aws-sdk/s3-request-presigner";var x=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 i=typeof r=="string"?Buffer.from(r,"utf8"):r;await this.client.send(new Ct({Bucket:this.bucket,Key:e,Body:i,ContentType:o}))}async get(e){let r=await Ot(this.client,new ht({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 St({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 yt({Bucket:this.bucket,Key:e}))}async list(e=""){let r=[],o;do{let i=await this.client.send(new kt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let a of i.Contents??[])a.Key&&r.push({key:a.Key,size:a.Size,updatedAt:a.LastModified?.toISOString()});o=i.IsTruncated?i.NextContinuationToken:void 0}while(o);return r}};function F(t,e){return console.warn(e),new O(t)}function re(t){let e=t.localRoot??Et(xt(),".toolnet-memory","storage");if(t.provider==="r2"){let r=t.r2;return r?.accountId&&r.bucket&&r.accessKeyId&&r.secretAccessKey?new x({name:"r2",endpoint:`https://${r.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:r.bucket,forcePathStyle:!0,accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey}):F(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 x({name:"s3",endpoint:r.endpoint,region:r.region??"us-east-1",bucket:r.bucket,forcePathStyle:r.forcePathStyle??!1,accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey}):F(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 R({namespace:r.namespace,bucket:r.bucket,accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey}):F(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new O(e)}function bt(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,i=e.maxDelayMs??2e3,a;for(let s=1;s<=r;s++)try{return await t()}catch(l){if(a=l,s>=r)break;let p=Math.min(i,o*2**(s-1)),d=Math.floor(Math.random()*Math.max(1,p*.2));await bt(p+d)}throw a}var vt=new Set(["put","get","getText","delete","list"]);function ne(t,e={}){return new Proxy(t,{get(r,o){let i=Reflect.get(r,o,r);return typeof i!="function"?i:vt.has(o)?(...a)=>oe(()=>Promise.resolve(i.apply(r,a)),e):i.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 i=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return i?`${i[1]}memory/records/${i[2]}`:(i=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),i?`${i[1]}memory/vectors/${i[2]}`:(i=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),i?`${i[1]}code/graph/${i[2]}`:e))}var D=class{constructor(e,r,o,i){this.provider=e;this.name=e.name,this.projectId=r,this.projectName=o,this.folder=ie(i??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,i=await this.provider.getText(e);if(i){let s;try{s=JSON.parse(i)}catch(l){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${l instanceof Error?l.message:String(l)}`)}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 a={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:r};await this.provider.put(e,JSON.stringify(a,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 le,readFileSync as Mt,readdirSync as ce}from"node:fs";import{join as T}from"node:path";import{existsSync as Pt,mkdirSync as Cn,readFileSync as It,renameSync as An,writeFileSync as On}from"node:fs";import{dirname as En,join as _t}from"node:path";function jt(t){return _t(t.rootPath,".toolnet","work","current.json")}function ae(t){let e=jt(t);if(!Pt(e))return null;try{let r=JSON.parse(It(e,"utf8"));return r.version!==1||r.projectId!==t.id?null:r}catch{return null}}function pe(t){if(!le(t))return null;try{return JSON.parse(Mt(t,"utf8"))}catch{return null}}function wt(t){let e=T(t.rootPath,".toolnet","sessions");if(!le(e))return[];let r=[];for(let o of ce(e,{withFileTypes:!0})){if(!o.isDirectory())continue;let i=T(e,o.name);for(let a of ce(i,{withFileTypes:!0})){if(!a.isDirectory())continue;let s=pe(T(i,a.name,"state.json"));!s||s.version!==1||s.projectId!==t.id||r.push(s)}}return r}function ue(t){return t.filter(e=>!!e).sort().at(-1)}function Rt(t){let e=pe(T(t.rootPath,".toolnet","runtime","opencode-status.json"));return!e||e.projectRoot&&e.projectRoot!==t.rootPath?null:e}function de(t){let e=wt(t),o=[...e].sort((u,g)=>(u.lastLocalEventAt??u.updatedAt).localeCompare(g.lastLocalEventAt??g.updatedAt)).at(-1),i=Array.from(new Set(e.map(u=>u.agent))).sort(),a=e.reduce((u,g)=>u+Math.max(0,g.lastSequence-g.lastRemoteSequence),0),s=Rt(t),l=s?.state==="capture-failed",p=s?.state==="sync-failed",d;l?d="degraded":a>0||p?d="pending":e.length>0?d="healthy":d="unknown";let m=ae(t);return{ok:d!=="degraded",agents:i,sessions:e.length,latestAgent:o?.agent,latestSessionId:o?.nativeSessionId,lastCaptureAt:ue(e.map(u=>u.lastLocalEventAt??u.updatedAt)),lastFlushAt:ue(e.map(u=>u.lastRemoteAt)),pendingWal:a,currentTask:m?.currentTask?.title,currentFile:m?.activeFiles?.at(-1)??m?.filesTouched.at(-1),syncHealth:d,opencode:s?{state:s.state,reason:s.reason,timestamp:s.timestamp,error:s.error}:void 0}}import{existsSync as ve}from"node:fs";import{homedir as Qt}from"node:os";import{join as Zt}from"node:path";import{spawnSync as Xt}from"node:child_process";import{homedir as Dt}from"node:os";import{join as $}from"node:path";function ge(t={}){return $(t.home??Dt(),".gemini")}function Tt(t={}){return $(ge(t),"config")}function Lt(t={}){return $(ge(t),"antigravity-cli")}function me(t={}){return[Lt(t),Tt(t)]}import{homedir as Nt}from"node:os";import{join as fe}from"node:path";function ye(t={}){let e=t.xdgConfigHome??process.env.XDG_CONFIG_HOME?.trim();return e?fe(e,"opencode"):fe(t.home??Nt(),".config","opencode")}import{homedir as Kt}from"node:os";import{join as Ut}from"node:path";function he(t={}){return Ut(t.home??Kt(),".claude")}import{homedir as Ft}from"node:os";import{join as E}from"node:path";function B(t={}){return t.kiroHome??process.env.KIRO_HOME??E(t.home??Ft(),".kiro")}function $t(t={}){return E(B(t),"settings")}function Se(t={}){return E($t(t),"mcp.json")}function Bt(t={}){return E(B(t),"hooks")}function ke(t={}){return E(Bt(t),"toolnet-memory.json")}function Ce(t={}){return[B(t)]}import{homedir as Ht}from"node:os";import{join as Ae,resolve as Gn}from"node:path";function Oe(t={}){return t.cursorHome??Ae(t.home??Ht(),".cursor")}function Gt(t={}){return t.cursorConfigDir??process.env.CURSOR_CONFIG_DIR??(t.xdgConfigHome??process.env.XDG_CONFIG_HOME?Ae(t.xdgConfigHome??process.env.XDG_CONFIG_HOME,"cursor"):void 0)??Oe(t)}function xe(t={}){return Array.from(new Set([Oe(t),Gt(t)]))}import{homedir as Vt}from"node:os";import{join as Wt,resolve as zn}from"node:path";function Yt(t={}){return t.copilotHome??process.env.COPILOT_HOME??Wt(t.home??Vt(),".copilot")}function Ee(t={}){return[Yt(t)]}import{homedir as zt}from"node:os";import{join as Jt,resolve as Zn}from"node:path";function qt(t={}){return t.grokHome??process.env.GROK_HOME??Jt(t.home??zt(),".grok")}function be(t={}){return[qt(t)]}function er(t){return Xt("sh",["-lc",`command -v ${JSON.stringify(t)} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}function y(t){let e=t.commandExists(t.command),r=t.configPaths.filter(a=>ve(a)),o=r.length>0,i=[];e&&i.push(`command:${t.command}`);for(let a of r)i.push(`config:${a}`);return{agent:t.agent,detected:e||o,commandDetected:e,configDetected:o,evidence:i}}function tr(t){let e=t.commands.filter(s=>t.commandExists(s)),r=t.configPaths.filter(s=>ve(s)),o=e.length>0,i=r.length>0,a=[...e.map(s=>`command:${s}`),...r.map(s=>`config:${s}`)];return{agent:t.agent,detected:o||i,commandDetected:o,configDetected:i,evidence:a}}function Pe(t={}){let e=t.home??Qt(),r=t.commandExists??er,o=t.codexHome??process.env.CODEX_HOME??Zt(e,".codex");return[y({agent:"agy",command:"agy",commandExists:r,configPaths:me({home:e})}),y({agent:"opencode",command:"opencode",commandExists:r,configPaths:[ye({home:e,xdgConfigHome:t.xdgConfigHome})]}),y({agent:"claude",command:"claude",commandExists:r,configPaths:[he({home:e})]}),y({agent:"kiro",command:"kiro-cli",commandExists:r,configPaths:Ce({home:e,kiroHome:t.kiroHome})}),tr({agent:"cursor",commands:["agent","cursor-agent"],commandExists:r,configPaths:xe({home:e,cursorHome:t.cursorHome,cursorConfigDir:t.cursorConfigDir,xdgConfigHome:t.xdgConfigHome})}),y({agent:"copilot",command:"copilot",commandExists:r,configPaths:Ee({home:e,copilotHome:t.copilotHome})}),y({agent:"grok",command:"grok",commandExists:r,configPaths:be({home:e,grokHome:t.grokHome})}),y({agent:"codex",command:"codex",commandExists:r,configPaths:[o]})]}import{existsSync as H,readFileSync as rr}from"node:fs";var or="ToolNet Memory - ",nr=["SessionStart","UserPromptSubmit","PreToolUse","PostToolUse","Stop"];function h(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function Ie(t){if(!H(t))return{};let e;try{e=JSON.parse(rr(t,"utf8"))}catch(r){return{error:r instanceof Error?r.message:String(r)}}return h(e)?{value:e}:{error:"root must be a JSON object"}}function ir(t){if(!t||!h(t.mcpServers))return!1;let e=t.mcpServers["toolnet-memory"];return h(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 sr(t){if(!(!h(t)||!h(t.action)))return typeof t.action.command=="string"?t.action.command:void 0}function ar(t){if(!t||t.version!=="v1"||!Array.isArray(t.hooks))return[];let e=new Set;for(let r of t.hooks){if(!h(r)||typeof r.name!="string"||!r.name.startsWith(or))continue;let o=sr(r);!o||!o.includes("session:kiro-hook")||r.enabled!==!1&&typeof r.trigger=="string"&&e.add(r.trigger)}return[...e]}function _e(t={}){let e=t.configFile??Se(),r=t.hooksFile??ke(),o=Ie(e),i=Ie(r),a=!o.error&&ir(o.value),s=i.error?[]:ar(i.value),l=nr.every(g=>s.includes(g)),p=[];o.error&&p.push(`MCP config: ${o.error}`),i.error&&p.push(`Hooks config: ${i.error}`);let d=a&&l,m=H(e)||H(r),u=p.length>0?"invalid":d?"ready":m?"partial":"not-installed";return{installed:d,state:u,mcp:{configured:a,configFile:e,error:o.error},hooks:{configured:l,hooksFile:r,triggers:s,error:i.error},errors:p}}var cr={spinner:["\xB7","\u2722","\u2733","\u2736","\u273B","\u273D"],barFilled:"\u2588",barEmpty:"\u2591",phaseDone:"\u25C6",phaseActive:"\u25C7",rail:"\u2502",branch:"\u251C",corner:"\u2514",dash:"\u2014"},ur={spinner:[".","*","+","x","*","+"],barFilled:"#",barEmpty:"-",phaseDone:"[OK]",phaseActive:"[>>]",rail:"|",branch:"|",corner:"\\",dash:"-"};function lr(){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 G;function je(){return G||(G=lr()?cr:ur),G}var S={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 pr(t){return t.noColor||process.env.NO_COLOR?!1:t.tty??process.stdout.isTTY??!1}function b(t,e,r){return pr(r)?`${e}${t}${S.reset}`:t}function L(t,e){return b(t,S.dim,e)}function dr(t,e){return b(t,S.bold,e)}function gr(t,e){return b(t,S.cyan,e)}function mr(t,e){return b(t,S.red,e)}function fr(t,e){return b(t,S.white,e)}function Me(t,e,r){let o=je(),i=e?` ${L(`v${e}`,r)}`:"";return`${gr(o.phaseDone,r)} ${t}${i}`}function v(t,e){return dr(t,e)}function f(t,e,r,o){let i=" ".repeat(Math.max(0,r-t.length));return` ${L(t,o)}${i} ${fr(e,o)}`}function we(t){return mr("\u2717",t)}function yr(t){return{tty:t.tty,noColor:t.noColor}}async function hr(t){let e=yr(t);console.log(""),console.log(Me("ToolNet Status",void 0,e)),console.log("");try{let r=new _().detect(),o=V(),i=Z();console.log(v("PROJECT",e)),console.log(f("Name",r.name,8,e));let a=ne(re({provider:o.storage.provider,r2:o.storage.r2,s3:o.storage.s3,huggingface:o.storage.huggingface,localRoot:o.storage.localRoot}),{attempts:3}),s=new D(a,r.id,r.name,r.remote??r.name),l="unknown",p="unknown";try{l=await s.exists(`${r.id}/memory.json`)?"ready":"not initialized"}catch{l="error"}try{p=await s.exists(`${r.id}/code-graph.json`)?"ready":"not built"}catch{p="error"}console.log(f("Memory",l,8,e)),console.log(f("Index",p,8,e)),console.log(""),console.log(v("AI",e)),console.log(f("Provider",i.llm.provider,8,e)),console.log(f("Model",i.llm.model??"not set",8,e)),console.log("");let d=Pe(),m=d.filter(g=>g.detected).map(g=>g.agent);if(m.length>0){if(console.log(v("INTEGRATIONS",e)),console.log(f("Detected",m.join(", "),8,e)),d.find(P=>P.agent==="kiro")?.detected){let P=_e();console.log(f("Kiro",P.installed?"ready":P.state,8,e))}console.log("")}let u=de(r);if(u.agents.length>0){console.log(v("SERVICE",e));let g=u.syncHealth==="healthy"?"running":u.syncHealth==="degraded"?"degraded":"stopped";console.log(f("Daemon",g,8,e)),console.log("")}}catch(r){console.log(we(e)+" Failed to get status"),console.log(""),console.log(L(` ${r instanceof Error?r.message:String(r)}`,e)),console.log(""),process.exitCode=1}}async function Sr(){let t=process.argv.slice(2),e={tty:process.stdout.isTTY,noColor:process.env.NO_COLOR!==void 0||t.includes("--no-color")};await hr(e)}Sr().catch(t=>{console.error(""),console.error(t instanceof Error?t.message:String(t)),console.error(""),process.exitCode=1});
1
+ import{existsSync as Me,readFileSync as Ee}from"node:fs";import{homedir as Te}from"node:os";import{join as De}from"node:path";function _e(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 Ke(){let t=process.env.TOOLNET_GLOBAL_ENV??De(Te(),".config","toolnet-memory",".env");if(!Me(t))return;let e=Ee(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]=_e(o.slice(n+1)))}}Ke();function h(t,e){return t===void 0?e:["1","true","yes","on"].includes(t.toLowerCase())}function k(t,e){if(!t)return e;let r=Number(t);return Number.isFinite(r)?r:e}function G(){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:k(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:k(process.env.MEMORY_RERANK_TOP,10),finalContext:k(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:k(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:k(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Ne}from"node:crypto";import{existsSync as E,mkdirSync as Fe,readFileSync as $e,renameSync as He,writeFileSync as Le}from"node:fs";import{basename as Ge,dirname as P,join as w,parse as W,resolve as x}from"node:path";var V=".toolnet",Ue="project.json";function ze(t){return Ne("sha256").update(t).digest("hex").slice(0,16)}function T(t){return w(t,V,Ue)}function We(t){return E(T(t))}function Ve(t,e){let r=x(t),o=W(r).root;for(;;){if(We(r))return r;if(r===o||e&&r===x(e))break;let n=P(r);if(n===r)break;r=n}return null}function Be(t){let e=x(t),r=W(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>E(w(e,i))))return e;if(e===r)break;let n=P(e);if(n===e)break;e=n}return x(t)}function Je(t){let e;try{e=JSON.parse($e(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:P(P(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 U(t,e){let r=w(t,V);Fe(r,{recursive:!0});let o=T(t),n=`${o}.tmp-${process.pid}`;Le(n,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),He(n,o)}function z(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 j=class{detect(e=process.cwd()){let r=x(e),o=Be(r),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(l=>E(w(o,l))),s=Ve(r,i?o:void 0);if(s){let l=T(s),a=Je(l);return a.rootPath!==s&&(a.rootPath=s,a.updatedAt=new Date().toISOString(),U(s,a)),z(a,s)}let u=new Date().toISOString(),p=Ge(o),c={version:1,id:ze(o),name:p,remote:p,rootPath:o,createdAt:u,updatedAt:u,graphVersion:0,memoryVersion:0};return U(o,c),z(c,o)}};import{homedir as ht}from"node:os";import{join as kt}from"node:path";import{DeleteObjectCommand as Ye,GetObjectCommand as Qe,HeadObjectCommand as Ze,ListObjectsV2Command as Xe,PutObjectCommand as qe,S3Client as et}from"@aws-sdk/client-s3";import{getSignedUrl as tt}from"@aws-sdk/s3-request-presigner";var O=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new et({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 qe({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let r=await tt(this.client,new Qe({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 Ze({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 Ye({Bucket:this.bucket,Key:e}))}async list(e=""){let r=[],o;do{let n=await this.client.send(new Xe({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 B,mkdir as rt,readFile as ot,readdir as nt,rm as st,stat as J,writeFile as it}from"node:fs/promises";import{dirname as at,join as ct,relative as Y,resolve as ut}from"node:path";var C=class{constructor(e){this.root=e}root;name="local";path(e){let r=e.replace(/^\/+/,"");return ut(this.root,r)}async put(e,r){let o=this.path(e);await rt(at(o),{recursive:!0}),await it(o,r)}async get(e){try{return await ot(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 B(this.path(e)),!0}catch{return!1}}async delete(e){await st(this.path(e),{force:!0})}async list(e=""){let r=this.path(e),o=[];try{await B(r)}catch{return o}let n=async s=>{let u=await nt(s,{withFileTypes:!0});for(let p of u){let c=ct(s,p.name);if(p.isDirectory()){await n(c);continue}let l=await J(c);o.push({key:Y(this.root,c),size:l.size,updatedAt:l.mtime.toISOString()})}},i=await J(r);return i.isDirectory()?await n(r):o.push({key:Y(this.root,r),size:i.size,updatedAt:i.mtime.toISOString()}),o}};import{DeleteObjectCommand as pt,GetObjectCommand as lt,HeadObjectCommand as gt,ListObjectsV2Command as dt,PutObjectCommand as mt,S3Client as ft}from"@aws-sdk/client-s3";import{getSignedUrl as yt}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 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,r,o="application/octet-stream"){let n=typeof r=="string"?Buffer.from(r,"utf8"):r;await this.client.send(new mt({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let r=await yt(this.client,new lt({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 gt({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 pt({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}};function D(t,e){return console.warn(e),new C(t)}function Q(t){let e=t.localRoot??kt(ht(),".toolnet-memory","storage");if(t.provider==="r2"){let r=t.r2;return r?.accountId&&r.bucket&&r.accessKeyId&&r.secretAccessKey?new S({name:"r2",endpoint:`https://${r.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:r.bucket,forcePathStyle:!0,accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey}):D(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 S({name:"s3",endpoint:r.endpoint,region:r.region??"us-east-1",bucket:r.bucket,forcePathStyle:r.forcePathStyle??!1,accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey}):D(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 O({namespace:r.namespace,bucket:r.bucket,accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey}):D(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new C(e)}function xt(t){return new Promise(e=>setTimeout(e,t))}async function Z(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(u){if(i=u,s>=r)break;let p=Math.min(n,o*2**(s-1)),c=Math.floor(Math.random()*Math.max(1,p*.2));await xt(p+c)}throw i}var Ct=new Set(["put","get","getText","delete","list"]);function X(t,e={}){return new Proxy(t,{get(r,o){let n=Reflect.get(r,o,r);return typeof n!="function"?n:Ct.has(o)?(...i)=>Z(()=>Promise.resolve(n.apply(r,i)),e):n.bind(r)}})}function q(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 ee(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 A=class{constructor(e,r,o,n){this.provider=e;this.name=e.name,this.projectId=r,this.projectName=o,this.folder=q(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(u){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${u instanceof Error?u.message:String(u)}`)}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=ee(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 ne,readFileSync as jt,readdirSync as re}from"node:fs";import{join as I}from"node:path";import{existsSync as St,mkdirSync as fn,readFileSync as bt,renameSync as yn,writeFileSync as hn}from"node:fs";import{dirname as xn,join as vt}from"node:path";function Pt(t){return vt(t.rootPath,".toolnet","work","current.json")}function te(t){let e=Pt(t);if(!St(e))return null;try{let r=JSON.parse(bt(e,"utf8"));return r.version!==1||r.projectId!==t.id?null:r}catch{return null}}function se(t){if(!ne(t))return null;try{return JSON.parse(jt(t,"utf8"))}catch{return null}}function wt(t){let e=I(t.rootPath,".toolnet","sessions");if(!ne(e))return[];let r=[];for(let o of re(e,{withFileTypes:!0})){if(!o.isDirectory())continue;let n=I(e,o.name);for(let i of re(n,{withFileTypes:!0})){if(!i.isDirectory())continue;let s=se(I(n,i.name,"state.json"));!s||s.version!==1||s.projectId!==t.id||r.push(s)}}return r}function oe(t){return t.filter(e=>!!e).sort().at(-1)}function Ot(t){let e=se(I(t.rootPath,".toolnet","runtime","opencode-status.json"));return!e||e.projectRoot&&e.projectRoot!==t.rootPath?null:e}function ie(t){let e=wt(t),o=[...e].sort((a,g)=>(a.lastLocalEventAt??a.updatedAt).localeCompare(g.lastLocalEventAt??g.updatedAt)).at(-1),n=Array.from(new Set(e.map(a=>a.agent))).sort(),i=e.reduce((a,g)=>a+Math.max(0,g.lastSequence-g.lastRemoteSequence),0),s=Ot(t),u=s?.state==="capture-failed",p=s?.state==="sync-failed",c;u?c="degraded":i>0||p?c="pending":e.length>0?c="healthy":c="unknown";let l=te(t);return{ok:c!=="degraded",agents:n,sessions:e.length,latestAgent:o?.agent,latestSessionId:o?.nativeSessionId,lastCaptureAt:oe(e.map(a=>a.lastLocalEventAt??a.updatedAt)),lastFlushAt:oe(e.map(a=>a.lastRemoteAt)),pendingWal:i,currentTask:l?.currentTask?.title,currentFile:l?.activeFiles?.at(-1)??l?.filesTouched.at(-1),syncHealth:c,opencode:s?{state:s.state,reason:s.reason,timestamp:s.timestamp,error:s.error}:void 0}}import{existsSync as Pe}from"node:fs";import{homedir as Qt}from"node:os";import{join as Zt}from"node:path";import{spawnSync as Xt}from"node:child_process";import{homedir as At}from"node:os";import{join as _}from"node:path";function ae(t={}){return _(t.home??At(),".gemini")}function It(t={}){return _(ae(t),"config")}function Rt(t={}){return _(ae(t),"antigravity-cli")}function ce(t={}){return[Rt(t),It(t)]}import{homedir as Mt}from"node:os";import{join as ue}from"node:path";function pe(t={}){let e=t.xdgConfigHome??process.env.XDG_CONFIG_HOME?.trim();return e?ue(e,"opencode"):ue(t.home??Mt(),".config","opencode")}import{homedir as Et}from"node:os";import{join as Tt}from"node:path";function le(t={}){return Tt(t.home??Et(),".claude")}import{homedir as Dt}from"node:os";import{join as b}from"node:path";function K(t={}){return t.kiroHome??process.env.KIRO_HOME??b(t.home??Dt(),".kiro")}function _t(t={}){return b(K(t),"settings")}function ge(t={}){return b(_t(t),"mcp.json")}function Kt(t={}){return b(K(t),"hooks")}function de(t={}){return b(Kt(t),"toolnet-memory.json")}function me(t={}){return[K(t)]}import{homedir as Nt}from"node:os";import{join as N}from"node:path";function fe(t={}){let e=t.home??Nt(),r=t.xdgConfigHome??process.env.XDG_CONFIG_HOME;return r?N(r,"toolnet-memory"):N(e,".config","toolnet-memory")}function Ft(t={}){return N(fe(t),"mcp.json")}function ye(t={}){return[fe(t),Ft(t)]}import{homedir as $t}from"node:os";import{join as F}from"node:path";function $(t={}){return t.kiloHome??process.env.KILO_HOME??F(t.home??$t(),".kilo")}function Ht(t={}){return F($(t),"kilo.jsonc")}function Lt(t={}){return F($(t),"mcp.json")}function he(t={}){return[$(t),Lt(t),Ht(t)]}import{homedir as Gt}from"node:os";import{join as ke,resolve as Wn}from"node:path";function xe(t={}){return t.cursorHome??ke(t.home??Gt(),".cursor")}function Ut(t={}){return t.cursorConfigDir??process.env.CURSOR_CONFIG_DIR??(t.xdgConfigHome??process.env.XDG_CONFIG_HOME?ke(t.xdgConfigHome??process.env.XDG_CONFIG_HOME,"cursor"):void 0)??xe(t)}function Ce(t={}){return Array.from(new Set([xe(t),Ut(t)]))}import{homedir as zt}from"node:os";import{join as Wt,resolve as Yn}from"node:path";function Vt(t={}){return t.copilotHome??process.env.COPILOT_HOME??Wt(t.home??zt(),".copilot")}function Se(t={}){return[Vt(t)]}import{homedir as Bt}from"node:os";import{join as Jt,resolve as qn}from"node:path";function Yt(t={}){return t.grokHome??process.env.GROK_HOME??Jt(t.home??Bt(),".grok")}function be(t={}){return[Yt(t)]}function qt(t){return Xt("sh",["-lc",`command -v ${JSON.stringify(t)} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}function d(t){let e=t.commandExists(t.command),r=t.configPaths.filter(i=>Pe(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 ve(t){let e=t.commands.filter(s=>t.commandExists(s)),r=t.configPaths.filter(s=>Pe(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 je(t={}){let e=t.home??Qt(),r=t.commandExists??qt,o=t.codexHome??process.env.CODEX_HOME??Zt(e,".codex");return[d({agent:"agy",command:"agy",commandExists:r,configPaths:ce({home:e})}),d({agent:"opencode",command:"opencode",commandExists:r,configPaths:[pe({home:e,xdgConfigHome:t.xdgConfigHome})]}),d({agent:"claude",command:"claude",commandExists:r,configPaths:[le({home:e})]}),d({agent:"kiro",command:"kiro-cli",commandExists:r,configPaths:me({home:e,kiroHome:t.kiroHome})}),ve({agent:"cursor",commands:["agent","cursor-agent"],commandExists:r,configPaths:Ce({home:e,cursorHome:t.cursorHome,cursorConfigDir:t.cursorConfigDir,xdgConfigHome:t.xdgConfigHome})}),d({agent:"copilot",command:"copilot",commandExists:r,configPaths:Se({home:e,copilotHome:t.copilotHome})}),d({agent:"grok",command:"grok",commandExists:r,configPaths:be({home:e,grokHome:t.grokHome})}),d({agent:"toolnet-cli",command:"toolnet-memory",commandExists:r,configPaths:ye({home:e,xdgConfigHome:t.xdgConfigHome})}),ve({agent:"kilo",commands:["kilo","kilo-code"],commandExists:r,configPaths:he({home:e,kiloHome:t.kiloHome})}),d({agent:"codex",command:"codex",commandExists:r,configPaths:[o]})]}import{existsSync as H,readFileSync as er}from"node:fs";var tr="ToolNet Memory - ",rr=["SessionStart","UserPromptSubmit","PreToolUse","PostToolUse","Stop"];function f(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function we(t){if(!H(t))return{};let e;try{e=JSON.parse(er(t,"utf8"))}catch(r){return{error:r instanceof Error?r.message:String(r)}}return f(e)?{value:e}:{error:"root must be a JSON object"}}function or(t){if(!t||!f(t.mcpServers))return!1;let e=t.mcpServers["toolnet-memory"];return f(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 nr(t){if(!(!f(t)||!f(t.action)))return typeof t.action.command=="string"?t.action.command:void 0}function sr(t){if(!t||t.version!=="v1"||!Array.isArray(t.hooks))return[];let e=new Set;for(let r of t.hooks){if(!f(r)||typeof r.name!="string"||!r.name.startsWith(tr))continue;let o=nr(r);!o||!o.includes("session:kiro-hook")||r.enabled!==!1&&typeof r.trigger=="string"&&e.add(r.trigger)}return[...e]}function Oe(t={}){let e=t.configFile??ge(),r=t.hooksFile??de(),o=we(e),n=we(r),i=!o.error&&or(o.value),s=n.error?[]:sr(n.value),u=rr.every(g=>s.includes(g)),p=[];o.error&&p.push(`MCP config: ${o.error}`),n.error&&p.push(`Hooks config: ${n.error}`);let c=i&&u,l=H(e)||H(r),a=p.length>0?"invalid":c?"ready":l?"partial":"not-installed";return{installed:c,state:a,mcp:{configured:i,configFile:e,error:o.error},hooks:{configured:u,hooksFile:r,triggers:s,error:n.error},errors:p}}var ir={spinner:["\xB7","\u2722","\u2733","\u2736","\u273B","\u273D"],barFilled:"\u2588",barEmpty:"\u2591",phaseDone:"\u25C6",phaseActive:"\u25C7",rail:"\u2502",branch:"\u251C",corner:"\u2514",dash:"\u2014"},ar={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 L;function Ae(){return L||(L=cr()?ir:ar),L}var y={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 ur(t){return t.noColor||process.env.NO_COLOR?!1:t.tty??process.stdout.isTTY??!1}function v(t,e,r){return ur(r)?`${e}${t}${y.reset}`:t}function R(t,e){return v(t,y.dim,e)}function pr(t,e){return v(t,y.bold,e)}function lr(t,e){return v(t,y.cyan,e)}function gr(t,e){return v(t,y.red,e)}function dr(t,e){return v(t,y.white,e)}function Ie(t,e,r){let o=Ae(),n=e?` ${R(`v${e}`,r)}`:"";return`${lr(o.phaseDone,r)} ${t}${n}`}function M(t,e){return pr(t,e)}function m(t,e,r,o){let n=" ".repeat(Math.max(0,r-t.length));return` ${R(t,o)}${n} ${dr(e,o)}`}function Re(t){return gr("\u2717",t)}function mr(t){return{tty:t.tty,noColor:t.noColor}}async function fr(t){let e=mr(t);console.log(""),console.log(Ie("ToolNet Status",void 0,e)),console.log("");try{let r=new j().detect(),o=G();console.log(M("PROJECT",e)),console.log(m("Name",r.name,8,e));let n=X(Q({provider:o.storage.provider,r2:o.storage.r2,s3:o.storage.s3,huggingface:o.storage.huggingface,localRoot:o.storage.localRoot}),{attempts:3}),i=new A(n,r.id,r.name,r.remote??r.name),s="unknown",u="unknown";try{s=await i.exists(`${r.id}/memory.json`)?"ready":"not initialized"}catch{s="error"}try{u=await i.exists(`${r.id}/code-graph.json`)?"ready":"not built"}catch{u="error"}console.log(m("Memory",s,8,e)),console.log(m("Index",u,8,e)),console.log("");let p=je(),c=p.filter(a=>a.detected).map(a=>a.agent);if(c.length>0){if(console.log(M("INTEGRATIONS",e)),console.log(m("Detected",c.join(", "),8,e)),p.find(g=>g.agent==="kiro")?.detected){let g=Oe();console.log(m("Kiro",g.installed?"ready":g.state,8,e))}console.log("")}let l=ie(r);if(l.agents.length>0){console.log(M("SERVICE",e));let a=l.syncHealth==="healthy"?"running":l.syncHealth==="degraded"?"degraded":"stopped";console.log(m("Daemon",a,8,e)),console.log("")}}catch(r){console.log(Re(e)+" Failed to get status"),console.log(""),console.log(R(` ${r instanceof Error?r.message:String(r)}`,e)),console.log(""),process.exitCode=1}}async function yr(){let t=process.argv.slice(2),e={tty:process.stdout.isTTY,noColor:process.env.NO_COLOR!==void 0||t.includes("--no-color")};await fr(e)}yr().catch(t=>{console.error(""),console.error(t instanceof Error?t.message:String(t)),console.error(""),process.exitCode=1});
@@ -0,0 +1,2 @@
1
+ import{existsSync as C,mkdirSync as y,readFileSync as N,renameSync as S,rmSync as T,writeFileSync as h}from"node:fs";import{dirname as I}from"node:path";import{homedir as d}from"node:os";import{join as a}from"node:path";function g(o={}){let n=o.home??d(),t=o.xdgConfigHome??process.env.XDG_CONFIG_HOME;return t?a(t,"toolnet-memory"):a(n,".config","toolnet-memory")}function s(o={}){return a(g(o),"mcp.json")}function f(o){return typeof o=="object"&&o!==null&&!Array.isArray(o)}function b(o){if(!C(o))return{};let n=N(o,"utf8").trim();if(!n)return{};let t;try{t=JSON.parse(n)}catch(e){throw new Error(`Invalid existing ToolNet CLI MCP config: ${e instanceof Error?e.message:String(e)}`)}if(!f(t))throw new Error("Invalid existing ToolNet CLI MCP config: root must be a JSON object.");return t}function x(o,n){y(I(o),{recursive:!0,mode:448});let t=`${o}.tmp-${process.pid}-${Date.now()}`;try{h(t,`${JSON.stringify(n,null,2)}
2
+ `,{encoding:"utf8",mode:384}),S(t,o)}finally{T(t,{force:!0})}}function u(o={}){let n=o.binary??"toolnet-memory",t=o.configFile??s(),e=b(t),i="toolnet-memory";if(f(e.mcpServers)&&e.mcpServers[i]!=null&&!o.force)return{installed:!0,changed:!1,configFile:t};let r=f(e.mcpServers)?e.mcpServers:{};return r[i]={command:n,args:["mcp"]},e.mcpServers=r,x(t,e),{installed:!0,changed:!0,configFile:t}}function m(o={}){let n=o.binary??"toolnet-memory",t=u({binary:n,configFile:o.configFile,force:o.force});return{installed:t.installed,changed:t.changed,mcp:{...t,configured:t.installed},files:[t.configFile]}}import{existsSync as p}from"node:fs";function c(){let o=g(),n=s(),t=p(o),e=p(n),i=[];return t||i.push(`Config directory missing: ${o}`),{installed:t,state:t?"installed":"missing-config",mcp:{configured:e,configFile:n},errors:i}}function O(){let o=c();console.log("ToolNet CLI Integration"),console.log("======================="),console.log(""),console.log(`State : ${o.state}`),console.log(`MCP : ${o.mcp.configured?"ready":"missing"} \u2014 ${o.mcp.configFile}`);for(let n of o.errors)console.log(`Error : ${n}`);return console.log(""),o.installed}function F(){let o=process.argv.slice(2),n=o.includes("--json");if(o.includes("--status")||o[0]==="status"){let r=c();n?console.log(JSON.stringify(r,null,2)):O(),r.installed||(process.exitCode=1);return}let e=o.includes("--force"),i=m({force:e}),l=c();if(!l.installed)throw new Error(`ToolNet CLI integration installation did not verify successfully (state=${l.state}).`);if(n){console.log(JSON.stringify({installed:!0,changed:i.changed,files:i.files,status:l},null,2));return}console.log(`ToolNet CLI MCP: ${i.mcp.configured?"configured":"not configured"}`),i.changed?console.log(`Config updated: ${i.mcp.configFile}`):console.log("Config unchanged (already configured)"),console.log(""),console.log("ToolNet CLI integration ready.")}F();
@@ -1,9 +1,9 @@
1
1
  import{existsSync as ye,readFileSync as he}from"node:fs";import{homedir as ke}from"node:os";import{join as Se}from"node:path";function we(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 ve(){let r=process.env.TOOLNET_GLOBAL_ENV??Se(ke(),".config","toolnet-memory",".env");if(!ye(r))return;let e=he(r,"utf8");for(let t of e.split(/\r?\n/)){let s=t.trim();if(!s||s.startsWith("#"))continue;s.startsWith("export ")&&(s=s.slice(7));let n=s.indexOf("=");if(n<=0)continue;let i=s.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=we(s.slice(n+1)))}}ve();function h(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function k(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function Y(){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:k(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:k(process.env.MEMORY_RERANK_TOP,10),finalContext:k(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:k(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:k(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as be}from"node:crypto";import{existsSync as T,mkdirSync as je,readFileSync as xe,renameSync as Ae,writeFileSync as Pe}from"node:fs";import{basename as Re,dirname as j,join as A,parse as Z,resolve as S}from"node:path";var q=".toolnet",Me="project.json";function Ce(r){return be("sha256").update(r).digest("hex").slice(0,16)}function E(r){return A(r,q,Me)}function Ie(r){return T(E(r))}function Te(r,e){let t=S(r),s=Z(t).root;for(;;){if(Ie(t))return t;if(t===s||e&&t===S(e))break;let n=j(t);if(n===t)break;t=n}return null}function Ee(r){let e=S(r),t=Z(e).root,s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(s.some(i=>T(A(e,i))))return e;if(e===t)break;let n=j(e);if(n===e)break;e=n}return S(r)}function Oe(r){let e;try{e=JSON.parse(xe(r,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${r}: ${n instanceof Error?n.message:String(n)}`)}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 s=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:j(j(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:s,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:s,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function G(r,e){let t=A(r,q);je(t,{recursive:!0});let s=E(r),n=`${s}.tmp-${process.pid}`;Pe(n,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),Ae(n,s)}function Q(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}}var x=class{detect(e=process.cwd()){let t=S(e),s=Ee(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>T(A(s,m))),a=Te(t,i?s:void 0);if(a){let m=E(a),f=Oe(m);return f.rootPath!==a&&(f.rootPath=a,f.updatedAt=new Date().toISOString(),G(a,f)),Q(f,a)}let c=new Date().toISOString(),p=Re(s),d={version:1,id:Ce(s),name:p,remote:p,rootPath:s,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return G(s,d),Q(d,s)}};import{homedir as rt}from"node:os";import{join as st}from"node:path";import{DeleteObjectCommand as _e,GetObjectCommand as Ne,HeadObjectCommand as $e,ListObjectsV2Command as Ke,PutObjectCommand as De,S3Client as Le}from"@aws-sdk/client-s3";import{getSignedUrl as ze}from"@aws-sdk/s3-request-presigner";var P=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Le({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,s="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new De({Bucket:this.bucket,Key:e,Body:n,ContentType:s}))}async get(e){let t=await ze(this.client,new Ne({Bucket:this.bucket,Key:e}),{expiresIn:60}),s=await fetch(t,{redirect:"follow"});if(s.status===404)return null;if(!s.ok)throw new Error(`HF download failed: ${s.status} ${s.statusText}`);return new Uint8Array(await s.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 _e({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],s;do{let n=await this.client.send(new Ke({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:s}));for(let i of n.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});s=n.IsTruncated?n.NextContinuationToken:void 0}while(s);return t}};import{access as X,mkdir as Be,readFile as Fe,readdir as We,rm as Ve,stat as ee,writeFile as Je}from"node:fs/promises";import{dirname as Ue,join as He,relative as te,resolve as Ye}from"node:path";var w=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Ye(this.root,t)}async put(e,t){let s=this.path(e);await Be(Ue(s),{recursive:!0}),await Je(s,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 X(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),s=[];try{await X(t)}catch{return s}let n=async a=>{let c=await We(a,{withFileTypes:!0});for(let p of c){let d=He(a,p.name);if(p.isDirectory()){await n(d);continue}let m=await ee(d);s.push({key:te(this.root,d),size:m.size,updatedAt:m.mtime.toISOString()})}},i=await ee(t);return i.isDirectory()?await n(t):s.push({key:te(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),s}};import{DeleteObjectCommand as Ge,GetObjectCommand as Qe,HeadObjectCommand as Ze,ListObjectsV2Command as qe,PutObjectCommand as Xe,S3Client as et}from"@aws-sdk/client-s3";import{getSignedUrl as tt}from"@aws-sdk/s3-request-presigner";var v=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new et({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,s="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Xe({Bucket:this.bucket,Key:e,Body:n,ContentType:s}))}async get(e){let t=await tt(this.client,new Qe({Bucket:this.bucket,Key:e}),{expiresIn:60}),s=await fetch(t,{redirect:"follow"});if(s.status===404)return null;if(!s.ok)throw new Error(`${this.name} download failed: ${s.status} ${s.statusText}`);return new Uint8Array(await s.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 Ze({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=[],s;do{let n=await this.client.send(new qe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:s}));for(let i of n.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});s=n.IsTruncated?n.NextContinuationToken:void 0}while(s);return t}};function O(r,e){return console.warn(e),new w(r)}function re(r){let e=r.localRoot??st(rt(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new v({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):O(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 v({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):O(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 P({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):O(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new w(e)}function ot(r){return new Promise(e=>setTimeout(e,r))}async function se(r,e={}){let t=Math.max(1,e.attempts??3),s=e.baseDelayMs??150,n=e.maxDelayMs??2e3,i;for(let a=1;a<=t;a++)try{return await r()}catch(c){if(i=c,a>=t)break;let p=Math.min(n,s*2**(a-1)),d=Math.floor(Math.random()*Math.max(1,p*.2));await ot(p+d)}throw i}var nt=new Set(["put","get","getText","delete","list"]);function oe(r,e={}){return new Proxy(r,{get(t,s){let n=Reflect.get(t,s,t);return typeof n!="function"?n:nt.has(s)?(...i)=>se(()=>Promise.resolve(n.apply(t,i)),e):n.bind(t)}})}function ne(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 ie(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 s=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(s)return`${s[1]}memory/records/${s[2]}`;if(s=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),s)return`${s[1]}memory/vectors/${s[2]}`;if(s=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),s)return`${s[1]}code/graph/${s[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 R=class{constructor(e,t,s,n){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=s,this.folder=ne(n??s),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(),s=t,n=await this.provider.getText(e);if(n){let a;try{a=JSON.parse(n)}catch(c){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${c instanceof Error?c.message:String(c)}`)}if(typeof a.id=="string"&&a.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${a.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof a.createdAt=="string"&&(s=a.createdAt)}let i={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:s,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=ie(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,s){return await this.ensureRegistered(),this.provider.put(this.key(e),t,s)}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{join as ue}from"node:path";import{mkdirSync as dt}from"node:fs";import{createHash as it}from"node:crypto";import{dirname as at}from"node:path";import{mkdirSync as ct,readFileSync as ys,renameSync as ut,writeFileSync as pt}from"node:fs";function ae(r){return it("sha256").update(r).digest("hex")}function ce(r,e){ct(at(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;pt(t,JSON.stringify(e,null,2)+`
5
- `,{encoding:"utf8",mode:384}),ut(t,r)}function de(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function l(r,e=20){let t=[],s=new Set;for(let n of r.slice().reverse()){let i=de(n);if(!(!i||s.has(i))&&(s.add(i),t.push(n),t.length>=e))break}return t.reverse()}function lt(r,e=20){let t=new Map;for(let s of r){let n=`${s.kind}|${de(s.command)}`;t.delete(n),t.set(n,s)}return Array.from(t.values()).slice(-e)}function mt(r){return r.kind==="phase"?/^Phase\s+\d+$/iu.test(r.text):r.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(r.text):!1}function pe(r,e){let t=e.status??r?.status??"pending",s=t;r&&(r.status==="completed"&&t!=="completed"?s="completed":t==="pending"&&(r.status==="in_progress"||r.status==="blocked")&&(s=r.status));let n=r&&mt(e)?r.title:e.text;return{id:r?.id??ae(e.key).slice(0,24),title:n,status:s,order:e.order??r?.order,confidence:Math.max(e.confidence,r?.confidence??0),updatedAt:e.occurredAt,updatedBy:{agent:e.agent,nativeSessionId:e.nativeSessionId,eventId:e.eventId}}}async function gt(r,e){let t=`projects/${r.id}/work/observations/`,s=await e.list(t),n=[];for(let i of s.filter(a=>a.key.endsWith(".json")).sort((a,c)=>a.key.localeCompare(c.key))){let a=await e.getText(i.key);if(a)try{let c=JSON.parse(a);c.version===1&&Array.isArray(c.observations)&&n.push(c)}catch{}}return n}async function le(r,e){let s=(await gt(r,e)).flatMap(o=>o.observations).sort((o,u)=>{let U=o.occurredAt.localeCompare(u.occurredAt);if(U!==0)return U;let H=o.sequence-u.sequence;return H!==0?H:o.id.localeCompare(u.id)}),n=new Map,i=new Map,a,c,p,d,m,f=[],N=[],$=[],K=[],D=[],M=new Map,L=[],z=[],B=[],F=[],W=[],V=[];for(let o of s)switch(o.kind){case"request":a=o.text;break;case"activity":c=o.text;break;case"goal":p=o.text;break;case"plan":d=o.text;break;case"phase":n.set(o.key,pe(n.get(o.key),o));break;case"task":i.set(o.key,pe(i.get(o.key),o));break;case"decision":f.push(o.text);break;case"blocker":N.push(o.text);break;case"warning":$.push(o.text);break;case"next_action":K.push(o.text);break;case"file":{D.push(o.text);let u=o.fileAction??"active";M.delete(o.text),M.set(o.text,u),u==="modified"?L.push(o.text):u==="created"?z.push(o.text):u==="deleted"&&B.push(o.text);break}case"command":F.push(o.text);break;case"test":W.push(o.text),o.checkKind&&V.push({kind:o.checkKind,command:o.text,status:o.checkStatus??"unknown",updatedAt:o.occurredAt,agent:o.agent,nativeSessionId:o.nativeSessionId});break;case"session":m={agent:o.agent,nativeSessionId:o.nativeSessionId,sessionKey:o.sessionKey,updatedAt:o.occurredAt};break}let y=Array.from(n.values()).sort((o,u)=>(o.order??Number.MAX_SAFE_INTEGER)-(u.order??Number.MAX_SAFE_INTEGER)),g=Array.from(i.values()).sort((o,u)=>(o.order??Number.MAX_SAFE_INTEGER)-(u.order??Number.MAX_SAFE_INTEGER)),C=y.find(o=>o.status==="in_progress")??y.find(o=>o.status==="blocked")??y.find(o=>o.status==="pending"),b=g.find(o=>o.status==="in_progress")??g.find(o=>o.status==="blocked")??g.find(o=>o.status==="pending"),ge=l([...K,...b?[b.title]:[],...!b&&C?[C.title]:[],...g.filter(o=>o.status==="pending").slice(0,5).map(o=>o.title)],8),fe=l([...N,...y.filter(o=>o.status==="blocked").map(o=>o.title),...g.filter(o=>o.status==="blocked").map(o=>o.title)],20),I={version:1,projectId:r.id,projectName:r.name,currentRequest:a,currentActivity:c,goal:p,plan:d,phases:y,tasks:g,decisions:l(f,20),blockers:fe,warnings:l($,20),nextActions:ge,filesTouched:l(D,30),activeFiles:Array.from(M.entries()).filter(([,o])=>o!=="deleted").map(([o])=>o).slice(-5),modifiedFiles:l(L,30),createdFiles:l(z,30),deletedFiles:l(B,30),commands:l(F,20),tests:l(W,20),checks:lt(V,20),currentPhase:C,currentTask:b,progress:{phasesTotal:y.length,phasesCompleted:y.filter(o=>o.status==="completed").length,tasksTotal:g.length,tasksCompleted:g.filter(o=>o.status==="completed").length,blocked:y.filter(o=>o.status==="blocked").length+g.filter(o=>o.status==="blocked").length},lastSession:m,updatedAt:s.length?s[s.length-1].occurredAt:new Date().toISOString()},J=ue(r.rootPath,".toolnet","work");return dt(J,{recursive:!0}),ce(ue(J,"current.json"),I),await e.put(`projects/${r.id}/work/current.json`,JSON.stringify(I,null,2)+`
6
- `,"application/json"),I}async function _(r,e){let t=await e.getText(`projects/${r.id}/work/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}function ft(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function yt(r){let e=Y(),t=oe(re({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new R(t,r.id,r.name,r.remote??r.name)}function me(r){console.log(),console.log(`Project: ${r.projectName}`),r.goal&&console.log(`Goal: ${r.goal}`),r.currentPhase&&console.log(`Current phase: ${r.currentPhase.title} [${r.currentPhase.status}]`),r.currentTask&&console.log(`Current task: ${r.currentTask.title} [${r.currentTask.status}]`),console.log(`Phases: ${r.progress.phasesCompleted}/${r.progress.phasesTotal}`),console.log(`Tasks: ${r.progress.tasksCompleted}/${r.progress.tasksTotal}`),r.nextActions.length&&(console.log(),console.log("Next actions:"),r.nextActions.forEach((e,t)=>console.log(`${t+1}. ${e}`))),r.blockers.length&&(console.log(),console.log("Blockers:"),r.blockers.forEach(e=>console.log(`- ${e}`))),r.lastSession&&(console.log(),console.log(`Last session: ${r.lastSession.agent} / ${r.lastSession.nativeSessionId}`))}async function ht(){let[r="help",...e]=process.argv.slice(2),t=new x().detect(ft(e,"--project")??process.cwd()),s=yt(t);if(r==="reconcile"){let n=await le(t,s);me(n);return}if(r==="status"){let n=await _(t,s);if(!n){console.log("No active work state yet.");return}me(n);return}if(r==="json"){let n=await _(t,s);console.log(JSON.stringify(n,null,2));return}console.log(`Work Continuity
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 be(){let r=process.env.TOOLNET_GLOBAL_ENV??Se(ke(),".config","toolnet-memory",".env");if(!ye(r))return;let e=he(r,"utf8");for(let t of e.split(/\r?\n/)){let s=t.trim();if(!s||s.startsWith("#"))continue;s.startsWith("export ")&&(s=s.slice(7));let n=s.indexOf("=");if(n<=0)continue;let i=s.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=we(s.slice(n+1)))}}be();function h(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function k(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function Y(){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:k(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:k(process.env.MEMORY_RERANK_TOP,10),finalContext:k(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:k(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:k(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as ve}from"node:crypto";import{existsSync as T,mkdirSync as xe,readFileSync as je,renameSync as Ae,writeFileSync as Pe}from"node:fs";import{basename as Re,dirname as x,join as A,parse as Z,resolve as S}from"node:path";var q=".toolnet",Me="project.json";function Ce(r){return ve("sha256").update(r).digest("hex").slice(0,16)}function E(r){return A(r,q,Me)}function Ie(r){return T(E(r))}function Te(r,e){let t=S(r),s=Z(t).root;for(;;){if(Ie(t))return t;if(t===s||e&&t===S(e))break;let n=x(t);if(n===t)break;t=n}return null}function Ee(r){let e=S(r),t=Z(e).root,s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(s.some(i=>T(A(e,i))))return e;if(e===t)break;let n=x(e);if(n===e)break;e=n}return S(r)}function Oe(r){let e;try{e=JSON.parse(je(r,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${r}: ${n instanceof Error?n.message:String(n)}`)}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 s=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:x(x(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:s,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:s,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function G(r,e){let t=A(r,q);xe(t,{recursive:!0});let s=E(r),n=`${s}.tmp-${process.pid}`;Pe(n,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),Ae(n,s)}function Q(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}}var j=class{detect(e=process.cwd()){let t=S(e),s=Ee(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>T(A(s,m))),a=Te(t,i?s:void 0);if(a){let m=E(a),f=Oe(m);return f.rootPath!==a&&(f.rootPath=a,f.updatedAt=new Date().toISOString(),G(a,f)),Q(f,a)}let c=new Date().toISOString(),d=Re(s),p={version:1,id:Ce(s),name:d,remote:d,rootPath:s,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return G(s,p),Q(p,s)}};import{homedir as rt}from"node:os";import{join as st}from"node:path";import{DeleteObjectCommand as _e,GetObjectCommand as Ne,HeadObjectCommand as $e,ListObjectsV2Command as Ke,PutObjectCommand as De,S3Client as Le}from"@aws-sdk/client-s3";import{getSignedUrl as ze}from"@aws-sdk/s3-request-presigner";var P=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Le({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,s="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new De({Bucket:this.bucket,Key:e,Body:n,ContentType:s}))}async get(e){let t=await ze(this.client,new Ne({Bucket:this.bucket,Key:e}),{expiresIn:60}),s=await fetch(t,{redirect:"follow"});if(s.status===404)return null;if(!s.ok)throw new Error(`HF download failed: ${s.status} ${s.statusText}`);return new Uint8Array(await s.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 _e({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],s;do{let n=await this.client.send(new Ke({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:s}));for(let i of n.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});s=n.IsTruncated?n.NextContinuationToken:void 0}while(s);return t}};import{access as X,mkdir as Be,readFile as Fe,readdir as We,rm as Ve,stat as ee,writeFile as Je}from"node:fs/promises";import{dirname as Ue,join as He,relative as te,resolve as Ye}from"node:path";var w=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Ye(this.root,t)}async put(e,t){let s=this.path(e);await Be(Ue(s),{recursive:!0}),await Je(s,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 X(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),s=[];try{await X(t)}catch{return s}let n=async a=>{let c=await We(a,{withFileTypes:!0});for(let d of c){let p=He(a,d.name);if(d.isDirectory()){await n(p);continue}let m=await ee(p);s.push({key:te(this.root,p),size:m.size,updatedAt:m.mtime.toISOString()})}},i=await ee(t);return i.isDirectory()?await n(t):s.push({key:te(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),s}};import{DeleteObjectCommand as Ge,GetObjectCommand as Qe,HeadObjectCommand as Ze,ListObjectsV2Command as qe,PutObjectCommand as Xe,S3Client as et}from"@aws-sdk/client-s3";import{getSignedUrl as tt}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 et({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,s="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Xe({Bucket:this.bucket,Key:e,Body:n,ContentType:s}))}async get(e){let t=await tt(this.client,new Qe({Bucket:this.bucket,Key:e}),{expiresIn:60}),s=await fetch(t,{redirect:"follow"});if(s.status===404)return null;if(!s.ok)throw new Error(`${this.name} download failed: ${s.status} ${s.statusText}`);return new Uint8Array(await s.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 Ze({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=[],s;do{let n=await this.client.send(new qe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:s}));for(let i of n.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});s=n.IsTruncated?n.NextContinuationToken:void 0}while(s);return t}};function O(r,e){return console.warn(e),new w(r)}function re(r){let e=r.localRoot??st(rt(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new b({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):O(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 b({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):O(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 P({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):O(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new w(e)}function ot(r){return new Promise(e=>setTimeout(e,r))}async function se(r,e={}){let t=Math.max(1,e.attempts??3),s=e.baseDelayMs??150,n=e.maxDelayMs??2e3,i;for(let a=1;a<=t;a++)try{return await r()}catch(c){if(i=c,a>=t)break;let d=Math.min(n,s*2**(a-1)),p=Math.floor(Math.random()*Math.max(1,d*.2));await ot(d+p)}throw i}var nt=new Set(["put","get","getText","delete","list"]);function oe(r,e={}){return new Proxy(r,{get(t,s){let n=Reflect.get(t,s,t);return typeof n!="function"?n:nt.has(s)?(...i)=>se(()=>Promise.resolve(n.apply(t,i)),e):n.bind(t)}})}function ne(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 ie(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 s=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(s)return`${s[1]}memory/records/${s[2]}`;if(s=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),s)return`${s[1]}memory/vectors/${s[2]}`;if(s=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),s)return`${s[1]}code/graph/${s[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 R=class{constructor(e,t,s,n){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=s,this.folder=ne(n??s),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(),s=t,n=await this.provider.getText(e);if(n){let a;try{a=JSON.parse(n)}catch(c){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${c instanceof Error?c.message:String(c)}`)}if(typeof a.id=="string"&&a.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${a.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof a.createdAt=="string"&&(s=a.createdAt)}let i={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:s,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=ie(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,s){return await this.ensureRegistered(),this.provider.put(this.key(e),t,s)}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{join as ue}from"node:path";import{mkdirSync as pt}from"node:fs";import{createHash as it}from"node:crypto";import{dirname as at}from"node:path";import{mkdirSync as ct,readFileSync as ys,renameSync as ut,writeFileSync as dt}from"node:fs";function ae(r){return it("sha256").update(r).digest("hex")}function ce(r,e){ct(at(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;dt(t,JSON.stringify(e,null,2)+`
5
+ `,{encoding:"utf8",mode:384}),ut(t,r)}function pe(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function l(r,e=20){let t=[],s=new Set;for(let n of r.slice().reverse()){let i=pe(n);if(!(!i||s.has(i))&&(s.add(i),t.push(n),t.length>=e))break}return t.reverse()}function lt(r,e=20){let t=new Map;for(let s of r){let n=`${s.kind}|${pe(s.command)}`;t.delete(n),t.set(n,s)}return Array.from(t.values()).slice(-e)}function mt(r){return r.kind==="phase"?/^Phase\s+\d+$/iu.test(r.text):r.kind==="task"?/^(?:TODO|Task|Việc)\s+\d+$/iu.test(r.text):!1}function de(r,e){let t=e.status??r?.status??"pending",s=t;r&&(r.status==="completed"&&t!=="completed"?s="completed":t==="pending"&&(r.status==="in_progress"||r.status==="blocked")&&(s=r.status));let n=r&&mt(e)?r.title:e.text;return{id:r?.id??ae(e.key).slice(0,24),title:n,status:s,order:e.order??r?.order,confidence:Math.max(e.confidence,r?.confidence??0),updatedAt:e.occurredAt,updatedBy:{agent:e.agent,nativeSessionId:e.nativeSessionId,eventId:e.eventId}}}async function gt(r,e){let t=`projects/${r.id}/work/observations/`,s=await e.list(t),n=[];for(let i of s.filter(a=>a.key.endsWith(".json")).sort((a,c)=>a.key.localeCompare(c.key))){let a=await e.getText(i.key);if(a)try{let c=JSON.parse(a);c.version===1&&Array.isArray(c.observations)&&n.push(c)}catch{}}return n}async function le(r,e){let s=(await gt(r,e)).flatMap(o=>o.observations).sort((o,u)=>{let U=o.occurredAt.localeCompare(u.occurredAt);if(U!==0)return U;let H=o.sequence-u.sequence;return H!==0?H:o.id.localeCompare(u.id)}),n=new Map,i=new Map,a,c,d,p,m,f=[],N=[],$=[],K=[],D=[],M=new Map,L=[],z=[],B=[],F=[],W=[],V=[];for(let o of s)switch(o.kind){case"request":a=o.text;break;case"activity":c=o.text;break;case"goal":d=o.text;break;case"plan":p=o.text;break;case"phase":n.set(o.key,de(n.get(o.key),o));break;case"task":i.set(o.key,de(i.get(o.key),o));break;case"decision":f.push(o.text);break;case"blocker":N.push(o.text);break;case"warning":$.push(o.text);break;case"next_action":K.push(o.text);break;case"file":{D.push(o.text);let u=o.fileAction??"active";M.delete(o.text),M.set(o.text,u),u==="modified"?L.push(o.text):u==="created"?z.push(o.text):u==="deleted"&&B.push(o.text);break}case"command":F.push(o.text);break;case"test":W.push(o.text),o.checkKind&&V.push({kind:o.checkKind,command:o.text,status:o.checkStatus??"unknown",updatedAt:o.occurredAt,agent:o.agent,nativeSessionId:o.nativeSessionId});break;case"session":m={agent:o.agent,nativeSessionId:o.nativeSessionId,sessionKey:o.sessionKey,updatedAt:o.occurredAt};break}let y=Array.from(n.values()).sort((o,u)=>(o.order??Number.MAX_SAFE_INTEGER)-(u.order??Number.MAX_SAFE_INTEGER)),g=Array.from(i.values()).sort((o,u)=>(o.order??Number.MAX_SAFE_INTEGER)-(u.order??Number.MAX_SAFE_INTEGER)),C=y.find(o=>o.status==="in_progress")??y.find(o=>o.status==="blocked")??y.find(o=>o.status==="pending"),v=g.find(o=>o.status==="in_progress")??g.find(o=>o.status==="blocked")??g.find(o=>o.status==="pending"),ge=l([...K,...v?[v.title]:[],...!v&&C?[C.title]:[],...g.filter(o=>o.status==="pending").slice(0,5).map(o=>o.title)],8),fe=l([...N,...y.filter(o=>o.status==="blocked").map(o=>o.title),...g.filter(o=>o.status==="blocked").map(o=>o.title)],20),I={version:1,projectId:r.id,projectName:r.name,currentRequest:a,currentActivity:c,goal:d,plan:p,phases:y,tasks:g,decisions:l(f,20),blockers:fe,warnings:l($,20),nextActions:ge,filesTouched:l(D,30),activeFiles:Array.from(M.entries()).filter(([,o])=>o!=="deleted").map(([o])=>o).slice(-5),modifiedFiles:l(L,30),createdFiles:l(z,30),deletedFiles:l(B,30),commands:l(F,20),tests:l(W,20),checks:lt(V,20),currentPhase:C,currentTask:v,progress:{phasesTotal:y.length,phasesCompleted:y.filter(o=>o.status==="completed").length,tasksTotal:g.length,tasksCompleted:g.filter(o=>o.status==="completed").length,blocked:y.filter(o=>o.status==="blocked").length+g.filter(o=>o.status==="blocked").length},lastSession:m,updatedAt:s.length?s[s.length-1].occurredAt:new Date().toISOString()},J=ue(r.rootPath,".toolnet","work");return pt(J,{recursive:!0}),ce(ue(J,"current.json"),I),await e.put(`projects/${r.id}/work/current.json`,JSON.stringify(I,null,2)+`
6
+ `,"application/json"),I}async function _(r,e){let t=await e.getText(`projects/${r.id}/work/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}function ft(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function yt(r){let e=Y(),t=oe(re({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new R(t,r.id,r.name,r.remote??r.name)}function me(r){console.log(),console.log(`Project: ${r.projectName}`),r.goal&&console.log(`Goal: ${r.goal}`),r.currentPhase&&console.log(`Current phase: ${r.currentPhase.title} [${r.currentPhase.status}]`),r.currentTask&&console.log(`Current task: ${r.currentTask.title} [${r.currentTask.status}]`),console.log(`Phases: ${r.progress.phasesCompleted}/${r.progress.phasesTotal}`),console.log(`Tasks: ${r.progress.tasksCompleted}/${r.progress.tasksTotal}`),r.nextActions.length&&(console.log(),console.log("Next actions:"),r.nextActions.forEach((e,t)=>console.log(`${t+1}. ${e}`))),r.blockers.length&&(console.log(),console.log("Blockers:"),r.blockers.forEach(e=>console.log(`- ${e}`))),r.lastSession&&(console.log(),console.log(`Last session: ${r.lastSession.agent} / ${r.lastSession.nativeSessionId}`))}async function ht(){let[r="help",...e]=process.argv.slice(2),t=new j().detect(ft(e,"--project")??process.cwd()),s=yt(t);if(r==="reconcile"){let n=await le(t,s);me(n);return}if(r==="status"){let n=await _(t,s);if(!n){console.log("No active work state yet.");return}me(n);return}if(r==="json"){let n=await _(t,s);console.log(JSON.stringify(n,null,2));return}console.log(`Work Continuity
7
7
 
8
8
  Commands:
9
9
  status [--project PATH]