toolnet-memory 0.2.18 → 0.2.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,24 +1,24 @@
1
1
  #!/usr/bin/env node
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(`
2
+ import*as $ 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
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
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
- `,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(`
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 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)}
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 U,mkdirSync as tr,readFileSync as H,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(!U(t))return null;try{let e=H(t,"utf8").trim();if(!e)return null;let o=new Date(0).toISOString(),n=Re(r);if(U(n))try{let s=JSON.parse(H(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
15
 
16
16
  [Fast handoff truncated]`),["[TOOLNET FAST HANDOFF]","",`Project: ${r.name}`,`Updated: ${e.generatedAt}`,"",o].join(`
17
- `)}var _="memory_agent_ask";function q(){return`
17
+ `)}var A="memory_agent_ask";function q(){return`
18
18
  [TOOLNET MEMORY AGENT]
19
19
 
20
20
  Tool available:
21
- - ${_}
21
+ - ${A}
22
22
 
23
23
  Use it automatically BEFORE guessing when:
24
24
 
@@ -55,6 +55,12 @@ Rules:
55
55
 
56
56
  - Never invent previous work.
57
57
  - Current repository evidence overrides stale memory.
58
+ - NEVER reconstruct previous work by reading ToolNet internal session files.
59
+ - NEVER read/list/search .toolnet/sessions/**, session state.json,
60
+ events.jsonl, or raw transcripts to discover previous-agent state.
61
+ - Do not search the filesystem for the implementation/schema of
62
+ memory_agent_ask. Invoke the MCP tool directly when deeper
63
+ continuity is required.
58
64
  - Do not dump raw transcripts or full memory.
59
65
  - After receiving the ToolNet answer, continue the task
60
66
  instead of asking the user to repeat known context.
@@ -63,19 +69,30 @@ Rules:
63
69
  [TOOLNET MEMORY AGENT]
64
70
 
65
71
  Tool:
66
- - ${_}
67
-
68
- If the user asks to resume previous work and the fast context
69
- is insufficient, call ${_} before guessing.
72
+ - ${A}
73
+
74
+ For resume/continue requests:
75
+
76
+ 1. Use the injected ToolNet continuity handoff FIRST.
77
+ 2. If the handoff is missing or ambiguous, invoke
78
+ ${A} directly BEFORE repository/history exploration.
79
+ 3. NEVER reconstruct prior work from:
80
+ - .toolnet/sessions/**
81
+ - state.json
82
+ - events.jsonl
83
+ - raw transcripts
84
+ 4. NEVER search for the implementation/schema of
85
+ ${A}; invoke the MCP tool directly.
86
+ 5. Inspect git/source only AFTER continuity context is known.
70
87
 
71
88
  Use:
72
89
  - mode="local" for current task, last file, blocker or next action.
73
90
  - mode="ai" for ambiguous or combined continuity questions.
74
91
 
75
92
  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(`
93
+ `.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 C(r){try{return h.existsSync(r)?h.readFileSync(r,"utf-8").trim():null}catch{return null}}function Z(r){return r.split(`
77
94
  `).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(`
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]
95
+ `)}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=C(s)||"",i=C(c)||"";l=Z(l),i=Z(i);let p=`[TOOLNET PROJECT CONTEXT]
79
96
 
80
97
  Project: ${n}
81
98
  Root: ${e}
@@ -92,7 +109,7 @@ Forbidden At Startup:
92
109
  - Do not perform deep recovery merely because an agent starts.
93
110
  - If the user asks to resume previous work and fast context is insufficient,
94
111
  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
112
+ `;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=C(o)||"",c=C(n)||"",l=`# AI Startup Instructions
96
113
 
97
114
  Read and follow:
98
115
  - .toolnet/profile.md
@@ -117,7 +134,7 @@ ${s}
117
134
  ## Current Work
118
135
 
