toolnet-memory 0.3.15 → 0.3.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
- import{existsSync as $e,readFileSync as Ke}from"node:fs";import{homedir as ze}from"node:os";import{join as He}from"node:path";function Le(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??He(ze(),".config","toolnet-memory",".env");if(!$e(r))return;let e=Ke(r,"utf8");for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let n=o.indexOf("=");if(n<=0)continue;let s=o.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=Le(o.slice(n+1)))}}Ve();function j(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function M(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function re(){return{memory:{autoCapture:j(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:j(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:j(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:j(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:M(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:M(process.env.MEMORY_RERANK_TOP,10),finalContext:M(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:M(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:j(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:M(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Be}from"node:crypto";import{existsSync as C,mkdirSync as Fe,readFileSync as We,renameSync as Je,writeFileSync as Ue}from"node:fs";import{basename as Ye,dirname as O,join as A,parse as ae,resolve as w}from"node:path";var ce=".toolnet",Ge="project.json";function Ze(r){return Be("sha256").update(r).digest("hex").slice(0,16)}function T(r){return A(r,ce,Ge)}function qe(r){return C(T(r))}function oe(r,e){let t=w(r),o=ae(t).root;for(;;){if(qe(t))return t;if(t===o||e&&t===w(e))break;let n=O(t);if(n===t)break;t=n}return null}function ne(r){let e=w(r),t=ae(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(s=>C(A(e,s))))return e;if(e===t)break;let n=O(e);if(n===e)break;e=n}return w(r)}function se(r){let e;try{e=JSON.parse(We(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 o=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:O(O(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:o,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:o,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 ie(r,e){let t=A(r,ce);Fe(t,{recursive:!0});let o=T(r),n=`${o}.tmp-${process.pid}`;Ue(n,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),Je(n,o)}function F(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 E=class{findExisting(e=process.cwd()){let t=w(e),o=ne(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>C(A(o,d))),a=oe(t,s?o:void 0);if(!a)return null;let c=se(T(a));return F(c,a)}requireExisting(e=process.cwd()){let t=this.findExisting(e);if(!t)throw new Error("PROJECT_NOT_INITIALIZED");return t}detect(e=process.cwd()){let t=w(e),o=ne(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>C(A(o,m))),a=oe(t,s?o:void 0);if(a){let m=T(a),f=se(m);return f.rootPath!==a&&(f.rootPath=a,f.updatedAt=new Date().toISOString(),ie(a,f)),F(f,a)}let c=new Date().toISOString(),d=Ye(o),l={version:1,id:Ze(o),name:d,remote:d,rootPath:o,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return ie(o,l),F(l,o)}};var Qe=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_-]{20,}\b/g,confidence:"exact"},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g,confidence:"exact"},{type:"aws_access_key",regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,confidence:"exact"},{type:"github_token",regex:/\b(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{40,255})\b/g,confidence:"exact"},{type:"stripe_secret_key",regex:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,confidence:"exact"},{type:"google_api_key",regex:/\bAIza[A-Za-z0-9_-]{30,}\b/g,confidence:"exact"},{type:"slack_token",regex:/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/g,confidence:"exact"},{type:"npm_token",regex:/\bnpm_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi,confidence:"high"},{type:"jwt",regex:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,confidence:"exact"},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,confidence:"exact"},{type:"password_assignment",regex:/\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^"' \t\r\n]{6,}["']?/gi,confidence:"high"},{type:"secret_assignment",regex:/\b(?:secret|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\s*[:=]\s*["']?[^"' \t\r\n]{8,}["']?/gi,confidence:"high"},{type:"cookie",regex:/\b(?:cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi,confidence:"high"},{type:"url_credentials",regex:/\bhttps?:\/\/[^:/@\s]+:[^/@\s]{4,}@[^/\s]+/gi,confidence:"high"}],Xe=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function ue(r){return r.normalize("NFKC").trim().toLowerCase()}function et(r){if(r.length===0)return 0;let e=new Map;for(let o of r)e.set(o,(e.get(o)??0)+1);let t=0;for(let o of e.values()){let n=o/r.length;t-=n*Math.log2(n)}return t}function tt(r){return/^[a-f0-9]{32}$/iu.test(r)||/^[a-f0-9]{40}$/iu.test(r)||/^[a-f0-9]{64}$/iu.test(r)}function rt(r,e,t){let o=r.slice(Math.max(0,e-48),e),n=r.slice(t,Math.min(r.length,t+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${o} ${n}`)}function ot(r,e){return r.start<e.end&&e.start<r.end}function de(r){return r.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var _=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let o=ue(t);o&&this.allowValues.add(o)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let s of Qe){let a=new RegExp(s.regex.source,s.regex.flags);for(let c of e.matchAll(a))c.index===void 0||!c[0]||this.allowed(c[0])||t.push({type:s.type,value:c[0],start:c.index,end:c.index+c[0].length,confidence:s.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let o=de(t),n=[];for(let s of o)n.some(a=>ot(a,s))||n.push(s);return de(n)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=ue(e);return Xe.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],o=/[A-Za-z0-9_+/=-]{32,160}/g;for(let n of e.matchAll(o)){if(n.index===void 0||!n[0])continue;let s=n[0];this.allowed(s)||tt(s)||!/[A-Za-z]/u.test(s)||!/[0-9]/u.test(s)||rt(e,n.index,n.index+s.length)&&(et(s)<3.7||t.push({type:"high_entropy_secret",value:s,start:n.index,end:n.index+s.length,confidence:"heuristic"}))}return t}};var N=class{scanner;constructor(e={}){this.scanner=new _(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let o=e,n=[...t].sort((a,c)=>c.start-a.start),s=new Set;for(let a of n)s.add(a.type),o=o.slice(0,a.start)+`[REDACTED:${a.type}]`+o.slice(a.end);return{text:o,redacted:t.length,secretTypes:[...s].sort()}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[o,n]of Object.entries(e)){let s=o.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(s.includes("password")||s.includes("passwd")||s==="pwd"||s.includes("secret")||s.includes("token")||s.includes("cookie")||s.includes("authorization")||s.includes("apikey")||s.includes("accesskey")||s.includes("privatekey")||s.includes("clientsecret")||s.includes("credential")){t[o]="[REDACTED]";continue}t[o]=this.sanitizeValue(n)}return t}return e}};var hr=new N;import{homedir as At}from"node:os";import{join as Rt}from"node:path";import{DeleteObjectCommand as nt,GetObjectCommand as st,HeadObjectCommand as it,ListObjectsV2Command as at,PutObjectCommand as ct,S3Client as ut}from"@aws-sdk/client-s3";import{getSignedUrl as dt}from"@aws-sdk/s3-request-presigner";var D=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new ut({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,o="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new ct({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await dt(this.client,new st({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{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 t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new it({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new nt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new at({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let s of n.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return t}};import{access as le,mkdir as lt,readFile as pt,readdir as mt,rm as ft,stat as pe,writeFile as gt}from"node:fs/promises";import{dirname as yt,join as ht,relative as me,resolve as St}from"node:path";var R=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return St(this.root,t)}async put(e,t){let o=this.path(e);await lt(yt(o),{recursive:!0}),await gt(o,t)}async get(e){try{return await pt(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await le(this.path(e)),!0}catch{return!1}}async delete(e){await ft(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await le(t)}catch{return o}let n=async a=>{let c=await mt(a,{withFileTypes:!0});for(let d of c){let l=ht(a,d.name);if(d.isDirectory()){await n(l);continue}let m=await pe(l);o.push({key:me(this.root,l),size:m.size,updatedAt:m.mtime.toISOString()})}},s=await pe(t);return s.isDirectory()?await n(t):o.push({key:me(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),o}};import{DeleteObjectCommand as kt,GetObjectCommand as bt,HeadObjectCommand as wt,ListObjectsV2Command as vt,PutObjectCommand as xt,S3Client as jt}from"@aws-sdk/client-s3";import{getSignedUrl as Mt}from"@aws-sdk/s3-request-presigner";var P=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new jt({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,o="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new xt({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await Mt(this.client,new bt({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{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 t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new wt({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 kt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new vt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let s of n.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return t}};function W(r,e){return console.warn(e),new R(r)}function fe(r){let e=r.localRoot??Rt(At(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new P({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):W(e,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let t=r.s3;return t?.bucket&&t.accessKeyId&&t.secretAccessKey?new P({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):W(e,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new D({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):W(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new R(e)}var $=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"memories","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return[];let o=JSON.parse(t);if(!Array.isArray(o))throw new Error("Invalid memory snapshot");return o}async save(e,t){let o=JSON.stringify(t,null,2);await this.storage.put(this.key(e),o,"application/json")}};function Pt(r){return new Promise(e=>setTimeout(e,r))}async function ge(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,n=e.maxDelayMs??2e3,s;for(let a=1;a<=t;a++)try{return await r()}catch(c){if(s=c,a>=t)break;let d=Math.min(n,o*2**(a-1)),l=Math.floor(Math.random()*Math.max(1,d*.2));await Pt(d+l)}throw s}var It=new Set(["put","get","getText","delete","list"]);function ye(r,e={}){return new Proxy(r,{get(t,o){let n=Reflect.get(t,o,t);return typeof n!="function"?n:It.has(o)?(...s)=>ge(()=>Promise.resolve(n.apply(t,s)),e):n.bind(t)}})}function he(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 Se(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 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 K=class{constructor(e,t,o,n){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=he(n??o),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(),o=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"&&(o=a.createdAt)}let s={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:t};await this.provider.put(e,JSON.stringify(s,null,2)+`
4
- `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=Se(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,o){return await this.ensureRegistered(),this.provider.put(this.key(e),t,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{join as we}from"node:path";import{mkdirSync as Nt}from"node:fs";import{createHash as Ct}from"node:crypto";import{dirname as Ot}from"node:path";import{mkdirSync as Tt,readFileSync as nn,renameSync as Et,writeFileSync as _t}from"node:fs";function ke(r){return Ct("sha256").update(r).digest("hex")}function be(r,e){Tt(Ot(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;_t(t,JSON.stringify(e,null,2)+`
5
- `,{encoding:"utf8",mode:384}),Et(t,r)}function xe(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function y(r,e=20){let t=[],o=new Set;for(let n of r.slice().reverse()){let s=xe(n);if(!(!s||o.has(s))&&(o.add(s),t.push(n),t.length>=e))break}return t.reverse()}function Dt(r,e=20){let t=new Map;for(let o of r){let n=`${o.kind}|${xe(o.command)}`;t.delete(n),t.set(n,o)}return Array.from(t.values()).slice(-e)}function $t(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 ve(r,e){let t=e.status??r?.status??"pending",o=t;r&&(r.status==="completed"&&t!=="completed"?o="completed":t==="pending"&&(r.status==="in_progress"||r.status==="blocked")&&(o=r.status));let n=r&&$t(e)?r.title:e.text;return{id:r?.id??ke(e.key).slice(0,24),title:n,status:o,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 je(r,e){let t=`projects/${r.id}/work/observations/`,o=await e.list(t),n=[];for(let s of o.filter(a=>a.key.endsWith(".json")).sort((a,c)=>a.key.localeCompare(c.key))){let a=await e.getText(s.key);if(a)try{let c=JSON.parse(a);c.version===1&&Array.isArray(c.observations)&&n.push(c)}catch{}}return n}async function Kt(r,e){let o=(await je(r,e)).flatMap(i=>i.observations).sort((i,g)=>{let ee=i.occurredAt.localeCompare(g.occurredAt);if(ee!==0)return ee;let te=i.sequence-g.sequence;return te!==0?te:i.id.localeCompare(g.id)}),n=new Map,s=new Map,a,c,d,l,m,f=[],u=[],p=[],S=[],v=[],x=new Map,U=[],Y=[],G=[],Z=[],q=[],Q=[];for(let i of o)switch(i.kind){case"request":a=i.text;break;case"activity":c=i.text;break;case"goal":d=i.text;break;case"plan":l=i.text;break;case"phase":n.set(i.key,ve(n.get(i.key),i));break;case"task":s.set(i.key,ve(s.get(i.key),i));break;case"decision":f.push(i.text);break;case"blocker":u.push(i.text);break;case"warning":p.push(i.text);break;case"next_action":S.push(i.text);break;case"file":{v.push(i.text);let g=i.fileAction??"active";x.delete(i.text),x.set(i.text,g),g==="modified"?U.push(i.text):g==="created"?Y.push(i.text):g==="deleted"&&G.push(i.text);break}case"command":Z.push(i.text);break;case"test":q.push(i.text),i.checkKind&&Q.push({kind:i.checkKind,command:i.text,status:i.checkStatus??"unknown",updatedAt:i.occurredAt,agent:i.agent,nativeSessionId:i.nativeSessionId});break;case"session":m={agent:i.agent,nativeSessionId:i.nativeSessionId,sessionKey:i.sessionKey,updatedAt:i.occurredAt};break}let k=Array.from(n.values()).sort((i,g)=>(i.order??Number.MAX_SAFE_INTEGER)-(g.order??Number.MAX_SAFE_INTEGER)),h=Array.from(s.values()).sort((i,g)=>(i.order??Number.MAX_SAFE_INTEGER)-(g.order??Number.MAX_SAFE_INTEGER)),V=k.find(i=>i.status==="in_progress")??k.find(i=>i.status==="blocked")??k.find(i=>i.status==="pending"),I=h.find(i=>i.status==="in_progress")??h.find(i=>i.status==="blocked")??h.find(i=>i.status==="pending"),Ne=y([...S,...I?[I.title]:[],...!I&&V?[V.title]:[],...h.filter(i=>i.status==="pending").slice(0,5).map(i=>i.title)],8),De=y([...u,...k.filter(i=>i.status==="blocked").map(i=>i.title),...h.filter(i=>i.status==="blocked").map(i=>i.title)],20),B={version:1,projectId:r.id,projectName:r.name,currentRequest:a,currentActivity:c,goal:d,plan:l,phases:k,tasks:h,decisions:y(f,20),blockers:De,warnings:y(p,20),nextActions:Ne,filesTouched:y(v,30),activeFiles:Array.from(x.entries()).filter(([,i])=>i!=="deleted").map(([i])=>i).slice(-5),modifiedFiles:y(U,30),createdFiles:y(Y,30),deletedFiles:y(G,30),commands:y(Z,20),tests:y(q,20),checks:Dt(Q,20),currentPhase:V,currentTask:I,progress:{phasesTotal:k.length,phasesCompleted:k.filter(i=>i.status==="completed").length,tasksTotal:h.length,tasksCompleted:h.filter(i=>i.status==="completed").length,blocked:k.filter(i=>i.status==="blocked").length+h.filter(i=>i.status==="blocked").length},lastSession:m,updatedAt:o.length?o[o.length-1].occurredAt:new Date().toISOString()},X=we(r.rootPath,".toolnet","work");return Nt(X,{recursive:!0}),be(we(X,"current.json"),B),await e.put(`projects/${r.id}/work/current.json`,JSON.stringify(B,null,2)+`
6
- `,"application/json"),B}async function Me(r,e){if((await je(r,e)).length>0)return Kt(r,e);let o=await e.getText(`projects/${r.id}/work/current.json`);if(!o)return null;try{return JSON.parse(o)}catch{return null}}import{createHash as Wt}from"node:crypto";import{hostname as Jt}from"node:os";import{createHash as zt,randomUUID as Ht}from"node:crypto";function b(r,e){let t=r.trim();if(!t)throw new Error(`${e} is required`);return t}function z(r,e){return encodeURIComponent(b(r,e))}function Lt(r){let e=JSON.stringify(r);if(e===void 0)throw new Error("Multi-host operation payload must be JSON serializable");return e}function Re(r){return zt("sha256").update(r).digest("hex")}function Pe(r){return Re(Lt(r))}function Ie(r){return Number.isFinite(Date.parse(r))}function Vt(r){return Re(JSON.stringify({version:r.version,operationId:r.operationId,projectId:r.projectId,scope:r.scope,hostId:r.hostId,occurredAt:r.occurredAt,payloadSha256:r.payloadSha256,payload:r.payload}))}function Ce(r){let e=b(r.projectId,"projectId"),t=b(r.scope,"scope"),o=b(r.hostId,"hostId"),n=b(r.operationId??Ht(),"operationId"),s=r.occurredAt??new Date().toISOString();if(!Ie(s))throw new Error(`Invalid operation timestamp: ${s}`);return{version:1,operationId:n,projectId:e,scope:t,hostId:o,occurredAt:s,payloadSha256:Pe(r.payload),payload:r.payload}}function Oe(r,e){let t=["projects",z(r,"projectId"),"operations"];return e?`${[...t,z(e,"scope")].join("/")}/`:`${t.join("/")}/`}function Bt(r){return[Oe(r.projectId,r.scope).replace(/\/$/,""),z(r.hostId,"hostId"),`${z(r.operationId,"operationId")}-${r.payloadSha256}.json`].join("/")}async function Te(r,e){let t=Bt(e);return await r.put(t,`${JSON.stringify(e,null,2)}
7
- `,"application/json"),t}function Ft(r){let e;try{e=JSON.parse(r)}catch{return null}return e.version!==1||typeof e.operationId!="string"||typeof e.projectId!="string"||typeof e.scope!="string"||typeof e.hostId!="string"||typeof e.occurredAt!="string"||!Ie(e.occurredAt)||typeof e.payloadSha256!="string"||Pe(e.payload)!==e.payloadSha256?null:e}function Ae(r,e){let t=r.occurredAt.localeCompare(e.occurredAt);if(t!==0)return t;let o=r.hostId.localeCompare(e.hostId);if(o!==0)return o;let n=r.operationId.localeCompare(e.operationId);return n!==0?n:r.payloadSha256.localeCompare(e.payloadSha256)}async function Ee(r,e,t){let o=b(e,"projectId"),n=b(t,"scope"),s=Oe(o,n),a=await r.list(s),c=[],d=[];for(let u of a){let p=await r.getText(u.key);if(!p){c.push(u.key);continue}let S=Ft(p);if(!S){c.push(u.key);continue}if(S.projectId!==o){c.push(u.key);continue}if(S.scope!==n){c.push(u.key);continue}d.push(S)}let l=new Map;for(let u of d){let p=l.get(u.operationId);if(!p){l.set(u.operationId,[u]);continue}p.push(u)}let m=[],f=[];for(let[u,p]of l){if(new Set(p.map(x=>Vt(x))).size>1){f.push({operationId:u,variants:[...p].sort(Ae)});continue}let v=p[0];v&&m.push(v)}return m.sort(Ae),f.sort((u,p)=>u.operationId.localeCompare(p.operationId)),c.sort(),{operations:m,conflicts:f,invalidKeys:c}}function Ut(r){let t=(r??process.env.TOOLNET_HOST_ID??Jt()).trim();return t||`pid-${process.pid}`}function Yt(r){let e=t=>{if(t===null||typeof t!="object")return t;if(Array.isArray(t))return t.map(n=>e(n));let o=t;return Object.fromEntries(Object.keys(o).sort().map(n=>[n,e(o[n])]))};return JSON.stringify(e(r))}function H(r){return Wt("sha256").update(Yt(r)).digest("hex")}function Gt(r,e){let t=H(r).slice(0,12),o=H(e);return["memory",t,o].join("-")}function Zt(r,e){let t=r.updatedAt.localeCompare(e.updatedAt);if(t!==0)return t;let o=r.createdAt.localeCompare(e.createdAt);return o!==0?o:H(r).localeCompare(H(e))}function qt(r,e){return Zt(r,e)>=0?r:e}function J(r,e){let t=new Map;for(let o of r)t.set(o.id,o);for(let o of e){if(o.payload.kind!=="upsert")continue;let n=o.payload.memory,s=t.get(n.id);if(!s){t.set(n.id,n);continue}t.set(n.id,qt(s,n))}return[...t.values()].sort((o,n)=>o.id.localeCompare(n.id))}var L=class{constructor(e,t={}){this.storage=e;this.legacy=new $(e),this.hostId=Ut(t.hostId)}storage;legacy;hostId;diagnostics={operationCount:0,conflicts:0,invalidKeys:0};getDiagnostics(){return{...this.diagnostics}}async operations(e){let t=await Ee(this.storage,e,"memory");return this.diagnostics={operationCount:t.operations.length,conflicts:t.conflicts.length,invalidKeys:t.invalidKeys.length},t.operations}async load(e){let t=await this.legacy.load(e),o=await this.operations(e);return J(t,o)}async appendMemory(e,t){let o=Ce({projectId:e,scope:"memory",hostId:this.hostId,operationId:Gt(this.hostId,t),occurredAt:t.updatedAt,payload:{kind:"upsert",memory:t}});await Te(this.storage,o)}async refreshProjection(e){let t=await this.legacy.load(e),o=await this.operations(e),n=J(t,o);return await this.legacy.save(e,n),n}async save(e,t){let o=[...t].sort((a,c)=>a.id.localeCompare(c.id));for(let a of o)await this.appendMemory(e,a);let n=await this.operations(e),s=J(t,n);await this.legacy.save(e,s)}};async function _e(r,e){let t=new Date().toISOString(),n=await new L(e).refreshProjection(r.id),s=await Me(r,e);return{startedAt:t,finishedAt:new Date().toISOString(),memories:n.length,workAvailable:s!==null}}function Qt(r,e){let t=r.indexOf(e);if(!(t<0))return r[t+1]}function Xt(r){return{projectPath:Qt(r,"--project"),json:r.includes("--json"),quiet:r.includes("--quiet")}}async function er(r){let e=re(),t=ye(fe({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new K(t,r.id,r.name,r.remote??r.name)}async function tr(){let r=Xt(process.argv.slice(2)),e=r.projectPath??process.cwd(),t=new E().detect(e);if(!t){r.quiet||console.error(`ToolNet project not found: ${e}`),process.exitCode=2;return}let o;try{o=await er(t)}catch(n){r.quiet||console.error(n instanceof Error?n.message:String(n)),process.exitCode=3;return}try{let n=await _e(t,o);if(r.quiet)return;if(r.json){console.log(JSON.stringify(n));return}console.log(["ToolNet Memory refreshed",`memory=${n.memories}`,`work=${n.workAvailable?"yes":"no"}`].join(" "))}catch(n){r.quiet||console.error(n instanceof Error?n.message:String(n)),process.exitCode=4}}tr().then(()=>{process.exit(process.exitCode??0)});
1
+ import{existsSync as Ge,readFileSync as Ue}from"node:fs";import{homedir as Ye}from"node:os";import{join as qe}from"node:path";function Ze(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 Qe(){let r=process.env.TOOLNET_GLOBAL_ENV??qe(Ye(),".config","toolnet-memory",".env");if(!Ge(r))return;let e=Ue(r,"utf8");for(let t of e.split(/\r?\n/)){let n=t.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let o=n.indexOf("=");if(o<=0)continue;let s=n.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=Ze(n.slice(o+1)))}}Qe();function R(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function A(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function ce(){return{memory:{autoCapture:R(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:R(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:R(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:R(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:A(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:A(process.env.MEMORY_RERANK_TOP,10),finalContext:A(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:A(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:R(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:A(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as st}from"node:crypto";import{existsSync as N,mkdirSync as it,readFileSync as at,renameSync as ct,writeFileSync as ut}from"node:fs";import{basename as dt,dirname as K,join as P,parse as ye,resolve as w}from"node:path";import{createHash as le}from"node:crypto";import{spawnSync as Xe}from"node:child_process";var I="git-remote-v1",et=new Set(["github.com","gitlab.com","bitbucket.org"]);function pe(r,e){let t=e.replaceAll("\\","/").replace(/^\/+/u,"").replace(/\/+$/u,"").replace(/\.git$/iu,"").replace(/\/+/gu,"/");return!t||t==="."||t===".."||t.split("/").some(n=>!n||n==="."||n==="..")?null:(et.has(r)&&(t=t.toLowerCase()),t)}function tt(r){let e;try{e=new URL(r)}catch{return null}if(!["https:","http:","ssh:","git:"].includes(e.protocol))return null;let t=e.hostname.trim().toLowerCase();if(!t)return null;let n=e.protocol==="https:"&&e.port==="443"||e.protocol==="http:"&&e.port==="80"||e.protocol==="ssh:"&&e.port==="22",o=e.port&&!n?`${t}:${e.port}`:t,s=pe(t,e.pathname);return s?`${o}/${s}`:null}function rt(r){let e=r.match(/^(?:[^@\s/:]+@)?([^:/\s]+):(.+)$/u);if(!e)return null;let t=e[1]?.trim().toLowerCase();if(!t||t.length===1)return null;let n=pe(t,e[2]??"");return n?`${t}/${n}`:null}function ue(r){let e=r.trim();return e?e.includes("://")?tt(e):rt(e):null}function nt(r){return le("sha256").update(`${I}:${r}`).digest("hex")}function me(r){return le("sha256").update(`toolnet-project:${I}:${r}`).digest("hex").slice(0,16)}function ot(r){return r.split("/").filter(Boolean).at(-1)?.trim()||null}function U(r,e){let t=Xe("git",["-C",r,...e],{encoding:"utf8",windowsHide:!0,stdio:["ignore","pipe","ignore"]});return t.error||t.status!==0?null:t.stdout?.trim()||null}function de(r,e){let t=ot(r);return t?{scheme:I,canonicalRemote:r,fingerprint:nt(r),repositoryName:t,source:e}:null}function fe(r){let e=U(r,["remote","get-url","origin"]);if(e){let o=ue(e);if(o)return de(o,"origin")}let t=U(r,["remote"]);if(!t)return null;let n=new Set;for(let o of t.split(/\r?\n/u).map(s=>s.trim()).filter(Boolean)){let s=U(r,["remote","get-url",o]);if(!s)continue;let a=ue(s);a&&n.add(a)}return n.size!==1?null:de([...n][0],"unique-remote")}var he=".toolnet",lt="project.json";function pt(r){return st("sha256").update(r).digest("hex").slice(0,16)}function v(r){return P(r,he,lt)}function Se(r){return N(v(r))}function ge(r,e){let t=w(r),n=ye(t).root;for(;;){if(Se(t))return t;if(t===n||e&&t===w(e))break;let o=K(t);if(o===t)break;t=o}return null}function Y(r){let e=w(r),t=ye(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(s=>N(P(e,s))))return e;if(e===t)break;let o=K(e);if(o===e)break;e=o}return w(r)}function O(r){let e;try{e=JSON.parse(at(r,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${r}: ${o instanceof Error?o.message:String(o)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:K(K(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:n,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:n,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function _(r,e){let t=P(r,he);it(t,{recursive:!0});let n=v(r),o=`${n}.tmp-${process.pid}`;ut(o,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),ct(o,n)}function k(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}function q(r){return{version:1,scheme:I,canonicalRemote:r.canonicalRemote,fingerprint:r.fingerprint,repositoryName:r.repositoryName}}function mt(r){let e=r.metadata?.toolnetIdentity;if(!e||typeof e!="object"||Array.isArray(e))return null;let t=e;return typeof t.fingerprint=="string"?t.fingerprint:null}var D=class{adopt(e,t){let n=Y(w(e));if(!t.id.trim())throw new Error("PROJECT_ADOPTION_INVALID_ID");if(!t.name.trim())throw new Error("PROJECT_ADOPTION_INVALID_NAME");if(!t.remote.trim())throw new Error("PROJECT_ADOPTION_INVALID_REMOTE");if(Se(n)){let c=O(v(n));if(c.id!==t.id)throw new Error(["PROJECT_IDENTITY_ALREADY_EXISTS",`existing=${c.id}`,`requested=${t.id}`].join(" "));return k(c,n)}let o=new Date().toISOString(),s={...t.metadata};t.gitIdentity&&(s.toolnetIdentity=q(t.gitIdentity));let a={version:1,id:t.id.trim(),name:t.name.trim(),remote:t.remote.trim(),rootPath:n,createdAt:t.createdAt??o,updatedAt:o,graphVersion:t.graphVersion??0,memoryVersion:t.memoryVersion??0,metadata:Object.keys(s).length?s:void 0};return _(n,a),k(a,n)}recordGitIdentity(e,t,n={}){let o=this.requireExisting(e),s=v(o.rootPath),a=O(s),c=mt(a);if(c&&c!==t.fingerprint&&!n.allowRebind)throw new Error(["PROJECT_GIT_REMOTE_CHANGED",`existing=${c}`,`current=${t.fingerprint}`,"Use explicit rebind only when this repository identity change is intentional."].join(" "));let d=a.metadata?.toolnetIdentity;return d&&typeof d=="object"&&!Array.isArray(d)&&d.fingerprint===t.fingerprint||(a.metadata={...a.metadata,toolnetIdentity:q(t)},a.updatedAt=new Date().toISOString(),_(o.rootPath,a)),k(a,o.rootPath)}findExisting(e=process.cwd()){let t=w(e),n=Y(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>N(P(n,d))),a=ge(t,s?n:void 0);if(!a)return null;let c=O(v(a));return k(c,a)}requireExisting(e=process.cwd()){let t=this.findExisting(e);if(!t)throw new Error("PROJECT_NOT_INITIALIZED");return t}detect(e=process.cwd()){let t=w(e),n=Y(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(g=>N(P(n,g))),a=ge(t,s?n:void 0);if(a){let g=v(a),u=O(g);return u.rootPath!==a&&(u.rootPath=a,u.updatedAt=new Date().toISOString(),_(a,u)),k(u,a)}let c=new Date().toISOString(),d=dt(n),l=fe(n),m={version:1,id:l?me(l.canonicalRemote):pt(n),name:d,remote:l?.repositoryName??d,rootPath:n,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0,metadata:l?{toolnetIdentity:q(l)}:void 0};return _(n,m),k(m,n)}};var ft=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_-]{20,}\b/g,confidence:"exact"},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g,confidence:"exact"},{type:"aws_access_key",regex:/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/g,confidence:"exact"},{type:"github_token",regex:/\b(?:gh[pousr]_[A-Za-z0-9]{30,255}|github_pat_[A-Za-z0-9_]{40,255})\b/g,confidence:"exact"},{type:"stripe_secret_key",regex:/\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b/g,confidence:"exact"},{type:"google_api_key",regex:/\bAIza[A-Za-z0-9_-]{30,}\b/g,confidence:"exact"},{type:"slack_token",regex:/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/g,confidence:"exact"},{type:"npm_token",regex:/\bnpm_[A-Za-z0-9]{20,}\b/g,confidence:"exact"},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b/gi,confidence:"high"},{type:"jwt",regex:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,confidence:"exact"},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g,confidence:"exact"},{type:"password_assignment",regex:/\b(?:password|passwd|pwd)\s*[:=]\s*["']?[^"' \t\r\n]{6,}["']?/gi,confidence:"high"},{type:"secret_assignment",regex:/\b(?:secret|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\s*[:=]\s*["']?[^"' \t\r\n]{8,}["']?/gi,confidence:"high"},{type:"cookie",regex:/\b(?:cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi,confidence:"high"},{type:"url_credentials",regex:/\bhttps?:\/\/[^:/@\s]+:[^/@\s]{4,}@[^/\s]+/gi,confidence:"high"}],gt=new Set(["example","example-key","example-token","changeme","change-me","password","secret","your-api-key","your-token","<token>","<secret>","<password>","[redacted]"]);function be(r){return r.normalize("NFKC").trim().toLowerCase()}function yt(r){if(r.length===0)return 0;let e=new Map;for(let n of r)e.set(n,(e.get(n)??0)+1);let t=0;for(let n of e.values()){let o=n/r.length;t-=o*Math.log2(o)}return t}function ht(r){return/^[a-f0-9]{32}$/iu.test(r)||/^[a-f0-9]{40}$/iu.test(r)||/^[a-f0-9]{64}$/iu.test(r)}function St(r,e,t){let n=r.slice(Math.max(0,e-48),e),o=r.slice(t,Math.min(r.length,t+16));return/\b(?:token|secret|key|credential|authorization|password|passwd|apikey|api_key|access[_-]?key)\b/iu.test(`${n} ${o}`)}function bt(r,e){return r.start<e.end&&e.start<r.end}function ke(r){return r.sort((e,t)=>e.start!==t.start?e.start-t.start:t.end-t.start-(e.end-e.start))}var $=class{allowValues=new Set;enableEntropyHeuristic;constructor(e={}){for(let t of e.allowValues??[]){let n=be(t);n&&this.allowValues.add(n)}this.enableEntropyHeuristic=e.enableEntropyHeuristic??!0}scan(e){let t=[];for(let s of ft){let a=new RegExp(s.regex.source,s.regex.flags);for(let c of e.matchAll(a))c.index===void 0||!c[0]||this.allowed(c[0])||t.push({type:s.type,value:c[0],start:c.index,end:c.index+c[0].length,confidence:s.confidence})}this.enableEntropyHeuristic&&t.push(...this.entropyMatches(e));let n=ke(t),o=[];for(let s of n)o.some(a=>bt(a,s))||o.push(s);return ke(o)}hasSecrets(e){return this.scan(e).length>0}allowed(e){let t=be(e);return gt.has(t)?!0:this.allowValues.has(t)}entropyMatches(e){let t=[],n=/[A-Za-z0-9_+/=-]{32,160}/g;for(let o of e.matchAll(n)){if(o.index===void 0||!o[0])continue;let s=o[0];this.allowed(s)||ht(s)||!/[A-Za-z]/u.test(s)||!/[0-9]/u.test(s)||St(e,o.index,o.index+s.length)&&(yt(s)<3.7||t.push({type:"high_entropy_secret",value:s,start:o.index,end:o.index+s.length,confidence:"heuristic"}))}return t}};var z=class{scanner;constructor(e={}){this.scanner=new $(e)}sanitize(e){let t=this.scanner.scan(e);if(t.length===0)return{text:e,redacted:0,secretTypes:[]};let n=e,o=[...t].sort((a,c)=>c.start-a.start),s=new Set;for(let a of o)s.add(a.type),n=n.slice(0,a.start)+`[REDACTED:${a.type}]`+n.slice(a.end);return{text:n,redacted:t.length,secretTypes:[...s].sort()}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[n,o]of Object.entries(e)){let s=n.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");if(s.includes("password")||s.includes("passwd")||s==="pwd"||s.includes("secret")||s.includes("token")||s.includes("cookie")||s.includes("authorization")||s.includes("apikey")||s.includes("accesskey")||s.includes("privatekey")||s.includes("clientsecret")||s.includes("credential")){t[n]="[REDACTED]";continue}t[n]=this.sanitizeValue(o)}return t}return e}};var Dr=new z;import{homedir as Vt}from"node:os";import{join as Ft}from"node:path";import{DeleteObjectCommand as kt,GetObjectCommand as wt,HeadObjectCommand as xt,ListObjectsV2Command as vt,PutObjectCommand as Mt,S3Client as jt}from"@aws-sdk/client-s3";import{getSignedUrl as Rt}from"@aws-sdk/s3-request-presigner";var L=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new jt({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,n="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Mt({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await Rt(this.client,new wt({Bucket:this.bucket,Key:e}),{expiresIn:60}),n=await fetch(t,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`HF download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new xt({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new kt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new vt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let s of o.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return t}};import{access as we,mkdir as At,readFile as It,readdir as Pt,rm as Ct,stat as xe,writeFile as Tt}from"node:fs/promises";import{dirname as Et,join as Ot,relative as ve,resolve as _t}from"node:path";var C=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return _t(this.root,t)}async put(e,t){let n=this.path(e);await At(Et(n),{recursive:!0}),await Tt(n,t)}async get(e){try{return await It(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await we(this.path(e)),!0}catch{return!1}}async delete(e){await Ct(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),n=[];try{await we(t)}catch{return n}let o=async a=>{let c=await Pt(a,{withFileTypes:!0});for(let d of c){let l=Ot(a,d.name);if(d.isDirectory()){await o(l);continue}let m=await xe(l);n.push({key:ve(this.root,l),size:m.size,updatedAt:m.mtime.toISOString()})}},s=await xe(t);return s.isDirectory()?await o(t):n.push({key:ve(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),n}};import{DeleteObjectCommand as Nt,GetObjectCommand as Kt,HeadObjectCommand as Dt,ListObjectsV2Command as $t,PutObjectCommand as zt,S3Client as Lt}from"@aws-sdk/client-s3";import{getSignedUrl as Ht}from"@aws-sdk/s3-request-presigner";var T=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Lt({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,n="application/octet-stream"){let o=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new zt({Bucket:this.bucket,Key:e,Body:o,ContentType:n}))}async get(e){let t=await Ht(this.client,new Kt({Bucket:this.bucket,Key:e}),{expiresIn:60}),n=await fetch(t,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`${this.name} download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new Dt({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new Nt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],n;do{let o=await this.client.send(new $t({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:n}));for(let s of o.Contents??[])s.Key&&t.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return t}};function Z(r,e){return console.warn(e),new C(r)}function Me(r){let e=r.localRoot??Ft(Vt(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new T({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):Z(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 T({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):Z(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 L({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):Z(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new C(e)}var H=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"memories","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return[];let n=JSON.parse(t);if(!Array.isArray(n))throw new Error("Invalid memory snapshot");return n}async save(e,t){let n=JSON.stringify(t,null,2);await this.storage.put(this.key(e),n,"application/json")}};function Bt(r){return new Promise(e=>setTimeout(e,r))}async function je(r,e={}){let t=Math.max(1,e.attempts??3),n=e.baseDelayMs??150,o=e.maxDelayMs??2e3,s;for(let a=1;a<=t;a++)try{return await r()}catch(c){if(s=c,a>=t)break;let d=Math.min(o,n*2**(a-1)),l=Math.floor(Math.random()*Math.max(1,d*.2));await Bt(d+l)}throw s}var Wt=new Set(["put","get","getText","delete","list"]);function Re(r,e={}){return new Proxy(r,{get(t,n){let o=Reflect.get(t,n,t);return typeof o!="function"?o:Wt.has(n)?(...s)=>je(()=>Promise.resolve(o.apply(t,s)),e):o.bind(t)}})}function Ae(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 n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let o=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return o?`${o[1]}memory/records/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),o?`${o[1]}memory/vectors/${o[2]}`:(o=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),o?`${o[1]}code/graph/${o[2]}`:e))}var V=class{constructor(e,t,n,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=n,this.folder=Ae(o??n),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),n=t,o=await this.provider.getText(e);if(o){let 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"&&(n=a.createdAt)}let s={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:n,updatedAt:t};await this.provider.put(e,JSON.stringify(s,null,2)+`
4
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=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,n){return await this.ensureRegistered(),this.provider.put(this.key(e),t,n)}async get(e){return await this.ensureRegistered(),this.provider.get(this.key(e))}async getText(e){return await this.ensureRegistered(),this.provider.getText(this.key(e))}async delete(e){return await this.ensureRegistered(),this.provider.delete(this.key(e))}async exists(e){return await this.ensureRegistered(),this.provider.exists(this.key(e))}async list(e){return await this.ensureRegistered(),this.provider.list(this.key(e))}};import{join as Te}from"node:path";import{mkdirSync as Zt}from"node:fs";import{createHash as Jt}from"node:crypto";import{dirname as Gt}from"node:path";import{mkdirSync as Ut,readFileSync as Po,renameSync as Yt,writeFileSync as qt}from"node:fs";function Pe(r){return Jt("sha256").update(r).digest("hex")}function Ce(r,e){Ut(Gt(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;qt(t,JSON.stringify(e,null,2)+`
5
+ `,{encoding:"utf8",mode:384}),Yt(t,r)}function Oe(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function y(r,e=20){let t=[],n=new Set;for(let o of r.slice().reverse()){let s=Oe(o);if(!(!s||n.has(s))&&(n.add(s),t.push(o),t.length>=e))break}return t.reverse()}function Qt(r,e=20){let t=new Map;for(let n of r){let o=`${n.kind}|${Oe(n.command)}`;t.delete(o),t.set(o,n)}return Array.from(t.values()).slice(-e)}function Xt(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 Ee(r,e){let t=e.status??r?.status??"pending",n=t;r&&(r.status==="completed"&&t!=="completed"?n="completed":t==="pending"&&(r.status==="in_progress"||r.status==="blocked")&&(n=r.status));let o=r&&Xt(e)?r.title:e.text;return{id:r?.id??Pe(e.key).slice(0,24),title:o,status:n,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 _e(r,e){let t=`projects/${r.id}/work/observations/`,n=await e.list(t),o=[];for(let s of n.filter(a=>a.key.endsWith(".json")).sort((a,c)=>a.key.localeCompare(c.key))){let a=await e.getText(s.key);if(a)try{let c=JSON.parse(a);c.version===1&&Array.isArray(c.observations)&&o.push(c)}catch{}}return o}async function er(r,e){let n=(await _e(r,e)).flatMap(i=>i.observations).sort((i,f)=>{let ie=i.occurredAt.localeCompare(f.occurredAt);if(ie!==0)return ie;let ae=i.sequence-f.sequence;return ae!==0?ae:i.id.localeCompare(f.id)}),o=new Map,s=new Map,a,c,d,l,m,g=[],u=[],p=[],S=[],M=[],j=new Map,X=[],ee=[],te=[],re=[],ne=[],oe=[];for(let i of n)switch(i.kind){case"request":a=i.text;break;case"activity":c=i.text;break;case"goal":d=i.text;break;case"plan":l=i.text;break;case"phase":o.set(i.key,Ee(o.get(i.key),i));break;case"task":s.set(i.key,Ee(s.get(i.key),i));break;case"decision":g.push(i.text);break;case"blocker":u.push(i.text);break;case"warning":p.push(i.text);break;case"next_action":S.push(i.text);break;case"file":{M.push(i.text);let f=i.fileAction??"active";j.delete(i.text),j.set(i.text,f),f==="modified"?X.push(i.text):f==="created"?ee.push(i.text):f==="deleted"&&te.push(i.text);break}case"command":re.push(i.text);break;case"test":ne.push(i.text),i.checkKind&&oe.push({kind:i.checkKind,command:i.text,status:i.checkStatus??"unknown",updatedAt:i.occurredAt,agent:i.agent,nativeSessionId:i.nativeSessionId});break;case"session":m={agent:i.agent,nativeSessionId:i.nativeSessionId,sessionKey:i.sessionKey,updatedAt:i.occurredAt};break}let b=Array.from(o.values()).sort((i,f)=>(i.order??Number.MAX_SAFE_INTEGER)-(f.order??Number.MAX_SAFE_INTEGER)),h=Array.from(s.values()).sort((i,f)=>(i.order??Number.MAX_SAFE_INTEGER)-(f.order??Number.MAX_SAFE_INTEGER)),J=b.find(i=>i.status==="in_progress")??b.find(i=>i.status==="blocked")??b.find(i=>i.status==="pending"),E=h.find(i=>i.status==="in_progress")??h.find(i=>i.status==="blocked")??h.find(i=>i.status==="pending"),We=y([...S,...E?[E.title]:[],...!E&&J?[J.title]:[],...h.filter(i=>i.status==="pending").slice(0,5).map(i=>i.title)],8),Je=y([...u,...b.filter(i=>i.status==="blocked").map(i=>i.title),...h.filter(i=>i.status==="blocked").map(i=>i.title)],20),G={version:1,projectId:r.id,projectName:r.name,currentRequest:a,currentActivity:c,goal:d,plan:l,phases:b,tasks:h,decisions:y(g,20),blockers:Je,warnings:y(p,20),nextActions:We,filesTouched:y(M,30),activeFiles:Array.from(j.entries()).filter(([,i])=>i!=="deleted").map(([i])=>i).slice(-5),modifiedFiles:y(X,30),createdFiles:y(ee,30),deletedFiles:y(te,30),commands:y(re,20),tests:y(ne,20),checks:Qt(oe,20),currentPhase:J,currentTask:E,progress:{phasesTotal:b.length,phasesCompleted:b.filter(i=>i.status==="completed").length,tasksTotal:h.length,tasksCompleted:h.filter(i=>i.status==="completed").length,blocked:b.filter(i=>i.status==="blocked").length+h.filter(i=>i.status==="blocked").length},lastSession:m,updatedAt:n.length?n[n.length-1].occurredAt:new Date().toISOString()},se=Te(r.rootPath,".toolnet","work");return Zt(se,{recursive:!0}),Ce(Te(se,"current.json"),G),await e.put(`projects/${r.id}/work/current.json`,JSON.stringify(G,null,2)+`
6
+ `,"application/json"),G}async function Ne(r,e){if((await _e(r,e)).length>0)return er(r,e);let n=await e.getText(`projects/${r.id}/work/current.json`);if(!n)return null;try{return JSON.parse(n)}catch{return null}}import{createHash as ar}from"node:crypto";import{hostname as cr}from"node:os";import{createHash as tr,randomUUID as rr}from"node:crypto";function x(r,e){let t=r.trim();if(!t)throw new Error(`${e} is required`);return t}function F(r,e){return encodeURIComponent(x(r,e))}function nr(r){let e=JSON.stringify(r);if(e===void 0)throw new Error("Multi-host operation payload must be JSON serializable");return e}function De(r){return tr("sha256").update(r).digest("hex")}function $e(r){return De(nr(r))}function ze(r){return Number.isFinite(Date.parse(r))}function or(r){return De(JSON.stringify({version:r.version,operationId:r.operationId,projectId:r.projectId,scope:r.scope,hostId:r.hostId,occurredAt:r.occurredAt,payloadSha256:r.payloadSha256,payload:r.payload}))}function Le(r){let e=x(r.projectId,"projectId"),t=x(r.scope,"scope"),n=x(r.hostId,"hostId"),o=x(r.operationId??rr(),"operationId"),s=r.occurredAt??new Date().toISOString();if(!ze(s))throw new Error(`Invalid operation timestamp: ${s}`);return{version:1,operationId:o,projectId:e,scope:t,hostId:n,occurredAt:s,payloadSha256:$e(r.payload),payload:r.payload}}function He(r,e){let t=["projects",F(r,"projectId"),"operations"];return e?`${[...t,F(e,"scope")].join("/")}/`:`${t.join("/")}/`}function sr(r){return[He(r.projectId,r.scope).replace(/\/$/,""),F(r.hostId,"hostId"),`${F(r.operationId,"operationId")}-${r.payloadSha256}.json`].join("/")}async function Ve(r,e){let t=sr(e);return await r.put(t,`${JSON.stringify(e,null,2)}
7
+ `,"application/json"),t}function ir(r){let e;try{e=JSON.parse(r)}catch{return null}return e.version!==1||typeof e.operationId!="string"||typeof e.projectId!="string"||typeof e.scope!="string"||typeof e.hostId!="string"||typeof e.occurredAt!="string"||!ze(e.occurredAt)||typeof e.payloadSha256!="string"||$e(e.payload)!==e.payloadSha256?null:e}function Ke(r,e){let t=r.occurredAt.localeCompare(e.occurredAt);if(t!==0)return t;let n=r.hostId.localeCompare(e.hostId);if(n!==0)return n;let o=r.operationId.localeCompare(e.operationId);return o!==0?o:r.payloadSha256.localeCompare(e.payloadSha256)}async function Fe(r,e,t){let n=x(e,"projectId"),o=x(t,"scope"),s=He(n,o),a=await r.list(s),c=[],d=[];for(let u of a){let p=await r.getText(u.key);if(!p){c.push(u.key);continue}let S=ir(p);if(!S){c.push(u.key);continue}if(S.projectId!==n){c.push(u.key);continue}if(S.scope!==o){c.push(u.key);continue}d.push(S)}let l=new Map;for(let u of d){let p=l.get(u.operationId);if(!p){l.set(u.operationId,[u]);continue}p.push(u)}let m=[],g=[];for(let[u,p]of l){if(new Set(p.map(j=>or(j))).size>1){g.push({operationId:u,variants:[...p].sort(Ke)});continue}let M=p[0];M&&m.push(M)}return m.sort(Ke),g.sort((u,p)=>u.operationId.localeCompare(p.operationId)),c.sort(),{operations:m,conflicts:g,invalidKeys:c}}function ur(r){let t=(r??process.env.TOOLNET_HOST_ID??cr()).trim();return t||`pid-${process.pid}`}function dr(r){let e=t=>{if(t===null||typeof t!="object")return t;if(Array.isArray(t))return t.map(o=>e(o));let n=t;return Object.fromEntries(Object.keys(n).sort().map(o=>[o,e(n[o])]))};return JSON.stringify(e(r))}function B(r){return ar("sha256").update(dr(r)).digest("hex")}function lr(r,e){let t=B(r).slice(0,12),n=B(e);return["memory",t,n].join("-")}function pr(r,e){let t=r.updatedAt.localeCompare(e.updatedAt);if(t!==0)return t;let n=r.createdAt.localeCompare(e.createdAt);return n!==0?n:B(r).localeCompare(B(e))}function mr(r,e){return pr(r,e)>=0?r:e}function Q(r,e){let t=new Map;for(let n of r)t.set(n.id,n);for(let n of e){if(n.payload.kind!=="upsert")continue;let o=n.payload.memory,s=t.get(o.id);if(!s){t.set(o.id,o);continue}t.set(o.id,mr(s,o))}return[...t.values()].sort((n,o)=>n.id.localeCompare(o.id))}var W=class{constructor(e,t={}){this.storage=e;this.legacy=new H(e),this.hostId=ur(t.hostId)}storage;legacy;hostId;diagnostics={operationCount:0,conflicts:0,invalidKeys:0};getDiagnostics(){return{...this.diagnostics}}async operations(e){let t=await Fe(this.storage,e,"memory");return this.diagnostics={operationCount:t.operations.length,conflicts:t.conflicts.length,invalidKeys:t.invalidKeys.length},t.operations}async load(e){let t=await this.legacy.load(e),n=await this.operations(e);return Q(t,n)}async appendMemory(e,t){let n=Le({projectId:e,scope:"memory",hostId:this.hostId,operationId:lr(this.hostId,t),occurredAt:t.updatedAt,payload:{kind:"upsert",memory:t}});await Ve(this.storage,n)}async refreshProjection(e){let t=await this.legacy.load(e),n=await this.operations(e),o=Q(t,n);return await this.legacy.save(e,o),o}async save(e,t){let n=[...t].sort((a,c)=>a.id.localeCompare(c.id));for(let a of n)await this.appendMemory(e,a);let o=await this.operations(e),s=Q(t,o);await this.legacy.save(e,s)}};async function Be(r,e){let t=new Date().toISOString(),o=await new W(e).refreshProjection(r.id),s=await Ne(r,e);return{startedAt:t,finishedAt:new Date().toISOString(),memories:o.length,workAvailable:s!==null}}function fr(r,e){let t=r.indexOf(e);if(!(t<0))return r[t+1]}function gr(r){return{projectPath:fr(r,"--project"),json:r.includes("--json"),quiet:r.includes("--quiet")}}async function yr(r){let e=ce(),t=Re(Me({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new V(t,r.id,r.name,r.remote??r.name)}async function hr(){let r=gr(process.argv.slice(2)),e=r.projectPath??process.cwd(),t=new D().detect(e);if(!t){r.quiet||console.error(`ToolNet project not found: ${e}`),process.exitCode=2;return}let n;try{n=await yr(t)}catch(o){r.quiet||console.error(o instanceof Error?o.message:String(o)),process.exitCode=3;return}try{let o=await Be(t,n);if(r.quiet)return;if(r.json){console.log(JSON.stringify(o));return}console.log(["ToolNet Memory refreshed",`memory=${o.memories}`,`work=${o.workAvailable?"yes":"no"}`].join(" "))}catch(o){r.quiet||console.error(o instanceof Error?o.message:String(o)),process.exitCode=4}}hr().then(()=>{process.exit(process.exitCode??0)});