toolnet-memory 0.2.2 → 0.2.4

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{readFileSync as Ne}from"node:fs";import{existsSync as F,readFileSync as B}from"node:fs";import{homedir as H}from"node:os";import{join as U}from"node:path";function Y(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 G(){let r=process.env.TOOLNET_GLOBAL_ENV??U(H(),".config","toolnet-memory",".env");if(!F(r))return;let e=B(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]=Y(o.slice(n+1)))}}G();function d(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function u(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function R(){return{memory:{autoCapture:d(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:d(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:d(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:d(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:u(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:u(process.env.MEMORY_RERANK_TOP,10),finalContext:u(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:u(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",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:u(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as W}from"node:crypto";import{existsSync as M,mkdirSync as Z,readFileSync as Q,renameSync as X,writeFileSync as q}from"node:fs";import{basename as ee,dirname as l,join as j,parse as k,resolve as g}from"node:path";var T=".toolnet",te="project.json";function re(r){return W("sha256").update(r).digest("hex").slice(0,16)}function S(r){return j(r,T,te)}function oe(r){return M(S(r))}function ne(r){let e=g(r),t=k(e).root;for(;;){if(oe(e))return e;if(e===t)break;let o=l(e);if(o===e)break;e=o}return null}function se(r){let e=g(r),t=k(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(s=>M(j(e,s))))return e;if(e===t)break;let n=l(e);if(n===e)break;e=n}return g(r)}function ie(r){let e;try{e=JSON.parse(Q(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:l(l(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 A(r,e){let t=j(r,T);Z(t,{recursive:!0});let o=S(r),n=`${o}.tmp-${process.pid}`;q(n,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),X(n,o)}function b(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=g(e),o=ne(t);if(o){let p=S(o),c=ie(p);return c.rootPath!==o&&(c.rootPath=o,c.updatedAt=new Date().toISOString(),A(o,c)),b(c,o)}let n=se(t),s=new Date().toISOString(),i=ee(n),a={version:1,id:re(n),name:i,remote:i,rootPath:n,createdAt:s,updatedAt:s,graphVersion:0,memoryVersion:0};return A(n,a),b(a,n)}};import{homedir as xe}from"node:os";import{join as Pe}from"node:path";import{DeleteObjectCommand as ae,GetObjectCommand as ce,HeadObjectCommand as pe,ListObjectsV2Command as ue,PutObjectCommand as me,S3Client as de}from"@aws-sdk/client-s3";import{getSignedUrl as le}from"@aws-sdk/s3-request-presigner";var y=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new de({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 me({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await le(this.client,new ce({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 pe({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 ae({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new ue({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 E,mkdir as ge,readFile as fe,readdir as ye,rm as he,stat as O,writeFile as je}from"node:fs/promises";import{dirname as Se,join as ve,relative as C,resolve as we}from"node:path";var m=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 o=this.path(e);await ge(Se(o),{recursive:!0}),await je(o,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 E(this.path(e)),!0}catch{return!1}}async delete(e){await he(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await E(t)}catch{return o}let n=async i=>{let a=await ye(i,{withFileTypes:!0});for(let p of a){let c=ve(i,p.name);if(p.isDirectory()){await n(c);continue}let P=await O(c);o.push({key:C(this.root,c),size:P.size,updatedAt:P.mtime.toISOString()})}},s=await O(t);return s.isDirectory()?await n(t):o.push({key:C(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),o}};function I(r){let e=r.localRoot??Pe(xe(),".toolnet-memory","storage");if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new y({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new m(e))}return new m(e)}function Re(r){return new Promise(e=>setTimeout(e,r))}async function _(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,n=e.maxDelayMs??2e3,s;for(let i=1;i<=t;i++)try{return await r()}catch(a){if(s=a,i>=t)break;let p=Math.min(n,o*2**(i-1)),c=Math.floor(Math.random()*Math.max(1,p*.2));await Re(p+c)}throw s}var Ae=new Set(["put","get","getText","delete","list"]);function N(r,e={}){return new Proxy(r,{get(t,o){let n=Reflect.get(t,o,t);return typeof n!="function"?n:Ae.has(o)?(...s)=>_(()=>Promise.resolve(n.apply(t,s)),e):n.bind(t)}})}function $(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 z(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 h=class{constructor(e,t,o,n){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=$(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 i;try{i=JSON.parse(n)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(o=i.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=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,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{existsSync as V,mkdirSync as Me,readFileSync as ke,statSync as D,writeFileSync as Te}from"node:fs";import{dirname as Ee,join as Oe}from"node:path";import{createHash as be}from"node:crypto";function v(r){return be("sha256").update(r).digest("hex")}var L=64*1024,Ce=`# ToolNet Project Operating Manual
1
+ import{readFileSync as $e}from"node:fs";import{existsSync as B,readFileSync as H}from"node:fs";import{homedir as U}from"node:os";import{join as Y}from"node:path";function G(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 W(){let r=process.env.TOOLNET_GLOBAL_ENV??Y(U(),".config","toolnet-memory",".env");if(!B(r))return;let e=H(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]=G(o.slice(n+1)))}}W();function f(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function d(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function b(){return{memory:{autoCapture:f(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:f(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:f(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:f(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:d(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:d(process.env.MEMORY_RERANK_TOP,10),finalContext:d(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:d(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",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:d(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Z}from"node:crypto";import{existsSync as w,mkdirSync as Q,readFileSync as X,renameSync as q,writeFileSync as ee}from"node:fs";import{basename as te,dirname as y,join as j,parse as T,resolve as l}from"node:path";var E=".toolnet",re="project.json";function oe(r){return Z("sha256").update(r).digest("hex").slice(0,16)}function x(r){return j(r,E,re)}function ne(r){return w(x(r))}function se(r,e){let t=l(r),o=T(t).root;for(;;){if(ne(t))return t;if(t===o||e&&t===l(e))break;let n=y(t);if(n===t)break;t=n}return null}function ie(r){let e=l(r),t=T(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(s=>w(j(e,s))))return e;if(e===t)break;let n=y(e);if(n===e)break;e=n}return l(r)}function ae(r){let e;try{e=JSON.parse(X(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:y(y(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 M(r,e){let t=j(r,E);Q(t,{recursive:!0});let o=x(r),n=`${o}.tmp-${process.pid}`;ee(n,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),q(n,o)}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}}var h=class{detect(e=process.cwd()){let t=l(e),o=ie(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>w(j(o,u))),i=se(t,s?o:void 0);if(i){let u=x(i),m=ae(u);return m.rootPath!==i&&(m.rootPath=i,m.updatedAt=new Date().toISOString(),M(i,m)),k(m,i)}let a=new Date().toISOString(),c=te(o),p={version:1,id:oe(o),name:c,remote:c,rootPath:o,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return M(o,p),k(p,o)}};import{homedir as Pe}from"node:os";import{join as Re}from"node:path";import{DeleteObjectCommand as ce,GetObjectCommand as pe,HeadObjectCommand as ue,ListObjectsV2Command as me,PutObjectCommand as de,S3Client as le}from"@aws-sdk/client-s3";import{getSignedUrl as ge}from"@aws-sdk/s3-request-presigner";var S=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,o="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:o}))}async get(e){let t=await ge(this.client,new pe({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 ue({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=[],o;do{let n=await this.client.send(new me({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 O,mkdir as fe,readFile as ye,readdir as he,rm as je,stat as C,writeFile as Se}from"node:fs/promises";import{dirname as ve,join as we,relative as I,resolve as xe}from"node:path";var g=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return xe(this.root,t)}async put(e,t){let o=this.path(e);await fe(ve(o),{recursive:!0}),await Se(o,t)}async get(e){try{return await ye(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 O(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),o=[];try{await O(t)}catch{return o}let n=async i=>{let a=await he(i,{withFileTypes:!0});for(let c of a){let p=we(i,c.name);if(c.isDirectory()){await n(p);continue}let u=await C(p);o.push({key:I(this.root,p),size:u.size,updatedAt:u.mtime.toISOString()})}},s=await C(t);return s.isDirectory()?await n(t):o.push({key:I(this.root,t),size:s.size,updatedAt:s.mtime.toISOString()}),o}};function _(r){let e=r.localRoot??Re(Pe(),".toolnet-memory","storage");if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new S({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new g(e))}return new g(e)}function Ae(r){return new Promise(e=>setTimeout(e,r))}async function N(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,n=e.maxDelayMs??2e3,s;for(let i=1;i<=t;i++)try{return await r()}catch(a){if(s=a,i>=t)break;let c=Math.min(n,o*2**(i-1)),p=Math.floor(Math.random()*Math.max(1,c*.2));await Ae(c+p)}throw s}var be=new Set(["put","get","getText","delete","list"]);function $(r,e={}){return new Proxy(r,{get(t,o){let n=Reflect.get(t,o,t);return typeof n!="function"?n:be.has(o)?(...s)=>N(()=>Promise.resolve(n.apply(t,s)),e):n.bind(t)}})}function z(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 D(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 v=class{constructor(e,t,o,n){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=z(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 i;try{i=JSON.parse(n)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(o=i.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=D(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{existsSync as J,mkdirSync as ke,readFileSync as Te,statSync as L,writeFileSync as Ee}from"node:fs";import{dirname as Oe,join as Ce}from"node:path";import{createHash as Me}from"node:crypto";function P(r){return Me("sha256").update(r).digest("hex")}var V=64*1024,Ie=`# ToolNet Project Operating Manual
5
5
 
6
6
  This file contains persistent instructions for AI agents working on this project.
7
7
 
@@ -44,11 +44,11 @@ Things an AI agent should always remember.
44
44
  <!--
45
45
  - [advisory] Prefer small focused files.
46
46
  -->
47
- `;function J(r){return Oe(r.rootPath,".toolnet","PROJECT.md")}function Ie(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function _e(r){let e=[],t=new Set,o=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,n;for(;n=o.exec(r);){let s=n[1].toLowerCase(),i=Ie(n[2]);if(!i)continue;let a=`${s}:${i.toLowerCase()}`;t.has(a)||(t.add(a),e.push({id:v(a).slice(0,24),mode:s,text:i,source:"manual"}))}return e}function w(r){let e=J(r);return V(e)||(Me(Ee(e),{recursive:!0}),Te(e,Ce,{encoding:"utf8",mode:384})),e}function x(r,e=!1){let t=e?w(r):J(r);if(!V(t))return null;if(D(t).size>L)throw new Error(`PROJECT.md exceeds ${L} bytes`);let n=ke(t,"utf8");return{path:t,content:n,digest:v(n),rules:_e(n),bytes:Buffer.byteLength(n,"utf8"),updatedAt:new Date(D(t).mtimeMs).toISOString()}}async function K(r,e){let t=x(r,!0);if(!t)throw new Error("Project manual unavailable");let o=`projects/${r.id}/project`;return await e.put(`${o}/manual.md`,t.content,"text/markdown"),await e.put(`${o}/manual.json`,JSON.stringify({version:1,projectId:r.id,projectName:r.name,digest:t.digest,bytes:t.bytes,ruleCount:t.rules.length,enforceRules:t.rules.filter(n=>n.mode==="enforce").length,advisoryRules:t.rules.filter(n=>n.mode==="advisory").length,updatedAt:t.updatedAt},null,2)+`
48
- `,"application/json"),t}function $e(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function ze(r){let e=R(),t=N(I({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new h(t,r.id,r.name,r.remote??r.name)}async function De(){let[r="help",...e]=process.argv.slice(2),t=new f().detect($e(e,"--project")??process.cwd());if(r==="init"){let o=w(t);console.log(`\u2705 Project manual: ${o}`);return}if(r==="show"){let o=x(t,!1);if(!o){console.log("No .toolnet/PROJECT.md yet.");return}process.stdout.write(Ne(o.path,"utf8"));return}if(r==="sync"){let o=await K(t,ze(t));console.log(JSON.stringify({project:t.name,path:o.path,digest:o.digest,bytes:o.bytes,rules:o.rules.length,enforce:o.rules.filter(n=>n.mode==="enforce").length,advisory:o.rules.filter(n=>n.mode==="advisory").length},null,2));return}console.log(`Project Manual
47
+ `;function K(r){return Ce(r.rootPath,".toolnet","PROJECT.md")}function _e(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function Ne(r){let e=[],t=new Set,o=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,n;for(;n=o.exec(r);){let s=n[1].toLowerCase(),i=_e(n[2]);if(!i)continue;let a=`${s}:${i.toLowerCase()}`;t.has(a)||(t.add(a),e.push({id:P(a).slice(0,24),mode:s,text:i,source:"manual"}))}return e}function R(r){let e=K(r);return J(e)||(ke(Oe(e),{recursive:!0}),Ee(e,Ie,{encoding:"utf8",mode:384})),e}function A(r,e=!1){let t=e?R(r):K(r);if(!J(t))return null;if(L(t).size>V)throw new Error(`PROJECT.md exceeds ${V} bytes`);let n=Te(t,"utf8");return{path:t,content:n,digest:P(n),rules:Ne(n),bytes:Buffer.byteLength(n,"utf8"),updatedAt:new Date(L(t).mtimeMs).toISOString()}}async function F(r,e){let t=A(r,!0);if(!t)throw new Error("Project manual unavailable");let o=`projects/${r.id}/project`;return await e.put(`${o}/manual.md`,t.content,"text/markdown"),await e.put(`${o}/manual.json`,JSON.stringify({version:1,projectId:r.id,projectName:r.name,digest:t.digest,bytes:t.bytes,ruleCount:t.rules.length,enforceRules:t.rules.filter(n=>n.mode==="enforce").length,advisoryRules:t.rules.filter(n=>n.mode==="advisory").length,updatedAt:t.updatedAt},null,2)+`
48
+ `,"application/json"),t}function ze(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function De(r){let e=b(),t=$(_({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 Le(){let[r="help",...e]=process.argv.slice(2),t=new h().detect(ze(e,"--project")??process.cwd());if(r==="init"){let o=R(t);console.log(`\u2705 Project manual: ${o}`);return}if(r==="show"){let o=A(t,!1);if(!o){console.log("No .toolnet/PROJECT.md yet.");return}process.stdout.write($e(o.path,"utf8"));return}if(r==="sync"){let o=await F(t,De(t));console.log(JSON.stringify({project:t.name,path:o.path,digest:o.digest,bytes:o.bytes,rules:o.rules.length,enforce:o.rules.filter(n=>n.mode==="enforce").length,advisory:o.rules.filter(n=>n.mode==="advisory").length},null,2));return}console.log(`Project Manual
49
49
 
50
50
  Commands:
51
51
  init [--project PATH]
52
52
  show [--project PATH]
53
53
  sync [--project PATH]
54
- `)}De().catch(r=>{console.error(r instanceof Error?r.message:r),process.exit(1)});
54
+ `)}Le().catch(r=>{console.error(r instanceof Error?r.message:r),process.exit(1)});
@@ -0,0 +1,11 @@
1
+ import{randomUUID as Nt}from"node:crypto";var Pt={critical:100,high:75,normal:50,temporary:20};function He(o){return Pt[o]}function Ke(o,e){let t=e.toLowerCase();return t.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||t.includes("b\u1EAFt bu\u1ED9c")||t.includes("must not")||t.includes("critical")?"critical":o==="rule"||o==="decision"?"high":o==="todo"?"normal":o==="activity"||o==="summary"?"temporary":"normal"}var Rt=[{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 r of Rt){let s=new RegExp(r.regex.source,r.regex.flags);for(let n of e.matchAll(s))t.push({type:r.type,value:n[0]})}return t}hasSecrets(e){return this.scan(e).length>0}};var P=class{scanner=new _;sanitize(e){let t=e,r=this.scanner.scan(e),s=new Set;for(let n of r)s.add(n.type),t=t.split(n.value).join(`[REDACTED:${n.type}]`);return{text:t,redacted:r.length,secretTypes:[...s]}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[r,s]of Object.entries(e)){let n=r.toLowerCase();n.includes("password")||n.includes("secret")||n.includes("token")||n.includes("cookie")||n.includes("authorization")?t[r]="[REDACTED]":t[r]=this.sanitizeValue(s)}return t}return e}};var kt=new Set(["decision","rule","todo","summary","activity","user","error","file","write","command","learned","session","architecture","fix","context","opencode","agy","codex"]),Tt=new Set(["d\xF9ng","s\u1EED","d\u1EE5ng","use","using","the","a","an","cho","v\xE0","l\xE0","c\u1EE7a","to","for","with","quy\u1EBFt","\u0111\u1ECBnh"]);function We(o){return new Set(o.toLowerCase().normalize("NFKC").replace(/[^\p{L}\p{N}_-]+/gu," ").split(/\s+/).filter(e=>e.length>2&&!Tt.has(e)))}function Mt(o,e){let t=We(o),r=We(e);if(t.size===0||r.size===0)return 0;let s=0;for(let i of t)r.has(i)&&s++;let n=new Set([...t,...r]).size;return s/n}function Ve(o){return new Set(o.tags.filter(e=>!kt.has(e.toLowerCase())))}var G=class{findSuperseded(e,t){if(e.type!=="rule"&&e.type!=="decision")return[];let r=typeof e.metadata?.topic=="string"?e.metadata.topic:void 0,s=Ve(e);return t.filter(n=>{if(n.id===e.id||n.projectId!==e.projectId||n.type!==e.type||n.metadata?.supersededBy)return!1;let i=typeof n.metadata?.topic=="string"?n.metadata.topic:void 0;if(r&&i&&r===i)return!0;let a=Ve(n);for(let c of s)if(a.has(c))return!0;return Mt(e.content,n.content)>=.6})}};var It={critical:100,high:75,normal:50,temporary:20},At={activity:14,summary:30,todo:90,decision:365,rule:730,code:180};function Ue(o,e,t=new Date){let r;if(e==="temporary"&&(r=30),o==="activity"&&(r=Math.min(r??14,14)),o==="summary"&&(r=Math.min(r??30,30)),!!r)return new Date(t.getTime()+r*864e5).toISOString()}function Pe(o,e=Date.now()){return o.expiresAt?new Date(o.expiresAt).getTime()<=e:!1}function Lt(o){return!!o.metadata?.supersededBy}function Re(o,e=Date.now()){return!Pe(o,e)&&!Lt(o)}function M(o,e=Date.now()){if(!Re(o,e))return 0;let t=It[o.importance];if(o.importance==="critical")return t;let r=At[o.type]??180,n=Math.max(0,e-new Date(o.updatedAt).getTime())/864e5,i=Math.pow(.5,n/r);return t*i}var R=class{memories=new Map;sanitizer=new P;conflicts=new G;remember(e){let t=new Date().toISOString(),r=this.sanitizer.sanitize(e.content.trim()).text,s=e.importance??Ke(e.type,r),n={id:Nt(),projectId:e.projectId,type:e.type,content:r,importance:s,importanceScore:He(s),tags:e.tags??[],source:e.source??"agent",createdAt:t,updatedAt:t,expiresAt:e.expiresAt??Ue(e.type,s,new Date(t)),metadata:this.sanitizer.sanitizeValue(e.metadata)},i=this.conflicts.findSuperseded(n,this.list(e.projectId));if(i.length){n.metadata={...n.metadata??{},supersedes:i.map(a=>a.id)};for(let a of i)a.updatedAt=t,a.metadata={...a.metadata??{},supersededBy:n.id,supersededAt:t},this.memories.set(a.id,a)}return this.memories.set(n.id,n),n}importRecords(e){let t=0;for(let r of e)r?.id&&(this.memories.set(r.id,r),t++);return t}exportProject(e){return this.listAll(e)}get(e){return this.memories.get(e)}delete(e){return this.memories.delete(e)}listAll(e){return[...this.memories.values()].filter(t=>t.projectId===e).sort((t,r)=>r.createdAt.localeCompare(t.createdAt))}list(e){return this.listAll(e).filter(t=>Re(t))}recent(e,t=10){return this.list(e).slice(0,t)}byType(e,t){return this.list(e).filter(r=>r.type===t)}search(e){let t=e.query.trim().toLowerCase(),r=e.limit??10,s=t.split(/\s+/).filter(Boolean);return this.list(e.projectId).filter(n=>{if(e.types&&!e.types.includes(n.type))return!1;let i=M(n);return!(e.minImportanceScore&&i<e.minImportanceScore||e.tags?.length&&!e.tags.some(c=>n.tags.includes(c)))}).map(n=>{let i=n.content.toLowerCase(),a=s.filter(p=>i.includes(p)).length,c=s.length===0?0:a/s.length,l=M(n)/500;return{memory:n,score:c+l,source:"memory"}}).filter(n=>t.length===0||n.score>0).sort((n,i)=>i.score-n.score).slice(0,r)}pruneExpired(e,t=Date.now()){let r=0;for(let[s,n]of this.memories)n.projectId===e&&Pe(n,t)&&(this.memories.delete(s),r++);return r}pruneSuperseded(e,t=30,r=Date.now()){let s=0,n=t*864e5;for(let[i,a]of this.memories){if(a.projectId!==e)continue;let c=a.metadata?.supersededAt;if(typeof c!="string")continue;r-new Date(c).getTime()>=n&&(this.memories.delete(i),s++)}return s}clearProject(e){let t=0;for(let[r,s]of this.memories)s.projectId===e&&(this.memories.delete(r),t++);return t}};var D=class{constructor(e){this.memory=e}memory;run(e){let t=this.memory.pruneExpired(e),r=this.memory.pruneSuperseded(e,30);return{expiredRemoved:t,supersededRemoved:r,active:this.memory.list(e).length,total:this.memory.listAll(e).length}}};function ke(o){return[...new Set(o.filter(Boolean))]}var z=class{constructor(e){this.memory=e}memory;consolidate(e,t={}){let r=t.minItems??4,s=t.maxItems??50,n=t.retentionDays??90,i=this.memory.byType(e,"activity").slice(0,s);if(i.length<r)return{scanned:i.length,consolidated:0,summaryCreated:!1};let a=this.buildSummary(i),c=new Date,l=new Date(c.getTime()+n*864e5).toISOString(),p=this.memory.remember({projectId:e,type:"summary",content:a,importance:"normal",tags:["consolidated","activity-summary"],source:"auto-consolidation",expiresAt:l,metadata:{consolidatedFrom:i.map(u=>u.id),itemCount:i.length}}),d=c.toISOString();for(let u of i){let f=this.memory.get(u.id);f&&(f.updatedAt=d,f.metadata={...f.metadata??{},consolidated:!0,supersededBy:p.id,supersededAt:d})}return{scanned:i.length,consolidated:i.length,summaryCreated:!0,summaryId:p.id}}buildSummary(e){let t=ke(e.filter(i=>i.content.startsWith("Modified file:")).map(i=>i.content.replace("Modified file:","").trim())),r=ke(e.filter(i=>i.content.startsWith("Command:")).map(i=>i.content.replace("Command:","").trim())),s=ke(e.filter(i=>i.content.startsWith("Error:")).map(i=>i.content.replace("Error:","").trim())),n=["Activity consolidation:",`- Activities: ${e.length}`];return t.length&&n.push(`- Files changed: ${t.slice(0,15).join(", ")}`),r.length&&n.push(`- Commands: ${r.slice(0,10).join("; ")}`),s.length&&n.push(`- Errors: ${s.slice(0,10).join("; ")}`),n.join(`
2
+ `)}};function B(o){return o.toLowerCase().normalize("NFKC").replace(/[^\p{L}\p{N}_\-./]+/gu," ").split(/\s+/).map(e=>e.trim()).filter(e=>e.length>1)}var H=class{score(e,t){let r=B(e),s=B([t.content,...t.tags??[],t.type].join(" "));if(r.length===0||s.length===0)return 0;let n=new Map;for(let a of s)n.set(a,(n.get(a)??0)+1);let i=0;for(let a of r){let c=n.get(a)??0;c!==0&&(i+=1+Math.log(1+c))}return i/r.length}};function qe(o,e=Date.now()){let t=o.updatedAt??o.createdAt,r=new Date(t).getTime();if(!Number.isFinite(r))return 0;let s=Math.max(0,e-r)/864e5;return Math.exp(-Math.LN2*s/30)}function Je(o){return M(o)/100}var Ot={rule:1,decision:.9,todo:.8,summary:.6,activity:.3};function Ye(o){return Ot[o]??.4}var K=class{analyze(e){let t=e.toLowerCase(),r=[];return(t.includes("quy\u1EBFt \u0111\u1ECBnh")||t.includes("decision")||t.includes("\u0111\xE3 ch\u1ECDn"))&&r.push("decision"),(t.includes("todo")||t.includes("c\u1EA7n l\xE0m")||t.includes("ti\u1EBFp theo")||t.includes("ch\u01B0a xong"))&&r.push("todo"),(t.includes("quy t\u1EAFc")||t.includes("rule")||t.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||t.includes("b\u1EAFt bu\u1ED9c"))&&r.push("rule"),(t.includes("t\xF3m t\u1EAFt")||t.includes("summary")||t.includes("\u0111\xE3 l\xE0m"))&&r.push("summary"),{query:e,preferredTypes:r}}};var W=class{bm25=new H;analyzer=new K;search(e,t,r={}){let s=r.topK??8,n=r.minScore??.05,i=this.analyzer.analyze(e),a=[];for(let c of t){if(r.types?.length&&!r.types.includes(c.type))continue;let l=this.bm25.score(e,c),p=qe(c),d=Je(c),u=Ye(c.type);i.preferredTypes.includes(c.type)&&(u=Math.min(1,u+.25));let f=l*.55+d*.2+p*.15+u*.1;l<=0||f<n||a.push({memory:c,score:f,scores:{keyword:l,recency:p,importance:d,type:u}})}return a.sort((c,l)=>l.score-c.score).slice(0,s)}};var V=class{build(e,t=6e3){let r=[],s=0;for(let n of e){let i=n.memory,a=[`[${i.type.toUpperCase()}]`,i.content].join(" ");if(s+a.length>t)break;r.push(a),s+=a.length}return r.join(`
3
+ `)}};var U=class{constructor(e){this.memory=e}memory;searcher=new W;contextBuilder=new V;search(e,t,r={}){return this.searcher.search(t,this.memory.list(e),r)}context(e,t,r={}){let s=this.search(e,t,r);return this.contextBuilder.build(s)}};var q=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`,r=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(!r.ok)throw new Error(`HF embedding failed: ${r.status} ${await r.text()}`);let s=await r.json();if(!Array.isArray(s))throw new Error("HF embedding returned invalid response");return s.map(n=>Ft(n))}};function Ft(o){if(!Array.isArray(o))throw new Error("Invalid embedding");if(o.length>0&&typeof o[0]=="number")return o;if(o.length>0&&Array.isArray(o[0])){let e=o;if(e.length===0)return[];let t=e[0].length,r=new Array(t).fill(0);for(let s of e)for(let n=0;n<t;n++)r[n]+=s[n]??0;for(let s=0;s<t;s++)r[s]/=e.length;return r}throw new Error("Unsupported embedding shape")}import{createHash as $t}from"node:crypto";var J=class{name="hash-fallback";dimensions=128;async embed(e){let t=new Array(this.dimensions).fill(0),r=e.toLowerCase().split(/\s+/).filter(Boolean);for(let s of r){let i=$t("sha256").update(s).digest().readUInt32BE(0)%this.dimensions;t[i]+=1}return _t(t)}async embedMany(e){return Promise.all(e.map(t=>this.embed(t)))}};function _t(o){let e=Math.sqrt(o.reduce((t,r)=>t+r*r,0));return e===0?o:o.map(t=>t/e)}var Te=class{constructor(e,t=new J){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 Me(){let o=process.env.HF_TOKEN,e=process.env.HF_EMBEDDING_MODEL??"sentence-transformers/all-MiniLM-L6-v2",t=o?new q({token:o,model:e}):null;return new Te(t)}import{readdir as Bt}from"node:fs/promises";import{extname as Ht,join as Kt,relative as Wt}from"node:path";import{basename as Gt}from"node:path";var Dt=new Set([".env",".env.local",".env.production",".env.development","id_rsa","id_ed25519","credentials","credentials.json","service-account.json"]),zt=new Set([".pem",".key",".p12",".pfx"]);function Ie(o){let e=Gt(o).toLowerCase();if(Dt.has(e))return!0;for(let t of zt)if(e.endsWith(t))return!0;return!1}var Vt=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".mts",".cts"]),Ut=new Set(["node_modules",".git","dist","build","coverage",".next",".cache",".toolnet-memory"]);async function Ae(o){let e=[];async function t(r){let s=await Bt(r,{withFileTypes:!0});for(let n of s){if(Ut.has(n.name))continue;let i=Kt(r,n.name);if(n.isDirectory()){await t(i);continue}Vt.has(Ht(n.name))&&(Ie(i)||e.push(Wt(o,i)))}}return await t(o),e.sort()}import{readFile as qt}from"node:fs/promises";import{join as Jt}from"node:path";import{createHash as Yt}from"node:crypto";import v from"typescript";function Ze(o,e){return Yt("sha256").update(`${o}:${e}`).digest("hex").slice(0,24)}function Le(o,e){return o.getLineAndCharacterOfPosition(e.getStart(o)).line+1}async function Ne(o,e,t){let r=Jt(e,t),s=await qt(r,"utf8"),n=v.createSourceFile(t,s,v.ScriptTarget.Latest,!0,t.endsWith(".tsx")||t.endsWith(".jsx")?v.ScriptKind.TSX:v.ScriptKind.TS),i=[],a=[],c=[],l=[],p={id:Ze(o,`file:${t}`),projectId:o,name:t,qualifiedName:t,type:"file",filePath:t,startLine:1,endLine:n.getLineAndCharacterOfPosition(n.end).line+1};i.push(p);let d=[],u=[];function f(m,S,b,y){let E=Ze(o,`${t}:${b}:${y??S}:${m.pos}`);return i.push({id:E,projectId:o,name:S,qualifiedName:y??S,type:b,filePath:t,startLine:Le(n,m),endLine:n.getLineAndCharacterOfPosition(m.end).line+1}),E}function x(m){if(!v.isStringLiteral(m.moduleSpecifier))return;let S=[],b=m.importClause;if(b?.name&&S.push({localName:b.name.text,importedName:"default",kind:"default"}),b?.namedBindings&&v.isNamedImports(b.namedBindings))for(let y of b.namedBindings.elements)S.push({localName:y.name.text,importedName:y.propertyName?.text??y.name.text,kind:"named"});b?.namedBindings&&v.isNamespaceImport(b.namedBindings)&&S.push({localName:b.namedBindings.name.text,importedName:"*",kind:"namespace"}),a.push({source:m.moduleSpecifier.text,bindings:S})}function h(m,S){for(let b of m.heritageClauses??[])for(let y of b.types){let E=y.expression.getText(n).split(".").at(-1)??"";E&&l.push({fromId:S,targetName:E,type:b.token===v.SyntaxKind.ExtendsKeyword?"INHERITS":"IMPLEMENTS"})}}function g(m){let S=!1,b=!1;if(v.isImportDeclaration(m)&&x(m),v.isInterfaceDeclaration(m)&&f(m,m.name.text,"interface",m.name.text),v.isClassDeclaration(m)&&m.name){let y=f(m,m.name.text,"class",m.name.text);h(m,y),u.push({id:y,name:m.name.text}),b=!0}if(v.isFunctionDeclaration(m)&&m.name){let y=f(m,m.name.text,"function",m.name.text);d.push(y),S=!0}if(v.isMethodDeclaration(m)&&m.name){let y=m.name.getText(n),E=u.at(-1)?.name,jt=f(m,y,"method",E?`${E}.${y}`:y);d.push(jt),S=!0}if(v.isCallExpression(m)&&(v.isIdentifier(m.expression)&&c.push({callerId:d.at(-1),calleeName:m.expression.text,line:Le(n,m)}),v.isPropertyAccessExpression(m.expression))){let y=m.expression;c.push({callerId:d.at(-1),qualifier:y.expression.getText(n),calleeName:y.name.text,line:Le(n,m)})}v.forEachChild(m,g),S&&d.pop(),b&&u.pop()}return g(n),{filePath:t,symbols:i,imports:a,calls:c,heritage:l}}import{createHash as Zt}from"node:crypto";import{dirname as Qt,extname as Xt,normalize as er,posix as tr}from"node:path";var C=class{symbols=new Map;edges=new Map;addSymbol(e){this.symbols.set(e.id,e)}addEdge(e){this.edges.set(e.id,e)}getSymbol(e){return this.symbols.get(e)}findByName(e,t){return[...this.symbols.values()].filter(r=>r.projectId===e&&(r.name===t||r.qualifiedName===t))}allSymbols(e){return[...this.symbols.values()].filter(t=>t.projectId===e)}allEdges(e){return[...this.edges.values()].filter(t=>t.projectId===e)}import(e,t){for(let r of e)this.addSymbol(r);for(let r of t)this.addEdge(r)}clearProject(e){for(let[t,r]of this.symbols)r.projectId===e&&this.symbols.delete(t);for(let[t,r]of this.edges)r.projectId===e&&this.edges.delete(t)}};function rr(o,e,t,r){return Zt("sha256").update(`${o}:${e}:${t}:${r}`).digest("hex").slice(0,24)}function j(o){return er(o).replaceAll("\\","/")}function Oe(o,e,t){if(!e.startsWith("."))return;let r=j(tr.join(Qt(o),e)),s=Xt(r),n;if(s===".js"){let i=r.slice(0,-3);n=[`${i}.ts`,`${i}.tsx`,`${i}.js`,`${i}.jsx`]}else if(s===".mjs"){let i=r.slice(0,-4);n=[`${i}.mts`,`${i}.ts`,`${i}.mjs`]}else if(s===".cjs"){let i=r.slice(0,-4);n=[`${i}.cts`,`${i}.ts`,`${i}.cjs`]}else s?n=[r]:n=[`${r}.ts`,`${r}.tsx`,`${r}.mts`,`${r}.cts`,`${r}.js`,`${r}.jsx`,`${r}.mjs`,`${r}.cjs`,`${r}/index.ts`,`${r}/index.tsx`,`${r}/index.js`,`${r}/index.jsx`];return n.find(i=>t.has(j(i)))}var I=class{build(e,t){let r=new C,s=new Map;for(let i of t)for(let a of i.symbols)r.addSymbol(a),a.type==="file"&&s.set(j(i.filePath),a);let n=new Set(s.keys());for(let i of t){let a=j(i.filePath),c=s.get(a);if(c){for(let l of i.symbols)l.id!==c.id&&r.addEdge(this.edge(e,c.id,"DEFINES",l.id));for(let l of i.imports){let p=Oe(a,l.source,n);if(!p)continue;let d=s.get(p);d&&r.addEdge(this.edge(e,c.id,"IMPORTS",d.id,{source:l.source}))}for(let l of i.heritage){let p=r.findByName(e,l.targetName).filter(d=>d.type==="class"||d.type==="interface");for(let d of p)r.addEdge(this.edge(e,l.fromId,l.type,d.id))}for(let l of i.calls){if(!l.callerId)continue;let p=this.resolveCallTargets(e,i,l.calleeName,l.qualifier,t,r,n);for(let d of p)d.id!==l.callerId&&r.addEdge(this.edge(e,l.callerId,"CALLS",d.id,{line:l.line,qualifier:l.qualifier}))}}}return r}resolveCallTargets(e,t,r,s,n,i,a){let c=j(t.filePath),l=i.findByName(e,r).filter(p=>j(p.filePath)===c);if(!s&&l.length)return l;if(s)for(let p of t.imports){if(!p.bindings.find(f=>f.kind==="namespace"&&f.localName===s))continue;let u=Oe(c,p.source,a);if(u)return i.findByName(e,r).filter(f=>j(f.filePath)===u)}for(let p of t.imports){let d=p.bindings.find(h=>h.localName===r);if(!d)continue;let u=Oe(c,p.source,a);if(!u)continue;let f=d.importedName==="default"?r:d.importedName,x=i.findByName(e,f).filter(h=>j(h.filePath)===u);if(x.length)return x}return i.findByName(e,r).filter(p=>p.type==="function"||p.type==="method")}edge(e,t,r,s,n){return{id:rr(e,t,r,s),projectId:e,from:t,to:s,type:r,metadata:n}}};function Qe(o,e){let t=o.allSymbols(e),r=o.allEdges(e),s=i=>t.filter(a=>a.type===i).length,n=i=>r.filter(a=>a.type===i).length;return{files:s("file"),classes:s("class"),interfaces:s("interface"),functions:s("function"),methods:s("method"),properties:s("property"),routes:s("route"),symbols:t.length,edges:r.length,calls:n("CALLS"),callReferences:n("CALL_REFERENCE"),imports:n("IMPORTS"),inherits:n("INHERITS"),implements:n("IMPLEMENTS"),usesType:n("USES_TYPE"),tests:n("TESTS"),routeEdges:n("ROUTE"),writes:n("WRITES")}}var Y=class{constructor(e){this.graph=e}graph;findSymbol(e,t){return this.graph.findByName(e,t)}findCallers(e,t){return this.graph.allEdges(e).filter(s=>s.type==="CALLS"&&s.to===t).map(s=>s.from).map(s=>this.graph.getSymbol(s)).filter(s=>!!s)}};function or(o,e){return e.ranges.length===0?!0:typeof o.startLine!="number"||typeof o.endLine!="number"?!1:e.ranges.some(t=>o.startLine<=t.endLine&&o.endLine>=t.startLine)}var Z=class{constructor(e){this.graph=e}graph;map(e,t){let r=this.graph.allSymbols(e),s=[];for(let n of t){let i=r.filter(l=>l.filePath===n.filePath),c=i.filter(l=>l.type!=="file").filter(l=>or(l,n));if(c.length===0){let l=i.find(p=>p.type==="file");l&&s.push({symbol:l,fileStatus:n.status,direct:!0});continue}for(let l of c)s.push({symbol:l,fileStatus:n.status,direct:!0})}return s}mapFile(e,t){return this.map(e,[{filePath:t,status:"modified",ranges:[]}])}};var sr={CALLS:4,CALL_REFERENCE:6,USES_TYPE:4,TESTS:2,ROUTE:4,WRITES:3,IMPORTS:3,INHERITS:5,IMPLEMENTS:5,DEFINES:1};function nr(o){return o>=30?"CRITICAL":o>=16?"HIGH":o>=6?"MEDIUM":"LOW"}function Xe(o){let e=o.toLowerCase().replaceAll("\\","/");return e.startsWith("tests/")||e.includes("/tests/")||e.includes("__tests__")||/\.(test|spec)\.[^.]+$/.test(e)}var Q=class{constructor(e){this.graph=e}graph;analyze(e,t,r=4){let s=this.graph.allEdges(e),n=new Map,i=0;for(let p of t){p.fileStatus==="deleted"?i+=8:p.fileStatus==="renamed"?i+=5:i+=2,p.symbol.type==="interface"&&(i+=5),p.symbol.type==="class"&&(i+=3);let d=new Set([p.symbol.id]),u=[{id:p.symbol.id,depth:0}];for(;u.length;){let f=u.shift();if(f.depth>=r)continue;let x=s.filter(h=>h.to===f.id&&["CALLS","CALL_REFERENCE","USES_TYPE","TESTS","ROUTE","WRITES","IMPORTS","INHERITS","IMPLEMENTS","DEFINES"].includes(h.type));for(let h of x){if(d.has(h.from))continue;d.add(h.from);let g=this.graph.getSymbol(h.from);if(!g)continue;let m=f.depth+1,S=`${p.symbol.id}:${g.id}`;n.set(S,{symbol:g,relation:h.type,depth:m,sourceSymbolId:p.symbol.id});let b=sr[h.type]??1;i+=Math.max(1,b-(m-1)),u.push({id:g.id,depth:m})}}}let a=[...n.values()].sort((p,d)=>p.depth-d.depth),c=[...new Set(a.map(p=>p.symbol.filePath))],l=c.filter(Xe);return l.length===0&&l.push(...c.filter(p=>!Xe(p)).slice(0,10)),{risk:nr(i),riskScore:i,changedSymbols:t,impacted:a,impactedFiles:c,suggestedTests:l}}};import{execFile as ir}from"node:child_process";import{promisify as ar}from"node:util";var Fe=ar(ir);function cr(o){let e=[],t=/^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/gm;for(let r of o.matchAll(t)){let s=Number(r[1]),n=Number(r[2]??1);e.push({startLine:s,endLine:Math.max(s,s+n-1)})}return e}function lr(o){return o.startsWith("A")?"added":o.startsWith("D")?"deleted":o.startsWith("R")?"renamed":"modified"}async function et(o){let e="";try{e=(await Fe("git",["diff","HEAD","--name-status","--no-renames"],{cwd:o,maxBuffer:10485760})).stdout}catch{return[]}let t=[];for(let r of e.split(/\r?\n/).filter(Boolean)){let[s,...n]=r.split(" "),i=n.at(-1);if(!i)continue;let a="";try{a=(await Fe("git",["diff","HEAD","--unified=0","--",i],{cwd:o,maxBuffer:20971520})).stdout}catch{a=""}t.push({filePath:i,status:lr(s),ranges:cr(a)})}try{let r=await Fe("git",["ls-files","--others","--exclude-standard"],{cwd:o});for(let s of r.stdout.split(/\r?\n/).filter(Boolean))t.some(n=>n.filePath===s)||t.push({filePath:s,status:"added",ranges:[]})}catch{}return t}var X=class{constructor(e){this.graph=e;this.mapper=new Z(e),this.blast=new Q(e)}graph;mapper;blast;async analyzeGitDiff(e,t,r={}){let s=await et(t),n=this.mapper.map(e,s),i=this.blast.analyze(e,n,r.maxDepth??4);return{mode:"git_diff",changes:s,...i}}analyzeFile(e,t,r={}){let s=this.mapper.mapFile(e,t);return{mode:"planned_file",filePath:t,...this.blast.analyze(e,s,r.maxDepth??4)}}};var dr=/(^|[_-])(write|edit|patch|replace|multiedit|create|delete|remove|rename|move)([_-]|$)/i,pr=new Set(["path","filepath","file_path","filename","file","target","targetpath","target_path","sourcepath","source_path"]);function tt(o){return o.trim().replace(/^["']|["']$/g,"").replace(/^a\//,"").replace(/^b\//,"").replaceAll("\\","/")}function mr(o){return o.length>0&&o.length<500&&!o.includes(`
4
+ `)&&/(^|\/)[^/]+\.[A-Za-z0-9]+$/.test(o)}function ur(o){let e=[],t=[/^\*\*\* (?:Update|Add|Delete) File:\s*(.+)$/gm,/^\+\+\+\s+b\/(.+)$/gm,/^---\s+a\/(.+)$/gm];for(let r of t)for(let s of o.matchAll(r))s[1]&&e.push(tt(s[1]));return e}function $e(o,e,t){if(typeof o=="string"){let r=t?.toLowerCase();if(r&&pr.has(r)&&mr(o)&&e.add(tt(o)),o.includes("*** Update File:")||o.includes("*** Add File:")||o.includes("*** Delete File:")||o.includes("+++ b/"))for(let s of ur(o))e.add(s);return}if(Array.isArray(o)){for(let r of o)$e(r,e,t);return}if(o&&typeof o=="object")for(let[r,s]of Object.entries(o))$e(s,e,r)}function fr(o){return dr.test(o.toLowerCase())}function rt(o,e){if(!fr(o))return[];let t=new Set;return $e(e,t),[...t]}import{createHash as gr}from"node:crypto";import{readFile as hr}from"node:fs/promises";async function ot(o){let e=await hr(o);return gr("sha256").update(e).digest("hex")}function st(o,e){let t=o?.files??{},r=e.files,s=[],n=[],i=[],a=[];for(let[c,l]of Object.entries(r)){let p=t[c];p?p.hash!==l.hash?n.push(c):a.push(c):s.push(c)}for(let c of Object.keys(t))r[c]||i.push(c);return{added:s.sort(),modified:n.sort(),deleted:i.sort(),unchanged:a.sort()}}import{join as yr}from"node:path";async function nt(o,e){let t=await Ae(e),r={};for(let s of t)r[s]={path:s,hash:await ot(yr(e,s))};return{version:1,projectId:o,updatedAt:new Date().toISOString(),files:r}}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 ee=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","manifest.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 te=class{constructor(e){this.storage=e}storage;async index(e,t){let r=new ee(this.storage),s=new k(this.storage),n=await r.load(e),i=await s.load(e),a=await nt(e,t),c=st(n,a),l=[...c.added,...c.modified];if(n&&i&&l.length===0&&c.deleted.length===0)return{firstRun:!1,scanned:Object.keys(a.files).length,parsed:0,added:0,modified:0,deleted:0,unchanged:c.unchanged.length,symbols:i.symbols.length,edges:i.edges.length,saved:!1};let p=i?.symbols.filter(g=>c.unchanged.includes(g.filePath))??[],d=[];for(let g of l)d.push(await Ne(e,t,g));let u=new I().build(e,d),f=new C;for(let g of p)f.addSymbol(g);for(let g of u.allSymbols(e))f.addSymbol(g);let x=new Set(f.allSymbols(e).map(g=>g.id));for(let g of i?.edges??[])x.has(g.from)&&x.has(g.to)&&!l.includes(i.symbols.find(m=>m.id===g.from)?.filePath??"")&&!l.includes(i.symbols.find(m=>m.id===g.to)?.filePath??"")&&f.addEdge(g);for(let g of u.allEdges(e))f.addEdge(g);let h={version:1,projectId:e,updatedAt:new Date().toISOString(),files:Object.keys(a.files).length,symbols:f.allSymbols(e),edges:f.allEdges(e)};return await s.save(h),await r.save(a),{firstRun:n===null,scanned:Object.keys(a.files).length,parsed:l.length,added:c.added.length,modified:c.modified.length,deleted:c.deleted.length,unchanged:c.unchanged.length,symbols:h.symbols.length,edges:h.edges.length,saved:!0}}};var A=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[r,s]of this.records)s.projectId===e&&(this.records.delete(r),t++);return t}exportProject(e){return[...this.records.values()].filter(t=>t.projectId===e)}importRecords(e){let t=0;for(let r of e)!r?.id||!r?.projectId||!Array.isArray(r.vector)||(this.records.set(r.id,r),t++);return t}search(e,t,r=10){let s=[];for(let n of this.records.values()){if(n.projectId!==e)continue;let i=Sr(t,n.vector);s.push({id:n.id,score:i,metadata:n.metadata})}return s.sort((n,i)=>i.score-n.score).slice(0,r)}size(){return this.records.size}};function Sr(o,e){if(o.length===0||e.length===0||o.length!==e.length)return 0;let t=0,r=0,s=0;for(let n=0;n<o.length;n++){let i=o[n]??0,a=e[n]??0;t+=i*a,r+=i*i,s+=a*a}return r===0||s===0?0:t/(Math.sqrt(r)*Math.sqrt(s))}import zn from"typescript";import w from"typescript";var Un=new Set([w.SyntaxKind.EqualsToken,w.SyntaxKind.PlusEqualsToken,w.SyntaxKind.MinusEqualsToken,w.SyntaxKind.AsteriskEqualsToken,w.SyntaxKind.SlashEqualsToken,w.SyntaxKind.PercentEqualsToken,w.SyntaxKind.QuestionQuestionEqualsToken,w.SyntaxKind.AmpersandAmpersandEqualsToken,w.SyntaxKind.BarBarEqualsToken]);var re=class{constructor(e,t){this.embeddings=e;this.store=t}embeddings;store;async index(e){let t=e.filter(n=>!this.store.has(n.id));if(t.length===0)return 0;let r=await this.embeddings.embedMany(t.map(n=>[n.type,n.content,...n.tags??[]].join(" "))),s=0;for(let n=0;n<t.length;n++){let i=t[n],a=r[n];!i||!a||(this.store.upsert({id:i.id,projectId:i.projectId,vector:a,metadata:{type:i.type,updatedAt:i.updatedAt}}),s++)}return s}};var L=class{constructor(e,t,r,s,n){this.projectId=e;this.model=t;this.embeddings=r;this.store=s;this.persistence=n}projectId;model;embeddings;store;persistence;async initialize(e){let t=0,r=await this.persistence.load(this.projectId);r&&r.model===this.model&&(t=this.store.importRecords(r.records));let s=new Set(e.map(d=>d.id)),n=0;for(let d of this.store.exportProject(this.projectId))s.has(d.id)||this.store.remove(d.id)&&n++;let a=await new re(this.embeddings,this.store).index(e),c=this.store.exportProject(this.projectId),l=c[0]?.vector.length??this.embeddings.dimensions??0,p=!1;return(a>0||n>0||!r)&&(await this.persistence.save({version:1,projectId:this.projectId,model:this.model,dimensions:l,updatedAt:new Date().toISOString(),records:c}),p=!0),{loaded:t,indexed:a,removed:n,total:c.length,saved:p}}};var oe=class{events=[];push(e){this.events.push(e)}drain(){let e=[...this.events];return this.events.length=0,e}list(){return[...this.events]}size(){return this.events.length}shouldFlush(e){return this.events.length>=e}};import{createHash as xr}from"node:crypto";var se=class{seen=new Set;fingerprint(e){return xr("sha256").update(JSON.stringify({projectId:e.projectId,type:e.type,data:e.data})).digest("hex")}filter(e){let t=[];for(let r of e){let s=this.fingerprint(r);this.seen.has(s)||(this.seen.add(s),t.push(r))}return t}clear(){this.seen.clear()}};import{randomUUID as vr}from"node:crypto";var ne=class{constructor(e){this.queue=e}queue;sanitizer=new P;capture(e,t,r={}){let s={id:vr(),projectId:e,type:t,timestamp:new Date().toISOString(),data:this.sanitizer.sanitizeValue(r)};return this.queue.push(s),s}};import{randomUUID as wr}from"node:crypto";var ie=class{constructor(e){this.capture=e}capture;sessionId=wr();start(e){return this.capture.capture(e,"session_start",{sessionId:this.sessionId})}end(e){return this.capture.capture(e,"session_end",{sessionId:this.sessionId})}};var ae=class{extract(e){switch(e.type){case"decision":return{type:"decision",content:String(e.data.content??"Decision recorded"),tags:["decision"],source:"auto-extractor",metadata:e.data};case"todo":return{type:"todo",content:String(e.data.content??"TODO recorded"),tags:["todo"],source:"auto-extractor",metadata:e.data};case"error":return{type:"activity",content:`Error: ${String(e.data.message??"")}`,tags:["error"],source:"auto-extractor",metadata:e.data};case"file_write":return{type:"activity",content:`Modified file: ${String(e.data.filePath??"")}`,tags:["file","write"],source:"auto-extractor",metadata:e.data};case"command":return{type:"activity",content:`Command: ${String(e.data.command??"")}`,tags:["command"],source:"auto-extractor",metadata:e.data};case"session_start":case"session_end":case"file_read":case"tool_call":case"user_prompt":case"test":case"commit":case"deploy":return null;default:return null}}};function _e(o){let e=o.toLowerCase();return["kh\xF4ng \u0111\u01B0\u1EE3c","b\u1EAFt bu\u1ED9c","ph\u1EA3i lu\xF4n","tuy\u1EC7t \u0111\u1ED1i","never ","must ","always ","do not "].some(t=>e.includes(t))}function Ge(o){let e=o.toLowerCase();return["quy\u1EBFt \u0111\u1ECBnh","ch\u1ECDn ","s\u1EED d\u1EE5ng ","d\xF9ng ","decided","decision","we will use","use "].some(t=>e.includes(t))}function De(o){let e=o.toLowerCase();return["todo","c\u1EA7n l\xE0m","ch\u01B0a xong","c\xF2n ph\u1EA3i","next:","next step","pending"].some(t=>e.includes(t))}function ce(o,e){let t=e.toLowerCase();return t.includes("kh\xF4ng \u0111\u01B0\u1EE3c")||t.includes("tuy\u1EC7t \u0111\u1ED1i")||t.includes("must not")||t.includes("never ")?"critical":o==="rule"||o==="decision"?"high":o==="todo"||t.includes("error")||t.includes("failed")||t.includes("exception")?"normal":"temporary"}function N(o){return[...new Set(o.filter(Boolean))]}function le(o,e=120){return o.length>e?`${o.slice(0,e)}\u2026`:o}var de=class{summarize(e){if(e.length===0)return null;let t=N(e.filter(c=>c.type==="file_write").map(c=>String(c.data.filePath??""))),r=N(e.filter(c=>c.type==="command").map(c=>le(String(c.data.command??"")))),s=N(e.filter(c=>c.type==="error").map(c=>le(String(c.data.message??"")))),n=N(e.filter(c=>c.type==="decision").map(c=>le(String(c.data.content??"")))),i=N(e.filter(c=>c.type==="todo").map(c=>le(String(c.data.content??""))));if(t.length===0&&r.length===0&&s.length===0&&n.length===0&&i.length===0)return null;let a=["Session summary:"];return t.length&&a.push(`- Files changed (${t.length}): ${t.slice(0,10).join(", ")}`),r.length&&a.push(`- Commands (${r.length}): ${r.slice(0,5).join("; ")}`),s.length&&a.push(`- Errors (${s.length}): ${s.slice(0,5).join("; ")}`),n.length&&a.push(`- Decisions: ${n.slice(0,5).join("; ")}`),i.length&&a.push(`- TODO: ${i.slice(0,5).join("; ")}`),a.join(`
5
+ `)}};var pe=class{constructor(e){this.memory=e}memory;extractor=new ae;summarizer=new de;process(e){let t=0;for(let s of e){let n=this.extractor.extract(s);if(n){let i=this.refineType(n.type,n.content);this.memory.remember({projectId:s.projectId,type:i,content:n.content,importance:ce(i,n.content),tags:n.tags,source:n.source,metadata:{eventId:s.id,timestamp:s.timestamp,...n.metadata}}),t++}if(s.type==="user_prompt"){let i=String(s.data.content??""),a=this.detectPromptMemoryType(i);a&&(this.memory.remember({projectId:s.projectId,type:a,content:i,importance:ce(a,i),tags:["user",a],source:"auto-prompt-extractor",metadata:{eventId:s.id,timestamp:s.timestamp}}),t++)}}let r=this.summarizer.summarize(e);if(r){let s=e[0]?.projectId;s&&(this.memory.remember({projectId:s,type:"summary",content:r,importance:"temporary",tags:["summary"],source:"auto-summary",metadata:{eventCount:e.length}}),t++)}return t}refineType(e,t){return _e(t)?"rule":De(t)?"todo":Ge(t)?"decision":e}detectPromptMemoryType(e){return _e(e)?"rule":De(e)?"todo":Ge(e)?"decision":null}};import{createHash as Er}from"node:crypto";function Cr(o){return Er("sha256").update([o.projectId,o.type,o.content.trim().toLowerCase()].join("|")).digest("hex")}function it(o){let e=new Set,t=[];for(let r of o){let s=Cr(r);e.has(s)||(e.add(s),t.push(r))}return t}var me=class{projectId;memory;memoryStore;queue=new oe;capture=new ne(this.queue);session=new ie(this.capture);processor;dedup=new se;maxEventsBeforeFlush;constructor(e){this.projectId=e.projectId,this.memory=e.memory,this.memoryStore=e.memoryStore,this.maxEventsBeforeFlush=e.maxEventsBeforeFlush??100,this.processor=new pe(this.memory)}async sessionStart(){this.session.start(this.projectId),await this.flushIfNeeded()}async sessionEnd(){this.session.end(this.projectId),await this.flush()}async userPrompt(e){this.capture.capture(this.projectId,"user_prompt",{content:e}),await this.flushIfNeeded()}async beforeTool(e,t){this.capture.capture(this.projectId,"tool_call",{phase:"before",tool:e,input:t}),await this.flushIfNeeded()}async afterTool(e,t){this.capture.capture(this.projectId,"tool_call",{phase:"after",tool:e,output:t}),await this.flushIfNeeded()}async fileRead(e){this.capture.capture(this.projectId,"file_read",{filePath:e}),await this.flushIfNeeded()}async fileWrite(e){this.capture.capture(this.projectId,"file_write",{filePath:e}),await this.flushIfNeeded()}async command(e,t){this.capture.capture(this.projectId,"command",{command:e,exitCode:t}),await this.flushIfNeeded()}async error(e){let t=e instanceof Error?e.message:String(e);this.capture.capture(this.projectId,"error",{message:t}),await this.flushIfNeeded()}async decision(e,t={}){this.capture.capture(this.projectId,"decision",{content:e,...t}),await this.flushIfNeeded()}async todo(e,t={}){this.capture.capture(this.projectId,"todo",{content:e,...t}),await this.flushIfNeeded()}async flushIfNeeded(){this.queue.shouldFlush(this.maxEventsBeforeFlush)&&await this.flush()}async flush(){let e=this.queue.drain();if(e.length===0)return 0;let t=this.dedup.filter(e);if(t.length===0)return 0;let r=this.processor.process(t),s=it(this.memory.exportProject(this.projectId));return this.memory.clearProject(this.projectId),this.memory.importRecords(s),await this.memoryStore.save(this.projectId,s),r}pendingEvents(){return this.queue.size()}};var ue=class{constructor(e,t,r){this.memory=e;this.retrieval=t;this.graph=r}memory;retrieval;graph;build(e,t,r={}){let s=r.maxRules??3,n=r.maxTodos??3,i=r.maxDecisions??3,a=r.maxRelevant??5,c=r.maxCharacters??7e3,l=this.memory.byType(e,"rule").slice(0,s),p=this.memory.byType(e,"todo").slice(0,n),d=this.memory.byType(e,"decision").slice(0,i),u=this.retrieval.search(e,t,{topK:a}),f=Qe(this.graph,e),x=[];x.push(["[PROJECT]",`files=${f.files}`,`classes=${f.classes}`,`functions=${f.functions}`,`methods=${f.methods}`,`calls=${f.calls}`].join(" "));for(let g of l)x.push(`[RULE] ${g.content}`);for(let g of d)x.push(`[DECISION] ${g.content}`);for(let g of p)x.push(`[TODO] ${g.content}`);for(let g of u){let S=`[${g.memory.type.toUpperCase()}] ${g.memory.content}`;x.includes(S)||x.push(S)}let h="";for(let g of x){let m=h.length===0?g:`${h}
6
+ ${g}`;if(m.length>c)break;h=m}return h}};var fe=class{constructor(e,t,r){this.runtime=e;this.builder=t;this.projectId=r}runtime;builder;projectId;async prepare(e){await this.runtime.userPrompt(e);let t=this.builder.build(this.projectId,e);return{originalPrompt:e,context:t,augmentedPrompt:t?["<toolnet_memory>",t,"</toolnet_memory>","",e].join(`
7
+ `):e}}};var at={LOW:0,MEDIUM:1,HIGH:2,CRITICAL:3},ge=class{constructor(e,t){this.guard=e;this.projectId=t}guard;projectId;async beforeTool(e,t){let r=rt(e,t);if(r.length===0)return{triggered:!1,tool:e,highestRisk:"LOW",totalRiskScore:0,files:[],impactedFiles:[],suggestedTests:[],requiresVerification:!1,context:""};let s=[];for(let d of r){let u=this.guard.analyzeFile(this.projectId,d);s.push({filePath:d,risk:u.risk,riskScore:u.riskScore,impactedFiles:u.impactedFiles,suggestedTests:u.suggestedTests,impactedCount:u.impacted.length})}let n="LOW";for(let d of s)at[d.risk]>at[n]&&(n=d.risk);let i=[...new Set(s.flatMap(d=>d.impactedFiles))],a=[...new Set(s.flatMap(d=>d.suggestedTests))],c=s.reduce((d,u)=>d+u.riskScore,0),l=n==="HIGH"||n==="CRITICAL",p=["[TOOLNET IMPACT GUARD]",`Risk: ${n}`,`Risk score: ${c}`,`Files being changed: ${r.join(", ")}`,`Impacted files: ${i.length}`];return i.length&&p.push("Blast radius:",...i.slice(0,20).map(d=>`- ${d}`)),a.length&&p.push("Verify/tests:",...a.slice(0,15).map(d=>`- ${d}`)),l&&p.push("IMPORTANT: High blast radius. Inspect affected dependencies and run relevant tests after the edit."),{triggered:!0,tool:e,highestRisk:n,totalRiskScore:c,files:s,impactedFiles:i,suggestedTests:a,requiresVerification:l,context:p.join(`
8
+ `)}}};import{homedir as Dr}from"node:os";import{join as zr}from"node:path";import{DeleteObjectCommand as jr,GetObjectCommand as Pr,HeadObjectCommand as Rr,ListObjectsV2Command as kr,PutObjectCommand as Tr,S3Client as Mr}from"@aws-sdk/client-s3";import{getSignedUrl as Ir}from"@aws-sdk/s3-request-presigner";var he=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Mr({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,r="application/octet-stream"){let s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Tr({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let t=await Ir(this.client,new Pr({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 Rr({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 jr({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let s=await this.client.send(new kr({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:r}));for(let n of s.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});r=s.IsTruncated?s.NextContinuationToken:void 0}while(r);return t}};import{access as ct,mkdir as Ar,readFile as Lr,readdir as Nr,rm as Or,stat as lt,writeFile as Fr}from"node:fs/promises";import{dirname as $r,join as _r,relative as dt,resolve as Gr}from"node:path";var O=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Gr(this.root,t)}async put(e,t){let r=this.path(e);await Ar($r(r),{recursive:!0}),await Fr(r,t)}async get(e){try{return await Lr(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 ct(this.path(e)),!0}catch{return!1}}async delete(e){await Or(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await ct(t)}catch{return r}let s=async i=>{let a=await Nr(i,{withFileTypes:!0});for(let c of a){let l=_r(i,c.name);if(c.isDirectory()){await s(l);continue}let p=await lt(l);r.push({key:dt(this.root,l),size:p.size,updatedAt:p.mtime.toISOString()})}},n=await lt(t);return n.isDirectory()?await s(t):r.push({key:dt(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),r}};function pt(o){let e=o.localRoot??zr(Dr(),".toolnet-memory","storage");if(o.provider==="huggingface"){let t=o.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new he({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new O(e))}return new O(e)}var T=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 r=JSON.parse(t);if(!Array.isArray(r))throw new Error("Invalid memory snapshot");return r}async save(e,t){let r=JSON.stringify(t,null,2);await this.storage.put(this.key(e),r,"application/json")}};var ye=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return null;let r=JSON.parse(t);if(r.version!==1||r.projectId!==e||!Array.isArray(r.records))throw new Error("Invalid vector snapshot");return r}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};function Br(o){return new Promise(e=>setTimeout(e,o))}async function mt(o,e={}){let t=Math.max(1,e.attempts??3),r=e.baseDelayMs??150,s=e.maxDelayMs??2e3,n;for(let i=1;i<=t;i++)try{return await o()}catch(a){if(n=a,i>=t)break;let c=Math.min(s,r*2**(i-1)),l=Math.floor(Math.random()*Math.max(1,c*.2));await Br(c+l)}throw n}var Hr=new Set(["put","get","getText","delete","list"]);function ut(o,e={}){return new Proxy(o,{get(t,r){let s=Reflect.get(t,r,t);return typeof s!="function"?s:Hr.has(r)?(...n)=>mt(()=>Promise.resolve(s.apply(t,n)),e):s.bind(t)}})}function ft(o){let e=o.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 gt(o){let e=o.replace(/^\/+/,"");if(e.startsWith("memories/"))return"memory/records/"+e.slice(9);if(e.startsWith("vectors/"))return"memory/vectors/"+e.slice(8);if(e.startsWith("graph/"))return"code/graph/"+e.slice(6);let t=e.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(t)return`${t[1]}memory/records/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),t)return`${t[1]}memory/vectors/${t[2]}`;if(t=e.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),t)return`${t[1]}code/graph/${t[2]}`;let r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(r)return`${r[1]}memory/records/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),r)return`${r[1]}memory/vectors/${r[2]}`;if(r=e.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),r)return`${r[1]}code/graph/${r[2]}`;let s=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:e))}var Se=class{constructor(e,t,r,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=ft(s??r),this.sourcePrefix=`projects/${t}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let e=`${this.targetPrefix}/project.json`,t=new Date().toISOString(),r=t,s=await this.provider.getText(e);if(s){let i;try{i=JSON.parse(s)}catch(a){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${a instanceof Error?a.message:String(a)}`)}if(typeof i.id=="string"&&i.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${i.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof i.createdAt=="string"&&(r=i.createdAt)}let 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)+`
9
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=gt(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))}};function Wr(o){let e=o.metadata?.learningFingerprint;return typeof e=="string"?e:void 0}async function Vr(o,e){let t=`projects/${o.id}/memory/learned/`,r=await e.list(t),s=[];for(let n of r.filter(i=>i.key.includes("/batches/")&&i.key.endsWith(".json")).sort((i,a)=>i.key.localeCompare(a.key))){let i=await e.getText(n.key);if(i)try{let a=JSON.parse(i);if(a.version!==1||!Array.isArray(a.candidates))continue;s.push(a)}catch{}}return s}async function ht(o,e){let t=await Vr(o,e),r=new T(e),s=await r.load(o.id),n=new R;n.importRecords(s);let i=new Set(s.map(p=>Wr(p)).filter(p=>!!p)),a=0,c=0,l=0;for(let p of t)for(let d of p.candidates){if(a+=1,i.has(d.fingerprint)){l+=1;continue}n.remember({projectId:o.id,type:d.type,content:d.content,importance:d.importance,tags:d.tags,source:"session-memory-learner",metadata:{learningFingerprint:d.fingerprint,learningKind:d.kind,confidence:d.confidence,provenance:d.provenance,sourceCreatedAt:d.createdAt,sessionKey:d.sessionKey,agent:d.agent,nativeSessionId:d.nativeSessionId}}),i.add(d.fingerprint),c+=1}return c>0&&await r.save(o.id,n.exportProject(o.id)),{batches:t.length,candidates:a,added:c,duplicates:l,memories:n.exportProject(o.id).length}}var Ur=["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"],be=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 s=new Date().toISOString(),n=s.replace(/[:.]/g,"-"),i=this.projectPrefix(e),a=this.snapshotPrefix(e,n),c=[];for(let p of Ur){let d=`${i}/${p}`,u=await this.storage.get(d);u&&(await this.storage.put(`${a}/${p}`,u,"application/json"),c.push(p))}if(c.length===0)return null;let l={version:1,id:n,projectId:e,createdAt:s,reason:t,objects:c,metadata:r};return await this.storage.put(`${a}/snapshot.json`,JSON.stringify(l,null,2),"application/json"),l}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),s=(await this.storage.list(t)).filter(i=>i.key.endsWith("/snapshot.json")),n=[];for(let i of s){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),s=await this.storage.getText(`${r}/snapshot.json`);if(!s)throw new Error(`Snapshot not found: ${t}`);let n=JSON.parse(s);if(n.projectId!==e)throw new Error("Snapshot project mismatch");let i=this.projectPrefix(e),a=[];for(let c of n.objects){let l=await this.storage.get(`${r}/${c}`);l&&(await this.storage.put(`${i}/${c}`,l,"application/json"),a.push(c))}return{restored:a}}async remove(e,t){let r=this.snapshotPrefix(e,t),s=await this.storage.list(r);for(let n of s)await this.storage.delete(n.key);return s.length}async prune(e,t=10){let s=(await this.list(e)).slice(t),n=0;for(let i of s)await this.remove(e,i.id),n++;return n}};import{closeSync as qr,mkdirSync as Jr,openSync as Yr,readFileSync as Zr,unlinkSync as yt,writeFileSync as Qr}from"node:fs";import{tmpdir as Xr}from"node:os";import{join as St}from"node:path";function eo(o){try{return process.kill(o,0),!0}catch(e){return e?.code==="EPERM"}}var xe=class{acquired=!1;path;exitHandler=()=>{this.releaseSync()};constructor(e){let t=St(Xr(),"toolnet-memory-locks");Jr(t,{recursive:!0});let r=e.replace(/[^A-Za-z0-9_.-]/g,"_");this.path=St(t,`${r}.lock`)}async acquire(){if(!this.acquired){for(let e=0;e<2;e++)try{let t=Yr(this.path,"wx");Qr(t,JSON.stringify({pid:process.pid,createdAt:new Date().toISOString()})),qr(t),this.acquired=!0,process.once("exit",this.exitHandler);return}catch(t){if(t?.code!=="EEXIST")throw t;let r=!0;try{let s=JSON.parse(Zr(this.path,"utf8"));Number.isInteger(s.pid)&&eo(s.pid)&&(r=!1)}catch{r=!0}if(!r)throw new Error("ToolNet Memory is already running for this project");try{yt(this.path)}catch{}}throw new Error("Unable to acquire ToolNet Memory project lock")}}async release(){this.releaseSync()}releaseSync(){if(this.acquired){try{yt(this.path)}catch{}this.acquired=!1,process.off("exit",this.exitHandler)}}};var ve=class{constructor(e){this.options=e;this.memoryStore=new T(e.storage),this.graphStore=new k(e.storage),this.vectorStore=new ye(e.storage),this.processLock=new xe(e.project.id),this.retrieval=new U(this.memory),this.references=new Y(this.graph),this.hooks=new me({projectId:e.project.id,memory:this.memory,memoryStore:this.memoryStore,maxEventsBeforeFlush:100});let t=new ue(this.memory,this.retrieval,this.graph);this.autoRetrieval=new fe(this.hooks,t,e.project.id),this.impactGuard=new X(this.graph),this.autoImpactGuard=new ge(this.impactGuard,e.project.id)}options;memory=new R;graph=new C;vectors=new A;retrieval;references;hooks;autoRetrieval;impactGuard;autoImpactGuard;memoryStore;graphStore;vectorStore;processLock;async start(){let{project:e}=this.options;await this.processLock.acquire(),await ht(e,this.options.storage);let t=await this.memoryStore.load(e.id);this.memory.importRecords(t);let s=new D(this.memory).run(e.id);(s.expiredRemoved>0||s.supersededRemoved>0)&&await this.memoryStore.save(e.id,this.memory.exportProject(e.id));let n=await this.graphStore.load(e.id);n&&this.graph.import(n.symbols,n.edges);let i=Me(),c=await new L(e.id,this.options.embeddingModel,i,this.vectors,this.vectorStore).initialize(this.memory.list(e.id));return await this.hooks.sessionStart(),{memories:t.length,graphSymbols:this.graph.allSymbols(e.id).length,graphEdges:this.graph.allEdges(e.id).length,vectors:c.total,vectorsIndexed:c.indexed}}async preparePrompt(e){return this.autoRetrieval.prepare(e)}async beforeTool(e,t){let r=await this.autoImpactGuard.beforeTool(e,t);return await this.hooks.beforeTool(e,t),r}async afterTool(e,t){return this.hooks.afterTool(e,t)}async stop(){let{project:e,storage:t,embeddingModel:r}=this.options,s=new be(t),n=await s.create(e.id,"session-end-auto");await s.prune(e.id,10),await this.hooks.sessionEnd();let i=new z(this.memory).consolidate(e.id);i.summaryCreated&&await this.memoryStore.save(e.id,this.memory.exportProject(e.id));let a=await new te(t).index(e.id,e.rootPath),c=await this.graphStore.load(e.id);c&&(this.graph.clearProject(e.id),this.graph.import(c.symbols,c.edges));let l=Me(),d=await new L(e.id,r,l,this.vectors,this.vectorStore).initialize(this.memory.list(e.id)),u={code:a,vectors:d,consolidation:i,snapshot:n?.id,memories:this.memory.list(e.id).length};return await this.processLock.release(),u}};import"dotenv/config";import{existsSync as to,readFileSync as ro}from"node:fs";import{homedir as oo}from"node:os";import{join as so}from"node:path";function no(o){let e=o.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
10
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function io(){let o=process.env.TOOLNET_GLOBAL_ENV??so(oo(),".config","toolnet-memory",".env");if(!to(o))return;let e=ro(o,"utf8");for(let t of e.split(/\r?\n/)){let r=t.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let s=r.indexOf("=");if(s<=0)continue;let n=r.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(n)&&process.env[n]===void 0&&(process.env[n]=no(r.slice(s+1)))}}io();function we(o,e){return o===void 0?e:["1","true","yes","on"].includes(o.toLowerCase())}function F(o,e){if(!o)return e;let t=Number(o);return Number.isFinite(t)?t:e}function bt(){return{memory:{autoCapture:we(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:we(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:we(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:we(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:F(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:F(process.env.MEMORY_RERANK_TOP,10),finalContext:F(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:F(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",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:F(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as ao}from"node:crypto";import{existsSync as ze,mkdirSync as co,readFileSync as lo,renameSync as po,writeFileSync as mo}from"node:fs";import{basename as uo,dirname as Ee,join as je,parse as wt,resolve as $}from"node:path";var Et=".toolnet",fo="project.json";function go(o){return ao("sha256").update(o).digest("hex").slice(0,16)}function Be(o){return je(o,Et,fo)}function ho(o){return ze(Be(o))}function yo(o,e){let t=$(o),r=wt(t).root;for(;;){if(ho(t))return t;if(t===r||e&&t===$(e))break;let s=Ee(t);if(s===t)break;t=s}return null}function So(o){let e=$(o),t=wt(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(n=>ze(je(e,n))))return e;if(e===t)break;let s=Ee(e);if(s===e)break;e=s}return $(o)}function bo(o){let e;try{e=JSON.parse(lo(o,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${o}: ${s instanceof Error?s.message:String(s)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${o}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${o}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${o}`);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:Ee(Ee(o)),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 xt(o,e){let t=je(o,Et);co(t,{recursive:!0});let r=Be(o),s=`${r}.tmp-${process.pid}`;mo(s,JSON.stringify(e,null,2)+`
11
+ `,{encoding:"utf8",mode:384}),po(s,r)}function vt(o,e){return{id:o.id,name:o.name,remote:o.remote,rootPath:e,createdAt:o.createdAt,updatedAt:o.updatedAt,graphVersion:o.graphVersion,memoryVersion:o.memoryVersion,metadata:o.metadata}}var Ce=class{detect(e=process.cwd()){let t=$(e),r=So(t),n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>ze(je(r,p))),i=yo(t,n?r:void 0);if(i){let p=Be(i),d=bo(p);return d.rootPath!==i&&(d.rootPath=i,d.updatedAt=new Date().toISOString(),xt(i,d)),vt(d,i)}let a=new Date().toISOString(),c=uo(r),l={version:1,id:go(r),name:c,remote:c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return xt(r,l),vt(l,r)}};function Ct(o=process.cwd()){let e=bt(),t=new Ce().detect(o),r=pt({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),s=ut(r,{attempts:Number(process.env.TOOLNET_STORAGE_RETRIES??3)}),n=new Se(s,t.id,t.name,t.remote??t.name),i=process.env.HF_EMBEDDING_MODEL??"sentence-transformers/all-MiniLM-L6-v2";return new ve({project:t,storage:n,embeddingModel:i})}async function xo(){let o=Ct(),e=await o.start(),t=await o.preparePrompt("Ti\u1EBFp t\u1EE5c c\xF4ng vi\u1EC7c hi\u1EC7n t\u1EA1i");console.log({started:!0,...e,contextCharacters:t.context.length});let r=await o.stop();console.log({stopped:!0,memories:r.memories,codeParsed:r.code.parsed,vectorsIndexed:r.vectors.indexed})}xo().catch(o=>{console.error(o),process.exit(1)});
@@ -0,0 +1,6 @@
1
+ import"dotenv/config";import{existsSync as ue,readFileSync as ge}from"node:fs";import{homedir as he}from"node:os";import{join as ye}from"node:path";function Se(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 be(){let s=process.env.TOOLNET_GLOBAL_ENV??ye(he(),".config","toolnet-memory",".env");if(!ue(s))return;let e=ge(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]=Se(r.slice(o+1)))}}be();function N(s,e){return s===void 0?e:["1","true","yes","on"].includes(s.toLowerCase())}function k(s,e){if(!s)return e;let t=Number(s);return Number.isFinite(t)?t:e}function Q(){return{memory:{autoCapture:N(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:N(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:N(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:N(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",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 xe}from"node:crypto";import{existsSync as V,mkdirSync as Ee,readFileSync as Ce,renameSync as we,writeFileSync as ve}from"node:fs";import{basename as Pe,dirname as A,join as I,parse as te,resolve as T}from"node:path";var re=".toolnet",ke="project.json";function Te(s){return xe("sha256").update(s).digest("hex").slice(0,16)}function U(s){return I(s,re,ke)}function Re(s){return V(U(s))}function je(s,e){let t=T(s),r=te(t).root;for(;;){if(Re(t))return t;if(t===r||e&&t===T(e))break;let o=A(t);if(o===t)break;t=o}return null}function Le(s){let e=T(s),t=te(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(n=>V(I(e,n))))return e;if(e===t)break;let o=A(e);if(o===e)break;e=o}return T(s)}function Ne(s){let e;try{e=JSON.parse(Ce(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:A(A(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 X(s,e){let t=I(s,re);Ee(t,{recursive:!0});let r=U(s),o=`${r}.tmp-${process.pid}`;ve(o,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),we(o,r)}function ee(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 M=class{detect(e=process.cwd()){let t=T(e),r=Le(t),n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>V(I(r,d))),i=je(t,n?r:void 0);if(i){let d=U(i),p=Ne(d);return p.rootPath!==i&&(p.rootPath=i,p.updatedAt=new Date().toISOString(),X(i,p)),ee(p,i)}let c=new Date().toISOString(),l=Pe(r),a={version:1,id:Te(r),name:l,remote:l,rootPath:r,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return X(r,a),ee(a,r)}};var Ae=[{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}],O=class{scan(e){let t=[];for(let r of Ae){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 R=class{scanner=new O;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.toLowerCase();n.includes("password")||n.includes("secret")||n.includes("token")||n.includes("cookie")||n.includes("authorization")?t[r]="[REDACTED]":t[r]=this.sanitizeValue(o)}return t}return e}};import{homedir as Je}from"node:os";import{join as qe}from"node:path";import{DeleteObjectCommand as Me,GetObjectCommand as Ie,HeadObjectCommand as Oe,ListObjectsV2Command as Fe,PutObjectCommand as _e,S3Client as $e}from"@aws-sdk/client-s3";import{getSignedUrl as Ge}from"@aws-sdk/s3-request-presigner";var F=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new $e({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 _e({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await Ge(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 Oe({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 Me({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],r;do{let o=await this.client.send(new Fe({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 se,mkdir as De,readFile as ze,readdir as Be,rm as He,stat as oe,writeFile as Ke}from"node:fs/promises";import{dirname as We,join as Ve,relative as ne,resolve as Ue}from"node:path";var j=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Ue(this.root,t)}async put(e,t){let r=this.path(e);await De(We(r),{recursive:!0}),await Ke(r,t)}async get(e){try{return await ze(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 se(this.path(e)),!0}catch{return!1}}async delete(e){await He(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await se(t)}catch{return r}let o=async i=>{let c=await Be(i,{withFileTypes:!0});for(let l of c){let a=Ve(i,l.name);if(l.isDirectory()){await o(a);continue}let d=await oe(a);r.push({key:ne(this.root,a),size:d.size,updatedAt:d.mtime.toISOString()})}},n=await oe(t);return n.isDirectory()?await o(t):r.push({key:ne(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),r}};function ie(s){let e=s.localRoot??qe(Je(),".toolnet-memory","storage");if(s.provider==="huggingface"){let t=s.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new F({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new j(e))}return new j(e)}var L=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var _=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","chunks","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var $=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 ae(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 ce(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 G=class{constructor(e,t,r,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=ae(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(c){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${c instanceof Error?c.message:String(c)}`)}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=ce(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 Yr from"typescript";var C=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 Xe}from"node:child_process";import{promisify as et}from"node:util";var fs=et(Xe);import{createHash as tt}from"node:crypto";import{readFile as rt}from"node:fs/promises";import{join as st}from"node:path";function le(s){return tt("sha256").update(s).digest("hex")}var D=class{sanitizer=new R;async build(e,t,r,o={}){let n=o.maxLines??80,i=o.overlapLines??10,c=new Map;for(let a of r){let d=c.get(a.filePath)??[];d.push(a),c.set(a.filePath,d)}let l=[];for(let[a,d]of c){let p;try{p=await rt(st(t,a),"utf8")}catch{continue}let f=p.split(/\r?\n/),g=d.filter(u=>u.type!=="file"&&typeof u.startLine=="number"&&typeof u.endLine=="number");if(g.length>0)for(let u of g)l.push(...this.chunkRange({projectId:e,filePath:a,lines:f,symbol:u,startLine:u.startLine,endLine:u.endLine,maxLines:n,overlapLines:i}));else l.push(...this.chunkRange({projectId:e,filePath:a,lines:f,startLine:1,endLine:Math.max(1,f.length),maxLines:n,overlapLines:i}))}return l}chunkRange(e){let{projectId:t,filePath:r,lines:o,symbol:n,maxLines:i}=e,c=Math.min(e.overlapLines,Math.max(0,i-1)),l=Math.max(1,e.startLine),a=Math.min(o.length,Math.max(l,e.endLine)),d=[],p=l,f=0;for(;p<=a;){let g=Math.min(a,p+i-1),u=o.slice(p-1,g).join(`
5
+ `).trim();if(u){let S=this.sanitizer.sanitize(u).text,w=le(S),v=[t,r,n?.id??"file",String(f),w].join(":");d.push({id:le(v).slice(0,32),projectId:t,filePath:r,symbolId:n?.id,symbolName:n?.qualifiedName??n?.name,symbolType:n?.type,startLine:p,endLine:g,content:S,contentHash:w})}if(g>=a)break;p=g-c+1,f++}return d}};var z=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[r,o]of this.records)o.projectId===e&&(this.records.delete(r),t++);return t}exportProject(e){return[...this.records.values()].filter(t=>t.projectId===e)}importRecords(e){let t=0;for(let r of e)!r?.id||!r?.projectId||!Array.isArray(r.vector)||(this.records.set(r.id,r),t++);return t}search(e,t,r=10){let o=[];for(let n of this.records.values()){if(n.projectId!==e)continue;let i=ot(t,n.vector);o.push({id:n.id,score:i,metadata:n.metadata})}return o.sort((n,i)=>i.score-n.score).slice(0,r)}size(){return this.records.size}};function ot(s,e){if(s.length===0||e.length===0||s.length!==e.length)return 0;let t=0,r=0,o=0;for(let n=0;n<s.length;n++){let i=s[n]??0,c=e[n]??0;t+=i*c,r+=i*i,o+=c*c}return r===0||o===0?0:t/(Math.sqrt(r)*Math.sqrt(o))}function J(s){return s.toLowerCase().normalize("NFKC").replace(/[^\p{L}\p{N}_\-./]+/gu," ").split(/\s+/).map(e=>e.trim()).filter(e=>e.length>1)}function de(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 B=class{constructor(e){this.options=e}options;vectors=new z;chunks=new Map;async initialize(){let{projectId:e,rootPath:t,storage:r,embeddings:o,graph:n,model:i}=this.options,c=new _(r),l=new $(r),a=await new D().build(e,t,n.allSymbols(e));this.chunks.clear();for(let m of a)this.chunks.set(m.id,m);let d=await c.load(e),p=!d||d.chunks.length!==a.length||d.chunks.some(m=>!this.chunks.has(m.id));p&&await c.save({version:1,projectId:e,updatedAt:new Date().toISOString(),chunks:a});let f=await l.load(e),g=0;f&&f.model===i&&(g=this.vectors.importRecords(f.records));let u=new Set(a.map(m=>m.id)),S=0;for(let m of this.vectors.exportProject(e))u.has(m.id)||this.vectors.remove(m.id)&&S++;let w=a.filter(m=>{let x=this.vectors.get(m.id);return x?x.metadata?.contentHash!==m.contentHash:!0}),v=0,Y=8,P=this.vectors.exportProject(e)[0]?.vector.length;for(let m=0;m<w.length;m+=Y){let x=w.slice(m,m+Y),me=x.map(h=>[`file: ${h.filePath}`,h.symbolName?`symbol: ${h.symbolName}`:"",h.symbolType?`type: ${h.symbolType}`:"",h.content].filter(Boolean).join(`
6
+ `)),fe=await o.embedMany(me);for(let h=0;h<x.length;h++){let b=x[h],E=fe[h];if(!(!b||!E||E.length===0)){if(P===void 0&&(P=E.length),E.length!==P){console.warn(`[code-semantic] skip dimension mismatch: ${E.length} != ${P}`);continue}this.vectors.upsert({id:b.id,projectId:e,vector:E,metadata:{contentHash:b.contentHash,filePath:b.filePath,symbolName:b.symbolName,symbolType:b.symbolType,startLine:b.startLine,endLine:b.endLine}}),v++}}}let W=this.vectors.exportProject(e),Z=v>0||S>0||!f||f.model!==i;return Z&&await l.save({version:1,projectId:e,model:i,dimensions:W[0]?.vector.length??P??0,updatedAt:new Date().toISOString(),records:W}),{chunks:a.length,vectorsLoaded:g,vectorsIndexed:v,vectorsRemoved:S,totalVectors:W.length,savedChunks:p,savedVectors:Z}}async search(e,t=8){let r=await this.options.embeddings.embed(e),o=this.vectors.search(this.options.projectId,r,Math.max(t*4,20)),n=new Set(J(e)),i=[];for(let c of o){let l=this.chunks.get(c.id);if(!l)continue;let a=new Set(J([l.filePath,l.symbolName??"",l.symbolType??"",l.content].join(" "))),d=0;for(let S of n)a.has(S)&&d++;let p=n.size===0?0:d/n.size,f=Math.max(0,c.score),g=de(l.filePath,e),u=(f*.75+p*.25)*g;i.push({chunk:l,score:u,vectorScore:f,lexicalScore:p})}return i.sort((c,l)=>l.score-c.score).slice(0,t)}size(){return this.chunks.size}};import yo from"typescript";import y from"typescript";var wo=new Set([y.SyntaxKind.EqualsToken,y.SyntaxKind.PlusEqualsToken,y.SyntaxKind.MinusEqualsToken,y.SyntaxKind.AsteriskEqualsToken,y.SyntaxKind.SlashEqualsToken,y.SyntaxKind.PercentEqualsToken,y.SyntaxKind.QuestionQuestionEqualsToken,y.SyntaxKind.AmpersandAmpersandEqualsToken,y.SyntaxKind.BarBarEqualsToken]);var H=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`,r=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(!r.ok)throw new Error(`HF embedding failed: ${r.status} ${await r.text()}`);let o=await r.json();if(!Array.isArray(o))throw new Error("HF embedding returned invalid response");return o.map(n=>it(n))}};function it(s){if(!Array.isArray(s))throw new Error("Invalid embedding");if(s.length>0&&typeof s[0]=="number")return s;if(s.length>0&&Array.isArray(s[0])){let e=s;if(e.length===0)return[];let t=e[0].length,r=new Array(t).fill(0);for(let o of e)for(let n=0;n<t;n++)r[n]+=o[n]??0;for(let o=0;o<t;o++)r[o]/=e.length;return r}throw new Error("Unsupported embedding shape")}import{createHash as at}from"node:crypto";var K=class{name="hash-fallback";dimensions=128;async embed(e){let t=new Array(this.dimensions).fill(0),r=e.toLowerCase().split(/\s+/).filter(Boolean);for(let o of r){let i=at("sha256").update(o).digest().readUInt32BE(0)%this.dimensions;t[i]+=1}return ct(t)}async embedMany(e){return Promise.all(e.map(t=>this.embed(t)))}};function ct(s){let e=Math.sqrt(s.reduce((t,r)=>t+r*r,0));return e===0?s:s.map(t=>t/e)}var q=class{constructor(e,t=new K){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 pe(){let s=process.env.HF_TOKEN,e=process.env.HF_EMBEDDING_MODEL??"sentence-transformers/all-MiniLM-L6-v2",t=s?new H({token:s,model:e}):null;return new q(t)}async function lt(){let s=Q(),e=new M().detect(),t=ie({provider:s.storage.provider,huggingface:s.storage.huggingface,localRoot:s.storage.localRoot}),r=new G(t,e.id,e.name,e.remote??e.name),o=new C,n=await new L(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 B({projectId:e.id,rootPath:e.rootPath,model:process.env.HF_EMBEDDING_MODEL??"sentence-transformers/all-MiniLM-L6-v2",storage:r,embeddings:pe(),graph:o}),c=await i.initialize(),l=process.argv.slice(2).join(" ")||"memory storage hugging face",a=await i.search(l,5);console.log({ok:!0,query:l,...c,results:a.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)}))})}lt().catch(s=>{console.error(s),process.exit(1)});
@@ -1,4 +1,4 @@
1
1
  import"dotenv/config";import{existsSync as L,readFileSync as V}from"node:fs";import{homedir as K}from"node:os";import{join as J}from"node:path";function B(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 F(){let s=process.env.TOOLNET_GLOBAL_ENV??J(K(),".config","toolnet-memory",".env");if(!L(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]=B(r.slice(o+1)))}}F();function l(s,e){return s===void 0?e:["1","true","yes","on"].includes(s.toLowerCase())}function u(s,e){if(!s)return e;let t=Number(s);return Number.isFinite(t)?t:e}function P(){return{memory:{autoCapture:l(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:l(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:l(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:l(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:u(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:u(process.env.MEMORY_RERANK_TOP,10),finalContext:u(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:u(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",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:u(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as U}from"node:crypto";import{existsSync as A,mkdirSync as H,readFileSync as Y,renameSync as G,writeFileSync as W}from"node:fs";import{basename as Z,dirname as f,join as S,parse as k,resolve as y}from"node:path";var M=".toolnet",Q="project.json";function X(s){return U("sha256").update(s).digest("hex").slice(0,16)}function w(s){return S(s,M,Q)}function q(s){return A(w(s))}function ee(s){let e=y(s),t=k(e).root;for(;;){if(q(e))return e;if(e===t)break;let r=f(e);if(r===e)break;e=r}return null}function te(s){let e=y(s),t=k(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(n=>A(S(e,n))))return e;if(e===t)break;let o=f(e);if(o===e)break;e=o}return y(s)}function re(s){let e;try{e=JSON.parse(Y(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:f(f(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 b(s,e){let t=S(s,M);H(t,{recursive:!0});let r=w(s),o=`${r}.tmp-${process.pid}`;W(o,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),G(o,r)}function R(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 h=class{detect(e=process.cwd()){let t=y(e),r=ee(t);if(r){let p=w(r),c=re(p);return c.rootPath!==r&&(c.rootPath=r,c.updatedAt=new Date().toISOString(),b(r,c)),R(c,r)}let o=te(t),n=new Date().toISOString(),i=Z(o),a={version:1,id:X(o),name:i,remote:i,rootPath:o,createdAt:n,updatedAt:n,graphVersion:0,memoryVersion:0};return b(o,a),R(a,o)}};import{homedir as je}from"node:os";import{join as ve}from"node:path";import{DeleteObjectCommand as oe,GetObjectCommand as se,HeadObjectCommand as ne,ListObjectsV2Command as ie,PutObjectCommand as ae,S3Client as ce}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 ce({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 ae({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await pe(this.client,new se({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 ne({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 ie({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 T,mkdir as me,readFile as de,readdir as ue,rm as ge,stat as E,writeFile as le}from"node:fs/promises";import{dirname as fe,join as ye,relative as O,resolve as he}from"node:path";var g=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return he(this.root,t)}async put(e,t){let r=this.path(e);await me(fe(r),{recursive:!0}),await le(r,t)}async get(e){try{return await de(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 T(this.path(e)),!0}catch{return!1}}async delete(e){await ge(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await T(t)}catch{return r}let o=async i=>{let a=await ue(i,{withFileTypes:!0});for(let p of a){let c=ye(i,p.name);if(p.isDirectory()){await o(c);continue}let m=await E(c);r.push({key:O(this.root,c),size:m.size,updatedAt:m.mtime.toISOString()})}},n=await E(t);return n.isDirectory()?await o(t):r.push({key:O(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),r}};function C(s){let e=s.localRoot??ve(je(),".toolnet-memory","storage");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}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new g(e))}return new g(e)}function Se(s){return new Promise(e=>setTimeout(e,s))}async function I(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 p=Math.min(o,r*2**(i-1)),c=Math.floor(Math.random()*Math.max(1,p*.2));await Se(p+c)}throw n}var we=new Set(["put","get","getText","delete","list"]);function _(s,e={}){return new Proxy(s,{get(t,r){let o=Reflect.get(t,r,t);return typeof o!="function"?o:we.has(r)?(...n)=>I(()=>Promise.resolve(o.apply(t,n)),e):o.bind(t)}})}function $(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 N(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 v=class{constructor(e,t,r,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=$(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=N(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 xe=["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"],d=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),p=[];for(let m of xe){let D=`${i}/${m}`,x=await this.storage.get(D);x&&(await this.storage.put(`${a}/${m}`,x,"application/json"),p.push(m))}if(p.length===0)return null;let c={version:1,id:n,projectId:e,createdAt:o,reason:t,objects:p,metadata:r};return await this.storage.put(`${a}/snapshot.json`,JSON.stringify(c,null,2),"application/json"),c}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 p of n.objects){let c=await this.storage.get(`${r}/${p}`);c&&(await this.storage.put(`${i}/${p}`,c,"application/json"),a.push(p))}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 z(s,e){let t=new d(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 Pe(){let s=process.argv[2],e=P(),t=new h().detect(),r=_(C({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),o=new v(r,t.id,t.name,t.remote??t.name),n=new d(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 z(o,t.id));return}throw new Error("Usage: snapshot-cli list|create|restore|recover-latest")}Pe().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 F(){let s=process.env.TOOLNET_GLOBAL_ENV??J(K(),".config","toolnet-memory",".env");if(!L(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]=B(r.slice(o+1)))}}F();function y(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 R(){return{memory:{autoCapture:y(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:y(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:y(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:y(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates: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",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 U}from"node:crypto";import{existsSync as x,mkdirSync as H,readFileSync as Y,renameSync as G,writeFileSync as W}from"node:fs";import{basename as Z,dirname as h,join as v,parse as M,resolve as l}from"node:path";var T=".toolnet",Q="project.json";function X(s){return U("sha256").update(s).digest("hex").slice(0,16)}function P(s){return v(s,T,Q)}function q(s){return x(P(s))}function ee(s,e){let t=l(s),r=M(t).root;for(;;){if(q(t))return t;if(t===r||e&&t===l(e))break;let o=h(t);if(o===t)break;t=o}return null}function te(s){let e=l(s),t=M(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=h(e);if(o===e)break;e=o}return l(s)}function re(s){let e;try{e=JSON.parse(Y(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:h(h(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 A(s,e){let t=v(s,T);H(t,{recursive:!0});let r=P(s),o=`${r}.tmp-${process.pid}`;W(o,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),G(o,r)}function k(s,e){return{id:s.id,name:s.name,remote:s.remote,rootPath:e,createdAt:s.createdAt,updatedAt:s.updatedAt,graphVersion:s.graphVersion,memoryVersion:s.memoryVersion,metadata:s.metadata}}var j=class{detect(e=process.cwd()){let t=l(e),r=te(t),n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>x(v(r,m))),i=ee(t,n?r:void 0);if(i){let m=P(i),d=re(m);return d.rootPath!==i&&(d.rootPath=i,d.updatedAt=new Date().toISOString(),A(i,d)),k(d,i)}let a=new Date().toISOString(),c=Z(r),p={version:1,id:X(r),name:c,remote:c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return A(r,p),k(p,r)}};import{homedir as je}from"node:os";import{join as ve}from"node:path";import{DeleteObjectCommand as oe,GetObjectCommand as se,HeadObjectCommand as ne,ListObjectsV2Command as ie,PutObjectCommand as ae,S3Client as ce}from"@aws-sdk/client-s3";import{getSignedUrl as pe}from"@aws-sdk/s3-request-presigner";var S=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new ce({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 ae({Bucket:this.bucket,Key:e,Body:o,ContentType:r}))}async get(e){let t=await pe(this.client,new se({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 ne({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 ie({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 E,mkdir as me,readFile as de,readdir as ue,rm as ge,stat as O,writeFile as le}from"node:fs/promises";import{dirname as fe,join as ye,relative as C,resolve as he}from"node:path";var f=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return he(this.root,t)}async put(e,t){let r=this.path(e);await me(fe(r),{recursive:!0}),await le(r,t)}async get(e){try{return await de(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 E(this.path(e)),!0}catch{return!1}}async delete(e){await ge(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await E(t)}catch{return r}let o=async i=>{let a=await ue(i,{withFileTypes:!0});for(let c of a){let p=ye(i,c.name);if(c.isDirectory()){await o(p);continue}let m=await O(p);r.push({key:C(this.root,p),size:m.size,updatedAt:m.mtime.toISOString()})}},n=await O(t);return n.isDirectory()?await o(t):r.push({key:C(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),r}};function I(s){let e=s.localRoot??ve(je(),".toolnet-memory","storage");if(s.provider==="huggingface"){let t=s.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new S({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new f(e))}return new f(e)}function Se(s){return new Promise(e=>setTimeout(e,s))}async function _(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 Se(c+p)}throw n}var we=new Set(["put","get","getText","delete","list"]);function $(s,e={}){return new Proxy(s,{get(t,r){let o=Reflect.get(t,r,t);return typeof o!="function"?o:we.has(r)?(...n)=>_(()=>Promise.resolve(o.apply(t,n)),e):o.bind(t)}})}function N(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 w=class{constructor(e,t,r,o){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=r,this.folder=N(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 xe=["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"],u=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 m of xe){let d=`${i}/${m}`,b=await this.storage.get(d);b&&(await this.storage.put(`${a}/${m}`,b,"application/json"),c.push(m))}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 D(s,e){let t=new u(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 Pe(){let s=process.argv[2],e=R(),t=new j().detect(),r=$(I({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),o=new w(r,t.id,t.name,t.remote??t.name),n=new u(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 D(o,t.id));return}throw new Error("Usage: snapshot-cli list|create|restore|recover-latest")}Pe().catch(s=>{console.error(s instanceof Error?s.message:s),process.exit(1)});
@@ -0,0 +1 @@
1
+ import a from"node:fs";import n from"node:path";import{fileURLToPath as u}from"node:url";import{spawnSync as p}from"node:child_process";var s="toolnet-memory";function i(o,e,t={}){return p(o,e,{encoding:"utf8",stdio:t.capture?["ignore","pipe","pipe"]:"inherit"})}function g(){let o=n.dirname(u(import.meta.url));return n.resolve(o,"..")}function m(o){try{let e=JSON.parse(a.readFileSync(n.join(o,"package.json"),"utf8"));return String(e.version??"unknown")}catch{return"unknown"}}function d(o){let e=`${n.sep}lib${n.sep}node_modules${n.sep}${s}`;return o.endsWith(e)?o.slice(0,-e.length)||n.parse(o).root:null}function f(){let o=g(),e=m(o),t=i("npm",["view",`${s}@latest`,"version","--silent"],{capture:!0});t.status!==0&&(console.error("Unable to check the latest ToolNet Memory version."),t.stderr&&console.error(t.stderr.trim()),process.exit(1));let r=(t.stdout??"").trim();if(console.log(""),console.log("ToolNet Memory Update"),console.log("====================="),console.log(""),console.log(`Current: v${e}`),console.log(`Latest : v${r}`),console.log(""),e===r){console.log("\u2713 ToolNet Memory is already up to date"),console.log("");return}let l=d(o);l||(console.log("This appears to be a development checkout."),console.log(""),console.log("Self-update is disabled for source checkouts."),console.log(""),console.log("For the published CLI, install/update with:"),console.log(" npx toolnet-memory-install"),console.log(""),process.exit(1)),console.log(`Updating to v${r}...`),console.log("");let c=i("npm",["install","-g","--prefix",l,`${s}@latest`,"--no-fund","--no-audit","--loglevel=error"]);c.status!==0&&(console.error(""),console.error("\u2717 Update failed"),console.error(""),console.error("You can retry using:"),console.error(" npx toolnet-memory-install"),process.exit(c.status??1)),console.log(""),console.log(`\u2713 ToolNet Memory updated to v${r}`),console.log("")}f();
@@ -1,9 +1,9 @@
1
1
  import{existsSync as ne,readFileSync as ie}from"node:fs";import{homedir as ae}from"node:os";import{join as ce}from"node:path";function pe(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 de(){let r=process.env.TOOLNET_GLOBAL_ENV??ce(ae(),".config","toolnet-memory",".env");if(!ne(r))return;let e=ie(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 s=o.indexOf("=");if(s<=0)continue;let i=o.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=pe(o.slice(s+1)))}}de();function j(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function y(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function z(){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:y(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:y(process.env.MEMORY_RERANK_TOP,10),finalContext:y(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:y(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",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:y(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as ue}from"node:crypto";import{existsSync as V,mkdirSync as me,readFileSync as le,renameSync as ge,writeFileSync as fe}from"node:fs";import{basename as ye,dirname as k,join as R,parse as W,resolve as v}from"node:path";var K=".toolnet",he="project.json";function Se(r){return ue("sha256").update(r).digest("hex").slice(0,16)}function T(r){return R(r,K,he)}function je(r){return V(T(r))}function ke(r){let e=v(r),t=W(e).root;for(;;){if(je(e))return e;if(e===t)break;let o=k(e);if(o===e)break;e=o}return null}function ve(r){let e=v(r),t=W(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>V(R(e,i))))return e;if(e===t)break;let s=k(e);if(s===e)break;e=s}return v(r)}function xe(r){let e;try{e=JSON.parse(le(r,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${r}: ${s instanceof Error?s.message:String(s)}`)}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:k(k(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 D(r,e){let t=R(r,K);me(t,{recursive:!0});let o=T(r),s=`${o}.tmp-${process.pid}`;fe(s,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),ge(s,o)}function L(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=v(e),o=ke(t);if(o){let d=T(o),p=xe(d);return p.rootPath!==o&&(p.rootPath=o,p.updatedAt=new Date().toISOString(),D(o,p)),L(p,o)}let s=ve(t),i=new Date().toISOString(),a=ye(s),c={version:1,id:Se(s),name:a,remote:a,rootPath:s,createdAt:i,updatedAt:i,graphVersion:0,memoryVersion:0};return D(s,c),L(c,s)}};import{homedir as De}from"node:os";import{join as Le}from"node:path";import{DeleteObjectCommand as we,GetObjectCommand as be,HeadObjectCommand as Pe,ListObjectsV2Command as Ae,PutObjectCommand as Re,S3Client as Te}from"@aws-sdk/client-s3";import{getSignedUrl as Me}from"@aws-sdk/s3-request-presigner";var w=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Te({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 s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Re({Bucket:this.bucket,Key:e,Body:s,ContentType:o}))}async get(e){let t=await Me(this.client,new be({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 Pe({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=[],o;do{let s=await this.client.send(new Ae({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of s.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=s.IsTruncated?s.NextContinuationToken:void 0}while(o);return t}};import{access as J,mkdir as Ie,readFile as Oe,readdir as Ee,rm as Ce,stat as B,writeFile as _e}from"node:fs/promises";import{dirname as Ne,join as $e,relative as F,resolve as ze}from"node:path";var h=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return ze(this.root,t)}async put(e,t){let o=this.path(e);await Ie(Ne(o),{recursive:!0}),await _e(o,t)}async get(e){try{return await Oe(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 J(this.path(e)),!0}catch{return!1}}async delete(e){await Ce(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await J(t)}catch{return o}let s=async a=>{let c=await Ee(a,{withFileTypes:!0});for(let d of c){let p=$e(a,d.name);if(d.isDirectory()){await s(p);continue}let f=await B(p);o.push({key:F(this.root,p),size:f.size,updatedAt:f.mtime.toISOString()})}},i=await B(t);return i.isDirectory()?await s(t):o.push({key:F(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),o}};function H(r){let e=r.localRoot??Le(De(),".toolnet-memory","storage");if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new w({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new h(e))}return new h(e)}function Ve(r){return new Promise(e=>setTimeout(e,r))}async function G(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,s=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(s,o*2**(a-1)),p=Math.floor(Math.random()*Math.max(1,d*.2));await Ve(d+p)}throw i}var We=new Set(["put","get","getText","delete","list"]);function U(r,e={}){return new Proxy(r,{get(t,o){let s=Reflect.get(t,o,t);return typeof s!="function"?s:We.has(o)?(...i)=>G(()=>Promise.resolve(s.apply(t,i)),e):s.bind(t)}})}function Y(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 Z(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 s=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:e))}var b=class{constructor(e,t,o,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=Y(s??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,s=await this.provider.getText(e);if(s){let a;try{a=JSON.parse(s)}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 i={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:t};await this.provider.put(e,JSON.stringify(i,null,2)+`
2
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function de(){let r=process.env.TOOLNET_GLOBAL_ENV??ce(ae(),".config","toolnet-memory",".env");if(!ne(r))return;let e=ie(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 s=o.indexOf("=");if(s<=0)continue;let i=o.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=pe(o.slice(s+1)))}}de();function v(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function h(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function D(){return{memory:{autoCapture:v(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:v(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:v(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:v(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:h(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:h(process.env.MEMORY_RERANK_TOP,10),finalContext:h(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:h(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",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:h(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as ue}from"node:crypto";import{existsSync as M,mkdirSync as me,readFileSync as le,renameSync as ge,writeFileSync as fe}from"node:fs";import{basename as ye,dirname as x,join as b,parse as W,resolve as S}from"node:path";var K=".toolnet",he="project.json";function Se(r){return ue("sha256").update(r).digest("hex").slice(0,16)}function I(r){return b(r,K,he)}function je(r){return M(I(r))}function ke(r,e){let t=S(r),o=W(t).root;for(;;){if(je(t))return t;if(t===o||e&&t===S(e))break;let s=x(t);if(s===t)break;t=s}return null}function ve(r){let e=S(r),t=W(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>M(b(e,i))))return e;if(e===t)break;let s=x(e);if(s===e)break;e=s}return S(r)}function xe(r){let e;try{e=JSON.parse(le(r,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${r}: ${s instanceof Error?s.message:String(s)}`)}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:x(x(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 L(r,e){let t=b(r,K);me(t,{recursive:!0});let o=I(r),s=`${o}.tmp-${process.pid}`;fe(s,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),ge(s,o)}function V(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 w=class{detect(e=process.cwd()){let t=S(e),o=ve(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(u=>M(b(o,u))),a=ke(t,i?o:void 0);if(a){let u=I(a),l=xe(u);return l.rootPath!==a&&(l.rootPath=a,l.updatedAt=new Date().toISOString(),L(a,l)),V(l,a)}let c=new Date().toISOString(),p=ye(o),d={version:1,id:Se(o),name:p,remote:p,rootPath:o,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return L(o,d),V(d,o)}};import{homedir as De}from"node:os";import{join as Le}from"node:path";import{DeleteObjectCommand as we,GetObjectCommand as be,HeadObjectCommand as Pe,ListObjectsV2Command as Ae,PutObjectCommand as Re,S3Client as Te}from"@aws-sdk/client-s3";import{getSignedUrl as Me}from"@aws-sdk/s3-request-presigner";var P=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Te({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 s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Re({Bucket:this.bucket,Key:e,Body:s,ContentType:o}))}async get(e){let t=await Me(this.client,new be({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 Pe({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=[],o;do{let s=await this.client.send(new Ae({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of s.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=s.IsTruncated?s.NextContinuationToken:void 0}while(o);return t}};import{access as J,mkdir as Ie,readFile as Oe,readdir as Ee,rm as Ce,stat as B,writeFile as _e}from"node:fs/promises";import{dirname as Ne,join as $e,relative as F,resolve as ze}from"node:path";var j=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return ze(this.root,t)}async put(e,t){let o=this.path(e);await Ie(Ne(o),{recursive:!0}),await _e(o,t)}async get(e){try{return await Oe(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 J(this.path(e)),!0}catch{return!1}}async delete(e){await Ce(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await J(t)}catch{return o}let s=async a=>{let c=await Ee(a,{withFileTypes:!0});for(let p of c){let d=$e(a,p.name);if(p.isDirectory()){await s(d);continue}let u=await B(d);o.push({key:F(this.root,d),size:u.size,updatedAt:u.mtime.toISOString()})}},i=await B(t);return i.isDirectory()?await s(t):o.push({key:F(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),o}};function H(r){let e=r.localRoot??Le(De(),".toolnet-memory","storage");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}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new j(e))}return new j(e)}function Ve(r){return new Promise(e=>setTimeout(e,r))}async function G(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,s=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(s,o*2**(a-1)),d=Math.floor(Math.random()*Math.max(1,p*.2));await Ve(p+d)}throw i}var We=new Set(["put","get","getText","delete","list"]);function U(r,e={}){return new Proxy(r,{get(t,o){let s=Reflect.get(t,o,t);return typeof s!="function"?s:We.has(o)?(...i)=>G(()=>Promise.resolve(s.apply(t,i)),e):s.bind(t)}})}function Y(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 Z(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 s=e.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return s?`${s[1]}memory/records/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),s?`${s[1]}memory/vectors/${s[2]}`:(s=e.match(/^(projects\/[^/]+\/)graph\/(.+)$/),s?`${s[1]}code/graph/${s[2]}`:e))}var A=class{constructor(e,t,o,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=Y(s??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,s=await this.provider.getText(e);if(s){let a;try{a=JSON.parse(s)}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 i={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:t};await this.provider.put(e,JSON.stringify(i,null,2)+`
4
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,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 q}from"node:path";import{mkdirSync as Ge}from"node:fs";import{createHash as Ke}from"node:crypto";import{dirname as Je}from"node:path";import{mkdirSync as Be,readFileSync as Lr,renameSync as Fe,writeFileSync as He}from"node:fs";function X(r){return Ke("sha256").update(r).digest("hex")}function Q(r,e){Be(Je(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;He(t,JSON.stringify(e,null,2)+`
5
- `,{encoding:"utf8",mode:384}),Fe(t,r)}function Ue(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function g(r,e=20){let t=[],o=new Set;for(let s of r.slice().reverse()){let i=Ue(s);if(!(!i||o.has(i))&&(o.add(i),t.push(s),t.length>=e))break}return t.reverse()}function Ye(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",o=t;r&&(r.status==="completed"&&t!=="completed"?o="completed":t==="pending"&&(r.status==="in_progress"||r.status==="blocked")&&(o=r.status));let s=r&&Ye(e)?r.title:e.text;return{id:r?.id??X(e.key).slice(0,24),title:s,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 Ze(r,e){let t=`projects/${r.id}/work/observations/`,o=await e.list(t),s=[];for(let i of o.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)&&s.push(c)}catch{}}return s}async function te(r,e){let o=(await Ze(r,e)).flatMap(n=>n.observations).sort((n,l)=>{let N=n.occurredAt.localeCompare(l.occurredAt);if(N!==0)return N;let $=n.sequence-l.sequence;return $!==0?$:n.id.localeCompare(l.id)}),s=new Map,i=new Map,a,c,d,p=[],f=[],I=[],O=[],E=[],C=[];for(let n of o)switch(n.kind){case"goal":a=n.text;break;case"plan":c=n.text;break;case"phase":s.set(n.key,ee(s.get(n.key),n));break;case"task":i.set(n.key,ee(i.get(n.key),n));break;case"decision":p.push(n.text);break;case"blocker":f.push(n.text);break;case"warning":I.push(n.text);break;case"next_action":O.push(n.text);break;case"file":E.push(n.text);break;case"test":C.push(n.text);break;case"session":d={agent:n.agent,nativeSessionId:n.nativeSessionId,sessionKey:n.sessionKey,updatedAt:n.occurredAt};break}let m=Array.from(s.values()).sort((n,l)=>(n.order??Number.MAX_SAFE_INTEGER)-(l.order??Number.MAX_SAFE_INTEGER)),u=Array.from(i.values()).sort((n,l)=>(n.order??Number.MAX_SAFE_INTEGER)-(l.order??Number.MAX_SAFE_INTEGER)),P=m.find(n=>n.status==="in_progress")??m.find(n=>n.status==="blocked")??m.find(n=>n.status==="pending"),S=u.find(n=>n.status==="in_progress")??u.find(n=>n.status==="blocked")??u.find(n=>n.status==="pending"),oe=g([...O,...S?[S.title]:[],...!S&&P?[P.title]:[],...u.filter(n=>n.status==="pending").slice(0,5).map(n=>n.title)],8),se=g([...f,...m.filter(n=>n.status==="blocked").map(n=>n.title),...u.filter(n=>n.status==="blocked").map(n=>n.title)],20),A={version:1,projectId:r.id,projectName:r.name,goal:a,plan:c,phases:m,tasks:u,decisions:g(p,20),blockers:se,warnings:g(I,20),nextActions:oe,filesTouched:g(E,30),tests:g(C,20),currentPhase:P,currentTask:S,progress:{phasesTotal:m.length,phasesCompleted:m.filter(n=>n.status==="completed").length,tasksTotal:u.length,tasksCompleted:u.filter(n=>n.status==="completed").length,blocked:m.filter(n=>n.status==="blocked").length+u.filter(n=>n.status==="blocked").length},lastSession:d,updatedAt:o.length?o[o.length-1].occurredAt:new Date().toISOString()},_=q(r.rootPath,".toolnet","work");return Ge(_,{recursive:!0}),Q(q(_,"current.json"),A),await e.put(`projects/${r.id}/work/current.json`,JSON.stringify(A,null,2)+`
6
- `,"application/json"),A}async function M(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 Xe(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function Qe(r){let e=z(),t=U(H({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new b(t,r.id,r.name,r.remote??r.name)}function re(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 qe(){let[r="help",...e]=process.argv.slice(2),t=new x().detect(Xe(e,"--project")??process.cwd()),o=Qe(t);if(r==="reconcile"){let s=await te(t,o);re(s);return}if(r==="status"){let s=await M(t,o);if(!s){console.log("No active work state yet.");return}re(s);return}if(r==="json"){let s=await M(t,o);console.log(JSON.stringify(s,null,2));return}console.log(`Work Continuity
5
+ `,{encoding:"utf8",mode:384}),Fe(t,r)}function Ue(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 s of r.slice().reverse()){let i=Ue(s);if(!(!i||o.has(i))&&(o.add(i),t.push(s),t.length>=e))break}return t.reverse()}function Ye(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",o=t;r&&(r.status==="completed"&&t!=="completed"?o="completed":t==="pending"&&(r.status==="in_progress"||r.status==="blocked")&&(o=r.status));let s=r&&Ye(e)?r.title:e.text;return{id:r?.id??X(e.key).slice(0,24),title:s,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 Ze(r,e){let t=`projects/${r.id}/work/observations/`,o=await e.list(t),s=[];for(let i of o.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)&&s.push(c)}catch{}}return s}async function te(r,e){let o=(await Ze(r,e)).flatMap(n=>n.observations).sort((n,f)=>{let $=n.occurredAt.localeCompare(f.occurredAt);if($!==0)return $;let z=n.sequence-f.sequence;return z!==0?z:n.id.localeCompare(f.id)}),s=new Map,i=new Map,a,c,p,d=[],u=[],l=[],E=[],C=[],_=[];for(let n of o)switch(n.kind){case"goal":a=n.text;break;case"plan":c=n.text;break;case"phase":s.set(n.key,ee(s.get(n.key),n));break;case"task":i.set(n.key,ee(i.get(n.key),n));break;case"decision":d.push(n.text);break;case"blocker":u.push(n.text);break;case"warning":l.push(n.text);break;case"next_action":E.push(n.text);break;case"file":C.push(n.text);break;case"test":_.push(n.text);break;case"session":p={agent:n.agent,nativeSessionId:n.nativeSessionId,sessionKey:n.sessionKey,updatedAt:n.occurredAt};break}let g=Array.from(s.values()).sort((n,f)=>(n.order??Number.MAX_SAFE_INTEGER)-(f.order??Number.MAX_SAFE_INTEGER)),m=Array.from(i.values()).sort((n,f)=>(n.order??Number.MAX_SAFE_INTEGER)-(f.order??Number.MAX_SAFE_INTEGER)),R=g.find(n=>n.status==="in_progress")??g.find(n=>n.status==="blocked")??g.find(n=>n.status==="pending"),k=m.find(n=>n.status==="in_progress")??m.find(n=>n.status==="blocked")??m.find(n=>n.status==="pending"),oe=y([...E,...k?[k.title]:[],...!k&&R?[R.title]:[],...m.filter(n=>n.status==="pending").slice(0,5).map(n=>n.title)],8),se=y([...u,...g.filter(n=>n.status==="blocked").map(n=>n.title),...m.filter(n=>n.status==="blocked").map(n=>n.title)],20),T={version:1,projectId:r.id,projectName:r.name,goal:a,plan:c,phases:g,tasks:m,decisions:y(d,20),blockers:se,warnings:y(l,20),nextActions:oe,filesTouched:y(C,30),tests:y(_,20),currentPhase:R,currentTask:k,progress:{phasesTotal:g.length,phasesCompleted:g.filter(n=>n.status==="completed").length,tasksTotal:m.length,tasksCompleted:m.filter(n=>n.status==="completed").length,blocked:g.filter(n=>n.status==="blocked").length+m.filter(n=>n.status==="blocked").length},lastSession:p,updatedAt:o.length?o[o.length-1].occurredAt:new Date().toISOString()},N=q(r.rootPath,".toolnet","work");return Ge(N,{recursive:!0}),Q(q(N,"current.json"),T),await e.put(`projects/${r.id}/work/current.json`,JSON.stringify(T,null,2)+`
6
+ `,"application/json"),T}async function O(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 Xe(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function Qe(r){let e=D(),t=U(H({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new A(t,r.id,r.name,r.remote??r.name)}function re(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 qe(){let[r="help",...e]=process.argv.slice(2),t=new w().detect(Xe(e,"--project")??process.cwd()),o=Qe(t);if(r==="reconcile"){let s=await te(t,o);re(s);return}if(r==="status"){let s=await O(t,o);if(!s){console.log("No active work state yet.");return}re(s);return}if(r==="json"){let s=await O(t,o);console.log(JSON.stringify(s,null,2));return}console.log(`Work Continuity
7
7
 
8
8
  Commands:
9
9
  status [--project PATH]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolnet-memory",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "tsx src/index.ts",