toolnet-memory 0.2.15 → 0.2.17

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,27 +1,98 @@
1
1
  #!/usr/bin/env node
2
- import*as N from"fs";import*as he from"path";import*as y from"fs";import*as f from"path";import*as U from"crypto";function j(r){return r?Math.ceil(r.length/3.5):0}function $(r,t){if(!r)return"";if(j(r)<=t)return r;let o=Math.floor(t*3.5),n=r.slice(0,o),s=n.lastIndexOf("."),c=n.lastIndexOf(`
3
- `),l=Math.max(s,c);return l>o*.7?n.slice(0,l+1):n}function V(r,t){if(!r)return"";let e=r.split(`
2
+ import*as N from"fs";import*as we from"path";import*as h from"fs";import*as g from"path";import*as X from"crypto";function j(r){return r?Math.ceil(r.length/3.5):0}function $(r,t){if(!r)return"";if(j(r)<=t)return r;let o=Math.floor(t*3.5),n=r.slice(0,o),s=n.lastIndexOf("."),c=n.lastIndexOf(`
3
+ `),l=Math.max(s,c);return l>o*.7?n.slice(0,l+1):n}function J(r,t){if(!r)return"";let e=r.split(`
4
4
  `).filter(s=>s.trim());if(e.length<=t)return r;let o=e.slice(0,t),n=e.length-t;return[...o,`... (${n} more items omitted)`].join(`
5
- `)}function ye(r,t){let{maxTokens:e,trimMarker:o="[Context trimmed by ToolNet Memory token budget]"}=t;if(r.length===0)return"";let n=[...r].sort((i,u)=>u.priority-i.priority),s=[],c=0,l=!1;for(let i of n){let u=`# ${i.title}
5
+ `)}function be(r,t){let{maxTokens:e,trimMarker:o="[Context trimmed by ToolNet Memory token budget]"}=t;if(r.length===0)return"";let n=[...r].sort((i,p)=>p.priority-i.priority),s=[],c=0,l=!1;for(let i of n){let p=`# ${i.title}
6
6
 
7
- `,m=j(u),a=j(i.content),g=m+a;if(c+g<=e)s.push(u+i.content),c+=g;else{let p=e-c-m;if(p>50){let h=$(i.content,p);s.push(u+h),c=e,l=!0}else l=!0;break}}return l&&s.push(`
7
+ `,f=j(p),a=j(i.content),y=f+a;if(c+y<=e)s.push(p+i.content),c+=y;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(`
8
8
  ${o}
9
9
  `),s.join(`
10
10
 
11
11
  ---
12
12
 
13
- `)}function J(r,t){let e=[{title:"Profile",content:V(r,10),priority:100},{title:"Current Work",content:V(t,15),priority:90}];return ye(e,{maxTokens:800})}function k(r){let t=f.resolve(r),e=f.parse(t).root;for(;t!==e;){let o=f.join(t,".toolnet");if(y.existsSync(o)&&y.statSync(o).isDirectory())return t;t=f.dirname(t)}return null}function C(r){try{return y.existsSync(r)?y.readFileSync(r,"utf-8").trim():null}catch{return null}}function z(r){return r.split(`
13
+ `)}function z(r,t){let e=[{title:"Profile",content:J(r,10),priority:100},{title:"Current Work",content:J(t,15),priority:90}];return be(e,{maxTokens:800})}import{existsSync as H,mkdirSync as tr,readFileSync as U,renameSync as rr,writeFileSync as or}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 Oe}from"node:fs";function S(r){return Pe("sha256").update(r).digest("hex")}function k(r,t){Ae(Te(r),{recursive:!0});let e=`${r}.${process.pid}.tmp`;Oe(e,JSON.stringify(t,null,2)+`
14
+ `,{encoding:"utf8",mode:384}),Ce(e,r)}function Ee(r){return G(r.rootPath,".toolnet","context","handoff.md")}function Re(r){return G(r.rootPath,".toolnet","context","handoff.json")}function Ie(r){let t=Ee(r);if(!H(t))return null;try{let e=U(t,"utf8").trim();if(!e)return null;let o=new Date(0).toISOString(),n=Re(r);if(H(n))try{let s=JSON.parse(U(n,"utf8"));typeof s.generatedAt=="string"&&(o=s.generatedAt)}catch{}return{version:1,projectId:r.id,projectName:r.name,text:e,digest:S(e),generatedAt:o}}catch{return null}}function Y(r,t=1800){let e=Ie(r);if(!e?.text)return null;let o=e.text;return o.length>t&&(o=`${o.slice(0,t)}
15
+
16
+ [Fast handoff truncated]`),["[TOOLNET FAST HANDOFF]","",`Project: ${r.name}`,`Updated: ${e.generatedAt}`,"",o].join(`
17
+ `)}var _="memory_agent_ask";function q(){return`
18
+ [TOOLNET MEMORY AGENT]
19
+
20
+ Tool available:
21
+ - ${_}
22
+
23
+ Use it automatically BEFORE guessing when:
24
+
25
+ - The user asks to continue, resume, or pick up previous work.
26
+ - The user says things like:
27
+ - "ti\u1EBFp t\u1EE5c task l\xFAc n\xE3y"
28
+ - "l\xE0m ti\u1EBFp ph\u1EA7n \u0111ang d\u1EDF"
29
+ - "agent tr\u01B0\u1EDBc \u0111ang l\xE0m g\xEC?"
30
+ - "d\u1EEBng \u1EDF \u0111\xE2u?"
31
+ - "todo n\xE0o ch\u01B0a xong?"
32
+ - "continue the previous task"
33
+ - "resume the last session"
34
+ - Previous-agent state, unfinished work, blockers,
35
+ decisions, touched files, or next actions are unclear.
36
+ - Fast startup context is not enough to safely continue.
37
+
38
+ Preferred mode:
39
+
40
+ - mode="local"
41
+ for direct factual questions such as:
42
+ current task, last file, blocker, completed TODOs.
43
+
44
+ - mode="ai"
45
+ for composite or ambiguous continuity questions
46
+ that benefit from ToolNet Memory Agent reasoning.
47
+
48
+ Do NOT call it automatically when:
49
+
50
+ - Normal startup context already gives enough information.
51
+ - The question is unrelated to previous project work.
52
+ - The answer is obvious from current repository evidence.
53
+
54
+ Rules:
55
+
56
+ - Never invent previous work.
57
+ - Current repository evidence overrides stale memory.
58
+ - Do not dump raw transcripts or full memory.
59
+ - After receiving the ToolNet answer, continue the task
60
+ instead of asking the user to repeat known context.
61
+ - If ToolNet says information is not recorded, say so.
62
+ `.trim()}function Q(){return`
63
+ [TOOLNET MEMORY AGENT]
64
+
65
+ Tool:
66
+ - ${_}
67
+
68
+ If the user asks to resume previous work and the fast context
69
+ is insufficient, call ${_} before guessing.
70
+
71
+ Use:
72
+ - mode="local" for current task, last file, blocker or next action.
73
+ - mode="ai" for ambiguous or combined continuity questions.
74
+
75
+ Current repository evidence overrides stale memory.
76
+ `.trim()}function v(r){let t=g.resolve(r),e=g.parse(t).root;for(;t!==e;){let o=g.join(t,".toolnet");if(h.existsSync(o)&&h.statSync(o).isDirectory())return t;t=g.dirname(t)}return null}function A(r){try{return h.existsSync(r)?h.readFileSync(r,"utf-8").trim():null}catch{return null}}function Z(r){return r.split(`
14
77
  `).filter(o=>{let n=o.toUpperCase();return!(n.includes("SECRET")||n.includes("TOKEN")||n.includes("API_KEY")||n.includes("APIKEY")||n.includes("PASSWORD")||n.includes("PASS="))}).join(`
15
- `)}function _(r={}){let t=r.projectPath||process.cwd(),e=k(t);if(!e)return null;let o=f.join(e,".toolnet","project.json"),n="Unknown";try{if(y.existsSync(o)){let g=JSON.parse(y.readFileSync(o,"utf-8"));n=g.name||g.projectName||"Unknown"}}catch{}let s=f.join(e,".toolnet","profile.md"),c=f.join(e,".toolnet","current.md"),l=C(s)||"",i=C(c)||"";l=z(l),i=z(i);let u=`[TOOLNET PROJECT CONTEXT]
78
+ `)}function K(r={}){let t=r.projectPath||process.cwd(),e=v(t);if(!e)return null;let o=g.join(e,".toolnet","project.json"),n="Unknown";try{if(h.existsSync(o)){let m=JSON.parse(h.readFileSync(o,"utf-8"));n=m.name||m.projectName||"Unknown"}}catch{}let s=g.join(e,".toolnet","profile.md"),c=g.join(e,".toolnet","current.md"),l=A(s)||"",i=A(c)||"";l=Z(l),i=Z(i);let p=`[TOOLNET PROJECT CONTEXT]
16
79
 
17
80
  Project: ${n}
18
81
  Root: ${e}
19
82
 
20
- `,m=J(l,i);return u+m+`
83
+ `,f=z(l,i),a=Y({id:"",name:n,rootPath:e},1600),y=a?`
84
+
85
+ ${a}
86
+ `:"",u=`
87
+
88
+ ${Q()}
89
+
21
90
  Forbidden At Startup:
22
- - Do not run session:agy-recover, handoff:latest, or brief automatically
23
- - Deep memory only when user explicitly asks
24
- `}function H(r={}){let t=r.projectPath||process.cwd(),e=k(t);if(!e)throw new Error("Not in a ToolNet project (no .toolnet directory found)");let o=f.join(e,".toolnet","profile.md"),n=f.join(e,".toolnet","current.md"),s=C(o)||"",c=C(n)||"",l=`# AI Startup Instructions
91
+ - Do not run session:agy-recover, handoff:latest, or brief automatically.
92
+ - Do not perform deep recovery merely because an agent starts.
93
+ - If the user asks to resume previous work and fast context is insufficient,
94
+ use memory_agent_ask before guessing.
95
+ `;return p+f+y+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 o=g.join(e,".toolnet","profile.md"),n=g.join(e,".toolnet","current.md"),s=A(o)||"",c=A(n)||"",l=`# AI Startup Instructions
25
96
 
26
97
  Read and follow:
27
98
  - .toolnet/profile.md
@@ -30,7 +101,10 @@ Read and follow:
30
101
  Rules:
31
102
  - Fast context first.
32
103
  - Do not run session:agy-recover, handoff:latest, or brief automatically.
33
- - Deep memory only when the user explicitly asks.
104
+ - Do not invent previous-session state.
105
+ - Current repository evidence overrides stale memory.
106
+
107
+ ${q()}
34
108
 
35
109
  ---
36
110
 
@@ -43,8 +117,7 @@ ${s}
43
117
  ## Current Work
44
118
 
45
119
  ${c}
46
- `,i=["GEMINI.md","AGENTS.md","CLAUDE.md"],u=[];for(let m of i){let a=f.join(e,m);try{y.writeFileSync(a,l,"utf-8"),u.push(m)}catch(g){console.error(`Failed to write ${m}:`,g)}}return u}function Y(r){return U.createHash("sha256").update(r,"utf-8").digest("hex")}import{existsSync as dr,mkdirSync as $e,readFileSync as mr,writeFileSync as _e}from"node:fs";import{dirname as Ke,join as te}from"node:path";import{createHash as Se}from"node:crypto";import{dirname as je}from"node:path";import{mkdirSync as ke,readFileSync as zt,renameSync as ve,writeFileSync as xe}from"node:fs";function S(r){return Se("sha256").update(r).digest("hex")}function v(r,t){ke(je(r),{recursive:!0});let e=`${r}.${process.pid}.tmp`;xe(e,JSON.stringify(t,null,2)+`
47
- `,{encoding:"utf8",mode:384}),ve(e,r)}import{existsSync as q,mkdirSync as we,readFileSync as be,statSync as G,writeFileSync as Pe}from"node:fs";import{dirname as Ae,join as Ce}from"node:path";var Q=64*1024,Te=`# ToolNet Project Operating Manual
120
+ `,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(y){console.error(`Failed to write ${f}:`,y)}}return p}function te(r){return X.createHash("sha256").update(r,"utf-8").digest("hex")}import{existsSync as Ir,mkdirSync as ze,readFileSync as Mr,writeFileSync as He}from"node:fs";import{dirname as Ue,join as ce}from"node:path";import{existsSync as ne,mkdirSync as Me,readFileSync as Ne,statSync as re,writeFileSync as $e}from"node:fs";import{dirname as _e,join as Ke}from"node:path";var oe=64*1024,De=`# ToolNet Project Operating Manual
48
121
 
49
122
  This file contains persistent instructions for AI agents working on this project.
50
123
 
@@ -87,17 +160,17 @@ Things an AI agent should always remember.
87
160
  <!--
88
161
  - [advisory] Prefer small focused files.
89
162
  -->
90
- `;function T(r){return Ce(r.rootPath,".toolnet","PROJECT.md")}function Oe(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function Re(r){let t=[],e=new Set,o=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,n;for(;n=o.exec(r);){let s=n[1].toLowerCase(),c=Oe(n[2]);if(!c)continue;let l=`${s}:${c.toLowerCase()}`;e.has(l)||(e.add(l),t.push({id:S(l).slice(0,24),mode:s,text:c,source:"manual"}))}return t}function Ee(r){let t=T(r);return q(t)||(we(Ae(t),{recursive:!0}),Pe(t,Te,{encoding:"utf8",mode:384})),t}function K(r,t=!1){let e=t?Ee(r):T(r);if(!q(e))return null;if(G(e).size>Q)throw new Error(`PROJECT.md exceeds ${Q} bytes`);let n=be(e,"utf8");return{path:e,content:n,digest:S(n),rules:Re(n),bytes:Buffer.byteLength(n,"utf8"),updatedAt:new Date(G(e).mtimeMs).toISOString()}}async function D(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 Z(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 X(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 B(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 Ie(r){let t=[],e=!1;for(let o of r.split(/\r?\n/u)){let n=o.trim();if(n.includes("<!--")&&(e=!0),e){n.includes("-->")&&(e=!1);continue}let s=n.toLowerCase();if(!(!n||n.startsWith("#")||n==="```"||s.startsWith("- [enforce]")||s.startsWith("* [enforce]")||s.startsWith("- [advisory]")||s.startsWith("* [advisory]"))&&(n=n.replace(/^[-*]\s+/u,""),n&&t.push(d(n,280)),t.length>=16))break}return t}function Me(r){let t=[],e=[];for(let o of r.split(/\\r?\\n/u)){let n=o.trim(),s=n.toLowerCase(),l=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(u=>s.startsWith(u));if(!l)continue;let i=n.slice(l.length).trim();i&&(l.includes("enforce")?t.push(i):e.push(i))}return{enforce:t,advisory:e}}function Ne(r,t){let e=[];for(let o of r){let n=[...e,o].join(`
91
- `);if(B(n)<=t){e.push(o);continue}let s=B(e.join(`
163
+ `;function C(r){return Ke(r.rootPath,".toolnet","PROJECT.md")}function Fe(r){return r.normalize("NFKC").replace(/\s+/g," ").trim()}function We(r){let t=[],e=new Set,o=/^\s*[-*]\s+\[(enforce|advisory)\]\s+(.+?)\s*$/gimu,n;for(;n=o.exec(r);){let s=n[1].toLowerCase(),c=Fe(n[2]);if(!c)continue;let l=`${s}:${c.toLowerCase()}`;e.has(l)||(e.add(l),t.push({id:S(l).slice(0,24),mode:s,text:c,source:"manual"}))}return t}function Be(r){let t=C(r);return ne(t)||(Me(_e(t),{recursive:!0}),$e(t,De,{encoding:"utf8",mode:384})),t}function D(r,t=!1){let e=t?Be(r):C(r);if(!ne(e))return null;if(re(e).size>oe)throw new Error(`PROJECT.md exceeds ${oe} bytes`);let n=Ne(e,"utf8");return{path:e,content:n,digest:S(n),rules:We(n),bytes:Buffer.byteLength(n,"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 o of r.split(/\r?\n/u)){let n=o.trim();if(n.includes("<!--")&&(e=!0),e){n.includes("-->")&&(e=!1);continue}let s=n.toLowerCase();if(!(!n||n.startsWith("#")||n==="```"||s.startsWith("- [enforce]")||s.startsWith("* [enforce]")||s.startsWith("- [advisory]")||s.startsWith("* [advisory]"))&&(n=n.replace(/^[-*]\s+/u,""),n&&t.push(d(n,280)),t.length>=16))break}return t}function Ve(r){let t=[],e=[];for(let o of r.split(/\\r?\\n/u)){let n=o.trim(),s=n.toLowerCase(),l=["- [enforce]","* [enforce]","- [advisory]","* [advisory]"].find(p=>s.startsWith(p));if(!l)continue;let i=n.slice(l.length).trim();i&&(l.includes("enforce")?t.push(i):e.push(i))}return{enforce:t,advisory:e}}function Je(r,t){let e=[];for(let o of r){let n=[...e,o].join(`
164
+ `);if(W(n)<=t){e.push(o);continue}let s=W(e.join(`
92
165
  `)),c=Math.max(0,t-s);if(c>=16){let l=Math.floor(c*3.2),i=d(o,l);i&&e.push(i)}break}return e.join(`
93
- `).trim()}async function ee(r){let t=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),e=K(r.project,!1),o=e?.content??"";o||(o=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let n=Me(o),s=e?e.rules.filter(p=>p.mode==="enforce").map(p=>p.text):n.enforce,c=e?e.rules.filter(p=>p.mode==="advisory").map(p=>p.text):n.advisory,l=o?Ie(o):[],i=await D(r.project,r.storage),u=await X(r.project,r.storage),m=await Z(r.project,r.storage),a=[];if(a.push("[TOOLNET PROJECT CONTEXT]"),a.push(`Project: ${r.project.name}`),a.push("Continue existing project state. Do not restart completed work unless evidence shows it is necessary."),o&&a.push(`Full operating manual: ${T(r.project)}`),s.length){a.push("","PROJECT RULES \u2014 MUST FOLLOW");for(let p of s.slice(0,24))a.push(`- [ENFORCE] ${d(p,240)}`)}if(c.length){a.push("","PROJECT PREFERENCES");for(let p of c.slice(0,10))a.push(`- ${d(p,220)}`)}if(u&&(u.mission&&a.push("","MISSION",d(u.mission.value,420)),u.activeObjective&&a.push("","CURRENT OBJECTIVE",d(u.activeObjective.value,420)),u.why&&a.push("","WHY THIS WORK MATTERS",d(u.why.value,420)),u.desiredOutcome&&a.push("","DESIRED OUTCOME",d(u.desiredOutcome.value,420)),u.planRationale&&a.push("","WHY THIS APPROACH",d(u.planRationale.value,420))),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&&u){let p=u.phases.find(h=>h.order===i.currentPhase?.order);p&&(p.objective&&a.push(`Phase objective: ${d(p.objective.value,340)}`),p.why?a.push(`Why this phase: ${d(p.why.value,340)}`):a.push("Why this phase: not explicitly recorded. Inspect existing implementation before assuming intent."),p.deliverable&&a.push(`Deliverable: ${d(p.deliverable.value,340)}`),p.dependencies.length&&a.push(`Depends on: ${p.dependencies.slice(0,4).map(h=>d(h.value,180)).join("; ")}`),p.acceptanceCriteria.length&&(a.push("","DEFINITION OF DONE"),p.acceptanceCriteria.slice(0,6).forEach(h=>{a.push(`- ${d(h.value,260)}`)})),p.openQuestions.length&&(a.push("","OPEN QUESTIONS FOR CURRENT PHASE"),p.openQuestions.slice(0,4).forEach(h=>{a.push(`- ${d(h.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((p,h)=>{a.push(`${h+1}. ${d(p,260)}`)})),i.blockers.length&&(a.push("","BLOCKERS"),i.blockers.slice(0,5).forEach(p=>{a.push(`- ${d(p,260)}`)})),i.warnings.length&&(a.push("","ATTENTION"),i.warnings.slice(-5).forEach(p=>{a.push(`- ${d(p,260)}`)})),i.decisions.length&&(a.push("","RECENT DECISIONS"),i.decisions.slice(-5).forEach(p=>{a.push(`- ${d(p,260)}`)})),i.lastSession&&a.push("",`Last work session: ${i.lastSession.agent} / ${i.lastSession.nativeSessionId}`)}if(u&&u.openQuestions.length&&(a.push("","UNRESOLVED QUESTIONS"),u.openQuestions.slice(0,5).forEach(p=>{a.push(`- ${d(p.value,260)}`)})),m&&a.push(`Latest handoff: ${m.reason} / ${m.sourceSession.agent}`),l.length){a.push("","OPERATING NOTES");for(let p of l)a.push(`- ${p}`)}a.push("","Before changing anything: verify the current repository state and continue from the active phase/task above.");let g=Ne(a,t);return{version:1,projectId:r.project.id,projectName:r.project.name,text:g,estimatedTokens:B(g),maxTokens:t,hasManual:!!o,hasWorkState:!!i,hasHandoff:!!m,generatedAt:new Date().toISOString()}}function De(r){return te(r.rootPath,".toolnet","context","startup.md")}function Be(r){return te(r.rootPath,".toolnet","context","startup.json")}function We(r,t){let e=De(r);$e(Ke(e),{recursive:!0}),_e(e,t.text.endsWith(`
166
+ `).trim()}async function ae(r){let t=Math.max(256,Math.min(2e3,r.maxTokens??1e3)),e=D(r.project,!1),o=e?.content??"";o||(o=await r.storage.getText(`projects/${r.project.id}/project/manual.md`)??"");let n=Ve(o),s=e?e.rules.filter(u=>u.mode==="enforce").map(u=>u.text):n.enforce,c=e?e.rules.filter(u=>u.mode==="advisory").map(u=>u.text):n.advisory,l=o?Le(o):[],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."),o&&a.push(`Full operating manual: ${C(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 y=Je(a,t);return{version:1,projectId:r.project.id,projectName:r.project.name,text:y,estimatedTokens:W(y),maxTokens:t,hasManual:!!o,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}),He(e,t.text.endsWith(`
94
167
  `)?t.text:t.text+`
95
- `,{encoding:"utf8",mode:384}),v(Be(r),t)}async function re(r,t,e=800){let n=(await ee({project:r,storage:t,maxTokens:e})).text;j(n)>e&&(n=$(n,e),n+=`
168
+ `,{encoding:"utf8",mode:384}),k(Ye(r),t)}async function ue(r,t,e=800){let n=(await ae({project:r,storage:t,maxTokens:e})).text;j(n)>e&&(n=$(n,e),n+=`
96
169
 
97
170
  [Context trimmed by ToolNet Memory token budget]
98
- `);let c={version:1,projectId:r.id,projectName:r.name,text:n,digest:S(n),estimatedTokens:j(n),generatedAt:new Date().toISOString()};return We(r,c),await t.put(`projects/${r.id}/context/startup.md`,c.text+`
171
+ `);let c={version:1,projectId:r.id,projectName:r.name,text:n,digest:S(n),estimatedTokens:j(n),generatedAt:new Date().toISOString()};return qe(r,c),await t.put(`projects/${r.id}/context/startup.md`,c.text+`
99
172
  `,"text/markdown"),await t.put(`projects/${r.id}/context/startup.json`,JSON.stringify(c,null,2)+`
100
- `,"application/json"),c}import{existsSync as Fe,readFileSync as Le}from"node:fs";import{homedir as Ve}from"node:os";import{join as Je}from"node:path";function ze(r){let t=r.trim();return t.length>=2&&t.startsWith('"')&&t.endsWith('"')?(t=t.slice(1,-1),t.replace(/\\n/g,`
101
- `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):t.length>=2&&t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function Ue(){let r=process.env.TOOLNET_GLOBAL_ENV??Je(Ve(),".config","toolnet-memory",".env");if(!Fe(r))return;let t=Le(r,"utf8");for(let e of t.split(/\r?\n/)){let o=e.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let n=o.indexOf("=");if(n<=0)continue;let s=o.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=ze(o.slice(n+1)))}}Ue();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 oe(){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 He}from"node:crypto";import{existsSync as W,mkdirSync as Ye,readFileSync as Ge,renameSync as Qe,writeFileSync as qe}from"node:fs";import{basename as Ze,dirname as O,join as E,parse as ie,resolve as b}from"node:path";var ae=".toolnet",Xe="project.json";function et(r){return He("sha256").update(r).digest("hex").slice(0,16)}function F(r){return E(r,ae,Xe)}function tt(r){return W(F(r))}function rt(r,t){let e=b(r),o=ie(e).root;for(;;){if(tt(e))return e;if(e===o||t&&e===b(t))break;let n=O(e);if(n===e)break;e=n}return null}function ot(r){let t=b(r),e=ie(t).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(s=>W(E(t,s))))return t;if(t===e)break;let n=O(t);if(n===t)break;t=n}return b(r)}function nt(r){let t;try{t=JSON.parse(Ge(r,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${r}: ${n instanceof Error?n.message:String(n)}`)}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 o=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:O(O(r)),createdAt:typeof e.createdAt=="string"?e.createdAt:o,updatedAt:typeof e.updatedAt=="string"?e.updatedAt:o,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 ne(r,t){let e=E(r,ae);Ye(e,{recursive:!0});let o=F(r),n=`${o}.tmp-${process.pid}`;qe(n,JSON.stringify(t,null,2)+`
102
- `,{encoding:"utf8",mode:384}),Qe(n,o)}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 R=class{detect(t=process.cwd()){let e=b(t),o=ot(e),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>W(E(o,m))),c=rt(e,s?o:void 0);if(c){let m=F(c),a=nt(m);return a.rootPath!==c&&(a.rootPath=c,a.updatedAt=new Date().toISOString(),ne(c,a)),se(a,c)}let l=new Date().toISOString(),i=Ze(o),u={version:1,id:et(o),name:i,remote:i,rootPath:o,createdAt:l,updatedAt:l,graphVersion:0,memoryVersion:0};return ne(o,u),se(u,o)}};import{homedir as Ct}from"node:os";import{join as Tt}from"node:path";import{DeleteObjectCommand as st,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(t){this.bucket=t.bucket,this.client=new ut({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,o="application/octet-stream"){let n=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new pt({Bucket:this.bucket,Key:t,Body:n,ContentType:o}))}async get(t){let e=await lt(this.client,new it({Bucket:this.bucket,Key:t}),{expiresIn:60}),o=await fetch(e,{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(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 at({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 st({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],o;do{let n=await this.client.send(new ct({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:o}));for(let s of n.Contents??[])s.Key&&e.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return e}};import{access as ce,mkdir as dt,readFile as mt,readdir as ft,rm as gt,stat as pe,writeFile as ht}from"node:fs/promises";import{dirname as yt,join as St,relative as ue,resolve as jt}from"node:path";var P=class{constructor(t){this.root=t}root;name="local";path(t){let e=t.replace(/^\/+/,"");return jt(this.root,e)}async put(t,e){let o=this.path(t);await dt(yt(o),{recursive:!0}),await ht(o,e)}async get(t){try{return await mt(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 ce(this.path(t)),!0}catch{return!1}}async delete(t){await gt(this.path(t),{force:!0})}async list(t=""){let e=this.path(t),o=[];try{await ce(e)}catch{return o}let n=async c=>{let l=await ft(c,{withFileTypes:!0});for(let i of l){let u=St(c,i.name);if(i.isDirectory()){await n(u);continue}let m=await pe(u);o.push({key:ue(this.root,u),size:m.size,updatedAt:m.mtime.toISOString()})}},s=await pe(e);return s.isDirectory()?await n(e):o.push({key:ue(this.root,e),size:s.size,updatedAt:s.mtime.toISOString()}),o}};import{DeleteObjectCommand as kt,GetObjectCommand as vt,HeadObjectCommand as xt,ListObjectsV2Command as wt,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(t){this.name=t.name??"s3",this.bucket=t.bucket,this.client=new Pt({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,o="application/octet-stream"){let n=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new bt({Bucket:this.bucket,Key:t,Body:n,ContentType:o}))}async get(t){let e=await At(this.client,new vt({Bucket:this.bucket,Key:t}),{expiresIn:60}),o=await fetch(e,{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(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 xt({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 kt({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],o;do{let n=await this.client.send(new wt({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:o}));for(let s of n.Contents??[])s.Key&&e.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return e}};function L(r,t){return console.warn(t),new P(r)}function le(r){let t=r.localRoot??Tt(Ct(),".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}):L(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}):L(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 I({namespace:e.namespace,bucket:e.bucket,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}):L(t,"[storage] Hugging Face credentials missing. Using local fallback.")}return new P(t)}function Ot(r){return new Promise(t=>setTimeout(t,r))}async function de(r,t={}){let e=Math.max(1,t.attempts??3),o=t.baseDelayMs??150,n=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(n,o*2**(c-1)),u=Math.floor(Math.random()*Math.max(1,i*.2));await Ot(i+u)}throw s}var Rt=new Set(["put","get","getText","delete","list"]);function me(r,t={}){return new Proxy(r,{get(e,o){let n=Reflect.get(e,o,e);return typeof n!="function"?n:Rt.has(o)?(...s)=>de(()=>Promise.resolve(n.apply(e,s)),t):n.bind(e)}})}function fe(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 ge(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 o=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(o)return`${o[1]}memory/records/${o[2]}`;if(o=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),o)return`${o[1]}memory/vectors/${o[2]}`;if(o=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),o)return`${o[1]}code/graph/${o[2]}`;let n=t.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return n?`${n[1]}memory/records/${n[2]}`:(n=t.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),n?`${n[1]}memory/vectors/${n[2]}`:(n=t.match(/^(projects\/[^/]+\/)graph\/(.+)$/),n?`${n[1]}code/graph/${n[2]}`:t))}var M=class{constructor(t,e,o,n){this.provider=t;this.name=t.name,this.projectId=e,this.projectName=o,this.folder=fe(n??o),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(),o=e,n=await this.provider.getText(t);if(n){let c;try{c=JSON.parse(n)}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"&&(o=c.createdAt)}let s={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:e};await this.provider.put(t,JSON.stringify(s,null,2)+`
103
- `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(t){if(t=ge(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,o){return await this.ensureRegistered(),this.provider.put(this.key(t),e,o)}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 Et(){let r=process.argv.slice(2),t=r[0]||"print",e={mode:"minimal"};for(let o=1;o<r.length;o++)r[o]==="--project"&&r[o+1]?(e.project=r[o+1],o++):r[o]==="--limit"&&r[o+1]?(e.limit=parseInt(r[o+1],10),o++):r[o]==="--focused"&&r[o+1]?(e.mode="focused",e.query=r[o+1],o++):r[o]==="--deep"&&(e.mode="deep");return{command:t,options:e}}async function It(){let{command:r,options:t}=Et();try{switch(r){case"print":await Mt(t);break;case"sync":await Nt(t);break;case"refresh":await $t(t);break;case"profile-show":await _t(t);break;case"profile-sync":await Kt(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 Mt(r){let t=r.mode||"minimal";if(t==="minimal"){let e=_({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 Nt(r){let t=_({projectPath:r.project});t||(console.error("No ToolNet project found."),process.exit(1));let e=Y(t);console.log(`Context hash: ${e}`),console.log(`Context size: ${t.length} chars`)}async function $t(r){console.log("Refreshing deep startup brief cache...");let t=r.project||process.cwd(),e=k(t);e||(console.error("No ToolNet project found."),process.exit(1));let o=new R().detect(e),n=oe(),s=me(le({provider:n.storage.provider,huggingface:n.storage.huggingface,localRoot:n.storage.localRoot}),{attempts:2}),c=new M(s,o.id,o.name,o.remote??o.name);await re(o,c),console.log("Deep startup brief cache refreshed.")}async function _t(r){let t=r.project||process.cwd(),e=k(t);e||(console.error("No ToolNet project found."),process.exit(1));let o=he.join(e,".toolnet","profile.md");N.existsSync(o)||(console.error("No profile.md found in .toolnet directory."),process.exit(1));let n=N.readFileSync(o,"utf-8");process.stdout.write(n)}async function Kt(r){let t=H({projectPath:r.project});console.log("Created/updated:");for(let e of t)console.log(`- ${e}`)}It();
173
+ `,"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,`
174
+ `).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 o=e.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let n=o.indexOf("=");if(n<=0)continue;let s=o.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=tt(o.slice(n+1)))}}rt();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 pe(){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 ot}from"node:crypto";import{existsSync as B,mkdirSync as nt,readFileSync as st,renameSync as it,writeFileSync as at}from"node:fs";import{basename as ct,dirname as O,join as R,parse as fe,resolve as b}from"node:path";var me=".toolnet",ut="project.json";function pt(r){return ot("sha256").update(r).digest("hex").slice(0,16)}function L(r){return R(r,me,ut)}function lt(r){return B(L(r))}function dt(r,t){let e=b(r),o=fe(e).root;for(;;){if(lt(e))return e;if(e===o||t&&e===b(t))break;let n=O(e);if(n===e)break;e=n}return null}function ft(r){let t=b(r),e=fe(t).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(s=>B(R(t,s))))return t;if(t===e)break;let n=O(t);if(n===t)break;t=n}return b(r)}function mt(r){let t;try{t=JSON.parse(st(r,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${r}: ${n instanceof Error?n.message:String(n)}`)}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 o=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:O(O(r)),createdAt:typeof e.createdAt=="string"?e.createdAt:o,updatedAt:typeof e.updatedAt=="string"?e.updatedAt:o,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=R(r,me);nt(e,{recursive:!0});let o=L(r),n=`${o}.tmp-${process.pid}`;at(n,JSON.stringify(t,null,2)+`
175
+ `,{encoding:"utf8",mode:384}),it(n,o)}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 E=class{detect(t=process.cwd()){let e=b(t),o=ft(e),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(f=>B(R(o,f))),c=dt(e,s?o: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(o),p={version:1,id:pt(o),name:i,remote:i,rootPath:o,createdAt:l,updatedAt:l,graphVersion:0,memoryVersion:0};return le(o,p),de(p,o)}};import{homedir as Kt}from"node:os";import{join as Dt}from"node:path";import{DeleteObjectCommand as gt,GetObjectCommand as ht,HeadObjectCommand as yt,ListObjectsV2Command as St,PutObjectCommand as jt,S3Client as kt}from"@aws-sdk/client-s3";import{getSignedUrl as vt}from"@aws-sdk/s3-request-presigner";var I=class{name="huggingface";client;bucket;constructor(t){this.bucket=t.bucket,this.client=new kt({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,o="application/octet-stream"){let n=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new jt({Bucket:this.bucket,Key:t,Body:n,ContentType:o}))}async get(t){let e=await vt(this.client,new ht({Bucket:this.bucket,Key:t}),{expiresIn:60}),o=await fetch(e,{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(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=[],o;do{let n=await this.client.send(new St({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:o}));for(let s of n.Contents??[])s.Key&&e.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return e}};import{access as ge,mkdir as xt,readFile as wt,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 Ot}from"node:path";var P=class{constructor(t){this.root=t}root;name="local";path(t){let e=t.replace(/^\/+/,"");return Ot(this.root,e)}async put(t,e){let o=this.path(t);await xt(At(o),{recursive:!0}),await Tt(o,e)}async get(t){try{return await wt(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),o=[];try{await ge(e)}catch{return o}let n=async c=>{let l=await bt(c,{withFileTypes:!0});for(let i of l){let p=Ct(c,i.name);if(i.isDirectory()){await n(p);continue}let f=await he(p);o.push({key:ye(this.root,p),size:f.size,updatedAt:f.mtime.toISOString()})}},s=await he(e);return s.isDirectory()?await n(e):o.push({key:ye(this.root,e),size:s.size,updatedAt:s.mtime.toISOString()}),o}};import{DeleteObjectCommand as Et,GetObjectCommand as Rt,HeadObjectCommand as It,ListObjectsV2Command as Mt,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,o="application/octet-stream"){let n=typeof e=="string"?Buffer.from(e,"utf8"):e;await this.client.send(new Nt({Bucket:this.bucket,Key:t,Body:n,ContentType:o}))}async get(t){let e=await _t(this.client,new Rt({Bucket:this.bucket,Key:t}),{expiresIn:60}),o=await fetch(e,{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(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 It({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 Et({Bucket:this.bucket,Key:t}))}async list(t=""){let e=[],o;do{let n=await this.client.send(new Mt({Bucket:this.bucket,Prefix:t||void 0,ContinuationToken:o}));for(let s of n.Contents??[])s.Key&&e.push({key:s.Key,size:s.Size,updatedAt:s.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return e}};function V(r,t){return console.warn(t),new P(r)}function Se(r){let t=r.localRoot??Dt(Kt(),".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 I({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 je(r,t={}){let e=Math.max(1,t.attempts??3),o=t.baseDelayMs??150,n=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(n,o*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 ke(r,t={}){return new Proxy(r,{get(e,o){let n=Reflect.get(e,o,e);return typeof n!="function"?n:Wt.has(o)?(...s)=>je(()=>Promise.resolve(n.apply(e,s)),t):n.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 xe(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 o=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)memories\/(.+)$/);if(o)return`${o[1]}memory/records/${o[2]}`;if(o=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)vectors\/(.+)$/),o)return`${o[1]}memory/vectors/${o[2]}`;if(o=t.match(/^(projects\/[^/]+\/snapshots\/[^/]+\/)graph\/(.+)$/),o)return`${o[1]}code/graph/${o[2]}`;let n=t.match(/^(projects\/[^/]+\/)memories\/(.+)$/);return n?`${n[1]}memory/records/${n[2]}`:(n=t.match(/^(projects\/[^/]+\/)vectors\/(.+)$/),n?`${n[1]}memory/vectors/${n[2]}`:(n=t.match(/^(projects\/[^/]+\/)graph\/(.+)$/),n?`${n[1]}code/graph/${n[2]}`:t))}var M=class{constructor(t,e,o,n){this.provider=t;this.name=t.name,this.projectId=e,this.projectName=o,this.folder=ve(n??o),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(),o=e,n=await this.provider.getText(t);if(n){let c;try{c=JSON.parse(n)}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"&&(o=c.createdAt)}let s={version:1,id:this.projectId,name:this.projectName,remote:this.folder,createdAt:o,updatedAt:e};await this.provider.put(t,JSON.stringify(s,null,2)+`
176
+ `,"application/json")}async ensureRegistered(){return this.registryPromise||(this.registryPromise=this.registerProject()),this.registryPromise}key(t){if(t=xe(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,o){return await this.ensureRegistered(),this.provider.put(this.key(t),e,o)}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 o=1;o<r.length;o++)r[o]==="--project"&&r[o+1]?(e.project=r[o+1],o++):r[o]==="--limit"&&r[o+1]?(e.limit=parseInt(r[o+1],10),o++):r[o]==="--focused"&&r[o+1]?(e.mode="focused",e.query=r[o+1],o++):r[o]==="--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 Jt(t);break;case"refresh":await zt(t);break;case"profile-show":await Ht(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=K({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 Jt(r){let t=K({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 o=new E().detect(e),n=pe(),s=ke(Se({provider:n.storage.provider,huggingface:n.storage.huggingface,localRoot:n.storage.localRoot}),{attempts:2}),c=new M(s,o.id,o.name,o.remote??o.name);await ue(o,c),console.log("Deep startup brief cache refreshed.")}async function Ht(r){let t=r.project||process.cwd(),e=v(t);e||(console.error("No ToolNet project found."),process.exit(1));let o=we.join(e,".toolnet","profile.md");N.existsSync(o)||(console.error("No profile.md found in .toolnet directory."),process.exit(1));let n=N.readFileSync(o,"utf-8");process.stdout.write(n)}async function Ut(r){let t=ee({projectPath:r.project});console.log("Created/updated:");for(let e of t)console.log(`- ${e}`)}Lt();
package/bundle/doctor.js CHANGED
@@ -1,3 +1,5 @@
1
- import"dotenv/config";import{existsSync as ae,readFileSync as ce}from"node:fs";import{homedir as de}from"node:os";import{join as pe}from"node:path";function le(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 me(){let r=process.env.TOOLNET_GLOBAL_ENV??pe(de(),".config","toolnet-memory",".env");if(!ae(r))return;let e=ce(r,"utf8");for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let n=o.indexOf("=");if(n<=0)continue;let i=o.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=le(o.slice(n+1)))}}me();function f(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 V(){return{memory:{autoCapture:f(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:f(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:f(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:f(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates: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:f(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 ue}from"node:crypto";import{existsSync as K,mkdirSync as ge,readFileSync as fe,renameSync as ye,writeFileSync as he}from"node:fs";import{basename as Ee,dirname as v,join as A,parse as H,resolve as h}from"node:path";var G=".toolnet",be="project.json";function ve(r){return ue("sha256").update(r).digest("hex").slice(0,16)}function N(r){return A(r,G,be)}function Se(r){return K(N(r))}function Ae(r,e){let t=h(r),o=H(t).root;for(;;){if(Se(t))return t;if(t===o||e&&t===h(e))break;let n=v(t);if(n===t)break;t=n}return null}function _e(r){let e=h(r),t=H(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>K(A(e,i))))return e;if(e===t)break;let n=v(e);if(n===e)break;e=n}return h(r)}function Pe(r){let e;try{e=JSON.parse(fe(r,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${r}: ${n instanceof Error?n.message:String(n)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let o=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:v(v(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:o,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:o,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function F(r,e){let t=A(r,G);ge(t,{recursive:!0});let o=N(r),n=`${o}.tmp-${process.pid}`;he(n,JSON.stringify(e,null,2)+`
3
- `,{encoding:"utf8",mode:384}),ye(n,o)}function Y(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 S=class{detect(e=process.cwd()){let t=h(e),o=_e(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(m=>K(A(o,m))),a=Ae(t,i?o:void 0);if(a){let m=N(a),u=Pe(m);return u.rootPath!==a&&(u.rootPath=a,u.updatedAt=new Date().toISOString(),F(a,u)),Y(u,a)}let d=new Date().toISOString(),p=Ee(o),l={version:1,id:ve(o),name:p,remote:p,rootPath:o,createdAt:d,updatedAt:d,graphVersion:0,memoryVersion:0};return F(o,l),Y(l,o)}};import{homedir as ze}from"node:os";import{join as Je}from"node:path";import{DeleteObjectCommand as we,GetObjectCommand as je,HeadObjectCommand as Ie,ListObjectsV2Command as Oe,PutObjectCommand as xe,S3Client as ke}from"@aws-sdk/client-s3";import{getSignedUrl as Re}from"@aws-sdk/s3-request-presigner";var _=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new ke({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new xe({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await Re(this.client,new je({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 Ie({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new we({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new Oe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of n.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return t}};import{access as z,mkdir as Me,readFile as Ce,readdir as Te,rm as De,stat as J,writeFile as Ke}from"node:fs/promises";import{dirname as Ne,join as Le,relative as q,resolve as Ue}from"node:path";var E=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Ue(this.root,t)}async put(e,t){let o=this.path(e);await Me(Ne(o),{recursive:!0}),await Ke(o,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 z(this.path(e)),!0}catch{return!1}}async delete(e){await De(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await z(t)}catch{return o}let n=async a=>{let d=await Te(a,{withFileTypes:!0});for(let p of d){let l=Le(a,p.name);if(p.isDirectory()){await n(l);continue}let m=await J(l);o.push({key:q(this.root,l),size:m.size,updatedAt:m.mtime.toISOString()})}},i=await J(t);return i.isDirectory()?await n(t):o.push({key:q(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),o}};import{DeleteObjectCommand as Be,GetObjectCommand as $e,HeadObjectCommand as Ve,ListObjectsV2Command as Fe,PutObjectCommand as Ye,S3Client as He}from"@aws-sdk/client-s3";import{getSignedUrl as Ge}from"@aws-sdk/s3-request-presigner";var b=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new He({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 n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Ye({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await Ge(this.client,new $e({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 Ve({Bucket:this.bucket,Key:e})),!0}catch(t){if(typeof t=="object"&&t!==null&&"$metadata"in t&&t.$metadata?.httpStatusCode===404)return!1;throw t}}async delete(e){await this.client.send(new Be({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new Fe({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of n.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return t}};function L(r,e){return console.warn(e),new E(r)}function W(r){let e=r.localRoot??Je(ze(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new b({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):L(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 b({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):L(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 _({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):L(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new E(e)}var P=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"memories","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return[];let o=JSON.parse(t);if(!Array.isArray(o))throw new Error("Invalid memory snapshot");return o}async save(e,t){let o=JSON.stringify(t,null,2);await this.storage.put(this.key(e),o,"application/json")}};var w=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return null;let o=JSON.parse(t);if(o.version!==1||o.projectId!==e||!Array.isArray(o.records))throw new Error("Invalid vector snapshot");return o}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var j=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var I=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","chunks","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var O=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};function qe(r){return new Promise(e=>setTimeout(e,r))}async function Z(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,n=e.maxDelayMs??2e3,i;for(let a=1;a<=t;a++)try{return await r()}catch(d){if(i=d,a>=t)break;let p=Math.min(n,o*2**(a-1)),l=Math.floor(Math.random()*Math.max(1,p*.2));await qe(p+l)}throw i}var We=new Set(["put","get","getText","delete","list"]);function Q(r,e={}){return new Proxy(r,{get(t,o){let n=Reflect.get(t,o,t);return typeof n!="function"?n:We.has(o)?(...i)=>Z(()=>Promise.resolve(n.apply(t,i)),e):n.bind(t)}})}var X=[{id:"openai-compatible",label:"OpenAI-compatible",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"alibaba",label:"Alibaba / DashScope",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"openrouter",label:"OpenRouter",defaultBaseUrl:"https://openrouter.ai/api/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"groq",label:"Groq",defaultBaseUrl:"https://api.groq.com/openai/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"deepseek",label:"DeepSeek",defaultBaseUrl:"https://api.deepseek.com",defaultModel:"deepseek-v4-flash",requiresApiKey:!0,transport:"openai-compatible"},{id:"nvidia",label:"NVIDIA NIM",defaultBaseUrl:"https://integrate.api.nvidia.com/v1",defaultModel:"deepseek-ai/deepseek-v4-pro",requiresApiKey:!0,transport:"openai-compatible"},{id:"gemini",label:"Gemini",defaultBaseUrl:"https://generativelanguage.googleapis.com/v1beta",requiresApiKey:!0,transport:"gemini"},{id:"huggingface",label:"Hugging Face",defaultBaseUrl:"https://router.huggingface.co/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"ollama",label:"Ollama / Local",defaultBaseUrl:"http://127.0.0.1:11434/v1",requiresApiKey:!1,transport:"openai-compatible"},{id:"custom",label:"Custom endpoint",requiresApiKey:!1,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"cloudflare",label:"Cloudflare Workers AI",requiresApiKey:!0,requiresAccountId:!0,transport:"cloudflare"}];function x(r){let e=X.find(t=>t.id===r);if(!e)throw new Error(`Unsupported AI provider: ${r}`);return e}function k(r){return X.some(e=>e.id===r)}function s(r){return process.env[r]?.trim()||void 0}function c(...r){return r.find(e=>!!e?.trim())}function ee(){if(s("GROQ_API_KEY"))return"groq";if(s("DEEPSEEK_API_KEY"))return"deepseek";if(s("NVIDIA_API_KEY")||s("NVIDIA_NIM_API_KEY"))return"nvidia";if(s("OPENROUTER_API_KEY"))return"openrouter";if(s("ALIBABA_API_KEY")||s("DASHSCOPE_API_KEY"))return"alibaba";if(s("GEMINI_API_KEY")||s("GOOGLE_API_KEY"))return"gemini";if(s("CLOUDFLARE_API_TOKEN")&&s("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(s("HF_TOKEN"))return"huggingface";if(s("OLLAMA_MODEL")||s("OLLAMA_BASE_URL"))return"ollama"}function Ze(){let r=s("TOOLNET_LLM_PROVIDER");return r&&k(r)?r:ee()??"openai-compatible"}function U(r){let e=x(r);switch(r){case"alibaba":return{provider:r,apiKey:c(s("ALIBABA_API_KEY"),s("DASHSCOPE_API_KEY")),baseUrl:c(s("ALIBABA_BASE_URL"),s("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:c(s("ALIBABA_MODEL"),s("DASHSCOPE_MODEL"))};case"openrouter":return{provider:r,apiKey:s("OPENROUTER_API_KEY"),baseUrl:c(s("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:s("OPENROUTER_MODEL")};case"groq":return{provider:r,apiKey:s("GROQ_API_KEY"),baseUrl:c(s("GROQ_BASE_URL"),e.defaultBaseUrl),model:s("GROQ_MODEL")};case"deepseek":return{provider:r,apiKey:s("DEEPSEEK_API_KEY"),baseUrl:c(s("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:c(s("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:r,apiKey:c(s("NVIDIA_API_KEY"),s("NVIDIA_NIM_API_KEY")),baseUrl:c(s("NVIDIA_BASE_URL"),s("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:c(s("NVIDIA_MODEL"),s("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:r,apiKey:c(s("GEMINI_API_KEY"),s("GOOGLE_API_KEY")),baseUrl:c(s("GEMINI_BASE_URL"),e.defaultBaseUrl),model:s("GEMINI_MODEL")};case"huggingface":return{provider:r,apiKey:s("HF_TOKEN"),baseUrl:c(s("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:c(s("HF_LLM_MODEL"),s("HF_MODEL"))};case"ollama":return{provider:r,apiKey:s("OLLAMA_API_KEY"),baseUrl:c(s("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:s("OLLAMA_MODEL")};case"cloudflare":return{provider:r,accountId:s("CLOUDFLARE_ACCOUNT_ID"),apiKey:s("CLOUDFLARE_API_TOKEN"),baseUrl:s("CLOUDFLARE_AI_BASE_URL"),model:s("CLOUDFLARE_MODEL")};case"custom":return{provider:r,apiKey:s("CUSTOM_AI_API_KEY"),baseUrl:s("CUSTOM_AI_BASE_URL"),model:s("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:c(s("OPENAI_API_KEY"),s("MODEL_API_KEY")),baseUrl:c(s("OPENAI_BASE_URL"),s("MODEL_BASE_URL")),model:c(s("OPENAI_MODEL"),s("MODEL_NAME"))}}}function Qe(){let r=s("TOOLNET_LLM_PROVIDER"),e=r&&k(r)?r:Ze(),t=x(e),o=U(e);return{provider:e,apiKey:c(s("TOOLNET_LLM_API_KEY"),o.apiKey),baseUrl:c(s("TOOLNET_LLM_BASE_URL"),o.baseUrl,t.defaultBaseUrl),model:c(s("TOOLNET_LLM_MODEL"),o.model,t.defaultModel),accountId:c(s("TOOLNET_LLM_ACCOUNT_ID"),o.accountId)}}function Xe(){let r=s("TOOLNET_EMBEDDING_PROVIDER");return r==="local"?"local":r&&k(r)?r:s("HF_TOKEN")||s("HF_EMBEDDING_MODEL")?"huggingface":"local"}function et(){let r=Xe();if(r==="local")return{provider:"local",model:c(s("TOOLNET_EMBEDDING_MODEL"),s("LOCAL_EMBEDDING_MODEL"))};let e=x(r),t,o,n,i;switch(r){case"huggingface":t=s("HF_TOKEN"),o=s("HF_INFERENCE_BASE_URL"),n=s("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=s("OPENAI_API_KEY"),o=s("OPENAI_BASE_URL"),n=s("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=s("CLOUDFLARE_API_TOKEN"),o=s("CLOUDFLARE_AI_BASE_URL"),n=s("CLOUDFLARE_EMBEDDING_MODEL"),i=s("CLOUDFLARE_ACCOUNT_ID");break;default:t=U(r).apiKey,o=U(r).baseUrl,n=s(`${r.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}return{provider:r,apiKey:c(s("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:c(s("TOOLNET_EMBEDDING_BASE_URL"),o,e.defaultBaseUrl),model:c(s("TOOLNET_EMBEDDING_MODEL"),n),accountId:c(s("TOOLNET_EMBEDDING_ACCOUNT_ID"),i)}}function te(){let r=Qe(),e=et();return{llm:r,embedding:e,legacy:{llm:!s("TOOLNET_LLM_PROVIDER")&&!!ee(),embedding:!s("TOOLNET_EMBEDDING_PROVIDER")&&!!(s("HF_TOKEN")||s("HF_EMBEDDING_MODEL"))}}}var R=class{constructor(e){this.options=e}options;name="huggingface";dimensions=384;async embed(e){let[t]=await this.embedMany([e]);return t}async embedMany(e){if(e.length===0)return[];let t=`https://router.huggingface.co/hf-inference/models/${this.options.model}/pipeline/feature-extraction`,o=await fetch(t,{method:"POST",headers:{Authorization:`Bearer ${this.options.token}`,"Content-Type":"application/json"},body:JSON.stringify({inputs:e,options:{wait_for_model:!0}})});if(!o.ok)throw new Error(`HF embedding failed: ${o.status} ${await o.text()}`);let n=await o.json();if(!Array.isArray(n))throw new Error("HF embedding returned invalid response");return n.map(i=>tt(i))}};function tt(r){if(!Array.isArray(r))throw new Error("Invalid embedding");if(r.length>0&&typeof r[0]=="number")return r;if(r.length>0&&Array.isArray(r[0])){let e=r;if(e.length===0)return[];let t=e[0].length,o=new Array(t).fill(0);for(let n of e)for(let i=0;i<t;i++)o[i]+=n[i]??0;for(let n=0;n<t;n++)o[n]/=e.length;return o}throw new Error("Unsupported embedding shape")}import{createHash as rt}from"node:crypto";var M=class{name="hash-fallback";dimensions=128;async embed(e){let t=new Array(this.dimensions).fill(0),o=e.toLowerCase().split(/\s+/).filter(Boolean);for(let n of o){let a=rt("sha256").update(n).digest().readUInt32BE(0)%this.dimensions;t[a]+=1}return ot(t)}async embedMany(e){return Promise.all(e.map(t=>this.embed(t)))}};function ot(r){let e=Math.sqrt(r.reduce((t,o)=>t+o*o,0));return e===0?r:r.map(t=>t/e)}var C=class{constructor(e){this.options=e;this.dimensions=e.dimensions}options;name="openai-compatible";dimensions;async embed(e){let[t]=await this.embedMany([e]);return t}async embedMany(e){if(e.length===0)return[];let t=this.options.baseUrl.replace(/\/+$/,""),o=await fetch(`${t}/embeddings`,{method:"POST",headers:{"content-type":"application/json",...this.options.apiKey?{authorization:`Bearer ${this.options.apiKey}`}:{}},body:JSON.stringify({model:this.options.model,input:e})});if(!o.ok)throw new Error(`Embedding failed: ${o.status} ${await o.text()}`);let i=(await o.json()).data?.sort((a,d)=>(a.index??0)-(d.index??0)).map(a=>a.embedding);if(!i||i.length!==e.length||i.some(a=>!Array.isArray(a)))throw new Error("Embedding provider returned invalid response");return i}};var B=class{constructor(e,t=new M){this.primary=e;this.fallback=t}primary;fallback;name="resilient";async embed(e){if(this.primary)try{return await this.primary.embed(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embed(e)}async embedMany(e){if(this.primary)try{return await this.primary.embedMany(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embedMany(e)}};function nt(){let r=te().embedding;return r.provider==="local"?null:r.provider==="huggingface"?!r.apiKey||!r.model?null:new R({token:r.apiKey,model:r.model}):r.baseUrl&&r.model?new C({apiKey:r.apiKey,baseUrl:r.baseUrl,model:r.model}):null}function re(){return new B(nt())}var st=["memories/current.json","vectors/current.json","graph/current.json","graph/manifest.json","graph/resolution/current.json","code/chunks/current.json","code/vectors/current.json","code/architecture/current.json","code/architecture/entry-points.json","code/architecture/hotspots.json","code/architecture/layers.json","code/architecture/clusters.json","code/analysis/current.json","code/analysis/dead-code.json","code/analysis/dependencies.json","code/visualization/graph.json"],T=class{constructor(e){this.storage=e}storage;projectPrefix(e){return`projects/${e}`}snapshotPrefix(e,t){return[this.projectPrefix(e),"snapshots",t].join("/")}async create(e,t="automatic",o){let n=new Date().toISOString(),i=n.replace(/[:.]/g,"-"),a=this.projectPrefix(e),d=this.snapshotPrefix(e,i),p=[];for(let m of st){let u=`${a}/${m}`,g=await this.storage.get(u);g&&(await this.storage.put(`${d}/${m}`,g,"application/json"),p.push(m))}if(p.length===0)return null;let l={version:1,id:i,projectId:e,createdAt:n,reason:t,objects:p,metadata:o};return await this.storage.put(`${d}/snapshot.json`,JSON.stringify(l,null,2),"application/json"),l}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),n=(await this.storage.list(t)).filter(a=>a.key.endsWith("/snapshot.json")),i=[];for(let a of n){let d=await this.storage.getText(a.key);if(d)try{i.push(JSON.parse(d))}catch{}}return i.sort((a,d)=>d.createdAt.localeCompare(a.createdAt))}async restore(e,t){let o=this.snapshotPrefix(e,t),n=await this.storage.getText(`${o}/snapshot.json`);if(!n)throw new Error(`Snapshot not found: ${t}`);let i=JSON.parse(n);if(i.projectId!==e)throw new Error("Snapshot project mismatch");let a=this.projectPrefix(e),d=[];for(let p of i.objects){let l=await this.storage.get(`${o}/${p}`);l&&(await this.storage.put(`${a}/${p}`,l,"application/json"),d.push(p))}return{restored:d}}async remove(e,t){let o=this.snapshotPrefix(e,t),n=await this.storage.list(o);for(let i of n)await this.storage.delete(i.key);return n.length}async prune(e,t=10){let n=(await this.list(e)).slice(t),i=0;for(let a of n)await this.remove(e,a.id),i++;return i}};function $(r,e){for(let t of r)process.env[t]||e.push(`Missing ${t}`)}function oe(){let r=[],e=[],t=process.env.MEMORY_STORAGE_PROVIDER??"local";return t==="r2"?$(["R2_ACCOUNT_ID","R2_BUCKET","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY"],r):t==="s3"?$(["S3_BUCKET","S3_ACCESS_KEY_ID","S3_SECRET_ACCESS_KEY"],r):t==="huggingface"?$(["HF_NAMESPACE","HF_BUCKET","HF_S3_ACCESS_KEY_ID","HF_S3_SECRET_ACCESS_KEY"],r):t!=="local"&&r.push(`Unsupported MEMORY_STORAGE_PROVIDER: ${t}`),process.env.HF_TOKEN||e.push("HF_TOKEN missing: semantic embedding will use fallback"),process.env.HF_EMBEDDING_MODEL||e.push("HF_EMBEDDING_MODEL not set; default model will be used"),{ok:r.length===0,errors:r,warnings:e}}import{randomUUID as it}from"node:crypto";var D=class{constructor(e,t){this.storage=e;this.embeddings=t}storage;embeddings;async run(){let e=`_health/production-${it()}.txt`,t=`toolnet-memory:${Date.now()}`,o=!1;try{await this.storage.put(e,t,"text/plain"),o=await this.storage.getText(e)===t}finally{try{await this.storage.delete(e)}catch{}}let n=null;if(this.embeddings)try{let i=await this.embeddings.embed("ToolNet Memory production health check");n={ok:i.length>0,dimensions:i.length,mode:i.length===384?"huggingface":"fallback-or-custom"}}catch{n={ok:!1,dimensions:0,mode:"failed"}}return{ok:o&&(n===null||n.ok),storage:{ok:o,provider:this.storage.name},embedding:n}}};function se(){return process.argv.includes("--json")}function at(r){if(console.log(""),console.log("ToolNet Memory Doctor"),console.log("====================="),console.log(""),r.project&&(console.log(`Project: ${r.project}`),console.log("")),r.storage)if(r.storage.ok){let n=typeof r.storage.provider=="string"?` (${r.storage.provider})`:"";console.log(`\u2713 Storage${n}`)}else console.log("\u2717 Storage");if(r.embedding)if(r.embedding.ok){let n=[];typeof r.embedding.mode=="string"&&n.push(r.embedding.mode),typeof r.embedding.dimensions=="number"&&n.push(`${r.embedding.dimensions} dimensions`),console.log(`\u2713 Embedding${n.length?` (${n.join(", ")})`:""}`)}else console.log("\u2717 Embedding");(r.memory!==void 0||r.graphSymbols!==void 0||r.codeChunks!==void 0)&&(console.log(""),console.log("Project data:"),r.memory!==void 0&&console.log(` Memories ${r.memory}`),r.graphSymbols!==void 0&&console.log(` Graph symbols ${r.graphSymbols}`),r.graphEdges!==void 0&&console.log(` Graph edges ${r.graphEdges}`),r.memoryVectors!==void 0&&console.log(` Memory vectors ${r.memoryVectors}`),r.codeChunks!==void 0&&console.log(` Code chunks ${r.codeChunks}`),r.codeVectors!==void 0&&console.log(` Code vectors ${r.codeVectors}`),r.snapshots!==void 0&&console.log(` Snapshots ${r.snapshots}`));let e=r.config?.errors??[];if(e.length>0){console.log(""),console.log("Configuration required:");for(let n of e)console.log(` - ${n}`)}let t=[...r.config?.warnings??[],...r.warnings??[]],o=[...new Set(t)];if(o.length>0){console.log(""),console.log("Warnings:");for(let n of o)console.log(` - ${n}`)}console.log(""),r.ok?console.log("\u2713 ToolNet Memory is ready"):(console.log("\u2717 ToolNet Memory requires attention"),e.length>0&&(console.log(""),console.log("Run:"),console.log(" toolnet-memory setup"))),console.log("")}function ne(r){se()?console.log(JSON.stringify(r,null,2)):at(r)}async function ct(){let r=oe();if(!r.ok){let ie={ok:!1,config:r,warnings:r.warnings};ne(ie),process.exitCode=1;return}let e=V(),t=new S().detect(),o=Q(W({provider:e.storage.provider,r2:e.storage.r2,s3:e.storage.s3,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),n=re(),i=await new D(o,n).run(),a=await new P(o).load(t.id),d=await new j(o).load(t.id),p=await new w(o).load(t.id),l=await new I(o).load(t.id),m=await new O(o).load(t.id),u=await new T(o).list(t.id),g={ok:i.ok,project:t.name,storage:i.storage,embedding:i.embedding,memory:a.length,graphSymbols:d?.symbols.length??0,graphEdges:d?.edges.length??0,memoryVectors:p?.records.length??0,codeChunks:l?.chunks.length??0,codeVectors:m?.records.length??0,snapshots:u.length,warnings:r.warnings};ne(g),process.exitCode=g.ok?0:1}ct().catch(r=>{let e=r instanceof Error?r.message:String(r);se()?console.log(JSON.stringify({ok:!1,error:e},null,2)):(console.error(""),console.error("ToolNet Memory Doctor"),console.error("====================="),console.error(""),console.error(`\u2717 ${e}`),console.error("")),process.exitCode=1});
1
+ import"dotenv/config";import{existsSync as ve,readFileSync as Ae}from"node:fs";import{homedir as Se}from"node:os";import{join as we}from"node:path";function _e(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
2
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Pe(){let r=process.env.TOOLNET_GLOBAL_ENV??we(Se(),".config","toolnet-memory",".env");if(!ve(r))return;let e=Ae(r,"utf8");for(let t of e.split(/\r?\n/)){let o=t.trim();if(!o||o.startsWith("#"))continue;o.startsWith("export ")&&(o=o.slice(7));let n=o.indexOf("=");if(n<=0)continue;let i=o.slice(0,n).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=_e(o.slice(n+1)))}}Pe();function b(r,e){return r===void 0?e:["1","true","yes","on"].includes(r.toLowerCase())}function E(r,e){if(!r)return e;let t=Number(r);return Number.isFinite(t)?t:e}function X(){return{memory:{autoCapture:b(process.env.MEMORY_AUTO_CAPTURE,!0),autoRetrieve:b(process.env.MEMORY_AUTO_RETRIEVE,!0),autoSummarize:b(process.env.MEMORY_AUTO_SUMMARIZE,!0),autoSync:b(process.env.MEMORY_AUTO_SYNC,!0)},retrieval:{maxCandidates:E(process.env.MEMORY_MAX_CANDIDATES,50),rerankTop:E(process.env.MEMORY_RERANK_TOP,10),finalContext:E(process.env.MEMORY_FINAL_CONTEXT,5),tokenBudget:E(process.env.MEMORY_TOKEN_BUDGET,2e3)},storage:{provider:process.env.MEMORY_STORAGE_PROVIDER??"huggingface",r2:{accountId:process.env.R2_ACCOUNT_ID,bucket:process.env.R2_BUCKET,accessKeyId:process.env.R2_ACCESS_KEY_ID,secretAccessKey:process.env.R2_SECRET_ACCESS_KEY},s3:{endpoint:process.env.S3_ENDPOINT,region:process.env.S3_REGION,bucket:process.env.S3_BUCKET,accessKeyId:process.env.S3_ACCESS_KEY_ID,secretAccessKey:process.env.S3_SECRET_ACCESS_KEY,forcePathStyle:b(process.env.S3_FORCE_PATH_STYLE,!1)},huggingface:{namespace:process.env.HF_NAMESPACE,bucket:process.env.HF_BUCKET,accessKeyId:process.env.HF_S3_ACCESS_KEY_ID,secretAccessKey:process.env.HF_S3_SECRET_ACCESS_KEY},localRoot:process.env.MEMORY_LOCAL_STORAGE_PATH},cache:{maxMb:E(process.env.MEMORY_LOCAL_CACHE_MB,200)}}}import{createHash as Oe}from"node:crypto";import{existsSync as Y,mkdirSync as Ie,readFileSync as ke,renameSync as je,writeFileSync as xe}from"node:fs";import{basename as Re,dirname as P,join as I,parse as re,resolve as v}from"node:path";var oe=".toolnet",Ce="project.json";function Me(r){return Oe("sha256").update(r).digest("hex").slice(0,16)}function z(r){return I(r,oe,Ce)}function Te(r){return Y(z(r))}function Le(r,e){let t=v(r),o=re(t).root;for(;;){if(Te(t))return t;if(t===o||e&&t===v(e))break;let n=P(t);if(n===t)break;t=n}return null}function De(r){let e=v(r),t=re(e).root,o=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(o.some(i=>Y(I(e,i))))return e;if(e===t)break;let n=P(e);if(n===e)break;e=n}return v(r)}function Ke(r){let e;try{e=JSON.parse(ke(r,"utf8"))}catch(n){throw new Error(`Invalid ToolNet project manifest: ${r}: ${n instanceof Error?n.message:String(n)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let o=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:P(P(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 ee(r,e){let t=I(r,oe);Ie(t,{recursive:!0});let o=z(r),n=`${o}.tmp-${process.pid}`;xe(n,JSON.stringify(e,null,2)+`
3
+ `,{encoding:"utf8",mode:384}),je(n,o)}function te(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var O=class{detect(e=process.cwd()){let t=v(e),o=De(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>Y(I(o,p))),a=Le(t,i?o:void 0);if(a){let p=z(a),u=Ke(p);return u.rootPath!==a&&(u.rootPath=a,u.updatedAt=new Date().toISOString(),ee(a,u)),te(u,a)}let c=new Date().toISOString(),d=Re(o),m={version:1,id:Me(o),name:d,remote:d,rootPath:o,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return ee(o,m),te(m,o)}};import{homedir as it}from"node:os";import{join as at}from"node:path";import{DeleteObjectCommand as Ne,GetObjectCommand as Ue,HeadObjectCommand as $e,ListObjectsV2Command as Be,PutObjectCommand as Fe,S3Client as Ge}from"@aws-sdk/client-s3";import{getSignedUrl as Ve}from"@aws-sdk/s3-request-presigner";var k=class{name="huggingface";client;bucket;constructor(e){this.bucket=e.bucket,this.client=new Ge({region:"us-east-1",endpoint:`https://s3.hf.co/${e.namespace}`,forcePathStyle:!0,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new Fe({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await Ve(this.client,new Ue({Bucket:this.bucket,Key:e}),{expiresIn:60}),o=await fetch(t,{redirect:"follow"});if(o.status===404)return null;if(!o.ok)throw new Error(`HF download failed: ${o.status} ${o.statusText}`);return new Uint8Array(await o.arrayBuffer())}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await this.client.send(new $e({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 Ne({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new Be({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of n.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return t}};import{access as ne,mkdir as He,readFile as Ye,readdir as ze,rm as Je,stat as se,writeFile as qe}from"node:fs/promises";import{dirname as We,join as Ze,relative as ie,resolve as Qe}from"node:path";var A=class{constructor(e){this.root=e}root;name="local";path(e){let t=e.replace(/^\/+/,"");return Qe(this.root,t)}async put(e,t){let o=this.path(e);await He(We(o),{recursive:!0}),await qe(o,t)}async get(e){try{return await Ye(this.path(e))}catch(t){if(typeof t=="object"&&t!==null&&"code"in t&&t.code==="ENOENT")return null;throw t}}async getText(e){let t=await this.get(e);return t?Buffer.from(t).toString("utf8"):null}async exists(e){try{return await ne(this.path(e)),!0}catch{return!1}}async delete(e){await Je(this.path(e),{force:!0})}async list(e=""){let t=this.path(e),o=[];try{await ne(t)}catch{return o}let n=async a=>{let c=await ze(a,{withFileTypes:!0});for(let d of c){let m=Ze(a,d.name);if(d.isDirectory()){await n(m);continue}let p=await se(m);o.push({key:ie(this.root,m),size:p.size,updatedAt:p.mtime.toISOString()})}},i=await se(t);return i.isDirectory()?await n(t):o.push({key:ie(this.root,t),size:i.size,updatedAt:i.mtime.toISOString()}),o}};import{DeleteObjectCommand as Xe,GetObjectCommand as et,HeadObjectCommand as tt,ListObjectsV2Command as rt,PutObjectCommand as ot,S3Client as nt}from"@aws-sdk/client-s3";import{getSignedUrl as st}from"@aws-sdk/s3-request-presigner";var S=class{name;client;bucket;constructor(e){this.name=e.name??"s3",this.bucket=e.bucket,this.client=new nt({region:e.region??"us-east-1",endpoint:e.endpoint||void 0,forcePathStyle:e.forcePathStyle??!1,requestChecksumCalculation:"WHEN_REQUIRED",responseChecksumValidation:"WHEN_REQUIRED",credentials:{accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey}})}async put(e,t,o="application/octet-stream"){let n=typeof t=="string"?Buffer.from(t,"utf8"):t;await this.client.send(new ot({Bucket:this.bucket,Key:e,Body:n,ContentType:o}))}async get(e){let t=await st(this.client,new et({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 tt({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 Xe({Bucket:this.bucket,Key:e}))}async list(e=""){let t=[],o;do{let n=await this.client.send(new rt({Bucket:this.bucket,Prefix:e||void 0,ContinuationToken:o}));for(let i of n.Contents??[])i.Key&&t.push({key:i.Key,size:i.Size,updatedAt:i.LastModified?.toISOString()});o=n.IsTruncated?n.NextContinuationToken:void 0}while(o);return t}};function J(r,e){return console.warn(e),new A(r)}function ae(r){let e=r.localRoot??at(it(),".toolnet-memory","storage");if(r.provider==="r2"){let t=r.r2;return t?.accountId&&t.bucket&&t.accessKeyId&&t.secretAccessKey?new S({name:"r2",endpoint:`https://${t.accountId}.r2.cloudflarestorage.com`,region:"auto",bucket:t.bucket,forcePathStyle:!0,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):J(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 S({name:"s3",endpoint:t.endpoint,region:t.region??"us-east-1",bucket:t.bucket,forcePathStyle:t.forcePathStyle??!1,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):J(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 k({namespace:t.namespace,bucket:t.bucket,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey}):J(e,"[storage] Hugging Face credentials missing. Using local fallback.")}return new A(e)}var j=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"memories","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return[];let o=JSON.parse(t);if(!Array.isArray(o))throw new Error("Invalid memory snapshot");return o}async save(e,t){let o=JSON.stringify(t,null,2);await this.storage.put(this.key(e),o,"application/json")}};var x=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));if(!t)return null;let o=JSON.parse(t);if(o.version!==1||o.projectId!==e||!Array.isArray(o.records))throw new Error("Invalid vector snapshot");return o}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var R=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"graph","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var C=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","chunks","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};var M=class{constructor(e){this.storage=e}storage;key(e){return["projects",e,"code","vectors","current.json"].join("/")}async load(e){let t=await this.storage.getText(this.key(e));return t?JSON.parse(t):null}async save(e){await this.storage.put(this.key(e.projectId),JSON.stringify(e),"application/json")}};function ct(r){return new Promise(e=>setTimeout(e,r))}async function ce(r,e={}){let t=Math.max(1,e.attempts??3),o=e.baseDelayMs??150,n=e.maxDelayMs??2e3,i;for(let a=1;a<=t;a++)try{return await r()}catch(c){if(i=c,a>=t)break;let d=Math.min(n,o*2**(a-1)),m=Math.floor(Math.random()*Math.max(1,d*.2));await ct(d+m)}throw i}var dt=new Set(["put","get","getText","delete","list"]);function de(r,e={}){return new Proxy(r,{get(t,o){let n=Reflect.get(t,o,t);return typeof n!="function"?n:dt.has(o)?(...i)=>ce(()=>Promise.resolve(n.apply(t,i)),e):n.bind(t)}})}var le=[{id:"openai-compatible",label:"OpenAI-compatible",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"alibaba",label:"Alibaba / DashScope",requiresApiKey:!0,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"openrouter",label:"OpenRouter",defaultBaseUrl:"https://openrouter.ai/api/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"groq",label:"Groq",defaultBaseUrl:"https://api.groq.com/openai/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"deepseek",label:"DeepSeek",defaultBaseUrl:"https://api.deepseek.com",defaultModel:"deepseek-v4-flash",requiresApiKey:!0,transport:"openai-compatible"},{id:"nvidia",label:"NVIDIA NIM",defaultBaseUrl:"https://integrate.api.nvidia.com/v1",defaultModel:"deepseek-ai/deepseek-v4-pro",requiresApiKey:!0,transport:"openai-compatible"},{id:"gemini",label:"Gemini",defaultBaseUrl:"https://generativelanguage.googleapis.com/v1beta",requiresApiKey:!0,transport:"gemini"},{id:"huggingface",label:"Hugging Face",defaultBaseUrl:"https://router.huggingface.co/v1",requiresApiKey:!0,transport:"openai-compatible"},{id:"ollama",label:"Ollama / Local",defaultBaseUrl:"http://127.0.0.1:11434/v1",requiresApiKey:!1,transport:"openai-compatible"},{id:"custom",label:"Custom endpoint",requiresApiKey:!1,requiresBaseUrl:!0,transport:"openai-compatible"},{id:"cloudflare",label:"Cloudflare Workers AI",requiresApiKey:!0,requiresAccountId:!0,transport:"cloudflare"}];function f(r){let e=le.find(t=>t.id===r);if(!e)throw new Error(`Unsupported AI provider: ${r}`);return e}function T(r){return le.some(e=>e.id===r)}function s(r){return process.env[r]?.trim()||void 0}function l(...r){return r.find(e=>!!e?.trim())}function pe(){if(s("GROQ_API_KEY"))return"groq";if(s("DEEPSEEK_API_KEY"))return"deepseek";if(s("NVIDIA_API_KEY")||s("NVIDIA_NIM_API_KEY"))return"nvidia";if(s("OPENROUTER_API_KEY"))return"openrouter";if(s("ALIBABA_API_KEY")||s("DASHSCOPE_API_KEY"))return"alibaba";if(s("GEMINI_API_KEY")||s("GOOGLE_API_KEY"))return"gemini";if(s("CLOUDFLARE_API_TOKEN")&&s("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(s("HF_TOKEN"))return"huggingface";if(s("OLLAMA_MODEL")||s("OLLAMA_BASE_URL"))return"ollama"}function me(){let r=s("TOOLNET_LLM_PROVIDER");return r&&T(r)?r:pe()??"openai-compatible"}function L(r){let e=f(r);switch(r){case"alibaba":return{provider:r,apiKey:l(s("ALIBABA_API_KEY"),s("DASHSCOPE_API_KEY")),baseUrl:l(s("ALIBABA_BASE_URL"),s("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:l(s("ALIBABA_MODEL"),s("DASHSCOPE_MODEL"))};case"openrouter":return{provider:r,apiKey:s("OPENROUTER_API_KEY"),baseUrl:l(s("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:s("OPENROUTER_MODEL")};case"groq":return{provider:r,apiKey:s("GROQ_API_KEY"),baseUrl:l(s("GROQ_BASE_URL"),e.defaultBaseUrl),model:s("GROQ_MODEL")};case"deepseek":return{provider:r,apiKey:s("DEEPSEEK_API_KEY"),baseUrl:l(s("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:l(s("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:r,apiKey:l(s("NVIDIA_API_KEY"),s("NVIDIA_NIM_API_KEY")),baseUrl:l(s("NVIDIA_BASE_URL"),s("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:l(s("NVIDIA_MODEL"),s("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:r,apiKey:l(s("GEMINI_API_KEY"),s("GOOGLE_API_KEY")),baseUrl:l(s("GEMINI_BASE_URL"),e.defaultBaseUrl),model:s("GEMINI_MODEL")};case"huggingface":return{provider:r,apiKey:s("HF_TOKEN"),baseUrl:l(s("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:l(s("HF_LLM_MODEL"),s("HF_MODEL"))};case"ollama":return{provider:r,apiKey:s("OLLAMA_API_KEY"),baseUrl:l(s("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:s("OLLAMA_MODEL")};case"cloudflare":return{provider:r,accountId:s("CLOUDFLARE_ACCOUNT_ID"),apiKey:s("CLOUDFLARE_API_TOKEN"),baseUrl:s("CLOUDFLARE_AI_BASE_URL"),model:s("CLOUDFLARE_MODEL")};case"custom":return{provider:r,apiKey:s("CUSTOM_AI_API_KEY"),baseUrl:s("CUSTOM_AI_BASE_URL"),model:s("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:l(s("OPENAI_API_KEY"),s("MODEL_API_KEY")),baseUrl:l(s("OPENAI_BASE_URL"),s("MODEL_BASE_URL")),model:l(s("OPENAI_MODEL"),s("MODEL_NAME"))}}}function lt(){let r=s("TOOLNET_LLM_PROVIDER"),e=r&&T(r)?r:me(),t=f(e),o=L(e);return{provider:e,apiKey:l(s("TOOLNET_LLM_API_KEY"),o.apiKey),baseUrl:l(s("TOOLNET_LLM_BASE_URL"),o.baseUrl,t.defaultBaseUrl),model:l(s("TOOLNET_LLM_MODEL"),o.model,t.defaultModel),accountId:l(s("TOOLNET_LLM_ACCOUNT_ID"),o.accountId)}}function pt(){let r=s("TOOLNET_EMBEDDING_PROVIDER");return r==="local"?"local":r&&T(r)?r:s("HF_TOKEN")||s("HF_EMBEDDING_MODEL")?"huggingface":"local"}function mt(){let r=pt();if(r==="local")return{provider:"local",model:l(s("TOOLNET_EMBEDDING_MODEL"),s("LOCAL_EMBEDDING_MODEL"))};let e=f(r),t,o,n,i;switch(r){case"huggingface":t=s("HF_TOKEN"),o=s("HF_INFERENCE_BASE_URL"),n=s("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=s("OPENAI_API_KEY"),o=s("OPENAI_BASE_URL"),n=s("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=s("CLOUDFLARE_API_TOKEN"),o=s("CLOUDFLARE_AI_BASE_URL"),n=s("CLOUDFLARE_EMBEDDING_MODEL"),i=s("CLOUDFLARE_ACCOUNT_ID");break;default:t=L(r).apiKey,o=L(r).baseUrl,n=s(`${r.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let a=l(s("TOOLNET_EMBEDDING_ACCOUNT_ID"),i),c=l(s("TOOLNET_EMBEDDING_BASE_URL"),o,e.defaultBaseUrl),d=r==="cloudflare"&&!c&&a?`https://api.cloudflare.com/client/v4/accounts/${a}/ai/v1`:c;return{provider:r,apiKey:l(s("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:d,model:l(s("TOOLNET_EMBEDDING_MODEL"),n),accountId:a}}function w(){let r=lt(),e=mt();return{llm:r,embedding:e,legacy:{llm:!s("TOOLNET_LLM_PROVIDER")&&!!pe(),embedding:!s("TOOLNET_EMBEDDING_PROVIDER")&&!!(s("HF_TOKEN")||s("HF_EMBEDDING_MODEL"))}}}function ue(r=me()){let e=w().llm;if(r===e.provider)return{id:r,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId};let t=L(r);return{id:r,apiKey:t.apiKey,baseUrl:t.baseUrl,model:t.model,accountId:t.accountId}}var D=class{constructor(e){this.options=e}options;name="gemini";async embed(e){let t=this.options.model.replace(/^models\//,""),n=`${this.options.baseUrl?.replace(/\/+$/,"")||"https://generativelanguage.googleapis.com/v1beta"}/models/${encodeURIComponent(t)}:embedContent?key=${encodeURIComponent(this.options.apiKey)}`,i=await fetch(n,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({model:`models/${t}`,content:{parts:[{text:e}]}})});if(!i.ok)throw new Error(`Gemini embedding failed: ${i.status} ${await i.text()}`);let c=(await i.json()).embedding?.values;if(!Array.isArray(c)||c.length===0)throw new Error("Gemini embedding returned invalid response");return c}async embedMany(e){let t=[];for(let o of e)t.push(await this.embed(o));return t}};import{createHash as ut}from"node:crypto";var K=class{name="hash-fallback";dimensions=128;async embed(e){let t=new Array(this.dimensions).fill(0),o=e.toLowerCase().split(/\s+/).filter(Boolean);for(let n of o){let a=ut("sha256").update(n).digest().readUInt32BE(0)%this.dimensions;t[a]+=1}return gt(t)}async embedMany(e){return Promise.all(e.map(t=>this.embed(t)))}};function gt(r){let e=Math.sqrt(r.reduce((t,o)=>t+o*o,0));return e===0?r:r.map(t=>t/e)}var N=class{constructor(e){this.options=e;this.dimensions=e.dimensions}options;name="openai-compatible";dimensions;async embed(e){let[t]=await this.embedMany([e]);return t}async embedMany(e){if(e.length===0)return[];let t=this.options.baseUrl.replace(/\/+$/,""),o=await fetch(`${t}/embeddings`,{method:"POST",headers:{"content-type":"application/json",...this.options.apiKey?{authorization:`Bearer ${this.options.apiKey}`}:{}},body:JSON.stringify({model:this.options.model,input:e})});if(!o.ok)throw new Error(`Embedding failed: ${o.status} ${await o.text()}`);let i=(await o.json()).data?.sort((a,c)=>(a.index??0)-(c.index??0)).map(a=>a.embedding);if(!i||i.length!==e.length||i.some(a=>!Array.isArray(a)))throw new Error("Embedding provider returned invalid response");return i}};var U=class{constructor(e){this.options=e}options;name="huggingface";dimensions=384;async embed(e){let[t]=await this.embedMany([e]);return t}async embedMany(e){if(e.length===0)return[];let t=`https://router.huggingface.co/hf-inference/models/${this.options.model}/pipeline/feature-extraction`,o=await fetch(t,{method:"POST",headers:{Authorization:`Bearer ${this.options.token}`,"Content-Type":"application/json"},body:JSON.stringify({inputs:e,options:{wait_for_model:!0}})});if(!o.ok)throw new Error(`HF embedding failed: ${o.status} ${await o.text()}`);let n=await o.json();if(!Array.isArray(n))throw new Error("HF embedding returned invalid response");return n.map(i=>ft(i))}};function ft(r){if(!Array.isArray(r))throw new Error("Invalid embedding");if(r.length>0&&typeof r[0]=="number")return r;if(r.length>0&&Array.isArray(r[0])){let e=r;if(e.length===0)return[];let t=e[0].length,o=new Array(t).fill(0);for(let n of e)for(let i=0;i<t;i++)o[i]+=n[i]??0;for(let n=0;n<t;n++)o[n]/=e.length;return o}throw new Error("Unsupported embedding shape")}var q=class{constructor(e,t=new K){this.primary=e;this.fallback=t}primary;fallback;name="resilient";async embed(e){if(this.primary)try{return await this.primary.embed(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embed(e)}async embedMany(e){if(this.primary)try{return await this.primary.embedMany(e)}catch(t){console.warn("[embedding] primary failed, fallback enabled:",t instanceof Error?t.message:t)}return this.fallback.embedMany(e)}};function yt(r){return`https://api.cloudflare.com/client/v4/accounts/${r}/ai/v1`}function ht(){let r=w().embedding;if(r.provider==="local")return null;if(r.provider==="huggingface")return!r.apiKey||!r.model?null:new U({token:r.apiKey,model:r.model});if(r.provider==="gemini")return!r.apiKey||!r.model?null:new D({apiKey:r.apiKey,model:r.model,baseUrl:r.baseUrl});let e=r.baseUrl;return r.provider==="cloudflare"&&!e&&r.accountId&&(e=yt(r.accountId)),e&&r.model?new N({apiKey:r.apiKey,baseUrl:e,model:r.model}):null}function ge(){return new q(ht())}var W=class extends Error{status;constructor(e,t){super(e),this.name="AiHttpError",this.status=t}};async function y(r,e,t=3e4){let o=new AbortController,n=setTimeout(()=>o.abort(),t);n.unref?.();try{let i=await fetch(r,{...e,signal:o.signal}),a=await i.text();if(!i.ok){let c=a;try{let d=JSON.parse(a);c=d.error?.message??d.message??a}catch{}throw new W(c||`HTTP ${i.status}`,i.status)}return a.trim()?JSON.parse(a):{}}finally{clearTimeout(n)}}function $(r,e){return`${r.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`}var B=class{constructor(e){this.config=e}config;id="cloudflare";model(){let e=this.config.model?.trim();if(!e)throw new Error("cloudflare: MODEL is not configured");return e}async generate(e){let t=this.config.accountId?.trim(),o=this.config.apiKey?.trim();if(!t)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!o)throw new Error("cloudflare: API TOKEN is not configured");let n=this.model(),a=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${t}/ai/run`).replace(/\/+$/,"")}/${n}`,c=await y(a,{method:"POST",headers:{authorization:`Bearer ${o}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),d=c.result?.response?.trim();if(!d)throw new Error(c.errors?.[0]?.message??"cloudflare: empty model response");return{text:d,provider:"cloudflare",model:n}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"cloudflare",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"cloudflare",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var F=class{constructor(e){this.config=e}config;id="gemini";model(){let e=this.config.model?.trim();if(!e)throw new Error("gemini: MODEL is not configured");return e.replace(/^models\//,"")}async generate(e){let t=this.config.apiKey?.trim();if(!t)throw new Error("gemini: API KEY is not configured");let o=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",n=this.model(),i=e.messages.filter(p=>p.role==="system"),a=e.messages.filter(p=>p.role!=="system").map(p=>({role:p.role==="assistant"?"model":"user",parts:[{text:p.content}]})),c=`${$(o,`models/${encodeURIComponent(n)}:generateContent`)}?key=${encodeURIComponent(t)}`,d=await y(c,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...i.length?{systemInstruction:{parts:[{text:i.map(p=>p.content).join(`
4
+
5
+ `)}]}}:{},contents:a,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),m=d.candidates?.[0]?.content?.parts?.map(p=>p.text??"").join("").trim();if(!m)throw new Error("gemini: empty model response");return{text:m,provider:"gemini",model:n,usage:d.usageMetadata?{inputTokens:d.usageMetadata.promptTokenCount,outputTokens:d.usageMetadata.candidatesTokenCount,totalTokens:d.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"gemini",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:"gemini",model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};var G=class{constructor(e){this.config=e;this.id=e.id}config;id;baseUrl(){let e=this.config.baseUrl?.trim();if(!e)throw new Error(`${this.id}: BASE URL is not configured`);return e}model(){let e=this.config.model?.trim();if(!e)throw new Error(`${this.id}: MODEL is not configured`);return e}headers(){let e={"content-type":"application/json",...this.config.headers};return this.config.apiKey&&(e.authorization=`Bearer ${this.config.apiKey}`),e}async generate(e){let t=this.model(),o=await y($(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:t,messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),n=o.choices?.[0]?.message?.content?.trim();if(!n)throw new Error(`${this.id}: empty model response`);return{text:n,provider:this.id,model:t,usage:o.usage?{inputTokens:o.usage.prompt_tokens,outputTokens:o.usage.completion_tokens,totalTokens:o.usage.total_tokens}:void 0}}async healthCheck(){let e=Date.now();try{let t=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:t.model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(t){return{ok:!1,provider:this.id,model:this.config.model,message:t instanceof Error?t.message:String(t),latencyMs:Date.now()-e}}}};function fe(r=ue()){switch(f(r.id).transport){case"gemini":return new F(r);case"cloudflare":return new B(r);default:return new G(r)}}var bt=["memories/current.json","vectors/current.json","graph/current.json","graph/manifest.json","graph/resolution/current.json","code/chunks/current.json","code/vectors/current.json","code/architecture/current.json","code/architecture/entry-points.json","code/architecture/hotspots.json","code/architecture/layers.json","code/architecture/clusters.json","code/analysis/current.json","code/analysis/dead-code.json","code/analysis/dependencies.json","code/visualization/graph.json"],V=class{constructor(e){this.storage=e}storage;projectPrefix(e){return`projects/${e}`}snapshotPrefix(e,t){return[this.projectPrefix(e),"snapshots",t].join("/")}async create(e,t="automatic",o){let n=new Date().toISOString(),i=n.replace(/[:.]/g,"-"),a=this.projectPrefix(e),c=this.snapshotPrefix(e,i),d=[];for(let p of bt){let u=`${a}/${p}`,_=await this.storage.get(u);_&&(await this.storage.put(`${c}/${p}`,_,"application/json"),d.push(p))}if(d.length===0)return null;let m={version:1,id:i,projectId:e,createdAt:n,reason:t,objects:d,metadata:o};return await this.storage.put(`${c}/snapshot.json`,JSON.stringify(m,null,2),"application/json"),m}async list(e){let t=[this.projectPrefix(e),"snapshots"].join("/"),n=(await this.storage.list(t)).filter(a=>a.key.endsWith("/snapshot.json")),i=[];for(let a of n){let c=await this.storage.getText(a.key);if(c)try{i.push(JSON.parse(c))}catch{}}return i.sort((a,c)=>c.createdAt.localeCompare(a.createdAt))}async restore(e,t){let o=this.snapshotPrefix(e,t),n=await this.storage.getText(`${o}/snapshot.json`);if(!n)throw new Error(`Snapshot not found: ${t}`);let i=JSON.parse(n);if(i.projectId!==e)throw new Error("Snapshot project mismatch");let a=this.projectPrefix(e),c=[];for(let d of i.objects){let m=await this.storage.get(`${o}/${d}`);m&&(await this.storage.put(`${a}/${d}`,m,"application/json"),c.push(d))}return{restored:c}}async remove(e,t){let o=this.snapshotPrefix(e,t),n=await this.storage.list(o);for(let i of n)await this.storage.delete(i.key);return n.length}async prune(e,t=10){let n=(await this.list(e)).slice(t),i=0;for(let a of n)await this.remove(e,a.id),i++;return i}};function Z(r,e){for(let t of r)process.env[t]||e.push(`Missing ${t}`)}function ye(){let r=[],e=[],t=process.env.MEMORY_STORAGE_PROVIDER??"local";return t==="r2"?Z(["R2_ACCOUNT_ID","R2_BUCKET","R2_ACCESS_KEY_ID","R2_SECRET_ACCESS_KEY"],r):t==="s3"?Z(["S3_BUCKET","S3_ACCESS_KEY_ID","S3_SECRET_ACCESS_KEY"],r):t==="huggingface"?Z(["HF_NAMESPACE","HF_BUCKET","HF_S3_ACCESS_KEY_ID","HF_S3_SECRET_ACCESS_KEY"],r):t!=="local"&&r.push(`Unsupported MEMORY_STORAGE_PROVIDER: ${t}`),process.env.HF_TOKEN||e.push("HF_TOKEN missing: semantic embedding will use fallback"),process.env.HF_EMBEDDING_MODEL||e.push("HF_EMBEDDING_MODEL not set; default model will be used"),{ok:r.length===0,errors:r,warnings:e}}import{randomUUID as Et}from"node:crypto";var H=class{constructor(e,t){this.storage=e;this.embeddings=t}storage;embeddings;async run(){let e=`_health/production-${Et()}.txt`,t=`toolnet-memory:${Date.now()}`,o=!1;try{await this.storage.put(e,t,"text/plain"),o=await this.storage.getText(e)===t}finally{try{await this.storage.delete(e)}catch{}}let n=null;if(this.embeddings)try{let i=await this.embeddings.embed("ToolNet Memory production health check");n={ok:i.length>0,dimensions:i.length,mode:i.length===384?"huggingface":"fallback-or-custom"}}catch{n={ok:!1,dimensions:0,mode:"failed"}}return{ok:o&&(n===null||n.ok),storage:{ok:o,provider:this.storage.name},embedding:n}}};function be(){return process.argv.includes("--json")}function vt(r){if(console.log(""),console.log("ToolNet Memory Doctor"),console.log("====================="),console.log(""),r.project&&(console.log(`Project: ${r.project}`),console.log("")),r.storage)if(r.storage.ok){let n=typeof r.storage.provider=="string"?` (${r.storage.provider})`:"";console.log(`\u2713 Storage${n}`)}else console.log("\u2717 Storage");if(r.llm)if(r.llm.ok){let n=[];r.llm.provider&&n.push(r.llm.provider),r.llm.model&&n.push(r.llm.model),typeof r.llm.latencyMs=="number"&&n.push(`${r.llm.latencyMs} ms`),console.log(`\u2713 LLM${n.length?` (${n.join(", ")})`:""}`)}else console.log(`\u2717 LLM${r.llm.error?` (${r.llm.error})`:""}`);if(r.embedding)if(r.embedding.ok){let n=[];typeof r.embedding.mode=="string"&&n.push(r.embedding.mode),typeof r.embedding.dimensions=="number"&&n.push(`${r.embedding.dimensions} dimensions`),console.log(`\u2713 Embedding${n.length?` (${n.join(", ")})`:""}`)}else console.log("\u2717 Embedding");(r.memory!==void 0||r.graphSymbols!==void 0||r.codeChunks!==void 0)&&(console.log(""),console.log("Project data:"),r.memory!==void 0&&console.log(` Memories ${r.memory}`),r.graphSymbols!==void 0&&console.log(` Graph symbols ${r.graphSymbols}`),r.graphEdges!==void 0&&console.log(` Graph edges ${r.graphEdges}`),r.memoryVectors!==void 0&&console.log(` Memory vectors ${r.memoryVectors}`),r.codeChunks!==void 0&&console.log(` Code chunks ${r.codeChunks}`),r.codeVectors!==void 0&&console.log(` Code vectors ${r.codeVectors}`),r.snapshots!==void 0&&console.log(` Snapshots ${r.snapshots}`));let e=r.config?.errors??[];if(e.length>0){console.log(""),console.log("Configuration required:");for(let n of e)console.log(` - ${n}`)}let t=[...r.config?.warnings??[],...r.warnings??[]],o=[...new Set(t)];if(o.length>0){console.log(""),console.log("Warnings:");for(let n of o)console.log(` - ${n}`)}console.log(""),r.ok?console.log("\u2713 ToolNet Memory is ready"):(console.log("\u2717 ToolNet Memory requires attention"),e.length>0&&(console.log(""),console.log("Run:"),console.log(" toolnet-memory setup"))),console.log("")}function he(r){be()?console.log(JSON.stringify(r,null,2)):vt(r)}async function At(){let r=ye();if(!r.ok){let g={ok:!1,config:r,warnings:r.warnings};he(g),process.exitCode=1;return}let e=X(),t=new O().detect(),o=de(ae({provider:e.storage.provider,r2:e.storage.r2,s3:e.storage.s3,huggingface:e.storage.huggingface,localRoot:e.storage.localRoot}),{attempts:3}),n=ge(),i=w(),a;try{let h=await fe({id:i.llm.provider,apiKey:i.llm.apiKey,baseUrl:i.llm.baseUrl,model:i.llm.model,accountId:i.llm.accountId}).healthCheck();a={ok:h.ok,provider:i.llm.provider,model:h.model??i.llm.model,latencyMs:h.latencyMs,error:h.ok?void 0:h.message}}catch(g){a={ok:!1,provider:i.llm.provider,model:i.llm.model,error:g instanceof Error?g.message:String(g)}}let c=await new H(o,n).run(),d=await new j(o).load(t.id),m=await new R(o).load(t.id),p=await new x(o).load(t.id),u=await new C(o).load(t.id),_=await new M(o).load(t.id),Ee=await new V(o).list(t.id),Q={ok:c.ok&&!!a?.ok,project:t.name,storage:c.storage,llm:a,embedding:c.embedding,memory:d.length,graphSymbols:m?.symbols.length??0,graphEdges:m?.edges.length??0,memoryVectors:p?.records.length??0,codeChunks:u?.chunks.length??0,codeVectors:_?.records.length??0,snapshots:Ee.length,warnings:r.warnings};he(Q),process.exitCode=Q.ok?0:1}At().catch(r=>{let e=r instanceof Error?r.message:String(r);be()?console.log(JSON.stringify({ok:!1,error:e},null,2)):(console.error(""),console.error("ToolNet Memory Doctor"),console.error("====================="),console.error(""),console.error(`\u2717 ${e}`),console.error("")),process.exitCode=1});