toolnet-memory 0.2.20 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,9 @@
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(`
1
+ import*as y from"fs";import*as g from"path";function U(r){let e=g.resolve(r),t=g.parse(e).root;for(;e!==t;){let n=g.join(e,".toolnet");if(y.existsSync(n)&&y.statSync(n).isDirectory())return e;e=g.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 h(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 l(...r){return r.find(e=>!!e?.trim())}function B(){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 G(){let r=o("TOOLNET_LLM_PROVIDER");return r&&A(r)?r:B()??"openai-compatible"}function M(r){let e=h(r);switch(r){case"alibaba":return{provider:r,apiKey:l(o("ALIBABA_API_KEY"),o("DASHSCOPE_API_KEY")),baseUrl:l(o("ALIBABA_BASE_URL"),o("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:l(o("ALIBABA_MODEL"),o("DASHSCOPE_MODEL"))};case"openrouter":return{provider:r,apiKey:o("OPENROUTER_API_KEY"),baseUrl:l(o("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:o("OPENROUTER_MODEL")};case"groq":return{provider:r,apiKey:o("GROQ_API_KEY"),baseUrl:l(o("GROQ_BASE_URL"),e.defaultBaseUrl),model:o("GROQ_MODEL")};case"deepseek":return{provider:r,apiKey:o("DEEPSEEK_API_KEY"),baseUrl:l(o("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:l(o("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:r,apiKey:l(o("NVIDIA_API_KEY"),o("NVIDIA_NIM_API_KEY")),baseUrl:l(o("NVIDIA_BASE_URL"),o("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:l(o("NVIDIA_MODEL"),o("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:r,apiKey:l(o("GEMINI_API_KEY"),o("GOOGLE_API_KEY")),baseUrl:l(o("GEMINI_BASE_URL"),e.defaultBaseUrl),model:o("GEMINI_MODEL")};case"huggingface":return{provider:r,apiKey:o("HF_TOKEN"),baseUrl:l(o("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:l(o("HF_LLM_MODEL"),o("HF_MODEL"))};case"ollama":return{provider:r,apiKey:o("OLLAMA_API_KEY"),baseUrl:l(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:l(o("OPENAI_API_KEY"),o("MODEL_API_KEY")),baseUrl:l(o("OPENAI_BASE_URL"),o("MODEL_BASE_URL")),model:l(o("OPENAI_MODEL"),o("MODEL_NAME"))}}}function se(){let r=o("TOOLNET_LLM_PROVIDER"),e=r&&A(r)?r:G(),t=h(e),n=M(e);return{provider:e,apiKey:l(o("TOOLNET_LLM_API_KEY"),n.apiKey),baseUrl:l(o("TOOLNET_LLM_BASE_URL"),n.baseUrl,t.defaultBaseUrl),model:l(o("TOOLNET_LLM_MODEL"),n.model,t.defaultModel),accountId:l(o("TOOLNET_LLM_ACCOUNT_ID"),n.accountId)}}function ie(){let r=o("TOOLNET_EMBEDDING_PROVIDER");return r==="local"?"local":r&&A(r)?r:o("HF_TOKEN")||o("HF_EMBEDDING_MODEL")?"huggingface":"local"}function ae(){let r=ie();if(r==="local")return{provider:"local",model:l(o("TOOLNET_EMBEDDING_MODEL"),o("LOCAL_EMBEDDING_MODEL"))};let e=h(r),t,n,s,i;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"),i=o("CLOUDFLARE_ACCOUNT_ID");break;default:t=M(r).apiKey,n=M(r).baseUrl,s=o(`${r.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let a=l(o("TOOLNET_EMBEDDING_ACCOUNT_ID"),i),f=l(o("TOOLNET_EMBEDDING_BASE_URL"),n,e.defaultBaseUrl),u=r==="cloudflare"&&!f&&a?`https://api.cloudflare.com/client/v4/accounts/${a}/ai/v1`:f;return{provider:r,apiKey:l(o("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:u,model:l(o("TOOLNET_EMBEDDING_MODEL"),s),accountId:a}}function P(){let r=se(),e=ae();return{llm:r,embedding:e,legacy:{llm:!o("TOOLNET_LLM_PROVIDER")&&!!B(),embedding:!o("TOOLNET_EMBEDDING_PROVIDER")&&!!(o("HF_TOKEN")||o("HF_EMBEDDING_MODEL"))}}}function H(r=G()){let e=P().llm;if(r===e.provider)return{id:r,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId};let t=M(r);return{id:r,apiKey:t.apiKey,baseUrl:t.baseUrl,model:t.model,accountId:t.accountId}}function v(r,e){return o(`TOOLNET_LLM_FALLBACK_${r}_${e}`)}function Y(){let r=[];for(let e of[1,2]){let t=v(e,"PROVIDER");if(!t||!A(t))continue;let n=h(t);r.push({slot:e,config:{provider:t,apiKey:v(e,"API_KEY"),baseUrl:l(v(e,"BASE_URL"),n.defaultBaseUrl),model:l(v(e,"MODEL"),n.defaultModel),accountId:v(e,"ACCOUNT_ID")}})}return r}function V(){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 b=class extends Error{status;constructor(e,t){super(e),this.name="AiHttpError",this.status=t}};async function k(r,e,t=3e4){let n=new AbortController,s=setTimeout(()=>n.abort(),t);s.unref?.();try{let i=await fetch(r,{...e,signal:n.signal}),a=await i.text();if(!i.ok){let f=a;try{let u=JSON.parse(a);f=u.error?.message??u.message??a}catch{}throw new b(f||`HTTP ${i.status}`,i.status)}return a.trim()?JSON.parse(a):{}}finally{clearTimeout(s)}}function x(r,e){return`${r.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`}var _=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(),a=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${t}/ai/run`).replace(/\/+$/,"")}/${s}`,f=await k(a,{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=f.result?.response?.trim();if(!u)throw new Error(f.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(),i=e.messages.filter(d=>d.role==="system"),a=e.messages.filter(d=>d.role!=="system").map(d=>({role:d.role==="assistant"?"model":"user",parts:[{text:d.content}]})),f=`${x(n,`models/${encodeURIComponent(s)}:generateContent`)}?key=${encodeURIComponent(t)}`,u=await k(f,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...i.length?{systemInstruction:{parts:[{text:i.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 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
- ${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
- [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=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:`
3
+ `)}]}}:{},contents:a,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),m=u.candidates?.[0]?.content?.parts?.map(d=>d.text??"").join("").trim();if(!m)throw new Error("gemini: empty model response");return{text:m,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 S=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 k(x(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 W(r=H()){switch(h(r.id).transport){case"gemini":return new w(r);case"cloudflare":return new _(r);default:return new S(r)}}function ce(r){return new Promise(e=>{setTimeout(e,r)})}function le(r){if(r instanceof b){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 O=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:W(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 i=0;i<=this.maxRetries;i+=1)try{let a=await s.provider.generate(e);return this.success(n),a}catch(a){let f=a instanceof Error?a.message:String(a),u=le(a);if(t.push(`${s.label}: ${f}`),!u)throw a;if(i<this.maxRetries){await ce(Math.min(250*2**i,2e3));continue}this.fail(n,a)}}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 z(){let r=P(),e=Y();return new O({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}})),V())}var N=class{constructor(e=z()){this.provider=e}provider;get activeProvider(){return this.provider}setProvider(e){this.provider=e}generate(e){return this.provider.generate(e)}};function J(){return new N(z())}import{existsSync as Ae,readFileSync as ve}from"node:fs";import{join as be}from"node:path";import{existsSync as ue,mkdirSync as Ht,readFileSync as de,renameSync as Yt,writeFileSync as Vt}from"node:fs";import{dirname as zt,join as fe}from"node:path";function pe(r){return fe(r.rootPath,".toolnet","work","current.json")}function L(r){let e=pe(r);if(!ue(e))return null;try{let t=JSON.parse(de(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}import{existsSync as me,mkdirSync as qt,readFileSync as ge,renameSync as Zt,writeFileSync as Xt}from"node:fs";import{dirname as tr,join as he}from"node:path";function ye(r){return he(r.rootPath,".toolnet","context","session-origin.json")}function D(r){let e=ye(r);if(!me(e))return null;try{let t=JSON.parse(ge(e,"utf8"));return t.version!==1||t.projectId!==r.id?null:t}catch{return null}}function ke(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function Q(r){let e=ke(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"}var Ee={previous_agent:{previous_agent:100,task:35,phase:25},current_task:{task:100,phase:75,file:65,next_action:55,blocker:45},next_action:{next_action:100,todo:80,task:65,blocker:60,file:40},last_file:{file:100,task:65,next_action:40},blocker:{blocker:100,task:60,next_action:50,file:35},decision:{decision:100,task:45,file:30},completed:{completed:100,progress:70,task:30},status:{progress:100,task:85,phase:75,blocker:65,next_action:60},summary:{task:100,next_action:95,file:90,blocker:85,previous_agent:80,phase:75,completed:60,todo:60,decision:55,progress:50,test:45,goal:35}},Me={handoff:18,"session-origin":14,"work-state":8};function xe(r){return r.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function c(r,e){let t=e.value.replace(/\s+/g," ").trim();t&&r.push({...e,value:t,score:0})}function _e(r){let e=be(r.rootPath,".toolnet","work","handoff-latest.json");if(!Ae(e))return null;try{let n=JSON.parse(ve(e,"utf8")).continuity;return n?.schema!=="toolnet.handoff.v2"||n.project.id!==r.id?null:n}catch{return null}}function we(r){let e=_e(r);if(!e)return[];let t=[];c(t,{kind:"previous_agent",value:e.source.agent,source:"handoff"}),e.goal&&c(t,{kind:"goal",value:e.goal,source:"handoff"}),e.current.phase&&c(t,{kind:"phase",value:e.current.phase.title,source:"handoff"}),e.current.task&&c(t,{kind:"task",value:e.current.task.title,source:"handoff"}),e.files.current&&c(t,{kind:"file",value:e.files.current,source:"handoff"}),e.nextAction&&c(t,{kind:"next_action",value:e.nextAction,source:"handoff"});for(let n of e.blockers)c(t,{kind:"blocker",value:n,source:"handoff"});for(let n of e.decisions)c(t,{kind:"decision",value:n,source:"handoff"});for(let n of e.completed.tasks)c(t,{kind:"completed",value:n,source:"handoff"});for(let n of e.remaining.todos)c(t,{kind:"todo",value:n,source:"handoff"});return c(t,{kind:"test",value:`Test status: ${e.tests.status}`,source:"handoff"}),c(t,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"handoff"}),t}function Se(r){let e=D(r);if(!e)return[];let t=[];return c(t,{kind:"previous_agent",value:e.agent,source:"session-origin"}),e.currentPhase&&c(t,{kind:"phase",value:e.currentPhase,source:"session-origin"}),e.currentTask&&c(t,{kind:"task",value:e.currentTask,source:"session-origin"}),e.lastTouchedFile&&c(t,{kind:"file",value:e.lastTouchedFile,source:"session-origin"}),e.latestNextAction&&c(t,{kind:"next_action",value:e.latestNextAction,source:"session-origin"}),e.latestBlocker&&c(t,{kind:"blocker",value:e.latestBlocker,source:"session-origin"}),e.latestDecision&&c(t,{kind:"decision",value:e.latestDecision,source:"session-origin"}),t}function Oe(r){let e=L(r);if(!e)return[];let t=[];e.goal&&c(t,{kind:"goal",value:e.goal,source:"work-state"}),e.currentPhase&&c(t,{kind:"phase",value:e.currentPhase.title,source:"work-state"}),e.currentTask&&c(t,{kind:"task",value:e.currentTask.title,source:"work-state"});let n=e.filesTouched.at(-1);n&&c(t,{kind:"file",value:n,source:"work-state"});for(let s of e.nextActions.slice(0,5))c(t,{kind:"next_action",value:s,source:"work-state"});for(let s of e.blockers.slice(-5))c(t,{kind:"blocker",value:s,source:"work-state"});for(let s of e.decisions.slice(-5))c(t,{kind:"decision",value:s,source:"work-state"});for(let s of e.tasks.filter(i=>i.status==="completed").slice(-8))c(t,{kind:"completed",value:s.title,source:"work-state"});for(let s of e.tasks.filter(i=>i.status!=="completed"&&i.status!=="cancelled").slice(0,8))c(t,{kind:"todo",value:s.title,source:"work-state"});for(let s of e.tests.slice(-5))c(t,{kind:"test",value:s,source:"work-state"});return c(t,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"work-state"}),t}function Te(r,e){let t=Ee[r];return e.map((n,s)=>({...n,score:(t[n.kind]??10)+Me[n.source]+Math.max(0,5-s*.01)}))}function Re(r){let e=new Map;for(let t of r){let n=`${t.kind}:${xe(t.value)}`,s=e.get(n);(!s||t.score>s.score)&&e.set(n,t)}return[...e.values()]}function T(r,e,t={}){let n=Q(e),s=[...we(r),...Se(r),...Oe(r)],i=Re(Te(n,s)).sort((d,p)=>p.score-d.score),a=Math.max(1,t.maxFacts??12),f=Math.max(300,t.maxChars??3200),u=[],m=0;for(let d of i){if(u.length>=a)break;let p=d.kind.length+d.value.length+d.source.length+16;u.length>0&&m+p>f||(u.push(d),m+=p)}return{intent:n,facts:u,context:{project:{id:r.id,name:r.name},intent:n,selectedFacts:u.map(d=>({kind:d.kind,value:d.value,source:d.source}))},stats:{candidates:s.length,selected:u.length,chars:m}}}var q={previous_agent:"Agent tr\u01B0\u1EDBc",goal:"M\u1EE5c ti\xEAu",phase:"Phase",task:"Task hi\u1EC7n t\u1EA1i",file:"File hi\u1EC7n t\u1EA1i",todo:"TODO",next_action:"Ti\u1EBFp theo",blocker:"Blocker",decision:"Quy\u1EBFt \u0111\u1ECBnh",completed:"\u0110\xE3 ho\xE0n th\xE0nh",test:"Test",progress:"Ti\u1EBFn \u0111\u1ED9"},Z=["previous_agent","phase","task","file","todo","next_action","blocker","decision","completed","test","progress","goal"],Ie={previous_agent:["previous_agent"],current_task:["task","file","next_action"],next_action:["next_action","task","file","todo"],last_file:["file","task","next_action"],blocker:["blocker"],decision:["decision"],completed:["completed"],status:["progress","task","next_action","blocker"],summary:Z};function Ce(r){let e=r.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim();return/(?:^|\s)(?:todo|to-do)(?:\s|$)/u.test(e)||/(?:việc|task)\s+(?:còn lại|chưa làm|chưa xong|chưa hoàn thành)/u.test(e)}function Pe(r){let e=r.filter(t=>t.source==="handoff");return e.length>0?e:r}function Ne(r){let e=new Set,t=[];for(let n of r){let s=`${n.kind}:${n.value.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}`;e.has(s)||(e.add(s),t.push(n))}return t}function X(r){switch(r){case"todo":case"blocker":case"decision":case"completed":return 3;default:return 1}}function Le(r,e){let t=[];for(let n of e){let s=r.filter(i=>i.kind===n).slice(0,X(n));for(let i of s)t.push(`${q[n]}: ${i.value}`)}return t.join(`
4
+ `)}function De(r,e){let t=Ie[e]??Z,n=[];for(let s of t){let i=r.filter(a=>a.kind===s).slice(0,X(s));for(let a of i)n.push(`${q[s]}: ${a.value}`)}return n.join(`
5
+ `)}function F(r,e){let t=T(r,e,{maxFacts:32,maxChars:6400}),n=Ne(Pe(t.facts)),s=Ce(e)?Le(n,["todo","task","next_action","file"]):De(n,String(t.intent));return s?{intent:String(t.intent),answer:s,source:n[0]?.source??"none"}:{intent:String(t.intent),answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",source:"none"}}function Fe(r,e){let t=JSON.stringify(r,null,2);return t.length<=e?t:t.slice(0,e)+`
6
+ [truncated]`}function je(r,e){let t=F(r,e),n=T(r,e,{maxFacts:12,maxChars:3200});return Fe({project:n.context.project,intent:n.intent,directAnswer:t.answer,selectedMemory:n.context.selectedFacts,retrievalStats:n.stats},4200)}async function ee(r,e,t={}){let n=F(r,e),s=je(r,e),i=t.router??J();try{let a=await i.generate({temperature:.1,maxTokens:450,messages:[{role:"system",content:`
8
7
  You are ToolNet Memory Agent.
9
8
 
10
9
  You are NOT the coding agent.
@@ -38,12 +37,12 @@ ${e}
38
37
 
39
38
  ToolNet selected memory:
40
39
 
41
- ${n}
40
+ ${s}
42
41
 
43
42
  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 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}
43
+ `.trim()}]}),f=a.text.trim();return f?{answer:f,provider:a.provider,model:a.model,usedAi:!0}:{answer:n.answer,usedAi:!1}}catch{return{answer:n.answer,usedAi:!1}}}import{existsSync as $e,readFileSync as Ue}from"node:fs";import{homedir as Ke}from"node:os";import{join as Be}from"node:path";function Ge(r){let e=r.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
44
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function He(){let r=process.env.TOOLNET_GLOBAL_ENV??Be(Ke(),".config","toolnet-memory",".env");if(!$e(r))return;let e=Ue(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 i=n.slice(0,s).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=Ge(n.slice(s+1)))}}He();import{createHash as Ye}from"node:crypto";import{existsSync as j,mkdirSync as Ve,readFileSync as We,renameSync as ze,writeFileSync as Je}from"node:fs";import{basename as Qe,dirname as R,join as C,parse as ne,resolve as E}from"node:path";var oe=".toolnet",qe="project.json";function Ze(r){return Ye("sha256").update(r).digest("hex").slice(0,16)}function $(r){return C(r,oe,qe)}function Xe(r){return j($(r))}function et(r,e){let t=E(r),n=ne(t).root;for(;;){if(Xe(t))return t;if(t===n||e&&t===E(e))break;let s=R(t);if(s===t)break;t=s}return null}function tt(r){let e=E(r),t=ne(e).root,n=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(n.some(i=>j(C(e,i))))return e;if(e===t)break;let s=R(e);if(s===e)break;e=s}return E(r)}function rt(r){let e;try{e=JSON.parse(We(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:R(R(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 te(r,e){let t=C(r,oe);Ve(t,{recursive:!0});let n=$(r),s=`${n}.tmp-${process.pid}`;Je(s,JSON.stringify(e,null,2)+`
45
+ `,{encoding:"utf8",mode:384}),ze(s,n)}function re(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 I=class{detect(e=process.cwd()){let t=E(e),n=tt(t),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(d=>j(C(n,d))),a=et(t,i?n:void 0);if(a){let d=$(a),p=rt(d);return p.rootPath!==a&&(p.rootPath=a,p.updatedAt=new Date().toISOString(),te(a,p)),re(p,a)}let f=new Date().toISOString(),u=Qe(n),m={version:1,id:Ze(n),name:u,remote:u,rootPath:n,createdAt:f,updatedAt:f,graphVersion:0,memoryVersion:0};return te(n,m),re(m,n)}};async function nt(){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 I().detect(e);if(!t){console.error("Unable to detect ToolNet project."),process.exitCode=1;return}let n=await ee(t,r);process.stdout.write(`${n.answer}
47
46
  `),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
47
  `)+`
49
- `)}Fe().catch(r=>{console.error(r instanceof Error?r.message:String(r)),process.exitCode=1});
48
+ `)}nt().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 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
- `)}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
- ${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 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
- `)}ce();
1
+ import*as d from"fs";import*as u from"path";function x(n){let t=u.resolve(n),e=u.parse(t).root;for(;t!==e;){let r=u.join(t,".toolnet");if(d.existsSync(r)&&d.statSync(r).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 E,mkdirSync as Me,readFileSync as R,renameSync as Ce,writeFileSync as Ee}from"node:fs";import{dirname as Ie,join as I}from"node:path";function O(n){return I(n.rootPath,".toolnet","work","current.json")}function b(n){let t=O(n);if(!E(t))return null;try{let e=JSON.parse(R(t,"utf8"));return e.version!==1||e.projectId!==n.id?null:e}catch{return null}}import{existsSync as _,mkdirSync as je,readFileSync as j,renameSync as Ne,writeFileSync as Pe}from"node:fs";import{dirname as Fe,join as N}from"node:path";function P(n){return N(n.rootPath,".toolnet","context","session-origin.json")}function w(n){let t=P(n);if(!_(t))return null;try{let e=JSON.parse(j(t,"utf8"));return e.version!==1||e.projectId!==n.id?null:e}catch{return null}}function L(n){return n.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function W(n){let t=L(n),e=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(t),r=/(?:đ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&&r?"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 z(n){let t=D(n.rootPath,".toolnet","context","handoff.md");if(!$(t))return null;try{let e=F(t,"utf8").trim();return e||null}catch{return null}}function B(n,t=5){return n.slice(0,t).map(e=>`- ${e}`).join(`
2
+ `)}function A(n,t){let e=W(t),r=w(n),o=b(n);switch(e){case"previous_agent":{if(r)return{intent:e,answer:`Agent tr\u01B0\u1EDBc l\xE0 ${r.agent}. Session: ${r.nativeSessionId}.`,source:"session-origin"};break}case"current_task":{if(r?.currentTask){let s=[`Task hi\u1EC7n t\u1EA1i: ${r.currentTask}.`];return r.lastTouchedFile&&s.push(`File g\u1EA7n nh\u1EA5t: ${r.lastTouchedFile}.`),r.latestNextAction&&s.push(`Ti\u1EBFp theo: ${r.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=r?.latestNextAction??o?.nextActions?.[0];if(s)return{intent:e,answer:`Vi\u1EC7c n\xEAn l\xE0m ti\u1EBFp: ${s}.`,source:r?.latestNextAction?"session-origin":"work-state"};break}case"last_file":{let s=r?.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:r?.lastTouchedFile?"session-origin":"work-state"};break}case"blocker":{let s=r?.latestBlocker??o?.blockers?.at(-1);return s?{intent:e,answer:`Blocker hi\u1EC7n t\u1EA1i: ${s}.`,source:r?.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=r?.latestDecision??o?.decisions?.at(-1);if(s)return{intent:e,answer:`Quy\u1EBFt \u0111\u1ECBnh g\u1EA7n nh\u1EA5t: ${s}.`,source:r?.latestDecision?"session-origin":"work-state"};break}case"completed":{let s=o?.tasks?.filter(a=>a.status==="completed").map(a=>a.title)??[];if(s.length)return{intent:e,answer:`C\xE1c task \u0111\xE3 ho\xE0n th\xE0nh:
3
+ ${B(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(r||o){let s=[];r&&s.push(`Agent tr\u01B0\u1EDBc: ${r.agent}.`);let a=r?.currentTask??o?.currentTask?.title;a&&s.push(`Task hi\u1EC7n t\u1EA1i: ${a}.`);let f=r?.lastTouchedFile??o?.filesTouched?.at(-1);f&&s.push(`File g\u1EA7n nh\u1EA5t: ${f}.`);let p=r?.latestNextAction??o?.nextActions?.[0];p&&s.push(`Ti\u1EBFp theo: ${p}.`);let l=r?.latestBlocker??o?.blockers?.at(-1);l&&s.push(`Blocker: ${l}.`);let c=r?.latestDecision??o?.decisions?.at(-1);return c&&s.push(`Quy\u1EBFt \u0111\u1ECBnh g\u1EA7n nh\u1EA5t: ${c}.`),{intent:e,answer:s.join(" "),source:r?"session-origin":"work-state"}}break}}let i=z(n);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 V,readFileSync as G}from"node:fs";import{homedir as H}from"node:os";import{join as K}from"node:path";function Y(n){let t=n.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 n=process.env.TOOLNET_GLOBAL_ENV??K(H(),".config","toolnet-memory",".env");if(!V(n))return;let t=G(n,"utf8");for(let e of t.split(/\r?\n/)){let r=e.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let o=r.indexOf("=");if(o<=0)continue;let i=r.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=Y(r.slice(o+1)))}}J();import{createHash as U}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 C=".toolnet",te="project.json";function ne(n){return U("sha256").update(n).digest("hex").slice(0,16)}function S(n){return y(n,C,te)}function re(n){return k(S(n))}function oe(n,t){let e=m(n),r=M(e).root;for(;;){if(re(e))return e;if(e===r||t&&e===m(t))break;let o=g(e);if(o===e)break;e=o}return null}function se(n){let t=m(n),e=M(t).root,r=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"];for(;;){if(r.some(i=>k(y(t,i))))return t;if(t===e)break;let o=g(t);if(o===t)break;t=o}return m(n)}function ie(n){let t;try{t=JSON.parse(q(n,"utf8"))}catch(o){throw new Error(`Invalid ToolNet project manifest: ${n}: ${o instanceof Error?o.message:String(o)}`)}if(!t||typeof t!="object")throw new Error(`Invalid ToolNet project manifest: ${n}`);let e=t;if(typeof e.id!="string"||!e.id.trim())throw new Error(`ToolNet project manifest is missing id: ${n}`);if(typeof e.name!="string"||!e.name.trim())throw new Error(`ToolNet project manifest is missing name: ${n}`);let r=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(n)),createdAt:typeof e.createdAt=="string"?e.createdAt:r,updatedAt:typeof e.updatedAt=="string"?e.updatedAt:r,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 T(n,t){let e=y(n,C);Q(e,{recursive:!0});let r=S(n),o=`${r}.tmp-${process.pid}`;X(o,JSON.stringify(t,null,2)+`
6
+ `,{encoding:"utf8",mode:384}),Z(o,r)}function v(n,t){return{id:n.id,name:n.name,remote:n.remote,rootPath:t,createdAt:n.createdAt,updatedAt:n.updatedAt,graphVersion:n.graphVersion,memoryVersion:n.memoryVersion,metadata:n.metadata}}var h=class{detect(t=process.cwd()){let e=m(t),r=se(e),i=[".git","package.json","pyproject.toml","Cargo.toml","go.mod","composer.json"].some(l=>k(y(r,l))),s=oe(e,i?r:void 0);if(s){let l=S(s),c=ie(l);return c.rootPath!==s&&(c.rootPath=s,c.updatedAt=new Date().toISOString(),T(s,c)),v(c,s)}let a=new Date().toISOString(),f=ee(r),p={version:1,id:ne(r),name:f,remote:f,rootPath:r,createdAt:a,updatedAt:a,graphVersion:0,memoryVersion:0};return T(r,p),v(p,r)}};function ae(){let n=process.argv.slice(2).join(" ").trim();if(!n){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 r=new h().detect(e);if(!r){console.error("Unable to detect ToolNet project."),process.exitCode=1;return}let o=A(r,n);process.stdout.write(`${o.answer}
7
+ `)}ae();