toolnet-memory 0.2.9 → 0.2.10

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