toolnet-memory 0.2.2 → 0.2.3

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
1
  import{existsSync as ut}from"node:fs";import{dirname as lt,join as dt,resolve as mt}from"node:path";import{existsSync as se,readFileSync as ne}from"node:fs";import{homedir as ie}from"node:os";import{join as ae}from"node:path";function ce(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 pe(){let r=process.env.TOOLNET_GLOBAL_ENV??ae(ie(),".config","toolnet-memory",".env");if(!se(r))return;let e=ne(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]=ce(o.slice(s+1)))}}pe();function j(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 C(){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: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 _,mkdirSync as le,readFileSync as de,renameSync as me,writeFileSync as fe}from"node:fs";import{basename as ge,dirname as v,join as A,parse as W,resolve as k}from"node:path";var D=".toolnet",he="project.json";function ye(r){return ue("sha256").update(r).digest("hex").slice(0,16)}function T(r){return A(r,D,he)}function Se(r){return _(T(r))}function je(r){let e=k(r),t=W(e).root;for(;;){if(Se(e))return e;if(e===t)break;let o=v(e);if(o===e)break;e=o}return null}function ve(r){let e=k(r),t=W(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>_(A(e,i))))return e;if(e===t)break;let s=v(e);if(s===e)break;e=s}return k(r)}function ke(r){let e;try{e=JSON.parse(de(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:v(v(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 N(r,e){let t=A(r,D);le(t,{recursive:!0});let o=T(r),s=`${o}.tmp-${process.pid}`;fe(s,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),me(s,o)}function $(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=k(e),o=je(t);if(o){let n=T(o),u=ke(n);return u.rootPath!==o&&(u.rootPath=o,u.updatedAt=new Date().toISOString(),N(o,u)),$(u,o)}let s=ve(t),i=new Date().toISOString(),p=ge(s),l={version:1,id:ye(s),name:p,remote:p,rootPath:s,createdAt:i,updatedAt:i,graphVersion:0,memoryVersion:0};return N(s,l),$(l,s)}};import{homedir as We}from"node:os";import{join as De}from"node:path";import{DeleteObjectCommand as we,GetObjectCommand as xe,HeadObjectCommand as be,ListObjectsV2Command as Pe,PutObjectCommand as Ae,S3Client as Te}from"@aws-sdk/client-s3";import{getSignedUrl as Re}from"@aws-sdk/s3-request-presigner";var x=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 Ae({Bucket:this.bucket,Key:e,Body:s,ContentType:o}))}async get(e){let t=await Re(this.client,new xe({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 be({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new we({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let s=await this.client.send(new Pe({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 L,mkdir as Me,readFile as Oe,readdir as Ee,rm as Ie,stat as V,writeFile as Ce}from"node:fs/promises";import{dirname as Ne,join as $e,relative as B,resolve as _e}from"node:path";var y=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return _e(this.root,t)}async put(e,t){let o=this.path(e);await Me(Ne(o),{recursive:!0}),await Ce(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 L(this.path(e)),!0}catch{return!1}}async delete(e){await Ie(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await L(t)}catch{return o}let s=async p=>{let l=await Ee(p,{withFileTypes:!0});for(let n of l){let u=$e(p,n.name);if(n.isDirectory()){await s(u);continue}let g=await V(u);o.push({key:B(this.root,u),size:g.size,updatedAt:g.mtime.toISOString()})}},i=await V(t);return i.isDirectory()?await s(t):o.push({key:B(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),o}};function K(r){let e=r.localRoot??De(We(),".toolnet-memory","storage");if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new x({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new y(e))}return new y(e)}function Le(r){return new Promise(e=>setTimeout(e,r))}async function J(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,s=e.maxDelayMs??2e3,i;for(let p=1;p<=t;p++)try{return await r()}catch(l){if(i=l,p>=t)break;let n=Math.min(s,o*2**(p-1)),u=Math.floor(Math.random()*Math.max(1,n*.2));await Le(n+u)}throw i}var Ve=new Set(["put","get","getText","delete","list"]);function F(r,e={}){return new Proxy(r,{get(t,o){let s=Reflect.get(t,o,t);return typeof s!="function"?s:Ve.has(o)?(...i)=>J(()=>Promise.resolve(s.apply(t,i)),e):s.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 H(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=z(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 p;try{p=JSON.parse(s)}catch(l){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${l instanceof Error?l.message:String(l)}`)}if(typeof p.id=="string"&&p.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${p.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof p.createdAt=="string"&&(o=p.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
- `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=H(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,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 st,mkdirSync as nt,readFileSync as it,writeFileSync as at}from"node:fs";import{dirname as ct,join as X}from"node:path";import{createHash as Be}from"node:crypto";import{dirname as Ke}from"node:path";import{mkdirSync as Je,readFileSync as ro,renameSync as Fe,writeFileSync as ze}from"node:fs";function f(r){return Be("sha256").update(r).digest("hex")}function S(r,e){Je(Ke(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;ze(t,JSON.stringify(e,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 pe(){let r=process.env.TOOLNET_GLOBAL_ENV??ae(ie(),".config","toolnet-memory",".env");if(!se(r))return;let e=ne(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 a=o.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(a)&&process.env[a]===void 0&&(process.env[a]=ce(o.slice(s+1)))}}pe();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 N(){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 T,mkdirSync as le,readFileSync as de,renameSync as me,writeFileSync as fe}from"node:fs";import{basename as ge,dirname as k,join as x,parse as W,resolve as y}from"node:path";var D=".toolnet",he="project.json";function ye(r){return ue("sha256").update(r).digest("hex").slice(0,16)}function R(r){return x(r,D,he)}function Se(r){return T(R(r))}function je(r,e){let t=y(r),o=W(t).root;for(;;){if(Se(t))return t;if(t===o||e&&t===y(e))break;let s=k(t);if(s===t)break;t=s}return null}function ve(r){let e=y(r),t=W(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(a=>T(x(e,a))))return e;if(e===t)break;let s=k(e);if(s===e)break;e=s}return y(r)}function ke(r){let e;try{e=JSON.parse(de(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 $(r,e){let t=x(r,D);le(t,{recursive:!0});let o=R(r),s=`${o}.tmp-${process.pid}`;fe(s,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),me(s,o)}function _(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=y(e),o=ve(t),a=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>T(x(o,m))),c=je(t,a?o:void 0);if(c){let m=R(c),n=ke(m);return n.rootPath!==c&&(n.rootPath=c,n.updatedAt=new Date().toISOString(),$(c,n)),_(n,c)}let u=new Date().toISOString(),i=ge(o),l={version:1,id:ye(o),name:i,remote:i,rootPath:o,createdAt:u,updatedAt:u,graphVersion:0,memoryVersion:0};return $(o,l),_(l,o)}};import{homedir as We}from"node:os";import{join as De}from"node:path";import{DeleteObjectCommand as we,GetObjectCommand as xe,HeadObjectCommand as be,ListObjectsV2Command as Pe,PutObjectCommand as Ae,S3Client as Te}from"@aws-sdk/client-s3";import{getSignedUrl as Re}from"@aws-sdk/s3-request-presigner";var b=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 Ae({Bucket:this.bucket,Key:e,Body:s,ContentType:o}))}async get(e){let t=await Re(this.client,new xe({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 be({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new we({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let s=await this.client.send(new Pe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let a of s.Contents??[])a.Key&&t.push({key:a.Key,size:a.Size,updatedAt:a.LastModified?.toISOString()});o=s.IsTruncated?s.NextContinuationToken:void 0}while(o);return t}};import{access as B,mkdir as Me,readFile as Oe,readdir as Ee,rm as Ie,stat as L,writeFile as Ce}from"node:fs/promises";import{dirname as Ne,join as $e,relative as V,resolve as _e}from"node:path";var S=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return _e(this.root,t)}async put(e,t){let o=this.path(e);await Me(Ne(o),{recursive:!0}),await Ce(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 B(this.path(e)),!0}catch{return!1}}async delete(e){await Ie(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await B(t)}catch{return o}let s=async c=>{let u=await Ee(c,{withFileTypes:!0});for(let i of u){let l=$e(c,i.name);if(i.isDirectory()){await s(l);continue}let m=await L(l);o.push({key:V(this.root,l),size:m.size,updatedAt:m.mtime.toISOString()})}},a=await L(t);return a.isDirectory()?await s(t):o.push({key:V(this.root,t),size:a.size,updatedAt:a.mtime.toISOString()}),o}};function K(r){let e=r.localRoot??De(We(),".toolnet-memory","storage");if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new b({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new S(e))}return new S(e)}function Be(r){return new Promise(e=>setTimeout(e,r))}async function J(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,s=e.maxDelayMs??2e3,a;for(let c=1;c<=t;c++)try{return await r()}catch(u){if(a=u,c>=t)break;let i=Math.min(s,o*2**(c-1)),l=Math.floor(Math.random()*Math.max(1,i*.2));await Be(i+l)}throw a}var Le=new Set(["put","get","getText","delete","list"]);function F(r,e={}){return new Proxy(r,{get(t,o){let s=Reflect.get(t,o,t);return typeof s!="function"?s:Le.has(o)?(...a)=>J(()=>Promise.resolve(s.apply(t,a)),e):s.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 H(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 P=class{constructor(e,t,o,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=z(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 c;try{c=JSON.parse(s)}catch(u){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${u instanceof Error?u.message:String(u)}`)}if(typeof c.id=="string"&&c.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${c.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof c.createdAt=="string"&&(o=c.createdAt)}let a={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:t};await this.provider.put(e,JSON.stringify(a,null,2)+`
4
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=H(e),e===this.sourcePrefix)return this.targetPrefix;if(e.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+e.slice(this.sourcePrefix.length);if(e===this.targetPrefix||e.startsWith(`${this.targetPrefix}/`))return e;if(e.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${e}`].join(" "));return e}async put(e,t,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 st,mkdirSync as nt,readFileSync as it,writeFileSync as at}from"node:fs";import{dirname as ct,join as X}from"node:path";import{createHash as Ve}from"node:crypto";import{dirname as Ke}from"node:path";import{mkdirSync as Je,readFileSync as ro,renameSync as Fe,writeFileSync as ze}from"node:fs";function g(r){return Ve("sha256").update(r).digest("hex")}function j(r,e){Je(Ke(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;ze(t,JSON.stringify(e,null,2)+`
5
5
  `,{encoding:"utf8",mode:384}),Fe(t,r)}import{existsSync as Y,mkdirSync as He,readFileSync as Ue,statSync as U,writeFileSync as Ge}from"node:fs";import{dirname as Ye,join as Qe}from"node:path";var G=64*1024,qe=`# ToolNet Project Operating Manual
6
6
 
7
7
  This file contains persistent instructions for AI agents working on this project.
@@ -45,12 +45,12 @@ Things an AI agent should always remember.
45
45
  <!--
46
46
  - [advisory] Prefer small focused files.
47
47
  -->
48
- `;function P(r){return Qe(r.rootPath,".toolnet","PROJECT.md")}function Ze(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function Xe(r){let e=[],t=new Set,o=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=o.exec(r);){let i=s[1].toLowerCase(),p=Ze(s[2]);if(!p)continue;let l=`${i}:${p.toLowerCase()}`;t.has(l)||(t.add(l),e.push({id:f(l).slice(0,24),mode:i,text:p,source:"manual"}))}return e}function et(r){let e=P(r);return Y(e)||(He(Ye(e),{recursive:!0}),Ge(e,qe,{encoding:"utf8",mode:384})),e}function R(r,e=!1){let t=e?et(r):P(r);if(!Y(t))return null;if(U(t).size>G)throw new Error(`PROJECT.md exceeds ${G} bytes`);let s=Ue(t,"utf8");return{path:t,content:s,digest:f(s),rules:Xe(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(U(t).mtimeMs).toISOString()}}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}}async function Q(r,e){let t=await e.getText(`projects/${r.id}/work/handoff-latest.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function q(r,e){let t=await e.getText(`projects/${r.id}/work/semantic/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}function O(r){if(!r)return 0;let e=Array.from(r).length,t=r.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(e/3.5,t*1.3))}function d(r,e){let t=r.replace(/\s+/g," ").trim();return t.length<=e?t:t.slice(0,Math.max(0,e-1)).trimEnd()+"\u2026"}function tt(r){let e=[],t=!1;for(let o of r.split(/\r?\n/u)){let s=o.trim();if(s.includes("<!--")&&(t=!0),t){s.includes("-->")&&(t=!1);continue}let i=s.toLowerCase();if(!(!s||s.startsWith("#")||s==="```"||i.startsWith("- [enforce]")||i.startsWith("* [enforce]")||i.startsWith("- [advisory]")||i.startsWith("* [advisory]"))&&(s=s.replace(/^[-*]\s+/u,""),s&&e.push(d(s,280)),e.length>=16))break}return e}function rt(r){let e=[],t=[];for(let o of r.split(/\\r?\\n/u)){let s=o.trim(),i=s.toLowerCase(),l=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(u=>i.startsWith(u));if(!l)continue;let n=s.slice(l.length).trim();n&&(l.includes("enforce")?e.push(n):t.push(n))}return{enforce:e,advisory:t}}function ot(r,e){let t=[];for(let o of r){let s=[...t,o].join(`
49
- `);if(O(s)<=e){t.push(o);continue}let i=O(t.join(`
50
- `)),p=Math.max(0,e-i);if(p>=16){let l=Math.floor(p*3.2),n=d(o,l);n&&t.push(n)}break}return t.join(`
51
- `).trim()}async function Z(r){let e=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),t=R(r.project,!1),o=t?.content??"";o||(o=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let s=rt(o),i=t?t.rules.filter(c=>c.mode==="enforce").map(c=>c.text):s.enforce,p=t?t.rules.filter(c=>c.mode==="advisory").map(c=>c.text):s.advisory,l=o?tt(o):[],n=await M(r.project,r.storage),u=await q(r.project,r.storage),g=await Q(r.project,r.storage),a=[];if(a.push("[TOOLNET PROJECT CONTEXT]"),a.push(`Project: ${r.project.name}`),a.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),o&&a.push(`Full operating manual: ${P(r.project)}`),i.length){a.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let c of i.slice(0,24))a.push(`- [ENFORCE] ${d(c,240)}`)}if(p.length){a.push("","PROJECT PREFERENCES");for(let c of p.slice(0,10))a.push(`- ${d(c,220)}`)}if(u&&(u.mission&&a.push("","MISSION",d(u.mission.value,420)),u.activeObjective&&a.push("","CURRENT OBJECTIVE",d(u.activeObjective.value,420)),u.why&&a.push("","WHY THIS WORK MATTERS",d(u.why.value,420)),u.desiredOutcome&&a.push("","DESIRED OUTCOME",d(u.desiredOutcome.value,420)),u.planRationale&&a.push("","WHY THIS APPROACH",d(u.planRationale.value,420))),n){if(a.push("","ACTIVE WORK"),n.goal&&a.push(`Goal: ${d(n.goal,320)}`),n.plan&&a.push(`Plan: ${d(n.plan,320)}`),a.push(`Progress: phases ${n.progress.phasesCompleted}/${n.progress.phasesTotal}; tasks ${n.progress.tasksCompleted}/${n.progress.tasksTotal}; blocked ${n.progress.blocked}`),n.currentPhase&&a.push(`Current phase: ${n.currentPhase.title} [${n.currentPhase.status}]`),n.currentPhase&&u){let c=u.phases.find(m=>m.order===n.currentPhase?.order);c&&(c.objective&&a.push(`Phase objective: ${d(c.objective.value,340)}`),c.why?a.push(`Why this phase: ${d(c.why.value,340)}`):a.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),c.deliverable&&a.push(`Deliverable: ${d(c.deliverable.value,340)}`),c.dependencies.length&&a.push(`Depends on: ${c.dependencies.slice(0,4).map(m=>d(m.value,180)).join("; ")}`),c.acceptanceCriteria.length&&(a.push("","DEFINITION OF DONE"),c.acceptanceCriteria.slice(0,6).forEach(m=>{a.push(`- ${d(m.value,260)}`)})),c.openQuestions.length&&(a.push("","OPEN QUESTIONS FOR CURRENT PHASE"),c.openQuestions.slice(0,4).forEach(m=>{a.push(`- ${d(m.value,260)}`)})))}n.currentTask&&a.push(`Current task: ${n.currentTask.title} [${n.currentTask.status}]`),n.nextActions.length&&(a.push("","NEXT ACTIONS"),n.nextActions.slice(0,6).forEach((c,m)=>{a.push(`${m+1}. ${d(c,260)}`)})),n.blockers.length&&(a.push("","BLOCKERS"),n.blockers.slice(0,5).forEach(c=>{a.push(`- ${d(c,260)}`)})),n.warnings.length&&(a.push("","ATTENTION"),n.warnings.slice(-5).forEach(c=>{a.push(`- ${d(c,260)}`)})),n.decisions.length&&(a.push("","RECENT DECISIONS"),n.decisions.slice(-5).forEach(c=>{a.push(`- ${d(c,260)}`)})),n.lastSession&&a.push("",`Last work session: ${n.lastSession.agent} / ${n.lastSession.nativeSessionId}`)}if(u&&u.openQuestions.length&&(a.push("","UNRESOLVED QUESTIONS"),u.openQuestions.slice(0,5).forEach(c=>{a.push(`- ${d(c.value,260)}`)})),g&&a.push(`Latest handoff: ${g.reason} / ${g.sourceSession.agent}`),l.length){a.push("","OPERATING NOTES");for(let c of l)a.push(`- ${c}`)}a.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let I=ot(a,e);return{version:1,projectId:r.project.id,projectName:r.project.name,text:I,estimatedTokens:O(I),maxTokens:e,hasManual:!!o,hasWorkState:!!n,hasHandoff:!!g,generatedAt:new Date().toISOString()}}function ee(r){return X(r.rootPath,".toolnet","context","startup.md")}function pt(r){return X(r.rootPath,".toolnet","context","startup.json")}function te(r,e){let t=ee(r);nt(ct(t),{recursive:!0}),at(t,e.text.endsWith(`
48
+ `;function A(r){return Qe(r.rootPath,".toolnet","PROJECT.md")}function Ze(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function Xe(r){let e=[],t=new Set,o=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=o.exec(r);){let a=s[1].toLowerCase(),c=Ze(s[2]);if(!c)continue;let u=`${a}:${c.toLowerCase()}`;t.has(u)||(t.add(u),e.push({id:g(u).slice(0,24),mode:a,text:c,source:"manual"}))}return e}function et(r){let e=A(r);return Y(e)||(He(Ye(e),{recursive:!0}),Ge(e,qe,{encoding:"utf8",mode:384})),e}function M(r,e=!1){let t=e?et(r):A(r);if(!Y(t))return null;if(U(t).size>G)throw new Error(`PROJECT.md exceeds ${G} bytes`);let s=Ue(t,"utf8");return{path:t,content:s,digest:g(s),rules:Xe(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(U(t).mtimeMs).toISOString()}}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}}async function Q(r,e){let t=await e.getText(`projects/${r.id}/work/handoff-latest.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function q(r,e){let t=await e.getText(`projects/${r.id}/work/semantic/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}function E(r){if(!r)return 0;let e=Array.from(r).length,t=r.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(e/3.5,t*1.3))}function d(r,e){let t=r.replace(/\s+/g," ").trim();return t.length<=e?t:t.slice(0,Math.max(0,e-1)).trimEnd()+"\u2026"}function tt(r){let e=[],t=!1;for(let o of r.split(/\r?\n/u)){let s=o.trim();if(s.includes("<!--")&&(t=!0),t){s.includes("-->")&&(t=!1);continue}let a=s.toLowerCase();if(!(!s||s.startsWith("#")||s==="```"||a.startsWith("- [enforce]")||a.startsWith("* [enforce]")||a.startsWith("- [advisory]")||a.startsWith("* [advisory]"))&&(s=s.replace(/^[-*]\s+/u,""),s&&e.push(d(s,280)),e.length>=16))break}return e}function rt(r){let e=[],t=[];for(let o of r.split(/\\r?\\n/u)){let s=o.trim(),a=s.toLowerCase(),u=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(l=>a.startsWith(l));if(!u)continue;let i=s.slice(u.length).trim();i&&(u.includes("enforce")?e.push(i):t.push(i))}return{enforce:e,advisory:t}}function ot(r,e){let t=[];for(let o of r){let s=[...t,o].join(`
49
+ `);if(E(s)<=e){t.push(o);continue}let a=E(t.join(`
50
+ `)),c=Math.max(0,e-a);if(c>=16){let u=Math.floor(c*3.2),i=d(o,u);i&&t.push(i)}break}return t.join(`
51
+ `).trim()}async function Z(r){let e=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),t=M(r.project,!1),o=t?.content??"";o||(o=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let s=rt(o),a=t?t.rules.filter(p=>p.mode==="enforce").map(p=>p.text):s.enforce,c=t?t.rules.filter(p=>p.mode==="advisory").map(p=>p.text):s.advisory,u=o?tt(o):[],i=await O(r.project,r.storage),l=await q(r.project,r.storage),m=await Q(r.project,r.storage),n=[];if(n.push("[TOOLNET PROJECT CONTEXT]"),n.push(`Project: ${r.project.name}`),n.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),o&&n.push(`Full operating manual: ${A(r.project)}`),a.length){n.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let p of a.slice(0,24))n.push(`- [ENFORCE] ${d(p,240)}`)}if(c.length){n.push("","PROJECT PREFERENCES");for(let p of c.slice(0,10))n.push(`- ${d(p,220)}`)}if(l&&(l.mission&&n.push("","MISSION",d(l.mission.value,420)),l.activeObjective&&n.push("","CURRENT OBJECTIVE",d(l.activeObjective.value,420)),l.why&&n.push("","WHY THIS WORK MATTERS",d(l.why.value,420)),l.desiredOutcome&&n.push("","DESIRED OUTCOME",d(l.desiredOutcome.value,420)),l.planRationale&&n.push("","WHY THIS APPROACH",d(l.planRationale.value,420))),i){if(n.push("","ACTIVE WORK"),i.goal&&n.push(`Goal: ${d(i.goal,320)}`),i.plan&&n.push(`Plan: ${d(i.plan,320)}`),n.push(`Progress: phases ${i.progress.phasesCompleted}/${i.progress.phasesTotal}; tasks ${i.progress.tasksCompleted}/${i.progress.tasksTotal}; blocked ${i.progress.blocked}`),i.currentPhase&&n.push(`Current phase: ${i.currentPhase.title} [${i.currentPhase.status}]`),i.currentPhase&&l){let p=l.phases.find(f=>f.order===i.currentPhase?.order);p&&(p.objective&&n.push(`Phase objective: ${d(p.objective.value,340)}`),p.why?n.push(`Why this phase: ${d(p.why.value,340)}`):n.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),p.deliverable&&n.push(`Deliverable: ${d(p.deliverable.value,340)}`),p.dependencies.length&&n.push(`Depends on: ${p.dependencies.slice(0,4).map(f=>d(f.value,180)).join("; ")}`),p.acceptanceCriteria.length&&(n.push("","DEFINITION OF DONE"),p.acceptanceCriteria.slice(0,6).forEach(f=>{n.push(`- ${d(f.value,260)}`)})),p.openQuestions.length&&(n.push("","OPEN QUESTIONS FOR CURRENT PHASE"),p.openQuestions.slice(0,4).forEach(f=>{n.push(`- ${d(f.value,260)}`)})))}i.currentTask&&n.push(`Current task: ${i.currentTask.title} [${i.currentTask.status}]`),i.nextActions.length&&(n.push("","NEXT ACTIONS"),i.nextActions.slice(0,6).forEach((p,f)=>{n.push(`${f+1}. ${d(p,260)}`)})),i.blockers.length&&(n.push("","BLOCKERS"),i.blockers.slice(0,5).forEach(p=>{n.push(`- ${d(p,260)}`)})),i.warnings.length&&(n.push("","ATTENTION"),i.warnings.slice(-5).forEach(p=>{n.push(`- ${d(p,260)}`)})),i.decisions.length&&(n.push("","RECENT DECISIONS"),i.decisions.slice(-5).forEach(p=>{n.push(`- ${d(p,260)}`)})),i.lastSession&&n.push("",`Last work session: ${i.lastSession.agent} / ${i.lastSession.nativeSessionId}`)}if(l&&l.openQuestions.length&&(n.push("","UNRESOLVED QUESTIONS"),l.openQuestions.slice(0,5).forEach(p=>{n.push(`- ${d(p.value,260)}`)})),m&&n.push(`Latest handoff: ${m.reason} / ${m.sourceSession.agent}`),u.length){n.push("","OPERATING NOTES");for(let p of u)n.push(`- ${p}`)}n.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let C=ot(n,e);return{version:1,projectId:r.project.id,projectName:r.project.name,text:C,estimatedTokens:E(C),maxTokens:e,hasManual:!!o,hasWorkState:!!i,hasHandoff:!!m,generatedAt:new Date().toISOString()}}function ee(r){return X(r.rootPath,".toolnet","context","startup.md")}function pt(r){return X(r.rootPath,".toolnet","context","startup.json")}function te(r,e){let t=ee(r);nt(ct(t),{recursive:!0}),at(t,e.text.endsWith(`
52
52
  `)?e.text:e.text+`
53
- `,{encoding:"utf8",mode:384}),S(pt(r),e)}async function E(r,e,t=900){let o=await Z({project:r,storage:e,maxTokens:t}),s={version:1,projectId:r.id,projectName:r.name,text:o.text,digest:f(o.text),estimatedTokens:o.estimatedTokens,generatedAt:new Date().toISOString()};return te(r,s),await e.put(`projects/${r.id}/context/startup.md`,s.text+`
53
+ `,{encoding:"utf8",mode:384}),j(pt(r),e)}async function I(r,e,t=900){let o=await Z({project:r,storage:e,maxTokens:t}),s={version:1,projectId:r.id,projectName:r.name,text:o.text,digest:g(o.text),estimatedTokens:o.estimatedTokens,generatedAt:new Date().toISOString()};return te(r,s),await e.put(`projects/${r.id}/context/startup.md`,s.text+`
54
54
  `,"text/markdown"),await e.put(`projects/${r.id}/context/startup.json`,JSON.stringify(s,null,2)+`
55
- `,"application/json"),s}async function re(r,e,t=900){try{let s=await e.getText(`projects/${r.id}/context/startup.md`);if(s&&s.trim()){let i=s.trim(),p={version:1,projectId:r.id,projectName:r.name,text:i,digest:f(i),estimatedTokens:Math.ceil(i.length/3.5),generatedAt:new Date().toISOString()};return te(r,p),p}}catch{}let o=ee(r);if(st(o))try{let s=it(o,"utf8").trim();if(s)return{version:1,projectId:r.id,projectName:r.name,text:s,digest:f(s),estimatedTokens:Math.ceil(s.length/3.5),generatedAt:new Date().toISOString()}}catch{}try{return await E(r,e,t)}catch{return null}}function oe(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function ft(r){let e=mt(r);for(;;){if(ut(dt(e,".toolnet","project.json")))return e;let t=lt(e);if(t===e)return null;e=t}}function gt(r){let e=C(),t=F(K({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:2});return new b(t,r.id,r.name,r.remote??r.name)}async function ht(){let[r="print",...e]=process.argv.slice(2),t=oe(e,"--project")??process.cwd(),o=ft(t);if(!o)return;let s=new w().detect(o),i=gt(s),p=Number(oe(e,"--tokens")??900);if(r==="refresh"){let n=await E(s,i,Number.isFinite(p)?p:900);console.log(n.text);return}let l=await re(s,i,Number.isFinite(p)?p:900);if(l){if(r==="sync"){console.log(l.digest);return}process.stdout.write(l.text+`
55
+ `,"application/json"),s}async function re(r,e,t=900){try{let s=await e.getText(`projects/${r.id}/context/startup.md`);if(s&&s.trim()){let a=s.trim(),c={version:1,projectId:r.id,projectName:r.name,text:a,digest:g(a),estimatedTokens:Math.ceil(a.length/3.5),generatedAt:new Date().toISOString()};return te(r,c),c}}catch{}let o=ee(r);if(st(o))try{let s=it(o,"utf8").trim();if(s)return{version:1,projectId:r.id,projectName:r.name,text:s,digest:g(s),estimatedTokens:Math.ceil(s.length/3.5),generatedAt:new Date().toISOString()}}catch{}try{return await I(r,e,t)}catch{return null}}function oe(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function ft(r){let e=mt(r);for(;;){if(ut(dt(e,".toolnet","project.json")))return e;let t=lt(e);if(t===e)return null;e=t}}function gt(r){let e=N(),t=F(K({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:2});return new P(t,r.id,r.name,r.remote??r.name)}async function ht(){let[r="print",...e]=process.argv.slice(2),t=oe(e,"--project")??process.cwd(),o=ft(t);if(!o)return;let s=new w().detect(o),a=gt(s),c=Number(oe(e,"--tokens")??900);if(r==="refresh"){let i=await I(s,a,Number.isFinite(c)?c:900);console.log(i.text);return}let u=await re(s,a,Number.isFinite(c)?c:900);if(u){if(r==="sync"){console.log(u.digest);return}process.stdout.write(u.text+`
56
56
  `)}}ht().catch(()=>{process.exitCode=0});
package/bundle/context.js CHANGED
@@ -1,7 +1,7 @@
1
- import{existsSync as je,readFileSync as ve}from"node:fs";import{homedir as ke}from"node:os";import{join as we}from"node:path";function xe(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 be(){let r=process.env.TOOLNET_GLOBAL_ENV??we(ke(),".config","toolnet-memory",".env");if(!je(r))return;let e=ve(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 n=o.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(n)&&process.env[n]===void 0&&(process.env[n]=xe(o.slice(s+1)))}}be();function T(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function x(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function G(){return{memory:{autoCapture:T(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:T(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:T(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:T(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:x(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:x(process.env.MEMORY_RERANK_TOP,10),finalContext:x(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:x(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:x(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Pe}from"node:crypto";import{existsSync as q,mkdirSync as Ae,readFileSync as Te,renameSync as Re,writeFileSync as Oe}from"node:fs";import{basename as Me,dirname as R,join as V,parse as Z,resolve as O}from"node:path";var X=".toolnet",Ee="project.json";function Ie(r){return Pe("sha256").update(r).digest("hex").slice(0,16)}function K(r){return V(r,X,Ee)}function Ce(r){return q(K(r))}function Ne(r){let e=O(r),t=Z(e).root;for(;;){if(Ce(e))return e;if(e===t)break;let o=R(e);if(o===e)break;e=o}return null}function $e(r){let e=O(r),t=Z(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(n=>q(V(e,n))))return e;if(e===t)break;let s=R(e);if(s===e)break;e=s}return O(r)}function _e(r){let e;try{e=JSON.parse(Te(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:R(R(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 Y(r,e){let t=V(r,X);Ae(t,{recursive:!0});let o=K(r),s=`${o}.tmp-${process.pid}`;Oe(s,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),Re(s,o)}function Q(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var M=class{detect(e=process.cwd()){let t=O(e),o=Ne(t);if(o){let a=K(o),l=_e(a);return l.rootPath!==o&&(l.rootPath=o,l.updatedAt=new Date().toISOString(),Y(o,l)),Q(l,o)}let s=$e(t),n=new Date().toISOString(),p=Me(s),d={version:1,id:Ie(s),name:p,remote:p,rootPath:s,createdAt:n,updatedAt:n,graphVersion:0,memoryVersion:0};return Y(s,d),Q(d,s)}};import{homedir as Ze}from"node:os";import{join as Xe}from"node:path";import{DeleteObjectCommand as We,GetObjectCommand as De,HeadObjectCommand as Le,ListObjectsV2Command as Ve,PutObjectCommand as Ke,S3Client as Je}from"@aws-sdk/client-s3";import{getSignedUrl as ze}from"@aws-sdk/s3-request-presigner";var E=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Je({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 Ke({Bucket:this.bucket,Key:e,Body:s,ContentType:o}))}async get(e){let t=await ze(this.client,new De({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 Le({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 Ve({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let n of s.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});o=s.IsTruncated?s.NextContinuationToken:void 0}while(o);return t}};import{access as ee,mkdir as Be,readFile as Fe,readdir as He,rm as Ue,stat as te,writeFile as Ge}from"node:fs/promises";import{dirname as Ye,join as Qe,relative as re,resolve as qe}from"node:path";var b=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return qe(this.root,t)}async put(e,t){let o=this.path(e);await Be(Ye(o),{recursive:!0}),await Ge(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 ee(this.path(e)),!0}catch{return!1}}async delete(e){await Ue(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await ee(t)}catch{return o}let s=async p=>{let d=await He(p,{withFileTypes:!0});for(let a of d){let l=Qe(p,a.name);if(a.isDirectory()){await s(l);continue}let g=await te(l);o.push({key:re(this.root,l),size:g.size,updatedAt:g.mtime.toISOString()})}},n=await te(t);return n.isDirectory()?await s(t):o.push({key:re(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),o}};function oe(r){let e=r.localRoot??Xe(Ze(),".toolnet-memory","storage");if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new E({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new b(e))}return new b(e)}function et(r){return new Promise(e=>setTimeout(e,r))}async function se(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,s=e.maxDelayMs??2e3,n;for(let p=1;p<=t;p++)try{return await r()}catch(d){if(n=d,p>=t)break;let a=Math.min(s,o*2**(p-1)),l=Math.floor(Math.random()*Math.max(1,a*.2));await et(a+l)}throw n}var tt=new Set(["put","get","getText","delete","list"]);function ne(r,e={}){return new Proxy(r,{get(t,o){let s=Reflect.get(t,o,t);return typeof s!="function"?s:tt.has(o)?(...n)=>se(()=>Promise.resolve(s.apply(t,n)),e):s.bind(t)}})}function ie(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 ae(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 I=class{constructor(e,t,o,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=ie(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 p;try{p=JSON.parse(s)}catch(d){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${d instanceof Error?d.message:String(d)}`)}if(typeof p.id=="string"&&p.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${p.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof p.createdAt=="string"&&(o=p.createdAt)}let n={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,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=ae(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 at}from"node:path";import{createHash as rt}from"node:crypto";import{dirname as ot}from"node:path";import{mkdirSync as st,readFileSync as go,renameSync as nt,writeFileSync as it}from"node:fs";function y(r){return rt("sha256").update(r).digest("hex")}function k(r,e){st(ot(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;it(t,JSON.stringify(e,null,2)+`
1
+ import{existsSync as je,readFileSync as ke}from"node:fs";import{homedir as ve}from"node:os";import{join as we}from"node:path";function xe(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 be(){let r=process.env.TOOLNET_GLOBAL_ENV??we(ve(),".config","toolnet-memory",".env");if(!je(r))return;let e=ke(r,"utf8");for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let s=o.indexOf("=");if(s<=0)continue;let n=o.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(n)&&process.env[n]===void 0&&(process.env[n]=xe(o.slice(s+1)))}}be();function R(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function x(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function Y(){return{memory:{autoCapture:R(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:R(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:R(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:R(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:x(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:x(process.env.MEMORY_RERANK_TOP,10),finalContext:x(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:x(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:x(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Pe}from"node:crypto";import{existsSync as K,mkdirSync as Ae,readFileSync as Te,renameSync as Re,writeFileSync as Me}from"node:fs";import{basename as Oe,dirname as M,join as E,parse as Z,resolve as b}from"node:path";var X=".toolnet",Ee="project.json";function Ie(r){return Pe("sha256").update(r).digest("hex").slice(0,16)}function J(r){return E(r,X,Ee)}function Ce(r){return K(J(r))}function Ne(r,e){let t=b(r),o=Z(t).root;for(;;){if(Ce(t))return t;if(t===o||e&&t===b(e))break;let s=M(t);if(s===t)break;t=s}return null}function $e(r){let e=b(r),t=Z(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(n=>K(E(e,n))))return e;if(e===t)break;let s=M(e);if(s===e)break;e=s}return b(r)}function _e(r){let e;try{e=JSON.parse(Te(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:M(M(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 Q(r,e){let t=E(r,X);Ae(t,{recursive:!0});let o=J(r),s=`${o}.tmp-${process.pid}`;Me(s,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),Re(s,o)}function q(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var O=class{detect(e=process.cwd()){let t=b(e),o=$e(t),n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(f=>K(E(o,f))),p=Ne(t,n?o:void 0);if(p){let f=J(p),a=_e(f);return a.rootPath!==p&&(a.rootPath=p,a.updatedAt=new Date().toISOString(),Q(p,a)),q(a,p)}let l=new Date().toISOString(),c=Oe(o),d={version:1,id:Ie(o),name:c,remote:c,rootPath:o,createdAt:l,updatedAt:l,graphVersion:0,memoryVersion:0};return Q(o,d),q(d,o)}};import{homedir as Ze}from"node:os";import{join as Xe}from"node:path";import{DeleteObjectCommand as We,GetObjectCommand as De,HeadObjectCommand as Le,ListObjectsV2Command as Ve,PutObjectCommand as Ke,S3Client as Je}from"@aws-sdk/client-s3";import{getSignedUrl as ze}from"@aws-sdk/s3-request-presigner";var I=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Je({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 Ke({Bucket:this.bucket,Key:e,Body:s,ContentType:o}))}async get(e){let t=await ze(this.client,new De({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 Le({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 Ve({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let n of s.Contents??[])n.Key&&t.push({key:n.Key,size:n.Size,updatedAt:n.LastModified?.toISOString()});o=s.IsTruncated?s.NextContinuationToken:void 0}while(o);return t}};import{access as ee,mkdir as Be,readFile as Fe,readdir as He,rm as Ue,stat as te,writeFile as Ge}from"node:fs/promises";import{dirname as Ye,join as Qe,relative as re,resolve as qe}from"node:path";var P=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return qe(this.root,t)}async put(e,t){let o=this.path(e);await Be(Ye(o),{recursive:!0}),await Ge(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 ee(this.path(e)),!0}catch{return!1}}async delete(e){await Ue(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await ee(t)}catch{return o}let s=async p=>{let l=await He(p,{withFileTypes:!0});for(let c of l){let d=Qe(p,c.name);if(c.isDirectory()){await s(d);continue}let f=await te(d);o.push({key:re(this.root,d),size:f.size,updatedAt:f.mtime.toISOString()})}},n=await te(t);return n.isDirectory()?await s(t):o.push({key:re(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),o}};function oe(r){let e=r.localRoot??Xe(Ze(),".toolnet-memory","storage");if(r.provider==="huggingface"){let t=r.huggingface;return t?.namespace&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new I({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):(console.warn("[storage] Hugging Face credentials missing. Using local fallback."),new P(e))}return new P(e)}function et(r){return new Promise(e=>setTimeout(e,r))}async function se(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,s=e.maxDelayMs??2e3,n;for(let p=1;p<=t;p++)try{return await r()}catch(l){if(n=l,p>=t)break;let c=Math.min(s,o*2**(p-1)),d=Math.floor(Math.random()*Math.max(1,c*.2));await et(c+d)}throw n}var tt=new Set(["put","get","getText","delete","list"]);function ne(r,e={}){return new Proxy(r,{get(t,o){let s=Reflect.get(t,o,t);return typeof s!="function"?s:tt.has(o)?(...n)=>se(()=>Promise.resolve(s.apply(t,n)),e):s.bind(t)}})}function ie(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 ae(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 C=class{constructor(e,t,o,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=ie(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 p;try{p=JSON.parse(s)}catch(l){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${l instanceof Error?l.message:String(l)}`)}if(typeof p.id=="string"&&p.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${p.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof p.createdAt=="string"&&(o=p.createdAt)}let n={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,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=ae(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 at}from"node:path";import{createHash as rt}from"node:crypto";import{dirname as ot}from"node:path";import{mkdirSync as st,readFileSync as go,renameSync as nt,writeFileSync as it}from"node:fs";function y(r){return rt("sha256").update(r).digest("hex")}function v(r,e){st(ot(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;it(t,JSON.stringify(e,null,2)+`
5
5
  `,{encoding:"utf8",mode:384}),nt(t,r)}function ce(r,e){let t=r.trim(),o=t.replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,""),s=y(t).slice(0,12);if(!o||o==="."||o==="..")return`${e}--${s}`;let n=o.slice(0,100);return n===t&&t.length<=100?n:`${n.slice(0,85)}--${s}`}function pe(r,e,t){let o=e.trim(),s=t.trim();if(!o)throw new Error("Session agent is required");if(!s)throw new Error("Native session ID is required");let n=ce(o.toLowerCase(),"agent"),p=ce(s,"session");return{projectId:r.id,projectName:r.name,projectRoot:r.rootPath,agent:o,nativeSessionId:s,sessionKey:`${o}:${s}`,remotePrefix:["projects",r.id,"sessions",n,p].join("/"),localDirectory:at(r.rootPath,".toolnet","sessions",n,p)}}import{existsSync as de,mkdirSync as ct,readFileSync as pt,statSync as ue,writeFileSync as ut}from"node:fs";import{dirname as lt,join as dt}from"node:path";var le=64*1024,mt=`# ToolNet Project Operating Manual
6
6
 
7
7
  This file contains persistent instructions for AI agents working on this project.
@@ -45,14 +45,14 @@ Things an AI agent should always remember.
45
45
  <!--
46
46
  - [advisory] Prefer small focused files.
47
47
  -->
48
- `;function C(r){return dt(r.rootPath,".toolnet","PROJECT.md")}function ft(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function gt(r){let e=[],t=new Set,o=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=o.exec(r);){let n=s[1].toLowerCase(),p=ft(s[2]);if(!p)continue;let d=`${n}:${p.toLowerCase()}`;t.has(d)||(t.add(d),e.push({id:y(d).slice(0,24),mode:n,text:p,source:"manual"}))}return e}function ht(r){let e=C(r);return de(e)||(ct(lt(e),{recursive:!0}),ut(e,mt,{encoding:"utf8",mode:384})),e}function N(r,e=!1){let t=e?ht(r):C(r);if(!de(t))return null;if(ue(t).size>le)throw new Error(`PROJECT.md exceeds ${le} bytes`);let s=pt(t,"utf8");return{path:t,content:s,digest:y(s),rules:gt(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(ue(t).mtimeMs).toISOString()}}import{mkdirSync as kt}from"node:fs";import{join as J}from"node:path";import{join as me}from"node:path";import{mkdirSync as yt}from"node:fs";function St(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function w(r,e=20){let t=[],o=new Set;for(let s of r.slice().reverse()){let n=St(s);if(!(!n||o.has(n))&&(o.add(n),t.push(s),t.length>=e))break}return t.reverse()}function jt(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 fe(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&&jt(e)?r.title:e.text;return{id:r?.id??y(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 vt(r,e){let t=`projects/${r.id}/work/observations/`,o=await e.list(t),s=[];for(let n of o.filter(p=>p.key.endsWith(".json")).sort((p,d)=>p.key.localeCompare(d.key))){let p=await e.getText(n.key);if(p)try{let d=JSON.parse(p);d.version===1&&Array.isArray(d.observations)&&s.push(d)}catch{}}return s}async function ge(r,e){let o=(await vt(r,e)).flatMap(i=>i.observations).sort((i,v)=>{let H=i.occurredAt.localeCompare(v.occurredAt);if(H!==0)return H;let U=i.sequence-v.sequence;return U!==0?U:i.id.localeCompare(v.id)}),s=new Map,n=new Map,p,d,a,l=[],g=[],c=[],f=[],u=[],h=[];for(let i of o)switch(i.kind){case"goal":p=i.text;break;case"plan":d=i.text;break;case"phase":s.set(i.key,fe(s.get(i.key),i));break;case"task":n.set(i.key,fe(n.get(i.key),i));break;case"decision":l.push(i.text);break;case"blocker":g.push(i.text);break;case"warning":c.push(i.text);break;case"next_action":f.push(i.text);break;case"file":u.push(i.text);break;case"test":h.push(i.text);break;case"session":a={agent:i.agent,nativeSessionId:i.nativeSessionId,sessionKey:i.sessionKey,updatedAt:i.occurredAt};break}let j=Array.from(s.values()).sort((i,v)=>(i.order??Number.MAX_SAFE_INTEGER)-(v.order??Number.MAX_SAFE_INTEGER)),S=Array.from(n.values()).sort((i,v)=>(i.order??Number.MAX_SAFE_INTEGER)-(v.order??Number.MAX_SAFE_INTEGER)),D=j.find(i=>i.status==="in_progress")??j.find(i=>i.status==="blocked")??j.find(i=>i.status==="pending"),A=S.find(i=>i.status==="in_progress")??S.find(i=>i.status==="blocked")??S.find(i=>i.status==="pending"),ye=w([...f,...A?[A.title]:[],...!A&&D?[D.title]:[],...S.filter(i=>i.status==="pending").slice(0,5).map(i=>i.title)],8),Se=w([...g,...j.filter(i=>i.status==="blocked").map(i=>i.title),...S.filter(i=>i.status==="blocked").map(i=>i.title)],20),L={version:1,projectId:r.id,projectName:r.name,goal:p,plan:d,phases:j,tasks:S,decisions:w(l,20),blockers:Se,warnings:w(c,20),nextActions:ye,filesTouched:w(u,30),tests:w(h,20),currentPhase:D,currentTask:A,progress:{phasesTotal:j.length,phasesCompleted:j.filter(i=>i.status==="completed").length,tasksTotal:S.length,tasksCompleted:S.filter(i=>i.status==="completed").length,blocked:j.filter(i=>i.status==="blocked").length+S.filter(i=>i.status==="blocked").length},lastSession:a,updatedAt:o.length?o[o.length-1].occurredAt:new Date().toISOString()},F=me(r.rootPath,".toolnet","work");return yt(F,{recursive:!0}),k(me(F,"current.json"),L),await e.put(`projects/${r.id}/work/current.json`,JSON.stringify(L,null,2)+`
49
- `,"application/json"),L}async function $(r,e){let t=await e.getText(`projects/${r.id}/work/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}function wt(r){return{goal:r.goal,plan:r.plan,phases:r.phases.map(e=>({id:e.id,title:e.title,status:e.status,order:e.order})),tasks:r.tasks.map(e=>({id:e.id,title:e.title,status:e.status,order:e.order})),decisions:r.decisions,blockers:r.blockers,warnings:r.warnings,nextActions:r.nextActions,filesTouched:r.filesTouched,tests:r.tests}}function xt(r){return r.phases.some(e=>e.status==="pending"||e.status==="in_progress"||e.status==="blocked")||r.tasks.some(e=>e.status==="pending"||e.status==="in_progress"||e.status==="blocked")||r.nextActions.length>0||r.blockers.length>0}var _=class{constructor(e){this.options=e}options;async capture(e,t){let o=await $(this.options.project,this.options.storage);if(o||(o=await ge(this.options.project,this.options.storage)),!xt(o))return null;let s=N(this.options.project,!1),n=s?s.rules.filter(f=>f.mode==="enforce").map(f=>f.text):[],p=y(JSON.stringify(wt(o))),d=y([this.options.project.id,this.options.identity.sessionKey,p].join("|")).slice(0,24),a=new Date().toISOString(),l={version:1,id:d,projectId:this.options.project.id,projectName:this.options.project.name,createdAt:a,reason:e,sourceSession:{agent:this.options.identity.agent,nativeSessionId:this.options.identity.nativeSessionId,sessionKey:this.options.identity.sessionKey,sequence:t},goal:o.goal,plan:o.plan,progress:o.progress,currentPhase:o.currentPhase,currentTask:o.currentTask,incompletePhases:o.phases.filter(f=>f.status!=="completed"&&f.status!=="cancelled"),incompleteTasks:o.tasks.filter(f=>f.status!=="completed"&&f.status!=="cancelled"),nextActions:o.nextActions.slice(0,10),blockers:o.blockers.slice(0,10),decisions:o.decisions.slice(-10),warnings:o.warnings.slice(-10),attention:[...n,...o.warnings].slice(0,20),filesTouched:o.filesTouched.slice(-20),tests:o.tests.slice(-15),stateDigest:p},g=`projects/${this.options.project.id}/work/handoffs/${d}.json`;await this.options.storage.exists(g)||await this.options.storage.put(g,JSON.stringify(l,null,2)+`
50
- `,"application/json"),await this.options.storage.put(`projects/${this.options.project.id}/work/handoff-latest.json`,JSON.stringify(l,null,2)+`
51
- `,"application/json");let c=J(this.options.project.rootPath,".toolnet","work","handoffs");return kt(c,{recursive:!0}),k(J(c,`${d}.json`),l),k(J(this.options.project.rootPath,".toolnet","work","handoff-latest.json"),l),l}};async function W(r,e){let t=await e.getText(`projects/${r.id}/work/handoff-latest.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function he(r,e){let t=await e.getText(`projects/${r.id}/work/semantic/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}function z(r){if(!r)return 0;let e=Array.from(r).length,t=r.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(e/3.5,t*1.3))}function m(r,e){let t=r.replace(/\s+/g," ").trim();return t.length<=e?t:t.slice(0,Math.max(0,e-1)).trimEnd()+"\u2026"}function bt(r){let e=[],t=!1;for(let o of r.split(/\r?\n/u)){let s=o.trim();if(s.includes("<!--")&&(t=!0),t){s.includes("-->")&&(t=!1);continue}let n=s.toLowerCase();if(!(!s||s.startsWith("#")||s==="```"||n.startsWith("- [enforce]")||n.startsWith("* [enforce]")||n.startsWith("- [advisory]")||n.startsWith("* [advisory]"))&&(s=s.replace(/^[-*]\s+/u,""),s&&e.push(m(s,280)),e.length>=16))break}return e}function Pt(r){let e=[],t=[];for(let o of r.split(/\\r?\\n/u)){let s=o.trim(),n=s.toLowerCase(),d=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(l=>n.startsWith(l));if(!d)continue;let a=s.slice(d.length).trim();a&&(d.includes("enforce")?e.push(a):t.push(a))}return{enforce:e,advisory:t}}function At(r,e){let t=[];for(let o of r){let s=[...t,o].join(`
52
- `);if(z(s)<=e){t.push(o);continue}let n=z(t.join(`
53
- `)),p=Math.max(0,e-n);if(p>=16){let d=Math.floor(p*3.2),a=m(o,d);a&&t.push(a)}break}return t.join(`
54
- `).trim()}async function B(r){let e=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),t=N(r.project,!1),o=t?.content??"";o||(o=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let s=Pt(o),n=t?t.rules.filter(u=>u.mode==="enforce").map(u=>u.text):s.enforce,p=t?t.rules.filter(u=>u.mode==="advisory").map(u=>u.text):s.advisory,d=o?bt(o):[],a=await $(r.project,r.storage),l=await he(r.project,r.storage),g=await W(r.project,r.storage),c=[];if(c.push("[TOOLNET PROJECT CONTEXT]"),c.push(`Project: ${r.project.name}`),c.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),o&&c.push(`Full operating manual: ${C(r.project)}`),n.length){c.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let u of n.slice(0,24))c.push(`- [ENFORCE] ${m(u,240)}`)}if(p.length){c.push("","PROJECT PREFERENCES");for(let u of p.slice(0,10))c.push(`- ${m(u,220)}`)}if(l&&(l.mission&&c.push("","MISSION",m(l.mission.value,420)),l.activeObjective&&c.push("","CURRENT OBJECTIVE",m(l.activeObjective.value,420)),l.why&&c.push("","WHY THIS WORK MATTERS",m(l.why.value,420)),l.desiredOutcome&&c.push("","DESIRED OUTCOME",m(l.desiredOutcome.value,420)),l.planRationale&&c.push("","WHY THIS APPROACH",m(l.planRationale.value,420))),a){if(c.push("","ACTIVE WORK"),a.goal&&c.push(`Goal: ${m(a.goal,320)}`),a.plan&&c.push(`Plan: ${m(a.plan,320)}`),c.push(`Progress: phases ${a.progress.phasesCompleted}/${a.progress.phasesTotal}; tasks ${a.progress.tasksCompleted}/${a.progress.tasksTotal}; blocked ${a.progress.blocked}`),a.currentPhase&&c.push(`Current phase: ${a.currentPhase.title} [${a.currentPhase.status}]`),a.currentPhase&&l){let u=l.phases.find(h=>h.order===a.currentPhase?.order);u&&(u.objective&&c.push(`Phase objective: ${m(u.objective.value,340)}`),u.why?c.push(`Why this phase: ${m(u.why.value,340)}`):c.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),u.deliverable&&c.push(`Deliverable: ${m(u.deliverable.value,340)}`),u.dependencies.length&&c.push(`Depends on: ${u.dependencies.slice(0,4).map(h=>m(h.value,180)).join("; ")}`),u.acceptanceCriteria.length&&(c.push("","DEFINITION OF DONE"),u.acceptanceCriteria.slice(0,6).forEach(h=>{c.push(`- ${m(h.value,260)}`)})),u.openQuestions.length&&(c.push("","OPEN QUESTIONS FOR CURRENT PHASE"),u.openQuestions.slice(0,4).forEach(h=>{c.push(`- ${m(h.value,260)}`)})))}a.currentTask&&c.push(`Current task: ${a.currentTask.title} [${a.currentTask.status}]`),a.nextActions.length&&(c.push("","NEXT ACTIONS"),a.nextActions.slice(0,6).forEach((u,h)=>{c.push(`${h+1}. ${m(u,260)}`)})),a.blockers.length&&(c.push("","BLOCKERS"),a.blockers.slice(0,5).forEach(u=>{c.push(`- ${m(u,260)}`)})),a.warnings.length&&(c.push("","ATTENTION"),a.warnings.slice(-5).forEach(u=>{c.push(`- ${m(u,260)}`)})),a.decisions.length&&(c.push("","RECENT DECISIONS"),a.decisions.slice(-5).forEach(u=>{c.push(`- ${m(u,260)}`)})),a.lastSession&&c.push("",`Last work session: ${a.lastSession.agent} / ${a.lastSession.nativeSessionId}`)}if(l&&l.openQuestions.length&&(c.push("","UNRESOLVED QUESTIONS"),l.openQuestions.slice(0,5).forEach(u=>{c.push(`- ${m(u.value,260)}`)})),g&&c.push(`Latest handoff: ${g.reason} / ${g.sourceSession.agent}`),d.length){c.push("","OPERATING NOTES");for(let u of d)c.push(`- ${u}`)}c.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let f=At(c,e);return{version:1,projectId:r.project.id,projectName:r.project.name,text:f,estimatedTokens:z(f),maxTokens:e,hasManual:!!o,hasWorkState:!!a,hasHandoff:!!g,generatedAt:new Date().toISOString()}}function P(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function Tt(r){let e=G(),t=ne(oe({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new I(t,r.id,r.name,r.remote??r.name)}async function Rt(){let[r="help",...e]=process.argv.slice(2),t=new M().detect(P(e,"--project")??process.cwd()),o=Tt(t);if(r==="brief"){let s=Number(P(e,"--tokens")??1e3),n=await B({project:t,storage:o,maxTokens:Number.isFinite(s)?s:1e3});process.stdout.write(n.text+`
55
- `);return}if(r==="brief-json"){let s=await B({project:t,storage:o,maxTokens:Number(P(e,"--tokens")??1e3)});console.log(JSON.stringify(s,null,2));return}if(r==="handoff-latest"){let s=await W(t,o);console.log(JSON.stringify(s,null,2));return}if(r==="handoff-create"){let s=P(e,"--agent")??"manual";if(s==="manual")throw new Error("--agent must be opencode, agy, or codex");let n=P(e,"--session");if(!n)throw new Error("--session is required");let p=pe(t,s,n),a=await new _({project:t,storage:o,identity:p}).capture("manual",0);console.log(JSON.stringify(a,null,2));return}console.log(`Work Context
48
+ `;function N(r){return dt(r.rootPath,".toolnet","PROJECT.md")}function ft(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function gt(r){let e=[],t=new Set,o=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=o.exec(r);){let n=s[1].toLowerCase(),p=ft(s[2]);if(!p)continue;let l=`${n}:${p.toLowerCase()}`;t.has(l)||(t.add(l),e.push({id:y(l).slice(0,24),mode:n,text:p,source:"manual"}))}return e}function ht(r){let e=N(r);return de(e)||(ct(lt(e),{recursive:!0}),ut(e,mt,{encoding:"utf8",mode:384})),e}function $(r,e=!1){let t=e?ht(r):N(r);if(!de(t))return null;if(ue(t).size>le)throw new Error(`PROJECT.md exceeds ${le} bytes`);let s=pt(t,"utf8");return{path:t,content:s,digest:y(s),rules:gt(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(ue(t).mtimeMs).toISOString()}}import{mkdirSync as vt}from"node:fs";import{join as z}from"node:path";import{join as me}from"node:path";import{mkdirSync as yt}from"node:fs";function St(r){return r.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}]+/gu," ").replace(/\s+/g," ").trim()}function w(r,e=20){let t=[],o=new Set;for(let s of r.slice().reverse()){let n=St(s);if(!(!n||o.has(n))&&(o.add(n),t.push(s),t.length>=e))break}return t.reverse()}function jt(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 fe(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&&jt(e)?r.title:e.text;return{id:r?.id??y(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 kt(r,e){let t=`projects/${r.id}/work/observations/`,o=await e.list(t),s=[];for(let n of o.filter(p=>p.key.endsWith(".json")).sort((p,l)=>p.key.localeCompare(l.key))){let p=await e.getText(n.key);if(p)try{let l=JSON.parse(p);l.version===1&&Array.isArray(l.observations)&&s.push(l)}catch{}}return s}async function ge(r,e){let o=(await kt(r,e)).flatMap(i=>i.observations).sort((i,k)=>{let U=i.occurredAt.localeCompare(k.occurredAt);if(U!==0)return U;let G=i.sequence-k.sequence;return G!==0?G:i.id.localeCompare(k.id)}),s=new Map,n=new Map,p,l,c,d=[],f=[],a=[],g=[],u=[],h=[];for(let i of o)switch(i.kind){case"goal":p=i.text;break;case"plan":l=i.text;break;case"phase":s.set(i.key,fe(s.get(i.key),i));break;case"task":n.set(i.key,fe(n.get(i.key),i));break;case"decision":d.push(i.text);break;case"blocker":f.push(i.text);break;case"warning":a.push(i.text);break;case"next_action":g.push(i.text);break;case"file":u.push(i.text);break;case"test":h.push(i.text);break;case"session":c={agent:i.agent,nativeSessionId:i.nativeSessionId,sessionKey:i.sessionKey,updatedAt:i.occurredAt};break}let j=Array.from(s.values()).sort((i,k)=>(i.order??Number.MAX_SAFE_INTEGER)-(k.order??Number.MAX_SAFE_INTEGER)),S=Array.from(n.values()).sort((i,k)=>(i.order??Number.MAX_SAFE_INTEGER)-(k.order??Number.MAX_SAFE_INTEGER)),L=j.find(i=>i.status==="in_progress")??j.find(i=>i.status==="blocked")??j.find(i=>i.status==="pending"),T=S.find(i=>i.status==="in_progress")??S.find(i=>i.status==="blocked")??S.find(i=>i.status==="pending"),ye=w([...g,...T?[T.title]:[],...!T&&L?[L.title]:[],...S.filter(i=>i.status==="pending").slice(0,5).map(i=>i.title)],8),Se=w([...f,...j.filter(i=>i.status==="blocked").map(i=>i.title),...S.filter(i=>i.status==="blocked").map(i=>i.title)],20),V={version:1,projectId:r.id,projectName:r.name,goal:p,plan:l,phases:j,tasks:S,decisions:w(d,20),blockers:Se,warnings:w(a,20),nextActions:ye,filesTouched:w(u,30),tests:w(h,20),currentPhase:L,currentTask:T,progress:{phasesTotal:j.length,phasesCompleted:j.filter(i=>i.status==="completed").length,tasksTotal:S.length,tasksCompleted:S.filter(i=>i.status==="completed").length,blocked:j.filter(i=>i.status==="blocked").length+S.filter(i=>i.status==="blocked").length},lastSession:c,updatedAt:o.length?o[o.length-1].occurredAt:new Date().toISOString()},H=me(r.rootPath,".toolnet","work");return yt(H,{recursive:!0}),v(me(H,"current.json"),V),await e.put(`projects/${r.id}/work/current.json`,JSON.stringify(V,null,2)+`
49
+ `,"application/json"),V}async function _(r,e){let t=await e.getText(`projects/${r.id}/work/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}function wt(r){return{goal:r.goal,plan:r.plan,phases:r.phases.map(e=>({id:e.id,title:e.title,status:e.status,order:e.order})),tasks:r.tasks.map(e=>({id:e.id,title:e.title,status:e.status,order:e.order})),decisions:r.decisions,blockers:r.blockers,warnings:r.warnings,nextActions:r.nextActions,filesTouched:r.filesTouched,tests:r.tests}}function xt(r){return r.phases.some(e=>e.status==="pending"||e.status==="in_progress"||e.status==="blocked")||r.tasks.some(e=>e.status==="pending"||e.status==="in_progress"||e.status==="blocked")||r.nextActions.length>0||r.blockers.length>0}var W=class{constructor(e){this.options=e}options;async capture(e,t){let o=await _(this.options.project,this.options.storage);if(o||(o=await ge(this.options.project,this.options.storage)),!xt(o))return null;let s=$(this.options.project,!1),n=s?s.rules.filter(g=>g.mode==="enforce").map(g=>g.text):[],p=y(JSON.stringify(wt(o))),l=y([this.options.project.id,this.options.identity.sessionKey,p].join("|")).slice(0,24),c=new Date().toISOString(),d={version:1,id:l,projectId:this.options.project.id,projectName:this.options.project.name,createdAt:c,reason:e,sourceSession:{agent:this.options.identity.agent,nativeSessionId:this.options.identity.nativeSessionId,sessionKey:this.options.identity.sessionKey,sequence:t},goal:o.goal,plan:o.plan,progress:o.progress,currentPhase:o.currentPhase,currentTask:o.currentTask,incompletePhases:o.phases.filter(g=>g.status!=="completed"&&g.status!=="cancelled"),incompleteTasks:o.tasks.filter(g=>g.status!=="completed"&&g.status!=="cancelled"),nextActions:o.nextActions.slice(0,10),blockers:o.blockers.slice(0,10),decisions:o.decisions.slice(-10),warnings:o.warnings.slice(-10),attention:[...n,...o.warnings].slice(0,20),filesTouched:o.filesTouched.slice(-20),tests:o.tests.slice(-15),stateDigest:p},f=`projects/${this.options.project.id}/work/handoffs/${l}.json`;await this.options.storage.exists(f)||await this.options.storage.put(f,JSON.stringify(d,null,2)+`
50
+ `,"application/json"),await this.options.storage.put(`projects/${this.options.project.id}/work/handoff-latest.json`,JSON.stringify(d,null,2)+`
51
+ `,"application/json");let a=z(this.options.project.rootPath,".toolnet","work","handoffs");return vt(a,{recursive:!0}),v(z(a,`${l}.json`),d),v(z(this.options.project.rootPath,".toolnet","work","handoff-latest.json"),d),d}};async function D(r,e){let t=await e.getText(`projects/${r.id}/work/handoff-latest.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}async function he(r,e){let t=await e.getText(`projects/${r.id}/work/semantic/current.json`);if(!t)return null;try{return JSON.parse(t)}catch{return null}}function B(r){if(!r)return 0;let e=Array.from(r).length,t=r.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(e/3.5,t*1.3))}function m(r,e){let t=r.replace(/\s+/g," ").trim();return t.length<=e?t:t.slice(0,Math.max(0,e-1)).trimEnd()+"\u2026"}function bt(r){let e=[],t=!1;for(let o of r.split(/\r?\n/u)){let s=o.trim();if(s.includes("<!--")&&(t=!0),t){s.includes("-->")&&(t=!1);continue}let n=s.toLowerCase();if(!(!s||s.startsWith("#")||s==="```"||n.startsWith("- [enforce]")||n.startsWith("* [enforce]")||n.startsWith("- [advisory]")||n.startsWith("* [advisory]"))&&(s=s.replace(/^[-*]\s+/u,""),s&&e.push(m(s,280)),e.length>=16))break}return e}function Pt(r){let e=[],t=[];for(let o of r.split(/\\r?\\n/u)){let s=o.trim(),n=s.toLowerCase(),l=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(d=>n.startsWith(d));if(!l)continue;let c=s.slice(l.length).trim();c&&(l.includes("enforce")?e.push(c):t.push(c))}return{enforce:e,advisory:t}}function At(r,e){let t=[];for(let o of r){let s=[...t,o].join(`
52
+ `);if(B(s)<=e){t.push(o);continue}let n=B(t.join(`
53
+ `)),p=Math.max(0,e-n);if(p>=16){let l=Math.floor(p*3.2),c=m(o,l);c&&t.push(c)}break}return t.join(`
54
+ `).trim()}async function F(r){let e=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),t=$(r.project,!1),o=t?.content??"";o||(o=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let s=Pt(o),n=t?t.rules.filter(u=>u.mode==="enforce").map(u=>u.text):s.enforce,p=t?t.rules.filter(u=>u.mode==="advisory").map(u=>u.text):s.advisory,l=o?bt(o):[],c=await _(r.project,r.storage),d=await he(r.project,r.storage),f=await D(r.project,r.storage),a=[];if(a.push("[TOOLNET PROJECT CONTEXT]"),a.push(`Project: ${r.project.name}`),a.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),o&&a.push(`Full operating manual: ${N(r.project)}`),n.length){a.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let u of n.slice(0,24))a.push(`- [ENFORCE] ${m(u,240)}`)}if(p.length){a.push("","PROJECT PREFERENCES");for(let u of p.slice(0,10))a.push(`- ${m(u,220)}`)}if(d&&(d.mission&&a.push("","MISSION",m(d.mission.value,420)),d.activeObjective&&a.push("","CURRENT OBJECTIVE",m(d.activeObjective.value,420)),d.why&&a.push("","WHY THIS WORK MATTERS",m(d.why.value,420)),d.desiredOutcome&&a.push("","DESIRED OUTCOME",m(d.desiredOutcome.value,420)),d.planRationale&&a.push("","WHY THIS APPROACH",m(d.planRationale.value,420))),c){if(a.push("","ACTIVE WORK"),c.goal&&a.push(`Goal: ${m(c.goal,320)}`),c.plan&&a.push(`Plan: ${m(c.plan,320)}`),a.push(`Progress: phases ${c.progress.phasesCompleted}/${c.progress.phasesTotal}; tasks ${c.progress.tasksCompleted}/${c.progress.tasksTotal}; blocked ${c.progress.blocked}`),c.currentPhase&&a.push(`Current phase: ${c.currentPhase.title} [${c.currentPhase.status}]`),c.currentPhase&&d){let u=d.phases.find(h=>h.order===c.currentPhase?.order);u&&(u.objective&&a.push(`Phase objective: ${m(u.objective.value,340)}`),u.why?a.push(`Why this phase: ${m(u.why.value,340)}`):a.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),u.deliverable&&a.push(`Deliverable: ${m(u.deliverable.value,340)}`),u.dependencies.length&&a.push(`Depends on: ${u.dependencies.slice(0,4).map(h=>m(h.value,180)).join("; ")}`),u.acceptanceCriteria.length&&(a.push("","DEFINITION OF DONE"),u.acceptanceCriteria.slice(0,6).forEach(h=>{a.push(`- ${m(h.value,260)}`)})),u.openQuestions.length&&(a.push("","OPEN QUESTIONS FOR CURRENT PHASE"),u.openQuestions.slice(0,4).forEach(h=>{a.push(`- ${m(h.value,260)}`)})))}c.currentTask&&a.push(`Current task: ${c.currentTask.title} [${c.currentTask.status}]`),c.nextActions.length&&(a.push("","NEXT ACTIONS"),c.nextActions.slice(0,6).forEach((u,h)=>{a.push(`${h+1}. ${m(u,260)}`)})),c.blockers.length&&(a.push("","BLOCKERS"),c.blockers.slice(0,5).forEach(u=>{a.push(`- ${m(u,260)}`)})),c.warnings.length&&(a.push("","ATTENTION"),c.warnings.slice(-5).forEach(u=>{a.push(`- ${m(u,260)}`)})),c.decisions.length&&(a.push("","RECENT DECISIONS"),c.decisions.slice(-5).forEach(u=>{a.push(`- ${m(u,260)}`)})),c.lastSession&&a.push("",`Last work session: ${c.lastSession.agent} / ${c.lastSession.nativeSessionId}`)}if(d&&d.openQuestions.length&&(a.push("","UNRESOLVED QUESTIONS"),d.openQuestions.slice(0,5).forEach(u=>{a.push(`- ${m(u.value,260)}`)})),f&&a.push(`Latest handoff: ${f.reason} / ${f.sourceSession.agent}`),l.length){a.push("","OPERATING NOTES");for(let u of l)a.push(`- ${u}`)}a.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let g=At(a,e);return{version:1,projectId:r.project.id,projectName:r.project.name,text:g,estimatedTokens:B(g),maxTokens:e,hasManual:!!o,hasWorkState:!!c,hasHandoff:!!f,generatedAt:new Date().toISOString()}}function A(r,e){let t=r.indexOf(e);return t>=0?r[t+1]:void 0}function Tt(r){let e=Y(),t=ne(oe({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3});return new C(t,r.id,r.name,r.remote??r.name)}async function Rt(){let[r="help",...e]=process.argv.slice(2),t=new O().detect(A(e,"--project")??process.cwd()),o=Tt(t);if(r==="brief"){let s=Number(A(e,"--tokens")??1e3),n=await F({project:t,storage:o,maxTokens:Number.isFinite(s)?s:1e3});process.stdout.write(n.text+`
55
+ `);return}if(r==="brief-json"){let s=await F({project:t,storage:o,maxTokens:Number(A(e,"--tokens")??1e3)});console.log(JSON.stringify(s,null,2));return}if(r==="handoff-latest"){let s=await D(t,o);console.log(JSON.stringify(s,null,2));return}if(r==="handoff-create"){let s=A(e,"--agent")??"manual";if(s==="manual")throw new Error("--agent must be opencode, agy, or codex");let n=A(e,"--session");if(!n)throw new Error("--session is required");let p=pe(t,s,n),c=await new W({project:t,storage:o,identity:p}).capture("manual",0);console.log(JSON.stringify(c,null,2));return}console.log(`Work Context
56
56
 
57
57
  Commands:
58
58
  brief [--project PATH] [--tokens N]
package/bundle/doctor.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import"dotenv/config";import{existsSync as U,readFileSync as Y}from"node:fs";import{homedir as G}from"node:os";import{join as W}from"node:path";function Z(o){let e=o.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 Q(){let o=process.env.TOOLNET_GLOBAL_ENV??W(G(),".config","toolnet-memory",".env");if(!U(o))return;let e=Y(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]=Z(r.slice(s+1)))}}Q();function u(o,e){return o===void 0?e:["1","true","yes","on"].includes(o.toLowerCase())}function d(o,e){if(!o)return e;let t=Number(o);return Number.isFinite(t)?t:e}function O(){return{memory:{autoCapture:u(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:u(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:u(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:u(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 X}from"node:crypto";import{existsSync as $,mkdirSync as q,readFileSync as ee,renameSync as te,writeFileSync as re}from"node:fs";import{basename as oe,dirname as l,join as R,parse as N,resolve as f}from"node:path";var D=".toolnet",se="project.json";function ne(o){return X("sha256").update(o).digest("hex").slice(0,16)}function M(o){return R(o,D,se)}function ie(o){return $(M(o))}function ae(o){let e=f(o),t=N(e).root;for(;;){if(ie(e))return e;if(e===t)break;let r=l(e);if(r===e)break;e=r}return null}function ce(o){let e=f(o),t=N(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(n=>$(R(e,n))))return e;if(e===t)break;let s=l(e);if(s===e)break;e=s}return f(o)}function pe(o){let e;try{e=JSON.parse(ee(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:l(l(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 _(o,e){let t=R(o,D);q(t,{recursive:!0});let r=M(o),s=`${r}.tmp-${process.pid}`;re(s,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),te(s,r)}function I(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 h=class{detect(e=process.cwd()){let t=f(e),r=ae(t);if(r){let p=M(r),c=pe(p);return c.rootPath!==r&&(c.rootPath=r,c.updatedAt=new Date().toISOString(),_(r,c)),I(c,r)}let s=ce(t),n=new Date().toISOString(),i=oe(s),a={version:1,id:ne(s),name:i,remote:i,rootPath:s,createdAt:n,updatedAt:n,graphVersion:0,memoryVersion:0};return _(s,a),I(a,s)}};import{homedir as ke}from"node:os";import{join as Ee}from"node:path";import{DeleteObjectCommand as me,GetObjectCommand as de,HeadObjectCommand as ge,ListObjectsV2Command as ue,PutObjectCommand as le,S3Client as fe}from"@aws-sdk/client-s3";import{getSignedUrl as he}from"@aws-sdk/s3-request-presigner";var y=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new fe({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 le({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let t=await he(this.client,new de({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 ge({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 s=await this.client.send(new ue({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 z,mkdir as ye,readFile as ve,readdir as we,rm as je,stat as V,writeFile as Se}from"node:fs/promises";import{dirname as be,join as xe,relative as K,resolve as Pe}from"node:path";var g=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Pe(this.root,t)}async put(e,t){let r=this.path(e);await ye(be(r),{recursive:!0}),await Se(r,t)}async get(e){try{return await ve(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await z(this.path(e)),!0}catch{return!1}}async delete(e){await je(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await z(t)}catch{return r}let s=async i=>{let a=await we(i,{withFileTypes:!0});for(let p of a){let c=xe(i,p.name);if(p.isDirectory()){await s(c);continue}let m=await V(c);r.push({key:K(this.root,c),size:m.size,updatedAt:m.mtime.toISOString()})}},n=await V(t);return n.isDirectory()?await s(t):r.push({key:K(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),r}};function L(o){let e=o.localRoot??Ee(ke(),".toolnet-memory","storage");if(o.provider==="huggingface"){let t=o.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 g(e))}return new g(e)}var v=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 w=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")}};var j=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var S=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","chunks","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var b=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};function Ae(o){return new Promise(e=>setTimeout(e,o))}async function F(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 p=Math.min(s,r*2**(i-1)),c=Math.floor(Math.random()*Math.max(1,p*.2));await Ae(p+c)}throw n}var Re=new Set(["put","get","getText","delete","list"]);function B(o,e={}){return new Proxy(o,{get(t,r){let s=Reflect.get(t,r,t);return typeof s!="function"?s:Re.has(r)?(...n)=>F(()=>Promise.resolve(s.apply(t,n)),e):s.bind(t)}})}var x=class{constructor(e){this.options=e}options;name="huggingface";dimensions=384;async embed(e){let[t]=await this.embedMany([e]);return t}async embedMany(e){if(e.length===0)return[];let t=`https://router.huggingface.co/hf-inference/models/${this.options.model}/pipeline/feature-extraction`,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=>Me(n))}};function Me(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 Te}from"node:crypto";var P=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=Te("sha256").update(s).digest().readUInt32BE(0)%this.dimensions;t[i]+=1}return Ce(t)}async embedMany(e){return Promise.all(e.map(t=>this.embed(t)))}};function Ce(o){let e=Math.sqrt(o.reduce((t,r)=>t+r*r,0));return e===0?o:o.map(t=>t/e)}var T=class{constructor(e,t=new P){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 H(){let o=process.env.HF_TOKEN,e=process.env.HF_EMBEDDING_MODEL??"sentence-transformers/all-MiniLM-L6-v2",t=o?new x({token:o,model:e}):null;return new T(t)}var Oe=["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"],k=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),p=[];for(let m of Oe){let A=`${i}/${m}`,C=await this.storage.get(A);C&&(await this.storage.put(`${a}/${m}`,C,"application/json"),p.push(m))}if(p.length===0)return null;let c={version:1,id:n,projectId:e,createdAt:s,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("/"),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 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),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}};function J(){let o=[],e=[];if((process.env.MEMORY_STORAGE_PROVIDER??"local")==="huggingface"){let s=["HF_NAMESPACE","HF_BUCKET","HF_S3_ACCESS_KEY_ID","HF_S3_SECRET_ACCESS_KEY"];for(let n of s)process.env[n]||o.push(`Missing ${n}`);process.env.HF_TOKEN||e.push("HF_TOKEN missing: semantic embedding will use fallback")}return process.env.HF_EMBEDDING_MODEL||e.push("HF_EMBEDDING_MODEL not set; default model will be used"),{ok:o.length===0,errors:o,warnings:e}}import{randomUUID as _e}from"node:crypto";var E=class{constructor(e,t){this.storage=e;this.embeddings=t}storage;embeddings;async run(){let e=`_health/production-${_e()}.txt`,t=`toolnet-memory:${Date.now()}`,r=!1;try{await this.storage.put(e,t,"text/plain"),r=await this.storage.getText(e)===t}finally{try{await this.storage.delete(e)}catch{}}let s=null;if(this.embeddings)try{let n=await this.embeddings.embed("ToolNet Memory production health check");s={ok:n.length>0,dimensions:n.length,mode:n.length===384?"huggingface":"fallback-or-custom"}}catch{s={ok:!1,dimensions:0,mode:"failed"}}return{ok:r&&(s===null||s.ok),storage:{ok:r,provider:this.storage.name},embedding:s}}};async function Ie(){let o=J();o.ok||(console.log({ok:!1,config:o}),process.exit(1));let e=O(),t=new h().detect(),r=B(L({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),s=H(),n=await new E(r,s).run(),i=await new v(r).load(t.id),a=await new j(r).load(t.id),p=await new w(r).load(t.id),c=await new S(r).load(t.id),m=await new b(r).load(t.id),A=await new k(r).list(t.id);console.log({ok:n.ok,project:t.name,storage:n.storage,embedding:n.embedding,memory:i.length,graphSymbols:a?.symbols.length??0,graphEdges:a?.edges.length??0,memoryVectors:p?.records.length??0,codeChunks:c?.chunks.length??0,codeVectors:m?.records.length??0,snapshots:A.length,warnings:o.warnings}),n.ok||process.exit(1)}Ie().catch(o=>{console.error(o instanceof Error?o.message:o),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 Q(){let o=process.env.TOOLNET_GLOBAL_ENV??W(G(),".config","toolnet-memory",".env");if(!U(o))return;let e=Y(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]=Z(r.slice(s+1)))}}Q();function f(o,e){return o===void 0?e:["1","true","yes","on"].includes(o.toLowerCase())}function g(o,e){if(!o)return e;let t=Number(o);return Number.isFinite(t)?t:e}function _(){return{memory:{autoCapture:f(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:f(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:f(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:f(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:g(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:g(process.env.MEMORY_RERANK_TOP,10),finalContext:g(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:g(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",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 X}from"node:crypto";import{existsSync as M,mkdirSync as q,readFileSync as ee,renameSync as te,writeFileSync as re}from"node:fs";import{basename as oe,dirname as h,join as v,parse as N,resolve as u}from"node:path";var D=".toolnet",se="project.json";function ne(o){return X("sha256").update(o).digest("hex").slice(0,16)}function T(o){return v(o,D,se)}function ie(o){return M(T(o))}function ae(o,e){let t=u(o),r=N(t).root;for(;;){if(ie(t))return t;if(t===r||e&&t===u(e))break;let s=h(t);if(s===t)break;t=s}return null}function ce(o){let e=u(o),t=N(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(n=>M(v(e,n))))return e;if(e===t)break;let s=h(e);if(s===e)break;e=s}return u(o)}function pe(o){let e;try{e=JSON.parse(ee(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:h(h(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 I(o,e){let t=v(o,D);q(t,{recursive:!0});let r=T(o),s=`${r}.tmp-${process.pid}`;re(s,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),te(s,r)}function $(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 y=class{detect(e=process.cwd()){let t=u(e),r=ce(t),n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>M(v(r,m))),i=ae(t,n?r:void 0);if(i){let m=T(i),d=pe(m);return d.rootPath!==i&&(d.rootPath=i,d.updatedAt=new Date().toISOString(),I(i,d)),$(d,i)}let a=new Date().toISOString(),c=oe(r),p={version:1,id:ne(r),name:c,remote:c,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return I(r,p),$(p,r)}};import{homedir as ke}from"node:os";import{join as Ee}from"node:path";import{DeleteObjectCommand as me,GetObjectCommand as de,HeadObjectCommand as ge,ListObjectsV2Command as ue,PutObjectCommand as le,S3Client as fe}from"@aws-sdk/client-s3";import{getSignedUrl as he}from"@aws-sdk/s3-request-presigner";var j=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new fe({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 le({Bucket:this.bucket,Key:e,Body:s,ContentType:r}))}async get(e){let t=await he(this.client,new de({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 ge({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 s=await this.client.send(new ue({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 z,mkdir as ye,readFile as ve,readdir as je,rm as we,stat as V,writeFile as Se}from"node:fs/promises";import{dirname as be,join as xe,relative as K,resolve as Pe}from"node:path";var l=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Pe(this.root,t)}async put(e,t){let r=this.path(e);await ye(be(r),{recursive:!0}),await Se(r,t)}async get(e){try{return await ve(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await z(this.path(e)),!0}catch{return!1}}async delete(e){await we(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),r=[];try{await z(t)}catch{return r}let s=async i=>{let a=await je(i,{withFileTypes:!0});for(let c of a){let p=xe(i,c.name);if(c.isDirectory()){await s(p);continue}let m=await V(p);r.push({key:K(this.root,p),size:m.size,updatedAt:m.mtime.toISOString()})}},n=await V(t);return n.isDirectory()?await s(t):r.push({key:K(this.root,t),size:n.size,updatedAt:n.mtime.toISOString()}),r}};function L(o){let e=o.localRoot??Ee(ke(),".toolnet-memory","storage");if(o.provider==="huggingface"){let t=o.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 l(e))}return new l(e)}var w=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 S=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")}};var b=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 x=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 P=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(o){return new Promise(e=>setTimeout(e,o))}async function F(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)),p=Math.floor(Math.random()*Math.max(1,c*.2));await Ae(c+p)}throw n}var Re=new Set(["put","get","getText","delete","list"]);function B(o,e={}){return new Proxy(o,{get(t,r){let s=Reflect.get(t,r,t);return typeof s!="function"?s:Re.has(r)?(...n)=>F(()=>Promise.resolve(s.apply(t,n)),e):s.bind(t)}})}var k=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=>Me(n))}};function Me(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 Te}from"node:crypto";var E=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=Te("sha256").update(s).digest().readUInt32BE(0)%this.dimensions;t[i]+=1}return Ce(t)}async embedMany(e){return Promise.all(e.map(t=>this.embed(t)))}};function Ce(o){let e=Math.sqrt(o.reduce((t,r)=>t+r*r,0));return e===0?o:o.map(t=>t/e)}var C=class{constructor(e,t=new E){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 H(){let o=process.env.HF_TOKEN,e=process.env.HF_EMBEDDING_MODEL??"sentence-transformers/all-MiniLM-L6-v2",t=o?new k({token:o,model:e}):null;return new C(t)}var Oe=["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"],A=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 m of Oe){let d=`${i}/${m}`,O=await this.storage.get(d);O&&(await this.storage.put(`${a}/${m}`,O,"application/json"),c.push(m))}if(c.length===0)return null;let p={version:1,id:n,projectId:e,createdAt:s,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("/"),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 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),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}};function J(){let o=[],e=[];if((process.env.MEMORY_STORAGE_PROVIDER??"local")==="huggingface"){let s=["HF_NAMESPACE","HF_BUCKET","HF_S3_ACCESS_KEY_ID","HF_S3_SECRET_ACCESS_KEY"];for(let n of s)process.env[n]||o.push(`Missing ${n}`);process.env.HF_TOKEN||e.push("HF_TOKEN missing: semantic embedding will use fallback")}return process.env.HF_EMBEDDING_MODEL||e.push("HF_EMBEDDING_MODEL not set; default model will be used"),{ok:o.length===0,errors:o,warnings:e}}import{randomUUID as _e}from"node:crypto";var R=class{constructor(e,t){this.storage=e;this.embeddings=t}storage;embeddings;async run(){let e=`_health/production-${_e()}.txt`,t=`toolnet-memory:${Date.now()}`,r=!1;try{await this.storage.put(e,t,"text/plain"),r=await this.storage.getText(e)===t}finally{try{await this.storage.delete(e)}catch{}}let s=null;if(this.embeddings)try{let n=await this.embeddings.embed("ToolNet Memory production health check");s={ok:n.length>0,dimensions:n.length,mode:n.length===384?"huggingface":"fallback-or-custom"}}catch{s={ok:!1,dimensions:0,mode:"failed"}}return{ok:r&&(s===null||s.ok),storage:{ok:r,provider:this.storage.name},embedding:s}}};async function Ie(){let o=J();o.ok||(console.log({ok:!1,config:o}),process.exit(1));let e=_(),t=new y().detect(),r=B(L({provider:e.storage.provider,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),s=H(),n=await new R(r,s).run(),i=await new w(r).load(t.id),a=await new b(r).load(t.id),c=await new S(r).load(t.id),p=await new x(r).load(t.id),m=await new P(r).load(t.id),d=await new A(r).list(t.id);console.log({ok:n.ok,project:t.name,storage:n.storage,embedding:n.embedding,memory:i.length,graphSymbols:a?.symbols.length??0,graphEdges:a?.edges.length??0,memoryVectors:c?.records.length??0,codeChunks:p?.chunks.length??0,codeVectors:m?.records.length??0,snapshots:d.length,warnings:o.warnings}),n.ok||process.exit(1)}Ie().catch(o=>{console.error(o instanceof Error?o.message:o),process.exit(1)});