toolnet-memory 0.3.10 → 0.3.12

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,10 @@
1
- import{mkdirSync as G,mkdtempSync as Tt,rmSync as Pt,writeFileSync as he}from"node:fs";import{tmpdir as Ot}from"node:os";import{join as k}from"node:path";import{z as pe}from"zod";import{existsSync as qe,readFileSync as ze}from"node:fs";import{join as We}from"node:path";import{existsSync as Ae,mkdirSync as $t,readFileSync as Me,renameSync as Ut,writeFileSync as jt}from"node:fs";import{dirname as qt,join as xe}from"node:path";function we(n){return xe(n.rootPath,".toolnet","work","current.json")}function B(n){let e=we(n);if(!Ae(e))return null;try{let t=JSON.parse(Me(e,"utf8"));return t.version!==1||t.projectId!==n.id?null:t}catch{return null}}import{existsSync as Se,mkdirSync as Ht,readFileSync as Ee,renameSync as Gt,writeFileSync as Yt}from"node:fs";import{dirname as Qt,join as Ce}from"node:path";function _e(n){return Ce(n.rootPath,".toolnet","context","session-origin.json")}function q(n){let e=_e(n);if(!Se(e))return null;try{let t=JSON.parse(Ee(e,"utf8"));return t.version!==1||t.projectId!==n.id?null:t}catch{return null}}function Ie(n){return n.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function C(n){let e=Ie(n),t=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(e),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(e);return t&&r?"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"}import{existsSync as Ke,mkdirSync as Bn,readFileSync as $e}from"node:fs";import{join as V}from"node:path";var Pe=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_\-]{20,}\b/g},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._\-]{16,}\b/gi},{type:"jwt",regex:/\beyJ[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\b/g},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/g},{type:"password_assignment",regex:/\b(password|passwd|pwd)\s*[:=]\s*["']?[^"'\s]{6,}["']?/gi},{type:"secret_assignment",regex:/\b(secret|api[_-]?key|access[_-]?token|refresh[_-]?token)\s*[:=]\s*["']?[^"'\s]{8,}["']?/gi},{type:"cookie",regex:/\b(cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi}],_=class{scan(e){let t=[];for(let r of Pe){let o=new RegExp(r.regex.source,r.regex.flags);for(let i of e.matchAll(o))t.push({type:r.type,value:i[0]})}return t}hasSecrets(e){return this.scan(e).length>0}};var I=class{scanner=new _;sanitize(e){let t=e,r=this.scanner.scan(e),o=new Set;for(let i of r)o.add(i.type),t=t.split(i.value).join(`[REDACTED:${i.type}]`);return{text:t,redacted:r.length,secretTypes:[...o]}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(t=>this.sanitizeValue(t));if(e&&typeof e=="object"){let t={};for(let[r,o]of Object.entries(e)){let i=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");i.includes("password")||i.includes("passwd")||i==="pwd"||i.includes("secret")||i.includes("token")||i.includes("cookie")||i.includes("authorization")||i.includes("apikey")||i.includes("accesskey")||i.includes("privatekey")||i.includes("clientsecret")||i.includes("credential")?t[r]="[REDACTED]":t[r]=this.sanitizeValue(o)}return t}return e}};import{existsSync as Oe,readFileSync as Re}from"node:fs";import{homedir as Fe}from"node:os";import{join as Ne}from"node:path";function Le(n){let e=n.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
2
- `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function De(){let n=process.env.TOOLNET_GLOBAL_ENV??Ne(Fe(),".config","toolnet-memory",".env");if(!Oe(n))return;let e=Re(n,"utf8");for(let t of e.split(/\r?\n/)){let r=t.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let o=r.indexOf("=");if(o<=0)continue;let i=r.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(i)&&process.env[i]===void 0&&(process.env[i]=Le(r.slice(o+1)))}}De();var Tn=new I;function Ue(n){return V(n.rootPath,".toolnet","memory","checkpoints")}function je(n){return V(Ue(n),"latest.json")}function Be(n){let e=je(n);if(!Ke(e))return null;try{let t=JSON.parse($e(e,"utf8"));return t.schema!=="toolnet.memory.checkpoint.v1"||t.project.id!==n.id?null:t}catch{return null}}function Q(n){return Be(n)}var He={previous_agent:{previous_agent:100,task:35,phase:25},current_task:{task:100,request:95,activity:90,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,rule:85,architecture:80,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,request:98,activity:96,next_action:95,file:90,blocker:85,previous_agent:80,phase:75,completed:60,todo:60,decision:55,rule:54,architecture:53,fix:52,progress:50,test:45,goal:35}},Ge={checkpoint:20,handoff:18,"session-origin":14,"work-state":8};function Ye(n){return n.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function c(n,e){let t=e.value.replace(/\s+/g," ").trim();t&&n.push({...e,value:t,score:0})}function Ve(n){let e=We(n.rootPath,".toolnet","work","handoff-latest.json");if(!qe(e))return null;try{let r=JSON.parse(ze(e,"utf8")).continuity;return r?.schema!=="toolnet.handoff.v2"||r.project.id!==n.id?null:r}catch{return null}}function Qe(n){let e=Q(n);if(!e)return[];let t=[];e.request&&c(t,{kind:"request",value:e.request,source:"checkpoint"}),e.activity&&c(t,{kind:"activity",value:e.activity,source:"checkpoint"}),e.current.phase&&c(t,{kind:"phase",value:e.current.phase.title,source:"checkpoint"}),e.current.task&&c(t,{kind:"task",value:e.current.task.title,source:"checkpoint"});let r=e.files.active.at(-1);r&&c(t,{kind:"file",value:r,source:"checkpoint"});for(let o of e.nextActions)c(t,{kind:"next_action",value:o,source:"checkpoint"});for(let o of e.blockers)c(t,{kind:"blocker",value:o,source:"checkpoint"});for(let o of e.completed.tasks)c(t,{kind:"completed",value:o,source:"checkpoint"});for(let o of e.remaining.tasks)c(t,{kind:"todo",value:o,source:"checkpoint"});for(let o of e.durableFacts)c(t,{kind:o.kind,value:o.content,source:"checkpoint"});return t}function Je(n){let e=Ve(n);if(!e)return[];let t=[];c(t,{kind:"previous_agent",value:e.source.agent,source:"handoff"}),e.request&&c(t,{kind:"request",value:e.request,source:"handoff"}),e.activity&&c(t,{kind:"activity",value:e.activity,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 r of e.blockers)c(t,{kind:"blocker",value:r,source:"handoff"});for(let r of e.decisions)c(t,{kind:"decision",value:r,source:"handoff"});for(let r of e.completed.tasks)c(t,{kind:"completed",value:r,source:"handoff"});for(let r of e.remaining.todos)c(t,{kind:"todo",value:r,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 Xe(n){let e=q(n);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 Ze(n){let e=B(n);if(!e)return[];let t=[];e.currentRequest&&c(t,{kind:"request",value:e.currentRequest,source:"work-state"}),e.currentActivity&&c(t,{kind:"activity",value:e.currentActivity,source:"work-state"}),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 r=e.activeFiles?.at(-1)??e.filesTouched.at(-1);r&&c(t,{kind:"file",value:r,source:"work-state"});for(let o of e.nextActions.slice(0,5))c(t,{kind:"next_action",value:o,source:"work-state"});for(let o of e.blockers.slice(-5))c(t,{kind:"blocker",value:o,source:"work-state"});for(let o of e.decisions.slice(-5))c(t,{kind:"decision",value:o,source:"work-state"});for(let o of e.tasks.filter(i=>i.status==="completed").slice(-8))c(t,{kind:"completed",value:o.title,source:"work-state"});for(let o of e.tasks.filter(i=>i.status!=="completed"&&i.status!=="cancelled").slice(0,8))c(t,{kind:"todo",value:o.title,source:"work-state"});for(let o of e.tests.slice(-5))c(t,{kind:"test",value:o,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 et(n,e){let t=He[n];return e.map((r,o)=>({...r,score:(t[r.kind]??10)+Ge[r.source]+Math.max(0,5-o*.01)}))}function tt(n){let e=new Map;for(let t of n){let r=`${t.kind}:${Ye(t.value)}`,o=e.get(r);(!o||t.score>o.score)&&e.set(r,t)}return[...e.values()]}function y(n,e,t={}){let r=C(e),o=[...Qe(n),...Je(n),...Xe(n),...Ze(n)],i=tt(et(r,o)).sort((d,g)=>g.score-d.score),a=Math.max(1,t.maxFacts??12),p=Math.max(300,t.maxChars??3200),l=[],f=0;for(let d of i){if(l.length>=a)break;let g=d.kind.length+d.value.length+d.source.length+16;l.length>0&&f+g>p||(l.push(d),f+=g)}return{intent:r,facts:l,context:{project:{id:n.id,name:n.name},intent:r,selectedFacts:l.map(d=>({kind:d.kind,value:d.value,source:d.source}))},stats:{candidates:o.length,selected:l.length,chars:f}}}var J={previous_agent:"Agent tr\u01B0\u1EDBc",request:"Y\xEAu c\u1EA7u hi\u1EC7n t\u1EA1i",activity:"\u0110ang l\xE0m",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",rule:"Quy t\u1EAFc",architecture:"Ki\u1EBFn tr\xFAc",fix:"\u0110\xE3 s\u1EEDa",completed:"\u0110\xE3 ho\xE0n th\xE0nh",test:"Test",progress:"Ti\u1EBFn \u0111\u1ED9"},X=["previous_agent","request","activity","phase","task","file","todo","next_action","blocker","decision","rule","architecture","fix","completed","test","progress","goal"],nt={previous_agent:["previous_agent"],current_task:["request","activity","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:X};function rt(n){let e=n.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 ot(n){let e=n.filter(r=>r.source==="handoff");if(e.length===0)return n;let t=n.filter(r=>r.source==="checkpoint"&&["rule","architecture","fix"].includes(r.kind));return[...e,...t]}function st(n){let e=new Set,t=[];for(let r of n){let o=`${r.kind}:${r.value.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}`;e.has(o)||(e.add(o),t.push(r))}return t}function Z(n){switch(n){case"todo":case"blocker":case"decision":case"completed":return 3;default:return 1}}function it(n,e){let t=[];for(let r of e){let o=n.filter(i=>i.kind===r).slice(0,Z(r));for(let i of o)t.push(`${J[r]}: ${i.value}`)}return t.join(`
3
- `)}function at(n,e){let t=nt[e]??X,r=[];for(let o of t){let i=n.filter(a=>a.kind===o).slice(0,Z(o));for(let a of i)r.push(`${J[o]}: ${a.value}`)}return r.join(`
4
- `)}function M(n,e){let t=y(n,e,{maxFacts:32,maxChars:6400}),r=st(ot(t.facts)),o=rt(e)?it(r,["todo","task","next_action","file"]):at(r,String(t.intent));return o?{intent:String(t.intent),answer:o,source:r[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"}}var ee=[{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(n){let e=ee.find(t=>t.id===n);if(!e)throw new Error(`Unsupported AI provider: ${n}`);return e}function x(n){return ee.some(e=>e.id===n)}function s(n){return process.env[n]?.trim()||void 0}function u(...n){return n.find(e=>!!e?.trim())}function te(){if(s("GROQ_API_KEY"))return"groq";if(s("DEEPSEEK_API_KEY"))return"deepseek";if(s("NVIDIA_API_KEY")||s("NVIDIA_NIM_API_KEY"))return"nvidia";if(s("OPENROUTER_API_KEY"))return"openrouter";if(s("ALIBABA_API_KEY")||s("DASHSCOPE_API_KEY"))return"alibaba";if(s("GEMINI_API_KEY")||s("GOOGLE_API_KEY"))return"gemini";if(s("CLOUDFLARE_API_TOKEN")&&s("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(s("HF_TOKEN"))return"huggingface";if(s("OLLAMA_MODEL")||s("OLLAMA_BASE_URL"))return"ollama"}function ne(){let n=s("TOOLNET_LLM_PROVIDER");return n&&x(n)?n:te()??"openai-compatible"}function T(n){let e=h(n);switch(n){case"alibaba":return{provider:n,apiKey:u(s("ALIBABA_API_KEY"),s("DASHSCOPE_API_KEY")),baseUrl:u(s("ALIBABA_BASE_URL"),s("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:u(s("ALIBABA_MODEL"),s("DASHSCOPE_MODEL"))};case"openrouter":return{provider:n,apiKey:s("OPENROUTER_API_KEY"),baseUrl:u(s("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:s("OPENROUTER_MODEL")};case"groq":return{provider:n,apiKey:s("GROQ_API_KEY"),baseUrl:u(s("GROQ_BASE_URL"),e.defaultBaseUrl),model:s("GROQ_MODEL")};case"deepseek":return{provider:n,apiKey:s("DEEPSEEK_API_KEY"),baseUrl:u(s("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:u(s("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:n,apiKey:u(s("NVIDIA_API_KEY"),s("NVIDIA_NIM_API_KEY")),baseUrl:u(s("NVIDIA_BASE_URL"),s("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:u(s("NVIDIA_MODEL"),s("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:n,apiKey:u(s("GEMINI_API_KEY"),s("GOOGLE_API_KEY")),baseUrl:u(s("GEMINI_BASE_URL"),e.defaultBaseUrl),model:s("GEMINI_MODEL")};case"huggingface":return{provider:n,apiKey:s("HF_TOKEN"),baseUrl:u(s("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:u(s("HF_LLM_MODEL"),s("HF_MODEL"))};case"ollama":return{provider:n,apiKey:s("OLLAMA_API_KEY"),baseUrl:u(s("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:s("OLLAMA_MODEL")};case"cloudflare":return{provider:n,accountId:s("CLOUDFLARE_ACCOUNT_ID"),apiKey:s("CLOUDFLARE_API_TOKEN"),baseUrl:s("CLOUDFLARE_AI_BASE_URL"),model:s("CLOUDFLARE_MODEL")};case"custom":return{provider:n,apiKey:s("CUSTOM_AI_API_KEY"),baseUrl:s("CUSTOM_AI_BASE_URL"),model:s("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:u(s("OPENAI_API_KEY"),s("MODEL_API_KEY")),baseUrl:u(s("OPENAI_BASE_URL"),s("MODEL_BASE_URL")),model:u(s("OPENAI_MODEL"),s("MODEL_NAME"))}}}function ct(){let n=s("TOOLNET_LLM_PROVIDER"),e=n&&x(n)?n:ne(),t=h(e),r=T(e);return{provider:e,apiKey:u(s("TOOLNET_LLM_API_KEY"),r.apiKey),baseUrl:u(s("TOOLNET_LLM_BASE_URL"),r.baseUrl,t.defaultBaseUrl),model:u(s("TOOLNET_LLM_MODEL"),r.model,t.defaultModel),accountId:u(s("TOOLNET_LLM_ACCOUNT_ID"),r.accountId)}}function lt(){let n=s("TOOLNET_EMBEDDING_PROVIDER");return n==="local"?"local":n&&x(n)?n:s("HF_TOKEN")||s("HF_EMBEDDING_MODEL")?"huggingface":"local"}function ut(){let n=lt();if(n==="local")return{provider:"local",model:u(s("TOOLNET_EMBEDDING_MODEL"),s("LOCAL_EMBEDDING_MODEL"))};let e=h(n),t,r,o,i;switch(n){case"huggingface":t=s("HF_TOKEN"),r=s("HF_INFERENCE_BASE_URL"),o=s("HF_EMBEDDING_MODEL");break;case"openai-compatible":t=s("OPENAI_API_KEY"),r=s("OPENAI_BASE_URL"),o=s("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":t=s("CLOUDFLARE_API_TOKEN"),r=s("CLOUDFLARE_AI_BASE_URL"),o=s("CLOUDFLARE_EMBEDDING_MODEL"),i=s("CLOUDFLARE_ACCOUNT_ID");break;default:t=T(n).apiKey,r=T(n).baseUrl,o=s(`${n.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let a=u(s("TOOLNET_EMBEDDING_ACCOUNT_ID"),i),p=u(s("TOOLNET_EMBEDDING_BASE_URL"),r,e.defaultBaseUrl),l=n==="cloudflare"&&!p&&a?`https://api.cloudflare.com/client/v4/accounts/${a}/ai/v1`:p;return{provider:n,apiKey:u(s("TOOLNET_EMBEDDING_API_KEY"),t),baseUrl:l,model:u(s("TOOLNET_EMBEDDING_MODEL"),o),accountId:a}}function z(){let n=ct(),e=ut();return{llm:n,embedding:e,legacy:{llm:!s("TOOLNET_LLM_PROVIDER")&&!!te(),embedding:!s("TOOLNET_EMBEDDING_PROVIDER")&&!!(s("HF_TOKEN")||s("HF_EMBEDDING_MODEL"))}}}function re(n=ne()){let e=z().llm;if(n===e.provider)return{id:n,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId};let t=T(n);return{id:n,apiKey:t.apiKey,baseUrl:t.baseUrl,model:t.model,accountId:t.accountId}}function w(n,e){return s(`TOOLNET_LLM_FALLBACK_${n}_${e}`)}function oe(){let n=[];for(let e of[1,2]){let t=w(e,"PROVIDER");if(!t||!x(t))continue;let r=h(t);n.push({slot:e,config:{provider:t,apiKey:w(e,"API_KEY"),baseUrl:u(w(e,"BASE_URL"),r.defaultBaseUrl),model:u(w(e,"MODEL"),r.defaultModel),accountId:w(e,"ACCOUNT_ID")}})}return n}function se(){let n=s("TOOLNET_LLM_FALLBACK_COOLDOWN_MS"),e=s("TOOLNET_LLM_MAX_RETRIES"),t=Number(n??6e4),r=Number(e??1);return{cooldownMs:Number.isFinite(t)&&t>=0?t:6e4,maxRetries:Number.isFinite(r)&&r>=0?Math.floor(r):1}}var S=class extends Error{status;constructor(e,t){super(e),this.name="AiHttpError",this.status=t}};async function v(n,e,t=3e4){let r=new AbortController,o=setTimeout(()=>r.abort(),t);o.unref?.();try{let i=await fetch(n,{...e,signal:r.signal}),a=await i.text();if(!i.ok){let p=a;try{let l=JSON.parse(a);p=l.error?.message??l.message??a}catch{}throw new S(p||`HTTP ${i.status}`,i.status)}return a.trim()?JSON.parse(a):{}}finally{clearTimeout(o)}}function P(n,e){return`${n.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(),r=this.config.apiKey?.trim();if(!t)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!r)throw new Error("cloudflare: API TOKEN is not configured");let o=this.model(),a=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${t}/ai/run`).replace(/\/+$/,"")}/${o}`,p=await v(a,{method:"POST",headers:{authorization:`Bearer ${r}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),l=p.result?.response?.trim();if(!l)throw new Error(p.errors?.[0]?.message??"cloudflare: empty model response");return{text:l,provider:"cloudflare",model:o}}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 R=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 r=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",o=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}]})),p=`${P(r,`models/${encodeURIComponent(o)}:generateContent`)}?key=${encodeURIComponent(t)}`,l=await v(p,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...i.length?{systemInstruction:{parts:[{text:i.map(d=>d.content).join(`
1
+ import{mkdirSync as te,mkdtempSync as en,rmSync as tn,writeFileSync as _e}from"node:fs";import{tmpdir as nn}from"node:os";import{join as v}from"node:path";import{z as Z}from"zod";import{existsSync as nt,readFileSync as rt}from"node:fs";import{join as ot}from"node:path";import{existsSync as Fe,mkdirSync as ln,readFileSync as Ne,renameSync as dn,writeFileSync as mn}from"node:fs";import{dirname as pn,join as Le}from"node:path";function De(t){return Le(t.rootPath,".toolnet","work","current.json")}function Y(t){let e=De(t);if(!Fe(e))return null;try{let n=JSON.parse(Ne(e,"utf8"));return n.version!==1||n.projectId!==t.id?null:n}catch{return null}}import{existsSync as $e,mkdirSync as hn,readFileSync as Ke,renameSync as kn,writeFileSync as bn}from"node:fs";import{dirname as An,join as Ue}from"node:path";function je(t){return Ue(t.rootPath,".toolnet","context","session-origin.json")}function Q(t){let e=je(t);if(!$e(e))return null;try{let n=JSON.parse(Ke(e,"utf8"));return n.version!==1||n.projectId!==t.id?null:n}catch{return null}}function Be(t){return t.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function P(t){let e=Be(t),n=/(?:agent trước|previous agent|ai trước|phiên trước)/u.test(e),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(e);return n&&r?"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"}import{existsSync as Je,mkdirSync as mr,readFileSync as Xe}from"node:fs";import{join as re}from"node:path";var qe=[{type:"openai_key",regex:/\bsk-[A-Za-z0-9_\-]{20,}\b/g},{type:"huggingface_token",regex:/\bhf_[A-Za-z0-9]{20,}\b/g},{type:"hf_s3_access_key",regex:/\bHFAK[A-Za-z0-9]{8,}\b/g},{type:"bearer_token",regex:/\bBearer\s+[A-Za-z0-9._\-]{16,}\b/gi},{type:"jwt",regex:/\beyJ[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\.[A-Za-z0-9_\-]{8,}\b/g},{type:"private_key",regex:/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/g},{type:"password_assignment",regex:/\b(password|passwd|pwd)\s*[:=]\s*["']?[^"'\s]{6,}["']?/gi},{type:"secret_assignment",regex:/\b(secret|api[_-]?key|access[_-]?token|refresh[_-]?token)\s*[:=]\s*["']?[^"'\s]{8,}["']?/gi},{type:"cookie",regex:/\b(cookie|set-cookie)\s*[:=]\s*[^;\n]{8,}/gi}],R=class{scan(e){let n=[];for(let r of qe){let o=new RegExp(r.regex.source,r.regex.flags);for(let s of e.matchAll(o))n.push({type:r.type,value:s[0]})}return n}hasSecrets(e){return this.scan(e).length>0}};var F=class{scanner=new R;sanitize(e){let n=e,r=this.scanner.scan(e),o=new Set;for(let s of r)o.add(s.type),n=n.split(s.value).join(`[REDACTED:${s.type}]`);return{text:n,redacted:r.length,secretTypes:[...o]}}sanitizeValue(e){if(typeof e=="string")return this.sanitize(e).text;if(Array.isArray(e))return e.map(n=>this.sanitizeValue(n));if(e&&typeof e=="object"){let n={};for(let[r,o]of Object.entries(e)){let s=r.normalize("NFKC").toLowerCase().replace(/[^a-z0-9]+/g,"");s.includes("password")||s.includes("passwd")||s==="pwd"||s.includes("secret")||s.includes("token")||s.includes("cookie")||s.includes("authorization")||s.includes("apikey")||s.includes("accesskey")||s.includes("privatekey")||s.includes("clientsecret")||s.includes("credential")?n[r]="[REDACTED]":n[r]=this.sanitizeValue(o)}return n}return e}};import{existsSync as ze,readFileSync as We}from"node:fs";import{homedir as Ge}from"node:os";import{join as Ye}from"node:path";function Qe(t){let e=t.trim();return e.length>=2&&e.startsWith('"')&&e.endsWith('"')?(e=e.slice(1,-1),e.replace(/\\n/g,`
2
+ `).replace(/\\r/g,"\r").replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\")):e.length>=2&&e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function Ve(){let t=process.env.TOOLNET_GLOBAL_ENV??Ye(Ge(),".config","toolnet-memory",".env");if(!ze(t))return;let e=We(t,"utf8");for(let n of e.split(/\r?\n/)){let r=n.trim();if(!r||r.startsWith("#"))continue;r.startsWith("export ")&&(r=r.slice(7));let o=r.indexOf("=");if(o<=0)continue;let s=r.slice(0,o).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(s)&&process.env[s]===void 0&&(process.env[s]=Qe(r.slice(o+1)))}}Ve();var er=new F;function Ze(t){return re(t.rootPath,".toolnet","memory","checkpoints")}function et(t){return re(Ze(t),"latest.json")}function tt(t){let e=et(t);if(!Je(e))return null;try{let n=JSON.parse(Xe(e,"utf8"));return n.schema!=="toolnet.memory.checkpoint.v1"||n.project.id!==t.id?null:n}catch{return null}}function oe(t){return tt(t)}var st={previous_agent:{previous_agent:100,task:35,phase:25},current_task:{task:100,request:95,activity:90,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,rule:85,architecture:80,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,request:98,activity:96,next_action:95,file:90,blocker:85,previous_agent:80,phase:75,completed:60,todo:60,decision:55,rule:54,architecture:53,fix:52,progress:50,test:45,goal:35}},it={checkpoint:20,handoff:18,"session-origin":14,"work-state":8};function at(t){return t.normalize("NFKC").toLowerCase().replace(/\s+/g," ").trim()}function u(t,e){let n=e.value.replace(/\s+/g," ").trim();n&&t.push({...e,value:n,score:0})}function ct(t){let e=ot(t.rootPath,".toolnet","work","handoff-latest.json");if(!nt(e))return null;try{let r=JSON.parse(rt(e,"utf8")).continuity;return r?.schema!=="toolnet.handoff.v2"||r.project.id!==t.id?null:r}catch{return null}}function ut(t){let e=oe(t);if(!e)return[];let n=[];e.request&&u(n,{kind:"request",value:e.request,source:"checkpoint"}),e.activity&&u(n,{kind:"activity",value:e.activity,source:"checkpoint"}),e.current.phase&&u(n,{kind:"phase",value:e.current.phase.title,source:"checkpoint"}),e.current.task&&u(n,{kind:"task",value:e.current.task.title,source:"checkpoint"});let r=e.files.active.at(-1);r&&u(n,{kind:"file",value:r,source:"checkpoint"});for(let o of e.nextActions)u(n,{kind:"next_action",value:o,source:"checkpoint"});for(let o of e.blockers)u(n,{kind:"blocker",value:o,source:"checkpoint"});for(let o of e.completed.tasks)u(n,{kind:"completed",value:o,source:"checkpoint"});for(let o of e.remaining.tasks)u(n,{kind:"todo",value:o,source:"checkpoint"});for(let o of e.durableFacts)u(n,{kind:o.kind,value:o.content,source:"checkpoint"});return n}function lt(t){let e=ct(t);if(!e)return[];let n=[];u(n,{kind:"previous_agent",value:e.source.agent,source:"handoff"}),e.request&&u(n,{kind:"request",value:e.request,source:"handoff"}),e.activity&&u(n,{kind:"activity",value:e.activity,source:"handoff"}),e.goal&&u(n,{kind:"goal",value:e.goal,source:"handoff"}),e.current.phase&&u(n,{kind:"phase",value:e.current.phase.title,source:"handoff"}),e.current.task&&u(n,{kind:"task",value:e.current.task.title,source:"handoff"}),e.files.current&&u(n,{kind:"file",value:e.files.current,source:"handoff"}),e.nextAction&&u(n,{kind:"next_action",value:e.nextAction,source:"handoff"});for(let r of e.blockers)u(n,{kind:"blocker",value:r,source:"handoff"});for(let r of e.decisions)u(n,{kind:"decision",value:r,source:"handoff"});for(let r of e.completed.tasks)u(n,{kind:"completed",value:r,source:"handoff"});for(let r of e.remaining.todos)u(n,{kind:"todo",value:r,source:"handoff"});return u(n,{kind:"test",value:`Test status: ${e.tests.status}`,source:"handoff"}),u(n,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"handoff"}),n}function dt(t){let e=Q(t);if(!e)return[];let n=[];return u(n,{kind:"previous_agent",value:e.agent,source:"session-origin"}),e.currentPhase&&u(n,{kind:"phase",value:e.currentPhase,source:"session-origin"}),e.currentTask&&u(n,{kind:"task",value:e.currentTask,source:"session-origin"}),e.lastTouchedFile&&u(n,{kind:"file",value:e.lastTouchedFile,source:"session-origin"}),e.latestNextAction&&u(n,{kind:"next_action",value:e.latestNextAction,source:"session-origin"}),e.latestBlocker&&u(n,{kind:"blocker",value:e.latestBlocker,source:"session-origin"}),e.latestDecision&&u(n,{kind:"decision",value:e.latestDecision,source:"session-origin"}),n}function mt(t){let e=Y(t);if(!e)return[];let n=[];e.currentRequest&&u(n,{kind:"request",value:e.currentRequest,source:"work-state"}),e.currentActivity&&u(n,{kind:"activity",value:e.currentActivity,source:"work-state"}),e.goal&&u(n,{kind:"goal",value:e.goal,source:"work-state"}),e.currentPhase&&u(n,{kind:"phase",value:e.currentPhase.title,source:"work-state"}),e.currentTask&&u(n,{kind:"task",value:e.currentTask.title,source:"work-state"});let r=e.activeFiles?.at(-1)??e.filesTouched.at(-1);r&&u(n,{kind:"file",value:r,source:"work-state"});for(let o of e.nextActions.slice(0,5))u(n,{kind:"next_action",value:o,source:"work-state"});for(let o of e.blockers.slice(-5))u(n,{kind:"blocker",value:o,source:"work-state"});for(let o of e.decisions.slice(-5))u(n,{kind:"decision",value:o,source:"work-state"});for(let o of e.tasks.filter(s=>s.status==="completed").slice(-8))u(n,{kind:"completed",value:o.title,source:"work-state"});for(let o of e.tasks.filter(s=>s.status!=="completed"&&s.status!=="cancelled").slice(0,8))u(n,{kind:"todo",value:o.title,source:"work-state"});for(let o of e.tests.slice(-5))u(n,{kind:"test",value:o,source:"work-state"});return u(n,{kind:"progress",value:`${e.progress.tasksCompleted}/${e.progress.tasksTotal} tasks completed; ${e.progress.blocked} blocked`,source:"work-state"}),n}function ft(t,e){let n=st[t];return e.map((r,o)=>({...r,score:(n[r.kind]??10)+it[r.source]+Math.max(0,5-o*.01)}))}function pt(t){let e=new Map;for(let n of t){let r=`${n.kind}:${at(n.value)}`,o=e.get(r);(!o||n.score>o.score)&&e.set(r,n)}return[...e.values()]}function h(t,e,n={}){let r=P(e),o=[...ut(t),...lt(t),...dt(t),...mt(t)],s=pt(ft(r,o)).sort((m,y)=>y.score-m.score),a=Math.max(1,n.maxFacts??12),c=Math.max(300,n.maxChars??3200),d=[],l=0;for(let m of s){if(d.length>=a)break;let y=m.kind.length+m.value.length+m.source.length+16;d.length>0&&l+y>c||(d.push(m),l+=y)}return{intent:r,facts:d,context:{project:{id:t.id,name:t.name},intent:r,selectedFacts:d.map(m=>({kind:m.kind,value:m.value,source:m.source}))},stats:{candidates:o.length,selected:d.length,chars:l}}}var se={previous_agent:"Agent tr\u01B0\u1EDBc",request:"Y\xEAu c\u1EA7u hi\u1EC7n t\u1EA1i",activity:"\u0110ang l\xE0m",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",rule:"Quy t\u1EAFc",architecture:"Ki\u1EBFn tr\xFAc",fix:"\u0110\xE3 s\u1EEDa",completed:"\u0110\xE3 ho\xE0n th\xE0nh",test:"Test",progress:"Ti\u1EBFn \u0111\u1ED9"},ie=["previous_agent","request","activity","phase","task","file","todo","next_action","blocker","decision","rule","architecture","fix","completed","test","progress","goal"],gt={previous_agent:["previous_agent"],current_task:["request","activity","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:ie};function yt(t){let e=t.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 ht(t){let e=t.filter(r=>r.source==="handoff");if(e.length===0)return t;let n=t.filter(r=>r.source==="checkpoint"&&["rule","architecture","fix"].includes(r.kind));return[...e,...n]}function kt(t){let e=new Set,n=[];for(let r of t){let o=`${r.kind}:${r.value.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}`;e.has(o)||(e.add(o),n.push(r))}return n}function ae(t){switch(t){case"todo":case"blocker":case"decision":case"completed":return 3;default:return 1}}function bt(t,e){let n=[];for(let r of e){let o=t.filter(s=>s.kind===r).slice(0,ae(r));for(let s of o)n.push(`${se[r]}: ${s.value}`)}return n.join(`
3
+ `)}function vt(t,e){let n=gt[e]??ie,r=[];for(let o of n){let s=t.filter(a=>a.kind===o).slice(0,ae(o));for(let a of s)r.push(`${se[o]}: ${a.value}`)}return r.join(`
4
+ `)}function x(t,e){let n=h(t,e,{maxFacts:32,maxChars:6400}),r=kt(ht(n.facts)),o=yt(e)?bt(r,["todo","task","next_action","file"]):vt(r,String(n.intent));return o?{intent:String(n.intent),answer:o,source:r[0]?.source??"none"}:{intent:String(n.intent),answer:"ToolNet ch\u01B0a c\xF3 \u0111\u1EE7 memory cho c\xE2u h\u1ECFi n\xE0y.",source:"none"}}var ce=[{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 b(t){let e=ce.find(n=>n.id===t);if(!e)throw new Error(`Unsupported AI provider: ${t}`);return e}function _(t){return ce.some(e=>e.id===t)}function i(t){return process.env[t]?.trim()||void 0}function f(...t){return t.find(e=>!!e?.trim())}function ue(){if(i("GROQ_API_KEY"))return"groq";if(i("DEEPSEEK_API_KEY"))return"deepseek";if(i("NVIDIA_API_KEY")||i("NVIDIA_NIM_API_KEY"))return"nvidia";if(i("OPENROUTER_API_KEY"))return"openrouter";if(i("ALIBABA_API_KEY")||i("DASHSCOPE_API_KEY"))return"alibaba";if(i("GEMINI_API_KEY")||i("GOOGLE_API_KEY"))return"gemini";if(i("CLOUDFLARE_API_TOKEN")&&i("CLOUDFLARE_ACCOUNT_ID"))return"cloudflare";if(i("HF_TOKEN"))return"huggingface";if(i("OLLAMA_MODEL")||i("OLLAMA_BASE_URL"))return"ollama"}function le(){let t=i("TOOLNET_LLM_PROVIDER");return t&&_(t)?t:ue()??"openai-compatible"}function N(t){let e=b(t);switch(t){case"alibaba":return{provider:t,apiKey:f(i("ALIBABA_API_KEY"),i("DASHSCOPE_API_KEY")),baseUrl:f(i("ALIBABA_BASE_URL"),i("DASHSCOPE_BASE_URL"),e.defaultBaseUrl),model:f(i("ALIBABA_MODEL"),i("DASHSCOPE_MODEL"))};case"openrouter":return{provider:t,apiKey:i("OPENROUTER_API_KEY"),baseUrl:f(i("OPENROUTER_BASE_URL"),e.defaultBaseUrl),model:i("OPENROUTER_MODEL")};case"groq":return{provider:t,apiKey:i("GROQ_API_KEY"),baseUrl:f(i("GROQ_BASE_URL"),e.defaultBaseUrl),model:i("GROQ_MODEL")};case"deepseek":return{provider:t,apiKey:i("DEEPSEEK_API_KEY"),baseUrl:f(i("DEEPSEEK_BASE_URL"),e.defaultBaseUrl),model:f(i("DEEPSEEK_MODEL"),e.defaultModel)};case"nvidia":return{provider:t,apiKey:f(i("NVIDIA_API_KEY"),i("NVIDIA_NIM_API_KEY")),baseUrl:f(i("NVIDIA_BASE_URL"),i("NVIDIA_NIM_BASE_URL"),e.defaultBaseUrl),model:f(i("NVIDIA_MODEL"),i("NVIDIA_NIM_MODEL"),e.defaultModel)};case"gemini":return{provider:t,apiKey:f(i("GEMINI_API_KEY"),i("GOOGLE_API_KEY")),baseUrl:f(i("GEMINI_BASE_URL"),e.defaultBaseUrl),model:i("GEMINI_MODEL")};case"huggingface":return{provider:t,apiKey:i("HF_TOKEN"),baseUrl:f(i("HF_INFERENCE_BASE_URL"),e.defaultBaseUrl),model:f(i("HF_LLM_MODEL"),i("HF_MODEL"))};case"ollama":return{provider:t,apiKey:i("OLLAMA_API_KEY"),baseUrl:f(i("OLLAMA_BASE_URL"),e.defaultBaseUrl),model:i("OLLAMA_MODEL")};case"cloudflare":return{provider:t,accountId:i("CLOUDFLARE_ACCOUNT_ID"),apiKey:i("CLOUDFLARE_API_TOKEN"),baseUrl:i("CLOUDFLARE_AI_BASE_URL"),model:i("CLOUDFLARE_MODEL")};case"custom":return{provider:t,apiKey:i("CUSTOM_AI_API_KEY"),baseUrl:i("CUSTOM_AI_BASE_URL"),model:i("CUSTOM_AI_MODEL")};default:return{provider:"openai-compatible",apiKey:f(i("OPENAI_API_KEY"),i("MODEL_API_KEY")),baseUrl:f(i("OPENAI_BASE_URL"),i("MODEL_BASE_URL")),model:f(i("OPENAI_MODEL"),i("MODEL_NAME"))}}}function At(){let t=i("TOOLNET_LLM_PROVIDER"),e=t&&_(t)?t:le(),n=b(e),r=N(e);return{provider:e,apiKey:f(i("TOOLNET_LLM_API_KEY"),r.apiKey),baseUrl:f(i("TOOLNET_LLM_BASE_URL"),r.baseUrl,n.defaultBaseUrl),model:f(i("TOOLNET_LLM_MODEL"),r.model,n.defaultModel),accountId:f(i("TOOLNET_LLM_ACCOUNT_ID"),r.accountId)}}function xt(){let t=i("TOOLNET_EMBEDDING_PROVIDER");return t==="local"?"local":t&&_(t)?t:i("HF_TOKEN")||i("HF_EMBEDDING_MODEL")?"huggingface":"local"}function Mt(){let t=xt();if(t==="local")return{provider:"local",model:f(i("TOOLNET_EMBEDDING_MODEL"),i("LOCAL_EMBEDDING_MODEL"))};let e=b(t),n,r,o,s;switch(t){case"huggingface":n=i("HF_TOKEN"),r=i("HF_INFERENCE_BASE_URL"),o=i("HF_EMBEDDING_MODEL");break;case"openai-compatible":n=i("OPENAI_API_KEY"),r=i("OPENAI_BASE_URL"),o=i("OPENAI_EMBEDDING_MODEL");break;case"cloudflare":n=i("CLOUDFLARE_API_TOKEN"),r=i("CLOUDFLARE_AI_BASE_URL"),o=i("CLOUDFLARE_EMBEDDING_MODEL"),s=i("CLOUDFLARE_ACCOUNT_ID");break;default:n=N(t).apiKey,r=N(t).baseUrl,o=i(`${t.toUpperCase().replace(/-/g,"_")}_EMBEDDING_MODEL`)}let a=f(i("TOOLNET_EMBEDDING_ACCOUNT_ID"),s),c=f(i("TOOLNET_EMBEDDING_BASE_URL"),r,e.defaultBaseUrl),d=t==="cloudflare"&&!c&&a?`https://api.cloudflare.com/client/v4/accounts/${a}/ai/v1`:c;return{provider:t,apiKey:f(i("TOOLNET_EMBEDDING_API_KEY"),n),baseUrl:d,model:f(i("TOOLNET_EMBEDDING_MODEL"),o),accountId:a}}function V(){let t=At(),e=Mt();return{llm:t,embedding:e,legacy:{llm:!i("TOOLNET_LLM_PROVIDER")&&!!ue(),embedding:!i("TOOLNET_EMBEDDING_PROVIDER")&&!!(i("HF_TOKEN")||i("HF_EMBEDDING_MODEL"))}}}function de(t=le()){let e=V().llm;if(t===e.provider)return{id:t,apiKey:e.apiKey,baseUrl:e.baseUrl,model:e.model,accountId:e.accountId};let n=N(t);return{id:t,apiKey:n.apiKey,baseUrl:n.baseUrl,model:n.model,accountId:n.accountId}}function I(t,e){return i(`TOOLNET_LLM_FALLBACK_${t}_${e}`)}function me(){let t=[];for(let e of[1,2]){let n=I(e,"PROVIDER");if(!n||!_(n))continue;let r=b(n);t.push({slot:e,config:{provider:n,apiKey:I(e,"API_KEY"),baseUrl:f(I(e,"BASE_URL"),r.defaultBaseUrl),model:f(I(e,"MODEL"),r.defaultModel),accountId:I(e,"ACCOUNT_ID")}})}return t}function fe(){let t=i("TOOLNET_LLM_FALLBACK_COOLDOWN_MS"),e=i("TOOLNET_LLM_MAX_RETRIES"),n=Number(t??6e4),r=Number(e??1);return{cooldownMs:Number.isFinite(n)&&n>=0?n:6e4,maxRetries:Number.isFinite(r)&&r>=0?Math.floor(r):1}}var T=class extends Error{status;constructor(e,n){super(e),this.name="AiHttpError",this.status=n}};async function M(t,e,n=3e4){let r=new AbortController,o=setTimeout(()=>r.abort(),n);o.unref?.();try{let s=await fetch(t,{...e,signal:r.signal}),a=await s.text();if(!s.ok){let c=a;try{let d=JSON.parse(a);c=d.error?.message??d.message??a}catch{}throw new T(c||`HTTP ${s.status}`,s.status)}return a.trim()?JSON.parse(a):{}}finally{clearTimeout(o)}}function L(t,e){return`${t.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`}var D=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 n=this.config.accountId?.trim(),r=this.config.apiKey?.trim();if(!n)throw new Error("cloudflare: ACCOUNT ID is not configured");if(!r)throw new Error("cloudflare: API TOKEN is not configured");let o=this.model(),a=`${(this.config.baseUrl?.trim()||`https://api.cloudflare.com/client/v4/accounts/${n}/ai/run`).replace(/\/+$/,"")}/${o}`,c=await M(a,{method:"POST",headers:{authorization:`Bearer ${r}`,"content-type":"application/json",...this.config.headers},body:JSON.stringify({messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens})}),d=c.result?.response?.trim();if(!d)throw new Error(c.errors?.[0]?.message??"cloudflare: empty model response");return{text:d,provider:"cloudflare",model:o}}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(n){return{ok:!1,provider:"cloudflare",model:this.config.model,message:n instanceof Error?n.message:String(n),latencyMs:Date.now()-e}}}};var $=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 n=this.config.apiKey?.trim();if(!n)throw new Error("gemini: API KEY is not configured");let r=this.config.baseUrl?.trim()||"https://generativelanguage.googleapis.com/v1beta",o=this.model(),s=e.messages.filter(m=>m.role==="system"),a=e.messages.filter(m=>m.role!=="system").map(m=>({role:m.role==="assistant"?"model":"user",parts:[{text:m.content}]})),c=`${L(r,`models/${encodeURIComponent(o)}:generateContent`)}?key=${encodeURIComponent(n)}`,d=await M(c,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...s.length?{systemInstruction:{parts:[{text:s.map(m=>m.content).join(`
5
5
 
6
- `)}]}}:{},contents:a,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),f=l.candidates?.[0]?.content?.parts?.map(d=>d.text??"").join("").trim();if(!f)throw new Error("gemini: empty model response");return{text:f,provider:"gemini",model:o,usage:l.usageMetadata?{inputTokens:l.usageMetadata.promptTokenCount,outputTokens:l.usageMetadata.candidatesTokenCount,totalTokens:l.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 F=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(),r=await v(P(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}:{}})}),o=r.choices?.[0]?.message?.content?.trim();if(!o)throw new Error(`${this.id}: empty model response`);return{text:o,provider:this.id,model:t,usage:r.usage?{inputTokens:r.usage.prompt_tokens,outputTokens:r.usage.completion_tokens,totalTokens:r.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 ie(n=re()){switch(h(n.id).transport){case"gemini":return new R(n);case"cloudflare":return new O(n);default:return new F(n)}}function dt(n){return new Promise(e=>{setTimeout(e,n)})}function mt(n){if(n instanceof S){let t=n.status;return t===void 0||t===408||t===409||t===425||t===429?!0:t>=500}if(!(n instanceof Error))return!0;let e=n.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 N=class{id;config;providers;states=new Map;cooldownMs;maxRetries;constructor(e,t=[],r={}){this.id=e.config.id,this.config=e.config,this.cooldownMs=r.cooldownMs??6e4,this.maxRetries=Math.max(0,r.maxRetries??1),this.providers=[e,...t].map(o=>({provider:ie(o.config),label:o.label}))}key(e){let t=this.providers[e];return`${e}:${t.provider.id}:${t.provider.config.model??""}`}state(e){let t=this.key(e),r=this.states.get(t);return r||(r={failures:0,cooldownUntil:0},this.states.set(t,r)),r}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 r=this.state(e);r.failures+=1,r.lastError=t instanceof Error?t.message:String(t),r.cooldownUntil=Date.now()+this.cooldownMs}async generate(e){let t=[];for(let r=0;r<this.providers.length;r+=1){if(!this.available(r)){t.push(`${this.providers[r].label}: cooldown`);continue}let o=this.providers[r];for(let i=0;i<=this.maxRetries;i+=1)try{let a=await o.provider.generate(e);return this.success(r),a}catch(a){let p=a instanceof Error?a.message:String(a),l=mt(a);if(t.push(`${o.label}: ${p}`),!l)throw a;if(i<this.maxRetries){await dt(Math.min(250*2**i,2e3));continue}this.fail(r,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 r=this.state(t);return{position:t,provider:e.provider.id,model:e.provider.config.model,cooldown:r.cooldownUntil>Date.now(),cooldownUntil:r.cooldownUntil||void 0,failures:r.failures,lastError:r.lastError}})}};function ae(){let n=z(),e=oe();return new N({label:`Primary (${n.llm.provider})`,config:{id:n.llm.provider,apiKey:n.llm.apiKey,baseUrl:n.llm.baseUrl,model:n.llm.model,accountId:n.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}})),se())}var W=class{constructor(e=ae()){this.provider=e}provider;get activeProvider(){return this.provider}setProvider(e){this.provider=e}generate(e){return this.provider.generate(e)}};function ce(){return new W(ae())}function pt(n,e){let t=JSON.stringify(n,null,2);return t.length<=e?t:t.slice(0,e)+`
7
- [truncated]`}function ft(n,e){let t=M(n,e),r=y(n,e,{maxFacts:12,maxChars:3200});return pt({project:r.context.project,intent:r.intent,directAnswer:t.answer,selectedMemory:r.context.selectedFacts,retrievalStats:r.stats},4200)}async function le(n,e,t={}){let r=M(n,e),o=ft(n,e),i=t.router??ce();try{let a=await i.generate({temperature:.1,maxTokens:450,messages:[{role:"system",content:`
6
+ `)}]}}:{},contents:a,generationConfig:{temperature:e.temperature,maxOutputTokens:e.maxTokens}})}),l=d.candidates?.[0]?.content?.parts?.map(m=>m.text??"").join("").trim();if(!l)throw new Error("gemini: empty model response");return{text:l,provider:"gemini",model:o,usage:d.usageMetadata?{inputTokens:d.usageMetadata.promptTokenCount,outputTokens:d.usageMetadata.candidatesTokenCount,totalTokens:d.usageMetadata.totalTokenCount}:void 0}}async healthCheck(){let e=Date.now();try{return{ok:!0,provider:"gemini",model:(await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8})).model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(n){return{ok:!1,provider:"gemini",model:this.config.model,message:n instanceof Error?n.message:String(n),latencyMs:Date.now()-e}}}};var K=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 n=this.model(),r=await M(L(this.baseUrl(),"chat/completions"),{method:"POST",headers:this.headers(),body:JSON.stringify({model:n,messages:e.messages,temperature:e.temperature,max_tokens:e.maxTokens,...this.id==="alibaba"?{enable_thinking:!1}:{}})}),o=r.choices?.[0]?.message?.content?.trim();if(!o)throw new Error(`${this.id}: empty model response`);return{text:o,provider:this.id,model:n,usage:r.usage?{inputTokens:r.usage.prompt_tokens,outputTokens:r.usage.completion_tokens,totalTokens:r.usage.total_tokens}:void 0}}async healthCheck(){let e=Date.now();try{let n=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:this.id,model:n.model,message:"Provider reachable",latencyMs:Date.now()-e}}catch(n){return{ok:!1,provider:this.id,model:this.config.model,message:n instanceof Error?n.message:String(n),latencyMs:Date.now()-e}}}};function pe(t=de()){switch(b(t.id).transport){case"gemini":return new $(t);case"cloudflare":return new D(t);default:return new K(t)}}function St(t){return new Promise(e=>{setTimeout(e,t)})}function Ct(t){if(t instanceof T){let n=t.status;return n===void 0||n===408||n===409||n===425||n===429?!0:n>=500}if(!(t instanceof Error))return!0;let e=t.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 U=class{id;config;providers;states=new Map;cooldownMs;maxRetries;constructor(e,n=[],r={}){this.id=e.config.id,this.config=e.config,this.cooldownMs=r.cooldownMs??6e4,this.maxRetries=Math.max(0,r.maxRetries??1),this.providers=[e,...n].map(o=>({provider:pe(o.config),label:o.label}))}key(e){let n=this.providers[e];return`${e}:${n.provider.id}:${n.provider.config.model??""}`}state(e){let n=this.key(e),r=this.states.get(n);return r||(r={failures:0,cooldownUntil:0},this.states.set(n,r)),r}available(e){return this.state(e).cooldownUntil<=Date.now()}success(e){let n=this.state(e);n.failures=0,n.cooldownUntil=0,n.lastError=void 0}fail(e,n){let r=this.state(e);r.failures+=1,r.lastError=n instanceof Error?n.message:String(n),r.cooldownUntil=Date.now()+this.cooldownMs}async generate(e){let n=[];for(let r=0;r<this.providers.length;r+=1){if(!this.available(r)){n.push(`${this.providers[r].label}: cooldown`);continue}let o=this.providers[r];for(let s=0;s<=this.maxRetries;s+=1)try{let a=await o.provider.generate(e);return this.success(r),a}catch(a){let c=a instanceof Error?a.message:String(a),d=Ct(a);if(n.push(`${o.label}: ${c}`),!d)throw a;if(s<this.maxRetries){await St(Math.min(250*2**s,2e3));continue}this.fail(r,a)}}throw new Error(`All ToolNet LLM providers failed: ${n.join(" | ")}`)}async healthCheck(){let e=Date.now();try{let n=await this.generate({messages:[{role:"user",content:"Reply exactly: OK"}],temperature:0,maxTokens:8});return{ok:!0,provider:n.provider,model:n.model,message:"Fallback chain reachable",latencyMs:Date.now()-e}}catch(n){return{ok:!1,provider:this.id,model:this.config.model,message:n instanceof Error?n.message:String(n),latencyMs:Date.now()-e}}}status(){return this.providers.map((e,n)=>{let r=this.state(n);return{position:n,provider:e.provider.id,model:e.provider.config.model,cooldown:r.cooldownUntil>Date.now(),cooldownUntil:r.cooldownUntil||void 0,failures:r.failures,lastError:r.lastError}})}};function ge(){let t=V(),e=me();return new U({label:`Primary (${t.llm.provider})`,config:{id:t.llm.provider,apiKey:t.llm.apiKey,baseUrl:t.llm.baseUrl,model:t.llm.model,accountId:t.llm.accountId}},e.map(n=>({label:`Fallback ${n.slot} (${n.config.provider})`,config:{id:n.config.provider,apiKey:n.config.apiKey,baseUrl:n.config.baseUrl,model:n.config.model,accountId:n.config.accountId}})),fe())}var J=class{constructor(e=ge()){this.provider=e}provider;get activeProvider(){return this.provider}setProvider(e){this.provider=e}generate(e){return this.provider.generate(e)}};function ye(){return new J(ge())}function wt(t,e){let n=JSON.stringify(t,null,2);return n.length<=e?n:n.slice(0,e)+`
7
+ [truncated]`}function Et(t,e){let n=x(t,e),r=h(t,e,{maxFacts:12,maxChars:3200});return wt({project:r.context.project,intent:r.intent,directAnswer:n.answer,selectedMemory:r.context.selectedFacts,retrievalStats:r.stats},4200)}async function he(t,e,n={}){let r=x(t,e),o=Et(t,e),s=n.router??ye();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,10 +41,13 @@ ToolNet selected memory:
41
41
  ${o}
42
42
 
43
43
  Answer the coding agent directly.
44
- `.trim()}]}),p=a.text.trim();return p?{answer:p,provider:a.provider,model:a.model,usedAi:!0}:{answer:r.answer,usedAi:!1}}catch{return{answer:r.answer,usedAi:!1}}}import{existsSync as gt,mkdirSync as yt,readFileSync as ht,renameSync as kt,rmSync as bt,writeFileSync as vt}from"node:fs";import{join as ue}from"node:path";var At=720*60*1e3;function de(n){return ue(n.rootPath,".toolnet","context","memory-agent-conversation.json")}function E(n){return n.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}function Mt(n){let e=E(n);return[/\btiếp tục\b/u,/\btiếp tục task\b/u,/\blúc nãy\b/u,/\btrước đó\b/u,/\btask trước\b/u,/\bprevious (?:task|session|work)\b/u,/\bcontinue\b/u,/\bresume\b/u,/\bcurrent task\b/u,/\bđang làm gì\b/u].some(t=>t.test(e))}function xt(n){if(Mt(n))return!1;let e=E(n),t=e.split(/\s+/u).filter(Boolean);return[/^(?:tại sao|vì sao|sao vậy)\b/u,/^(?:why|why so|why that)\b/u,/^(?:còn|thế|vậy|rồi sao|sau đó)\b/u,/^(?:what about|and what|then what)\b/u,/^(?:cái đó|việc đó|nó|phần đó)\b/u].some(r=>r.test(e))?!0:t.length<=5&&/\b(?:nó|đó|vậy|thế|that|it|this)\b/u.test(e)}function wt(n,e,t){let r=de(n);if(!gt(r))return null;try{let o=JSON.parse(ht(r,"utf8"));if(o.schema!=="toolnet.memory-conversation.v1"||o.version!==1||o.projectId!==n.id||!Array.isArray(o.focus))return null;let i=Date.parse(o.updatedAt);return!Number.isFinite(i)||e-i>t?null:o}catch{return null}}function St(n,e=8){let t=new Set,r=[];for(let o of n){let i=o.value.replace(/\s+/gu," ").trim();if(!i)continue;let a=[o.kind,E(i)].join(":");if(!t.has(a)&&(t.add(a),r.push({...o,value:i}),r.length>=e))break}return r}function Et(n,e){let t=de(n),r=ue(n.rootPath,".toolnet","context");yt(r,{recursive:!0,mode:448});let o=`${t}.${process.pid}.tmp`;try{vt(o,JSON.stringify(e,null,2)+`
45
- `,{encoding:"utf8",mode:384}),kt(o,t)}finally{bt(o,{force:!0})}}function Ct(n){return n.focus.slice(0,8).map(e=>`- ${e.kind}: ${e.value}`).join(`
46
- `)}function _t(n,e){return n.priorFocus.find(t=>t.kind===e)?.value}function H(n){if(!n.usedPriorFocus||n.currentIntent!=="summary"||n.priorFocus.length===0)return null;let e=E(n.originalQuestion),t=/^(?:tại sao|vì sao|sao vậy|why|why so|why that)\b/u.test(e),r=/^(?:rồi sao|sau đó|tiếp thì sao|thế tiếp theo|then what|what next)\b/u.test(e),o=t?["decision","blocker","next_action","task","file"]:r?["next_action","todo","task","blocker","file","decision"]:["task","next_action","file","decision","blocker"],i={task:"Task li\xEAn quan",next_action:"Vi\u1EC7c ti\u1EBFp theo",file:"File li\xEAn quan",decision:"Quy\u1EBFt \u0111\u1ECBnh li\xEAn quan",blocker:"Blocker",todo:"TODO"},a=[];for(let p of o){let l=_t(n,p);if(l&&(a.push(`${i[p]??p}: ${l}.`),t&&a.length>=2||!t&&a.length>=3))break}return a.length===0?null:{answer:a.join(" "),intent:"summary",source:"conversation-focus"}}function It(n){let e=E(n);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)||/(?:còn|các)\s+(?:todo|việc)\b/u.test(e)}function me(n,e,t={}){let r=t.now??Date.now(),o=t.maxAgeMs??At,i=wt(n,r,o),a=!!(i&&i.focus.length>0&&xt(e)&&!It(e)),p=a&&i?[e.trim(),"","Previous ToolNet Memory conversation focus:",Ct(i),"","Use the compact focus only to resolve the current follow-up question.","Do not reconstruct or request raw session transcripts."].join(`
47
- `):e.trim(),l=C(e),d=y(n,p,{maxFacts:8,maxChars:1800}).facts.map(b=>({kind:b.kind,value:b.value,source:b.source})),g=St(a&&i?[...d,...i.focus]:d);return Et(n,{schema:"toolnet.memory-conversation.v1",version:1,projectId:n.id,updatedAt:new Date(r).toISOString(),lastIntent:l,focus:g}),{question:p,originalQuestion:e,usedPriorFocus:a,previousIntent:i?.lastIntent,currentIntent:l,priorFocus:i?.focus??[],focusCount:g.length}}var Dr={question:pe.string().min(2).max(4e3).describe("Question about previous project work, unfinished tasks, handoff, blockers, decisions, files or next actions."),mode:pe.enum(["ai","local"]).optional().describe("ai uses ToolNet Memory Agent with configured LLM fallback chain. local returns deterministic local memory only.")};async function fe(n,e){let t=me(n.project,e.question);if(e.mode==="local"){let o=H(t);if(o)return{answer:o.answer,mode:"local",usedAi:!1,source:o.source,intent:o.intent};let i=M(n.project,t.originalQuestion);return{answer:i.answer,mode:"local",usedAi:!1,source:i.source,intent:i.intent}}let r=await le(n.project,t.question);if(!r.usedAi){let o=H(t);if(o)return{answer:o.answer,mode:"ai",usedAi:!1,provider:r.provider,model:r.model}}return{answer:r.answer,mode:"ai",usedAi:r.usedAi,provider:r.provider,model:r.model}}var ge="RAW_TRANSCRIPT_MUST_NEVER_ENTER_CONTINUITY_CONTEXT_X1";function ye(n,e){he(n,JSON.stringify(e,null,2)+`
48
- `,"utf8")}function Rt(n,e,t,r,o,i,a){return{continuity:{schema:"toolnet.handoff.v2",version:2,project:{id:n,name:e},source:{agent:t,nativeSessionId:`${t}-x1-source`,sessionKey:`${t}:${t}-x1-source`,sequence:42,reason:"checkpoint"},capturedAt:"2026-08-13T05:30:00.000Z",current:{phase:{id:"x1",title:"Cross-Agent Continuity E2E",status:"in_progress"},task:{id:"x1-cross-agent",title:r,status:"in_progress"},file:o},completed:{phases:["A1 OpenCode Adapter","A2 Agy Adapter","A3 Claude Code Adapter"],tasks:["Build canonical handoff schema","Build intelligent memory retrieval"]},remaining:{phases:["X1 Cross-Agent Continuity E2E"],tasks:[r],todos:[i]},nextAction:a,blockers:[],decisions:["Canonical handoff must override stale session state","Never replay raw transcripts during continuity recovery"],files:{current:o,recent:[o]},tests:{status:"passing",recent:["A1-A3 adapter tests passed"]},attention:[],progress:{phasesTotal:3,phasesCompleted:2,tasksTotal:4,tasksCompleted:3,blocked:0},stateDigest:"a".repeat(64)}}}async function L(n,e){return fe({project:n},{question:e,mode:"local"})}async function Ft(n,e){let t=Tt(k(Ot(),`toolnet-x1-${n}-${e}-`));try{let r=`x1-${n}-${e}`,o=`x1-${n}-to-${e}`,i={id:r,name:o,rootPath:t,createdAt:"2026-08-13T05:30:00.000Z",updatedAt:"2026-08-13T05:30:00.000Z",graphVersion:1,memoryVersion:1},a=k(t,".toolnet","work"),p=k(t,".toolnet","context"),l=k(t,".toolnet","sessions",n,"raw-session-x1");G(a,{recursive:!0}),G(p,{recursive:!0}),G(l,{recursive:!0});let f=`X1 ${n} to ${e} canonical continuity`,d=`src/x1/${n}-to-${e}.ts`,g=`Implement ${e} continuation step`,b=`Continue ${f} in ${d}`;ye(k(a,"handoff-latest.json"),Rt(r,o,n,f,d,g,b)),ye(k(p,"session-origin.json"),{version:1,projectId:r,agent:"stale-agent",nativeSessionId:"stale-session",updatedAt:"2026-01-01T00:00:00.000Z",currentTask:"STALE TASK MUST NOT WIN",currentPhase:"STALE PHASE",lastTouchedFile:"src/stale/old.ts",latestNextAction:"STALE NEXT ACTION"}),he(k(l,"events.jsonl"),JSON.stringify({text:ge})+`
49
- `,"utf8");let be=y(i,"T\xF4i ph\u1EA3i l\xE0m g\xEC ti\u1EBFp?",{maxFacts:12,maxChars:3200}),D=await L(i,"Task hi\u1EC7n t\u1EA1i \u0111ang l\xE0m l\xE0 g\xEC?"),K=await L(i,"File hi\u1EC7n t\u1EA1i l\xE0 file n\xE0o?"),$=await L(i,"TODO c\xF2n l\u1EA1i l\xE0 g\xEC?"),U=await L(i,"T\xF4i ph\u1EA3i l\xE0m g\xEC ti\u1EBFp?"),ve=[D.answer,K.answer,$.answer,U.answer].join(`
50
- `),j=[D,K,$,U],Y={canonicalHandoffPreferred:be.facts[0]?.source==="handoff",taskRecovered:D.answer.includes(f),fileRecovered:K.answer.includes(d),todoRecovered:$.answer.includes(g),nextActionRecovered:U.answer.includes(b),localModeOnly:j.every(A=>A.mode==="local"),noAiRequired:j.every(A=>A.usedAi===!1),rawTranscriptIsolated:!ve.includes(ge),compact:j.every(A=>A.answer.length<1600)};return{from:n,to:e,passed:Object.values(Y).every(Boolean),checks:Y}}finally{Pt(t,{recursive:!0,force:!0})}}async function ke(){let n=[["agy","codex"],["codex","opencode"],["opencode","claude"],["claude","kiro"],["kiro","cursor"],["cursor","copilot"],["copilot","grok"],["grok","agy"]],e=[];for(let[r,o]of n)e.push(await Ft(r,o));let t=e.filter(r=>r.passed).length;return{passed:t===e.length,total:e.length,passedCount:t,cases:e}}var m={reset:"\x1B[0m",green:"\x1B[32m",red:"\x1B[31m",cyan:"\x1B[36m",gray:"\x1B[90m",white:"\x1B[97m"};function Nt(n){return n?`${m.green}\u2713${m.reset}`:`${m.red}\u2717${m.reset}`}function Lt(n){let e=`${n.from.padEnd(8)} \u2192 ${n.to.padEnd(8)}`;if(console.log(`\u2502 ${Nt(n.passed)} ${e}`),!n.passed)for(let[t,r]of Object.entries(n.checks))r||console.log(`\u2502 ${m.red}\u2717${m.reset} ${t}`)}async function Dt(){console.log(""),console.log(`${m.cyan}\u25C7${m.reset} ${m.white}ToolNet Cross-Agent Continuity Certification${m.reset}`),console.log(`${m.gray}\u2502${m.reset}`);let n=await ke();for(let e of n.cases)Lt(e);if(console.log(`${m.gray}\u2502${m.reset}`),n.passed){console.log(`${m.green}\u25C6 PASS${m.reset} ${n.passedCount}/${n.total} cross-agent transitions`),console.log(`${m.green}\u2713${m.reset} canonical handoff`),console.log(`${m.green}\u2713${m.reset} memory_agent_ask`),console.log(`${m.green}\u2713${m.reset} task / file / TODO / next action`),console.log(`${m.green}\u2713${m.reset} raw transcripts isolated`),console.log(`${m.green}\u2713${m.reset} AI not required for direct continuity`);return}console.log(`${m.red}\u25C6 FAIL${m.reset} ${n.passedCount}/${n.total} cross-agent transitions`),process.exitCode=1}Dt().catch(n=>{console.error(n instanceof Error?n.message:String(n)),process.exitCode=1});
44
+ `.trim()}]}),c=a.text.trim();return c?{answer:c,provider:a.provider,model:a.model,usedAi:!0}:{answer:r.answer,usedAi:!1}}catch{return{answer:r.answer,usedAi:!1}}}import{existsSync as _t,mkdirSync as It,readFileSync as Tt,renameSync as Ot,rmSync as Pt,writeFileSync as Rt}from"node:fs";import{join as ke}from"node:path";var Ft=720*60*1e3;function be(t){return ke(t.rootPath,".toolnet","context","memory-agent-conversation.json")}function O(t){return t.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}function Nt(t){let e=O(t);return[/\btiếp tục\b/u,/\btiếp tục task\b/u,/\blúc nãy\b/u,/\btrước đó\b/u,/\btask trước\b/u,/\bprevious (?:task|session|work)\b/u,/\bcontinue\b/u,/\bresume\b/u,/\bcurrent task\b/u,/\bđang làm gì\b/u].some(n=>n.test(e))}function Lt(t){if(Nt(t))return!1;let e=O(t),n=e.split(/\s+/u).filter(Boolean);return[/^(?:tại sao|vì sao|sao vậy)\b/u,/^(?:why|why so|why that)\b/u,/^(?:còn|thế|vậy|rồi sao|sau đó)\b/u,/^(?:what about|and what|then what)\b/u,/^(?:cái đó|việc đó|nó|phần đó)\b/u].some(r=>r.test(e))?!0:n.length<=5&&/\b(?:nó|đó|vậy|thế|that|it|this)\b/u.test(e)}function Dt(t,e,n){let r=be(t);if(!_t(r))return null;try{let o=JSON.parse(Tt(r,"utf8"));if(o.schema!=="toolnet.memory-conversation.v1"||o.version!==1||o.projectId!==t.id||!Array.isArray(o.focus))return null;let s=Date.parse(o.updatedAt);return!Number.isFinite(s)||e-s>n?null:o}catch{return null}}function $t(t,e=8){let n=new Set,r=[];for(let o of t){let s=o.value.replace(/\s+/gu," ").trim();if(!s)continue;let a=[o.kind,O(s)].join(":");if(!n.has(a)&&(n.add(a),r.push({...o,value:s}),r.length>=e))break}return r}function Kt(t,e){let n=be(t),r=ke(t.rootPath,".toolnet","context");It(r,{recursive:!0,mode:448});let o=`${n}.${process.pid}.tmp`;try{Rt(o,JSON.stringify(e,null,2)+`
45
+ `,{encoding:"utf8",mode:384}),Ot(o,n)}finally{Pt(o,{force:!0})}}function Ut(t){return t.focus.slice(0,8).map(e=>`- ${e.kind}: ${e.value}`).join(`
46
+ `)}function jt(t,e){return t.priorFocus.find(n=>n.kind===e)?.value}function X(t){if(!t.usedPriorFocus||t.currentIntent!=="summary"||t.priorFocus.length===0)return null;let e=O(t.originalQuestion),n=/^(?:tại sao|vì sao|sao vậy|why|why so|why that)\b/u.test(e),r=/^(?:rồi sao|sau đó|tiếp thì sao|thế tiếp theo|then what|what next)\b/u.test(e),o=n?["decision","blocker","next_action","task","file"]:r?["next_action","todo","task","blocker","file","decision"]:["task","next_action","file","decision","blocker"],s={task:"Task li\xEAn quan",next_action:"Vi\u1EC7c ti\u1EBFp theo",file:"File li\xEAn quan",decision:"Quy\u1EBFt \u0111\u1ECBnh li\xEAn quan",blocker:"Blocker",todo:"TODO"},a=[];for(let c of o){let d=jt(t,c);if(d&&(a.push(`${s[c]??c}: ${d}.`),n&&a.length>=2||!n&&a.length>=3))break}return a.length===0?null:{answer:a.join(" "),intent:"summary",source:"conversation-focus"}}function Bt(t){let e=O(t);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)||/(?:còn|các)\s+(?:todo|việc)\b/u.test(e)}function ve(t,e,n={}){let r=n.now??Date.now(),o=n.maxAgeMs??Ft,s=Dt(t,r,o),a=!!(s&&s.focus.length>0&&Lt(e)&&!Bt(e)),c=a&&s?[e.trim(),"","Previous ToolNet Memory conversation focus:",Ut(s),"","Use the compact focus only to resolve the current follow-up question.","Do not reconstruct or request raw session transcripts."].join(`
47
+ `):e.trim(),d=P(e),m=h(t,c,{maxFacts:8,maxChars:1800}).facts.map(A=>({kind:A.kind,value:A.value,source:A.source})),y=$t(a&&s?[...m,...s.focus]:m);return Kt(t,{schema:"toolnet.memory-conversation.v1",version:1,projectId:t.id,updatedAt:new Date(r).toISOString(),lastIntent:d,focus:y}),{question:c,originalQuestion:e,usedPriorFocus:a,previousIntent:s?.lastIntent,currentIntent:d,priorFocus:s?.focus??[],focusCount:y.length}}import{existsSync as Ht,readFileSync as qt}from"node:fs";import{join as zt}from"node:path";function k(t){return!!t?.trim()}function Ae(t){let e=[],n=[],r=100;k(t.goal)||k(t.request)||(e.push("goal_or_request"),r-=20),k(t.activity)||k(t.current.task?.title)||k(t.current.phase?.title)||(e.push("current_work"),r-=25),k(t.nextAction)||k(t.remaining.todos[0])||(e.push("next_action"),r-=25),t.tests.status!=="unknown"||t.tests.recent.length>0||(t.tests.checks?.length??0)>0||(t.evidence?.commands.length??0)>0||(t.evidence?.references.length??0)>0||(e.push("evidence"),r-=20),k(t.files.current)||t.files.recent.length>0||(t.files.active?.length??0)>0||(t.files.modified?.length??0)>0||(t.files.created?.length??0)>0||(e.push("files"),r-=10),t.tests.status==="failing"&&n.push("tests_failing"),t.blockers.length>0&&n.push("active_blockers"),r=Math.max(0,Math.min(100,r));let l=e.includes("current_work")||e.includes("next_action"),m;return r>=80&&!l?m="high":r>=50?m="medium":m="low",{confidence:m,score:r,missingContext:e,warnings:n}}var xe={compact:{completed:3,evidence:3,files:5,blockers:2,maxChars:1800},normal:{completed:10,evidence:10,files:15,blockers:5,maxChars:4200},benchmark:{completed:30,evidence:30,files:40,blockers:10,maxChars:1e4}};function S(t){let e=new Set,n=[];for(let r of t){let o=r?.replace(/\s+/gu," ").trim();if(!o)continue;let s=o.normalize("NFKC").toLowerCase();e.has(s)||(e.add(s),n.push(o))}return n}function C(t){return t.length>0?t.map(e=>`- ${e}`).join(`
48
+ `):"- none"}function Wt(t,e){return t.length<=e?t:[t.slice(0,e).trimEnd(),"","[Structured handoff truncated]"].join(`
49
+ `)}function Me(t,e){if(e)return e;let n=t.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim();return/\bbenchmark\b/u.test(n)||/\bdeep handoff\b/u.test(n)||/\bfull handoff\b/u.test(n)||/\btakeover\b/u.test(n)||/\btake over\b/u.test(n)||/tiếp quản/u.test(n)||/bằng chứng đầy đủ/u.test(n)||/evidence.*(?:file|test|command)/u.test(n)?"benchmark":/\bcompact\b/u.test(n)||/\bbrief\b/u.test(n)||/ngắn gọn/u.test(n)||/tóm tắt ngắn/u.test(n)?"compact":"normal"}function Gt(t,e="normal"){let n=xe[e],r=S([`Source agent: ${t.source.agent}`,`Captured: ${t.capturedAt}`,t.goal?`Goal: ${t.goal}`:void 0,t.request?`Request: ${t.request}`:void 0,t.activity?`Activity: ${t.activity}`:void 0,t.current.phase?`Phase: ${t.current.phase.title} [${t.current.phase.status}]`:void 0,t.current.task?`Task: ${t.current.task.title} [${t.current.task.status}]`:void 0,t.current.file?`Current file: ${t.current.file}`:void 0,`Progress: ${JSON.stringify(t.progress)}`]),o=S([...t.completed.phases.map(l=>`Phase: ${l}`),...t.completed.tasks.map(l=>`Task: ${l}`)]).slice(0,n.completed),s=S([`Tests status: ${t.tests.status}`,...t.tests.recent.map(l=>`Test: ${l}`),...(t.tests.checks??[]).map(l=>`Check [${l.status}] ${l.kind}: ${l.command}`),...(t.evidence?.commands??[]).map(l=>`Command: ${l}`),...(t.evidence?.references??[]).map(l=>`Reference: ${l}`),...t.decisions.map(l=>`Decision: ${l}`),...t.attention.map(l=>`Attention: ${l}`)]).slice(0,n.evidence),a=S([t.files.current,...(t.files.active??[]).map(l=>`Active: ${l}`),...(t.files.modified??[]).map(l=>`Modified: ${l}`),...(t.files.created??[]).map(l=>`Created: ${l}`),...(t.files.deleted??[]).map(l=>`Deleted: ${l}`),...t.files.recent.map(l=>`Recent: ${l}`)]).slice(0,n.files),c=S(t.blockers).slice(0,n.blockers),d=S([t.nextAction,t.nextAction?void 0:t.remaining.todos[0]]).slice(0,1);return{currentState:r,completed:o,evidence:s,filesTouched:a,blockers:c,nextAction:d}}function Yt(t,e,n){return[`HANDOFF_DETAIL: ${e}`,`CONTINUITY_CONFIDENCE: ${n.confidence}`,`QUALITY_SCORE: ${n.score}`,`MISSING_CONTEXT: ${n.missingContext.length>0?n.missingContext.join(", "):"none"}`,`QUALITY_WARNINGS: ${n.warnings.length>0?n.warnings.join(", "):"none"}`,"","CURRENT_STATE",C(t.currentState),"","COMPLETED",C(t.completed),"","EVIDENCE",C(t.evidence),"","FILES_TOUCHED",C(t.filesTouched),"","BLOCKERS",C(t.blockers),"","NEXT_ACTION",C(t.nextAction)].join(`
50
+ `)}function Se(t,e="normal"){let n=zt(t.rootPath,".toolnet","work","handoff-latest.json");if(!Ht(n))return null;try{let o=JSON.parse(qt(n,"utf8")).continuity;if(!o||o.schema!=="toolnet.handoff.v2"||o.version!==2)return null;let s=Gt(o,e),a=Ae(o),c=Wt(Yt(s,e,a),xe[e].maxChars);return{detail:e,data:s,quality:a,text:c}}catch{return null}}function Qt(t){return t.normalize("NFKC").toLowerCase().replace(/\s+/gu," ").trim()}var Vt=[/\bhandoff\b/u,/\bcontinuity\b/u,/\bcontinue\b/u,/\bresume\b/u,/\btakeover\b/u,/\btake over\b/u,/tiếp tục/u,/tiếp quản/u,/bàn giao/u,/dừng ở đâu/u,/đang làm gì/u],Jt=[/\bcurrent state\b/u,/\bcurrent task\b/u,/\bevidence\b/u,/\breport locations?\b/u,/\bfiles?\b/u,/\burls?\b/u,/\bassets?\b/u,/\btests?\b/u,/\bcommands?\b/u,/\bblockers?\b/u,/\bnext actions?\b/u,/trạng thái hiện tại/u,/task hiện tại/u,/bằng chứng/u,/vị trí báo cáo/u,/file/u,/url/u,/blocker/u,/việc tiếp theo/u,/bước tiếp theo/u],Xt=[/\bsummarize\b/u,/\bsummary\b/u,/\bfull state\b/u,/\bfull context\b/u,/tóm tắt/u,/đầy đủ/u,/toàn bộ trạng thái/u];function Zt(t){let e=0;for(let n of Jt)n.test(t)&&(e+=1);return e}function Ce(t,e){let n=Qt(t);if(/(?:^|\s)(?:todo|to-do)(?:\s|$)/u.test(n)||/(?:việc|task)\s+(?:còn lại|chưa làm|chưa xong|chưa hoàn thành)/u.test(n)||/(?:còn|các)\s+(?:todo|việc)\b/u.test(n))return!1;if(e==="summary"||e==="status")return!0;if(!n)return!1;let o=Vt.some(c=>c.test(n)),s=Xt.some(c=>c.test(n)),a=Zt(n);return!!(o&&a>=1||s&&a>=2||a>=4)}var yo={question:Z.string().min(2).max(4e3).describe("Question about previous project work, unfinished tasks, handoff, blockers, decisions, files or next actions."),mode:Z.enum(["ai","local"]).optional().describe("ai uses ToolNet Memory Agent with configured LLM fallback chain. local returns deterministic local memory only."),detail:Z.enum(["compact","normal","benchmark"]).optional().describe("Handoff detail level. compact=minimal, normal=standard, benchmark=deep evidence/files/tests for agent takeover.")};function j(t,e,n,r,o){if(!Ce(e,n))return{answer:r};let s=Me(e,o),a=Se(t.project,s);return a?{answer:a.text,handoff:a.data,detail:a.detail,confidence:a.quality.confidence,missingContext:a.quality.missingContext,quality:a.quality}:{answer:r}}async function ee(t,e){let n=ve(t.project,e.question);if(e.mode==="local"){let a=X(n);if(a)return{...j(t,n.originalQuestion,String(a.intent),a.answer,e.detail),mode:"local",usedAi:!1,source:a.source,intent:a.intent};let c=x(t.project,n.originalQuestion);return{...j(t,n.originalQuestion,String(c.intent),c.answer,e.detail),mode:"local",usedAi:!1,source:c.source,intent:c.intent}}let r=x(t.project,n.originalQuestion),o=j(t,n.originalQuestion,String(r.intent),r.answer,e.detail);if("handoff"in o)return{...o,mode:"ai",usedAi:!1,source:r.source,intent:r.intent,routing:"deterministic-handoff"};let s=await he(t.project,n.question);if(!s.usedAi){let a=X(n);if(a)return{...j(t,n.originalQuestion,String(a.intent),a.answer,e.detail),mode:"ai",usedAi:!1,provider:s.provider,model:s.model}}return{answer:s.answer,mode:"ai",usedAi:s.usedAi,provider:s.provider,model:s.model}}var we="RAW_TRANSCRIPT_MUST_NEVER_ENTER_CONTINUITY_CONTEXT_X1";function Ee(t,e){_e(t,JSON.stringify(e,null,2)+`
51
+ `,"utf8")}function rn(t,e,n,r,o,s,a,c){return{continuity:{schema:"toolnet.handoff.v2",version:2,project:{id:t,name:e},source:{agent:n,nativeSessionId:`${n}-x1-source`,sessionKey:`${n}:${n}-x1-source`,sequence:42,reason:"checkpoint"},capturedAt:"2026-08-13T05:30:00.000Z",goal:`Continue ${e} safely across agents`,request:`Recover ${o} with exact evidence and next action`,activity:`Preparing ${r} takeover from ${n}`,current:{phase:{id:"x1",title:"Cross-Agent Continuity E2E",status:"in_progress"},task:{id:"x1-cross-agent",title:o,status:"in_progress"},file:s},completed:{phases:["A1 OpenCode Adapter","A2 Agy Adapter","A3 Claude Code Adapter"],tasks:["Build canonical handoff schema","Build intelligent memory retrieval"]},remaining:{phases:["X1 Cross-Agent Continuity E2E"],tasks:[o],todos:[a]},nextAction:c,blockers:[],decisions:["Canonical handoff must override stale session state","Never replay raw transcripts during continuity recovery"],files:{current:s,recent:[s]},tests:{status:"passing",recent:["A1-A3 adapter tests passed"],checks:[{kind:"test",status:"passed",command:`node scripts/${n}-to-${r}-verify.mjs`}]},evidence:{commands:[`node scripts/${n}-to-${r}-verify.mjs`],references:[`https://example.test/${n}/${r}/continuity-report`]},attention:[],progress:{phasesTotal:3,phasesCompleted:2,tasksTotal:4,tasksCompleted:3,blocked:0},stateDigest:"a".repeat(64)}}}async function B(t,e){return ee({project:t},{question:e,mode:"local"})}async function on(t,e){let n=en(v(nn(),`toolnet-x1-${t}-${e}-`));try{let r=`x1-${t}-${e}`,o=`x1-${t}-to-${e}`,s={id:r,name:o,rootPath:n,createdAt:"2026-08-13T05:30:00.000Z",updatedAt:"2026-08-13T05:30:00.000Z",graphVersion:1,memoryVersion:1},a=v(n,".toolnet","work"),c=v(n,".toolnet","context"),d=v(n,".toolnet","sessions",t,"raw-session-x1");te(a,{recursive:!0}),te(c,{recursive:!0}),te(d,{recursive:!0});let l=`X1 ${t} to ${e} canonical continuity`,m=`src/x1/${t}-to-${e}.ts`,y=`Implement ${e} continuation step`,A=`Continue ${l} in ${m}`;Ee(v(a,"handoff-latest.json"),rn(r,o,t,e,l,m,y,A)),Ee(v(c,"session-origin.json"),{version:1,projectId:r,agent:"stale-agent",nativeSessionId:"stale-session",updatedAt:"2026-01-01T00:00:00.000Z",currentTask:"STALE TASK MUST NOT WIN",currentPhase:"STALE PHASE",lastTouchedFile:"src/stale/old.ts",latestNextAction:"STALE NEXT ACTION"}),_e(v(d,"events.jsonl"),JSON.stringify({text:we})+`
52
+ `,"utf8");let Te=h(s,"T\xF4i ph\u1EA3i l\xE0m g\xEC ti\u1EBFp?",{maxFacts:12,maxChars:3200}),H=await B(s,"Task hi\u1EC7n t\u1EA1i \u0111ang l\xE0m l\xE0 g\xEC?"),q=await B(s,"File hi\u1EC7n t\u1EA1i l\xE0 file n\xE0o?"),z=await B(s,"TODO c\xF2n l\u1EA1i l\xE0 g\xEC?"),W=await B(s,"T\xF4i ph\u1EA3i l\xE0m g\xEC ti\u1EBFp?"),g=await ee({project:s},{mode:"ai",detail:"benchmark",question:"Summarize current state, completed work, evidence, files, tests, blockers and exact next action for benchmark agent takeover."}),w=g,Oe=`node scripts/${t}-to-${e}-verify.mjs`,Pe=`https://example.test/${t}/${e}/continuity-report`,Re=[H.answer,q.answer,z.answer,W.answer,g.answer].join(`
53
+ `),G=[H,q,z,W],ne={canonicalHandoffPreferred:Te.facts[0]?.source==="handoff",taskRecovered:H.answer.includes(l),fileRecovered:q.answer.includes(m),todoRecovered:z.answer.includes(y),nextActionRecovered:W.answer.includes(A),localModeOnly:G.every(E=>E.mode==="local"),noAiRequired:G.every(E=>E.usedAi===!1),rawTranscriptIsolated:!Re.includes(we),compact:G.every(E=>E.answer.length<1600),structuredTakeoverRecovered:g.answer.includes("CURRENT_STATE")&&g.answer.includes("COMPLETED")&&g.answer.includes("EVIDENCE")&&g.answer.includes("FILES_TOUCHED")&&g.answer.includes("BLOCKERS")&&g.answer.includes("NEXT_ACTION"),benchmarkDetailRecovered:w.detail==="benchmark"&&g.answer.includes("HANDOFF_DETAIL: benchmark"),highConfidence:w.confidence==="high"&&Array.isArray(w.missingContext)&&w.missingContext.length===0,evidenceRecovered:g.answer.includes(Oe)&&g.answer.includes(Pe),deterministicTakeover:g.usedAi===!1&&w.routing==="deterministic-handoff"};return{from:t,to:e,passed:Object.values(ne).every(Boolean),checks:ne}}finally{tn(n,{recursive:!0,force:!0})}}async function Ie(){let t=[["agy","codex"],["codex","opencode"],["opencode","claude"],["claude","kiro"],["kiro","cursor"],["cursor","copilot"],["copilot","grok"],["grok","agy"]],e=[];for(let[r,o]of t)e.push(await on(r,o));let n=e.filter(r=>r.passed).length;return{passed:n===e.length,total:e.length,passedCount:n,cases:e}}var p={reset:"\x1B[0m",green:"\x1B[32m",red:"\x1B[31m",cyan:"\x1B[36m",gray:"\x1B[90m",white:"\x1B[97m"};function sn(t){return t?`${p.green}\u2713${p.reset}`:`${p.red}\u2717${p.reset}`}function an(t){let e=`${t.from.padEnd(8)} \u2192 ${t.to.padEnd(8)}`;if(console.log(`\u2502 ${sn(t.passed)} ${e}`),!t.passed)for(let[n,r]of Object.entries(t.checks))r||console.log(`\u2502 ${p.red}\u2717${p.reset} ${n}`)}async function cn(){console.log(""),console.log(`${p.cyan}\u25C7${p.reset} ${p.white}ToolNet Cross-Agent Continuity Certification${p.reset}`),console.log(`${p.gray}\u2502${p.reset}`);let t=await Ie();for(let e of t.cases)an(e);if(console.log(`${p.gray}\u2502${p.reset}`),t.passed){console.log(`${p.green}\u25C6 PASS${p.reset} ${t.passedCount}/${t.total} cross-agent transitions`),console.log(`${p.green}\u2713${p.reset} canonical handoff`),console.log(`${p.green}\u2713${p.reset} memory_agent_ask`),console.log(`${p.green}\u2713${p.reset} task / file / TODO / next action`),console.log(`${p.green}\u2713${p.reset} raw transcripts isolated`),console.log(`${p.green}\u2713${p.reset} AI not required for direct continuity`);return}console.log(`${p.red}\u25C6 FAIL${p.reset} ${t.passedCount}/${t.total} cross-agent transitions`),process.exitCode=1}cn().catch(t=>{console.error(t instanceof Error?t.message:String(t)),process.exitCode=1});