toolnet-memory 0.2.10 → 0.2.11

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,33 @@
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
1
+ #!/usr/bin/env node
2
+ import*as N from"fs";import*as ge from"path";import*as h from"fs";import*as g from"path";import*as z from"crypto";function k(r){let e=g.resolve(r),t=g.parse(e).root;for(;e!==t;){let o=g.join(e,".toolnet");if(h.existsSync(o)&&h.statSync(o).isDirectory())return e;e=g.dirname(e)}return null}function C(r){try{return h.existsSync(r)?h.readFileSync(r,"utf-8").trim():null}catch{return null}}function _(r,e){return r.length<=e?r:r.substring(0,e)+`
3
+
4
+ [... truncated ...]`}function J(r){return r.split(`
5
+ `).filter(o=>{let s=o.toUpperCase();return!(s.includes("SECRET")||s.includes("TOKEN")||s.includes("API_KEY")||s.includes("APIKEY")||s.includes("PASSWORD")||s.includes("PASS="))}).join(`
6
+ `)}function K(r={}){let e=r.maxChars||5e4,t=r.projectPath||process.cwd(),o=k(t);if(!o)return null;let s=g.join(o,".toolnet","project.json"),i="Unknown";try{if(h.existsSync(s)){let $=JSON.parse(h.readFileSync(s,"utf-8"));i=$.name||$.projectName||"Unknown"}}catch{}let c=g.join(o,".toolnet","profile.md"),l=g.join(o,".toolnet","current.md"),a=g.join(o,"GEMINI.md"),u=g.join(o,"AGENTS.md"),f=g.join(o,"CLAUDE.md"),n=C(c),S=C(l);n&&(n=J(n)),S&&(S=J(S));let p=h.existsSync(a),y=h.existsSync(u),he=h.existsSync(f),d=[];d.push("[TOOLNET PROJECT CONTEXT]"),d.push(""),d.push(`Project: ${i}`),d.push(""),d.push(`Root: ${o}`),d.push(""),n&&(d.push(`Profile: ${c}`),d.push(""),d.push("Mandatory Rules:"),d.push(_(n,Math.floor(e*.6))),d.push("")),S&&(d.push("Current Work:"),d.push(_(S,Math.floor(e*.3))),d.push("")),d.push("Agent Instruction Files:"),d.push(`- GEMINI.md: ${p?"yes":"no"}`),d.push(`- AGENTS.md: ${y?"yes":"no"}`),d.push(`- CLAUDE.md: ${he?"yes":"no"}`),d.push(""),d.push("Forbidden At Startup:"),d.push("- Do not run toolnet-memory session:agy-recover automatically."),d.push("- Do not run toolnet-memory handoff:latest automatically."),d.push("- Do not run toolnet-memory brief automatically."),d.push("- Do not scan old transcripts unless the user explicitly asks."),d.push("");let ye=d.join(`
7
+ `);return _(ye,e)}function U(r={}){let e=r.projectPath||process.cwd(),t=k(e);if(!t)throw new Error("Not in a ToolNet project (no .toolnet directory found)");let o=g.join(t,".toolnet","profile.md"),s=g.join(t,".toolnet","current.md"),i=C(o)||"",c=C(s)||"",l=`# AI Startup Instructions
8
+
9
+ Read and follow:
10
+ - .toolnet/profile.md
11
+ - .toolnet/current.md
12
+
13
+ Rules:
14
+ - Fast context first.
15
+ - Do not run session:agy-recover, handoff:latest, or brief automatically.
16
+ - Deep memory only when the user explicitly asks.
17
+
18
+ ---
19
+
20
+ ## Profile
21
+
22
+ ${i}
23
+
24
+ ---
25
+
26
+ ## Current Work
27
+
28
+ ${c}
29
+ `,a=["GEMINI.md","AGENTS.md","CLAUDE.md"],u=[];for(let f of a){let n=g.join(t,f);try{h.writeFileSync(n,l,"utf-8"),u.push(f)}catch(S){console.error(`Failed to write ${f}:`,S)}}return u}function H(r){return z.createHash("sha256").update(r,"utf-8").digest("hex")}import{existsSync as pr,mkdirSync as $e,readFileSync as ur,writeFileSync as _e}from"node:fs";import{dirname as Ke,join as ee}from"node:path";import{createHash as Se}from"node:crypto";import{dirname as je}from"node:path";import{mkdirSync as ke,readFileSync as Ft,renameSync as ve,writeFileSync as we}from"node:fs";function j(r){return Se("sha256").update(r).digest("hex")}function v(r,e){ke(je(r),{recursive:!0});let t=`${r}.${process.pid}.tmp`;we(t,JSON.stringify(e,null,2)+`
30
+ `,{encoding:"utf8",mode:384}),ve(t,r)}import{existsSync as Q,mkdirSync as xe,readFileSync as be,statSync as G,writeFileSync as Pe}from"node:fs";import{dirname as Ae,join as Ce}from"node:path";var Y=64*1024,Te=`# ToolNet Project Operating Manual
6
31
 
7
32
  This file contains persistent instructions for AI agents working on this project.
8
33
 
@@ -45,12 +70,14 @@ Things an AI agent should always remember.
45
70
  <!--
46
71
  - [advisory] Prefer small focused files.
47
72
  -->
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(`
73
+ `;function T(r){return Ce(r.rootPath,".toolnet","PROJECT.md")}function Ee(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function Re(r){let e=[],t=new Set,o=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,s;for(;s=o.exec(r);){let i=s[1].toLowerCase(),c=Ee(s[2]);if(!c)continue;let l=`${i}:${c.toLowerCase()}`;t.has(l)||(t.add(l),e.push({id:j(l).slice(0,24),mode:i,text:c,source:"manual"}))}return e}function Oe(r){let e=T(r);return Q(e)||(xe(Ae(e),{recursive:!0}),Pe(e,Te,{encoding:"utf8",mode:384})),e}function D(r,e=!1){let t=e?Oe(r):T(r);if(!Q(t))return null;if(G(t).size>Y)throw new Error(`PROJECT.md exceeds ${Y} bytes`);let s=be(t,"utf8");return{path:t,content:s,digest:j(s),rules:Re(s),bytes:Buffer.byteLength(s,"utf8"),updatedAt:new Date(G(t).mtimeMs).toISOString()}}async function W(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 Z(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 Ie(r){let e=[],t=!1;for(let o of r.split(/\r?\n/u)){let s=o.trim();if(s.includes("<!--")&&(t=!0),t){s.includes("-->")&&(t=!1);continue}let i=s.toLowerCase();if(!(!s||s.startsWith("#")||s==="```"||i.startsWith("- [enforce]")||i.startsWith("* [enforce]")||i.startsWith("- [advisory]")||i.startsWith("* [advisory]"))&&(s=s.replace(/^[-*]\s+/u,""),s&&e.push(m(s,280)),e.length>=16))break}return e}function Me(r){let e=[],t=[];for(let o of r.split(/\\r?\\n/u)){let s=o.trim(),i=s.toLowerCase(),l=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(u=>i.startsWith(u));if(!l)continue;let a=s.slice(l.length).trim();a&&(l.includes("enforce")?e.push(a):t.push(a))}return{enforce:e,advisory:t}}function Ne(r,e){let t=[];for(let o of r){let s=[...t,o].join(`
74
+ `);if(B(s)<=e){t.push(o);continue}let i=B(t.join(`
75
+ `)),c=Math.max(0,e-i);if(c>=16){let l=Math.floor(c*3.2),a=m(o,l);a&&t.push(a)}break}return t.join(`
76
+ `).trim()}async function X(r){let e=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),t=D(r.project,!1),o=t?.content??"";o||(o=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let s=Me(o),i=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,l=o?Ie(o):[],a=await W(r.project,r.storage),u=await Z(r.project,r.storage),f=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: ${T(r.project)}`),i.length){n.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let p of i.slice(0,24))n.push(`- [ENFORCE] ${m(p,240)}`)}if(c.length){n.push("","PROJECT PREFERENCES");for(let p of c.slice(0,10))n.push(`- ${m(p,220)}`)}if(u&&(u.mission&&n.push("","MISSION",m(u.mission.value,420)),u.activeObjective&&n.push("","CURRENT OBJECTIVE",m(u.activeObjective.value,420)),u.why&&n.push("","WHY THIS WORK MATTERS",m(u.why.value,420)),u.desiredOutcome&&n.push("","DESIRED OUTCOME",m(u.desiredOutcome.value,420)),u.planRationale&&n.push("","WHY THIS APPROACH",m(u.planRationale.value,420))),a){if(n.push("","ACTIVE WORK"),a.goal&&n.push(`Goal: ${m(a.goal,320)}`),a.plan&&n.push(`Plan: ${m(a.plan,320)}`),n.push(`Progress: phases ${a.progress.phasesCompleted}/${a.progress.phasesTotal}; tasks ${a.progress.tasksCompleted}/${a.progress.tasksTotal}; blocked ${a.progress.blocked}`),a.currentPhase&&n.push(`Current phase: ${a.currentPhase.title} [${a.currentPhase.status}]`),a.currentPhase&&u){let p=u.phases.find(y=>y.order===a.currentPhase?.order);p&&(p.objective&&n.push(`Phase objective: ${m(p.objective.value,340)}`),p.why?n.push(`Why this phase: ${m(p.why.value,340)}`):n.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),p.deliverable&&n.push(`Deliverable: ${m(p.deliverable.value,340)}`),p.dependencies.length&&n.push(`Depends on: ${p.dependencies.slice(0,4).map(y=>m(y.value,180)).join("; ")}`),p.acceptanceCriteria.length&&(n.push("","DEFINITION OF DONE"),p.acceptanceCriteria.slice(0,6).forEach(y=>{n.push(`- ${m(y.value,260)}`)})),p.openQuestions.length&&(n.push("","OPEN QUESTIONS FOR CURRENT PHASE"),p.openQuestions.slice(0,4).forEach(y=>{n.push(`- ${m(y.value,260)}`)})))}a.currentTask&&n.push(`Current task: ${a.currentTask.title} [${a.currentTask.status}]`),a.nextActions.length&&(n.push("","NEXT ACTIONS"),a.nextActions.slice(0,6).forEach((p,y)=>{n.push(`${y+1}. ${m(p,260)}`)})),a.blockers.length&&(n.push("","BLOCKERS"),a.blockers.slice(0,5).forEach(p=>{n.push(`- ${m(p,260)}`)})),a.warnings.length&&(n.push("","ATTENTION"),a.warnings.slice(-5).forEach(p=>{n.push(`- ${m(p,260)}`)})),a.decisions.length&&(n.push("","RECENT DECISIONS"),a.decisions.slice(-5).forEach(p=>{n.push(`- ${m(p,260)}`)})),a.lastSession&&n.push("",`Last work session: ${a.lastSession.agent} / ${a.lastSession.nativeSessionId}`)}if(u&&u.openQuestions.length&&(n.push("","UNRESOLVED QUESTIONS"),u.openQuestions.slice(0,5).forEach(p=>{n.push(`- ${m(p.value,260)}`)})),f&&n.push(`Latest handoff: ${f.reason} / ${f.sourceSession.agent}`),l.length){n.push("","OPERATING NOTES");for(let p of l)n.push(`- ${p}`)}n.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let S=Ne(n,e);return{version:1,projectId:r.project.id,projectName:r.project.name,text:S,estimatedTokens:B(S),maxTokens:e,hasManual:!!o,hasWorkState:!!a,hasHandoff:!!f,generatedAt:new Date().toISOString()}}function De(r){return ee(r.rootPath,".toolnet","context","startup.md")}function We(r){return ee(r.rootPath,".toolnet","context","startup.json")}function Be(r,e){let t=De(r);$e(Ke(t),{recursive:!0}),_e(t,e.text.endsWith(`
52
77
  `)?e.text:e.text+`
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});
78
+ `,{encoding:"utf8",mode:384}),v(We(r),e)}async function te(r,e,t=900){let o=await X({project:r,storage:e,maxTokens:t}),s={version:1,projectId:r.id,projectName:r.name,text:o.text,digest:j(o.text),estimatedTokens:o.estimatedTokens,generatedAt:new Date().toISOString()};return Be(r,s),await e.put(`projects/${r.id}/context/startup.md`,s.text+`
79
+ `,"text/markdown"),await e.put(`projects/${r.id}/context/startup.json`,JSON.stringify(s,null,2)+`
80
+ `,"application/json"),s}import{existsSync as Le,readFileSync as Fe}from"node:fs";import{homedir as Ve}from"node:os";import{join as Je}from"node:path";function ze(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
81
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Ue(){let r=process.env.TOOLNET_GLOBAL_ENV??Je(Ve(),".config","toolnet-memory",".env");if(!Le(r))return;let e=Fe(r,"utf8");for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let s=o.indexOf("=");if(s<=0)continue;let i=o.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=ze(o.slice(s+1)))}}Ue();function w(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 re(){return{memory:{autoCapture:w(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:w(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:w(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:w(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:w(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 He}from"node:crypto";import{existsSync as L,mkdirSync as Ge,readFileSync as Ye,renameSync as Qe,writeFileSync as qe}from"node:fs";import{basename as Ze,dirname as E,join as O,parse as ne,resolve as b}from"node:path";var ie=".toolnet",Xe="project.json";function et(r){return He("sha256").update(r).digest("hex").slice(0,16)}function F(r){return O(r,ie,Xe)}function tt(r){return L(F(r))}function rt(r,e){let t=b(r),o=ne(t).root;for(;;){if(tt(t))return t;if(t===o||e&&t===b(e))break;let s=E(t);if(s===t)break;t=s}return null}function ot(r){let e=b(r),t=ne(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>L(O(e,i))))return e;if(e===t)break;let s=E(e);if(s===e)break;e=s}return b(r)}function st(r){let e;try{e=JSON.parse(Ye(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:E(E(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 oe(r,e){let t=O(r,ie);Ge(t,{recursive:!0});let o=F(r),s=`${o}.tmp-${process.pid}`;qe(s,JSON.stringify(e,null,2)+`
82
+ `,{encoding:"utf8",mode:384}),Qe(s,o)}function se(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 R=class{detect(e=process.cwd()){let t=b(e),o=ot(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(f=>L(O(o,f))),c=rt(t,i?o:void 0);if(c){let f=F(c),n=st(f);return n.rootPath!==c&&(n.rootPath=c,n.updatedAt=new Date().toISOString(),oe(c,n)),se(n,c)}let l=new Date().toISOString(),a=Ze(o),u={version:1,id:et(o),name:a,remote:a,rootPath:o,createdAt:l,updatedAt:l,graphVersion:0,memoryVersion:0};return oe(o,u),se(u,o)}};import{homedir as Ct}from"node:os";import{join as Tt}from"node:path";import{DeleteObjectCommand as nt,GetObjectCommand as it,HeadObjectCommand as at,ListObjectsV2Command as ct,PutObjectCommand as pt,S3Client as ut}from"@aws-sdk/client-s3";import{getSignedUrl as lt}from"@aws-sdk/s3-request-presigner";var I=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new ut({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let s=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new pt({Bucket:this.bucket,Key:e,Body:s,ContentType:o}))}async get(e){let t=await lt(this.client,new it({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 at({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new nt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let s=await this.client.send(new ct({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of s.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=s.IsTruncated?s.NextContinuationToken:void 0}while(o);return t}};import{access as ae,mkdir as dt,readFile as mt,readdir as ft,rm as gt,stat as ce,writeFile as ht}from"node:fs/promises";import{dirname as yt,join as St,relative as pe,resolve as jt}from"node:path";var P=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return jt(this.root,t)}async put(e,t){let o=this.path(e);await dt(yt(o),{recursive:!0}),await ht(o,t)}async get(e){try{return await mt(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 ae(this.path(e)),!0}catch{return!1}}async delete(e){await gt(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await ae(t)}catch{return o}let s=async c=>{let l=await ft(c,{withFileTypes:!0});for(let a of l){let u=St(c,a.name);if(a.isDirectory()){await s(u);continue}let f=await ce(u);o.push({key:pe(this.root,u),size:f.size,updatedAt:f.mtime.toISOString()})}},i=await ce(t);return i.isDirectory()?await s(t):o.push({key:pe(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),o}};import{DeleteObjectCommand as kt,GetObjectCommand as vt,HeadObjectCommand as wt,ListObjectsV2Command as xt,PutObjectCommand as bt,S3Client as Pt}from"@aws-sdk/client-s3";import{getSignedUrl as At}from"@aws-sdk/s3-request-presigner";var A=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new Pt({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 bt({Bucket:this.bucket,Key:e,Body:s,ContentType:o}))}async get(e){let t=await At(this.client,new vt({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`${this.name} download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new wt({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new kt({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let s=await this.client.send(new xt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of s.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=s.IsTruncated?s.NextContinuationToken:void 0}while(o);return t}};function V(r,e){return console.warn(e),new P(r)}function ue(r){let e=r.localRoot??Tt(Ct(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new A({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):V(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 A({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):V(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 I({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):V(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new P(e)}function Et(r){return new Promise(e=>setTimeout(e,r))}async function le(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,s=e.maxDelayMs??2e3,i;for(let c=1;c<=t;c++)try{return await r()}catch(l){if(i=l,c>=t)break;let a=Math.min(s,o*2**(c-1)),u=Math.floor(Math.random()*Math.max(1,a*.2));await Et(a+u)}throw i}var Rt=new Set(["put","get","getText","delete","list"]);function de(r,e={}){return new Proxy(r,{get(t,o){let s=Reflect.get(t,o,t);return typeof s!="function"?s:Rt.has(o)?(...i)=>le(()=>Promise.resolve(s.apply(t,i)),e):s.bind(t)}})}function me(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 fe(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 M=class{constructor(e,t,o,s){this.provider=e;this.name=e.name,this.projectId=t,this.projectName=o,this.folder=me(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(l){throw new Error(`Invalid remote ToolNet project manifest at ${e}: ${l instanceof Error?l.message:String(l)}`)}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 i={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:t};await this.provider.put(e,JSON.stringify(i,null,2)+`
83
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(e){if(e=fe(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))}};function Ot(){let r=process.argv.slice(2),e=r[0]||"print",t={};for(let o=1;o<r.length;o++)r[o]==="--project"&&r[o+1]?(t.project=r[o+1],o++):r[o]==="--limit"&&r[o+1]&&(t.limit=parseInt(r[o+1],10),o++);return{command:e,options:t}}async function It(){let{command:r,options:e}=Ot();try{switch(r){case"print":await Mt(e);break;case"sync":await Nt(e);break;case"refresh":await $t(e);break;case"profile-show":await _t(e);break;case"profile-sync":await Kt(e);break;default:console.error(`Unknown command: ${r}`),console.error("Available commands: print, sync, refresh, profile-show, profile-sync"),process.exit(1)}}catch(t){console.error("Error:",t instanceof Error?t.message:String(t)),process.exit(1)}}async function Mt(r){let e=K({projectPath:r.project});e||(console.error("No ToolNet project found. Run toolnet-memory init first."),process.exit(1)),process.stdout.write(e)}async function Nt(r){let e=K({projectPath:r.project});e||(console.error("No ToolNet project found."),process.exit(1));let t=H(e);console.log(`Context hash: ${t}`),console.log(`Context size: ${e.length} chars`)}async function $t(r){console.log("Refreshing deep startup brief cache...");let e=r.project||process.cwd(),t=k(e);t||(console.error("No ToolNet project found."),process.exit(1));let o=new R().detect(t),s=re(),i=de(ue({provider:s.storage.provider,huggingface:s.storage.huggingface,localRoot:s.storage.localRoot}),{attempts:2}),c=new M(i,o.id,o.name,o.remote??o.name);await te(o,c),console.log("Deep startup brief cache refreshed.")}async function _t(r){let e=r.project||process.cwd(),t=k(e);t||(console.error("No ToolNet project found."),process.exit(1));let o=ge.join(t,".toolnet","profile.md");N.existsSync(o)||(console.error("No profile.md found in .toolnet directory."),process.exit(1));let s=N.readFileSync(o,"utf-8");process.stdout.write(s)}async function Kt(r){let e=U({projectPath:r.project});console.log("Created/updated:");for(let t of e)console.log(`- ${t}`)}It();