119
136
  ${c}
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
137
+ `,i=["GEMINI.md","AGENTS.md","CLAUDE.md"],p=[];for(let f of i){let a=g.join(e,f);try{h.writeFileSync(a,l,"utf-8"),p.push(f)}catch(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 Ue}from"node:fs";import{dirname as He,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
121
138
 
122
139
  This file contains persistent instructions for AI agents working on this project.
123
140
 
@@ -160,17 +177,17 @@ Things an AI agent should always remember.
160
177
  <!--
161
178
  - [advisory] Prefer small focused files.
162
179
  -->
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(`
180
+ `;function O(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=O(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):O(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
181
  `);if(W(n)<=t){e.push(o);continue}let s=W(e.join(`
165
182
  `)),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(`
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(`
183
+ `).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: ${O(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(He(e),{recursive:!0}),Ue(e,t.text.endsWith(`
167
184
  `)?t.text:t.text+`
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+=`
185
+ `,{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+=`
169
186
 
170
187
  [Context trimmed by ToolNet Memory token budget]
171
188
  `);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+`
172
189
  `,"text/markdown"),await t.put(`projects/${r.id}/context/startup.json`,JSON.stringify(c,null,2)+`
173
190
  `,"application/json"),c}import{existsSync as Qe,readFileSync as Ze}from"node:fs";import{homedir as Xe}from"node:os";import{join as et}from"node:path";function tt(r){let t=r.trim();return t.length>=2&&t.startsWith('"')&&t.endsWith('"')?(t=t.slice(1,-1),t.replace(/\\n/g,`
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();
191
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):t.length>=2&&t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function rt(){let r=process.env.TOOLNET_GLOBAL_ENV??et(Xe(),".config","toolnet-memory",".env");if(!Qe(r))return;let t=Ze(r,"utf8");for(let e of t.split(/\r?\n/)){let 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 E,join as I,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 I(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=E(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(I(t,s))))return t;if(t===e)break;let n=E(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:E(E(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=I(r,me);nt(e,{recursive:!0});let o=L(r),n=`${o}.tmp-${process.pid}`;at(n,JSON.stringify(t,null,2)+`
192
+ `,{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 R=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(I(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 M=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 M({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 N=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)+`
193
+ `,"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 Ut(t);break;case"profile-sync":await Ht(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 R().detect(e),n=pe(),s=ke(Se({provider:n.storage.provider,huggingface:n.storage.huggingface,localRoot:n.storage.localRoot}),{attempts:2}),c=new N(s,o.id,o.name,o.remote??o.name);await ue(o,c),console.log("Deep startup brief cache refreshed.")}async function Ut(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");$.existsSync(o)||(console.error("No profile.md found in .toolnet directory."),process.exit(1));let n=$.readFileSync(o,"utf-8");process.stdout.write(n)}async function Ht(r){let t=ee({projectPath:r.project});console.log("Created/updated:");for(let e of t)console.log(`- ${e}`)}Lt();
@@ -1,12 +1,12 @@
1
- import*as a from"fs";import*as i from"path";import{existsSync as T,mkdirSync as D,readFileSync as A,renameSync as $,writeFileSync as L}from"node:fs";import{dirname as H,join as b}from"node:path";import{createHash as F}from"node:crypto";function g(r){return F("sha256").update(r).digest("hex")}function w(r){return b(r.rootPath,".toolnet","context","handoff.md")}function v(r){return b(r.rootPath,".toolnet","context","handoff.json")}function C(r,e){D(H(r),{recursive:!0});let t=`${r}.tmp-${process.pid}-${Date.now()}`;L(t,e.endsWith(`
1
+ import*as a from"fs";import*as i from"path";import{existsSync as T,mkdirSync as D,readFileSync as A,renameSync as $,writeFileSync as L}from"node:fs";import{dirname as H,join as w}from"node:path";import{createHash as F}from"node:crypto";function g(r){return F("sha256").update(r).digest("hex")}function v(r){return w(r.rootPath,".toolnet","context","handoff.md")}function b(r){return w(r.rootPath,".toolnet","context","handoff.json")}function E(r,e){D(H(r),{recursive:!0});let t=`${r}.tmp-${process.pid}-${Date.now()}`;L(t,e.endsWith(`
2
2
  `)?e:`${e}
3
- `,{encoding:"utf8",mode:384}),$(t,r)}function z(r,e){C(r,`${JSON.stringify(e,null,2)}
4
- `)}function M(r,e){let t=e.replace(/\r\n/g,`
5
- `).trim();if(!t)return null;let n={version:1,projectId:r.id,projectName:r.name,text:t,digest:g(t),generatedAt:new Date().toISOString()};return C(w(r),t),z(v(r),n),n}function E(r){let e=w(r);if(!T(e))return null;try{let t=A(e,"utf8").trim();if(!t)return null;let n=new Date(0).toISOString(),o=v(r);if(T(o))try{let s=JSON.parse(A(o,"utf8"));typeof s.generatedAt=="string"&&(n=s.generatedAt)}catch{}return{version:1,projectId:r.id,projectName:r.name,text:t,digest:g(t),generatedAt:n}}catch{return null}}function R(r){let e=i.resolve(r),t=i.parse(e).root;for(;e!==t;){let n=i.join(e,".toolnet");if(a.existsSync(n)&&a.statSync(n).isDirectory())return e;e=i.dirname(e)}return null}import{existsSync as U,readFileSync as J}from"node:fs";import{join as G}from"node:path";import{existsSync as B,mkdirSync as Pe,readFileSync as K,renameSync as Ne,writeFileSync as Fe}from"node:fs";import{dirname as $e,join as Y}from"node:path";function V(r){return Y(r.rootPath,".toolnet","context","session-origin.json")}function W(r){let e=V(r);if(!B(e))return null;try{let t=JSON.parse(K(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function j(r){let e=W(r);if(!e)return null;let t=["Previous session:",`- Agent: ${e.agent}`,`- Session: ${e.nativeSessionId}`];return e.currentPhase&&t.push(`- Current phase: ${e.currentPhase}`),e.currentTask&&t.push(`- Current task: ${e.currentTask}`),e.lastTouchedFile&&t.push(`- Last touched file: ${e.lastTouchedFile}`),e.latestBlocker&&t.push(`- Blocker: ${e.latestBlocker}`),e.latestNextAction&&t.push(`- Next action: ${e.latestNextAction}`),e.latestDecision&&t.push(`- Important decision: ${e.latestDecision}`),t.join(`
6
- `)}function Z(r){let e=G(r.rootPath,".toolnet","current.md");if(!U(e))return null;try{return J(e,"utf8").trim()}catch{return null}}function Q(r,e){let t=e.replace(/\r\n/g,`
3
+ `,{encoding:"utf8",mode:384}),$(t,r)}function B(r,e){E(r,`${JSON.stringify(e,null,2)}
4
+ `)}function R(r,e){let t=e.replace(/\r\n/g,`
5
+ `).trim();if(!t)return null;let n={version:1,projectId:r.id,projectName:r.name,text:t,digest:g(t),generatedAt:new Date().toISOString()};return E(v(r),t),B(b(r),n),n}function C(r){let e=v(r);if(!T(e))return null;try{let t=A(e,"utf8").trim();if(!t)return null;let n=new Date(0).toISOString(),o=b(r);if(T(o))try{let s=JSON.parse(A(o,"utf8"));typeof s.generatedAt=="string"&&(n=s.generatedAt)}catch{}return{version:1,projectId:r.id,projectName:r.name,text:t,digest:g(t),generatedAt:n}}catch{return null}}function M(r){let e=i.resolve(r),t=i.parse(e).root;for(;e!==t;){let n=i.join(e,".toolnet");if(a.existsSync(n)&&a.statSync(n).isDirectory())return e;e=i.dirname(e)}return null}import{existsSync as W,readFileSync as J}from"node:fs";import{join as G}from"node:path";import{existsSync as z,mkdirSync as Pe,readFileSync as K,renameSync as Ne,writeFileSync as Fe}from"node:fs";import{dirname as $e,join as V}from"node:path";function Y(r){return V(r.rootPath,".toolnet","context","session-origin.json")}function U(r){let e=Y(r);if(!z(e))return null;try{let t=JSON.parse(K(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function j(r){let e=U(r);if(!e)return null;let t=["Previous session:",`- Agent: ${e.agent}`,`- Session: ${e.nativeSessionId}`];return e.currentPhase&&t.push(`- Current phase: ${e.currentPhase}`),e.currentTask&&t.push(`- Current task: ${e.currentTask}`),e.lastTouchedFile&&t.push(`- Last touched file: ${e.lastTouchedFile}`),e.latestBlocker&&t.push(`- Blocker: ${e.latestBlocker}`),e.latestNextAction&&t.push(`- Next action: ${e.latestNextAction}`),e.latestDecision&&t.push(`- Important decision: ${e.latestDecision}`),t.join(`
6
+ `)}function Z(r){let e=G(r.rootPath,".toolnet","current.md");if(!W(e))return null;try{return J(e,"utf8").trim()}catch{return null}}function q(r,e){let t=e.replace(/\r\n/g,`
7
7
  `).trim(),n=2400,o=t.length>n?`${t.slice(0,n)}
8
8
 
9
9
  [Current work truncated for fast handoff]`:t,s=j(r);return["# ToolNet Fast Handoff","",`Project: ${r.name}`,"",...s?[s,""]:[],o,"","---","","Continuation rule:","- Continue unfinished work; do not redo completed steps.","- Query ToolNet Memory only when deeper history is needed."].join(`
10
- `)}function O(r){let e=Z(r);if(e===null)return{updated:!1,reason:"missing-current",chars:0};if(!e.trim())return{updated:!1,reason:"empty-current",chars:0};let t=Q(r,e);return E(r)?.text.trim()===t.trim()?{updated:!1,reason:"unchanged",chars:t.length}:(M(r,t),{updated:!0,reason:"updated",chars:t.length})}import{existsSync as X,readFileSync as q}from"node:fs";import{homedir as ee}from"node:os";import{join as te}from"node:path";function re(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
11
- `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function ne(){let r=process.env.TOOLNET_GLOBAL_ENV??te(ee(),".config","toolnet-memory",".env");if(!X(r))return;let e=q(r,"utf8");for(let t of e.split(/\r?\n/)){let n=t.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let o=n.indexOf("=");if(o<=0)continue;let s=n.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=re(n.slice(o+1)))}}ne();import{createHash as oe}from"node:crypto";import{existsSync as y,mkdirSync as se,readFileSync as ie,renameSync as ce,writeFileSync as ae}from"node:fs";import{basename as ue,dirname as d,join as l,parse as P,resolve as f}from"node:path";var N=".toolnet",fe="project.json";function de(r){return oe("sha256").update(r).digest("hex").slice(0,16)}function h(r){return l(r,N,fe)}function me(r){return y(h(r))}function le(r,e){let t=f(r),n=P(t).root;for(;;){if(me(t))return t;if(t===n||e&&t===f(e))break;let o=d(t);if(o===t)break;t=o}return null}function pe(r){let e=f(r),t=P(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(s=>y(l(e,s))))return e;if(e===t)break;let o=d(e);if(o===e)break;e=o}return f(r)}function ge(r){let e;try{e=JSON.parse(ie(r,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${r}: ${o instanceof Error?o.message:String(o)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:d(d(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:n,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:n,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function _(r,e){let t=l(r,N);se(t,{recursive:!0});let n=h(r),o=`${n}.tmp-${process.pid}`;ae(o,JSON.stringify(e,null,2)+`
12
- `,{encoding:"utf8",mode:384}),ce(o,n)}function I(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var m=class{detect(e=process.cwd()){let t=f(e),n=pe(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>y(l(n,p))),c=le(t,s?n:void 0);if(c){let p=h(c),u=ge(p);return u.rootPath!==c&&(u.rootPath=c,u.updatedAt=new Date().toISOString(),_(c,u)),I(u,c)}let S=new Date().toISOString(),x=ue(n),k={version:1,id:de(n),name:x,remote:x,rootPath:n,createdAt:S,updatedAt:S,graphVersion:0,memoryVersion:0};return _(n,k),I(k,n)}};function ye(){let r=process.cwd(),e=R(r);if(!e){console.error("Not in a ToolNet project."),process.exitCode=1;return}let t=new m().detect(e);if(!t){console.error("Unable to detect ToolNet project."),process.exitCode=1;return}let n=O(t);console.log(JSON.stringify({project:t.name,...n},null,2))}ye();
10
+ `)}function O(r){let e=Z(r);if(e===null)return{updated:!1,reason:"missing-current",chars:0};if(!e.trim())return{updated:!1,reason:"empty-current",chars:0};let t=q(r,e);return C(r)?.text.trim()===t.trim()?{updated:!1,reason:"unchanged",chars:t.length}:(R(r,t),{updated:!0,reason:"updated",chars:t.length})}import{existsSync as Q,readFileSync as X}from"node:fs";import{homedir as ee}from"node:os";import{join as te}from"node:path";function re(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
11
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function ne(){let r=process.env.TOOLNET_GLOBAL_ENV??te(ee(),".config","toolnet-memory",".env");if(!Q(r))return;let e=X(r,"utf8");for(let t of e.split(/\r?\n/)){let n=t.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let o=n.indexOf("=");if(o<=0)continue;let s=n.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=re(n.slice(o+1)))}}ne();import{createHash as oe}from"node:crypto";import{existsSync as y,mkdirSync as se,readFileSync as ie,renameSync as ce,writeFileSync as ae}from"node:fs";import{basename as ue,dirname as d,join as l,parse as P,resolve as f}from"node:path";var N=".toolnet",fe="project.json";function de(r){return oe("sha256").update(r).digest("hex").slice(0,16)}function h(r){return l(r,N,fe)}function me(r){return y(h(r))}function le(r,e){let t=f(r),n=P(t).root;for(;;){if(me(t))return t;if(t===n||e&&t===f(e))break;let o=d(t);if(o===t)break;t=o}return null}function pe(r){let e=f(r),t=P(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(s=>y(l(e,s))))return e;if(e===t)break;let o=d(e);if(o===e)break;e=o}return f(r)}function ge(r){let e;try{e=JSON.parse(ie(r,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${r}: ${o instanceof Error?o.message:String(o)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:d(d(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:n,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:n,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function _(r,e){let t=l(r,N);se(t,{recursive:!0});let n=h(r),o=`${n}.tmp-${process.pid}`;ae(o,JSON.stringify(e,null,2)+`
12
+ `,{encoding:"utf8",mode:384}),ce(o,n)}function I(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var m=class{detect(e=process.cwd()){let t=f(e),n=pe(t),s=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(p=>y(l(n,p))),c=le(t,s?n:void 0);if(c){let p=h(c),u=ge(p);return u.rootPath!==c&&(u.rootPath=c,u.updatedAt=new Date().toISOString(),_(c,u)),I(u,c)}let S=new Date().toISOString(),x=ue(n),k={version:1,id:de(n),name:x,remote:x,rootPath:n,createdAt:S,updatedAt:S,graphVersion:0,memoryVersion:0};return _(n,k),I(k,n)}};function ye(){let r=process.cwd(),e=M(r);if(!e){console.error("Not in a ToolNet project."),process.exitCode=1;return}let t=new m().detect(e);if(!t){console.error("Unable to detect ToolNet project."),process.exitCode=1;return}let n=O(t);console.log(JSON.stringify({project:t.name,...n},null,2))}ye();
@@ -1,10 +1,10 @@
1
- import*as h from"fs";import*as f from"path";function j(r){let e=f.resolve(r),t=f.parse(e).root;for(;e!==t;){let n=f.join(e,".toolnet");if(h.existsSync(n)&&h.statSync(n).isDirectory())return e;e=f.dirname(e)}return null}var K=[{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 g(r){let e=K.find(t=>t.id===r);if(!e)throw new Error(`Unsupported AI provider: ${r}`);return e}function A(r){return K.some(e=>e.id===r)}function o(r){return process.env[r]?.trim()||void 0}function c(...r){return r.find(e=>!!e?.trim())}function F(){if(o("GROQ_API_KEY"))return"groq";if(o("DEEPSEEK_API_KEY"))return"deepseek";if(o("NVIDIA_API_KEY")||o("NVIDIA_NIM_API_KEY"))return"nvidia";if(o("OPENROUTER_API_KEY"))return"openrouter";if(o("ALIBABA_API_KEY")||o("DASHSCOPE_API_KEY"))return"alibaba";if(o("GEMINI_API_KEY")||o("GOOGLE_API_KEY"))return"gemini";if(o("CLOUDFLARE_API_TOKEN")&&o("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(o("HF_TOKEN"))return"huggingface";if(o("OLLAMA_MODEL")||o("OLLAMA_BASE_URL"))return"ollama"}function B(){let r=o("TOOLNET_LLM_PROVIDER");return r&&A(r)?r:F()??"openai-compatible"}function v(r){let e=g(r);switch(r){case"alibaba":return{provider:r,apiKey:c(o("ALIBABA_API_KEY"),o("DASHSCOPE_API_KEY")),baseUrl:c(o("ALIBABA_BASE_URL"),o("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:c(o("ALIBABA_MODEL"),o("DASHSCOPE_MODEL"))};case"openrouter":return{provider:r,apiKey:o("OPENROUTER_API_KEY"),baseUrl:c(o("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:o("OPENROUTER_MODEL")};case"groq":return{provider:r,apiKey:o("GROQ_API_KEY"),baseUrl:c(o("GROQ_BASE_URL"),e.defaultBaseUrl),model:o("GROQ_MODEL")};case"deepseek":return{provider:r,apiKey:o("DEEPSEEK_API_KEY"),baseUrl:c(o("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:c(o("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:r,apiKey:c(o("NVIDIA_API_KEY"),o("NVIDIA_NIM_API_KEY")),baseUrl:c(o("NVIDIA_BASE_URL"),o("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:c(o("NVIDIA_MODEL"),o("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:r,apiKey:c(o("GEMINI_API_KEY"),o("GOOGLE_API_KEY")),baseUrl:c(o("GEMINI_BASE_URL"),e.defaultBaseUrl),model:o("GEMINI_MODEL")};case"huggingface":return{provider:r,apiKey:o("HF_TOKEN"),baseUrl:c(o("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:c(o("HF_LLM_MODEL"),o("HF_MODEL"))};case"ollama":return{provider:r,apiKey:o("OLLAMA_API_KEY"),baseUrl:c(o("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:o("OLLAMA_MODEL")};case"cloudflare":return{provider:r,accountId:o("CLOUDFLARE_ACCOUNT_ID"),apiKey:o("CLOUDFLARE_API_TOKEN"),baseUrl:o("CLOUDFLARE_AI_BASE_URL"),model:o("CLOUDFLARE_MODEL")};case"custom":return{provider:r,apiKey:o("CUSTOM_AI_API_KEY"),baseUrl:o("CUSTOM_AI_BASE_URL"),model:o("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:c(o("OPENAI_API_KEY"),o("MODEL_API_KEY")),baseUrl:c(o("OPENAI_BASE_URL"),o("MODEL_BASE_URL")),model:c(o("OPENAI_MODEL"),o("MODEL_NAME"))}}}function X(){let r=o("TOOLNET_LLM_PROVIDER"),e=r&&A(r)?r:B(),t=g(e),n=v(e);return{provider:e,apiKey:c(o("TOOLNET_LLM_API_KEY"),n.apiKey),baseUrl:c(o("TOOLNET_LLM_BASE_URL"),n.baseUrl,t.defaultBaseUrl),model:c(o("TOOLNET_LLM_MODEL"),n.model,t.defaultModel),accountId:c(o("TOOLNET_LLM_ACCOUNT_ID"),n.accountId)}}function ee(){let r=o("TOOLNET_EMBEDDING_PROVIDER");return r==="local"?"local":r&&A(r)?r:o("HF_TOKEN")||o("HF_EMBEDDING_MODEL")?"huggingface":"local"}function te(){let r=ee();if(r==="local")return{provider:"local",model:c(o("TOOLNET_EMBEDDING_MODEL"),o("LOCAL_EMBEDDING_MODEL"))};let e=g(r),t,n,s,a;switch(r){case"huggingface":t=o("HF_TOKEN"),n=o("HF_INFERENCE_BASE_URL"),s=o("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=o("OPENAI_API_KEY"),n=o("OPENAI_BASE_URL"),s=o("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=o("CLOUDFLARE_API_TOKEN"),n=o("CLOUDFLARE_AI_BASE_URL"),s=o("CLOUDFLARE_EMBEDDING_MODEL"),a=o("CLOUDFLARE_ACCOUNT_ID");break;default:t=v(r).apiKey,n=v(r).baseUrl,s=o(`${r.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let i=c(o("TOOLNET_EMBEDDING_ACCOUNT_ID"),a),l=c(o("TOOLNET_EMBEDDING_BASE_URL"),n,e.defaultBaseUrl),u=r==="cloudflare"&&!l&&i?`https://api.cloudflare.com/client/v4/accounts/${i}/ai/v1`:l;return{provider:r,apiKey:c(o("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:u,model:c(o("TOOLNET_EMBEDDING_MODEL"),s),accountId:i}}function C(){let r=X(),e=te();return{llm:r,embedding:e,legacy:{llm:!o("TOOLNET_LLM_PROVIDER")&&!!F(),embedding:!o("TOOLNET_EMBEDDING_PROVIDER")&&!!(o("HF_TOKEN")||o("HF_EMBEDDING_MODEL"))}}}function $(r=B()){let e=C().llm;if(r===e.provider)return{id:r,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId};let t=v(r);return{id:r,apiKey:t.apiKey,baseUrl:t.baseUrl,model:t.model,accountId:t.accountId}}function k(r,e){return o(`TOOLNET_LLM_FALLBACK_${r}_${e}`)}function G(){let r=[];for(let e of[1,2]){let t=k(e,"PROVIDER");if(!t||!A(t))continue;let n=g(t);r.push({slot:e,config:{provider:t,apiKey:k(e,"API_KEY"),baseUrl:c(k(e,"BASE_URL"),n.defaultBaseUrl),model:c(k(e,"MODEL"),n.defaultModel),accountId:k(e,"ACCOUNT_ID")}})}return r}function Y(){let r=o("TOOLNET_LLM_FALLBACK_COOLDOWN_MS"),e=o("TOOLNET_LLM_MAX_RETRIES"),t=Number(r??6e4),n=Number(e??1);return{cooldownMs:Number.isFinite(t)&&t>=0?t:6e4,maxRetries:Number.isFinite(n)&&n>=0?Math.floor(n):1}}var E=class extends Error{status;constructor(e,t){super(e),this.name="AiHttpError",this.status=t}};async function y(r,e,t=3e4){let n=new AbortController,s=setTimeout(()=>n.abort(),t);s.unref?.();try{let a=await fetch(r,{...e,signal:n.signal}),i=await a.text();if(!a.ok){let l=i;try{let u=JSON.parse(i);l=u.error?.message??u.message??i}catch{}throw new E(l||`HTTP ${a.status}`,a.status)}return i.trim()?JSON.parse(i):{}}finally{clearTimeout(s)}}function _(r,e){return`${r.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`}var O=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(),n=this.config.apiKey?.trim();if(!t)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!n)throw new Error("cloudflare: API TOKEN is not configured");let s=this.model(),i=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${t}/ai/run`).replace(/\/+$/,"")}/${s}`,l=await y(i,{method:"POST",headers:{authorization:`Bearer ${n}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),u=l.result?.response?.trim();if(!u)throw new Error(l.errors?.[0]?.message??"cloudflare: empty model response");return{text:u,provider:"cloudflare",model:s}}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 w=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 n=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",s=this.model(),a=e.messages.filter(d=>d.role==="system"),i=e.messages.filter(d=>d.role!=="system").map(d=>({role:d.role==="assistant"?"model":"user",parts:[{text:d.content}]})),l=`${_(n,`models/${encodeURIComponent(s)}:generateContent`)}?key=${encodeURIComponent(t)}`,u=await y(l,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...a.length?{systemInstruction:{parts:[{text:a.map(d=>d.content).join(`
1
+ import*as h from"fs";import*as f from"path";function U(r){let e=f.resolve(r),t=f.parse(e).root;for(;e!==t;){let n=f.join(e,".toolnet");if(h.existsSync(n)&&h.statSync(n).isDirectory())return e;e=f.dirname(e)}return null}var F=[{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 g(r){let e=F.find(t=>t.id===r);if(!e)throw new Error(`Unsupported AI provider: ${r}`);return e}function A(r){return F.some(e=>e.id===r)}function o(r){return process.env[r]?.trim()||void 0}function c(...r){return r.find(e=>!!e?.trim())}function K(){if(o("GROQ_API_KEY"))return"groq";if(o("DEEPSEEK_API_KEY"))return"deepseek";if(o("NVIDIA_API_KEY")||o("NVIDIA_NIM_API_KEY"))return"nvidia";if(o("OPENROUTER_API_KEY"))return"openrouter";if(o("ALIBABA_API_KEY")||o("DASHSCOPE_API_KEY"))return"alibaba";if(o("GEMINI_API_KEY")||o("GOOGLE_API_KEY"))return"gemini";if(o("CLOUDFLARE_API_TOKEN")&&o("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(o("HF_TOKEN"))return"huggingface";if(o("OLLAMA_MODEL")||o("OLLAMA_BASE_URL"))return"ollama"}function B(){let r=o("TOOLNET_LLM_PROVIDER");return r&&A(r)?r:K()??"openai-compatible"}function b(r){let e=g(r);switch(r){case"alibaba":return{provider:r,apiKey:c(o("ALIBABA_API_KEY"),o("DASHSCOPE_API_KEY")),baseUrl:c(o("ALIBABA_BASE_URL"),o("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:c(o("ALIBABA_MODEL"),o("DASHSCOPE_MODEL"))};case"openrouter":return{provider:r,apiKey:o("OPENROUTER_API_KEY"),baseUrl:c(o("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:o("OPENROUTER_MODEL")};case"groq":return{provider:r,apiKey:o("GROQ_API_KEY"),baseUrl:c(o("GROQ_BASE_URL"),e.defaultBaseUrl),model:o("GROQ_MODEL")};case"deepseek":return{provider:r,apiKey:o("DEEPSEEK_API_KEY"),baseUrl:c(o("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:c(o("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:r,apiKey:c(o("NVIDIA_API_KEY"),o("NVIDIA_NIM_API_KEY")),baseUrl:c(o("NVIDIA_BASE_URL"),o("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:c(o("NVIDIA_MODEL"),o("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:r,apiKey:c(o("GEMINI_API_KEY"),o("GOOGLE_API_KEY")),baseUrl:c(o("GEMINI_BASE_URL"),e.defaultBaseUrl),model:o("GEMINI_MODEL")};case"huggingface":return{provider:r,apiKey:o("HF_TOKEN"),baseUrl:c(o("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:c(o("HF_LLM_MODEL"),o("HF_MODEL"))};case"ollama":return{provider:r,apiKey:o("OLLAMA_API_KEY"),baseUrl:c(o("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:o("OLLAMA_MODEL")};case"cloudflare":return{provider:r,accountId:o("CLOUDFLARE_ACCOUNT_ID"),apiKey:o("CLOUDFLARE_API_TOKEN"),baseUrl:o("CLOUDFLARE_AI_BASE_URL"),model:o("CLOUDFLARE_MODEL")};case"custom":return{provider:r,apiKey:o("CUSTOM_AI_API_KEY"),baseUrl:o("CUSTOM_AI_BASE_URL"),model:o("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:c(o("OPENAI_API_KEY"),o("MODEL_API_KEY")),baseUrl:c(o("OPENAI_BASE_URL"),o("MODEL_BASE_URL")),model:c(o("OPENAI_MODEL"),o("MODEL_NAME"))}}}function X(){let r=o("TOOLNET_LLM_PROVIDER"),e=r&&A(r)?r:B(),t=g(e),n=b(e);return{provider:e,apiKey:c(o("TOOLNET_LLM_API_KEY"),n.apiKey),baseUrl:c(o("TOOLNET_LLM_BASE_URL"),n.baseUrl,t.defaultBaseUrl),model:c(o("TOOLNET_LLM_MODEL"),n.model,t.defaultModel),accountId:c(o("TOOLNET_LLM_ACCOUNT_ID"),n.accountId)}}function ee(){let r=o("TOOLNET_EMBEDDING_PROVIDER");return r==="local"?"local":r&&A(r)?r:o("HF_TOKEN")||o("HF_EMBEDDING_MODEL")?"huggingface":"local"}function te(){let r=ee();if(r==="local")return{provider:"local",model:c(o("TOOLNET_EMBEDDING_MODEL"),o("LOCAL_EMBEDDING_MODEL"))};let e=g(r),t,n,s,a;switch(r){case"huggingface":t=o("HF_TOKEN"),n=o("HF_INFERENCE_BASE_URL"),s=o("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=o("OPENAI_API_KEY"),n=o("OPENAI_BASE_URL"),s=o("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=o("CLOUDFLARE_API_TOKEN"),n=o("CLOUDFLARE_AI_BASE_URL"),s=o("CLOUDFLARE_EMBEDDING_MODEL"),a=o("CLOUDFLARE_ACCOUNT_ID");break;default:t=b(r).apiKey,n=b(r).baseUrl,s=o(`${r.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let i=c(o("TOOLNET_EMBEDDING_ACCOUNT_ID"),a),l=c(o("TOOLNET_EMBEDDING_BASE_URL"),n,e.defaultBaseUrl),u=r==="cloudflare"&&!l&&i?`https://api.cloudflare.com/client/v4/accounts/${i}/ai/v1`:l;return{provider:r,apiKey:c(o("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:u,model:c(o("TOOLNET_EMBEDDING_MODEL"),s),accountId:i}}function C(){let r=X(),e=te();return{llm:r,embedding:e,legacy:{llm:!o("TOOLNET_LLM_PROVIDER")&&!!K(),embedding:!o("TOOLNET_EMBEDDING_PROVIDER")&&!!(o("HF_TOKEN")||o("HF_EMBEDDING_MODEL"))}}}function $(r=B()){let e=C().llm;if(r===e.provider)return{id:r,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId};let t=b(r);return{id:r,apiKey:t.apiKey,baseUrl:t.baseUrl,model:t.model,accountId:t.accountId}}function k(r,e){return o(`TOOLNET_LLM_FALLBACK_${r}_${e}`)}function G(){let r=[];for(let e of[1,2]){let t=k(e,"PROVIDER");if(!t||!A(t))continue;let n=g(t);r.push({slot:e,config:{provider:t,apiKey:k(e,"API_KEY"),baseUrl:c(k(e,"BASE_URL"),n.defaultBaseUrl),model:c(k(e,"MODEL"),n.defaultModel),accountId:k(e,"ACCOUNT_ID")}})}return r}function Y(){let r=o("TOOLNET_LLM_FALLBACK_COOLDOWN_MS"),e=o("TOOLNET_LLM_MAX_RETRIES"),t=Number(r??6e4),n=Number(e??1);return{cooldownMs:Number.isFinite(t)&&t>=0?t:6e4,maxRetries:Number.isFinite(n)&&n>=0?Math.floor(n):1}}var E=class extends Error{status;constructor(e,t){super(e),this.name="AiHttpError",this.status=t}};async function y(r,e,t=3e4){let n=new AbortController,s=setTimeout(()=>n.abort(),t);s.unref?.();try{let a=await fetch(r,{...e,signal:n.signal}),i=await a.text();if(!a.ok){let l=i;try{let u=JSON.parse(i);l=u.error?.message??u.message??i}catch{}throw new E(l||`HTTP ${a.status}`,a.status)}return i.trim()?JSON.parse(i):{}}finally{clearTimeout(s)}}function _(r,e){return`${r.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`}var w=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(),n=this.config.apiKey?.trim();if(!t)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!n)throw new Error("cloudflare: API TOKEN is not configured");let s=this.model(),i=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${t}/ai/run`).replace(/\/+$/,"")}/${s}`,l=await y(i,{method:"POST",headers:{authorization:`Bearer ${n}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),u=l.result?.response?.trim();if(!u)throw new Error(l.errors?.[0]?.message??"cloudflare: empty model response");return{text:u,provider:"cloudflare",model:s}}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 O=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 n=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",s=this.model(),a=e.messages.filter(d=>d.role==="system"),i=e.messages.filter(d=>d.role!=="system").map(d=>({role:d.role==="assistant"?"model":"user",parts:[{text:d.content}]})),l=`${_(n,`models/${encodeURIComponent(s)}:generateContent`)}?key=${encodeURIComponent(t)}`,u=await y(l,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...a.length?{systemInstruction:{parts:[{text:a.map(d=>d.content).join(`
2
2
 
3
- `)}]}}:{},contents:i,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),p=u.candidates?.[0]?.content?.parts?.map(d=>d.text??"").join("").trim();if(!p)throw new Error("gemini: empty model response");return{text:p,provider:"gemini",model:s,usage:u.usageMetadata?{inputTokens:u.usageMetadata.promptTokenCount,outputTokens:u.usageMetadata.candidatesTokenCount,totalTokens:u.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 T=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(),n=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,...this.id==="alibaba"?{enable_thinking:!1}:{}})}),s=n.choices?.[0]?.message?.content?.trim();if(!s)throw new Error(`${this.id}: empty model response`);return{text:s,provider:this.id,model:t,usage:n.usage?{inputTokens:n.usage.prompt_tokens,outputTokens:n.usage.completion_tokens,totalTokens:n.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 H(r=$()){switch(g(r.id).transport){case"gemini":return new w(r);case"cloudflare":return new O(r);default:return new T(r)}}function re(r){return new Promise(e=>{setTimeout(e,r)})}function ne(r){if(r instanceof E){let t=r.status;return t===void 0||t===408||t===409||t===425||t===429?!0:t>=500}if(!(r instanceof Error))return!0;let e=r.message.toLowerCase();return e.includes("401")||e.includes("403")||e.includes("400")||e.includes("invalid api key")||e.includes("unauthorized")||e.includes("forbidden")?!1:e.includes("timeout")||e.includes("timed out")||e.includes("abort")||e.includes("network")||e.includes("fetch failed")||e.includes("econnreset")||e.includes("econnrefused")||e.includes("429")||e.includes("rate limit")||e.includes("500")||e.includes("502")||e.includes("503")||e.includes("504")}var S=class{id;config;providers;states=new Map;cooldownMs;maxRetries;constructor(e,t=[],n={}){this.id=e.config.id,this.config=e.config,this.cooldownMs=n.cooldownMs??6e4,this.maxRetries=Math.max(0,n.maxRetries??1),this.providers=[e,...t].map(s=>({provider:H(s.config),label:s.label}))}key(e){let t=this.providers[e];return`${e}:${t.provider.id}:${t.provider.config.model??""}`}state(e){let t=this.key(e),n=this.states.get(t);return n||(n={failures:0,cooldownUntil:0},this.states.set(t,n)),n}available(e){return this.state(e).cooldownUntil<=Date.now()}success(e){let t=this.state(e);t.failures=0,t.cooldownUntil=0,t.lastError=void 0}fail(e,t){let n=this.state(e);n.failures+=1,n.lastError=t instanceof Error?t.message:String(t),n.cooldownUntil=Date.now()+this.cooldownMs}async generate(e){let t=[];for(let n=0;n<this.providers.length;n+=1){if(!this.available(n)){t.push(`${this.providers[n].label}: cooldown`);continue}let s=this.providers[n];for(let a=0;a<=this.maxRetries;a+=1)try{let i=await s.provider.generate(e);return this.success(n),i}catch(i){let l=i instanceof Error?i.message:String(i),u=ne(i);if(t.push(`${s.label}: ${l}`),!u)throw i;if(a<this.maxRetries){await re(Math.min(250*2**a,2e3));continue}this.fail(n,i)}}throw new Error(`All ToolNet LLM providers failed: ${t.join(" | ")}`)}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:t.provider,model:t.model,message:"Fallback chain 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}}}status(){return this.providers.map((e,t)=>{let n=this.state(t);return{position:t,provider:e.provider.id,model:e.provider.config.model,cooldown:n.cooldownUntil>Date.now(),cooldownUntil:n.cooldownUntil||void 0,failures:n.failures,lastError:n.lastError}})}};function W(){let r=C(),e=G();return new S({label:`Primary (${r.llm.provider})`,config:{id:r.llm.provider,apiKey:r.llm.apiKey,baseUrl:r.llm.baseUrl,model:r.llm.model,accountId:r.llm.accountId}},e.map(t=>({label:`Fallback ${t.slot} (${t.config.provider})`,config:{id:t.config.provider,apiKey:t.config.apiKey,baseUrl:t.config.baseUrl,model:t.config.model,accountId:t.config.accountId}})),Y())}var L=class{constructor(e=W()){this.provider=e}provider;get activeProvider(){return this.provider}setProvider(e){this.provider=e}generate(e){return this.provider.generate(e)}};function V(){return new L(W())}import{existsSync as pe,readFileSync as me}from"node:fs";import{join as fe}from"node:path";import{existsSync as oe,mkdirSync as _t,readFileSync as se,renameSync as Ot,writeFileSync as wt}from"node:fs";import{dirname as St,join as ie}from"node:path";function ae(r){return ie(r.rootPath,".toolnet","work","current.json")}function I(r){let e=ae(r);if(!oe(e))return null;try{let t=JSON.parse(se(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}import{existsSync as ce,mkdirSync as Mt,readFileSync as le,renameSync as Pt,writeFileSync as Rt}from"node:fs";import{dirname as Lt,join as ue}from"node:path";function de(r){return ue(r.rootPath,".toolnet","context","session-origin.json")}function x(r){let e=de(r);if(!ce(e))return null;try{let t=JSON.parse(le(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function ge(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function he(r){let e=ge(r),t=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(e),n=/(?:đang làm gì|làm tới đâu|dừng ở đâu|dở ở đâu|stopped where|working on|current task|file nào|last touched|làm gì tiếp|next action|next step)/u.test(e);return t&&n?"summary":/(?:agent trước là ai|previous agent|ai trước là ai|phiên trước là ai)/u.test(e)?"previous_agent":/(?:task hiện tại|current task|đang làm gì|đang làm task nào|dở ở đâu|dừng ở đâu|stopped where)/u.test(e)?"current_task":/(?:tiếp theo|next action|next step|làm gì tiếp|phải làm gì tiếp)/u.test(e)?"next_action":/(?:file cuối|last file|file nào|đang sửa file|last touched)/u.test(e)?"last_file":/(?:blocker|vướng|kẹt|lỗi gì|blocked)/u.test(e)?"blocker":/(?:decision|quyết định|đã chốt|important decision)/u.test(e)?"decision":/(?:đã xong|completed|hoàn thành|done|todo nào xong)/u.test(e)?"completed":/(?:status|trạng thái|tiến độ|progress)/u.test(e)?"status":"summary"}function ye(r){let e=fe(r.rootPath,".toolnet","context","handoff.md");if(!pe(e))return null;try{let t=me(e,"utf8").trim();return t||null}catch{return null}}function Ae(r,e=5){return r.slice(0,e).map(t=>`- ${t}`).join(`
4
- `)}function N(r,e){let t=he(e),n=x(r),s=I(r);switch(t){case"previous_agent":{if(n)return{intent:t,answer:`Agent tr\u01B0\u1EDBc l\xE0 ${n.agent}. Session: ${n.nativeSessionId}.`,source:"session-origin"};break}case"current_task":{if(n?.currentTask){let i=[`Task hi\u1EC7n t\u1EA1i: ${n.currentTask}.`];return n.lastTouchedFile&&i.push(`File g\u1EA7n nh\u1EA5t: ${n.lastTouchedFile}.`),n.latestNextAction&&i.push(`Ti\u1EBFp theo: ${n.latestNextAction}.`),{intent:t,answer:i.join(" "),source:"session-origin"}}if(s?.currentTask)return{intent:t,answer:`Task hi\u1EC7n t\u1EA1i: ${s.currentTask.title} (${s.currentTask.status}).`,source:"work-state"};break}case"next_action":{let i=n?.latestNextAction??s?.nextActions?.[0];if(i)return{intent:t,answer:`Vi\u1EC7c n\xEAn l\xE0m ti\u1EBFp: ${i}.`,source:n?.latestNextAction?"session-origin":"work-state"};break}case"last_file":{let i=n?.lastTouchedFile??s?.filesTouched?.at(-1);if(i)return{intent:t,answer:`File g\u1EA7n nh\u1EA5t \u0111\u01B0\u1EE3c nh\u1EAFc ho\u1EB7c s\u1EEDa: ${i}.`,source:n?.lastTouchedFile?"session-origin":"work-state"};break}case"blocker":{let i=n?.latestBlocker??s?.blockers?.at(-1);return i?{intent:t,answer:`Blocker hi\u1EC7n t\u1EA1i: ${i}.`,source:n?.latestBlocker?"session-origin":"work-state"}:{intent:t,answer:"Hi\u1EC7n ToolNet ch\u01B0a ghi nh\u1EADn blocker n\xE0o.",source:s?"work-state":"none"}}case"decision":{let i=n?.latestDecision??s?.decisions?.at(-1);if(i)return{intent:t,answer:`Quy\u1EBFt \u0111\u1ECBnh g\u1EA7n nh\u1EA5t: ${i}.`,source:n?.latestDecision?"session-origin":"work-state"};break}case"completed":{let i=s?.tasks?.filter(l=>l.status==="completed").map(l=>l.title)??[];if(i.length)return{intent:t,answer:`C\xE1c task \u0111\xE3 ho\xE0n th\xE0nh:
3
+ `)}]}}:{},contents:i,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),p=u.candidates?.[0]?.content?.parts?.map(d=>d.text??"").join("").trim();if(!p)throw new Error("gemini: empty model response");return{text:p,provider:"gemini",model:s,usage:u.usageMetadata?{inputTokens:u.usageMetadata.promptTokenCount,outputTokens:u.usageMetadata.candidatesTokenCount,totalTokens:u.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 T=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(),n=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,...this.id==="alibaba"?{enable_thinking:!1}:{}})}),s=n.choices?.[0]?.message?.content?.trim();if(!s)throw new Error(`${this.id}: empty model response`);return{text:s,provider:this.id,model:t,usage:n.usage?{inputTokens:n.usage.prompt_tokens,outputTokens:n.usage.completion_tokens,totalTokens:n.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 H(r=$()){switch(g(r.id).transport){case"gemini":return new O(r);case"cloudflare":return new w(r);default:return new T(r)}}function re(r){return new Promise(e=>{setTimeout(e,r)})}function ne(r){if(r instanceof E){let t=r.status;return t===void 0||t===408||t===409||t===425||t===429?!0:t>=500}if(!(r instanceof Error))return!0;let e=r.message.toLowerCase();return e.includes("401")||e.includes("403")||e.includes("400")||e.includes("invalid api key")||e.includes("unauthorized")||e.includes("forbidden")?!1:e.includes("timeout")||e.includes("timed out")||e.includes("abort")||e.includes("network")||e.includes("fetch failed")||e.includes("econnreset")||e.includes("econnrefused")||e.includes("429")||e.includes("rate limit")||e.includes("500")||e.includes("502")||e.includes("503")||e.includes("504")}var I=class{id;config;providers;states=new Map;cooldownMs;maxRetries;constructor(e,t=[],n={}){this.id=e.config.id,this.config=e.config,this.cooldownMs=n.cooldownMs??6e4,this.maxRetries=Math.max(0,n.maxRetries??1),this.providers=[e,...t].map(s=>({provider:H(s.config),label:s.label}))}key(e){let t=this.providers[e];return`${e}:${t.provider.id}:${t.provider.config.model??""}`}state(e){let t=this.key(e),n=this.states.get(t);return n||(n={failures:0,cooldownUntil:0},this.states.set(t,n)),n}available(e){return this.state(e).cooldownUntil<=Date.now()}success(e){let t=this.state(e);t.failures=0,t.cooldownUntil=0,t.lastError=void 0}fail(e,t){let n=this.state(e);n.failures+=1,n.lastError=t instanceof Error?t.message:String(t),n.cooldownUntil=Date.now()+this.cooldownMs}async generate(e){let t=[];for(let n=0;n<this.providers.length;n+=1){if(!this.available(n)){t.push(`${this.providers[n].label}: cooldown`);continue}let s=this.providers[n];for(let a=0;a<=this.maxRetries;a+=1)try{let i=await s.provider.generate(e);return this.success(n),i}catch(i){let l=i instanceof Error?i.message:String(i),u=ne(i);if(t.push(`${s.label}: ${l}`),!u)throw i;if(a<this.maxRetries){await re(Math.min(250*2**a,2e3));continue}this.fail(n,i)}}throw new Error(`All ToolNet LLM providers failed: ${t.join(" | ")}`)}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:t.provider,model:t.model,message:"Fallback chain 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}}}status(){return this.providers.map((e,t)=>{let n=this.state(t);return{position:t,provider:e.provider.id,model:e.provider.config.model,cooldown:n.cooldownUntil>Date.now(),cooldownUntil:n.cooldownUntil||void 0,failures:n.failures,lastError:n.lastError}})}};function W(){let r=C(),e=G();return new I({label:`Primary (${r.llm.provider})`,config:{id:r.llm.provider,apiKey:r.llm.apiKey,baseUrl:r.llm.baseUrl,model:r.llm.model,accountId:r.llm.accountId}},e.map(t=>({label:`Fallback ${t.slot} (${t.config.provider})`,config:{id:t.config.provider,apiKey:t.config.apiKey,baseUrl:t.config.baseUrl,model:t.config.model,accountId:t.config.accountId}})),Y())}var N=class{constructor(e=W()){this.provider=e}provider;get activeProvider(){return this.provider}setProvider(e){this.provider=e}generate(e){return this.provider.generate(e)}};function V(){return new N(W())}import{existsSync as pe,readFileSync as me}from"node:fs";import{join as fe}from"node:path";import{existsSync as oe,mkdirSync as _t,readFileSync as se,renameSync as wt,writeFileSync as Ot}from"node:fs";import{dirname as It,join as ie}from"node:path";function ae(r){return ie(r.rootPath,".toolnet","work","current.json")}function S(r){let e=ae(r);if(!oe(e))return null;try{let t=JSON.parse(se(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}import{existsSync as ce,mkdirSync as Mt,readFileSync as le,renameSync as Pt,writeFileSync as Rt}from"node:fs";import{dirname as Nt,join as ue}from"node:path";function de(r){return ue(r.rootPath,".toolnet","context","session-origin.json")}function x(r){let e=de(r);if(!ce(e))return null;try{let t=JSON.parse(le(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function ge(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function he(r){let e=ge(r),t=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(e),n=/(?:đang làm gì|làm tới đâu|dừng ở đâu|dở ở đâu|stopped where|working on|current task|file nào|last touched|làm gì tiếp|next action|next step)/u.test(e);return t&&n?"summary":/(?:agent trước là ai|previous agent|ai trước là ai|phiên trước là ai)/u.test(e)?"previous_agent":/(?:task hiện tại|current task|đang làm gì|đang làm task nào|dở ở đâu|dừng ở đâu|stopped where)/u.test(e)?"current_task":/(?:tiếp theo|next action|next step|làm gì tiếp|phải làm gì tiếp)/u.test(e)?"next_action":/(?:file cuối|last file|file nào|đang sửa file|last touched)/u.test(e)?"last_file":/(?:blocker|vướng|kẹt|lỗi gì|blocked)/u.test(e)?"blocker":/(?:decision|quyết định|đã chốt|important decision)/u.test(e)?"decision":/(?:đã xong|completed|hoàn thành|done|todo nào xong)/u.test(e)?"completed":/(?:status|trạng thái|tiến độ|progress)/u.test(e)?"status":"summary"}function ye(r){let e=fe(r.rootPath,".toolnet","context","handoff.md");if(!pe(e))return null;try{let t=me(e,"utf8").trim();return t||null}catch{return null}}function Ae(r,e=5){return r.slice(0,e).map(t=>`- ${t}`).join(`
4
+ `)}function L(r,e){let t=he(e),n=x(r),s=S(r);switch(t){case"previous_agent":{if(n)return{intent:t,answer:`Agent tr\u01B0\u1EDBc l\xE0 ${n.agent}. Session: ${n.nativeSessionId}.`,source:"session-origin"};break}case"current_task":{if(n?.currentTask){let i=[`Task hi\u1EC7n t\u1EA1i: ${n.currentTask}.`];return n.lastTouchedFile&&i.push(`File g\u1EA7n nh\u1EA5t: ${n.lastTouchedFile}.`),n.latestNextAction&&i.push(`Ti\u1EBFp theo: ${n.latestNextAction}.`),{intent:t,answer:i.join(" "),source:"session-origin"}}if(s?.currentTask)return{intent:t,answer:`Task hi\u1EC7n t\u1EA1i: ${s.currentTask.title} (${s.currentTask.status}).`,source:"work-state"};break}case"next_action":{let i=n?.latestNextAction??s?.nextActions?.[0];if(i)return{intent:t,answer:`Vi\u1EC7c n\xEAn l\xE0m ti\u1EBFp: ${i}.`,source:n?.latestNextAction?"session-origin":"work-state"};break}case"last_file":{let i=n?.lastTouchedFile??s?.filesTouched?.at(-1);if(i)return{intent:t,answer:`File g\u1EA7n nh\u1EA5t \u0111\u01B0\u1EE3c nh\u1EAFc ho\u1EB7c s\u1EEDa: ${i}.`,source:n?.lastTouchedFile?"session-origin":"work-state"};break}case"blocker":{let i=n?.latestBlocker??s?.blockers?.at(-1);return i?{intent:t,answer:`Blocker hi\u1EC7n t\u1EA1i: ${i}.`,source:n?.latestBlocker?"session-origin":"work-state"}:{intent:t,answer:"Hi\u1EC7n ToolNet ch\u01B0a ghi nh\u1EADn blocker n\xE0o.",source:s?"work-state":"none"}}case"decision":{let i=n?.latestDecision??s?.decisions?.at(-1);if(i)return{intent:t,answer:`Quy\u1EBFt \u0111\u1ECBnh g\u1EA7n nh\u1EA5t: ${i}.`,source:n?.latestDecision?"session-origin":"work-state"};break}case"completed":{let i=s?.tasks?.filter(l=>l.status==="completed").map(l=>l.title)??[];if(i.length)return{intent:t,answer:`C\xE1c task \u0111\xE3 ho\xE0n th\xE0nh:
5
5
  ${Ae(i,8)}`,source:"work-state"};break}case"status":{if(s){let i=[`Progress: ${s.progress.tasksCompleted}/${s.progress.tasksTotal} task ho\xE0n th\xE0nh.`];return s.currentTask&&i.push(`\u0110ang l\xE0m: ${s.currentTask.title}.`),s.progress.blocked>0&&i.push(`Blocked: ${s.progress.blocked}.`),{intent:t,answer:i.join(" "),source:"work-state"}}break}case"summary":{if(n||s){let i=[];n&&i.push(`Agent tr\u01B0\u1EDBc: ${n.agent}.`);let l=n?.currentTask??s?.currentTask?.title;l&&i.push(`Task hi\u1EC7n t\u1EA1i: ${l}.`);let u=n?.lastTouchedFile??s?.filesTouched?.at(-1);u&&i.push(`File g\u1EA7n nh\u1EA5t: ${u}.`);let p=n?.latestNextAction??s?.nextActions?.[0];p&&i.push(`Ti\u1EBFp theo: ${p}.`);let d=n?.latestBlocker??s?.blockers?.at(-1);d&&i.push(`Blocker: ${d}.`);let m=n?.latestDecision??s?.decisions?.at(-1);return m&&i.push(`Quy\u1EBFt \u0111\u1ECBnh g\u1EA7n nh\u1EA5t: ${m}.`),{intent:t,answer:i.join(" "),source:n?"session-origin":"work-state"}}break}}let a=ye(r);if(a){let i=a.length>900?`${a.slice(0,900)}
6
6
  [truncated]`:a;return{intent:t,answer:i,source:"handoff"}}return{intent:t,answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",source:"none"}}function ke(r,e){let t=JSON.stringify(r,null,2);return t.length<=e?t:t.slice(0,e)+`
7
- [truncated]`}function Ee(r,e){let t=N(r,e),n=x(r),s=I(r),a={project:{id:r.id,name:r.name},directAnswer:t.answer,previousSession:n,workState:s?{goal:s.goal,plan:s.plan,currentPhase:s.currentPhase,currentTask:s.currentTask,tasks:s.tasks,blockers:s.blockers,decisions:s.decisions,nextActions:s.nextActions,filesTouched:s.filesTouched,tests:s.tests,progress:s.progress,lastSession:s.lastSession}:null};return ke(a,7e3)}async function z(r,e){let t=N(r,e),n=Ee(r,e),s=V();try{let a=await s.generate({temperature:.1,maxTokens:450,messages:[{role:"system",content:`
7
+ [truncated]`}function Ee(r,e){let t=L(r,e),n=x(r),s=S(r),a={project:{id:r.id,name:r.name},directAnswer:t.answer,previousSession:n,workState:s?{goal:s.goal,plan:s.plan,currentPhase:s.currentPhase,currentTask:s.currentTask,tasks:s.tasks,blockers:s.blockers,decisions:s.decisions,nextActions:s.nextActions,filesTouched:s.filesTouched,tests:s.tests,progress:s.progress,lastSession:s.lastSession}:null};return ke(a,7e3)}async function z(r,e){let t=L(r,e),n=Ee(r,e),s=V();try{let a=await s.generate({temperature:.1,maxTokens:450,messages:[{role:"system",content:`
8
8
  You are ToolNet Memory Agent.
9
9
 
10
10
  You are NOT the coding agent.
@@ -41,9 +41,9 @@ ToolNet selected memory:
41
41
  ${n}
42
42
 
43
43
  Answer the coding agent directly.
44
- `.trim()}]}),i=a.text.trim();return i?{answer:i,provider:a.provider,model:a.model,usedAi:!0}:{answer:t.answer,usedAi:!1}}catch{return{answer:t.answer,usedAi:!1}}}import{existsSync as be,readFileSync as ve}from"node:fs";import{homedir as _e}from"node:os";import{join as Oe}from"node:path";function we(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
45
- `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Te(){let r=process.env.TOOLNET_GLOBAL_ENV??Oe(_e(),".config","toolnet-memory",".env");if(!be(r))return;let e=ve(r,"utf8");for(let t of e.split(/\r?\n/)){let n=t.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let s=n.indexOf("=");if(s<=0)continue;let a=n.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(a)&&process.env[a]===void 0&&(process.env[a]=we(n.slice(s+1)))}}Te();import{createHash as Se}from"node:crypto";import{existsSync as D,mkdirSync as Ie,readFileSync as xe,renameSync as Me,writeFileSync as Pe}from"node:fs";import{basename as Re,dirname as M,join as R,parse as Q,resolve as b}from"node:path";var Z=".toolnet",Ce="project.json";function Le(r){return Se("sha256").update(r).digest("hex").slice(0,16)}function U(r){return R(r,Z,Ce)}function Ne(r){return D(U(r))}function De(r,e){let t=b(r),n=Q(t).root;for(;;){if(Ne(t))return t;if(t===n||e&&t===b(e))break;let s=M(t);if(s===t)break;t=s}return null}function Ue(r){let e=b(r),t=Q(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(a=>D(R(e,a))))return e;if(e===t)break;let s=M(e);if(s===e)break;e=s}return b(r)}function je(r){let e;try{e=JSON.parse(xe(r,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${r}: ${s instanceof Error?s.message:String(s)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:M(M(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:n,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:n,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function J(r,e){let t=R(r,Z);Ie(t,{recursive:!0});let n=U(r),s=`${n}.tmp-${process.pid}`;Pe(s,JSON.stringify(e,null,2)+`
46
- `,{encoding:"utf8",mode:384}),Me(s,n)}function q(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var P=class{detect(e=process.cwd()){let t=b(e),n=Ue(t),a=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>D(R(n,d))),i=De(t,a?n:void 0);if(i){let d=U(i),m=je(d);return m.rootPath!==i&&(m.rootPath=i,m.updatedAt=new Date().toISOString(),J(i,m)),q(m,i)}let l=new Date().toISOString(),u=Re(n),p={version:1,id:Le(n),name:u,remote:u,rootPath:n,createdAt:l,updatedAt:l,graphVersion:0,memoryVersion:0};return J(n,p),q(p,n)}};async function Ke(){let r=process.argv.slice(2).join(" ").trim();if(!r){console.error('Usage: toolnet-memory ask-ai "<question>"'),process.exitCode=1;return}let e=j(process.cwd());if(!e){console.error("Not in a ToolNet project."),process.exitCode=1;return}let t=new P().detect(e);if(!t){console.error("Unable to detect ToolNet project."),process.exitCode=1;return}let n=await z(t,r);process.stdout.write(`${n.answer}
44
+ `.trim()}]}),i=a.text.trim();return i?{answer:i,provider:a.provider,model:a.model,usedAi:!0}:{answer:t.answer,usedAi:!1}}catch{return{answer:t.answer,usedAi:!1}}}import{existsSync as ve,readFileSync as be}from"node:fs";import{homedir as _e}from"node:os";import{join as we}from"node:path";function Oe(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
45
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Te(){let r=process.env.TOOLNET_GLOBAL_ENV??we(_e(),".config","toolnet-memory",".env");if(!ve(r))return;let e=be(r,"utf8");for(let t of e.split(/\r?\n/)){let n=t.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let s=n.indexOf("=");if(s<=0)continue;let a=n.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(a)&&process.env[a]===void 0&&(process.env[a]=Oe(n.slice(s+1)))}}Te();import{createHash as Ie}from"node:crypto";import{existsSync as D,mkdirSync as Se,readFileSync as xe,renameSync as Me,writeFileSync as Pe}from"node:fs";import{basename as Re,dirname as M,join as R,parse as Q,resolve as v}from"node:path";var Z=".toolnet",Ce="project.json";function Ne(r){return Ie("sha256").update(r).digest("hex").slice(0,16)}function j(r){return R(r,Z,Ce)}function Le(r){return D(j(r))}function De(r,e){let t=v(r),n=Q(t).root;for(;;){if(Le(t))return t;if(t===n||e&&t===v(e))break;let s=M(t);if(s===t)break;t=s}return null}function je(r){let e=v(r),t=Q(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(a=>D(R(e,a))))return e;if(e===t)break;let s=M(e);if(s===e)break;e=s}return v(r)}function Ue(r){let e;try{e=JSON.parse(xe(r,"utf8"))}catch(s){throw new Error(`Invalid ToolNet project manifest: ${r}: ${s instanceof Error?s.message:String(s)}`)}if(!e||typeof e!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let t=e;if(typeof t.id!="string"||!t.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof t.name!="string"||!t.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:t.id,name:t.name,remote:typeof t.remote=="string"&&t.remote.trim()?t.remote:t.name,rootPath:typeof t.rootPath=="string"?t.rootPath:M(M(r)),createdAt:typeof t.createdAt=="string"?t.createdAt:n,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:n,graphVersion:typeof t.graphVersion=="number"?t.graphVersion:0,memoryVersion:typeof t.memoryVersion=="number"?t.memoryVersion:0,metadata:t.metadata&&typeof t.metadata=="object"?t.metadata:void 0}}function J(r,e){let t=R(r,Z);Se(t,{recursive:!0});let n=j(r),s=`${n}.tmp-${process.pid}`;Pe(s,JSON.stringify(e,null,2)+`
46
+ `,{encoding:"utf8",mode:384}),Me(s,n)}function q(r,e){return{id:r.id,name:r.name,remote:r.remote,rootPath:e,createdAt:r.createdAt,updatedAt:r.updatedAt,graphVersion:r.graphVersion,memoryVersion:r.memoryVersion,metadata:r.metadata}}var P=class{detect(e=process.cwd()){let t=v(e),n=je(t),a=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>D(R(n,d))),i=De(t,a?n:void 0);if(i){let d=j(i),m=Ue(d);return m.rootPath!==i&&(m.rootPath=i,m.updatedAt=new Date().toISOString(),J(i,m)),q(m,i)}let l=new Date().toISOString(),u=Re(n),p={version:1,id:Ne(n),name:u,remote:u,rootPath:n,createdAt:l,updatedAt:l,graphVersion:0,memoryVersion:0};return J(n,p),q(p,n)}};async function Fe(){let r=process.argv.slice(2).join(" ").trim();if(!r){console.error('Usage: toolnet-memory ask-ai "<question>"'),process.exitCode=1;return}let e=U(process.cwd());if(!e){console.error("Not in a ToolNet project."),process.exitCode=1;return}let t=new P().detect(e);if(!t){console.error("Unable to detect ToolNet project."),process.exitCode=1;return}let n=await z(t,r);process.stdout.write(`${n.answer}
47
47
  `),process.env.TOOLNET_MEMORY_AGENT_DEBUG==="1"&&process.stderr.write(["",`[ToolNet Memory Agent] AI: ${n.usedAi?"yes":"fallback"}`,n.provider?`Provider: ${n.provider}`:"",n.model?`Model: ${n.model}`:""].filter(Boolean).join(`
48
48
  `)+`
49
- `)}Ke().catch(r=>{console.error(r instanceof Error?r.message:String(r)),process.exitCode=1});
49
+ `)}Fe().catch(r=>{console.error(r instanceof Error?r.message:String(r)),process.exitCode=1});
@@ -1,7 +1,7 @@
1
- import*as d from"fs";import*as u from"path";function x(r){let t=u.resolve(r),e=u.parse(t).root;for(;t!==e;){let n=u.join(t,".toolnet");if(d.existsSync(n)&&d.statSync(n).isDirectory())return t;t=u.dirname(t)}return null}import{existsSync as $,readFileSync as F}from"node:fs";import{join as D}from"node:path";import{existsSync as C,mkdirSync as be,readFileSync as I,renameSync as Ae,writeFileSync as Me}from"node:fs";import{dirname as Ee,join as j}from"node:path";function _(r){return j(r.rootPath,".toolnet","work","current.json")}function w(r){let t=_(r);if(!C(t))return null;try{let e=JSON.parse(I(t,"utf8"));return e.version!==1||e.projectId!==r.id?null:e}catch{return null}}import{existsSync as R,mkdirSync as je,readFileSync as O,renameSync as _e,writeFileSync as Re}from"node:fs";import{dirname as Pe,join as P}from"node:path";function N(r){return P(r.rootPath,".toolnet","context","session-origin.json")}function T(r){let t=N(r);if(!R(t))return null;try{let e=JSON.parse(O(t,"utf8"));return e.version!==1||e.projectId!==r.id?null:e}catch{return null}}function L(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function W(r){let t=L(r),e=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(t),n=/(?:đang làm gì|làm tới đâu|dừng ở đâu|dở ở đâu|stopped where|working on|current task|file nào|last touched|làm gì tiếp|next action|next step)/u.test(t);return e&&n?"summary":/(?:agent trước là ai|previous agent|ai trước là ai|phiên trước là ai)/u.test(t)?"previous_agent":/(?:task hiện tại|current task|đang làm gì|đang làm task nào|dở ở đâu|dừng ở đâu|stopped where)/u.test(t)?"current_task":/(?:tiếp theo|next action|next step|làm gì tiếp|phải làm gì tiếp)/u.test(t)?"next_action":/(?:file cuối|last file|file nào|đang sửa file|last touched)/u.test(t)?"last_file":/(?:blocker|vướng|kẹt|lỗi gì|blocked)/u.test(t)?"blocker":/(?:decision|quyết định|đã chốt|important decision)/u.test(t)?"decision":/(?:đã xong|completed|hoàn thành|done|todo nào xong)/u.test(t)?"completed":/(?:status|trạng thái|tiến độ|progress)/u.test(t)?"status":"summary"}function B(r){let t=D(r.rootPath,".toolnet","context","handoff.md");if(!$(t))return null;try{let e=F(t,"utf8").trim();return e||null}catch{return null}}function K(r,t=5){return r.slice(0,t).map(e=>`- ${e}`).join(`
1
+ import*as d from"fs";import*as u from"path";function x(r){let t=u.resolve(r),e=u.parse(t).root;for(;t!==e;){let n=u.join(t,".toolnet");if(d.existsSync(n)&&d.statSync(n).isDirectory())return t;t=u.dirname(t)}return null}import{existsSync as F,readFileSync as $}from"node:fs";import{join as D}from"node:path";import{existsSync as j,mkdirSync as be,readFileSync as C,renameSync as Ae,writeFileSync as ve}from"node:fs";import{dirname as Ee,join as I}from"node:path";function R(r){return I(r.rootPath,".toolnet","work","current.json")}function w(r){let t=R(r);if(!j(t))return null;try{let e=JSON.parse(C(t,"utf8"));return e.version!==1||e.projectId!==r.id?null:e}catch{return null}}import{existsSync as _,mkdirSync as Ie,readFileSync as O,renameSync as Re,writeFileSync as _e}from"node:fs";import{dirname as Ne,join as N}from"node:path";function P(r){return N(r.rootPath,".toolnet","context","session-origin.json")}function T(r){let t=P(r);if(!_(t))return null;try{let e=JSON.parse(O(t,"utf8"));return e.version!==1||e.projectId!==r.id?null:e}catch{return null}}function L(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function W(r){let t=L(r),e=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(t),n=/(?:đang làm gì|làm tới đâu|dừng ở đâu|dở ở đâu|stopped where|working on|current task|file nào|last touched|làm gì tiếp|next action|next step)/u.test(t);return e&&n?"summary":/(?:agent trước là ai|previous agent|ai trước là ai|phiên trước là ai)/u.test(t)?"previous_agent":/(?:task hiện tại|current task|đang làm gì|đang làm task nào|dở ở đâu|dừng ở đâu|stopped where)/u.test(t)?"current_task":/(?:tiếp theo|next action|next step|làm gì tiếp|phải làm gì tiếp)/u.test(t)?"next_action":/(?:file cuối|last file|file nào|đang sửa file|last touched)/u.test(t)?"last_file":/(?:blocker|vướng|kẹt|lỗi gì|blocked)/u.test(t)?"blocker":/(?:decision|quyết định|đã chốt|important decision)/u.test(t)?"decision":/(?:đã xong|completed|hoàn thành|done|todo nào xong)/u.test(t)?"completed":/(?:status|trạng thái|tiến độ|progress)/u.test(t)?"status":"summary"}function B(r){let t=D(r.rootPath,".toolnet","context","handoff.md");if(!F(t))return null;try{let e=$(t,"utf8").trim();return e||null}catch{return null}}function K(r,t=5){return r.slice(0,t).map(e=>`- ${e}`).join(`
2
2
  `)}function b(r,t){let e=W(t),n=T(r),o=w(r);switch(e){case"previous_agent":{if(n)return{intent:e,answer:`Agent tr\u01B0\u1EDBc l\xE0 ${n.agent}. Session: ${n.nativeSessionId}.`,source:"session-origin"};break}case"current_task":{if(n?.currentTask){let s=[`Task hi\u1EC7n t\u1EA1i: ${n.currentTask}.`];return n.lastTouchedFile&&s.push(`File g\u1EA7n nh\u1EA5t: ${n.lastTouchedFile}.`),n.latestNextAction&&s.push(`Ti\u1EBFp theo: ${n.latestNextAction}.`),{intent:e,answer:s.join(" "),source:"session-origin"}}if(o?.currentTask)return{intent:e,answer:`Task hi\u1EC7n t\u1EA1i: ${o.currentTask.title} (${o.currentTask.status}).`,source:"work-state"};break}case"next_action":{let s=n?.latestNextAction??o?.nextActions?.[0];if(s)return{intent:e,answer:`Vi\u1EC7c n\xEAn l\xE0m ti\u1EBFp: ${s}.`,source:n?.latestNextAction?"session-origin":"work-state"};break}case"last_file":{let s=n?.lastTouchedFile??o?.filesTouched?.at(-1);if(s)return{intent:e,answer:`File g\u1EA7n nh\u1EA5t \u0111\u01B0\u1EE3c nh\u1EAFc ho\u1EB7c s\u1EEDa: ${s}.`,source:n?.lastTouchedFile?"session-origin":"work-state"};break}case"blocker":{let s=n?.latestBlocker??o?.blockers?.at(-1);return s?{intent:e,answer:`Blocker hi\u1EC7n t\u1EA1i: ${s}.`,source:n?.latestBlocker?"session-origin":"work-state"}:{intent:e,answer:"Hi\u1EC7n ToolNet ch\u01B0a ghi nh\u1EADn blocker n\xE0o.",source:o?"work-state":"none"}}case"decision":{let s=n?.latestDecision??o?.decisions?.at(-1);if(s)return{intent:e,answer:`Quy\u1EBFt \u0111\u1ECBnh g\u1EA7n nh\u1EA5t: ${s}.`,source:n?.latestDecision?"session-origin":"work-state"};break}case"completed":{let s=o?.tasks?.filter(c=>c.status==="completed").map(c=>c.title)??[];if(s.length)return{intent:e,answer:`C\xE1c task \u0111\xE3 ho\xE0n th\xE0nh:
3
3
  ${K(s,8)}`,source:"work-state"};break}case"status":{if(o){let s=[`Progress: ${o.progress.tasksCompleted}/${o.progress.tasksTotal} task ho\xE0n th\xE0nh.`];return o.currentTask&&s.push(`\u0110ang l\xE0m: ${o.currentTask.title}.`),o.progress.blocked>0&&s.push(`Blocked: ${o.progress.blocked}.`),{intent:e,answer:s.join(" "),source:"work-state"}}break}case"summary":{if(n||o){let s=[];n&&s.push(`Agent tr\u01B0\u1EDBc: ${n.agent}.`);let c=n?.currentTask??o?.currentTask?.title;c&&s.push(`Task hi\u1EC7n t\u1EA1i: ${c}.`);let f=n?.lastTouchedFile??o?.filesTouched?.at(-1);f&&s.push(`File g\u1EA7n nh\u1EA5t: ${f}.`);let p=n?.latestNextAction??o?.nextActions?.[0];p&&s.push(`Ti\u1EBFp theo: ${p}.`);let l=n?.latestBlocker??o?.blockers?.at(-1);l&&s.push(`Blocker: ${l}.`);let a=n?.latestDecision??o?.decisions?.at(-1);return a&&s.push(`Quy\u1EBFt \u0111\u1ECBnh g\u1EA7n nh\u1EA5t: ${a}.`),{intent:e,answer:s.join(" "),source:n?"session-origin":"work-state"}}break}}let i=B(r);if(i){let s=i.length>900?`${i.slice(0,900)}
4
- [truncated]`:i;return{intent:e,answer:s,source:"handoff"}}return{intent:e,answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",source:"none"}}import{existsSync as z,readFileSync as H}from"node:fs";import{homedir as Y}from"node:os";import{join as V}from"node:path";function U(r){let t=r.trim();return t.length>=2&&t.startsWith('"')&&t.endsWith('"')?(t=t.slice(1,-1),t.replace(/\\n/g,`
5
- `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):t.length>=2&&t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function J(){let r=process.env.TOOLNET_GLOBAL_ENV??V(Y(),".config","toolnet-memory",".env");if(!z(r))return;let t=H(r,"utf8");for(let e of t.split(/\r?\n/)){let n=e.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let o=n.indexOf("=");if(o<=0)continue;let i=n.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=U(n.slice(o+1)))}}J();import{createHash as G}from"node:crypto";import{existsSync as k,mkdirSync as Q,readFileSync as Z,renameSync as q,writeFileSync as X}from"node:fs";import{basename as ee,dirname as g,join as y,parse as v,resolve as m}from"node:path";var E=".toolnet",te="project.json";function re(r){return G("sha256").update(r).digest("hex").slice(0,16)}function S(r){return y(r,E,te)}function ne(r){return k(S(r))}function oe(r,t){let e=m(r),n=v(e).root;for(;;){if(ne(e))return e;if(e===n||t&&e===m(t))break;let o=g(e);if(o===e)break;e=o}return null}function se(r){let t=m(r),e=v(t).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(i=>k(y(t,i))))return t;if(t===e)break;let o=g(t);if(o===t)break;t=o}return m(r)}function ie(r){let t;try{t=JSON.parse(Z(r,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${r}: ${o instanceof Error?o.message:String(o)}`)}if(!t||typeof t!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let e=t;if(typeof e.id!="string"||!e.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof e.name!="string"||!e.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:e.id,name:e.name,remote:typeof e.remote=="string"&&e.remote.trim()?e.remote:e.name,rootPath:typeof e.rootPath=="string"?e.rootPath:g(g(r)),createdAt:typeof e.createdAt=="string"?e.createdAt:n,updatedAt:typeof e.updatedAt=="string"?e.updatedAt:n,graphVersion:typeof e.graphVersion=="number"?e.graphVersion:0,memoryVersion:typeof e.memoryVersion=="number"?e.memoryVersion:0,metadata:e.metadata&&typeof e.metadata=="object"?e.metadata:void 0}}function A(r,t){let e=y(r,E);Q(e,{recursive:!0});let n=S(r),o=`${n}.tmp-${process.pid}`;X(o,JSON.stringify(t,null,2)+`
6
- `,{encoding:"utf8",mode:384}),q(o,n)}function M(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 h=class{detect(t=process.cwd()){let e=m(t),n=se(e),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(l=>k(y(n,l))),s=oe(e,i?n:void 0);if(s){let l=S(s),a=ie(l);return a.rootPath!==s&&(a.rootPath=s,a.updatedAt=new Date().toISOString(),A(s,a)),M(a,s)}let c=new Date().toISOString(),f=ee(n),p={version:1,id:re(n),name:f,remote:f,rootPath:n,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return A(n,p),M(p,n)}};function ce(){let r=process.argv.slice(2).join(" ").trim();if(!r){console.error('Usage: toolnet-memory ask "<question>"'),process.exitCode=1;return}let t=process.cwd(),e=x(t);if(!e){console.error("Not in a ToolNet project."),process.exitCode=1;return}let n=new h().detect(e);if(!n){console.error("Unable to detect ToolNet project."),process.exitCode=1;return}let o=b(n,r);process.stdout.write(`${o.answer}
4
+ [truncated]`:i;return{intent:e,answer:s,source:"handoff"}}return{intent:e,answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",source:"none"}}import{existsSync as z,readFileSync as H}from"node:fs";import{homedir as V}from"node:os";import{join as Y}from"node:path";function U(r){let t=r.trim();return t.length>=2&&t.startsWith('"')&&t.endsWith('"')?(t=t.slice(1,-1),t.replace(/\\n/g,`
5
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):t.length>=2&&t.startsWith("'")&&t.endsWith("'")?t.slice(1,-1):t}function J(){let r=process.env.TOOLNET_GLOBAL_ENV??Y(V(),".config","toolnet-memory",".env");if(!z(r))return;let t=H(r,"utf8");for(let e of t.split(/\r?\n/)){let n=e.trim();if(!n||n.startsWith("#"))continue;n.startsWith("export ")&&(n=n.slice(7));let o=n.indexOf("=");if(o<=0)continue;let i=n.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=U(n.slice(o+1)))}}J();import{createHash as G}from"node:crypto";import{existsSync as k,mkdirSync as Q,readFileSync as q,renameSync as Z,writeFileSync as X}from"node:fs";import{basename as ee,dirname as g,join as y,parse as M,resolve as m}from"node:path";var E=".toolnet",te="project.json";function re(r){return G("sha256").update(r).digest("hex").slice(0,16)}function S(r){return y(r,E,te)}function ne(r){return k(S(r))}function oe(r,t){let e=m(r),n=M(e).root;for(;;){if(ne(e))return e;if(e===n||t&&e===m(t))break;let o=g(e);if(o===e)break;e=o}return null}function se(r){let t=m(r),e=M(t).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(i=>k(y(t,i))))return t;if(t===e)break;let o=g(t);if(o===t)break;t=o}return m(r)}function ie(r){let t;try{t=JSON.parse(q(r,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${r}: ${o instanceof Error?o.message:String(o)}`)}if(!t||typeof t!="object")throw new Error(`Invalid ToolNet project manifest: ${r}`);let e=t;if(typeof e.id!="string"||!e.id.trim())throw new Error(`ToolNet project manifest is missing id: ${r}`);if(typeof e.name!="string"||!e.name.trim())throw new Error(`ToolNet project manifest is missing name: ${r}`);let n=new Date().toISOString();return{version:1,id:e.id,name:e.name,remote:typeof e.remote=="string"&&e.remote.trim()?e.remote:e.name,rootPath:typeof e.rootPath=="string"?e.rootPath:g(g(r)),createdAt:typeof e.createdAt=="string"?e.createdAt:n,updatedAt:typeof e.updatedAt=="string"?e.updatedAt:n,graphVersion:typeof e.graphVersion=="number"?e.graphVersion:0,memoryVersion:typeof e.memoryVersion=="number"?e.memoryVersion:0,metadata:e.metadata&&typeof e.metadata=="object"?e.metadata:void 0}}function A(r,t){let e=y(r,E);Q(e,{recursive:!0});let n=S(r),o=`${n}.tmp-${process.pid}`;X(o,JSON.stringify(t,null,2)+`
6
+ `,{encoding:"utf8",mode:384}),Z(o,n)}function v(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 h=class{detect(t=process.cwd()){let e=m(t),n=se(e),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(l=>k(y(n,l))),s=oe(e,i?n:void 0);if(s){let l=S(s),a=ie(l);return a.rootPath!==s&&(a.rootPath=s,a.updatedAt=new Date().toISOString(),A(s,a)),v(a,s)}let c=new Date().toISOString(),f=ee(n),p={version:1,id:re(n),name:f,remote:f,rootPath:n,createdAt:c,updatedAt:c,graphVersion:0,memoryVersion:0};return A(n,p),v(p,n)}};function ce(){let r=process.argv.slice(2).join(" ").trim();if(!r){console.error('Usage: toolnet-memory ask "<question>"'),process.exitCode=1;return}let t=process.cwd(),e=x(t);if(!e){console.error("Not in a ToolNet project."),process.exitCode=1;return}let n=new h().detect(e);if(!n){console.error("Unable to detect ToolNet project."),process.exitCode=1;return}let o=b(n,r);process.stdout.write(`${o.answer}
7
7
  `)}ce();