toolnet-memory 0.2.21 → 0.3.0

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,24 +1,26 @@
1
1
  #!/usr/bin/env node
2
- import*as $ from"fs";import*as xe from"path";import*as h from"fs";import*as g from"path";import*as X from"crypto";function k(r){return r?Math.ceil(r.length/3.5):0}function _(r,t){if(!r)return"";if(k(r)<=t)return r;let n=Math.floor(t*3.5),o=r.slice(0,n),s=o.lastIndexOf("."),c=o.lastIndexOf(`
3
- `),l=Math.max(s,c);return l>n*.7?o.slice(0,l+1):o}function H(r,t){if(!r)return"";let e=r.split(`
2
+ import*as $ from"fs";import*as Oe from"path";import*as h from"fs";import*as m from"path";import*as se from"crypto";function k(r){return r?Math.ceil(r.length/3.5):0}function D(r,t){if(!r)return"";if(k(r)<=t)return r;let n=Math.floor(t*3.5),o=r.slice(0,n),s=o.lastIndexOf("."),a=o.lastIndexOf(`
3
+ `),p=Math.max(s,a);return p>n*.7?o.slice(0,p+1):o}function z(r,t){if(!r)return"";let e=r.split(`
4
4
  `).filter(s=>s.trim());if(e.length<=t)return r;let n=e.slice(0,t),o=e.length-t;return[...n,`... (${o} more items omitted)`].join(`
5
- `)}function be(r,t){let{maxTokens:e,trimMarker:n="[Context trimmed by ToolNet Memory token budget]"}=t;if(r.length===0)return"";let o=[...r].sort((i,p)=>p.priority-i.priority),s=[],c=0,l=!1;for(let i of o){let p=`# ${i.title}
5
+ `)}function Me(r,t){let{maxTokens:e,trimMarker:n="[Context trimmed by ToolNet Memory token budget]"}=t;if(r.length===0)return"";let o=[...r].sort((i,l)=>l.priority-i.priority),s=[],a=0,p=!1;for(let i of o){let l=`# ${i.title}
6
6
 
7
- `,f=k(p),a=k(i.content),S=f+a;if(c+S<=e)s.push(p+i.content),c+=S;else{let u=e-c-f;if(u>50){let m=_(i.content,u);s.push(p+m),c=e,l=!0}else l=!0;break}}return l&&s.push(`
7
+ `,f=k(l),c=k(i.content),S=f+c;if(a+S<=e)s.push(l+i.content),a+=S;else{let u=e-a-f;if(u>50){let g=D(i.content,u);s.push(l+g),a=e,p=!0}else p=!0;break}}return p&&s.push(`
8
8
  ${n}
9
9
  `),s.join(`
10
10
 
11
11
  ---
12
12
 
13
- `)}function z(r,t){let e=[{title:"Profile",content:H(r,10),priority:100},{title:"Current Work",content:H(t,15),priority:90}];return be(e,{maxTokens:800})}import{existsSync as J,mkdirSync as tr,readFileSync as U,renameSync as rr,writeFileSync as nr}from"node:fs";import{dirname as sr,join as G}from"node:path";import{createHash as Pe}from"node:crypto";import{dirname as Te}from"node:path";import{mkdirSync as Ae,readFileSync as Zt,renameSync as Ce,writeFileSync as Me}from"node:fs";function y(r){return Pe("sha256").update(r).digest("hex")}function j(r,t){Ae(Te(r),{recursive:!0});let e=`${r}.${process.pid}.tmp`;Me(e,JSON.stringify(t,null,2)+`
14
- `,{encoding:"utf8",mode:384}),Ce(e,r)}function Ie(r){return G(r.rootPath,".toolnet","context","handoff.md")}function Re(r){return G(r.rootPath,".toolnet","context","handoff.json")}function Oe(r){let t=Ie(r);if(!J(t))return null;try{let e=U(t,"utf8").trim();if(!e)return null;let n=new Date(0).toISOString(),o=Re(r);if(J(o))try{let s=JSON.parse(U(o,"utf8"));typeof s.generatedAt=="string"&&(n=s.generatedAt)}catch{}return{version:1,projectId:r.id,projectName:r.name,text:e,digest:y(e),generatedAt:n}}catch{return null}}function Y(r,t=1800){let e=Oe(r);if(!e?.text)return null;let n=e.text;return n.length>t&&(n=`${n.slice(0,t)}
13
+ `)}function G(r,t){let e=[{title:"Profile",content:z(r,10),priority:100},{title:"Current Work",content:z(t,15),priority:90}];return Me(e,{maxTokens:800})}import{chmodSync as cr,existsSync as Ie,mkdirSync as ur,readFileSync as Re,renameSync as lr,writeFileSync as pr}from"node:fs";import{dirname as fr,join as Y}from"node:path";var Q="toolnet.context-offload.v1";function Ne(r){return Y(r,".toolnet","offload")}function $e(r){return Y(Ne(r),"graph.json")}function K(){return{schema:Q,version:1,updatedAt:new Date(0).toISOString(),nodes:[]}}function _e(r){let t=$e(r);if(!Ie(t))return K();try{let e=JSON.parse(Re(t,"utf8"));return e.schema!==Q||e.version!==1||!Array.isArray(e.nodes)?K():e}catch{return K()}}function U(r,t){let e=r.replace(/\s+/gu," ").trim();return e.length<=t?e:e.slice(0,t-1).trimEnd()+"\u2026"}function q(r,t={}){let e=_e(r);if(e.nodes.length===0)return"";let n=Math.max(1,Math.min(12,t.maxAssets??6)),o=Math.max(320,Math.min(2400,t.maxChars??900)),s=["[TOOLNET CONTEXT OFFLOAD GRAPH]","Large tool/file payloads stay outside prompt context.","Read only a needed asset with MCP context_offload_read."];for(let a of e.nodes.slice(-n).reverse()){let p=U(a.sourceRefs.at(-1)??"unknown",72),i=a.files.length>0?` files=${U(a.files.join(","),120)}`:"",l=`event:${p} --offloads--> asset:${a.id.slice(0,12)} kind=${a.kind} bytes=${a.bytes}${i}`;if([...s,l].join(`
14
+ `).length>o)break;s.push(l)}return s.join(`
15
+ `)}import{existsSync as X,mkdirSync as jr,readFileSync as Z,renameSync as xr,writeFileSync as wr}from"node:fs";import{dirname as Pr,join as ee}from"node:path";import{createHash as De}from"node:crypto";import{dirname as Ke}from"node:path";import{mkdirSync as Fe,readFileSync as Sr,renameSync as We,writeFileSync as Le}from"node:fs";function y(r){return De("sha256").update(r).digest("hex")}function v(r,t){Fe(Ke(r),{recursive:!0});let e=`${r}.${process.pid}.tmp`;Le(e,JSON.stringify(t,null,2)+`
16
+ `,{encoding:"utf8",mode:384}),We(e,r)}function Ve(r){return ee(r.rootPath,".toolnet","context","handoff.md")}function Be(r){return ee(r.rootPath,".toolnet","context","handoff.json")}function He(r){let t=Ve(r);if(!X(t))return null;try{let e=Z(t,"utf8").trim();if(!e)return null;let n=new Date(0).toISOString(),o=Be(r);if(X(o))try{let s=JSON.parse(Z(o,"utf8"));typeof s.generatedAt=="string"&&(n=s.generatedAt)}catch{}return{version:1,projectId:r.id,projectName:r.name,text:e,digest:y(e),generatedAt:n}}catch{return null}}function te(r,t=1800){let e=He(r);if(!e?.text)return null;let n=e.text;return n.length>t&&(n=`${n.slice(0,t)}
15
17
 
16
18
  [Fast handoff truncated]`),["[TOOLNET FAST HANDOFF]","",`Project: ${r.name}`,`Updated: ${e.generatedAt}`,"",n].join(`
17
- `)}var A="memory_agent_ask";function Q(){return`
19
+ `)}var C="memory_agent_ask";function re(){return`
18
20
  [TOOLNET MEMORY AGENT]
19
21
 
20
22
  Tool available:
21
- - ${A}
23
+ - ${C}
22
24
 
23
25
  Use it automatically BEFORE guessing when:
24
26
 
@@ -65,24 +67,24 @@ Rules:
65
67
  - After receiving the ToolNet answer, continue the task
66
68
  instead of asking the user to repeat known context.
67
69
  - If ToolNet says information is not recorded, say so.
68
- `.trim()}function q(){return`
70
+ `.trim()}function ne(){return`
69
71
  [TOOLNET MEMORY AGENT]
70
72
 
71
73
  Tool:
72
- - ${A}
74
+ - ${C}
73
75
 
74
76
  For resume/continue requests:
75
77
 
76
78
  1. Use the injected ToolNet continuity handoff FIRST.
77
79
  2. If the handoff is missing or ambiguous, invoke
78
- ${A} directly BEFORE repository/history exploration.
80
+ ${C} directly BEFORE repository/history exploration.
79
81
  3. NEVER reconstruct prior work from:
80
82
  - .toolnet/sessions/**
81
83
  - state.json
82
84
  - events.jsonl
83
85
  - raw transcripts
84
86
  4. NEVER search for the implementation/schema of
85
- ${A}; invoke the MCP tool directly.
87
+ ${C}; invoke the MCP tool directly.
86
88
  5. Inspect git/source only AFTER continuity context is known.
87
89
 
88
90
  Use:
@@ -90,26 +92,29 @@ Use:
90
92
  - mode="ai" for ambiguous or combined continuity questions.
91
93
 
92
94
  Current repository evidence overrides stale memory.
93
- `.trim()}function v(r){let t=g.resolve(r),e=g.parse(t).root;for(;t!==e;){let n=g.join(t,".toolnet");if(h.existsSync(n)&&h.statSync(n).isDirectory())return t;t=g.dirname(t)}return null}function C(r){try{return h.existsSync(r)?h.readFileSync(r,"utf-8").trim():null}catch{return null}}function Z(r){return r.split(`
95
+ `.trim()}function j(r){let t=m.resolve(r),e=m.parse(t).root;for(;t!==e;){let n=m.join(t,".toolnet");if(h.existsSync(n)&&h.statSync(n).isDirectory())return t;t=m.dirname(t)}return null}function T(r){try{return h.existsSync(r)?h.readFileSync(r,"utf-8").trim():null}catch{return null}}function oe(r){return r.split(`
94
96
  `).filter(n=>{let o=n.toUpperCase();return!(o.includes("SECRET")||o.includes("TOKEN")||o.includes("API_KEY")||o.includes("APIKEY")||o.includes("PASSWORD")||o.includes("PASS="))}).join(`
95
- `)}function D(r={}){let t=r.projectPath||process.cwd(),e=v(t);if(!e)return null;let n=g.join(e,".toolnet","project.json"),o="Unknown";try{if(h.existsSync(n)){let m=JSON.parse(h.readFileSync(n,"utf-8"));o=m.name||m.projectName||"Unknown"}}catch{}let s=g.join(e,".toolnet","profile.md"),c=g.join(e,".toolnet","current.md"),l=C(s)||"",i=C(c)||"";l=Z(l),i=Z(i);let p=`[TOOLNET PROJECT CONTEXT]
97
+ `)}function F(r={}){let t=r.projectPath||process.cwd(),e=j(t);if(!e)return null;let n=m.join(e,".toolnet","project.json"),o="Unknown";try{if(h.existsSync(n)){let _=JSON.parse(h.readFileSync(n,"utf-8"));o=_.name||_.projectName||"Unknown"}}catch{}let s=m.join(e,".toolnet","profile.md"),a=m.join(e,".toolnet","current.md"),p=T(s)||"",i=T(a)||"";p=oe(p),i=oe(i);let l=`[TOOLNET PROJECT CONTEXT]
96
98
 
97
99
  Project: ${o}
98
100
  Root: ${e}
99
101
 
100
- `,f=z(l,i),a=Y({id:"",name:o,rootPath:e},1600),S=a?`
102
+ `,f=G(p,i),c=te({id:"",name:o,rootPath:e},1600),S=c?`
101
103
 
102
- ${a}
103
- `:"",u=`
104
+ ${c}
105
+ `:"",u=q(e,{maxAssets:6,maxChars:900}),g=u?`
106
+
107
+ ${u}
108
+ `:"",Ee=`
104
109
 
105
- ${q()}
110
+ ${ne()}
106
111
 
107
112
  Forbidden At Startup:
108
113
  - Do not run session:agy-recover, handoff:latest, or brief automatically.
109
114
  - Do not perform deep recovery merely because an agent starts.
110
115
  - If the user asks to resume previous work and fast context is insufficient,
111
116
  use memory_agent_ask before guessing.
112
- `;return p+f+S+u}function ee(r={}){let t=r.projectPath||process.cwd(),e=v(t);if(!e)throw new Error("Not in a ToolNet project (no .toolnet directory found)");let n=g.join(e,".toolnet","profile.md"),o=g.join(e,".toolnet","current.md"),s=C(n)||"",c=C(o)||"",l=`# AI Startup Instructions
117
+ `;return l+f+S+g+Ee}function ie(r={}){let t=r.projectPath||process.cwd(),e=j(t);if(!e)throw new Error("Not in a ToolNet project (no .toolnet directory found)");let n=m.join(e,".toolnet","profile.md"),o=m.join(e,".toolnet","current.md"),s=T(n)||"",a=T(o)||"",p=`# AI Startup Instructions
113
118
 
114
119
  Read and follow:
115
120
  - .toolnet/profile.md
@@ -121,7 +126,7 @@ Rules:
121
126
  - Do not invent previous-session state.
122
127
  - Current repository evidence overrides stale memory.
123
128
 
124
- ${Q()}
129
+ ${re()}
125
130
 
126
131
  ---
127
132
 
@@ -133,8 +138,8 @@ ${s}
133
138
 
134
139
  ## Current Work
135
140
 
136
- ${c}
137
- `,i=["GEMINI.md","AGENTS.md","CLAUDE.md"],p=[];for(let f of i){let a=g.join(e,f);try{h.writeFileSync(a,l,"utf-8"),p.push(f)}catch(S){console.error(`Failed to write ${f}:`,S)}}return p}function te(r){return X.createHash("sha256").update(r,"utf-8").digest("hex")}import{existsSync as _r,mkdirSync as ze,readFileSync as Dr,writeFileSync as Je}from"node:fs";import{dirname as Ue,join as ce}from"node:path";import{existsSync as oe,mkdirSync as Ee,readFileSync as Ne,statSync as re,writeFileSync as $e}from"node:fs";import{dirname as _e,join as De}from"node:path";var ne=64*1024,Ke=`# ToolNet Project Operating Manual
141
+ ${a}
142
+ `,i=["GEMINI.md","AGENTS.md","CLAUDE.md"],l=[];for(let f of i){let c=m.join(e,f);try{h.writeFileSync(c,p,"utf-8"),l.push(f)}catch(S){console.error(`Failed to write ${f}:`,S)}}return l}function ae(r){return se.createHash("sha256").update(r,"utf-8").digest("hex")}import{existsSync as nn,mkdirSync as nt,readFileSync as on,writeFileSync as ot}from"node:fs";import{dirname as st,join as me}from"node:path";import{existsSync as le,mkdirSync as Je,readFileSync as ze,statSync as ce,writeFileSync as Ge}from"node:fs";import{dirname as Ue,join as Ye}from"node:path";var ue=64*1024,Qe=`# ToolNet Project Operating Manual
138
143
 
139
144
  This file contains persistent instructions for AI agents working on this project.
140
145
 
@@ -177,17 +182,17 @@ Things an AI agent should always remember.
177
182
  <!--
178
183
  - [advisory] Prefer small focused files.
179
184
  -->
180
- `;function M(r){return De(r.rootPath,".toolnet","PROJECT.md")}function Fe(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function We(r){let t=[],e=new Set,n=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,o;for(;o=n.exec(r);){let s=o[1].toLowerCase(),c=Fe(o[2]);if(!c)continue;let l=`${s}:${c.toLowerCase()}`;e.has(l)||(e.add(l),t.push({id:y(l).slice(0,24),mode:s,text:c,source:"manual"}))}return t}function Be(r){let t=M(r);return oe(t)||(Ee(_e(t),{recursive:!0}),$e(t,Ke,{encoding:"utf8",mode:384})),t}function K(r,t=!1){let e=t?Be(r):M(r);if(!oe(e))return null;if(re(e).size>ne)throw new Error(`PROJECT.md exceeds ${ne} bytes`);let o=Ne(e,"utf8");return{path:e,content:o,digest:y(o),rules:We(o),bytes:Buffer.byteLength(o,"utf8"),updatedAt:new Date(re(e).mtimeMs).toISOString()}}async function F(r,t){let e=await t.getText(`projects/${r.id}/work/current.json`);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async function se(r,t){let e=await t.getText(`projects/${r.id}/work/handoff-latest.json`);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async function ie(r,t){let e=await t.getText(`projects/${r.id}/work/semantic/current.json`);if(!e)return null;try{return JSON.parse(e)}catch{return null}}function W(r){if(!r)return 0;let t=Array.from(r).length,e=r.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(t/3.5,e*1.3))}function d(r,t){let e=r.replace(/\s+/g," ").trim();return e.length<=t?e:e.slice(0,Math.max(0,t-1)).trimEnd()+"\u2026"}function Le(r){let t=[],e=!1;for(let n of r.split(/\r?\n/u)){let o=n.trim();if(o.includes("<!--")&&(e=!0),e){o.includes("-->")&&(e=!1);continue}let s=o.toLowerCase();if(!(!o||o.startsWith("#")||o==="```"||s.startsWith("- [enforce]")||s.startsWith("* [enforce]")||s.startsWith("- [advisory]")||s.startsWith("* [advisory]"))&&(o=o.replace(/^[-*]\s+/u,""),o&&t.push(d(o,280)),t.length>=16))break}return t}function Ve(r){let t=[],e=[];for(let n of r.split(/\\r?\\n/u)){let o=n.trim(),s=o.toLowerCase(),l=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(p=>s.startsWith(p));if(!l)continue;let i=o.slice(l.length).trim();i&&(l.includes("enforce")?t.push(i):e.push(i))}return{enforce:t,advisory:e}}function He(r,t){let e=[];for(let n of r){let o=[...e,n].join(`
181
- `);if(W(o)<=t){e.push(n);continue}let s=W(e.join(`
182
- `)),c=Math.max(0,t-s);if(c>=16){let l=Math.floor(c*3.2),i=d(n,l);i&&e.push(i)}break}return e.join(`
183
- `).trim()}async function ae(r){let t=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),e=K(r.project,!1),n=e?.content??"";n||(n=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let o=Ve(n),s=e?e.rules.filter(u=>u.mode==="enforce").map(u=>u.text):o.enforce,c=e?e.rules.filter(u=>u.mode==="advisory").map(u=>u.text):o.advisory,l=n?Le(n):[],i=await F(r.project,r.storage),p=await ie(r.project,r.storage),f=await se(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."),n&&a.push(`Full operating manual: ${M(r.project)}`),s.length){a.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let u of s.slice(0,24))a.push(`- [ENFORCE] ${d(u,240)}`)}if(c.length){a.push("","PROJECT PREFERENCES");for(let u of c.slice(0,10))a.push(`- ${d(u,220)}`)}if(p&&(p.mission&&a.push("","MISSION",d(p.mission.value,420)),p.activeObjective&&a.push("","CURRENT OBJECTIVE",d(p.activeObjective.value,420)),p.why&&a.push("","WHY THIS WORK MATTERS",d(p.why.value,420)),p.desiredOutcome&&a.push("","DESIRED OUTCOME",d(p.desiredOutcome.value,420)),p.planRationale&&a.push("","WHY THIS APPROACH",d(p.planRationale.value,420))),i){if(a.push("","ACTIVE WORK"),i.goal&&a.push(`Goal: ${d(i.goal,320)}`),i.plan&&a.push(`Plan: ${d(i.plan,320)}`),a.push(`Progress: phases ${i.progress.phasesCompleted}/${i.progress.phasesTotal}; tasks ${i.progress.tasksCompleted}/${i.progress.tasksTotal}; blocked ${i.progress.blocked}`),i.currentPhase&&a.push(`Current phase: ${i.currentPhase.title} [${i.currentPhase.status}]`),i.currentPhase&&p){let u=p.phases.find(m=>m.order===i.currentPhase?.order);u&&(u.objective&&a.push(`Phase objective: ${d(u.objective.value,340)}`),u.why?a.push(`Why this phase: ${d(u.why.value,340)}`):a.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),u.deliverable&&a.push(`Deliverable: ${d(u.deliverable.value,340)}`),u.dependencies.length&&a.push(`Depends on: ${u.dependencies.slice(0,4).map(m=>d(m.value,180)).join("; ")}`),u.acceptanceCriteria.length&&(a.push("","DEFINITION OF DONE"),u.acceptanceCriteria.slice(0,6).forEach(m=>{a.push(`- ${d(m.value,260)}`)})),u.openQuestions.length&&(a.push("","OPEN QUESTIONS FOR CURRENT PHASE"),u.openQuestions.slice(0,4).forEach(m=>{a.push(`- ${d(m.value,260)}`)})))}i.currentTask&&a.push(`Current task: ${i.currentTask.title} [${i.currentTask.status}]`),i.nextActions.length&&(a.push("","NEXT ACTIONS"),i.nextActions.slice(0,6).forEach((u,m)=>{a.push(`${m+1}. ${d(u,260)}`)})),i.blockers.length&&(a.push("","BLOCKERS"),i.blockers.slice(0,5).forEach(u=>{a.push(`- ${d(u,260)}`)})),i.warnings.length&&(a.push("","ATTENTION"),i.warnings.slice(-5).forEach(u=>{a.push(`- ${d(u,260)}`)})),i.decisions.length&&(a.push("","RECENT DECISIONS"),i.decisions.slice(-5).forEach(u=>{a.push(`- ${d(u,260)}`)})),i.lastSession&&a.push("",`Last work session: ${i.lastSession.agent} / ${i.lastSession.nativeSessionId}`)}if(p&&p.openQuestions.length&&(a.push("","UNRESOLVED QUESTIONS"),p.openQuestions.slice(0,5).forEach(u=>{a.push(`- ${d(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 S=He(a,t);return{version:1,projectId:r.project.id,projectName:r.project.name,text:S,estimatedTokens:W(S),maxTokens:t,hasManual:!!n,hasWorkState:!!i,hasHandoff:!!f,generatedAt:new Date().toISOString()}}function Ge(r){return ce(r.rootPath,".toolnet","context","startup.md")}function Ye(r){return ce(r.rootPath,".toolnet","context","startup.json")}function Qe(r,t){let e=Ge(r);ze(Ue(e),{recursive:!0}),Je(e,t.text.endsWith(`
185
+ `;function O(r){return Ye(r.rootPath,".toolnet","PROJECT.md")}function qe(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function Xe(r){let t=[],e=new Set,n=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,o;for(;o=n.exec(r);){let s=o[1].toLowerCase(),a=qe(o[2]);if(!a)continue;let p=`${s}:${a.toLowerCase()}`;e.has(p)||(e.add(p),t.push({id:y(p).slice(0,24),mode:s,text:a,source:"manual"}))}return t}function Ze(r){let t=O(r);return le(t)||(Je(Ue(t),{recursive:!0}),Ge(t,Qe,{encoding:"utf8",mode:384})),t}function W(r,t=!1){let e=t?Ze(r):O(r);if(!le(e))return null;if(ce(e).size>ue)throw new Error(`PROJECT.md exceeds ${ue} bytes`);let o=ze(e,"utf8");return{path:e,content:o,digest:y(o),rules:Xe(o),bytes:Buffer.byteLength(o,"utf8"),updatedAt:new Date(ce(e).mtimeMs).toISOString()}}async function L(r,t){let e=await t.getText(`projects/${r.id}/work/current.json`);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async function pe(r,t){let e=await t.getText(`projects/${r.id}/work/handoff-latest.json`);if(!e)return null;try{return JSON.parse(e)}catch{return null}}async function de(r,t){let e=await t.getText(`projects/${r.id}/work/semantic/current.json`);if(!e)return null;try{return JSON.parse(e)}catch{return null}}function V(r){if(!r)return 0;let t=Array.from(r).length,e=r.trim().split(/\s+/u).filter(Boolean).length;return Math.ceil(Math.max(t/3.5,e*1.3))}function d(r,t){let e=r.replace(/\s+/g," ").trim();return e.length<=t?e:e.slice(0,Math.max(0,t-1)).trimEnd()+"\u2026"}function et(r){let t=[],e=!1;for(let n of r.split(/\r?\n/u)){let o=n.trim();if(o.includes("<!--")&&(e=!0),e){o.includes("-->")&&(e=!1);continue}let s=o.toLowerCase();if(!(!o||o.startsWith("#")||o==="```"||s.startsWith("- [enforce]")||s.startsWith("* [enforce]")||s.startsWith("- [advisory]")||s.startsWith("* [advisory]"))&&(o=o.replace(/^[-*]\s+/u,""),o&&t.push(d(o,280)),t.length>=16))break}return t}function tt(r){let t=[],e=[];for(let n of r.split(/\\r?\\n/u)){let o=n.trim(),s=o.toLowerCase(),p=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(l=>s.startsWith(l));if(!p)continue;let i=o.slice(p.length).trim();i&&(p.includes("enforce")?t.push(i):e.push(i))}return{enforce:t,advisory:e}}function rt(r,t){let e=[];for(let n of r){let o=[...e,n].join(`
186
+ `);if(V(o)<=t){e.push(n);continue}let s=V(e.join(`
187
+ `)),a=Math.max(0,t-s);if(a>=16){let p=Math.floor(a*3.2),i=d(n,p);i&&e.push(i)}break}return e.join(`
188
+ `).trim()}async function fe(r){let t=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),e=W(r.project,!1),n=e?.content??"";n||(n=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let o=tt(n),s=e?e.rules.filter(u=>u.mode==="enforce").map(u=>u.text):o.enforce,a=e?e.rules.filter(u=>u.mode==="advisory").map(u=>u.text):o.advisory,p=n?et(n):[],i=await L(r.project,r.storage),l=await de(r.project,r.storage),f=await pe(r.project,r.storage),c=[];if(c.push("[TOOLNET PROJECT CONTEXT]"),c.push(`Project: ${r.project.name}`),c.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),n&&c.push(`Full operating manual: ${O(r.project)}`),s.length){c.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let u of s.slice(0,24))c.push(`- [ENFORCE] ${d(u,240)}`)}if(a.length){c.push("","PROJECT PREFERENCES");for(let u of a.slice(0,10))c.push(`- ${d(u,220)}`)}if(l&&(l.mission&&c.push("","MISSION",d(l.mission.value,420)),l.activeObjective&&c.push("","CURRENT OBJECTIVE",d(l.activeObjective.value,420)),l.why&&c.push("","WHY THIS WORK MATTERS",d(l.why.value,420)),l.desiredOutcome&&c.push("","DESIRED OUTCOME",d(l.desiredOutcome.value,420)),l.planRationale&&c.push("","WHY THIS APPROACH",d(l.planRationale.value,420))),i){if(c.push("","ACTIVE WORK"),i.goal&&c.push(`Goal: ${d(i.goal,320)}`),i.plan&&c.push(`Plan: ${d(i.plan,320)}`),c.push(`Progress: phases ${i.progress.phasesCompleted}/${i.progress.phasesTotal}; tasks ${i.progress.tasksCompleted}/${i.progress.tasksTotal}; blocked ${i.progress.blocked}`),i.currentPhase&&c.push(`Current phase: ${i.currentPhase.title} [${i.currentPhase.status}]`),i.currentPhase&&l){let u=l.phases.find(g=>g.order===i.currentPhase?.order);u&&(u.objective&&c.push(`Phase objective: ${d(u.objective.value,340)}`),u.why?c.push(`Why this phase: ${d(u.why.value,340)}`):c.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),u.deliverable&&c.push(`Deliverable: ${d(u.deliverable.value,340)}`),u.dependencies.length&&c.push(`Depends on: ${u.dependencies.slice(0,4).map(g=>d(g.value,180)).join("; ")}`),u.acceptanceCriteria.length&&(c.push("","DEFINITION OF DONE"),u.acceptanceCriteria.slice(0,6).forEach(g=>{c.push(`- ${d(g.value,260)}`)})),u.openQuestions.length&&(c.push("","OPEN QUESTIONS FOR CURRENT PHASE"),u.openQuestions.slice(0,4).forEach(g=>{c.push(`- ${d(g.value,260)}`)})))}i.currentTask&&c.push(`Current task: ${i.currentTask.title} [${i.currentTask.status}]`),i.nextActions.length&&(c.push("","NEXT ACTIONS"),i.nextActions.slice(0,6).forEach((u,g)=>{c.push(`${g+1}. ${d(u,260)}`)})),i.blockers.length&&(c.push("","BLOCKERS"),i.blockers.slice(0,5).forEach(u=>{c.push(`- ${d(u,260)}`)})),i.warnings.length&&(c.push("","ATTENTION"),i.warnings.slice(-5).forEach(u=>{c.push(`- ${d(u,260)}`)})),i.decisions.length&&(c.push("","RECENT DECISIONS"),i.decisions.slice(-5).forEach(u=>{c.push(`- ${d(u,260)}`)})),i.lastSession&&c.push("",`Last work session: ${i.lastSession.agent} / ${i.lastSession.nativeSessionId}`)}if(l&&l.openQuestions.length&&(c.push("","UNRESOLVED QUESTIONS"),l.openQuestions.slice(0,5).forEach(u=>{c.push(`- ${d(u.value,260)}`)})),f&&c.push(`Latest handoff: ${f.reason} / ${f.sourceSession.agent}`),p.length){c.push("","OPERATING NOTES");for(let u of p)c.push(`- ${u}`)}c.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let S=rt(c,t);return{version:1,projectId:r.project.id,projectName:r.project.name,text:S,estimatedTokens:V(S),maxTokens:t,hasManual:!!n,hasWorkState:!!i,hasHandoff:!!f,generatedAt:new Date().toISOString()}}function it(r){return me(r.rootPath,".toolnet","context","startup.md")}function at(r){return me(r.rootPath,".toolnet","context","startup.json")}function ct(r,t){let e=it(r);nt(st(e),{recursive:!0}),ot(e,t.text.endsWith(`
184
189
  `)?t.text:t.text+`
185
- `,{encoding:"utf8",mode:384}),j(Ye(r),t)}async function ue(r,t,e=800){let o=(await ae({project:r,storage:t,maxTokens:e})).text;k(o)>e&&(o=_(o,e),o+=`
190
+ `,{encoding:"utf8",mode:384}),v(at(r),t)}async function ge(r,t,e=800){let o=(await fe({project:r,storage:t,maxTokens:e})).text;k(o)>e&&(o=D(o,e),o+=`
186
191
 
187
192
  [Context trimmed by ToolNet Memory token budget]
188
- `);let c={version:1,projectId:r.id,projectName:r.name,text:o,digest:y(o),estimatedTokens:k(o),generatedAt:new Date().toISOString()};return Qe(r,c),await t.put(`projects/${r.id}/context/startup.md`,c.text+`
189
- `,"text/markdown"),await t.put(`projects/${r.id}/context/startup.json`,JSON.stringify(c,null,2)+`
190
- `,"application/json"),c}import{existsSync as qe,readFileSync as Ze}from"node:fs";import{homedir as Xe}from"node:os";import{join as et}from"node:path";function tt(r){let t=r.trim();return t.length>=2&&t.startsWith('"')&&t.endsWith('"')?(t=t.slice(1,-1),t.replace(/\\n/g,`
191
- `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):t.length>=2&&t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function rt(){let r=process.env.TOOLNET_GLOBAL_ENV??et(Xe(),".config","toolnet-memory",".env");if(!qe(r))return;let t=Ze(r,"utf8");for(let e of t.split(/\r?\n/)){let n=e.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let o=n.indexOf("=");if(o<=0)continue;let s=n.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=tt(n.slice(o+1)))}}rt();function w(r,t){return r===void 0?t:["1","true","yes","on"].includes(r.toLowerCase())}function x(r,t){if(!r)return t;let e=Number(r);return Number.isFinite(e)?e:t}function pe(){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 nt}from"node:crypto";import{existsSync as B,mkdirSync as ot,readFileSync as st,renameSync as it,writeFileSync as at}from"node:fs";import{basename as ct,dirname as I,join as O,parse as fe,resolve as b}from"node:path";var me=".toolnet",ut="project.json";function pt(r){return nt("sha256").update(r).digest("hex").slice(0,16)}function L(r){return O(r,me,ut)}function lt(r){return B(L(r))}function dt(r,t){let e=b(r),n=fe(e).root;for(;;){if(lt(e))return e;if(e===n||t&&e===b(t))break;let o=I(e);if(o===e)break;e=o}return null}function ft(r){let t=b(r),e=fe(t).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(s=>B(O(t,s))))return t;if(t===e)break;let o=I(t);if(o===t)break;t=o}return b(r)}function mt(r){let t;try{t=JSON.parse(st(r,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${r}: ${o instanceof Error?o.message:String(o)}`)}if(!t||typeof t!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let e=t;if(typeof e.id!="string"||!e.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof e.name!="string"||!e.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:e.id,name:e.name,remote:typeof e.remote=="string"&&e.remote.trim()?e.remote:e.name,rootPath:typeof e.rootPath=="string"?e.rootPath:I(I(r)),createdAt:typeof e.createdAt=="string"?e.createdAt:n,updatedAt:typeof e.updatedAt=="string"?e.updatedAt:n,graphVersion:typeof e.graphVersion=="number"?e.graphVersion:0,memoryVersion:typeof e.memoryVersion=="number"?e.memoryVersion:0,metadata:e.metadata&&typeof e.metadata=="object"?e.metadata:void 0}}function le(r,t){let e=O(r,me);ot(e,{recursive:!0});let n=L(r),o=`${n}.tmp-${process.pid}`;at(o,JSON.stringify(t,null,2)+`
192
- `,{encoding:"utf8",mode:384}),it(o,n)}function de(r,t){return{id:r.id,name:r.name,remote:r.remote,rootPath:t,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var R=class{detect(t=process.cwd()){let e=b(t),n=ft(e),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(f=>B(O(n,f))),c=dt(e,s?n:void 0);if(c){let f=L(c),a=mt(f);return a.rootPath!==c&&(a.rootPath=c,a.updatedAt=new Date().toISOString(),le(c,a)),de(a,c)}let l=new Date().toISOString(),i=ct(n),p={version:1,id:pt(n),name:i,remote:i,rootPath:n,createdAt:l,updatedAt:l,graphVersion:0,memoryVersion:0};return le(n,p),de(p,n)}};import{homedir as Dt}from"node:os";import{join as Kt}from"node:path";import{DeleteObjectCommand as gt,GetObjectCommand as ht,HeadObjectCommand as yt,ListObjectsV2Command as St,PutObjectCommand as kt,S3Client as jt}from"@aws-sdk/client-s3";import{getSignedUrl as vt}from"@aws-sdk/s3-request-presigner";var E=class{name="huggingface";client;bucket;constructor(t){this.bucket=t.bucket,this.client=new jt({region:"us-east-1",endpoint:`https://s3.hf.co/${t.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,n="application/octet-stream"){let o=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new kt({Bucket:this.bucket,Key:t,Body:o,ContentType:n}))}async get(t){let e=await vt(this.client,new ht({Bucket:this.bucket,Key:t}),{expiresIn:60}),n=await fetch(e,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`HF download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.arrayBuffer())}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new yt({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new gt({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],n;do{let o=await this.client.send(new St({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:n}));for(let s of o.Contents??[])s.Key&&e.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return e}};import{access as ge,mkdir as wt,readFile as xt,readdir as bt,rm as Pt,stat as he,writeFile as Tt}from"node:fs/promises";import{dirname as At,join as Ct,relative as ye,resolve as Mt}from"node:path";var P=class{constructor(t){this.root=t}root;name="local";path(t){let e=t.replace(/^\/+/,"");return Mt(this.root,e)}async put(t,e){let n=this.path(t);await wt(At(n),{recursive:!0}),await Tt(n,e)}async get(t){try{return await xt(this.path(t))}catch(e){if(typeof e=="object"&&e!==null&&"code"in e&&e.code==="ENOENT")return null;throw e}}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await ge(this.path(t)),!0}catch{return!1}}async delete(t){await Pt(this.path(t),{force:!0})}async list(t=""){let e=this.path(t),n=[];try{await ge(e)}catch{return n}let o=async c=>{let l=await bt(c,{withFileTypes:!0});for(let i of l){let p=Ct(c,i.name);if(i.isDirectory()){await o(p);continue}let f=await he(p);n.push({key:ye(this.root,p),size:f.size,updatedAt:f.mtime.toISOString()})}},s=await he(e);return s.isDirectory()?await o(e):n.push({key:ye(this.root,e),size:s.size,updatedAt:s.mtime.toISOString()}),n}};import{DeleteObjectCommand as It,GetObjectCommand as Rt,HeadObjectCommand as Ot,ListObjectsV2Command as Et,PutObjectCommand as Nt,S3Client as $t}from"@aws-sdk/client-s3";import{getSignedUrl as _t}from"@aws-sdk/s3-request-presigner";var T=class{name;client;bucket;constructor(t){this.name=t.name??"s3",this.bucket=t.bucket,this.client=new $t({region:t.region??"us-east-1",endpoint:t.endpoint||void 0,forcePathStyle:t.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,n="application/octet-stream"){let o=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new Nt({Bucket:this.bucket,Key:t,Body:o,ContentType:n}))}async get(t){let e=await _t(this.client,new Rt({Bucket:this.bucket,Key:t}),{expiresIn:60}),n=await fetch(e,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`${this.name} download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.arrayBuffer())}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new Ot({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new It({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],n;do{let o=await this.client.send(new Et({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:n}));for(let s of o.Contents??[])s.Key&&e.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return e}};function V(r,t){return console.warn(t),new P(r)}function Se(r){let t=r.localRoot??Kt(Dt(),".toolnet-memory","storage");if(r.provider==="r2"){let e=r.r2;return e?.accountId&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new T({name:"r2",endpoint:`https://${e.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:e.bucket,forcePathStyle:!0,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):V(t,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let e=r.s3;return e?.bucket&&e.accessKeyId&&e.secretAccessKey?new T({name:"s3",endpoint:e.endpoint,region:e.region??"us-east-1",bucket:e.bucket,forcePathStyle:e.forcePathStyle??!1,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):V(t,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let e=r.huggingface;return e?.namespace&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new E({namespace:e.namespace,bucket:e.bucket,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):V(t,"[storage] Hugging Face credentials missing. Using local fallback.")}return new P(t)}function Ft(r){return new Promise(t=>setTimeout(t,r))}async function ke(r,t={}){let e=Math.max(1,t.attempts??3),n=t.baseDelayMs??150,o=t.maxDelayMs??2e3,s;for(let c=1;c<=e;c++)try{return await r()}catch(l){if(s=l,c>=e)break;let i=Math.min(o,n*2**(c-1)),p=Math.floor(Math.random()*Math.max(1,i*.2));await Ft(i+p)}throw s}var Wt=new Set(["put","get","getText","delete","list"]);function je(r,t={}){return new Proxy(r,{get(e,n){let o=Reflect.get(e,n,e);return typeof o!="function"?o:Wt.has(n)?(...s)=>ke(()=>Promise.resolve(o.apply(e,s)),t):o.bind(e)}})}function ve(r){let t=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!t||t==="."||t==="..")throw new Error("Invalid project storage folder");return t}function we(r){let t=r.replace(/^\/+/,"");if(t.startsWith("memories/"))return"memory/records/"+t.slice(9);if(t.startsWith("vectors/"))return"memory/vectors/"+t.slice(8);if(t.startsWith("graph/"))return"code/graph/"+t.slice(6);let e=t.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(e)return`${e[1]}memory/records/${e[2]}`;if(e=t.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),e)return`${e[1]}memory/vectors/${e[2]}`;if(e=t.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),e)return`${e[1]}code/graph/${e[2]}`;let n=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let o=t.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return o?`${o[1]}memory/records/${o[2]}`:(o=t.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),o?`${o[1]}memory/vectors/${o[2]}`:(o=t.match(/^(projects\/[^/]+\/)graph\/(.+)$/),o?`${o[1]}code/graph/${o[2]}`:t))}var N=class{constructor(t,e,n,o){this.provider=t;this.name=t.name,this.projectId=e,this.projectName=n,this.folder=ve(o??n),this.sourcePrefix=`projects/${e}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let t=`${this.targetPrefix}/project.json`,e=new Date().toISOString(),n=e,o=await this.provider.getText(t);if(o){let c;try{c=JSON.parse(o)}catch(l){throw new Error(`Invalid remote ToolNet project manifest at ${t}: ${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"&&(n=c.createdAt)}let s={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:n,updatedAt:e};await this.provider.put(t,JSON.stringify(s,null,2)+`
193
- `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(t){if(t=we(t),t===this.sourcePrefix)return this.targetPrefix;if(t.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+t.slice(this.sourcePrefix.length);if(t===this.targetPrefix||t.startsWith(`${this.targetPrefix}/`))return t;if(t.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${t}`].join(" "));return t}async put(t,e,n){return await this.ensureRegistered(),this.provider.put(this.key(t),e,n)}async get(t){return await this.ensureRegistered(),this.provider.get(this.key(t))}async getText(t){return await this.ensureRegistered(),this.provider.getText(this.key(t))}async delete(t){return await this.ensureRegistered(),this.provider.delete(this.key(t))}async exists(t){return await this.ensureRegistered(),this.provider.exists(this.key(t))}async list(t){return await this.ensureRegistered(),this.provider.list(this.key(t))}};function Bt(){let r=process.argv.slice(2),t=r[0]||"print",e={mode:"minimal"};for(let n=1;n<r.length;n++)r[n]==="--project"&&r[n+1]?(e.project=r[n+1],n++):r[n]==="--limit"&&r[n+1]?(e.limit=parseInt(r[n+1],10),n++):r[n]==="--focused"&&r[n+1]?(e.mode="focused",e.query=r[n+1],n++):r[n]==="--deep"&&(e.mode="deep");return{command:t,options:e}}async function Lt(){let{command:r,options:t}=Bt();try{switch(r){case"print":await Vt(t);break;case"sync":await Ht(t);break;case"refresh":await zt(t);break;case"profile-show":await Jt(t);break;case"profile-sync":await Ut(t);break;default:console.error(`Unknown command: ${r}`),console.error("Available commands: print, sync, refresh, profile-show, profile-sync"),process.exit(1)}}catch(e){console.error("Error:",e instanceof Error?e.message:String(e)),process.exit(1)}}async function Vt(r){let t=r.mode||"minimal";if(t==="minimal"){let e=D({projectPath:r.project});e||(console.error("No ToolNet project found. Run toolnet-memory init first."),process.exit(1)),process.stdout.write(e)}else(t==="focused"||t==="deep")&&(console.error("Focused and deep modes require storage access."),console.error("Use: toolnet-memory brief --deep for deep context"),process.exit(1))}async function Ht(r){let t=D({projectPath:r.project});t||(console.error("No ToolNet project found."),process.exit(1));let e=te(t);console.log(`Context hash: ${e}`),console.log(`Context size: ${t.length} chars`)}async function zt(r){console.log("Refreshing deep startup brief cache...");let t=r.project||process.cwd(),e=v(t);e||(console.error("No ToolNet project found."),process.exit(1));let n=new R().detect(e),o=pe(),s=je(Se({provider:o.storage.provider,huggingface:o.storage.huggingface,localRoot:o.storage.localRoot}),{attempts:2}),c=new N(s,n.id,n.name,n.remote??n.name);await ue(n,c),console.log("Deep startup brief cache refreshed.")}async function Jt(r){let t=r.project||process.cwd(),e=v(t);e||(console.error("No ToolNet project found."),process.exit(1));let n=xe.join(e,".toolnet","profile.md");$.existsSync(n)||(console.error("No profile.md found in .toolnet directory."),process.exit(1));let o=$.readFileSync(n,"utf-8");process.stdout.write(o)}async function Ut(r){let t=ee({projectPath:r.project});console.log("Created/updated:");for(let e of t)console.log(`- ${e}`)}Lt();
193
+ `);let a={version:1,projectId:r.id,projectName:r.name,text:o,digest:y(o),estimatedTokens:k(o),generatedAt:new Date().toISOString()};return ct(r,a),await t.put(`projects/${r.id}/context/startup.md`,a.text+`
194
+ `,"text/markdown"),await t.put(`projects/${r.id}/context/startup.json`,JSON.stringify(a,null,2)+`
195
+ `,"application/json"),a}import{existsSync as ut,readFileSync as lt}from"node:fs";import{homedir as pt}from"node:os";import{join as dt}from"node:path";function ft(r){let t=r.trim();return t.length>=2&&t.startsWith('"')&&t.endsWith('"')?(t=t.slice(1,-1),t.replace(/\\n/g,`
196
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):t.length>=2&&t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function mt(){let r=process.env.TOOLNET_GLOBAL_ENV??dt(pt(),".config","toolnet-memory",".env");if(!ut(r))return;let t=lt(r,"utf8");for(let e of t.split(/\r?\n/)){let n=e.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let o=n.indexOf("=");if(o<=0)continue;let s=n.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=ft(n.slice(o+1)))}}mt();function x(r,t){return r===void 0?t:["1","true","yes","on"].includes(r.toLowerCase())}function w(r,t){if(!r)return t;let e=Number(r);return Number.isFinite(e)?e:t}function he(){return{memory:{autoCapture:x(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:x(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:x(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:x(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:w(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:w(process.env.MEMORY_RERANK_TOP,10),finalContext:w(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:w(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:x(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:w(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as gt}from"node:crypto";import{existsSync as B,mkdirSync as ht,readFileSync as yt,renameSync as St,writeFileSync as kt}from"node:fs";import{basename as vt,dirname as E,join as I,parse as ke,resolve as b}from"node:path";var ve=".toolnet",jt="project.json";function xt(r){return gt("sha256").update(r).digest("hex").slice(0,16)}function H(r){return I(r,ve,jt)}function wt(r){return B(H(r))}function bt(r,t){let e=b(r),n=ke(e).root;for(;;){if(wt(e))return e;if(e===n||t&&e===b(t))break;let o=E(e);if(o===e)break;e=o}return null}function Pt(r){let t=b(r),e=ke(t).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(s=>B(I(t,s))))return t;if(t===e)break;let o=E(t);if(o===t)break;t=o}return b(r)}function At(r){let t;try{t=JSON.parse(yt(r,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${r}: ${o instanceof Error?o.message:String(o)}`)}if(!t||typeof t!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let e=t;if(typeof e.id!="string"||!e.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof e.name!="string"||!e.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:e.id,name:e.name,remote:typeof e.remote=="string"&&e.remote.trim()?e.remote:e.name,rootPath:typeof e.rootPath=="string"?e.rootPath:E(E(r)),createdAt:typeof e.createdAt=="string"?e.createdAt:n,updatedAt:typeof e.updatedAt=="string"?e.updatedAt:n,graphVersion:typeof e.graphVersion=="number"?e.graphVersion:0,memoryVersion:typeof e.memoryVersion=="number"?e.memoryVersion:0,metadata:e.metadata&&typeof e.metadata=="object"?e.metadata:void 0}}function ye(r,t){let e=I(r,ve);ht(e,{recursive:!0});let n=H(r),o=`${n}.tmp-${process.pid}`;kt(o,JSON.stringify(t,null,2)+`
197
+ `,{encoding:"utf8",mode:384}),St(o,n)}function Se(r,t){return{id:r.id,name:r.name,remote:r.remote,rootPath:t,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var M=class{detect(t=process.cwd()){let e=b(t),n=Pt(e),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(f=>B(I(n,f))),a=bt(e,s?n:void 0);if(a){let f=H(a),c=At(f);return c.rootPath!==a&&(c.rootPath=a,c.updatedAt=new Date().toISOString(),ye(a,c)),Se(c,a)}let p=new Date().toISOString(),i=vt(n),l={version:1,id:xt(n),name:i,remote:i,rootPath:n,createdAt:p,updatedAt:p,graphVersion:0,memoryVersion:0};return ye(n,l),Se(l,n)}};import{homedir as Yt}from"node:os";import{join as Qt}from"node:path";import{DeleteObjectCommand as Ct,GetObjectCommand as Tt,HeadObjectCommand as Ot,ListObjectsV2Command as Et,PutObjectCommand as Mt,S3Client as It}from"@aws-sdk/client-s3";import{getSignedUrl as Rt}from"@aws-sdk/s3-request-presigner";var R=class{name="huggingface";client;bucket;constructor(t){this.bucket=t.bucket,this.client=new It({region:"us-east-1",endpoint:`https://s3.hf.co/${t.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,n="application/octet-stream"){let o=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new Mt({Bucket:this.bucket,Key:t,Body:o,ContentType:n}))}async get(t){let e=await Rt(this.client,new Tt({Bucket:this.bucket,Key:t}),{expiresIn:60}),n=await fetch(e,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`HF download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.arrayBuffer())}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new Ot({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new Ct({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],n;do{let o=await this.client.send(new Et({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:n}));for(let s of o.Contents??[])s.Key&&e.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return e}};import{access as je,mkdir as Nt,readFile as $t,readdir as _t,rm as Dt,stat as xe,writeFile as Kt}from"node:fs/promises";import{dirname as Ft,join as Wt,relative as we,resolve as Lt}from"node:path";var P=class{constructor(t){this.root=t}root;name="local";path(t){let e=t.replace(/^\/+/,"");return Lt(this.root,e)}async put(t,e){let n=this.path(t);await Nt(Ft(n),{recursive:!0}),await Kt(n,e)}async get(t){try{return await $t(this.path(t))}catch(e){if(typeof e=="object"&&e!==null&&"code"in e&&e.code==="ENOENT")return null;throw e}}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await je(this.path(t)),!0}catch{return!1}}async delete(t){await Dt(this.path(t),{force:!0})}async list(t=""){let e=this.path(t),n=[];try{await je(e)}catch{return n}let o=async a=>{let p=await _t(a,{withFileTypes:!0});for(let i of p){let l=Wt(a,i.name);if(i.isDirectory()){await o(l);continue}let f=await xe(l);n.push({key:we(this.root,l),size:f.size,updatedAt:f.mtime.toISOString()})}},s=await xe(e);return s.isDirectory()?await o(e):n.push({key:we(this.root,e),size:s.size,updatedAt:s.mtime.toISOString()}),n}};import{DeleteObjectCommand as Vt,GetObjectCommand as Bt,HeadObjectCommand as Ht,ListObjectsV2Command as Jt,PutObjectCommand as zt,S3Client as Gt}from"@aws-sdk/client-s3";import{getSignedUrl as Ut}from"@aws-sdk/s3-request-presigner";var A=class{name;client;bucket;constructor(t){this.name=t.name??"s3",this.bucket=t.bucket,this.client=new Gt({region:t.region??"us-east-1",endpoint:t.endpoint||void 0,forcePathStyle:t.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}})}async put(t,e,n="application/octet-stream"){let o=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new zt({Bucket:this.bucket,Key:t,Body:o,ContentType:n}))}async get(t){let e=await Ut(this.client,new Bt({Bucket:this.bucket,Key:t}),{expiresIn:60}),n=await fetch(e,{redirect:"follow"});if(n.status===404)return null;if(!n.ok)throw new Error(`${this.name} download failed: ${n.status} ${n.statusText}`);return new Uint8Array(await n.arrayBuffer())}async getText(t){let e=await this.get(t);return e?Buffer.from(e).toString("utf8"):null}async exists(t){try{return await this.client.send(new Ht({Bucket:this.bucket,Key:t})),!0}catch(e){if(typeof e=="object"&&e!==null&&"$metadata"in e&&e.$metadata?.httpStatusCode===404)return!1;throw e}}async delete(t){await this.client.send(new Vt({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],n;do{let o=await this.client.send(new Jt({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:n}));for(let s of o.Contents??[])s.Key&&e.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});n=o.IsTruncated?o.NextContinuationToken:void 0}while(n);return e}};function J(r,t){return console.warn(t),new P(r)}function be(r){let t=r.localRoot??Qt(Yt(),".toolnet-memory","storage");if(r.provider==="r2"){let e=r.r2;return e?.accountId&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new A({name:"r2",endpoint:`https://${e.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:e.bucket,forcePathStyle:!0,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):J(t,"[storage] Cloudflare R2 credentials missing. Using local fallback.")}if(r.provider==="s3"){let e=r.s3;return e?.bucket&&e.accessKeyId&&e.secretAccessKey?new A({name:"s3",endpoint:e.endpoint,region:e.region??"us-east-1",bucket:e.bucket,forcePathStyle:e.forcePathStyle??!1,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):J(t,"[storage] S3 credentials missing. Using local fallback.")}if(r.provider==="huggingface"){let e=r.huggingface;return e?.namespace&&e.bucket&&e.accessKeyId&&e.secretAccessKey?new R({namespace:e.namespace,bucket:e.bucket,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):J(t,"[storage] Hugging Face credentials missing. Using local fallback.")}return new P(t)}function qt(r){return new Promise(t=>setTimeout(t,r))}async function Pe(r,t={}){let e=Math.max(1,t.attempts??3),n=t.baseDelayMs??150,o=t.maxDelayMs??2e3,s;for(let a=1;a<=e;a++)try{return await r()}catch(p){if(s=p,a>=e)break;let i=Math.min(o,n*2**(a-1)),l=Math.floor(Math.random()*Math.max(1,i*.2));await qt(i+l)}throw s}var Xt=new Set(["put","get","getText","delete","list"]);function Ae(r,t={}){return new Proxy(r,{get(e,n){let o=Reflect.get(e,n,e);return typeof o!="function"?o:Xt.has(n)?(...s)=>Pe(()=>Promise.resolve(o.apply(e,s)),t):o.bind(e)}})}function Ce(r){let t=r.trim().replace(/\s+/g,"_").replace(/[^A-Za-z0-9._-]/g,"_").replace(/_+/g,"_").replace(/^\.+|\.+$/g,"").slice(0,100);if(!t||t==="."||t==="..")throw new Error("Invalid project storage folder");return t}function Te(r){let t=r.replace(/^\/+/,"");if(t.startsWith("memories/"))return"memory/records/"+t.slice(9);if(t.startsWith("vectors/"))return"memory/vectors/"+t.slice(8);if(t.startsWith("graph/"))return"code/graph/"+t.slice(6);let e=t.match(/^(snapshots\/[^/]+\/)memories\/(.+)$/);if(e)return`${e[1]}memory/records/${e[2]}`;if(e=t.match(/^(snapshots\/[^/]+\/)vectors\/(.+)$/),e)return`${e[1]}memory/vectors/${e[2]}`;if(e=t.match(/^(snapshots\/[^/]+\/)graph\/(.+)$/),e)return`${e[1]}code/graph/${e[2]}`;let n=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(n)return`${n[1]}memory/records/${n[2]}`;if(n=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),n)return`${n[1]}memory/vectors/${n[2]}`;if(n=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),n)return`${n[1]}code/graph/${n[2]}`;let o=t.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return o?`${o[1]}memory/records/${o[2]}`:(o=t.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),o?`${o[1]}memory/vectors/${o[2]}`:(o=t.match(/^(projects\/[^/]+\/)graph\/(.+)$/),o?`${o[1]}code/graph/${o[2]}`:t))}var N=class{constructor(t,e,n,o){this.provider=t;this.name=t.name,this.projectId=e,this.projectName=n,this.folder=Ce(o??n),this.sourcePrefix=`projects/${e}`,this.targetPrefix=`projects/${this.folder}`}provider;name;folder;sourcePrefix;targetPrefix;projectId;projectName;registryPromise;async registerProject(){let t=`${this.targetPrefix}/project.json`,e=new Date().toISOString(),n=e,o=await this.provider.getText(t);if(o){let a;try{a=JSON.parse(o)}catch(p){throw new Error(`Invalid remote ToolNet project manifest at ${t}: ${p instanceof Error?p.message:String(p)}`)}if(typeof a.id=="string"&&a.id!==this.projectId)throw new Error(["ToolNet remote project namespace collision.",`Remote folder: ${this.targetPrefix}`,`Existing project id: ${a.id}`,`Current project id: ${this.projectId}`,"Refusing to mix data from two projects."].join(" "));typeof a.createdAt=="string"&&(n=a.createdAt)}let s={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:n,updatedAt:e};await this.provider.put(t,JSON.stringify(s,null,2)+`
198
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(t){if(t=Te(t),t===this.sourcePrefix)return this.targetPrefix;if(t.startsWith(`${this.sourcePrefix}/`))return this.targetPrefix+t.slice(this.sourcePrefix.length);if(t===this.targetPrefix||t.startsWith(`${this.targetPrefix}/`))return t;if(t.startsWith("projects/"))throw new Error(["Cross-project storage access denied.",`Current project: ${this.targetPrefix}`,`Requested key: ${t}`].join(" "));return t}async put(t,e,n){return await this.ensureRegistered(),this.provider.put(this.key(t),e,n)}async get(t){return await this.ensureRegistered(),this.provider.get(this.key(t))}async getText(t){return await this.ensureRegistered(),this.provider.getText(this.key(t))}async delete(t){return await this.ensureRegistered(),this.provider.delete(this.key(t))}async exists(t){return await this.ensureRegistered(),this.provider.exists(this.key(t))}async list(t){return await this.ensureRegistered(),this.provider.list(this.key(t))}};function Zt(){let r=process.argv.slice(2),t=r[0]||"print",e={mode:"minimal"};for(let n=1;n<r.length;n++)r[n]==="--project"&&r[n+1]?(e.project=r[n+1],n++):r[n]==="--limit"&&r[n+1]?(e.limit=parseInt(r[n+1],10),n++):r[n]==="--focused"&&r[n+1]?(e.mode="focused",e.query=r[n+1],n++):r[n]==="--deep"&&(e.mode="deep");return{command:t,options:e}}async function er(){let{command:r,options:t}=Zt();try{switch(r){case"print":await tr(t);break;case"sync":await rr(t);break;case"refresh":await nr(t);break;case"profile-show":await or(t);break;case"profile-sync":await sr(t);break;default:console.error(`Unknown command: ${r}`),console.error("Available commands: print, sync, refresh, profile-show, profile-sync"),process.exit(1)}}catch(e){console.error("Error:",e instanceof Error?e.message:String(e)),process.exit(1)}}async function tr(r){let t=r.mode||"minimal";if(t==="minimal"){let e=F({projectPath:r.project});e||(console.error("No ToolNet project found. Run toolnet-memory init first."),process.exit(1)),process.stdout.write(e)}else(t==="focused"||t==="deep")&&(console.error("Focused and deep modes require storage access."),console.error("Use: toolnet-memory brief --deep for deep context"),process.exit(1))}async function rr(r){let t=F({projectPath:r.project});t||(console.error("No ToolNet project found."),process.exit(1));let e=ae(t);console.log(`Context hash: ${e}`),console.log(`Context size: ${t.length} chars`)}async function nr(r){console.log("Refreshing deep startup brief cache...");let t=r.project||process.cwd(),e=j(t);e||(console.error("No ToolNet project found."),process.exit(1));let n=new M().detect(e),o=he(),s=Ae(be({provider:o.storage.provider,huggingface:o.storage.huggingface,localRoot:o.storage.localRoot}),{attempts:2}),a=new N(s,n.id,n.name,n.remote??n.name);await ge(n,a),console.log("Deep startup brief cache refreshed.")}async function or(r){let t=r.project||process.cwd(),e=j(t);e||(console.error("No ToolNet project found."),process.exit(1));let n=Oe.join(e,".toolnet","profile.md");$.existsSync(n)||(console.error("No profile.md found in .toolnet directory."),process.exit(1));let o=$.readFileSync(n,"utf-8");process.stdout.write(o)}async function sr(r){let t=ie({projectPath:r.project});console.log("Created/updated:");for(let e of t)console.log(`- ${e}`)}er();
@@ -1,12 +1,12 @@
1
- import*as c from"fs";import*as i from"path";import{existsSync as b,mkdirSync as D,readFileSync as M,renameSync as L,writeFileSync as $}from"node:fs";import{dirname as z,join as w}from"node:path";import{createHash as F}from"node:crypto";function g(r){return F("sha256").update(r).digest("hex")}function T(r){return w(r.rootPath,".toolnet","context","handoff.md")}function A(r){return w(r.rootPath,".toolnet","context","handoff.json")}function R(r,e){D(z(r),{recursive:!0});let t=`${r}.tmp-${process.pid}-${Date.now()}`;$(t,e.endsWith(`
1
+ import*as c from"fs";import*as i from"path";import{existsSync as b,mkdirSync as D,readFileSync as w,renameSync as $,writeFileSync as L}from"node:fs";import{dirname as H,join as v}from"node:path";import{createHash as F}from"node:crypto";function g(n){return F("sha256").update(n).digest("hex")}function A(n){return v(n.rootPath,".toolnet","context","handoff.md")}function C(n){return v(n.rootPath,".toolnet","context","handoff.json")}function M(n,e){D(H(n),{recursive:!0});let t=`${n}.tmp-${process.pid}-${Date.now()}`;L(t,e.endsWith(`
2
2
  `)?e:`${e}
3
- `,{encoding:"utf8",mode:384}),L(t,r)}function H(r,e){R(r,`${JSON.stringify(e,null,2)}
4
- `)}function v(r,e){let t=e.replace(/\r\n/g,`
5
- `).trim();if(!t)return null;let n={version:1,projectId:r.id,projectName:r.name,text:t,digest:g(t),generatedAt:new Date().toISOString()};return R(T(r),t),H(A(r),n),n}function C(r){let e=T(r);if(!b(e))return null;try{let t=M(e,"utf8").trim();if(!t)return null;let n=new Date(0).toISOString(),o=A(r);if(b(o))try{let s=JSON.parse(M(o,"utf8"));typeof s.generatedAt=="string"&&(n=s.generatedAt)}catch{}return{version:1,projectId:r.id,projectName:r.name,text:t,digest:g(t),generatedAt:n}}catch{return null}}function E(r){let e=i.resolve(r),t=i.parse(e).root;for(;e!==t;){let n=i.join(e,".toolnet");if(c.existsSync(n)&&c.statSync(n).isDirectory())return e;e=i.dirname(e)}return null}import{existsSync as W,readFileSync as G}from"node:fs";import{join as J}from"node:path";import{existsSync as B,mkdirSync as Pe,readFileSync as K,renameSync as Ne,writeFileSync as Fe}from"node:fs";import{dirname as Le,join as Y}from"node:path";function V(r){return Y(r.rootPath,".toolnet","context","session-origin.json")}function U(r){let e=V(r);if(!B(e))return null;try{let t=JSON.parse(K(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function j(r){let e=U(r);if(!e)return null;let t=["Previous session:",`- Agent: ${e.agent}`,`- Session: ${e.nativeSessionId}`];return e.currentPhase&&t.push(`- Current phase: ${e.currentPhase}`),e.currentTask&&t.push(`- Current task: ${e.currentTask}`),e.lastTouchedFile&&t.push(`- Last touched file: ${e.lastTouchedFile}`),e.latestBlocker&&t.push(`- Blocker: ${e.latestBlocker}`),e.latestNextAction&&t.push(`- Next action: ${e.latestNextAction}`),e.latestDecision&&t.push(`- Important decision: ${e.latestDecision}`),t.join(`
6
- `)}function Q(r){let e=J(r.rootPath,".toolnet","current.md");if(!W(e))return null;try{return G(e,"utf8").trim()}catch{return null}}function Z(r,e){let t=e.replace(/\r\n/g,`
7
- `).trim(),n=2400,o=t.length>n?`${t.slice(0,n)}
3
+ `,{encoding:"utf8",mode:384}),$(t,n)}function z(n,e){M(n,`${JSON.stringify(e,null,2)}
4
+ `)}function E(n,e){let t=e.replace(/\r\n/g,`
5
+ `).trim();if(!t)return null;let r={version:1,projectId:n.id,projectName:n.name,text:t,digest:g(t),generatedAt:new Date().toISOString()};return M(A(n),t),z(C(n),r),r}function T(n){let e=A(n);if(!b(e))return null;try{let t=w(e,"utf8").trim();if(!t)return null;let r=new Date(0).toISOString(),o=C(n);if(b(o))try{let s=JSON.parse(w(o,"utf8"));typeof s.generatedAt=="string"&&(r=s.generatedAt)}catch{}return{version:1,projectId:n.id,projectName:n.name,text:t,digest:g(t),generatedAt:r}}catch{return null}}function R(n){let e=i.resolve(n),t=i.parse(e).root;for(;e!==t;){let r=i.join(e,".toolnet");if(c.existsSync(r)&&c.statSync(r).isDirectory())return e;e=i.dirname(e)}return null}import{existsSync as W,readFileSync as J}from"node:fs";import{join as U}from"node:path";import{existsSync as V,mkdirSync as De,readFileSync as G,renameSync as $e,writeFileSync as Le}from"node:fs";import{dirname as ze,join as B}from"node:path";function K(n){return B(n.rootPath,".toolnet","context","session-origin.json")}function Y(n){let e=K(n);if(!V(e))return null;try{let t=JSON.parse(G(e,"utf8"));return t.version!==1||t.projectId!==n.id?null:t}catch{return null}}function O(n){let e=Y(n);if(!e)return null;let t=["Previous session:",`- Agent: ${e.agent}`,`- Session: ${e.nativeSessionId}`];return e.currentPhase&&t.push(`- Current phase: ${e.currentPhase}`),e.currentTask&&t.push(`- Current task: ${e.currentTask}`),e.lastTouchedFile&&t.push(`- Last touched file: ${e.lastTouchedFile}`),e.latestBlocker&&t.push(`- Blocker: ${e.latestBlocker}`),e.latestNextAction&&t.push(`- Next action: ${e.latestNextAction}`),e.latestDecision&&t.push(`- Important decision: ${e.latestDecision}`),t.join(`
6
+ `)}function Q(n){let e=U(n.rootPath,".toolnet","current.md");if(!W(e))return null;try{return J(e,"utf8").trim()}catch{return null}}function Z(n,e){let t=e.replace(/\r\n/g,`
7
+ `).trim(),r=2400,o=t.length>r?`${t.slice(0,r)}
8
8
 
9
- [Current work truncated for fast handoff]`:t,s=j(r);return["# ToolNet Fast Handoff","",`Project: ${r.name}`,"",...s?[s,""]:[],o,"","---","","Continuation rule:","- Continue unfinished work; do not redo completed steps.","- Query ToolNet Memory only when deeper history is needed."].join(`
10
- `)}function I(r){let e=Q(r);if(e===null)return{updated:!1,reason:"missing-current",chars:0};if(!e.trim())return{updated:!1,reason:"empty-current",chars:0};let t=Z(r,e);return C(r)?.text.trim()===t.trim()?{updated:!1,reason:"unchanged",chars:t.length}:(v(r,t),{updated:!0,reason:"updated",chars:t.length})}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,`
11
- `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function ne(){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 n=t.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let o=n.indexOf("=");if(o<=0)continue;let s=n.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=re(n.slice(o+1)))}}ne();import{createHash as oe}from"node:crypto";import{existsSync as y,mkdirSync as se,readFileSync as ie,renameSync as ae,writeFileSync as ce}from"node:fs";import{basename as ue,dirname as d,join as f,parse as P,resolve as l}from"node:path";var N=".toolnet",le="project.json";function de(r){return oe("sha256").update(r).digest("hex").slice(0,16)}function h(r){return f(r,N,le)}function pe(r){return y(h(r))}function fe(r,e){let t=l(r),n=P(t).root;for(;;){if(pe(t))return t;if(t===n||e&&t===l(e))break;let o=d(t);if(o===t)break;t=o}return null}function me(r){let e=l(r),t=P(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(s=>y(f(e,s))))return e;if(e===t)break;let o=d(e);if(o===e)break;e=o}return l(r)}function ge(r){let e;try{e=JSON.parse(ie(r,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${r}: ${o instanceof Error?o.message:String(o)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:d(d(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:n,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:n,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function O(r,e){let t=f(r,N);se(t,{recursive:!0});let n=h(r),o=`${n}.tmp-${process.pid}`;ce(o,JSON.stringify(e,null,2)+`
12
- `,{encoding:"utf8",mode:384}),ae(o,n)}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 p=class{detect(e=process.cwd()){let t=l(e),n=me(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>y(f(n,m))),a=fe(t,s?n:void 0);if(a){let m=h(a),u=ge(m);return u.rootPath!==a&&(u.rootPath=a,u.updatedAt=new Date().toISOString(),O(a,u)),_(u,a)}let S=new Date().toISOString(),k=ue(n),x={version:1,id:de(n),name:k,remote:k,rootPath:n,createdAt:S,updatedAt:S,graphVersion:0,memoryVersion:0};return O(n,x),_(x,n)}};function ye(){let r=process.cwd(),e=E(r);if(!e){console.error("Not in a ToolNet project."),process.exitCode=1;return}let t=new p().detect(e);if(!t){console.error("Unable to detect ToolNet project."),process.exitCode=1;return}let n=I(t);console.log(JSON.stringify({project:t.name,...n},null,2))}ye();
9
+ [Current work truncated for fast handoff]`:t,s=O(n);return["# ToolNet Fast Handoff","",`Project: ${n.name}`,"",...s?[s,""]:[],o,"","---","","Continuation rule:","- Continue unfinished work; do not redo completed steps.","- Query ToolNet Memory only when deeper history is needed."].join(`
10
+ `)}function I(n){let e=Q(n);if(e===null)return{updated:!1,reason:"missing-current",chars:0};if(!e.trim())return{updated:!1,reason:"empty-current",chars:0};let t=Z(n,e);return T(n)?.text.trim()===t.trim()?{updated:!1,reason:"unchanged",chars:t.length}:(E(n,t),{updated:!0,reason:"updated",chars:t.length})}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 ne(n){let e=n.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
11
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function re(){let n=process.env.TOOLNET_GLOBAL_ENV??te(ee(),".config","toolnet-memory",".env");if(!q(n))return;let e=X(n,"utf8");for(let t of e.split(/\r?\n/)){let r=t.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let o=r.indexOf("=");if(o<=0)continue;let s=r.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=ne(r.slice(o+1)))}}re();import{createHash as oe}from"node:crypto";import{existsSync as y,mkdirSync as se,readFileSync as ie,renameSync as ae,writeFileSync as ce}from"node:fs";import{basename as ue,dirname as l,join as p,parse as N,resolve as d}from"node:path";var P=".toolnet",de="project.json";function le(n){return oe("sha256").update(n).digest("hex").slice(0,16)}function h(n){return p(n,P,de)}function fe(n){return y(h(n))}function pe(n,e){let t=d(n),r=N(t).root;for(;;){if(fe(t))return t;if(t===r||e&&t===d(e))break;let o=l(t);if(o===t)break;t=o}return null}function me(n){let e=d(n),t=N(e).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(s=>y(p(e,s))))return e;if(e===t)break;let o=l(e);if(o===e)break;e=o}return d(n)}function ge(n){let e;try{e=JSON.parse(ie(n,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${n}: ${o instanceof Error?o.message:String(o)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${n}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${n}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${n}`);let r=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:l(l(n)),createdAt:typeof t.createdAt=="string"?t.createdAt:r,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:r,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function j(n,e){let t=p(n,P);se(t,{recursive:!0});let r=h(n),o=`${r}.tmp-${process.pid}`;ce(o,JSON.stringify(e,null,2)+`
12
+ `,{encoding:"utf8",mode:384}),ae(o,r)}function _(n,e){return{id:n.id,name:n.name,remote:n.remote,rootPath:e,createdAt:n.createdAt,updatedAt:n.updatedAt,graphVersion:n.graphVersion,memoryVersion:n.memoryVersion,metadata:n.metadata}}var f=class{detect(e=process.cwd()){let t=d(e),r=me(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>y(p(r,m))),a=pe(t,s?r:void 0);if(a){let m=h(a),u=ge(m);return u.rootPath!==a&&(u.rootPath=a,u.updatedAt=new Date().toISOString(),j(a,u)),_(u,a)}let S=new Date().toISOString(),x=ue(r),k={version:1,id:le(r),name:x,remote:x,rootPath:r,createdAt:S,updatedAt:S,graphVersion:0,memoryVersion:0};return j(r,k),_(k,r)}};function ye(){let n=process.cwd(),e=R(n);if(!e){console.error("Not in a ToolNet project."),process.exitCode=1;return}let t=new f().detect(e);if(!t){console.error("Unable to detect ToolNet project."),process.exitCode=1;return}let r=I(t);console.log(JSON.stringify({project:t.name,...r},null,2))}ye();