nex-code 0.4.13 → 0.4.15

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.
Files changed (2) hide show
  1. package/dist/nex-code.js +43 -43
  2. package/package.json +1 -1
package/dist/nex-code.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- var G=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Mn=G((jk,Hm)=>{Hm.exports={name:"nex-code",version:"0.4.13",description:"The open-source agentic coding CLI. Free with Ollama Cloud \u2014 switch to OpenAI, Anthropic or Gemini anytime. Alternative to Claude Code & Gemini CLI.",bin:{"nex-code":"./dist/nex-code.js"},files:["dist/","README.md","LICENSE"],engines:{node:">=18.0.0"},scripts:{start:"node dist/nex-code.js",build:"esbuild bin/nex-code.js --bundle --platform=node --target=node18 --outfile=dist/nex-code.js --minify --external:axios --external:dotenv --external:playwright",test:"jest --forceExit","test:orchestrator":"jest tests/orchestrator.test.js --forceExit",coverage:"jest --coverage --forceExit","test:watch":"jest --watch",format:"prettier --write .","install-hooks":"ln -sf ../../hooks/pre-push .git/hooks/pre-push && chmod +x .git/hooks/pre-push && ln -sf ../../hooks/post-merge .git/hooks/post-merge && chmod +x .git/hooks/post-merge && echo 'Hooks installed (pre-push, post-merge).'",prepublishOnly:"npm run build && npm test","merge-to-main":"bash scripts/merge-to-main.sh",release:"npm version patch && git push --follow-tags && npm publish"},keywords:["ai","cli","coding","agent","ollama","ollama-cloud","openai","anthropic","claude","gemini","llm","gpt","agentic","terminal","coding-assistant","claude-code-alternative","gemini-cli-alternative","open-source","free","qwen3","devstral","kimi-k2","deepseek","local-llm","mcp","model-context-protocol","multi-provider"],repository:{type:"git",url:"https://github.com/hybridpicker/nex-code.git"},bugs:{url:"https://github.com/hybridpicker/nex-code/issues"},homepage:"https://github.com/hybridpicker/nex-code#readme",license:"MIT",dependencies:{axios:"^1.7.0",dotenv:"^16.4.0"},devDependencies:{esbuild:"^0.27.3",jest:"^29.7.0",prettier:"^3.8.1"},jest:{coverageThreshold:{global:{lines:45,functions:30,branches:35},"./cli/sub-agent.js":{lines:70,functions:60,branches:55}}}}});var pn=G((qk,Cc)=>{"use strict";var kc="\x1B[0m",vc="\x1B[1m",Pn="\x1B[2m";function q(t,e,n){return`\x1B[38;2;${t};${e};${n}m`}function Gm(){if(!process.stdout.isTTY)return null;try{let{execFileSync:t}=require("child_process"),e=["import sys,os,tty,termios,select","f=open('/dev/tty','r+b',buffering=0)","fd=f.fileno()","s=termios.tcgetattr(fd)","try:"," tty.setraw(fd)"," f.write(bytes([0x1b,0x5d,0x31,0x31,0x3b,0x3f,0x1b,0x5c]))"," r=select.select([fd],[],[],0.1)[0]"," d=b''"," if r:"," while True:"," r2=select.select([fd],[],[],0.05)[0]"," if not r2:break"," c=os.read(fd,1)"," d+=c"," if d[-1:]==bytes([0x07]) or d[-2:]==bytes([0x1b,0x5c]):break"," sys.stdout.buffer.write(d)","finally:"," termios.tcsetattr(fd,termios.TCSADRAIN,s)"," f.close()"].join(`
2
+ var G=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Mn=G((jk,Hm)=>{Hm.exports={name:"nex-code",version:"0.4.15",description:"The open-source agentic coding CLI. Free with Ollama Cloud \u2014 switch to OpenAI, Anthropic or Gemini anytime. Alternative to Claude Code & Gemini CLI.",bin:{"nex-code":"./dist/nex-code.js"},files:["dist/","README.md","LICENSE"],engines:{node:">=18.0.0"},scripts:{start:"node dist/nex-code.js",build:"esbuild bin/nex-code.js --bundle --platform=node --target=node18 --outfile=dist/nex-code.js --minify --external:axios --external:dotenv --external:playwright",test:"jest --forceExit","test:orchestrator":"jest tests/orchestrator.test.js --forceExit",coverage:"jest --coverage --forceExit","test:watch":"jest --watch",format:"prettier --write .","install-hooks":"ln -sf ../../hooks/pre-push .git/hooks/pre-push && chmod +x .git/hooks/pre-push && ln -sf ../../hooks/post-merge .git/hooks/post-merge && chmod +x .git/hooks/post-merge && echo 'Hooks installed (pre-push, post-merge).'",prepublishOnly:"npm run build && npm test","merge-to-main":"bash scripts/merge-to-main.sh",release:"npm version patch && git push --follow-tags && npm publish"},keywords:["ai","cli","coding","agent","ollama","ollama-cloud","openai","anthropic","claude","gemini","llm","gpt","agentic","terminal","coding-assistant","claude-code-alternative","gemini-cli-alternative","open-source","free","qwen3","devstral","kimi-k2","deepseek","local-llm","mcp","model-context-protocol","multi-provider"],repository:{type:"git",url:"https://github.com/hybridpicker/nex-code.git"},bugs:{url:"https://github.com/hybridpicker/nex-code/issues"},homepage:"https://github.com/hybridpicker/nex-code#readme",license:"MIT",dependencies:{axios:"^1.7.0",dotenv:"^16.4.0"},devDependencies:{esbuild:"^0.27.3",jest:"^29.7.0",prettier:"^3.8.1"},jest:{coverageThreshold:{global:{lines:45,functions:30,branches:35},"./cli/sub-agent.js":{lines:70,functions:60,branches:55}}}}});var pn=G((qk,Cc)=>{"use strict";var kc="\x1B[0m",vc="\x1B[1m",Pn="\x1B[2m";function q(t,e,n){return`\x1B[38;2;${t};${e};${n}m`}function Gm(){if(!process.stdout.isTTY)return null;try{let{execFileSync:t}=require("child_process"),e=["import sys,os,tty,termios,select","f=open('/dev/tty','r+b',buffering=0)","fd=f.fileno()","s=termios.tcgetattr(fd)","try:"," tty.setraw(fd)"," f.write(bytes([0x1b,0x5d,0x31,0x31,0x3b,0x3f,0x1b,0x5c]))"," r=select.select([fd],[],[],0.1)[0]"," d=b''"," if r:"," while True:"," r2=select.select([fd],[],[],0.05)[0]"," if not r2:break"," c=os.read(fd,1)"," d+=c"," if d[-1:]==bytes([0x07]) or d[-2:]==bytes([0x1b,0x5c]):break"," sys.stdout.buffer.write(d)","finally:"," termios.tcsetattr(fd,termios.TCSADRAIN,s)"," f.close()"].join(`
3
3
  `),s=t("python3",["-c",e],{encoding:"buffer",timeout:400,stdio:["ignore","pipe","ignore"]}).toString("utf8").match(/rgb:([0-9a-fA-F]+)\/([0-9a-fA-F]+)\/([0-9a-fA-F]+)/);if(s){let r=parseInt(s[1].slice(0,2),16),i=parseInt(s[2].slice(0,2),16),c=parseInt(s[3].slice(0,2),16);return .299*r+.587*i+.114*c<128}}catch{}return null}function Sc(){let t=require("os");return require("path").join(t.homedir(),".nex-code",".theme_cache.json")}function Km(t){try{let n=require("fs").readFileSync(Sc(),"utf8"),o=JSON.parse(n);if(o&&typeof o[t]=="boolean")return o[t]}catch{}return null}function Ym(t,e){try{let n=require("fs"),o=require("path"),s=Sc(),r=o.dirname(s),i={};try{i=JSON.parse(n.readFileSync(s,"utf8"))}catch{}i[t]=e;let c=Object.keys(i);c.length>50&&c.slice(0,c.length-50).forEach(l=>delete i[l]),n.existsSync(r)||n.mkdirSync(r,{recursive:!0}),n.writeFileSync(s,JSON.stringify(i),"utf8")}catch{}}function zm(){let t=(process.env.NEX_THEME||"").toLowerCase();if(t==="light")return!1;if(t==="dark")return!0;let e=process.env.COLORFGBG;if(e){let i=e.split(";"),c=parseInt(i[i.length-1],10);if(!isNaN(c))return c<8}let n=process.env.TERM_SESSION_ID||"default",o=Km(n);if(o!==null)return o;let s=Gm(),r=s!==null?s:!0;return Ym(n,r),r}var Ec=zm(),Tc={reset:kc,bold:vc,dim:Pn,primary:q(80,190,255),secondary:q(60,170,190),success:q(80,210,120),warning:q(245,175,50),error:q(230,80,80),muted:Pn,subtle:q(130,130,145),tool_read:q(80,190,255),tool_write:q(245,165,55),tool_exec:q(185,100,235),tool_search:q(70,185,190),tool_git:q(90,210,100),tool_web:q(100,215,250),tool_sysadmin:q(225,150,75),tool_default:q(100,205,115),syn_keyword:q(185,100,235),syn_string:q(90,210,120),syn_number:q(245,175,50),syn_comment:Pn,syn_key:q(80,190,255),diff_add:q(80,210,120),diff_rem:q(230,80,80),banner_logo:q(80,200,255),banner_name:q(80,200,255),banner_version:Pn,banner_model:Pn,banner_yolo:q(245,175,50),footer_sep:Pn,footer_model:q(80,175,235),footer_branch:q(80,210,100),footer_project:q(130,130,145),footer_divider:q(80,80,95),footer_mode:q(210,150,50),white:"\x1B[37m",red:"\x1B[31m",green:"\x1B[32m",yellow:"\x1B[33m",blue:"\x1B[34m",magenta:"\x1B[35m",cyan:"\x1B[36m",gray:"\x1B[90m",bgRed:"\x1B[41m",bgGreen:"\x1B[42m",diff_add_bg:"\x1B[48;2;10;46;20m",diff_rem_bg:"\x1B[48;2;58;16;16m",brightCyan:"\x1B[96m",brightMagenta:"\x1B[95m",brightBlue:"\x1B[94m"},Rc={reset:kc,bold:vc,dim:q(110,110,120),primary:q(0,110,190),secondary:q(0,125,148),success:q(0,148,62),warning:q(168,92,0),error:q(188,32,32),muted:q(110,110,120),subtle:q(155,155,165),tool_read:q(0,110,190),tool_write:q(168,92,0),tool_exec:q(128,42,188),tool_search:q(0,122,148),tool_git:q(0,138,62),tool_web:q(0,112,178),tool_sysadmin:q(168,82,0),tool_default:q(0,138,62),syn_keyword:q(128,42,188),syn_string:q(0,138,62),syn_number:q(168,92,0),syn_comment:q(135,135,148),syn_key:q(0,110,190),diff_add:q(0,148,62),diff_rem:q(188,32,32),banner_logo:q(0,122,205),banner_name:q(0,122,205),banner_version:q(100,100,118),banner_model:q(100,100,118),banner_yolo:q(168,62,0),footer_sep:q(168,168,178),footer_model:q(0,102,175),footer_branch:q(0,138,62),footer_project:q(135,135,148),footer_divider:q(168,168,178),footer_mode:q(148,88,0),white:q(40,40,52),red:q(188,32,32),green:q(0,148,62),yellow:q(168,92,0),blue:q(0,110,190),magenta:q(128,42,188),cyan:q(0,125,148),gray:q(132,132,142),bgRed:"\x1B[41m",bgGreen:"\x1B[42m",diff_add_bg:"\x1B[48;2;215;245;220m",diff_rem_bg:"\x1B[48;2;255;215;215m",brightCyan:q(0,158,182),brightMagenta:q(158,52,208),brightBlue:q(0,112,208)},Xm=Ec?Tc:Rc;Cc.exports={T:Xm,isDark:Ec,DARK:Tc,LIGHT:Rc}});var Ln=G((Fk,Oc)=>{var{T:B}=pn(),mo=5,In=(()=>{let t=[];for(let e=0;e<mo;e++)t.push(e);for(let e=mo-2;e>=1;e--)t.push(e);return t})(),Ac=["\u273D","\u2726","\u2727","\u2726"],zr=class{constructor(e="Thinking..."){this.text=e,this.frame=0,this.interval=null,this.startTime=null}_render(){if(this._stopped)return;let e=In[this.frame%In.length],n="";for(let s=0;s<mo;s++)n+=s===e?`${B.cyan}\u25CF${B.reset}`:" ";let o="";if(this.startTime){let s=Math.floor((Date.now()-this.startTime)/1e3);if(s>=60){let r=Math.floor(s/60),i=s%60;o=` ${B.dim}${r}m ${String(i).padStart(2,"0")}s${B.reset}`}else s>=1&&(o=` ${B.dim}${s}s${B.reset}`)}process.stderr.write(`\x1B[2K\r${n} ${B.dim}${this.text}${B.reset}${o}`),this.frame++}start(){this._stopped=!1,this.startTime=Date.now(),process.stderr.isTTY&&(process.stderr.write("\x1B[?25l"),this._render(),this.interval=setInterval(()=>this._render(),100))}update(e){this.text=e}stop(){this._stopped=!0,this.interval&&(clearInterval(this.interval),this.interval=null),process.stderr.isTTY&&process.stderr.write("\x1B[2K\r\x1B[?25h"),this.startTime=null}},Xr=class{constructor(e){this.labels=e,this.statuses=e.map(()=>"running"),this.frame=0,this.interval=null,this.startTime=null,this.lineCount=e.length}_formatElapsed(){if(!this.startTime)return"";let e=Math.floor((Date.now()-this.startTime)/1e3);if(e<1)return"";let n=Math.floor(e/60),o=e%60;return n>0?`${n}m ${String(o).padStart(2,"0")}s`:`${o}s`}_render(){if(this._stopped)return;let e=In[this.frame%In.length],n=`${B.cyan}\u25CF${B.reset}`,o=`${B.dim}\u25CB${B.reset}`,s=this._formatElapsed(),r=s?` ${B.dim}${s}${B.reset}`:"",i="";for(let c=0;c<this.labels.length;c++){let l,u;switch(this.statuses[c]){case"done":l=`${B.green}\u2713${B.reset}`,u=B.dim;break;case"error":l=`${B.red}\u2717${B.reset}`,u=B.dim;break;case"retry":l=`${B.yellow}\u21BB${B.reset}`,u=B.yellow;break;default:l=c===e?n:" ",u=""}let d=c===this.labels.length-1?r:"";i+=`\x1B[2K ${l} ${u}${this.labels[c]}${B.reset}${d}
4
4
  `}this.lineCount>0&&(i+=`\x1B[${this.lineCount}A`),process.stderr.write(i),this.frame++}start(){this._stopped=!1,this.startTime=Date.now();let e="\x1B[?25l";for(let n=0;n<this.lineCount;n++)e+=`
5
5
  `;this.lineCount>0&&(e+=`\x1B[${this.lineCount}A`),process.stderr.write(e),this._render(),this.interval=setInterval(()=>this._render(),100)}update(e,n){e>=0&&e<this.statuses.length&&(this.statuses[e]=n)}stop(e={}){if(this._stopped=!0,this.interval&&(clearInterval(this.interval),this.interval=null),!e.silent)this._renderFinal();else{let n="";for(let o=0;o<this.lineCount;o++)n+=`\x1B[2K
@@ -116,7 +116,7 @@ ${o}`)}return e.join(`
116
116
  ${e.instructions}`);return t.length===0?"":`SKILL INSTRUCTIONS:
117
117
  ${t.join(`
118
118
 
119
- `)}`}function b$(){let t=[];for(let e of at)if(e.enabled)for(let n of e.commands)t.push({cmd:n.cmd,desc:n.desc||`[skill: ${e.name}]`});return t}function _$(){let t=[];for(let e of at)if(e.enabled)for(let n of e.tools)t.push({type:"function",function:{name:`skill_${n.function.name}`,description:`[Skill:${e.name}] ${n.function.description}`,parameters:n.function.parameters}});return t}async function x$(t,e){if(!t.startsWith("skill_"))return null;let n=t.substring(6);for(let o of at)if(o.enabled){for(let s of o.tools)if(s.function.name===n&&s.execute)try{let r=await s.execute(e);return typeof r=="string"?r:JSON.stringify(r)}catch(r){return`ERROR: Skill tool '${n}' failed: ${r.message}`}}return`ERROR: Skill tool '${n}' not found`}function k$(t){let[e,...n]=t.split(/\s+/),o=n.join(" ").trim();for(let s of at)if(s.enabled){for(let r of s.commands)if(r.cmd===e&&r.handler){try{r.handler(o)}catch(i){console.error(`Skill command error (${e}): ${i.message}`)}return!0}}return!1}function v$(){return at.map(t=>({name:t.name,type:t.type,enabled:t.enabled,description:t.description||"",commands:t.commands.length,tools:t.tools.length,filePath:t.filePath}))}function S$(t){let e=at.find(o=>o.name===t);if(!e)return!1;e.enabled=!0;let n=vi().filter(o=>o!==t);return Vl(n),!0}function E$(t){let e=at.find(o=>o.name===t);if(!e)return!1;e.enabled=!1;let n=vi();return n.includes(t)||(n.push(t),Vl(n)),!0}function T$(){return at}async function R$(t,e={}){let{execSync:n}=require("child_process"),o=Jl(),s=t;/^[\w-]+\/[\w.-]+$/.test(t)&&(s=`https://github.com/${t}.git`);let r=e.name||it.basename(s,".git").replace(/^nex-skill-/,""),i=it.join(o,r);if(Re.existsSync(i))return{ok:!1,name:r,error:`Skill "${r}" is already installed at ${i}. Remove it first to reinstall.`};try{n(`git clone --depth 1 ${s} ${i}`,{timeout:3e4,stdio:"pipe"})}catch(d){return{ok:!1,name:r,error:`Git clone failed: ${d.stderr?.toString().trim()||d.message}`}}let c=it.join(i,"skill.json"),l=Re.existsSync(c),u=Re.readdirSync(i).some(d=>(d.endsWith(".md")||d.endsWith(".js"))&&!d.startsWith("."));if(!l&&!u){try{Re.rmSync(i,{recursive:!0,force:!0})}catch{}return{ok:!1,name:r,error:"No skill.json manifest or .md/.js skill file found in repository"}}if(l)try{let d=JSON.parse(Re.readFileSync(c,"utf-8"));d.name||(d.name=r)}catch{try{Re.rmSync(i,{recursive:!0,force:!0})}catch{}return{ok:!1,name:r,error:"Invalid skill.json \u2014 not valid JSON"}}return Si(),{ok:!0,name:r}}async function C$(t){let e=require("axios");try{let n=encodeURIComponent(`nex-skill ${t} OR nex-code-skill ${t}`);return((await e.get(`https://api.github.com/search/repositories?q=${n}&sort=stars&per_page=10`,{timeout:1e4,headers:{Accept:"application/vnd.github.v3+json"}})).data.items||[]).map(s=>({name:s.name.replace(/^nex-skill-/,""),description:s.description||"(no description)",url:s.clone_url,stars:s.stargazers_count,owner:s.owner.login}))}catch(n){return[{name:"error",description:`Search failed: ${n.message}`,url:"",stars:0,owner:""}]}}function A$(t){let e=it.join(gs(),t);if(!Re.existsSync(e))return{ok:!1,error:`Skill "${t}" not found in ${gs()}`};try{return Re.rmSync(e,{recursive:!0,force:!0}),Si(),{ok:!0}}catch(n){return{ok:!1,error:n.message}}}Zl.exports={initSkillsDir:Jl,loadAllSkills:Si,getSkillInstructions:w$,getSkillCommands:b$,getSkillToolDefinitions:_$,routeSkillCall:x$,handleSkillCommand:k$,listSkills:v$,enableSkill:S$,disableSkill:E$,getLoadedSkills:T$,installSkill:R$,searchSkills:C$,removeSkill:A$,_getSkillsDir:gs,_validateScriptSkill:Ql,_loadMarkdownSkill:xi,_loadScriptSkill:ki}});var Ao=G((fv,ru)=>{var{spawn:O$}=require("child_process"),N$=require("path"),eu=require("fs"),Bt=new Map;function M$(){return N$.join(process.cwd(),".nex","config.json")}function Ei(){let t=M$();if(!eu.existsSync(t))return{};try{return JSON.parse(eu.readFileSync(t,"utf-8")).mcpServers||{}}catch{return{}}}function Co(t,e,n={},o=1e4){return new Promise((s,r)=>{let i=`${Date.now()}-${Math.random().toString(36).slice(2,6)}`,c=JSON.stringify({jsonrpc:"2.0",id:i,method:e,params:n})+`
119
+ `)}`}function b$(){let t=[];for(let e of at)if(e.enabled)for(let n of e.commands)t.push({cmd:n.cmd,desc:n.desc||`[skill: ${e.name}]`});return t}function _$(){let t=[];for(let e of at)if(e.enabled)for(let n of e.tools)t.push({type:"function",function:{name:`skill_${n.function.name}`,description:`[Skill:${e.name}] ${n.function.description}`,parameters:n.function.parameters}});return t}async function x$(t,e){if(!t.startsWith("skill_"))return null;let n=t.substring(6);for(let o of at)if(o.enabled){for(let s of o.tools)if(s.function.name===n&&s.execute)try{let r=await s.execute(e);return typeof r=="string"?r:JSON.stringify(r)}catch(r){return`ERROR: Skill tool '${n}' failed: ${r.message}`}}return`ERROR: Skill tool '${n}' not found`}function k$(t){let[e,...n]=t.split(/\s+/),o=n.join(" ").trim();for(let s of at)if(s.enabled){for(let r of s.commands)if(r.cmd===e&&r.handler){try{r.handler(o)}catch(i){console.error(`Skill command error (${e}): ${i.message}`)}return!0}}return!1}function v$(){return at.map(t=>({name:t.name,type:t.type,enabled:t.enabled,description:t.description||"",commands:t.commands.length,tools:t.tools.length,filePath:t.filePath}))}function S$(t){let e=at.find(o=>o.name===t);if(!e)return!1;e.enabled=!0;let n=vi().filter(o=>o!==t);return Vl(n),!0}function E$(t){let e=at.find(o=>o.name===t);if(!e)return!1;e.enabled=!1;let n=vi();return n.includes(t)||(n.push(t),Vl(n)),!0}function T$(){return at}async function R$(t,e={}){let{execSync:n}=require("child_process"),o=Jl(),s=t;/^[\w-]+\/[\w.-]+$/.test(t)&&(s=`https://github.com/${t}.git`);let r=e.name||it.basename(s,".git").replace(/^nex-skill-/,""),i=it.join(o,r);if(Re.existsSync(i))return{ok:!1,name:r,error:`Skill "${r}" is already installed at ${i}. Remove it first to reinstall.`};try{if(!/^https?:\/\/[a-zA-Z0-9._\-/:@#?=&%+~]+$/.test(s))throw new Error(`Invalid git URL: ${s}`);let d=i.replace(/'/g,"'\\''");n(`git clone --depth 1 '${s}' '${d}'`,{timeout:3e4,stdio:"pipe"})}catch(d){return{ok:!1,name:r,error:`Git clone failed: ${d.stderr?.toString().trim()||d.message}`}}let c=it.join(i,"skill.json"),l=Re.existsSync(c),u=Re.readdirSync(i).some(d=>(d.endsWith(".md")||d.endsWith(".js"))&&!d.startsWith("."));if(!l&&!u){try{Re.rmSync(i,{recursive:!0,force:!0})}catch{}return{ok:!1,name:r,error:"No skill.json manifest or .md/.js skill file found in repository"}}if(l)try{let d=JSON.parse(Re.readFileSync(c,"utf-8"));d.name||(d.name=r)}catch{try{Re.rmSync(i,{recursive:!0,force:!0})}catch{}return{ok:!1,name:r,error:"Invalid skill.json \u2014 not valid JSON"}}return Si(),{ok:!0,name:r}}async function C$(t){let e=require("axios");try{let n=encodeURIComponent(`nex-skill ${t} OR nex-code-skill ${t}`);return((await e.get(`https://api.github.com/search/repositories?q=${n}&sort=stars&per_page=10`,{timeout:1e4,headers:{Accept:"application/vnd.github.v3+json"}})).data.items||[]).map(s=>({name:s.name.replace(/^nex-skill-/,""),description:s.description||"(no description)",url:s.clone_url,stars:s.stargazers_count,owner:s.owner.login}))}catch(n){return[{name:"error",description:`Search failed: ${n.message}`,url:"",stars:0,owner:""}]}}function A$(t){let e=it.join(gs(),t);if(!Re.existsSync(e))return{ok:!1,error:`Skill "${t}" not found in ${gs()}`};try{return Re.rmSync(e,{recursive:!0,force:!0}),Si(),{ok:!0}}catch(n){return{ok:!1,error:n.message}}}Zl.exports={initSkillsDir:Jl,loadAllSkills:Si,getSkillInstructions:w$,getSkillCommands:b$,getSkillToolDefinitions:_$,routeSkillCall:x$,handleSkillCommand:k$,listSkills:v$,enableSkill:S$,disableSkill:E$,getLoadedSkills:T$,installSkill:R$,searchSkills:C$,removeSkill:A$,_getSkillsDir:gs,_validateScriptSkill:Ql,_loadMarkdownSkill:xi,_loadScriptSkill:ki}});var Ao=G((fv,ru)=>{var{spawn:O$}=require("child_process"),N$=require("path"),eu=require("fs"),Bt=new Map;function M$(){return N$.join(process.cwd(),".nex","config.json")}function Ei(){let t=M$();if(!eu.existsSync(t))return{};try{return JSON.parse(eu.readFileSync(t,"utf-8")).mcpServers||{}}catch{return{}}}function Co(t,e,n={},o=1e4){return new Promise((s,r)=>{let i=`${Date.now()}-${Math.random().toString(36).slice(2,6)}`,c=JSON.stringify({jsonrpc:"2.0",id:i,method:e,params:n})+`
120
120
  `,l="",u=setTimeout(()=>{f(),r(new Error(`MCP request timeout: ${e}`))},o);function d(m){l+=m.toString();let h=l.split(`
121
121
  `);for(let p of h)if(p.trim())try{let g=JSON.parse(p);if(g.id===i){f(),g.error?r(new Error(`MCP error: ${g.error.message||JSON.stringify(g.error)}`)):s(g.result);return}}catch{}l=h[h.length-1]||""}function f(){clearTimeout(u),t.stdout.removeListener("data",d)}t.stdout.on("data",d);try{t.stdin.write(c)}catch(m){f(),r(new Error(`MCP write failed: ${m.message}`))}})}async function tu(t,e){if(Bt.has(t))return Bt.get(t);let n=["PATH","HOME","USER","SHELL","LANG","TERM","NODE_ENV"],o={};for(let i of n)process.env[i]&&(o[i]=process.env[i]);let s=O$(e.command,e.args||[],{stdio:["pipe","pipe","pipe"],env:{...o,...e.env||{}}}),r={name:t,proc:s,tools:[],config:e};try{await Co(s,"initialize",{protocolVersion:"2024-11-05",capabilities:{},clientInfo:{name:"nex-code",version:"0.2.0"}});let i=await Co(s,"tools/list",{});return r.tools=i&&i.tools||[],Bt.set(t,r),r}catch(i){throw s.kill(),new Error(`Failed to connect MCP server '${t}': ${i.message}`)}}function nu(t){let e=Bt.get(t);if(!e)return!1;try{e.proc.kill()}catch{}return Bt.delete(t),!0}function P$(){for(let[t]of Bt)nu(t)}async function su(t,e,n={}){let o=Bt.get(t);if(!o)throw new Error(`MCP server not connected: ${t}`);let s=await Co(o.proc,"tools/call",{name:e,arguments:n});return s&&Array.isArray(s.content)?s.content.filter(r=>r.type==="text").map(r=>r.text).join(`
122
122
  `):JSON.stringify(s)}function ou(){let t=[];for(let[e,n]of Bt)for(let o of n.tools)t.push({server:e,name:o.name,description:o.description||"",inputSchema:o.inputSchema||{type:"object",properties:{}}});return t}function I$(){return ou().map(t=>({type:"function",function:{name:`mcp_${t.server}_${t.name}`,description:`[MCP:${t.server}] ${t.description}`,parameters:t.inputSchema}}))}async function L$(t,e){if(!t.startsWith("mcp_"))return null;let n=t.substring(4).split("_");if(n.length<2)return null;let o=n[0],s=n.slice(1).join("_");return su(o,s,e)}function D$(){let t=Ei();return Object.entries(t).map(([e,n])=>{let o=Bt.get(e);return{name:e,command:n.command,connected:!!o,toolCount:o?o.tools.length:0}})}async function j$(){let t=Ei(),e=[];for(let[n,o]of Object.entries(t))try{let s=await tu(n,o);e.push({name:n,tools:s.tools.length})}catch(s){e.push({name:n,tools:0,error:s.message})}return e}ru.exports={loadMCPConfig:Ei,sendRequest:Co,connectServer:tu,disconnectServer:nu,disconnectAll:P$,callTool:su,getAllTools:ou,getMCPToolDefinitions:I$,routeMCPCall:L$,listServers:D$,connectAll:j$}});var No=G((pv,lu)=>{var iu=require("fs"),Ti=require("path"),Oo=[],$s=[],yn={},ys=["onToolResult","onModelResponse","onSessionStart","onSessionEnd","onFileChange","beforeToolExec","afterToolExec"];function au(t,e){if(!t||!t.function||!t.function.name)return{ok:!1,error:"Tool definition must have function.name"};if(typeof e!="function")return{ok:!1,error:"Handler must be a function"};let n=t.function.name;return $s.some(o=>o.definition.function.name===n)?{ok:!1,error:`Tool "${n}" is already registered`}:($s.push({definition:{type:"function",...t},handler:e}),{ok:!0})}function cu(t,e){return ys.includes(t)?typeof e!="function"?{ok:!1,error:"Handler must be a function"}:(yn[t]||(yn[t]=[]),yn[t].push(e),{ok:!0}):{ok:!1,error:`Unknown event "${t}". Available: ${ys.join(", ")}`}}async function Ri(t,e){let n=yn[t]||[],o=e;for(let s of n)try{let r=await s(o);r!==void 0&&(o=r)}catch(r){process.env.NEX_DEBUG&&console.error(`[plugin] Hook error on ${t}: ${r.message}`)}return o}function q$(){let t=Ti.join(process.cwd(),".nex","plugins"),e=[];if(!iu.existsSync(t))return{loaded:0,errors:[]};let n=iu.readdirSync(t).filter(s=>s.endsWith(".js")),o={registerTool:au,registerHook:cu,EVENTS:ys};for(let s of n){let r=Ti.join(t,s);try{let i=require(r);if(typeof i=="function")i(o);else if(typeof i.setup=="function")i.setup(o);else{e.push(`${s}: Plugin must export a function or { setup: function }`);continue}Oo.push({name:i.name||Ti.basename(s,".js"),filePath:r})}catch(i){e.push(`${s}: ${i.message}`)}}return{loaded:Oo.length,errors:e}}function F$(){return $s.map(t=>t.definition)}async function U$(t,e,n={}){let o=$s.find(c=>c.definition.function.name===t);if(!o)return null;let s=await Ri("beforeToolExec",{name:t,args:e,options:n}),r=await o.handler(s.args||e,n);return(await Ri("afterToolExec",{name:t,args:e,result:r})).result||r}function W$(){return[...Oo]}function B$(){let t={};for(let e of ys)t[e]=(yn[e]||[]).length;return t}function H$(){Oo.length=0,$s.length=0;for(let t of Object.keys(yn))delete yn[t]}lu.exports={registerTool:au,registerHook:cu,emit:Ri,loadPlugins:q$,getPluginToolDefinitions:F$,executePluginTool:U$,getLoadedPlugins:W$,getHookCounts:B$,clearPlugins:H$,EVENTS:ys}});var Ci=G((mv,pu)=>{var{getSkillToolDefinitions:G$}=nn(),{getMCPToolDefinitions:K$}=Ao(),{getPluginToolDefinitions:Y$}=No(),Mo=new Map;function uu(){let{TOOL_DEFINITIONS:t}=Et();return[...t,...G$(),...K$(),...Y$()]}function du(t){if(Mo.has(t))return Mo.get(t);let n=uu().find(s=>s.function.name===t);if(!n)return null;let o=n.function.parameters;return Mo.set(t,o),o}function z$(){Mo.clear()}function Po(t,e){if(!t||e.length===0)return null;let n=null,o=1/0;for(let s of e){let r=fu(t.toLowerCase(),s.toLowerCase());r<o&&(o=r,n=s)}return o<=Math.ceil(t.length/2)?n:null}function fu(t,e){let n=t.length,o=e.length,s=Array.from({length:n+1},()=>Array(o+1).fill(0));for(let r=0;r<=n;r++)s[r][0]=r;for(let r=0;r<=o;r++)s[0][r]=r;for(let r=1;r<=n;r++)for(let i=1;i<=o;i++)s[r][i]=t[r-1]===e[i-1]?s[r-1][i-1]:1+Math.min(s[r-1][i],s[r][i-1],s[r-1][i-1]);return s[n][o]}function X$(t,e){let n=du(t);if(n===null){let d=uu().map(m=>m.function.name),f=Po(t,d);return{valid:!1,error:`Unknown tool "${t}".${f?` Did you mean "${f}"?`:""}
@@ -173,8 +173,8 @@ ERROR RECOVERY:
173
173
  - If edit_file fails with "old_text not found": read the file again, compare, and retry with exact text.
174
174
  - If bash fails: read the error, fix the root cause, then retry.
175
175
  - After 2 failed attempts at the same operation, summarize the issue and stop.`}];f.push({role:"user",content:t.task});let m=Bi(t),h=m.provider,p=m.model,g=m.tier,{TOOL_DEFINITIONS:y,executeTool:w}=Et(),k=Zu(n),R=ew(y.filter(_=>!k.has(_.function.name)),g);if(p&&!t._skipLog){let _=g?` (${g})`:"";process.stderr.write(` [sub-agent: ${h}:${p}${_}]
176
- `)}let x={};h&&(x.provider=h),p&&(x.model=p);try{for(let b=0;b<s;b++){let O=await Qu(f,R,x);if(!O||typeof O!="object")throw new Error("Empty or invalid response from provider");{let ae=h||Ko(),le=p||Qy();if(O.usage){let ee=O.usage.prompt_tokens||0,pe=O.usage.completion_tokens||0;c.input+=ee,c.output+=pe,Bu(ae,le,ee,pe)}else{let ee=O.content||"",pe=f.map(M=>typeof M.content=="string"?M.content:Array.isArray(M.content)?M.content.map(U=>typeof U=="string"?U:U.text||"").join(""):"").join(" "),z=Gu(pe),S=Gu(ee);c.input+=z,c.output+=S,c._estimated=!0,Bu(ae,le,z,S)}}let N=O.content||"",C=O.tool_calls,L={role:"assistant",content:N||""};if(C&&C.length>0&&(L.tool_calls=C),f.push(L),!C||C.length===0){for(let ae of l)Ts(ae);return{task:t.task,status:"done",result:N||"(no response)",toolsUsed:i,tokensUsed:c,modelSpec:h&&p?`${h}:${p}`:null}}let Ee=C.map(ae=>{let le=ae.function.name,ee=Wu(ae.function.arguments),pe=ae.id||`sub-${Date.now()}-${Math.random().toString(36).slice(2,6)}`;if(!ee)return Promise.resolve({role:"tool",content:`ERROR: Malformed tool arguments for ${le}`,tool_call_id:pe});let z=null;if(rw.has(le)&&ee.path){let M=require("path"),U=M.isAbsolute(ee.path)?ee.path:M.resolve(process.cwd(),ee.path);if(l.has(U)||!ow(U,r))return Promise.resolve({role:"tool",content:`ERROR: File '${ee.path}' is locked by another operation. Try a different approach or skip this file.`,tool_call_id:pe});l.add(U),z=U}return i.push(le),e.onUpdate&&e.onUpdate({type:"tool_call",tool:le,agentId:r}),(le==="spawn_agents"?sd(ee,n+1):w(le,ee,{autoConfirm:!0,silent:!0})).then(M=>{z&&(Ts(z),l.delete(z));let U=String(M??"");return{role:"tool",content:U.length>2e4?U.substring(0,2e4)+`
177
- ...(truncated)`:U,tool_call_id:pe}}).catch(M=>(z&&(Ts(z),l.delete(z)),{role:"tool",content:`ERROR: ${M.message}`,tool_call_id:pe}))}),me=await Promise.all(Ee);f.push(...me);for(let ae=0;ae<C.length;ae++){let le=C[ae];if(le.function.name==="bash_exec"){let ee=Wu(le.function.arguments);if((me[ae]?.content||"").startsWith("ERROR")&&ee&&ee.command){let z=ee.command.replace(/\s+/g," ").trim().slice(0,100);u.set(z,(u.get(z)||0)+1)}}}e.onUpdate&&e.onUpdate(`step ${b+1}/${s}`)}for(let b of l)Ts(b);let _=[...u.entries()].filter(([,b])=>b>=3).sort((b,O)=>O[1]-b[1]).slice(0,3).map(([b,O])=>`"${b}" (failed ${O}\xD7)`);return{task:t.task,status:"truncated",abortReason:"iteration_limit",repeatedFailures:_,result:f[f.length-1]?.content||"(max iterations reached)",toolsUsed:i,tokensUsed:c,modelSpec:h&&p?`${h}:${p}`:null}}catch(_){for(let b of l)Ts(b);return{task:t.task,status:"failed",result:`Error: ${_.message}`,toolsUsed:i,tokensUsed:c,modelSpec:h&&p?`${h}:${p}`:null}}}async function sd(t,e=0){if(e>=2)return"ERROR: max agent nesting depth (2) reached \u2014 reviewer agents cannot spawn further agents.";let n=e===0?nw:sw,o=e===0?zu:Xu,s=(t.agents||[]).slice(0,n);if(s.length===0)return"ERROR: No agents specified";let r=e>0?" \u21B3 ":"",i=e>0?38:44,c=s.map(d=>Bi(d)),l=s.map((d,f)=>{let m=c[f],h=m.model?` [${m.model}]`:"",p=d.task.substring(0,i-h.length);return`${r}Agent ${f+1}${h}: ${p}${d.task.length>p.length?"...":""}`}),u=new tw(l);u.start();try{let d=s.map((g,y)=>{let w=c[y],k=Math.min(g.max_iterations||o,o),R=w.model?{...g,model:`${w.provider}:${w.model}`,_skipLog:!0,max_iterations:k}:{...g,_skipLog:!0,max_iterations:k};return nd(R,{onUpdate:()=>{}},e).then(x=>(u.update(y,x.status==="failed"?"error":"done"),x)).catch(x=>(u.update(y,"error"),{task:g.task,status:"failed",result:`Error: ${x.message}`,toolsUsed:[],tokensUsed:{input:0,output:0}}))}),f=await Promise.all(d);u.stop(),Wi();let m=["Sub-agent results:",""],h=0,p=0;for(let g=0;g<f.length;g++){let y=f[g],w=y.status==="done"?"\u2713":y.status==="truncated"?"\u26A0":"\u2717",k=y.modelSpec?` [${y.modelSpec}]`:"";m.push(`${w} Agent ${g+1}${k}: ${y.task}`),m.push(` Status: ${y.status}`),m.push(` Tools used: ${y.toolsUsed.length>0?y.toolsUsed.join(", "):"none"}`),m.push(` Result: ${y.result}`),y.repeatedFailures&&y.repeatedFailures.length>0&&m.push(` Repeated failures: ${y.repeatedFailures.join("; ")}`),m.push(""),h+=y.tokensUsed.input,p+=y.tokensUsed.output}return m.push(`Total sub-agent tokens: ${h} input + ${p} output`),m.join(`
176
+ `)}let x={};h&&(x.provider=h),p&&(x.model=p);try{for(let b=0;b<s;b++){let O=await Qu(f,R,x);if(!O||typeof O!="object")throw new Error("Empty or invalid response from provider");{let ae=h||Ko(),le=p||Qy();if(O.usage){let ee=O.usage.prompt_tokens||0,pe=O.usage.completion_tokens||0;c.input+=ee,c.output+=pe,Bu(ae,le,ee,pe)}else{let ee=O.content||"",pe=f.map(M=>typeof M.content=="string"?M.content:Array.isArray(M.content)?M.content.map(U=>typeof U=="string"?U:U.text||"").join(""):"").join(" "),X=Gu(pe),S=Gu(ee);c.input+=X,c.output+=S,c._estimated=!0,Bu(ae,le,X,S)}}let N=O.content||"",C=O.tool_calls,L={role:"assistant",content:N||""};if(C&&C.length>0&&(L.tool_calls=C),f.push(L),!C||C.length===0){for(let ae of l)Ts(ae);return{task:t.task,status:"done",result:N||"(no response)",toolsUsed:i,tokensUsed:c,modelSpec:h&&p?`${h}:${p}`:null}}let Ee=C.map(ae=>{let le=ae.function.name,ee=Wu(ae.function.arguments),pe=ae.id||`sub-${Date.now()}-${Math.random().toString(36).slice(2,6)}`;if(!ee)return Promise.resolve({role:"tool",content:`ERROR: Malformed tool arguments for ${le}`,tool_call_id:pe});let X=null;if(rw.has(le)&&ee.path){let M=require("path"),U=M.isAbsolute(ee.path)?ee.path:M.resolve(process.cwd(),ee.path);if(l.has(U)||!ow(U,r))return Promise.resolve({role:"tool",content:`ERROR: File '${ee.path}' is locked by another operation. Try a different approach or skip this file.`,tool_call_id:pe});l.add(U),X=U}return i.push(le),e.onUpdate&&e.onUpdate({type:"tool_call",tool:le,agentId:r}),(le==="spawn_agents"?sd(ee,n+1):w(le,ee,{autoConfirm:!0,silent:!0})).then(M=>{X&&(Ts(X),l.delete(X));let U=String(M??"");return{role:"tool",content:U.length>2e4?U.substring(0,2e4)+`
177
+ ...(truncated)`:U,tool_call_id:pe}}).catch(M=>(X&&(Ts(X),l.delete(X)),{role:"tool",content:`ERROR: ${M.message}`,tool_call_id:pe}))}),me=await Promise.all(Ee);f.push(...me);for(let ae=0;ae<C.length;ae++){let le=C[ae];if(le.function.name==="bash_exec"){let ee=Wu(le.function.arguments);if((me[ae]?.content||"").startsWith("ERROR")&&ee&&ee.command){let X=ee.command.replace(/\s+/g," ").trim().slice(0,100);u.set(X,(u.get(X)||0)+1)}}}e.onUpdate&&e.onUpdate(`step ${b+1}/${s}`)}for(let b of l)Ts(b);let _=[...u.entries()].filter(([,b])=>b>=3).sort((b,O)=>O[1]-b[1]).slice(0,3).map(([b,O])=>`"${b}" (failed ${O}\xD7)`);return{task:t.task,status:"truncated",abortReason:"iteration_limit",repeatedFailures:_,result:f[f.length-1]?.content||"(max iterations reached)",toolsUsed:i,tokensUsed:c,modelSpec:h&&p?`${h}:${p}`:null}}catch(_){for(let b of l)Ts(b);return{task:t.task,status:"failed",result:`Error: ${_.message}`,toolsUsed:i,tokensUsed:c,modelSpec:h&&p?`${h}:${p}`:null}}}async function sd(t,e=0){if(e>=2)return"ERROR: max agent nesting depth (2) reached \u2014 reviewer agents cannot spawn further agents.";let n=e===0?nw:sw,o=e===0?zu:Xu,s=(t.agents||[]).slice(0,n);if(s.length===0)return"ERROR: No agents specified";let r=e>0?" \u21B3 ":"",i=e>0?38:44,c=s.map(d=>Bi(d)),l=s.map((d,f)=>{let m=c[f],h=m.model?` [${m.model}]`:"",p=d.task.substring(0,i-h.length);return`${r}Agent ${f+1}${h}: ${p}${d.task.length>p.length?"...":""}`}),u=new tw(l);u.start();try{let d=s.map((g,y)=>{let w=c[y],k=Math.min(g.max_iterations||o,o),R=w.model?{...g,model:`${w.provider}:${w.model}`,_skipLog:!0,max_iterations:k}:{...g,_skipLog:!0,max_iterations:k};return nd(R,{onUpdate:()=>{}},e).then(x=>(u.update(y,x.status==="failed"?"error":"done"),x)).catch(x=>(u.update(y,"error"),{task:g.task,status:"failed",result:`Error: ${x.message}`,toolsUsed:[],tokensUsed:{input:0,output:0}}))}),f=await Promise.all(d);u.stop(),Wi();let m=["Sub-agent results:",""],h=0,p=0;for(let g=0;g<f.length;g++){let y=f[g],w=y.status==="done"?"\u2713":y.status==="truncated"?"\u26A0":"\u2717",k=y.modelSpec?` [${y.modelSpec}]`:"";m.push(`${w} Agent ${g+1}${k}: ${y.task}`),m.push(` Status: ${y.status}`),m.push(` Tools used: ${y.toolsUsed.length>0?y.toolsUsed.join(", "):"none"}`),m.push(` Result: ${y.result}`),y.repeatedFailures&&y.repeatedFailures.length>0&&m.push(` Repeated failures: ${y.repeatedFailures.join("; ")}`),m.push(""),h+=y.tokensUsed.input,p+=y.tokensUsed.output}return m.push(`Total sub-agent tokens: ${h} input + ${p} output`),m.join(`
178
178
  `)}catch(d){return u.stop(),Wi(),`ERROR: Sub-agent execution failed: ${d.message}`}}od.exports={runSubAgent:nd,executeSpawnAgents:sd,clearAllLocks:Wi,classifyTask:ed,pickModelForTier:td,resolveSubAgentModel:Bi,isRetryableError:Vu,callWithRetry:Qu,getExcludedTools:Zu,LOCK_TIMEOUT_MS:Ju}});var As=G((Ev,yd)=>{var Le=require("fs"),Gt=require("path"),{atomicWrite:rd,withFileLockSync:id}=Zt(),lw=new Set(["the","a","an","is","are","and","or","but","in","on","at","to","for","of","with","this","that","it","as","be","by","from","was","were","has","have","had","not","do","does","did","so","if","its","my","me","we","you","he","she","they","our","your","their","can","will","would","could","should","may","might","then","than","also","which","when","where","how","what","who","all","any","each","more","most","use","used","using","get","set","new","add","make","der","die","das","den","dem","des","ein","eine","einen","einem","eines","und","oder","aber","von","zu","mit","auf","bei","nach","aus","vor","ist","sind","war","hat","haben","wird","kann","soll","muss","nicht","auch","als","durch"]);function zn(){let t=Gt.join(process.cwd(),".nex","brain");return Le.existsSync(t)||Le.mkdirSync(t,{recursive:!0}),t}function Jo(){return Gt.join(zn(),".brain-index.json")}function Ki(){return Gt.join(zn(),".embeddings.json")}function Rs(){let t=Gt.join(process.cwd(),".nex","brain");if(!Le.existsSync(t))return[];try{return Le.readdirSync(t).filter(e=>e.endsWith(".md")&&!e.startsWith(".")).map(e=>{let n=Gt.join(t,e),o=Le.statSync(n);return{name:e.replace(/\.md$/,""),path:n,size:o.size,modified:new Date(o.mtimeMs)}}).sort((e,n)=>n.modified-e.modified)}catch{return[]}}function Cs(t){let e={},n=t,o=t.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);if(o){let s=o[1].split(`
179
179
  `);for(let r of s){let i=r.match(/^(\w+):\s*(.+)$/);if(!i)continue;let c=i[1].trim(),l=i[2].trim();l.startsWith("[")&&l.endsWith("]")?e[c]=l.slice(1,-1).split(",").map(u=>u.trim()).filter(Boolean):e[c]=l}n=o[2]}return{frontmatter:e,body:n}}function ad(t){let e=Gt.join(zn(),`${t}.md`);if(!Le.existsSync(e))return{name:t,content:"",body:"",frontmatter:{}};let n=Le.readFileSync(e,"utf-8"),{frontmatter:o,body:s}=Cs(n);return{name:t,content:n,body:s,frontmatter:o}}function uw(t,e){let n=Gt.join(zn(),`${t}.md`);rd(n,e),pw(t,e),dw()}function dw(){if(process.env.NEX_BRAIN_EMBEDDINGS==="false")return;let t=Ki();Le.existsSync(t)&&setImmediate(async()=>{try{await md()}catch{}})}function fw(t){let e=Gt.join(zn(),`${t}.md`);return Le.existsSync(e)?(Le.unlinkSync(e),mw(t),!0):!1}function Xo(t){return t.toLowerCase().replace(/[^a-z0-9äöüß\s-]/g," ").split(/[\s-]+/).filter(e=>e.length>2&&!lw.has(e))}function Yi(t){let e={},{frontmatter:n,body:o}=Cs(t),s=Array.isArray(n.tags)?n.tags:[];for(let i of s){let c=i.toLowerCase().replace(/[^a-z0-9-]/g,"");c.length>1&&(e[c]=(e[c]||0)+5)}let r=(o||t).split(`
180
180
  `);for(let i of r)if(i.startsWith("#")){let c=i.replace(/^#+\s*/,"");for(let l of Xo(c))e[l]=(e[l]||0)+3}for(let i of Xo(o||t))e[i]=(e[i]||0)+1;return e}function zi(){let t=Jo();if(!Le.existsSync(t))return{documents:{}};try{return JSON.parse(Le.readFileSync(t,"utf-8"))}catch{return{documents:{}}}}function Xi(t){rd(Jo(),JSON.stringify(t,null,2))}function pw(t,e){id(Jo(),()=>{let n=zi(),{frontmatter:o}=Cs(e),s=Array.isArray(o.tags)?o.tags:[];n.documents[t]={keywords:Yi(e),tags:s,modified:new Date().toISOString()},Xi(n)})}function mw(t){id(Jo(),()=>{let e=zi();delete e.documents[t],Xi(e)})}function Gi(){let t=Rs(),e={documents:{}};for(let n of t){let o=Le.readFileSync(n.path,"utf-8"),{frontmatter:s}=Cs(o),r=Array.isArray(s.tags)?s.tags:[];e.documents[n.name]={keywords:Yi(o),tags:r,modified:n.modified.toISOString()}}return Xi(e),e}function cd(){let t=zi(),e=Rs();for(let n of e){let o=t.documents[n.name];if(!o||new Date(o.modified)<n.modified)return Gi()}for(let n of Object.keys(t.documents))if(!e.some(o=>o.name===n))return Gi();return t}function ld(t,e={}){let{topK:n=3,minScore:o=.1}=e,s=Xo(t);if(s.length===0)return[];let r=cd(),i=[];for(let[c,l]of Object.entries(r.documents)){let u=0;for(let d of s){l.keywords[d]&&(u+=l.keywords[d]);for(let[f,m]of Object.entries(l.keywords))f!==d&&f.length>3&&d.length>3&&(f.includes(d)||d.includes(f))&&(u+=m*.3)}u>=o&&i.push({name:c,score:u})}return i.sort((c,l)=>l.score-c.score),i.slice(0,n)}var ud=process.env.NEX_EMBED_MODEL||"nomic-embed-text",Hi=400,hw=50;async function dd(){if(process.env.NEX_BRAIN_EMBEDDINGS==="false")return!1;try{let t=process.env.OLLAMA_HOST||"http://localhost:11434",e=require("http"),n=require("https"),o=new URL(`${t}/api/tags`),s=o.protocol==="https:"?n:e;return((await new Promise((c,l)=>{let u=s.get(o.toString(),{timeout:2e3},d=>{let f="";d.on("data",m=>f+=m),d.on("end",()=>{try{c(JSON.parse(f))}catch{l(new Error("bad json"))}})});u.on("error",l),u.on("timeout",()=>{u.destroy(),l(new Error("timeout"))})})).models||[]).map(c=>c.name).some(c=>c.startsWith(ud.split(":")[0]))}catch{return!1}}async function Ji(t){let e=process.env.OLLAMA_HOST||"http://localhost:11434",n=require("http"),o=require("https"),s=new URL(`${e}/api/embeddings`),r=s.protocol==="https:"?o:n,i=JSON.stringify({model:ud,prompt:t});return new Promise((c,l)=>{let u=r.request(s,{method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(i)},timeout:3e4},d=>{let f="";d.on("data",m=>f+=m),d.on("end",()=>{try{c(JSON.parse(f).embedding||[])}catch(m){l(m)}})});u.on("error",l),u.on("timeout",()=>{u.destroy(),l(new Error("embedding timeout"))}),u.write(i),u.end()})}function fd(t,e){if(!t||!e||t.length!==e.length)return 0;let n=0,o=0,s=0;for(let i=0;i<t.length;i++)n+=t[i]*e[i],o+=t[i]*t[i],s+=e[i]*e[i];let r=Math.sqrt(o)*Math.sqrt(s);return r===0?0:n/r}function pd(t){let e=t.split(/\s+/),n=[],o=0;for(;o<e.length;){let s=e.slice(o,o+Hi).join(" ");if(n.push({text:s,offset:o}),o+Hi>=e.length)break;o+=Hi-hw}return n}async function md(){let t=Rs(),e={documents:{}},n=Ki();if(Le.existsSync(n))try{e=JSON.parse(Le.readFileSync(n,"utf-8"))}catch{}for(let o of t){let s=e.documents[o.name];if(s&&new Date(s.modified)>=o.modified)continue;let r=Le.readFileSync(o.path,"utf-8"),i=pd(r),c=[];for(let l of i){let u=await Ji(l.text);c.push({text:l.text,embedding:u,offset:l.offset})}e.documents[o.name]={chunks:c,modified:o.modified.toISOString()}}for(let o of Object.keys(e.documents))t.some(s=>s.name===o)||delete e.documents[o];return Le.writeFileSync(n,JSON.stringify(e),"utf-8"),e}async function hd(t,e={}){let{topK:n=3,minSimilarity:o=.3}=e,s=Ki();if(!Le.existsSync(s))return[];let r;try{r=JSON.parse(Le.readFileSync(s,"utf-8"))}catch{return[]}let i=await Ji(t),c=[];for(let[l,u]of Object.entries(r.documents||{})){let d=0,f="";for(let m of u.chunks||[]){let h=fd(i,m.embedding);h>d&&(d=h,f=m.text)}d>=o&&c.push({name:l,score:d,bestChunk:f})}return c.sort((l,u)=>u.score-l.score),c.slice(0,n)}function gd(t,e,n={}){let{k:o=60,topK:s=3}=n,r={};return t.forEach((i,c)=>{r[i.name]=(r[i.name]||0)+1/(o+c+1)}),e.forEach((i,c)=>{r[i.name]=(r[i.name]||0)+1/(o+c+1)}),Object.entries(r).map(([i,c])=>({name:i,score:c})).sort((i,c)=>c.score-i.score).slice(0,s)}async function $d(t,e={}){let{topK:n=3,minScore:o=.1}=e,s=ld(t,{topK:n,minScore:o}),r=s;if(process.env.NEX_BRAIN_EMBEDDINGS!=="false")try{if(await dd()){let c=await hd(t,{topK:n});r=gd(s,c,{topK:n})}}catch{}return r.map(i=>{let c=ad(i.name),l=(c.body||c.content||"").slice(0,300).replace(/\n+/g," ")+"...";return{name:i.name,score:i.score,content:c.content,excerpt:l}})}async function gw(t){if(!t||!t.trim())return"";let e=Gt.join(process.cwd(),".nex","brain");if(!Le.existsSync(e)||Rs().length===0)return"";let o;try{o=await $d(t,{topK:3})}catch{return""}if(!o||o.length===0)return"";let s;try{s=Qe().estimateTokens}catch{s=l=>Math.ceil(l.length/4)}let r=25e3,i=[],c=0;for(let l of o){let u=l.content||"",d=s(u);if(c+d>r){let m=r-c;if(m<100)break;let h=m/d;u=u.slice(0,Math.floor(u.length*h))+`
@@ -310,21 +310,21 @@ ${(m.stderr||m.message||"").toString().trim()}`}let i;try{i=kt(e.server)}catch(m
310
310
  ${d||f}`:f||"(no containers)"}case"container_logs":{if(!e.container)return"ERROR: container is required";let o=!e.server||e.server==="local"||e.server==="localhost",s=e.lines||50,r=e.since?`--since "${e.since}"`:"",i=`docker logs --tail ${s} ${r} ${e.container} 2>&1`.trim().replace(/\s+/g," ");if(o)try{let{stdout:h,stderr:p}=await Se(i,{timeout:15e3});return(h||p||"(no log output)").trim()}catch(h){return`EXIT ${h.code||1}
311
311
  ${(h.stderr||h.message||"").toString().trim()}`}let c;try{c=kt(e.server)}catch(h){return`ERROR: ${h.message}`}let{stdout:l,stderr:u,exitCode:d,error:f}=await ct(c,i,{timeout:2e4}),m=[l,u].filter(Boolean).join(`
312
312
  `).trim();return d!==0?`EXIT ${d}
313
- ${f||m}`:m||"(no log output)"}case"container_exec":{if(!e.container)return"ERROR: container is required";if(!e.command)return"ERROR: command is required";let o=!e.server||e.server==="local"||e.server==="localhost",s=/^(cat|ls|echo|env|printenv|df|du|ps|id|whoami|uname|hostname|date|pwd|which|find\s|head\s|tail\s|grep\s|curl\s+-[A-Za-z]*G|curl\s+https?:\/\/[^\s]+$)/;if(!n.autoConfirm&&!s.test(e.command.trim())){let h=o?"local":e.server;if(console.log(`
314
- ${ne.yellow} \u26A0 docker exec in ${e.container} on ${h}: ${e.command}${ne.reset}`),!await Tt(" Execute?"))return"CANCELLED: User declined."}let i=`docker exec ${e.container} sh -c ${JSON.stringify(e.command)}`;if(o)try{let{stdout:h,stderr:p}=await Se(i,{timeout:3e4});return(h||p||"(no output)").trim()}catch(h){return`EXIT ${h.code||1}
315
- ${(h.stderr||h.message||"").toString().trim()}`}let c;try{c=kt(e.server)}catch(h){return`ERROR: ${h.message}`}let{stdout:l,stderr:u,exitCode:d,error:f}=await ct(c,i,{timeout:35e3}),m=[l,u].filter(Boolean).join(`
316
- `).trim();return d!==0?`EXIT ${d}
317
- ${f||m}`:m||"(no output)"}case"container_manage":{if(!e.container)return"ERROR: container is required";if(!e.action)return"ERROR: action is required";let o=["start","stop","restart","remove","inspect"];if(!o.includes(e.action))return`ERROR: invalid action "${e.action}". Valid: ${o.join(", ")}`;let s=!e.server||e.server==="local"||e.server==="localhost";if(!(e.action==="inspect")&&!n.autoConfirm){let p=s?"local":e.server;if(console.log(`
313
+ ${f||m}`:m||"(no log output)"}case"container_exec":{if(!e.container)return"ERROR: container is required";if(!e.command)return"ERROR: command is required";let o=!e.server||e.server==="local"||e.server==="localhost",s=/^(cat|ls|echo|env|printenv|df|du|ps|id|whoami|uname|hostname|date|pwd|which|find\s|head\s|tail\s|grep\s|curl\s+-[A-Za-z]*G|curl\s+https?:\/\/[^\s]+$)/;if(!n.autoConfirm&&!s.test(e.command.trim())){let p=o?"local":e.server;if(console.log(`
314
+ ${ne.yellow} \u26A0 docker exec in ${e.container} on ${p}: ${e.command}${ne.reset}`),!await Tt(" Execute?"))return"CANCELLED: User declined."}let i=(e.container||"").replace(/[^a-zA-Z0-9._\/-]/g,"");if(!i)return"ERROR: Invalid container name";let c=`docker exec ${i} sh -c ${JSON.stringify(e.command)}`;if(o)try{let{stdout:p,stderr:g}=await Se(c,{timeout:3e4});return(p||g||"(no output)").trim()}catch(p){return`EXIT ${p.code||1}
315
+ ${(p.stderr||p.message||"").toString().trim()}`}let l;try{l=kt(e.server)}catch(p){return`ERROR: ${p.message}`}let{stdout:u,stderr:d,exitCode:f,error:m}=await ct(l,c,{timeout:35e3}),h=[u,d].filter(Boolean).join(`
316
+ `).trim();return f!==0?`EXIT ${f}
317
+ ${m||h}`:h||"(no output)"}case"container_manage":{if(!e.container)return"ERROR: container is required";if(!e.action)return"ERROR: action is required";let o=["start","stop","restart","remove","inspect"];if(!o.includes(e.action))return`ERROR: invalid action "${e.action}". Valid: ${o.join(", ")}`;let s=!e.server||e.server==="local"||e.server==="localhost";if(!(e.action==="inspect")&&!n.autoConfirm){let p=s?"local":e.server;if(console.log(`
318
318
  ${ne.yellow} \u26A0 docker ${e.action} ${e.container} on ${p}${ne.reset}`),!await Tt(" Execute?"))return"CANCELLED: User declined."}let i=e.action==="remove"?"rm":e.action,c=e.action==="inspect"?`docker inspect ${e.container}`:`docker ${i} ${e.container}`;if(s)try{let{stdout:p,stderr:g}=await Se(c,{timeout:3e4});return(p||g||`docker ${e.action} ${e.container}: OK`).trim()}catch(p){return`EXIT ${p.code||1}
319
319
  ${(p.stderr||p.message||"").toString().trim()}`}let l;try{l=kt(e.server)}catch(p){return`ERROR: ${p.message}`}let{stdout:u,stderr:d,exitCode:f,error:m}=await ct(l,c,{timeout:35e3}),h=[u,d].filter(Boolean).join(`
320
320
  `).trim();return f!==0?`EXIT ${f}
321
321
  ${m||h}`:h||`docker ${e.action} ${e.container}: OK`}case"deploy":{if(e.config)try{e={...Iw(e.config),...e},delete e.config,delete e._name}catch(d){return`ERROR: ${d.message}`}if(!e.server)return'ERROR: server is required (or use config: "<name>")';if(!e.remote_path)return"ERROR: remote_path is required";let o=e.method||"rsync";if(o==="rsync"&&!e.local_path)return"ERROR: local_path is required for rsync method";let s;try{s=kt(e.server)}catch(d){return`ERROR: ${d.message}`}let r=s.user?`${s.user}@${s.host}`:s.host;if(!e.dry_run&&!n.autoConfirm){if(o==="git"){let f=e.branch?` (branch: ${e.branch})`:"";console.log(`
322
322
  ${ne.yellow} \u26A0 Deploy [git pull]: ${r}:${e.remote_path}${f}${ne.reset}`)}else{let f=e.local_path.endsWith("/")?e.local_path:`${e.local_path}/`;console.log(`
323
- ${ne.yellow} \u26A0 Deploy [rsync]: ${f} \u2192 ${r}:${e.remote_path}${ne.reset}`)}if(e.deploy_script&&console.log(`${ne.yellow} Then run: ${e.deploy_script}${ne.reset}`),e.health_check&&console.log(`${ne.yellow} Health check: ${e.health_check}${ne.reset}`),!await Tt(" Proceed with deployment?"))return"CANCELLED: User declined."}let i="";if(o==="git"){let d=e.branch?`cd ${e.remote_path} && git fetch origin && git checkout ${e.branch} && git pull origin ${e.branch}`:`cd ${e.remote_path} && git pull`;if(e.dry_run)return`DRY RUN [git]: would run on ${r}:
324
- ${d}${e.deploy_script?`
325
- ${e.deploy_script}`:""}`;let{stdout:f,stderr:m,exitCode:h,error:p}=await ct(s,d,{timeout:12e4});if(i=[f,m].filter(Boolean).join(`
326
- `).trim(),h!==0)return`ERROR (git pull, exit ${h}):
327
- ${p||i}`}else{let d=s.key?`-e "ssh -i ${s.key.replace(/^~/,require("os").homedir())}${s.port&&Number(s.port)!==22?` -p ${s.port}`:""}"`:s.port&&Number(s.port)!==22?`-e "ssh -p ${s.port}"`:"",f=(e.exclude||[]).map(g=>`--exclude="${g}"`).join(" "),m=e.dry_run?"--dry-run":"",h=e.local_path.endsWith("/")?e.local_path:`${e.local_path}/`,p=`rsync -avz --delete ${m} ${f} ${d} ${h} ${r}:${e.remote_path}`.trim().replace(/\s+/g," ");try{let{stdout:g,stderr:y}=await Se(p,{timeout:12e4});i=(g||y||"").trim()}catch(g){return`ERROR (rsync): ${(g.stderr||g.message||"").toString().trim()}`}if(e.dry_run)return`DRY RUN [rsync]:
323
+ ${ne.yellow} \u26A0 Deploy [rsync]: ${f} \u2192 ${r}:${e.remote_path}${ne.reset}`)}if(e.deploy_script&&console.log(`${ne.yellow} Then run: ${e.deploy_script}${ne.reset}`),e.health_check&&console.log(`${ne.yellow} Health check: ${e.health_check}${ne.reset}`),!await Tt(" Proceed with deployment?"))return"CANCELLED: User declined."}let i="";if(o==="git"){let d=(e.branch||"").replace(/[^a-zA-Z0-9._\/-]/g,"");if(e.branch&&d!==e.branch)return`ERROR: Invalid branch name: ${e.branch}`;let f=(e.remote_path||"").replace(/'/g,"'\\''"),m=d?`cd '${f}' && git fetch origin && git checkout '${d}' && git pull origin '${d}'`:`cd '${f}' && git pull`;if(e.dry_run)return`DRY RUN [git]: would run on ${r}:
324
+ ${m}${e.deploy_script?`
325
+ ${e.deploy_script}`:""}`;let{stdout:h,stderr:p,exitCode:g,error:y}=await ct(s,m,{timeout:12e4});if(i=[h,p].filter(Boolean).join(`
326
+ `).trim(),g!==0)return`ERROR (git pull, exit ${g}):
327
+ ${y||i}`}else{let d=s.key?`-e "ssh -i ${s.key.replace(/^~/,require("os").homedir())}${s.port&&Number(s.port)!==22?` -p ${s.port}`:""}"`:s.port&&Number(s.port)!==22?`-e "ssh -p ${s.port}"`:"",f=(e.exclude||[]).map(g=>`--exclude="${g}"`).join(" "),m=e.dry_run?"--dry-run":"",h=e.local_path.endsWith("/")?e.local_path:`${e.local_path}/`,p=`rsync -avz --delete ${m} ${f} ${d} ${h} ${r}:${e.remote_path}`.trim().replace(/\s+/g," ");try{let{stdout:g,stderr:y}=await Se(p,{timeout:12e4});i=(g||y||"").trim()}catch(g){return`ERROR (rsync): ${(g.stderr||g.message||"").toString().trim()}`}if(e.dry_run)return`DRY RUN [rsync]:
328
328
  ${i||"(nothing to sync)"}`}let c="";if(e.deploy_script){let{stdout:d,stderr:f,exitCode:m,error:h}=await ct(s,e.deploy_script,{timeout:12e4}),p=[d,f].filter(Boolean).join(`
329
329
  `).trim();if(m!==0)return`${o==="git"?"git pull":"rsync"} OK
330
330
 
@@ -456,7 +456,7 @@ ${c}`),l&&l.length>0){let u=l.map(d=>` ${d.file}`).join(`
456
456
  `);s.push(`MERGE CONFLICTS (resolve before editing these files):
457
457
  ${u}`)}try{let u=Jw();u&&s.push(u)}catch{}return s.join(`
458
458
 
459
- `)}async function r0(t){let e=et.join(t,"package.json"),n="";if(await sn(()=>Rt.access(e).then(()=>!0).catch(()=>!1)))try{let i=await Rt.readFile(e,"utf-8"),c=JSON.parse(i);n=`${c.name||"?"} v${c.version||"?"}`}catch{}let[s,r]=await Promise.all([sn(async()=>{let{stdout:i}=await tr("git branch --show-current",{cwd:t,timeout:5e3});return i.trim()}),jd()]);if(r&&r.length>0){console.log(`${Xn.red} \u26A0 ${r.length} unresolved merge conflict(s):${Xn.reset}`);for(let i of r)console.log(`${Xn.red} ${i.file}${Xn.reset}`);console.log(`${Xn.yellow} \u2192 Resolve conflicts before starting tasks${Xn.reset}`)}console.log()}qd.exports={gatherProjectContext:o0,printContext:r0,generateFileTree:e0,_clearContextCache:()=>{aa.clear(),Jn.clear(),nr=null}}});var At=G((Pv,Wd)=>{var Ct=require("fs"),or=require("path"),{atomicWrite:i0}=Zt();function Ds(){return or.join(process.cwd(),".nex","sessions")}function ca(){let t=Ds();Ct.existsSync(t)||Ct.mkdirSync(t,{recursive:!0})}function la(t){let e=t.replace(/[^a-zA-Z0-9_-]/g,"_").substring(0,100);return or.join(Ds(),`${e}.json`)}function ua(t,e,n={}){ca();let o=la(t),s={name:t,createdAt:n.createdAt||new Date().toISOString(),updatedAt:new Date().toISOString(),messageCount:e.length,model:n.model||null,provider:n.provider||null,messages:e};return i0(o,JSON.stringify(s,null,2)),{path:o,name:t}}function Fd(t){let e=la(t);if(!Ct.existsSync(e))return null;try{return JSON.parse(Ct.readFileSync(e,"utf-8"))}catch{return null}}function Ud(){ca();let t=Ds(),e=Ct.readdirSync(t).filter(o=>o.endsWith(".json")),n=[];for(let o of e)try{let s=JSON.parse(Ct.readFileSync(or.join(t,o),"utf-8"));n.push({name:s.name||o.replace(".json",""),createdAt:s.createdAt,updatedAt:s.updatedAt,messageCount:s.messageCount||0,model:s.model,provider:s.provider,score:s.score!=null?s.score:null,scoreGrade:s.scoreGrade||null})}catch{}return n.sort((o,s)=>(s.updatedAt||"").localeCompare(o.updatedAt||""))}function a0(t){let e=la(t);return Ct.existsSync(e)?(Ct.unlinkSync(e),!0):!1}function c0(){let t=Ud();return t.length===0?null:Fd(t[0].name)}var xn=null,Kt=null,Ls=null;function l0(t,e={}){t.length!==0&&(xn&&clearTimeout(xn),Kt=t,Ls=e||{},xn=setTimeout(()=>{Kt&&Kt.length>0&&ua("_autosave",Kt,Ls),xn=null,Kt=null,Ls=null},5e3))}function u0(){xn&&(clearTimeout(xn),xn=null),Kt&&Kt.length>0&&(ua("_autosave",Kt,Ls),Kt=null,Ls=null)}function d0(){ca();let t=Ds(),e=Ct.readdirSync(t).filter(r=>r.endsWith(".json")),n=new Date,o=new Date(n.getTime()-720*60*60*1e3),s=0;for(let r of e){let i=or.join(t,r);try{let c=Ct.statSync(i);new Date(c.mtime)<o&&(Ct.unlinkSync(i),s++)}catch{}}return s}Wd.exports={saveSession:ua,loadSession:Fd,listSessions:Ud,deleteSession:a0,getLastSession:c0,autoSave:l0,flushAutoSave:u0,clearOldSessions:d0,_getSessionsDir:Ds}});var rr=G((Iv,Jd)=>{"use strict";var js=require("fs"),Bd=require("path");function Hd(t){let e=[];return t.forEach((n,o)=>{n.role==="assistant"&&(Array.isArray(n.content)&&n.content.forEach(s=>{s&&s.type==="tool_use"&&e.push({name:s.name||"",input:s.input||{},index:o})}),Array.isArray(n.tool_calls)&&n.tool_calls.forEach(s=>{let r=s.function?.name||s.name||"",i={};try{i=typeof s.function?.arguments=="string"?JSON.parse(s.function.arguments):s.function?.arguments||s.input||{}}catch{}e.push({name:r,input:i,index:o})}))}),e}function Gd(t){let e=[];return t.forEach((n,o)=>{if(n.role==="user"&&Array.isArray(n.content)&&n.content.forEach(s=>{if(s&&s.type==="tool_result"){let r=typeof s.content=="string"?s.content:Array.isArray(s.content)?s.content.map(i=>typeof i=="string"?i:i.text||"").join(""):JSON.stringify(s.content||"");e.push({content:r,index:o})}}),n.role==="tool"){let s=typeof n.content=="string"?n.content:JSON.stringify(n.content||"");e.push({content:s,index:o})}}),e}function Kd(t){for(let e=t.length-1;e>=0;e--){let n=t[e];if(n.role==="assistant"){if(typeof n.content=="string")return n.content.trim();if(Array.isArray(n.content)){let o=n.content.filter(s=>s&&(s.type==="text"||typeof s=="string")).map(s=>typeof s=="string"?s:s.text||"").join("").trim();if(o)return o}}}return""}function Yd(t,e){let n=[];for(let o=t.length-1;o>=0&&n.length<e;o--){let s=t[o];if(s.role!=="assistant")continue;let r="";typeof s.content=="string"?r=s.content.trim():Array.isArray(s.content)&&(r=s.content.filter(i=>i&&(i.type==="text"||typeof i=="string")).map(i=>typeof i=="string"?i:i.text||"").join("").trim()),r&&n.push(r)}return n}function zd(t){let e=new Map;for(let n of t){let o;try{o=JSON.stringify(n.input)}catch{o=String(n.input)}let s=`${n.name}|${o}`;e.set(s,(e.get(s)||0)+1)}return e}function Xd(t){if(!Array.isArray(t)||t.length===0)return{score:0,issues:["Empty or invalid session \u2014 no messages to analyse"],summary:"No messages found"};let e=10,n=[],o=Hd(t),s=Gd(t),r=o.length;t.some(S=>S.role==="user"&&typeof S.content=="string"&&S.content.startsWith("[SYSTEM WARNING]")&&(S.content.includes("edited")||S.content.includes("bash command")||S.content.includes("grep pattern")||S.content.includes("re-read")||S.content.includes("already in your context")))&&(e-=2,n.push("Loop-warning was fired during session (repeated file edits, bash commands, or re-reads)"));let c=o.find(S=>{let M=S.input?.command||S.input?.cmd||"";return/\bsed\s+-n\b/.test(M)});if(c){let S=(c.input?.command||c.input?.cmd||"").slice(0,80);e-=1.5,n.push(`sed -n anti-pattern used: ${S}`)}o.find(S=>{if(S.name!=="grep"&&S.name!=="bash"&&S.name!=="ssh_exec")return!1;let M=S.input?.command||S.input?.cmd||"",U=S.input?.pattern||"",K=`${M} ${U}`;return/(?:-[CAB]|--context|--after|--before)\s*[=\s]?([2-9][1-9]|\d{3,})/.test(K)||/grep.*-[CAB]\s*([2-9][1-9]|\d{3,})/.test(K)})&&(e-=1,n.push("grep used with >20 context lines (context flood risk)"));let u=t.some(S=>S.role==="assistant"),d=Kd(t),m=Yd(t,3).some(S=>S.length>100&&!/^[^.!]{0,40}\?$/.test(S));if(u&&!m&&(d.length<80||/^[^.!]{0,40}\?$/.test(d))){e-=2;let S=d.length>0?`"${d.slice(0,60)}..."`:"(no assistant text found)";n.push(`Session ends without diagnosis \u2014 last response too short or is only a question: ${S}`)}r>40?(e-=1.5,n.push(`Excessive tool calls: ${r} (>40 threshold)`)):r>25&&(e-=.5,n.push(`High tool call count: ${r} (>25 threshold)`)),t.some(S=>{let M=typeof S.content=="string"?S.content:Array.isArray(S.content)?S.content.map(U=>typeof U=="string"?U:U.text||"").join(""):"";return/\[auto-compressed|context compacted|force-compressed/.test(M)})&&(e-=.5,n.push("Auto-compress triggered (context flood indicator)"));let g=zd(o),y=0,w="";for(let[S,M]of g)M>y&&(y=M,w=S);if(y>=3){let[S]=w.split("|");e-=1,n.push(`Same tool call repeated ${y}\xD7 (tool: ${S})`)}let k=!1;for(let S of s)if(S.content&&S.content.includes('"valid":true')&&o.filter(U=>U.index>S.index).length>0){k=!0;break}k&&(e-=1.5,n.push('Stop-trigger ignored: tool result contained "valid":true but session continued with more tool calls'));let R=o.filter(S=>S.name==="ssh_exec");if(R.length>=8){let S=0,M=1;for(let U=1;U<R.length;U++)R[U].index<=R[U-1].index+2?M++:(S=Math.max(S,M),M=1);S=Math.max(S,M),S>=8&&(e-=.5,n.push(`SSH reconnect storm: ${S} consecutive SSH calls`))}let x=new Map;for(let S of o)if(S.name==="read_file"&&S.input?.path){let M=S.input.path;x.has(M)||x.set(M,{count:0,ranges:[]});let U=x.get(M);if(U.count++,S.input.line_start!=null){let K=S.input.line_start||1,se=S.input.line_end||K+350;U.ranges.push([K,se])}}function _(S,M,U){for(let[K,se]of U){let I=Math.max(S,K),W=Math.min(M,se);if(W>I){let oe=W-I,V=M-S||1;if(oe/V>=.7)return!0}}return!1}let b=0,O="";for(let[S,M]of x){if(M.count<3)continue;if(M.ranges.length===M.count){let K=!1,se=[];for(let[I,W]of M.ranges){if(se.length>0&&_(I,W,se)){K=!0;break}se.push([I,W])}if(!K)continue}M.count>b&&(b=M.count,O=S)}if(b>=3){e-=1;let S=O.split("/").slice(-2).join("/");n.push(`read_file loop: "${S}" read ${b}\xD7 (file already in context)`)}let N=0,C="";for(let[S,M]of x){if(M.ranges.length<4)continue;let U=[],K=!1;for(let[se,I]of M.ranges){if(U.length>0&&_(se,I,U)){K=!0;break}U.push([se,I])}!K&&M.ranges.length>N&&(N=M.ranges.length,C=S)}if(N>=4){e-=.5;let S=C.split("/").slice(-2).join("/");n.push(`File-scroll pattern: "${S}" read in ${N} sequential sections \u2014 use grep instead`)}let L=new Map;for(let S of o)if(S.name==="grep"&&S.input?.path&&S.input?.pattern){let M=S.input.path;L.has(M)||L.set(M,new Set),L.get(M).add(S.input.pattern)}let Ee=0,me="";for(let[S,M]of L)M.size>Ee&&(Ee=M.size,me=S);if(Ee>=3){e-=.75;let S=me.split("/").slice(-2).join("/");n.push(`grep flood on single file: "${S}" searched ${Ee}\xD7 with different patterns (file already in context)`)}{let S=new Set,M=new Set,U=/^(test_|demo_|temp_|tmp_|scratch_)/;for(let se of o){if(se.name==="write_file"&&se.input?.path){let I=se.input.path.split("/").pop(),W=se.input.path.includes("/tests/");U.test(I)&&!W&&S.add(se.input.path)}if((se.name==="bash"||se.name==="ssh_exec")&&se.input?.command){let I=se.input.command.match(/\brm\s+(?:-\w+\s+)?(\S+)/g);if(I)for(let W of I){let oe=W.split(/\s+/),V=oe[oe.length-1];for(let Z of S)(Z.endsWith(V)||V.endsWith(Z.split("/").pop()))&&M.add(Z)}}}let K=M.size;if(K>=1){let se=Math.min(K*.25,.5);e-=se;let I=[...M].map(W=>W.split("/").pop()).join(", ");n.push(`Temp file write-then-delete: ${I} \u2014 write inline logic or use tests/ instead`)}}let ae=s.filter(S=>S.content.startsWith("EXIT")).length;ae>=10?(e-=1,n.push(`Bash exit-error storm: ${ae} tool results started with EXIT (repeated failing commands)`)):ae>=5&&(e-=.5,n.push(`Repeated bash errors: ${ae} tool results with non-zero exit code`));for(let S of t){if(S.role!=="assistant")continue;let M="";if(typeof S.content=="string"?M=S.content:Array.isArray(S.content)&&(M=S.content.filter(V=>V&&(V.type==="text"||typeof V=="string")).map(V=>typeof V=="string"?V:V.text||"").join("")),M.length<=5e3)continue;let U=M.split(/(?<=\. )/).filter(V=>V.trim().length>0);if(U.length<6)continue;let K=new Map;for(let V=0;V<=U.length-3;V++){let Z=U.slice(V,V+3).join("").trim();Z.length>30&&K.set(Z,(K.get(Z)||0)+1)}let se=0,I="";for(let[V,Z]of K)Z>se&&(se=Z,I=V);if(se<3)continue;let oe=I.length*se/M.length;if(oe>=.4||se>=10){e-=1.5,n.push(`llm output loop: assistant message repeated content detected (${se}\xD7 same paragraph, ${Math.round(oe*100)}% repeated)`);break}}{let S=new Set(["read_file","list_directory","search_files","glob","grep"]),M=t.some(K=>Array.isArray(K.tool_calls)?K.tool_calls.some(se=>S.has(se.function?.name)):Array.isArray(K.content)?K.content.some(se=>se.type==="tool_use"&&S.has(se.name)):!1);t.some(K=>K.role==="assistant"&&typeof K.content=="string"&&(K.content.includes("## Steps")||K.content.includes("/plan approve")))&&!M&&(e-=2,n.push("plan written without reading any files \u2014 LLM invented data structures from training knowledge (hallucination risk)"))}let le=s.filter(S=>S.content.startsWith("BLOCKED:"));if(le.length>0){let S=Math.min(le.length*.5,1.5);e-=S,n.push(`${le.length} tool call${le.length===1?"":"s"} blocked (agent attempted denied actions)`)}let ee=t.filter(S=>{let M=typeof S.content=="string"?S.content:"";return/\[SYSTEM WARNING\] Context wiped \d+×/.test(M)}).length;if(ee>0){let S=Math.min(ee*1,2);e-=S,n.push(`Super-nuclear context wipe fired ${ee}\xD7 (context collapse \u2014 task too large or read loops)`)}{let S=!1,M=!1,U=!1;for(let se of o){if(se.name!=="bash")continue;let I=(se.input?.command||se.input?.cmd||"").trim();!(/cat\s*>/.test(I)||/<</.test(I))&&/\bcat\s+\S/.test(I)&&(S=!0),/^\s*ls(\s|$)/.test(I)&&!/npm|yarn|pnpm|make|git\b/.test(I)&&(M=!0),/\bfind\s+\S/.test(I)&&!/git\b|npm\b|-exec\b/.test(I)&&(U=!0)}let K=[S,M,U].filter(Boolean).length;if(K>0){let se=Math.min(K*.25,.75);e-=se;let I=[];S&&I.push("cat (use read_file)"),M&&I.push("ls (use list_directory)"),U&&I.push("find (use glob)"),n.push(`bash used instead of dedicated tool: ${I.join(", ")}`)}}e=Math.max(0,Math.min(10,e)),e=Math.round(e*10)/10;let pe=e>=9?"A":e>=8?"B":e>=7?"C":e>=6?"D":"F",z=n.length===0?`Clean session \u2014 no quality issues detected (${r} tool calls)`:`${n.length} issue${n.length===1?"":"s"} found \u2014 ${r} tool calls`;return{score:e,grade:pe,issues:n,summary:z}}function f0(t){try{let{loadSession:e}=At(),n=e(t);return n?Xd(n.messages||[]):null}catch{return null}}function p0(t,e=null){let{score:n,grade:o,issues:s,summary:r}=t,i=e?.dim||"",c=e?.reset||"",l=e?.green||"",u=e?.yellow||"",d=e?.red||"",f=e?.cyan||"",m=e?.bold||"",h=n>=8?l:n>=6?u:d,p=`
459
+ `)}async function r0(t){let e=et.join(t,"package.json"),n="";if(await sn(()=>Rt.access(e).then(()=>!0).catch(()=>!1)))try{let i=await Rt.readFile(e,"utf-8"),c=JSON.parse(i);n=`${c.name||"?"} v${c.version||"?"}`}catch{}let[s,r]=await Promise.all([sn(async()=>{let{stdout:i}=await tr("git branch --show-current",{cwd:t,timeout:5e3});return i.trim()}),jd()]);if(r&&r.length>0){console.log(`${Xn.red} \u26A0 ${r.length} unresolved merge conflict(s):${Xn.reset}`);for(let i of r)console.log(`${Xn.red} ${i.file}${Xn.reset}`);console.log(`${Xn.yellow} \u2192 Resolve conflicts before starting tasks${Xn.reset}`)}console.log()}qd.exports={gatherProjectContext:o0,printContext:r0,generateFileTree:e0,_clearContextCache:()=>{aa.clear(),Jn.clear(),nr=null}}});var At=G((Pv,Wd)=>{var Ct=require("fs"),or=require("path"),{atomicWrite:i0}=Zt();function Ds(){return or.join(process.cwd(),".nex","sessions")}function ca(){let t=Ds();Ct.existsSync(t)||Ct.mkdirSync(t,{recursive:!0})}function la(t){let e=t.replace(/[^a-zA-Z0-9_-]/g,"_").substring(0,100);return or.join(Ds(),`${e}.json`)}function ua(t,e,n={}){ca();let o=la(t),s={name:t,createdAt:n.createdAt||new Date().toISOString(),updatedAt:new Date().toISOString(),messageCount:e.length,model:n.model||null,provider:n.provider||null,messages:e};return i0(o,JSON.stringify(s,null,2)),{path:o,name:t}}function Fd(t){let e=la(t);if(!Ct.existsSync(e))return null;try{return JSON.parse(Ct.readFileSync(e,"utf-8"))}catch{return null}}function Ud(){ca();let t=Ds(),e=Ct.readdirSync(t).filter(o=>o.endsWith(".json")),n=[];for(let o of e)try{let s=JSON.parse(Ct.readFileSync(or.join(t,o),"utf-8"));n.push({name:s.name||o.replace(".json",""),createdAt:s.createdAt,updatedAt:s.updatedAt,messageCount:s.messageCount||0,model:s.model,provider:s.provider,score:s.score!=null?s.score:null,scoreGrade:s.scoreGrade||null})}catch{}return n.sort((o,s)=>(s.updatedAt||"").localeCompare(o.updatedAt||""))}function a0(t){let e=la(t);return Ct.existsSync(e)?(Ct.unlinkSync(e),!0):!1}function c0(){let t=Ud();return t.length===0?null:Fd(t[0].name)}var xn=null,Kt=null,Ls=null;function l0(t,e={}){t.length!==0&&(xn&&clearTimeout(xn),Kt=t,Ls=e||{},xn=setTimeout(()=>{Kt&&Kt.length>0&&ua("_autosave",Kt,Ls),xn=null,Kt=null,Ls=null},5e3))}function u0(){xn&&(clearTimeout(xn),xn=null),Kt&&Kt.length>0&&(ua("_autosave",Kt,Ls),Kt=null,Ls=null)}function d0(){ca();let t=Ds(),e=Ct.readdirSync(t).filter(r=>r.endsWith(".json")),n=new Date,o=new Date(n.getTime()-720*60*60*1e3),s=0;for(let r of e){let i=or.join(t,r);try{let c=Ct.statSync(i);new Date(c.mtime)<o&&(Ct.unlinkSync(i),s++)}catch{}}return s}Wd.exports={saveSession:ua,loadSession:Fd,listSessions:Ud,deleteSession:a0,getLastSession:c0,autoSave:l0,flushAutoSave:u0,clearOldSessions:d0,_getSessionsDir:Ds}});var rr=G((Iv,Jd)=>{"use strict";var js=require("fs"),Bd=require("path");function Hd(t){let e=[];return t.forEach((n,o)=>{n.role==="assistant"&&(Array.isArray(n.content)&&n.content.forEach(s=>{s&&s.type==="tool_use"&&e.push({name:s.name||"",input:s.input||{},index:o})}),Array.isArray(n.tool_calls)&&n.tool_calls.forEach(s=>{let r=s.function?.name||s.name||"",i={};try{i=typeof s.function?.arguments=="string"?JSON.parse(s.function.arguments):s.function?.arguments||s.input||{}}catch{}e.push({name:r,input:i,index:o})}))}),e}function Gd(t){let e=[];return t.forEach((n,o)=>{if(n.role==="user"&&Array.isArray(n.content)&&n.content.forEach(s=>{if(s&&s.type==="tool_result"){let r=typeof s.content=="string"?s.content:Array.isArray(s.content)?s.content.map(i=>typeof i=="string"?i:i.text||"").join(""):JSON.stringify(s.content||"");e.push({content:r,index:o})}}),n.role==="tool"){let s=typeof n.content=="string"?n.content:JSON.stringify(n.content||"");e.push({content:s,index:o})}}),e}function Kd(t){for(let e=t.length-1;e>=0;e--){let n=t[e];if(n.role==="assistant"){if(typeof n.content=="string")return n.content.trim();if(Array.isArray(n.content)){let o=n.content.filter(s=>s&&(s.type==="text"||typeof s=="string")).map(s=>typeof s=="string"?s:s.text||"").join("").trim();if(o)return o}}}return""}function Yd(t,e){let n=[];for(let o=t.length-1;o>=0&&n.length<e;o--){let s=t[o];if(s.role!=="assistant")continue;let r="";typeof s.content=="string"?r=s.content.trim():Array.isArray(s.content)&&(r=s.content.filter(i=>i&&(i.type==="text"||typeof i=="string")).map(i=>typeof i=="string"?i:i.text||"").join("").trim()),r&&n.push(r)}return n}function zd(t){let e=new Map;for(let n of t){let o;try{o=JSON.stringify(n.input)}catch{o=String(n.input)}let s=`${n.name}|${o}`;e.set(s,(e.get(s)||0)+1)}return e}function Xd(t){if(!Array.isArray(t)||t.length===0)return{score:0,issues:["Empty or invalid session \u2014 no messages to analyse"],summary:"No messages found"};let e=10,n=[],o=Hd(t),s=Gd(t),r=o.length;t.some(S=>S.role==="user"&&typeof S.content=="string"&&S.content.startsWith("[SYSTEM WARNING]")&&(S.content.includes("edited")||S.content.includes("bash command")||S.content.includes("grep pattern")||S.content.includes("re-read")||S.content.includes("already in your context")))&&(e-=2,n.push("Loop-warning was fired during session (repeated file edits, bash commands, or re-reads)"));let c=o.find(S=>{let M=S.input?.command||S.input?.cmd||"";return/\bsed\s+-n\b/.test(M)});if(c){let S=(c.input?.command||c.input?.cmd||"").slice(0,80);e-=1.5,n.push(`sed -n anti-pattern used: ${S}`)}o.find(S=>{if(S.name!=="grep"&&S.name!=="bash"&&S.name!=="ssh_exec")return!1;let M=S.input?.command||S.input?.cmd||"",U=S.input?.pattern||"",K=`${M} ${U}`;return/(?:-[CAB]|--context|--after|--before)\s*[=\s]?([2-9][1-9]|\d{3,})/.test(K)||/grep.*-[CAB]\s*([2-9][1-9]|\d{3,})/.test(K)})&&(e-=1,n.push("grep used with >20 context lines (context flood risk)"));let u=t.some(S=>S.role==="assistant"),d=Kd(t),m=Yd(t,3).some(S=>S.length>100&&!/^[^.!]{0,40}\?$/.test(S));if(u&&!m&&(d.length<80||/^[^.!]{0,40}\?$/.test(d))){e-=2;let S=d.length>0?`"${d.slice(0,60)}..."`:"(no assistant text found)";n.push(`Session ends without diagnosis \u2014 last response too short or is only a question: ${S}`)}r>40?(e-=1.5,n.push(`Excessive tool calls: ${r} (>40 threshold)`)):r>25&&(e-=.5,n.push(`High tool call count: ${r} (>25 threshold)`)),t.some(S=>{let M=typeof S.content=="string"?S.content:Array.isArray(S.content)?S.content.map(U=>typeof U=="string"?U:U.text||"").join(""):"";return/\[auto-compressed|context compacted|force-compressed/.test(M)})&&(e-=.5,n.push("Auto-compress triggered (context flood indicator)"));let g=zd(o),y=0,w="";for(let[S,M]of g)M>y&&(y=M,w=S);if(y>=3){let[S]=w.split("|");e-=1,n.push(`Same tool call repeated ${y}\xD7 (tool: ${S})`)}let k=!1;for(let S of s)if(S.content&&S.content.includes('"valid":true')&&o.filter(U=>U.index>S.index).length>0){k=!0;break}k&&(e-=1.5,n.push('Stop-trigger ignored: tool result contained "valid":true but session continued with more tool calls'));let R=o.filter(S=>S.name==="ssh_exec");if(R.length>=8){let S=0,M=1;for(let U=1;U<R.length;U++)R[U].index<=R[U-1].index+2?M++:(S=Math.max(S,M),M=1);S=Math.max(S,M),S>=8&&(e-=.5,n.push(`SSH reconnect storm: ${S} consecutive SSH calls`))}let x=new Map;for(let S of o)if(S.name==="read_file"&&S.input?.path){let M=S.input.path;x.has(M)||x.set(M,{count:0,ranges:[]});let U=x.get(M);if(U.count++,S.input.line_start!=null){let K=S.input.line_start||1,se=S.input.line_end||K+350;U.ranges.push([K,se])}}function _(S,M,U){for(let[K,se]of U){let I=Math.max(S,K),W=Math.min(M,se);if(W>I){let oe=W-I,V=M-S||1;if(oe/V>=.7)return!0}}return!1}let b=0,O="";for(let[S,M]of x){if(M.count<3)continue;if(M.ranges.length===M.count){let K=!1,se=[];for(let[I,W]of M.ranges){if(se.length>0&&_(I,W,se)){K=!0;break}se.push([I,W])}if(!K)continue}M.count>b&&(b=M.count,O=S)}if(b>=3){e-=1;let S=O.split("/").slice(-2).join("/");n.push(`read_file loop: "${S}" read ${b}\xD7 (file already in context)`)}let N=0,C="";for(let[S,M]of x){if(M.ranges.length<4)continue;let U=[],K=!1;for(let[se,I]of M.ranges){if(U.length>0&&_(se,I,U)){K=!0;break}U.push([se,I])}!K&&M.ranges.length>N&&(N=M.ranges.length,C=S)}if(N>=4){e-=.5;let S=C.split("/").slice(-2).join("/");n.push(`File-scroll pattern: "${S}" read in ${N} sequential sections \u2014 use grep instead`)}let L=new Map;for(let S of o)if(S.name==="grep"&&S.input?.path&&S.input?.pattern){let M=S.input.path;L.has(M)||L.set(M,new Set),L.get(M).add(S.input.pattern)}let Ee=0,me="";for(let[S,M]of L)M.size>Ee&&(Ee=M.size,me=S);if(Ee>=3){e-=.75;let S=me.split("/").slice(-2).join("/");n.push(`grep flood on single file: "${S}" searched ${Ee}\xD7 with different patterns (file already in context)`)}{let S=new Set,M=new Set,U=/^(test_|demo_|temp_|tmp_|scratch_)/;for(let se of o){if(se.name==="write_file"&&se.input?.path){let I=se.input.path.split("/").pop(),W=se.input.path.includes("/tests/");U.test(I)&&!W&&S.add(se.input.path)}if((se.name==="bash"||se.name==="ssh_exec")&&se.input?.command){let I=se.input.command.match(/\brm\s+(?:-\w+\s+)?(\S+)/g);if(I)for(let W of I){let oe=W.split(/\s+/),V=oe[oe.length-1];for(let Z of S)(Z.endsWith(V)||V.endsWith(Z.split("/").pop()))&&M.add(Z)}}}let K=M.size;if(K>=1){let se=Math.min(K*.25,.5);e-=se;let I=[...M].map(W=>W.split("/").pop()).join(", ");n.push(`Temp file write-then-delete: ${I} \u2014 write inline logic or use tests/ instead`)}}let ae=s.filter(S=>S.content.startsWith("EXIT")).length;ae>=10?(e-=1,n.push(`Bash exit-error storm: ${ae} tool results started with EXIT (repeated failing commands)`)):ae>=5&&(e-=.5,n.push(`Repeated bash errors: ${ae} tool results with non-zero exit code`));for(let S of t){if(S.role!=="assistant")continue;let M="";if(typeof S.content=="string"?M=S.content:Array.isArray(S.content)&&(M=S.content.filter(V=>V&&(V.type==="text"||typeof V=="string")).map(V=>typeof V=="string"?V:V.text||"").join("")),M.length<=5e3)continue;let U=M.split(/(?<=\. )/).filter(V=>V.trim().length>0);if(U.length<6)continue;let K=new Map;for(let V=0;V<=U.length-3;V++){let Z=U.slice(V,V+3).join("").trim();Z.length>30&&K.set(Z,(K.get(Z)||0)+1)}let se=0,I="";for(let[V,Z]of K)Z>se&&(se=Z,I=V);if(se<3)continue;let oe=I.length*se/M.length;if(oe>=.4||se>=10){e-=1.5,n.push(`llm output loop: assistant message repeated content detected (${se}\xD7 same paragraph, ${Math.round(oe*100)}% repeated)`);break}}{let S=new Set(["read_file","list_directory","search_files","glob","grep"]),M=t.some(K=>Array.isArray(K.tool_calls)?K.tool_calls.some(se=>S.has(se.function?.name)):Array.isArray(K.content)?K.content.some(se=>se.type==="tool_use"&&S.has(se.name)):!1);t.some(K=>K.role==="assistant"&&typeof K.content=="string"&&(K.content.includes("## Steps")||K.content.includes("/plan approve")))&&!M&&(e-=2,n.push("plan written without reading any files \u2014 LLM invented data structures from training knowledge (hallucination risk)"))}let le=s.filter(S=>S.content.startsWith("BLOCKED:"));if(le.length>0){let S=Math.min(le.length*.5,1.5);e-=S,n.push(`${le.length} tool call${le.length===1?"":"s"} blocked (agent attempted denied actions)`)}let ee=t.filter(S=>{let M=typeof S.content=="string"?S.content:"";return/\[SYSTEM WARNING\] Context wiped \d+×/.test(M)}).length;if(ee>0){let S=Math.min(ee*1,2);e-=S,n.push(`Super-nuclear context wipe fired ${ee}\xD7 (context collapse \u2014 task too large or read loops)`)}{let S=!1,M=!1,U=!1;for(let se of o){if(se.name!=="bash")continue;let I=(se.input?.command||se.input?.cmd||"").trim();!(/cat\s*>/.test(I)||/<</.test(I))&&/\bcat\s+\S/.test(I)&&(S=!0),/^\s*ls(\s|$)/.test(I)&&!/npm|yarn|pnpm|make|git\b/.test(I)&&(M=!0),/\bfind\s+\S/.test(I)&&!/git\b|npm\b|-exec\b/.test(I)&&(U=!0)}let K=[S,M,U].filter(Boolean).length;if(K>0){let se=Math.min(K*.25,.75);e-=se;let I=[];S&&I.push("cat (use read_file)"),M&&I.push("ls (use list_directory)"),U&&I.push("find (use glob)"),n.push(`bash used instead of dedicated tool: ${I.join(", ")}`)}}e=Math.max(0,Math.min(10,e)),e=Math.round(e*10)/10;let pe=e>=9?"A":e>=8?"B":e>=7?"C":e>=6?"D":"F",X=n.length===0?`Clean session \u2014 no quality issues detected (${r} tool calls)`:`${n.length} issue${n.length===1?"":"s"} found \u2014 ${r} tool calls`;return{score:e,grade:pe,issues:n,summary:X}}function f0(t){try{let{loadSession:e}=At(),n=e(t);return n?Xd(n.messages||[]):null}catch{return null}}function p0(t,e=null){let{score:n,grade:o,issues:s,summary:r}=t,i=e?.dim||"",c=e?.reset||"",l=e?.green||"",u=e?.yellow||"",d=e?.red||"",f=e?.cyan||"",m=e?.bold||"",h=n>=8?l:n>=6?u:d,p=`
460
460
  ${i} Session score: ${c}${m}${h}${n}/10 (${o})${c}`;if(r&&(p+=` ${i}${r}${c}`),s.length>0)for(let g of s)p+=`
461
461
  ${u}\u26A0${c} ${i}${g}${c}`;return p}function m0(t,e={}){try{let n=Bd.join(process.cwd(),".nex");js.existsSync(n)||js.mkdirSync(n,{recursive:!0});let o=Bd.join(n,"benchmark-history.json"),s=[];if(js.existsSync(o))try{s=JSON.parse(js.readFileSync(o,"utf-8"))}catch{s=[]}Array.isArray(s)||(s=[]);let r=t>=9?"A":t>=8?"B":t>=7?"C":t>=6?"D":"F",i={date:new Date().toISOString(),version:e.version||null,model:e.model||null,score:t,grade:r,sessionName:e.sessionName||null,issues:Array.isArray(e.issues)?e.issues:[]};s.push(i),s.length>100&&(s=s.slice(s.length-100)),js.writeFileSync(o,JSON.stringify(s,null,2))}catch{}}Jd.exports={scoreMessages:Xd,scoreSession:f0,formatScore:p0,appendScoreHistory:m0,_extractToolCalls:Hd,_extractToolResults:Gd,_getLastAssistantText:Kd,_getLastNAssistantTexts:Yd,_countDuplicateToolCalls:zd}});var rn=G((Lv,sf)=>{var on=require("fs"),ir=require("path"),h0=require("os"),{atomicWrite:g0,withFileLockSync:Vd}=Zt();function da(){return ir.join(process.cwd(),".nex","memory")}function qs(){return ir.join(da(),"memory.json")}function $0(){return ir.join(process.cwd(),"NEX.md")}function Qd(){return ir.join(h0.homedir(),".nex","NEX.md")}function fa(){let t=da();on.existsSync(t)||on.mkdirSync(t,{recursive:!0})}function ar(){let t=qs();if(!on.existsSync(t))return{};try{return JSON.parse(on.readFileSync(t,"utf-8"))}catch{return{}}}function Zd(t){fa(),g0(qs(),JSON.stringify(t,null,2))}function y0(t,e){fa(),Vd(qs(),()=>{let n=ar();n[t]={value:e,updatedAt:new Date().toISOString()},Zd(n)})}function w0(t){let e=ar();return e[t]?e[t].value:null}function b0(t){return fa(),Vd(qs(),()=>{let e=ar();return t in e?(delete e[t],Zd(e),!0):!1})}function ef(){let t=ar();return Object.entries(t).map(([e,n])=>({key:e,value:n.value,updatedAt:n.updatedAt}))}function tf(){let t=Qd();if(!on.existsSync(t))return"";try{return on.readFileSync(t,"utf-8").trim()}catch{return""}}function nf(){let t=$0();if(!on.existsSync(t))return"";try{return on.readFileSync(t,"utf-8").trim()}catch{return""}}function _0(){let t=[],e=tf();e&&t.push(`GLOBAL INSTRUCTIONS (~/.nex/NEX.md):
462
462
  ${e}`);let n=nf();n&&t.push(`PROJECT INSTRUCTIONS (NEX.md):
@@ -587,12 +587,12 @@ RULES:
587
587
  - If your task says "add X to README" \u2014 add it, don't check if it exists first.
588
588
  - Max 10 tool calls. If you need more, you are doing too much \u2014 narrow your scope.
589
589
  - When done: stop calling tools and write a one-line summary of what you changed.
590
- `,g=l.map(async(C,L)=>{let Ee=await d();try{let me=f.findings.filter(z=>z.agentId!==C.id).map(z=>`Agent ${z.agentId} found: ${z.summary}`).join(`
590
+ `,g=l.map(async(C,L)=>{let Ee=await d();try{let me=f.findings.filter(X=>X.agentId!==C.id).map(X=>`Agent ${X.agentId} found: ${X.summary}`).join(`
591
591
  `),ae=[me?`Prior agent findings:
592
592
  ${me}
593
593
  `:"",C.scope.length>0?`Focus on files: ${C.scope.join(", ")}`:""].filter(Boolean),le=0,ee=await Df(async()=>(le>0&&(h.update(L,"retry"),process.stderr.write(` ${ie.dim}[Agent ${L+1}] retrying after error...${ie.reset}
594
594
  `)),le++,ab({task:C.task,context:ae.length>0?ae.join(`
595
- `):void 0,max_iterations:Math.min(C.estimatedCalls||10,15),model:o,_skipLog:!0,_systemPrompt:p},{onUpdate:z=>{if(z&&z.type==="tool_call"&&process.stderr.isTTY){let S=` ${ie.dim}[Agent ${L+1}] ${z.tool}${ie.reset}`;process.stderr.write(S+`
595
+ `):void 0,max_iterations:Math.min(C.estimatedCalls||10,15),model:o,_skipLog:!0,_systemPrompt:p},{onUpdate:X=>{if(X&&X.type==="tool_call"&&process.stderr.isTTY){let S=` ${ie.dim}[Agent ${L+1}] ${X.tool}${ie.reset}`;process.stderr.write(S+`
596
596
  `)}}})),1,2e3),pe=typeof ee.result=="string"?ee.result.slice(0,200):String(ee.result||"").slice(0,200);return f.findings.push({agentId:C.id,summary:pe,files:Array.isArray(C.scope)?C.scope:[]}),h.update(L,ee.status==="failed"?"error":"done"),c.input+=ee.tokensUsed?.input||0,c.output+=ee.tokensUsed?.output||0,ee.tokensUsed?._estimated&&(c._estimated=!0),{...ee,_scope:C.scope,_idx:L}}catch(me){return h.update(L,"error"),{task:C.task,status:"failed",result:`Error: ${me.message}`,toolsUsed:[],tokensUsed:{input:0,output:0}}}finally{Ee()}}),y;try{y=await Promise.all(g)}finally{h.stop({silent:!0}),cb()}console.log("");let w=Math.round((Date.now()-u)/1e3),k=w>=60?`${Math.floor(w/60)}m ${w%60}s`:`${w}s`;for(let C=0;C<y.length;C++){let L=y[C],me=L.status==="done"||L.status==="truncated"&&L.result&&!L.result.startsWith("Error")?`${ie.green}\u2713${ie.reset}`:`${ie.red}\u2717${ie.reset}`,ae=L._scope&&L._scope.length>0?L._scope.map(pe=>pe.replace(/^.*\//,"").replace(/\/$/,"")).filter(Boolean):[],le=ae.length>0?ae.join(", "):L.task.substring(0,35)+(L.task.length>35?"...":""),ee=C===y.length-1;console.log(` ${me} Agent ${C+1} ${ie.dim}${le}${ie.reset}${ee?` ${ie.dim}${k}${ie.reset}`:""}`)}console.log(""),i("synthesizing"),console.log(`${ie.dim}Phase 3: Synthesizing results...${ie.reset}`);let R;try{R=await Ff(y,t,n)}catch(C){console.log(`${ie.yellow}Synthesize failed: ${C.message} \u2014 using raw results.${ie.reset}`),R={summary:y.map(L=>L.result).join(`
597
597
  `),conflicts:[],commitMessage:"",filesChanged:[]}}let x=f.findings.flatMap(C=>C.files),_=new Map;for(let C of x)_.set(C,(_.get(C)||0)+1);let b=[..._.values()].some(C=>C>1),O=f.findings.length>1&&b?` ${ie.dim}(agents shared context)${ie.reset}`:"";if(console.log(`
598
598
  ${ie.bold}Summary:${ie.reset} ${R.summary}${O}`),R.conflicts.length>0){console.log(`${ie.yellow}Conflicts:${ie.reset}`);for(let C of R.conflicts)console.log(` - ${C}`)}R.commitMessage&&console.log(`${ie.dim}Suggested commit: ${R.commitMessage}${ie.reset}`);let N=c.input===0&&c.output===0?"n/a (provider does not report token counts)":c._estimated?`~${c.input} input / ~${c.output} output (est.)`:`${c.input} input + ${c.output} output`;return console.log(`${ie.dim}Tokens: ${N}${ie.reset}
@@ -921,7 +921,7 @@ You have access to a persistent knowledge base in .nex/brain/.
921
921
  ${$.dim} ${c}${$.reset}`),l>=30&&process.stdout.isTTY){let u=n.size>0?`Done \u2014 ${n.size} ${n.size===1?"file":"files"} modified in ${l}s`:`Done \u2014 ${t} ${t===1?"step":"steps"} in ${l}s`;T_(u)}n.size>0?console.log(`${$.dim} \u{1F4A1} /diff \xB7 /commit \xB7 /undo${$.reset}`):!r&&o.size>=5&&n.size===0&&t>=3?console.log(`${$.dim} \u{1F4A1} Found issues? Say "fix 1" or "apply all fixes"${$.reset}`):o.size>0&&t>=2&&console.log(`${$.dim} \u{1F4A1} /save \xB7 /clear${$.reset}`)}async function R_(){if(!process.stdout.isTTY)return{action:"quit"};let t=ts(),e=Rn(),n=wr.fast?.[t],o=wr.strong?.[t],s=n&&n!==e,r=o&&o!==e&&o!==n,i=[];i.push({key:"r",label:`Retry with current model ${$.dim}(${e})${$.reset}`}),s&&i.push({key:"f",label:`Switch to ${$.bold}${n}${$.reset} ${$.dim}\u2014 fast, low latency${$.reset}`,model:n}),r&&i.push({key:"s",label:`Switch to ${$.bold}${o}${$.reset} ${$.dim}\u2014 reliable tool-calling, medium speed${$.reset}`,model:o}),i.push({key:"q",label:`${$.dim}Quit${$.reset}`}),console.log(),console.log(`${$.yellow} Stream stale \u2014 all retries exhausted.${$.reset} What would you like to do?`);for(let c of i)console.log(` ${$.cyan}[${c.key}]${$.reset} ${c.label}`);return process.stdout.write(` ${$.yellow}> ${$.reset}`),new Promise(c=>{let l=process.stdin,u=l.isRaw;l.setRawMode(!0),l.resume(),l.setEncoding("utf8");let d=!1,f=m=>{if(d)return;d=!0,l.removeListener("data",f),l.setRawMode(u||!1),l.pause();let h=m.toLowerCase().trim();if(process.stdout.write(`${h}
922
922
  `),m==="")return c({action:"quit"});let p=i.find(g=>g.key===h);!p||p.key==="q"||!p.model&&p.key!=="r"?c({action:"quit"}):p.key==="r"?c({action:"retry"}):c({action:"switch",model:p.model,provider:t})};l.on("data",f)})}var qt=null;async function C_(t,e=null,n={}){qt=e;let o=sp(t);Q.push({role:"user",content:o}),x_();let s=n.autoOrchestrate||process.env.NEX_AUTO_ORCHESTRATE==="true",r=parseInt(process.env.NEX_ORCHESTRATE_THRESHOLD||"3",10);try{let{detectComplexPrompt:qe,runOrchestrated:Ne}=Bs(),Fe=qe(typeof t=="string"?t:"");if(s&&Fe.isComplex&&Fe.estimatedGoals>=r)return console.log(`${$.yellow}\u26A1 Auto-orchestrate: ${Fe.estimatedGoals} goals \u2192 parallel agents${$.reset}`),await Ne(t,{orchestratorModel:n.orchestratorModel||process.env.NEX_ORCHESTRATOR_MODEL,workerModel:n.model});Fe.isComplex&&console.log(`${$.dim}Hint: ~${Fe.estimatedGoals} goals. Try --auto-orchestrate for parallel execution.${$.reset}`)}catch{}let{setOnChange:i}=Ho(),c=null,l=0;i((qe,Ne)=>{qe==="create"?(c&&c.stop(),c=new fb(Ne.name,Ne.tasks),c.setStats({tokens:l}),c.start()):qe==="update"&&c?c.updateTask(Ne.id,Ne.status):qe==="clear"&&c&&(c.stop(),c=null)});let u=await lp(),d=u;try{let{getBrainContext:qe}=As(),Ne=await qe(t);Ne&&(d=u+`
923
923
  `+Ne+`
924
- `)}catch(qe){process.env.NEX_DEBUG&&console.error("[agent] brain context failed:",qe.message)}let f=[{role:"system",content:d},...Q],m=new es("Thinking...");m.start();let p=Q.length===1?E_().catch(()=>null):Promise.resolve(null),g=Je(),[{messages:y,compressed:w,compacted:k,tokensRemoved:R},x]=await Promise.all([wb(f,g),p]),_=Ot(f,g);if(m.stop(),x&&console.log(`${$.dim}${x}${$.reset}`),k)console.log(`${$.dim} [context compacted \u2014 summary (~${R} tokens freed)]${$.reset}`);else if(w){let qe=_.limit>0?Math.round(R/_.limit*100):0;re(`${$.dim} [context compressed \u2014 ~${R} tokens freed (${qe}%)]${$.reset}`)}_.percentage>85&&re(`${$.yellow} \u26A0 Context ${Math.round(_.percentage)}% used (${Math.round(100-_.percentage)}% remaining) \u2014 consider /clear or /save + start fresh${$.reset}`);let b=y;if(Ot(b,Je()).percentage>=65){let{messages:Ne,tokensRemoved:Fe}=jt(b,Je());Fe>0&&(b=Ne,console.log(`${$.dim} [pre-flight compress \u2014 ${Fe} tokens freed, now ${Math.round(Ot(b,Je()).percentage)}% used]${$.reset}`))}let O=0,N=0,C=0,L=0,Ee=0,me=9,ae=0,le=(()=>{let qe=Q.find(Ne=>Ne.role==="user");return typeof qe?.content=="string"?qe.content:""})(),ee=/set_reminder|google.?auth|cron:|api\.log|jarvis.{0,30}(fehler|error|fail|broken|crash|nicht.{0,10}(funktioniert|läuft)|debug)|(?:fehler|error|crash|broken).{0,30}jarvis/i.test(le),pe=0,z=0,S=new Map,M=new Set,U=new Set,K=Date.now(),se=new hb(zb),I=cp,W=2,oe=4,V=ip,Z=5,ge=8,fe=ap,we=4,be=7,je=Pa,Ge=3,Jt=4,Nn=Ia,Lr=2,Lm=3,ln=0,Dm=6,jm=10,un=0,mc=5,dn=0,qm=2,Fm=3,Dr=0,jr=8,Um=12,dt,io=Oa,qr=0,hc=3,Fr=!1;e:for(;;){for(Fr=!1,dt=0;dt<io&&!pr()?.aborted;dt++){{let E=Je(),v=Ot(b,E),J=z===0?65:78;if(v.percentage>=J){let{messages:D,tokensRemoved:X}=jt(b,E,z===0);X>0&&(b=D,X>50&&console.log(`${$.dim} [auto-compressed \u2014 ~${X} tokens freed, now ${Math.round(Ot(b,E).percentage)}%]${$.reset}`))}}let Ne=!0;z>0&&Db();let Fe=null;if(c&&c.isActive())c._paused&&c.resume();else if(!c){let E,v=jb();if(v&&v.total>1){let J=v.description.length>40?v.description.slice(0,37)+"\u2026":v.description;E=`Plan step ${v.current}/${v.total}: ${J}`}else E=z>0?`Thinking... (step ${z+1})`:"Thinking...";Fe=new es(E),Fe.start()}let Ur=!0,Ft="",Wr=!1,ft=new qb,Pt,Br=Date.now(),ao=!1,Hr=new AbortController,gc=setInterval(()=>{let E=Date.now()-Br;if(E>=Vf)ft._clearCursorLine(),re(`${$.yellow} \u26A0 Stream stale for ${Math.round(E/1e3)}s \u2014 aborting and retrying${$.reset}`),Hr.abort();else if(E>=u_&&!ao){ao=!0,ft._clearCursorLine();let v=wr.fast?.[ts()],J=C>0?` (retry ${C+1}/${fr})`:"",D=Math.round((Vf-E)/1e3);re(`${$.yellow} \u26A0 No tokens received for ${Math.round(E/1e3)}s \u2014 waiting...${J}${$.reset}`),v&&v!==Rn()?console.log(`${$.dim} \u{1F4A1} Will auto-switch to ${v} in ~${D}s if no tokens arrive${$.reset}`):console.log(`${$.dim} \u{1F4A1} Ctrl+C to abort \xB7 auto-abort in ~${D}s${$.reset}`)}},5e3),bt="",Ut=null;try{let E=op(Je()),v=Ys()?E.filter(X=>np.has(X.function.name)):E,J=pr(),D=new AbortController;J&&J.addEventListener("abort",()=>D.abort(),{once:!0}),Hr.signal.addEventListener("abort",()=>D.abort(),{once:!0}),Pt=await Wf(b,v,{signal:D.signal,onThinkingToken:()=>{Br=Date.now(),ao=!1,qt?.onThinkingToken&&qt.onThinkingToken()},onToken:X=>{if(Br=Date.now(),ao=!1,qt?.onToken){qt.onToken(X),Ft+=X;return}if(Ft+=X,!Wr&&Ft.length>400&&Ft.length%250<X.length+1){let ce=Aa(Ft,3);ce.truncated&&(Wr=!0,ft._clearCursorLine?.(),re(`${$.yellow} \u26A0 LLM stream loop detected (${ce.repeatCount}\xD7 repeated) \u2014 suppressing display${$.reset}`))}Wr||(bt+=X,process.stdout.isTTY?Ut||(Ut=setTimeout(()=>{bt&&ft&&ft.push(bt),bt="",Ut=null},50)):(ft.push(bt),bt=""),Ur&&(c&&!c._paused?c.pause():Fe&&Fe.stop(),Ne||(Ne=!0),ft.startCursor(),Ur=!1))}})}catch(E){if(clearInterval(gc),Ut&&(clearTimeout(Ut),Ut=null),bt&&ft&&(ft.push(bt),bt=""),c&&!c._paused&&c.pause(),Fe&&Fe.stop(),ft.stopCursor(),Hr.signal.aborted&&!pr()?.aborted){if(C++,C>fr){if(L<1){L++,Zn("Stale retries exhausted \u2014 last-resort force-compress...",$.yellow);let j=Je(),{messages:H,tokensRemoved:te}=jt(b,j);b=H,te>50&&re(`${$.dim} [force-compressed \u2014 ~${te} tokens freed]${$.reset}`),C=0,dt--;continue}c&&(c.stop(),c=null);let ce=await R_();if(ce.action==="quit"){i(null),We(z,S,M,U,K),Ue(Q);break}ce.action==="switch"&&(Xf(`${ce.provider}:${ce.model}`),console.log(`${$.green} \u2713 Switched to ${ce.provider}:${ce.model}${$.reset}`)),C=0,dt--;continue}let D=C===1?3e3:5e3;if(C>=1&&ae<1){ae++,Zn(`Stale retry ${C}/${fr} \u2014 force-compressing before retry...`,$.yellow);let ce=Je(),{messages:j,tokensRemoved:H}=jt(b,ce,!0);if(b=j,H>0&&H>50&&re(`${$.dim} [force-compressed \u2014 ~${H} tokens freed]${$.reset}`),d_){let te=wr.fast?.[ts()];te&&te!==Rn()&&(Xf(`${ts()}:${te}`),console.log(`${$.cyan} \u26A1 Auto-switched to ${te} to avoid further stale timeouts${$.reset}`),console.log(`${$.dim} (disable with NEX_STALE_AUTO_SWITCH=0)${$.reset}`))}}else re(`${$.yellow} \u26A0 Stale retry ${C}/${fr} \u2014 retrying in ${D/1e3}s...${$.reset}`);let X=new es(`Waiting ${D/1e3}s before retry...`);X.start(),await new Promise(ce=>setTimeout(ce,D)),X.stop(),dt--;continue}if(E.name==="AbortError"||E.name==="CanceledError"||E.message?.includes("canceled")||E.message?.includes("aborted")){c&&(c.stop(),c=null),i(null),We(z,S,M,U,K),Ue(Q);break}let v=E.message;if(E.code==="ECONNREFUSED"||E.message.includes("ECONNREFUSED"))v="Connection refused \u2014 please check your internet connection or API endpoint";else if(E.code==="ENOTFOUND"||E.message.includes("ENOTFOUND"))v="Network error \u2014 could not reach the API server. Please check your connection";else if(E.code==="ETIMEDOUT"||E.message.includes("timeout"))v="Request timed out \u2014 the API server took too long to respond. Please try again";else if(E.message.includes("401")||E.message.includes("Unauthorized"))v="Authentication failed \u2014 please check your API key in the .env file";else if(E.message.includes("403")||E.message.includes("Forbidden"))v="Access denied \u2014 your API key may not have permission for this model";else if(E.message.includes("404")){v=`Model not found (404): ${Rn?Rn():"unknown"} \u2014 check your .env MODEL setting or run /models to list available models`,console.log(`${$.red} \u2717 ${v}${$.reset}`),c&&(c.stop(),c=null),i(null),We(z,S,M,U,K),Ue(Q);break}else if(E.message.includes("400")){if(L<3&&Ee<me){L++,Ee++;let D=z===0&&L===1,X=D||L===3||ae>0;if(D){L=3;let te=E.message.replace(/^API Error(\s*\[HTTP \d+\])?:\s*/i,"").slice(0,150);Zn(`Bad request (400) \u2014 ${te||"system prompt too large"}, compressing...`,$.yellow)}else Zn(X?`Bad request (400) \u2014 nuclear compression (attempt ${L}/3, dropping history)...`:`Bad request (400) \u2014 force-compressing and retrying... (attempt ${L}/3)`,$.yellow);let ce=Je(),{messages:j,tokensRemoved:H}=jt(b,ce,X);b=j,H>50&&re(`${$.dim} [force-compressed \u2014 ~${H} tokens freed]${$.reset}`),dt--;continue}{let D=b.find(ue=>ue.role==="system"),X=b.find(ue=>ue.role==="user"&&!String(ue.content).startsWith("[SYSTEM")&&!String(ue.content).startsWith("BLOCKED:")),ce=[D,X].filter(Boolean),{getUsage:j}=Qe(),H=Qe().estimateMessagesTokens(ce),te=Qe().estimateMessagesTokens(b);if(H<te){let ue=[],$e=Q.filter(de=>de.role==="assistant"&&typeof de.content=="string"&&de.content.trim().length>30).slice(-3).map(de=>de.content.trim().slice(0,120).replace(/\n+/g," "));$e.length>0&&ue.push(`Key findings:
924
+ `)}catch(qe){process.env.NEX_DEBUG&&console.error("[agent] brain context failed:",qe.message)}let f=[{role:"system",content:d},...Q],m=new es("Thinking...");m.start();let p=Q.length===1?E_().catch(()=>null):Promise.resolve(null),g=Je(),[{messages:y,compressed:w,compacted:k,tokensRemoved:R},x]=await Promise.all([wb(f,g),p]),_=Ot(f,g);if(m.stop(),x&&console.log(`${$.dim}${x}${$.reset}`),k)console.log(`${$.dim} [context compacted \u2014 summary (~${R} tokens freed)]${$.reset}`);else if(w){let qe=_.limit>0?Math.round(R/_.limit*100):0;re(`${$.dim} [context compressed \u2014 ~${R} tokens freed (${qe}%)]${$.reset}`)}_.percentage>85&&re(`${$.yellow} \u26A0 Context ${Math.round(_.percentage)}% used (${Math.round(100-_.percentage)}% remaining) \u2014 consider /clear or /save + start fresh${$.reset}`);let b=y;if(Ot(b,Je()).percentage>=65){let{messages:Ne,tokensRemoved:Fe}=jt(b,Je());Fe>0&&(b=Ne,console.log(`${$.dim} [pre-flight compress \u2014 ${Fe} tokens freed, now ${Math.round(Ot(b,Je()).percentage)}% used]${$.reset}`))}let O=0,N=0,C=0,L=0,Ee=0,me=9,ae=0,le=(()=>{let qe=Q.find(Ne=>Ne.role==="user");return typeof qe?.content=="string"?qe.content:""})(),ee=/set_reminder|google.?auth|cron:|api\.log|jarvis.{0,30}(fehler|error|fail|broken|crash|nicht.{0,10}(funktioniert|läuft)|debug)|(?:fehler|error|crash|broken).{0,30}jarvis/i.test(le),pe=0,X=0,S=new Map,M=new Set,U=new Set,K=Date.now(),se=new hb(zb),I=cp,W=2,oe=4,V=ip,Z=5,ge=8,fe=ap,we=4,be=7,je=Pa,Ge=3,Jt=4,Nn=Ia,Lr=2,Lm=3,ln=0,Dm=6,jm=10,un=0,mc=5,dn=0,qm=2,Fm=3,Dr=0,jr=8,Um=12,dt,io=Oa,qr=0,hc=3,Fr=!1;e:for(;;){for(Fr=!1,dt=0;dt<io&&!pr()?.aborted;dt++){{let E=Je(),v=Ot(b,E),J=X===0?65:78;if(v.percentage>=J){let{messages:D,tokensRemoved:Y}=jt(b,E,X===0);Y>0&&(b=D,Y>50&&console.log(`${$.dim} [auto-compressed \u2014 ~${Y} tokens freed, now ${Math.round(Ot(b,E).percentage)}%]${$.reset}`))}}let Ne=!0;X>0&&Db();let Fe=null;if(c&&c.isActive())c._paused&&c.resume();else if(!c){let E,v=jb();if(v&&v.total>1){let J=v.description.length>40?v.description.slice(0,37)+"\u2026":v.description;E=`Plan step ${v.current}/${v.total}: ${J}`}else E=X>0?`Thinking... (step ${X+1})`:"Thinking...";Fe=new es(E),Fe.start()}let Ur=!0,Ft="",Wr=!1,ft=new qb,Pt,Br=Date.now(),ao=!1,Hr=new AbortController,gc=setInterval(()=>{let E=Date.now()-Br;if(E>=Vf)ft._clearCursorLine(),re(`${$.yellow} \u26A0 Stream stale for ${Math.round(E/1e3)}s \u2014 aborting and retrying${$.reset}`),Hr.abort();else if(E>=u_&&!ao){ao=!0,ft._clearCursorLine();let v=wr.fast?.[ts()],J=C>0?` (retry ${C+1}/${fr})`:"",D=Math.round((Vf-E)/1e3);re(`${$.yellow} \u26A0 No tokens received for ${Math.round(E/1e3)}s \u2014 waiting...${J}${$.reset}`),v&&v!==Rn()?console.log(`${$.dim} \u{1F4A1} Will auto-switch to ${v} in ~${D}s if no tokens arrive${$.reset}`):console.log(`${$.dim} \u{1F4A1} Ctrl+C to abort \xB7 auto-abort in ~${D}s${$.reset}`)}},5e3),bt="",Ut=null;try{let E=op(Je()),v=Ys()?E.filter(Y=>np.has(Y.function.name)):E,J=pr(),D=new AbortController;J&&J.addEventListener("abort",()=>D.abort(),{once:!0}),Hr.signal.addEventListener("abort",()=>D.abort(),{once:!0}),Pt=await Wf(b,v,{signal:D.signal,onThinkingToken:()=>{Br=Date.now(),ao=!1,qt?.onThinkingToken&&qt.onThinkingToken()},onToken:Y=>{if(Br=Date.now(),ao=!1,qt?.onToken){qt.onToken(Y),Ft+=Y;return}if(Ft+=Y,!Wr&&Ft.length>400&&Ft.length%250<Y.length+1){let ce=Aa(Ft,3);ce.truncated&&(Wr=!0,ft._clearCursorLine?.(),re(`${$.yellow} \u26A0 LLM stream loop detected (${ce.repeatCount}\xD7 repeated) \u2014 suppressing display${$.reset}`))}Wr||(bt+=Y,process.stdout.isTTY?Ut||(Ut=setTimeout(()=>{bt&&ft&&ft.push(bt),bt="",Ut=null},50)):(ft.push(bt),bt=""),Ur&&(c&&!c._paused?c.pause():Fe&&Fe.stop(),Ne||(Ne=!0),ft.startCursor(),Ur=!1))}})}catch(E){if(clearInterval(gc),Ut&&(clearTimeout(Ut),Ut=null),bt&&ft&&(ft.push(bt),bt=""),c&&!c._paused&&c.pause(),Fe&&Fe.stop(),ft.stopCursor(),Hr.signal.aborted&&!pr()?.aborted){if(C++,C>fr){if(L<1){L++,Zn("Stale retries exhausted \u2014 last-resort force-compress...",$.yellow);let j=Je(),{messages:H,tokensRemoved:te}=jt(b,j);b=H,te>50&&re(`${$.dim} [force-compressed \u2014 ~${te} tokens freed]${$.reset}`),C=0,dt--;continue}c&&(c.stop(),c=null);let ce=await R_();if(ce.action==="quit"){i(null),We(X,S,M,U,K),Ue(Q);break}ce.action==="switch"&&(Xf(`${ce.provider}:${ce.model}`),console.log(`${$.green} \u2713 Switched to ${ce.provider}:${ce.model}${$.reset}`)),C=0,dt--;continue}let D=C===1?3e3:5e3;if(C>=1&&ae<1){ae++,Zn(`Stale retry ${C}/${fr} \u2014 force-compressing before retry...`,$.yellow);let ce=Je(),{messages:j,tokensRemoved:H}=jt(b,ce,!0);if(b=j,H>0&&H>50&&re(`${$.dim} [force-compressed \u2014 ~${H} tokens freed]${$.reset}`),d_){let te=wr.fast?.[ts()];te&&te!==Rn()&&(Xf(`${ts()}:${te}`),console.log(`${$.cyan} \u26A1 Auto-switched to ${te} to avoid further stale timeouts${$.reset}`),console.log(`${$.dim} (disable with NEX_STALE_AUTO_SWITCH=0)${$.reset}`))}}else re(`${$.yellow} \u26A0 Stale retry ${C}/${fr} \u2014 retrying in ${D/1e3}s...${$.reset}`);let Y=new es(`Waiting ${D/1e3}s before retry...`);Y.start(),await new Promise(ce=>setTimeout(ce,D)),Y.stop(),dt--;continue}if(E.name==="AbortError"||E.name==="CanceledError"||E.message?.includes("canceled")||E.message?.includes("aborted")){c&&(c.stop(),c=null),i(null),We(X,S,M,U,K),Ue(Q);break}let v=E.message;if(E.code==="ECONNREFUSED"||E.message.includes("ECONNREFUSED"))v="Connection refused \u2014 please check your internet connection or API endpoint";else if(E.code==="ENOTFOUND"||E.message.includes("ENOTFOUND"))v="Network error \u2014 could not reach the API server. Please check your connection";else if(E.code==="ETIMEDOUT"||E.message.includes("timeout"))v="Request timed out \u2014 the API server took too long to respond. Please try again";else if(E.message.includes("401")||E.message.includes("Unauthorized"))v="Authentication failed \u2014 please check your API key in the .env file";else if(E.message.includes("403")||E.message.includes("Forbidden"))v="Access denied \u2014 your API key may not have permission for this model";else if(E.message.includes("404")){v=`Model not found (404): ${Rn?Rn():"unknown"} \u2014 check your .env MODEL setting or run /models to list available models`,console.log(`${$.red} \u2717 ${v}${$.reset}`),c&&(c.stop(),c=null),i(null),We(X,S,M,U,K),Ue(Q);break}else if(E.message.includes("400")){if(L<3&&Ee<me){L++,Ee++;let D=X===0&&L===1,Y=D||L===3||ae>0;if(D){L=3;let te=E.message.replace(/^API Error(\s*\[HTTP \d+\])?:\s*/i,"").slice(0,150);Zn(`Bad request (400) \u2014 ${te||"system prompt too large"}, compressing...`,$.yellow)}else Zn(Y?`Bad request (400) \u2014 nuclear compression (attempt ${L}/3, dropping history)...`:`Bad request (400) \u2014 force-compressing and retrying... (attempt ${L}/3)`,$.yellow);let ce=Je(),{messages:j,tokensRemoved:H}=jt(b,ce,Y);b=j,H>50&&re(`${$.dim} [force-compressed \u2014 ~${H} tokens freed]${$.reset}`),dt--;continue}{let D=b.find(ue=>ue.role==="system"),Y=b.find(ue=>ue.role==="user"&&!String(ue.content).startsWith("[SYSTEM")&&!String(ue.content).startsWith("BLOCKED:")),ce=[D,Y].filter(Boolean),{getUsage:j}=Qe(),H=Qe().estimateMessagesTokens(ce),te=Qe().estimateMessagesTokens(b);if(H<te){let ue=[],$e=Q.filter(de=>de.role==="assistant"&&typeof de.content=="string"&&de.content.trim().length>30).slice(-3).map(de=>de.content.trim().slice(0,120).replace(/\n+/g," "));$e.length>0&&ue.push(`Key findings:
925
925
  `+$e.map(de=>`- ${de}`).join(`
926
926
  `));let Ie=Q.filter(de=>de.role==="tool"&&typeof de.content=="string"&&!de.content.startsWith("BLOCKED:")&&de.content.trim().length>10).slice(-3).map(de=>de.content.trim().split(`
927
927
  `).slice(0,3).join(`
@@ -931,29 +931,29 @@ ${$.dim} ${c}${$.reset}`),l>=30&&process.stdout.isTTY){let u=n.size>0?`Done \u2
931
931
  ${ue.join(`
932
932
  `)}
933
933
  Continue implementing the fixes based on these findings.`};ce.push(de)}if(Ks>=3){let de=M.size>0?`
934
- Files modified so far: ${[...M].map(pt=>pt.split("/").slice(-1)[0]).join(", ")}`:"";re(`${$.red} \u2717 Super-nuclear limit reached (3\xD7) \u2014 aborting to prevent runaway context loop${$.reset}`),console.log(`${$.yellow} \u{1F4A1} Task may exceed model context. Try /clear and break it into smaller steps.${de?$.dim+de:""}${$.reset}`),c&&(c.stop(),c=null),i(null),We(z,S,M,U,K,{suppressHint:!0}),Ue(Q);break}if(b=ce,Ks++,Nt=0,pe=0,Ia.clear(),ss.clear(),os.clear(),Pa.clear(),Zn(`Super-nuclear compression \u2014 dropped all history, keeping original task only (${te-H} tokens freed)`,$.yellow),Ks>=1){let de={role:"user",content:`[SYSTEM WARNING] Context wiped ${Ks}\xD7. SKIP investigation \u2014 implement directly using findings above. Max 5 tool calls total, then finish.
934
+ Files modified so far: ${[...M].map(pt=>pt.split("/").slice(-1)[0]).join(", ")}`:"";re(`${$.red} \u2717 Super-nuclear limit reached (3\xD7) \u2014 aborting to prevent runaway context loop${$.reset}`),console.log(`${$.yellow} \u{1F4A1} Task may exceed model context. Try /clear and break it into smaller steps.${de?$.dim+de:""}${$.reset}`),c&&(c.stop(),c=null),i(null),We(X,S,M,U,K,{suppressHint:!0}),Ue(Q);break}if(b=ce,Ks++,Nt=0,pe=0,Ia.clear(),ss.clear(),os.clear(),Pa.clear(),Zn(`Super-nuclear compression \u2014 dropped all history, keeping original task only (${te-H} tokens freed)`,$.yellow),Ks>=1){let de={role:"user",content:`[SYSTEM WARNING] Context wiped ${Ks}\xD7. SKIP investigation \u2014 implement directly using findings above. Max 5 tool calls total, then finish.
935
935
 
936
- CRITICAL: If you must re-read a file, use line_start/line_end to read ONLY the section you need (e.g. last 50 lines). Never read a full large file again \u2014 that is what caused the context overflow.`};Q.push(de),b.push(de)}L=0,dt--;continue}}v="Context too large to compress \u2014 use /clear to start fresh"}else E.message.includes("500")||E.message.includes("502")||E.message.includes("503")||E.message.includes("504")?v="API server error \u2014 the provider is experiencing issues. Please try again in a moment":(E.message.includes("fetch failed")||E.message.includes("fetch"))&&(v="Network request failed \u2014 please check your internet connection");if(console.log(`${$.red} \u2717 ${v}${$.reset}`),E.message.includes("429")){if(O++,O>Ta){console.log(`${$.red} Rate limit: max retries (${Ta}) exceeded. Try again later or use /budget to check your limits.${$.reset}`),c&&(c.stop(),c=null),i(null),We(z,S,M,U,K),Ue(Q);break}let D=Math.min(1e4*Math.pow(2,O-1),12e4),X=new es(`Rate limit \u2014 waiting ${Math.round(D/1e3)}s (retry ${O}/${Ta})`);X.start(),await new Promise(ce=>setTimeout(ce,D)),X.stop();continue}if(E.message.includes("socket disconnected")||E.message.includes("TLS")||E.message.includes("ECONNRESET")||E.message.includes("ECONNABORTED")||E.message.includes("ETIMEDOUT")||E.code==="ECONNRESET"||E.code==="ECONNABORTED"){if(N++,N>Ra){console.log(`${$.red} Network error: max retries (${Ra}) exceeded. Check your connection and try again.${$.reset}`),c&&(c.stop(),c=null),i(null),We(z,S,M,U,K),Ue(Q);break}let D=Math.min(2e3*Math.pow(2,N-1),3e4),X=new es(`Network error \u2014 retrying in ${Math.round(D/1e3)}s (${N}/${Ra})`);X.start(),await new Promise(ce=>setTimeout(ce,D)),X.stop(),dt--;continue}c&&(c.stop(),c=null),i(null),We(z,S,M,U,K),Ue(Q);break}if(clearInterval(gc),O=0,N=0,Ur&&(c&&!c._paused&&c.pause(),Fe&&Fe.stop()),Ut&&(clearTimeout(Ut),Ut=null),bt&&ft&&(ft.push(bt),bt=""),Ft&&ft.flush(),N=0,C=0,Pt&&Pt.usage){let E=Pt.usage.prompt_tokens||0,v=Pt.usage.completion_tokens||0;Gf(ts(),Rn(),E,v),l+=E+v,c&&c.setStats({tokens:l})}else if(Pt&&!Pt.usage){let E=b.map(D=>typeof D.content=="string"?D.content:Array.isArray(D.content)?D.content.map(X=>typeof X=="string"?X:X.text||"").join(""):"").join(" "),v=Yf(E),J=Yf(Pt.content||Ft||"");Gf(ts(),Rn(),v,J),l+=v+J,c&&c.setStats({tokens:l})}let{content:$c,tool_calls:fn}=Pt,co=Aa($c||""),yc=co.truncated?co.text:$c;co.truncated&&re(`${$.yellow} \u26A0 LLM output loop detected (${co.repeatCount}\xD7 repeated paragraph) \u2014 response truncated${$.reset}`);let lo=Qb(yc||""),us=lo.truncated?lo.text:yc;lo.truncated&&re(`${$.yellow} \u26A0 LLM output loop detected (${lo.repeatCount}\xD7 repeated window) \u2014 response truncated${$.reset}`);let Gr={role:"assistant",content:us||""};if(fn&&fn.length>0&&(Gr.tool_calls=fn),Q.push(Gr),b.push(Gr),!fn||fn.length===0){let E=(us||"").trim().length>0||Ft.trim().length>0,v=!1;if(rs&&E&&(rs=!1,Nt=0,v=!0),v&&E){let J=(us||"").trim();if(J.endsWith("?")||/\b(Wo |Bitte |Kannst du|Soll ich)\b/.test(J.slice(-200))){let X={role:"user",content:"[SYSTEM] Continue. Do not ask questions \u2014 implement the fix yourself using SSH. The server is at 94.130.37.43."};b.push(X),Q.push(X);continue}}if(!E&&z>0&&dt<Oa-1){let J={role:"user",content:"[SYSTEM] You ran tools but produced no visible output. The user CANNOT see tool results \u2014 only your text. Please summarize your findings now."};b.push(J),Q.push(J);continue}if(Ys()&&E&&z===0)if(hr++,hr>2)re(`${$.yellow} \u26A0 Plan accepted despite no file reads (rejection loop cap reached)${$.reset}`);else{let J={role:"user",content:`[SYSTEM] You wrote a plan without reading any files. This plan may be based on incorrect assumptions (wrong database type, wrong file structure, etc.).
936
+ CRITICAL: If you must re-read a file, use line_start/line_end to read ONLY the section you need (e.g. last 50 lines). Never read a full large file again \u2014 that is what caused the context overflow.`};Q.push(de),b.push(de)}L=0,dt--;continue}}v="Context too large to compress \u2014 use /clear to start fresh"}else E.message.includes("500")||E.message.includes("502")||E.message.includes("503")||E.message.includes("504")?v="API server error \u2014 the provider is experiencing issues. Please try again in a moment":(E.message.includes("fetch failed")||E.message.includes("fetch"))&&(v="Network request failed \u2014 please check your internet connection");if(console.log(`${$.red} \u2717 ${v}${$.reset}`),E.message.includes("429")){if(O++,O>Ta){console.log(`${$.red} Rate limit: max retries (${Ta}) exceeded. Try again later or use /budget to check your limits.${$.reset}`),c&&(c.stop(),c=null),i(null),We(X,S,M,U,K),Ue(Q);break}let D=Math.min(1e4*Math.pow(2,O-1),12e4),Y=new es(`Rate limit \u2014 waiting ${Math.round(D/1e3)}s (retry ${O}/${Ta})`);Y.start(),await new Promise(ce=>setTimeout(ce,D)),Y.stop();continue}if(E.message.includes("socket disconnected")||E.message.includes("TLS")||E.message.includes("ECONNRESET")||E.message.includes("ECONNABORTED")||E.message.includes("ETIMEDOUT")||E.code==="ECONNRESET"||E.code==="ECONNABORTED"){if(N++,N>Ra){console.log(`${$.red} Network error: max retries (${Ra}) exceeded. Check your connection and try again.${$.reset}`),c&&(c.stop(),c=null),i(null),We(X,S,M,U,K),Ue(Q);break}let D=Math.min(2e3*Math.pow(2,N-1),3e4),Y=new es(`Network error \u2014 retrying in ${Math.round(D/1e3)}s (${N}/${Ra})`);Y.start(),await new Promise(ce=>setTimeout(ce,D)),Y.stop(),dt--;continue}c&&(c.stop(),c=null),i(null),We(X,S,M,U,K),Ue(Q);break}if(clearInterval(gc),O=0,N=0,Ur&&(c&&!c._paused&&c.pause(),Fe&&Fe.stop()),Ut&&(clearTimeout(Ut),Ut=null),bt&&ft&&(ft.push(bt),bt=""),Ft&&ft.flush(),N=0,C=0,Pt&&Pt.usage){let E=Pt.usage.prompt_tokens||0,v=Pt.usage.completion_tokens||0;Gf(ts(),Rn(),E,v),l+=E+v,c&&c.setStats({tokens:l})}else if(Pt&&!Pt.usage){let E=b.map(D=>typeof D.content=="string"?D.content:Array.isArray(D.content)?D.content.map(Y=>typeof Y=="string"?Y:Y.text||"").join(""):"").join(" "),v=Yf(E),J=Yf(Pt.content||Ft||"");Gf(ts(),Rn(),v,J),l+=v+J,c&&c.setStats({tokens:l})}let{content:$c,tool_calls:fn}=Pt,co=Aa($c||""),yc=co.truncated?co.text:$c;co.truncated&&re(`${$.yellow} \u26A0 LLM output loop detected (${co.repeatCount}\xD7 repeated paragraph) \u2014 response truncated${$.reset}`);let lo=Qb(yc||""),us=lo.truncated?lo.text:yc;lo.truncated&&re(`${$.yellow} \u26A0 LLM output loop detected (${lo.repeatCount}\xD7 repeated window) \u2014 response truncated${$.reset}`);let Gr={role:"assistant",content:us||""};if(fn&&fn.length>0&&(Gr.tool_calls=fn),Q.push(Gr),b.push(Gr),!fn||fn.length===0){let E=(us||"").trim().length>0||Ft.trim().length>0,v=!1;if(rs&&E&&(rs=!1,Nt=0,v=!0),v&&E){let J=(us||"").trim();if(J.endsWith("?")||/\b(Wo |Bitte |Kannst du|Soll ich)\b/.test(J.slice(-200))){let Y={role:"user",content:"[SYSTEM] Continue. Do not ask questions \u2014 implement the fix yourself using SSH. The server is at 94.130.37.43."};b.push(Y),Q.push(Y);continue}}if(!E&&X>0&&dt<Oa-1){let J={role:"user",content:"[SYSTEM] You ran tools but produced no visible output. The user CANNOT see tool results \u2014 only your text. Please summarize your findings now."};b.push(J),Q.push(J);continue}if(Ys()&&E&&X===0)if(hr++,hr>2)re(`${$.yellow} \u26A0 Plan accepted despite no file reads (rejection loop cap reached)${$.reset}`);else{let J={role:"user",content:`[SYSTEM] You wrote a plan without reading any files. This plan may be based on incorrect assumptions (wrong database type, wrong file structure, etc.).
937
937
 
938
- MANDATORY: Use read_file, glob, or grep to investigate the actual codebase first. Read at least the relevant module file and route file before writing the plan.`};Q.push(J),b.push(J),re(`${$.yellow} \u26A0 Plan rejected (${hr}/2): no files read \u2014 forcing investigation${$.reset}`);continue}if(Ys()&&E){let J=(us||Ft||"").trim();Pb(J),f_(J);let D=Ib(J);if(D.length>0){let X=Q.find(te=>te.role==="user"),ce=typeof X?.content=="string"?X.content.slice(0,120):"Task";Lb(ce,D);let j=D.length===1?"step":"steps",H=!1;if(process.stdout.isTTY&&process.stdin.isTTY){let{approvePlan:te,startExecution:ue,setPlanMode:$e}=Dt();process.stdout.write(`
938
+ MANDATORY: Use read_file, glob, or grep to investigate the actual codebase first. Read at least the relevant module file and route file before writing the plan.`};Q.push(J),b.push(J),re(`${$.yellow} \u26A0 Plan rejected (${hr}/2): no files read \u2014 forcing investigation${$.reset}`);continue}if(Ys()&&E){let J=(us||Ft||"").trim();Pb(J),f_(J);let D=Ib(J);if(D.length>0){let Y=Q.find(te=>te.role==="user"),ce=typeof Y?.content=="string"?Y.content.slice(0,120):"Task";Lb(ce,D);let j=D.length===1?"step":"steps",H=!1;if(process.stdout.isTTY&&process.stdin.isTTY){let{approvePlan:te,startExecution:ue,setPlanMode:$e}=Dt();process.stdout.write(`
939
939
  ${$.cyan}${$.bold}Plan ready${$.reset} ${$.dim}(${D.length} ${j})${$.reset} ${$.green}[A]${$.reset}${$.dim}pprove${$.reset} ${$.yellow}[E]${$.reset}${$.dim}dit${$.reset} ${$.red}[R]${$.reset}${$.dim}eject${$.reset} ${$.dim}[\u21B5 = approve]:${$.reset} `);let Ie=process.stdin.isRaw,de=await new Promise(pt=>{try{process.stdin.setRawMode(!0)}catch{}process.stdin.resume(),process.stdin.once("data",uo=>{try{process.stdin.setRawMode(Ie||!1)}catch{}let Yr=uo.toString().toLowerCase()[0]||"\r";pt(Yr)})});if(process.stdout.write(`
940
940
  `),de==="r")console.log(`${$.red}Plan rejected.${$.reset} Ask follow-up questions to refine.`);else if(de==="e")console.log(`${$.yellow}Type /plan edit to open in editor, or give feedback.${$.reset}`);else if(te()){ue(),$e(!1),Ma(),console.log(`${$.green}${$.bold}Approved!${$.reset} Executing ${D.length} ${j}...`);let pt=`[PLAN APPROVED \u2014 EXECUTE NOW]
941
941
 
942
942
  Implement the following plan step by step. All tools are now available.
943
943
 
944
944
  ${J}`;Q.push({role:"user",content:pt}),b.push({role:"user",content:pt}),H=!0}}else console.log(`
945
- ${$.cyan}${$.bold}Plan ready${$.reset} ${$.dim}(${D.length} ${j} extracted).${$.reset} Type ${$.cyan}/plan approve${$.reset}${$.dim} to execute, or ${$.reset}${$.cyan}/plan edit${$.reset}${$.dim} to review.${$.reset}`);if(H){c&&(c.stop(),c=null),dt--;continue}}else{let X=!1;if(process.stdout.isTTY&&process.stdin.isTTY){let{approvePlan:ce,startExecution:j,setPlanMode:H}=Dt();process.stdout.write(`
945
+ ${$.cyan}${$.bold}Plan ready${$.reset} ${$.dim}(${D.length} ${j} extracted).${$.reset} Type ${$.cyan}/plan approve${$.reset}${$.dim} to execute, or ${$.reset}${$.cyan}/plan edit${$.reset}${$.dim} to review.${$.reset}`);if(H){c&&(c.stop(),c=null),dt--;continue}}else{let Y=!1;if(process.stdout.isTTY&&process.stdin.isTTY){let{approvePlan:ce,startExecution:j,setPlanMode:H}=Dt();process.stdout.write(`
946
946
  ${$.cyan}${$.bold}Plan ready.${$.reset} ${$.green}[A]${$.reset}${$.dim}pprove${$.reset} ${$.red}[R]${$.reset}${$.dim}eject${$.reset} ${$.dim}[\u21B5 = approve]:${$.reset} `);let te=process.stdin.isRaw,ue=await new Promise($e=>{try{process.stdin.setRawMode(!0)}catch{}process.stdin.resume(),process.stdin.once("data",Ie=>{try{process.stdin.setRawMode(te||!1)}catch{}$e(Ie.toString().toLowerCase()[0]||"\r")})});if(process.stdout.write(`
947
947
  `),ue==="r")console.log(`${$.red}Plan rejected.${$.reset} Ask follow-up questions to refine.`);else if(ce()){j(),H(!1),Ma(),console.log(`${$.green}${$.bold}Approved!${$.reset} Executing...`);let Ie=`[PLAN APPROVED \u2014 EXECUTE NOW]
948
948
 
949
949
  Implement the following plan step by step. All tools are now available.
950
950
 
951
- ${getPlanContent()||Pt.content}`;Q.push({role:"user",content:Ie}),b.push({role:"user",content:Ie}),X=!0}}else console.log(`
952
- ${$.cyan}${$.bold}Plan ready.${$.reset} ${$.dim}Type ${$.reset}${$.cyan}/plan approve${$.reset}${$.dim} to execute, or ask follow-up questions to refine.${$.reset}`);if(X){c&&(c.stop(),c=null),dt--;continue}}}if(c&&(c.stop(),c=null),i(null),We(z,S,M,U,K),z>0&&!n._isSummaryTurn&&tp()&&Eb(us))try{re(`${$.dim} [post-turn] terse ending \u2014 requesting summary${$.reset}`);let J=[...b,{role:"user",content:"Please summarize what you just did in 2-3 sentences."}],X=((await Wf(J,[],{}))?.content||"").trim();X&&console.log(`
953
- ${X}`)}catch{}Ue(Q),Bf(Q);return}z++,z>=1&&(Ne=!1);for(let E of fn){let v=E.function.name;S.set(v,(S.get(v)||0)+1)}let Pe=await Promise.all(fn.map(E=>p_(E)));{let E=Ot(b,Je()),v=E.percentage,J=Pe.some(j=>j.canExecute&&j.fnName==="read_file"&&!j.args?.line_end),D=Pe.filter(j=>j.canExecute&&j.fnName==="read_file"&&j.args?.path&&Nn.get(j.args.path)>=1&&!j.args?.line_start).map(j=>j.args.path.split("/").slice(-2).join("/")),X=D.length>0;if(v>=70&&J&&Dr<70||v>=85&&Dr<85||X){Dr=v;let j=v>=85?"URGENT":"WARNING",H;X?(j="WARNING",H=`Unbounded re-read of ${D.join(", ")} \u2014 already in context. Use line_start/line_end to read specific sections instead.`):J?H=`Unbounded read at ${Math.round(v)}% context \u2014 use line_start/line_end to avoid overflow.`:H=`Context ${Math.round(v)}% used. Avoid large reads, wrap up with what you have.`;let te={role:"user",content:`[SYSTEM ${j}] Context ${Math.round(v)}% used (${E.used}/${E.limit} tokens). ${H}`};if(Q.push(te),b.push(te),v>=85){let ue=X?` (re-read of: ${D.join(", ")})`:"";re(`${$.yellow} \u26A0 Context ${Math.round(v)}% used \u2014 agent warned to use targeted reads${ue}${$.reset}`)}}}for(let E of Pe){if(!E.canExecute||E.fnName!=="read_file")continue;let v=E.args?.path;if(!v)continue;let J=Nn.get(v)||0,D=E.args?.line_start!=null,X=ss.get(v)===!0,ce=6;if(J>=ce){let j=v.split("/").slice(-2).join("/"),H=(os.get(v)||0)+1;os.set(v,H),H===1&&re(`${$.red} \u2716 Blocked: "${j}" read ${J}\xD7 \u2014 hard cap (${ce}) reached${$.reset}`),E.canExecute=!1,E.errorResult={role:"tool",content:`BLOCKED: read_file("${v}") denied \u2014 file already read ${J}\xD7 (hard cap: ${ce}). You have seen enough of this file. Use grep to find specific content or proceed with what you know.`,tool_call_id:E.callId}}else if(J>=1&&D)if(X){let j=v.split("/").slice(-2).join("/");console.log(`${$.cyan} \u21A9 Targeted re-read: "${j}" (line_start=${E.args.line_start}) \u2014 edit recovery${$.reset}`),ss.delete(v)}else{let j=E.args.line_start||1,H=E.args.line_end||j+350,te=Gs.get(v)||[],ue=!1;for(let[$e,Ie]of te){let de=Math.max(j,$e),pt=Math.min(H,Ie);if(pt>de){let uo=pt-de,Yr=H-j||1;if(uo/Yr>=.7){let xc=v.split("/").slice(-2).join("/");re(`${$.red} \u2716 Blocked duplicate read: "${xc}" lines ${j}-${H} (\u226570% overlap with lines ${$e}-${Ie} already in context)${$.reset}`),E.canExecute=!1,E.errorResult={role:"tool",content:`BLOCKED: read_file("${v}", lines ${j}-${H}) is a duplicate \u2014 lines ${$e}-${Ie} are already in your context (\u226570% overlap). Use grep to find specific content instead of re-reading.`,tool_call_id:E.callId},ue=!0;break}}}if(!ue){let $e=te.length,Ie=2;if($e>=3){let pt=v.split("/").slice(-2).join("/");re(`${$.red} \u2716 Blocked file-scroll: "${pt}" \u2014 ${$e} sections already read. Use grep to find specific content.${$.reset}`),E.canExecute=!1,E.errorResult={role:"tool",content:`BLOCKED: read_file("${v}") denied \u2014 you have already read ${$e} different sections of this file (file-scroll pattern). You have seen most of this file. Use grep_search to find the exact lines you need instead of continuing to scroll.`,tool_call_id:E.callId}}else $e>=Ie&&(E._scrollWarn={sectionCount:$e+1,path:v})}}else if(J>=1){let j=v.split("/").slice(-2).join("/"),H=(os.get(v)||0)+1;os.set(v,H),H===1&&re(`${$.red} \u2716 Blocked unbounded re-read: "${j}" \u2014 already in context. Use line_start/line_end for specific sections.${$.reset}`),E.canExecute=!1,E.errorResult={role:"tool",content:`BLOCKED: read_file("${v}") denied \u2014 file already in context (read ${J}\xD7). Use line_start/line_end to read a specific section instead of the full file.`,tool_call_id:E.callId}}}for(let E of Pe)E.canExecute&&(E.fnName!=="ssh_exec"&&E.fnName!=="bash"||/\bsed\s+-n\b/.test(E.args?.command||"")&&(re(`${$.red} \u2716 Blocked sed -n: use grep -n "pattern" <file> | head -30 instead${$.reset}`),E.canExecute=!1,E.errorResult={role:"tool",content:'BLOCKED: sed -n is forbidden \u2014 it floods context with line ranges. Use grep -n "pattern" <file> | head -30 to read a specific section, or cat <file> for the full file.',tool_call_id:E.callId}));for(let E of Pe){if(!E.canExecute||E.fnName!=="write_file")continue;let v=E.args?.path,J=E.args?.content||"";if(v)try{let D=require("fs"),X=require("path").resolve(process.cwd(),v);if(D.existsSync(X)){let ce=D.statSync(X).size,j=Buffer.byteLength(J,"utf8"),H=ce>0?j/ce:1;if(H<.6&&ce>200){let te=v.split("/").slice(-2).join("/");console.log(`${$.red} \u2716 write_file shrink guard: "${te}" would shrink to ${Math.round(H*100)}% of original \u2014 likely context loss${$.reset}`),E.canExecute=!1,E.errorResult={role:"tool",content:`BLOCKED: write_file("${v}") denied \u2014 new content is only ${Math.round(H*100)}% of current file size (${ce} \u2192 ${j} bytes). This looks like a partial rewrite after context loss. Use edit_file/patch_file to add only the new code, or read the file first to see full content before replacing.`,tool_call_id:E.callId}}}}catch{}}for(let E of Pe){if(!E.canExecute||E.fnName!=="grep")continue;let v=E.args?.path;if(!v)continue;let J=je.get(v)||0;if(J>=Jt){let D=v.split("/").slice(-2).join("/");re(`${$.red} \u2716 Blocked grep: "${D}" grepped ${J}\xD7 with different patterns \u2014 flood threshold exceeded${$.reset}`),E.canExecute=!1,E.errorResult={role:"tool",content:`BLOCKED: grep("${v}") denied \u2014 ${J} patterns already tried. Use existing results.`,tool_call_id:E.callId}}}if(rs){let E=Pe.filter(D=>D.canExecute&&D.fnName==="ssh_exec"),v=Pe.some(D=>D.canExecute&&D.fnName!=="ssh_exec"),J=ee&&pe<3;if(E.length>0&&!v&&J&&$r<1)rs=!1,$r++,Nt=Math.max(0,jr-2),re(`${$.dim} [dual-block deadlock: SSH storm relaxed \u2014 allowing 1 SSH call (relax ${$r}/1)]${$.reset}`);else for(let D of E)D.canExecute=!1,D.errorResult={role:"tool",content:`BLOCKED: ssh_exec denied \u2014 SSH storm (${jr}+ calls). Synthesize findings now.`,tool_call_id:D.callId}}if(ee&&pe<3){for(let E of Pe)if(E.canExecute&&["bash","read_file","find_files"].includes(E.fnName)){pe++;{let v=Je(),{messages:J}=jt(b,v);b=J}re(`${$.yellow} \u26A0 Jarvis-local guard: blocking local ${E.fnName} \u2014 use ssh_exec on 94.130.37.43${$.reset}`),E.canExecute=!1,E.errorResult={role:"tool",content:`BLOCKED: ${E.fnName} denied \u2014 this is a server issue. Use ssh_exec on 94.130.37.43 instead.`,tool_call_id:E.callId};break}}let ds=c?{skipSpinner:!0,skipSummaries:!0}:{},Wm=Pe.some(E=>E.fnName==="ask_user"),wc=!ds.skipSummaries&&!Ne,Kr=null;wc&&!Wm?(Ne=!0,ds.skipSpinner=!0,process.stdout.isTTY?(process.stdout.write(ka(Pe,z,!1,"blink")),Kr=!0):qt||process.stdout.write(ka(Pe,z,!1)+`
954
- `)):wc&&(Ne=!0,ds.skipSpinner=!0),c&&c._paused&&c.resume();let{results:bc,summaries:Bm}=await g_(Pe,!0,{...ds,skipSummaries:!0});if(Kr&&(Kr=null,process.stdout.write(`\r\x1B[2K${ka(Pe,z,!1)}
955
- `)),!ds.skipSummaries){let E=Bm.filter((D,X)=>!(Pe[X]&&Pe[X].fnName==="ask_user"));for(let D of E)console.log(D);console.log("");let v=Pe.filter(D=>D&&D.fnName!=="ask_user").map(D=>D.fnName),J=se.record(0,v,U,M);J&&Xb(J)}for(let E of Pe){if(E.canExecute||!E.errorResult)continue;let v=typeof E.errorResult.content=="string"?E.errorResult.content:"";if((v.startsWith("BLOCKED:")||v.startsWith("PLAN MODE:"))&&(un++,un>=mc)){re(`${$.red} \u2716 Loop abort: ${un} consecutive blocked calls (pre-execution) \u2014 model not heeding BLOCKED messages${$.reset}`),c&&(c.stop(),c=null),i(null),We(z,S,M,U,K,{suppressHint:!0}),Ue(Q);return}}for(let E=0;E<Pe.length;E++){let v=Pe[E];if(!v.canExecute)continue;let J=bc[E].content,D=J.split(`
956
- `)[0],X=!D.startsWith("ERROR")&&!D.startsWith("CANCELLED")&&!D.startsWith("Command failed")&&!D.startsWith("EXIT");if(!X&&(v.fnName==="edit_file"||v.fnName==="patch_file")&&v.args?.path&&D.includes("old_text not found")&&ss.set(v.args.path,!0),X&&v.fnName==="write_file"&&v.args?.path){let j=v.args.path.split("/").pop(),H=v.args.path.includes("/tests/")||v.args.path.includes("\\tests\\");if(/^(test_|demo_|temp_|tmp_|scratch_)/.test(j)&&!H){re(`${$.yellow} \u26A0 Temp file: "${j}" \u2014 delete with bash rm when done to keep the workspace clean${$.reset}`);let ue={role:"user",content:`[HINT] "${v.args.path}" looks like a temporary test/demo file. Delete it with bash("rm ${v.args.path}") as soon as you're done \u2014 orphaned temp files count against session quality.`};Q.push(ue),b.push(ue)}}if(X&&["write_file","edit_file","patch_file"].includes(v.fnName)&&v.args&&v.args.path){ss.delete(v.args.path),M.add(v.args.path);let j=(I.get(v.args.path)||0)+1;I.set(v.args.path,j);let H=v.args.path.split("/").slice(-2).join("/");if(j===W){re(`${$.yellow} \u26A0 Loop warning: "${H}" edited ${j}\xD7 \u2014 possible edit loop${$.reset}`);let te={role:"user",content:`[SYSTEM WARNING] "${v.args.path}" edited ${j}\xD7. One more edit max, then move on.`};Q.push(te),b.push(te)}else if(j>=oe){re(`${$.red} \u2716 Loop abort: "${H}" edited ${j}\xD7 \u2014 aborting to prevent runaway loop${$.reset}`),c&&(c.stop(),c=null),i(null),We(z,S,M,U,K,{suppressHint:!0}),Ue(Q);return}}if((v.fnName==="bash"||v.fnName==="ssh_exec")&&v.args&&v.args.command){let j=v.args.command.replace(/\d+/g,"N").replace(/\s+/g," ").trim().slice(0,100),H=(V.get(j)||0)+1;if(V.set(j,H),H===Z){re(`${$.yellow} \u26A0 Loop warning: same bash command run ${H}\xD7 \u2014 possible debug loop${$.reset}`);let te={role:"user",content:`[SYSTEM WARNING] Same bash command ${H}\xD7. Debug loop detected \u2014 try a different approach.`};Q.push(te),b.push(te)}else if(H>=ge){re(`${$.red} \u2716 Loop abort: same bash command run ${H}\xD7 \u2014 aborting runaway debug loop${$.reset}`),c&&(c.stop(),c=null),i(null),We(z,S,M,U,K,{suppressHint:!0}),Ue(Q);return}}if(v.fnName==="ssh_exec"){if(Nt++,Nt>=Um){re(`${$.red} \u2716 SSH storm abort: ${Nt} consecutive ssh_exec calls \u2014 aborting${$.reset}`),c&&(c.stop(),c=null),i(null),We(z,S,M,U,K,{suppressHint:!0}),Ue(Q);return}else if(Nt===jr){{let H=Je(),{messages:te}=jt(b,H);b=te}rs=!0,re(`${$.yellow} \u26A0 SSH storm warning: ${Nt} consecutive ssh_exec calls \u2014 blocking further SSH${$.reset}`);let j={role:"user",content:`[SYSTEM WARNING] ${Nt} consecutive SSH calls. Synthesize findings now \u2014 no more SSH.`};Q.push(j),b.push(j)}}else v.canExecute&&(Nt=0);if(X&&v.fnName==="grep"&&v.args&&v.args.pattern){let j=`${v.args.pattern}|${v.args.path||""}`,H=(fe.get(j)||0)+1;if(fe.set(j,H),H===we){re(`${$.yellow} \u26A0 Loop warning: grep pattern "${v.args.pattern.slice(0,40)}" run ${H}\xD7 \u2014 possible search loop${$.reset}`);let te={role:"user",content:`[SYSTEM WARNING] Same grep pattern ${H}\xD7. Results unchanged \u2014 use existing data or try different pattern.`};Q.push(te),b.push(te)}else if(H>=be){re(`${$.red} \u2716 Loop abort: grep pattern run ${H}\xD7 \u2014 aborting runaway search loop${$.reset}`),c&&(c.stop(),c=null),i(null),We(z,S,M,U,K,{suppressHint:!0}),Ue(Q);return}if(v.args.path){let te=(je.get(v.args.path)||0)+1;if(je.set(v.args.path,te),te===Ge){let ue=v.args.path.split("/").slice(-2).join("/");re(`${$.yellow} \u26A0 Loop warning: "${ue}" grepped ${te}\xD7 with different patterns \u2014 context flood risk${$.reset}`);let $e={role:"user",content:`[SYSTEM WARNING] "${v.args.path}" grepped ${te}\xD7 \u2014 file already in context. Use existing data, stop searching.`};Q.push($e),b.push($e)}}}if(X&&(v.fnName==="bash"||v.fnName==="ssh_exec")&&J.includes('"valid":true')){{let H=Je();if(Ot(b,H).percentage>=60){let{messages:ue,tokensRemoved:$e}=jt(b,H);$e>0&&(b=ue,console.log(`${$.dim} [pre-stop-compress \u2014 ~${$e} tokens freed before STOP injection, now ${Math.round(Ot(b,H).percentage)}%]${$.reset}`))}}let j={role:"user",content:'[SYSTEM STOP] Tool result contains {"valid":true}. The token/service is valid and reachable. STOP all further investigation immediately. Report to the user that the token is valid, the service is healthy, and no fix is needed. Do NOT read any more log files.'};Q.push(j),b.push(j),console.log(`${$.cyan} \u2713 Health-check stop signal detected \u2014 injecting STOP instruction${$.reset}`)}if(J.startsWith("BLOCKED:")){if(un++,un>=mc){re(`${$.red} \u2716 Loop abort: ${un} consecutive blocked calls \u2014 model not heeding BLOCKED messages${$.reset}`),c&&(c.stop(),c=null),i(null),We(z,S,M,U,K,{suppressHint:!0}),Ue(Q);return}}else un=0;if(X)ln=0,Fr=!0;else if(ln++,ln===Dm){re(`${$.yellow} \u26A0 Loop warning: ${ln} consecutive tool errors \u2014 possible stuck loop${$.reset}`);let j={role:"user",content:`[SYSTEM WARNING] ${ln} consecutive errors. Stuck loop \u2014 try fundamentally different approach or declare done.`};Q.push(j),b.push(j)}else if(ln>=jm){re(`${$.red} \u2716 Loop abort: ${ln} consecutive errors \u2014 aborting stuck loop${$.reset}`),c&&(c.stop(),c=null),i(null),We(z,S,M,U,K,{suppressHint:!0}),Ue(Q);return}if(X&&v.fnName==="read_file"&&v.args&&v.args.path){U.add(v.args.path);let j=(Nn.get(v.args.path)||0)+1;if(Nn.set(v.args.path,j),v.args.line_start!=null){let ue=v.args.line_start||1,$e=v.args.line_end||ue+350;Gs.has(v.args.path)||Gs.set(v.args.path,[]),Gs.get(v.args.path).push([ue,$e])}if(v._scrollWarn){let{sectionCount:ue,path:$e}=v._scrollWarn,Ie={role:"user",content:`[SYSTEM WARNING] "${$e}" \u2014 you have now read ${ue} different sections of this file. This is a file-scroll pattern. Stop reading sections and use grep_search to find the specific lines you need instead.`};Q.push(Ie),b.push(Ie),re(`${$.yellow} \u26A0 Scroll warning: "${$e.split("/").slice(-2).join("/")}" \u2014 ${ue} sections read \u2014 use grep instead${$.reset}`)}let H=v.args.path.split("/").slice(-2).join("/"),te=!v.args?.line_start&&!v.args?.line_end;if(te&&j===Lr){{let $e=Je();if(Ot(b,$e).percentage>=60){let{messages:de}=jt(b,$e);b=de}}re(`${$.yellow} \u26A0 Loop warning: "${H}" read unbounded ${j}\xD7 \u2014 use line_start/line_end${$.reset}`);let ue={role:"user",content:`[SYSTEM WARNING] "${v.args.path}" read ${j}\xD7 without line ranges. Use line_start/line_end to read specific sections \u2014 do not re-read the full file.`};Q.push(ue),b.push(ue)}else if(te&&j>=Lm){re(`${$.red} \u2716 Loop abort: "${H}" read unbounded ${j}\xD7 \u2014 aborting runaway read loop${$.reset}`),c&&(c.stop(),c=null),i(null),We(z,S,M,U,K,{suppressHint:!0}),Ue(Q);return}}if(v.fnName==="spawn_agents"){let j=(J.match(/\bStatus: done\b/g)||[]).length;if((J.match(/\bStatus: truncated\b/g)||[]).length>0&&j===0){if(dn++,dn===qm){re(`${$.yellow} \u26A0 Swarm warning: all sub-agents hit iteration limit ${dn}\xD7 in a row${$.reset}`);let te={role:"user",content:`[SYSTEM WARNING] Sub-agents truncated ${dn}\xD7 in a row. Stop spawning \u2014 try different approach or report findings.`};Q.push(te),b.push(te)}else if(dn>=Fm){console.log(`${$.red} \u2716 Swarm abort: all sub-agents hit iteration limit ${dn}\xD7 \u2014 aborting stuck swarm${$.reset}`),c&&(c.stop(),c=null),i(null),We(z,S,M,U,K,{suppressHint:!0}),Ue(Q);return}}else j>0&&(dn=0)}}for(let E of bc)Q.push(E),b.push(E);{let E=Je();if(Ot(b,E).percentage>=78){let{messages:J,tokensRemoved:D}=jt(b,E);D>0&&(b=J,console.log(`${$.dim} [auto-compressed \u2014 ~${D} tokens freed, now ${Math.round(Ot(b,E).percentage)}%]${$.reset}`))}}let _c=y_();if(_c){let E={role:"user",content:`[User note mid-run]: ${_c}`};Q.push(E),b.push(E),console.log(`${$.cyan} \u270E Context added${$.reset}`)}}if(dt>=io){c&&(c.stop(),c=null),i(null),We(z,S,M,U,K),Ue(Q),Bf(Q);let{getActiveProviderName:qe}=Te();if(qe()==="ollama"&&qr<hc){if(M.size===0&&!Fr){console.log(`${$.yellow} \u26A0 Max iterations reached with no progress. Stopping.${$.reset}`);break e}qr++,io=20,console.log(`${$.dim} \u2500\u2500 auto-extending (+20 turns, ext ${qr}/${hc}) \u2500\u2500${$.reset}`);continue e}if(console.log(`
951
+ ${getPlanContent()||Pt.content}`;Q.push({role:"user",content:Ie}),b.push({role:"user",content:Ie}),Y=!0}}else console.log(`
952
+ ${$.cyan}${$.bold}Plan ready.${$.reset} ${$.dim}Type ${$.reset}${$.cyan}/plan approve${$.reset}${$.dim} to execute, or ask follow-up questions to refine.${$.reset}`);if(Y){c&&(c.stop(),c=null),dt--;continue}}}if(c&&(c.stop(),c=null),i(null),We(X,S,M,U,K),X>0&&!n._isSummaryTurn&&tp()&&Eb(us))try{re(`${$.dim} [post-turn] terse ending \u2014 requesting summary${$.reset}`);let J=[...b,{role:"user",content:"Please summarize what you just did in 2-3 sentences."}],Y=((await Wf(J,[],{}))?.content||"").trim();Y&&(console.log(`
953
+ ${Y}`),Q.push({role:"user",content:"Please summarize what you just did in 2-3 sentences."},{role:"assistant",content:Y}))}catch{}Ue(Q),Bf(Q);return}X++,X>=1&&(Ne=!1);for(let E of fn){let v=E.function.name;S.set(v,(S.get(v)||0)+1)}let Pe=await Promise.all(fn.map(E=>p_(E)));{let E=Ot(b,Je()),v=E.percentage,J=Pe.some(j=>j.canExecute&&j.fnName==="read_file"&&!j.args?.line_end),D=Pe.filter(j=>j.canExecute&&j.fnName==="read_file"&&j.args?.path&&Nn.get(j.args.path)>=1&&!j.args?.line_start).map(j=>j.args.path.split("/").slice(-2).join("/")),Y=D.length>0;if(v>=70&&J&&Dr<70||v>=85&&Dr<85||Y){Dr=v;let j=v>=85?"URGENT":"WARNING",H;Y?(j="WARNING",H=`Unbounded re-read of ${D.join(", ")} \u2014 already in context. Use line_start/line_end to read specific sections instead.`):J?H=`Unbounded read at ${Math.round(v)}% context \u2014 use line_start/line_end to avoid overflow.`:H=`Context ${Math.round(v)}% used. Avoid large reads, wrap up with what you have.`;let te={role:"user",content:`[SYSTEM ${j}] Context ${Math.round(v)}% used (${E.used}/${E.limit} tokens). ${H}`};if(Q.push(te),b.push(te),v>=85){let ue=Y?` (re-read of: ${D.join(", ")})`:"";re(`${$.yellow} \u26A0 Context ${Math.round(v)}% used \u2014 agent warned to use targeted reads${ue}${$.reset}`)}}}for(let E of Pe){if(!E.canExecute||E.fnName!=="read_file")continue;let v=E.args?.path;if(!v)continue;let J=Nn.get(v)||0,D=E.args?.line_start!=null,Y=ss.get(v)===!0,ce=6;if(J>=ce){let j=v.split("/").slice(-2).join("/"),H=(os.get(v)||0)+1;os.set(v,H),H===1&&re(`${$.red} \u2716 Blocked: "${j}" read ${J}\xD7 \u2014 hard cap (${ce}) reached${$.reset}`),E.canExecute=!1,E.errorResult={role:"tool",content:`BLOCKED: read_file("${v}") denied \u2014 file already read ${J}\xD7 (hard cap: ${ce}). You have seen enough of this file. Use grep to find specific content or proceed with what you know.`,tool_call_id:E.callId}}else if(J>=1&&D)if(Y){let j=v.split("/").slice(-2).join("/");console.log(`${$.cyan} \u21A9 Targeted re-read: "${j}" (line_start=${E.args.line_start}) \u2014 edit recovery${$.reset}`),ss.delete(v)}else{let j=E.args.line_start||1,H=E.args.line_end||j+350,te=Gs.get(v)||[],ue=!1;for(let[$e,Ie]of te){let de=Math.max(j,$e),pt=Math.min(H,Ie);if(pt>de){let uo=pt-de,Yr=H-j||1;if(uo/Yr>=.7){let xc=v.split("/").slice(-2).join("/");re(`${$.red} \u2716 Blocked duplicate read: "${xc}" lines ${j}-${H} (\u226570% overlap with lines ${$e}-${Ie} already in context)${$.reset}`),E.canExecute=!1,E.errorResult={role:"tool",content:`BLOCKED: read_file("${v}", lines ${j}-${H}) is a duplicate \u2014 lines ${$e}-${Ie} are already in your context (\u226570% overlap). Use grep to find specific content instead of re-reading.`,tool_call_id:E.callId},ue=!0;break}}}if(!ue){let $e=te.length,Ie=2;if($e>=3){let pt=v.split("/").slice(-2).join("/");re(`${$.red} \u2716 Blocked file-scroll: "${pt}" \u2014 ${$e} sections already read. Use grep to find specific content.${$.reset}`),E.canExecute=!1,E.errorResult={role:"tool",content:`BLOCKED: read_file("${v}") denied \u2014 you have already read ${$e} different sections of this file (file-scroll pattern). You have seen most of this file. Use grep_search to find the exact lines you need instead of continuing to scroll.`,tool_call_id:E.callId}}else $e>=Ie&&(E._scrollWarn={sectionCount:$e+1,path:v})}}else if(J>=1){let j=v.split("/").slice(-2).join("/"),H=(os.get(v)||0)+1;os.set(v,H),H===1&&re(`${$.red} \u2716 Blocked unbounded re-read: "${j}" \u2014 already in context. Use line_start/line_end for specific sections.${$.reset}`),E.canExecute=!1,E.errorResult={role:"tool",content:`BLOCKED: read_file("${v}") denied \u2014 file already in context (read ${J}\xD7). Use line_start/line_end to read a specific section instead of the full file.`,tool_call_id:E.callId}}}for(let E of Pe)E.canExecute&&(E.fnName!=="ssh_exec"&&E.fnName!=="bash"||/\bsed\s+-n\b/.test(E.args?.command||"")&&(re(`${$.red} \u2716 Blocked sed -n: use grep -n "pattern" <file> | head -30 instead${$.reset}`),E.canExecute=!1,E.errorResult={role:"tool",content:'BLOCKED: sed -n is forbidden \u2014 it floods context with line ranges. Use grep -n "pattern" <file> | head -30 to read a specific section, or cat <file> for the full file.',tool_call_id:E.callId}));for(let E of Pe){if(!E.canExecute||E.fnName!=="write_file")continue;let v=E.args?.path,J=E.args?.content||"";if(v)try{let D=require("fs"),Y=require("path").resolve(process.cwd(),v);if(D.existsSync(Y)){let ce=D.statSync(Y).size,j=Buffer.byteLength(J,"utf8"),H=ce>0?j/ce:1;if(H<.6&&ce>200){let te=v.split("/").slice(-2).join("/");console.log(`${$.red} \u2716 write_file shrink guard: "${te}" would shrink to ${Math.round(H*100)}% of original \u2014 likely context loss${$.reset}`),E.canExecute=!1,E.errorResult={role:"tool",content:`BLOCKED: write_file("${v}") denied \u2014 new content is only ${Math.round(H*100)}% of current file size (${ce} \u2192 ${j} bytes). This looks like a partial rewrite after context loss. Use edit_file/patch_file to add only the new code, or read the file first to see full content before replacing.`,tool_call_id:E.callId}}}}catch{}}for(let E of Pe){if(!E.canExecute||E.fnName!=="grep")continue;let v=E.args?.path;if(!v)continue;let J=je.get(v)||0;if(J>=Jt){let D=v.split("/").slice(-2).join("/");re(`${$.red} \u2716 Blocked grep: "${D}" grepped ${J}\xD7 with different patterns \u2014 flood threshold exceeded${$.reset}`),E.canExecute=!1,E.errorResult={role:"tool",content:`BLOCKED: grep("${v}") denied \u2014 ${J} patterns already tried. Use existing results.`,tool_call_id:E.callId}}}if(rs){let E=Pe.filter(D=>D.canExecute&&D.fnName==="ssh_exec"),v=Pe.some(D=>D.canExecute&&D.fnName!=="ssh_exec"),J=ee&&pe<3;if(E.length>0&&!v&&J&&$r<1)rs=!1,$r++,Nt=Math.max(0,jr-2),re(`${$.dim} [dual-block deadlock: SSH storm relaxed \u2014 allowing 1 SSH call (relax ${$r}/1)]${$.reset}`);else for(let D of E)D.canExecute=!1,D.errorResult={role:"tool",content:`BLOCKED: ssh_exec denied \u2014 SSH storm (${jr}+ calls). Synthesize findings now.`,tool_call_id:D.callId}}if(ee&&pe<3){for(let E of Pe)if(E.canExecute&&["bash","read_file","find_files"].includes(E.fnName)){pe++;{let v=Je(),{messages:J}=jt(b,v);b=J}re(`${$.yellow} \u26A0 Jarvis-local guard: blocking local ${E.fnName} \u2014 use ssh_exec on 94.130.37.43${$.reset}`),E.canExecute=!1,E.errorResult={role:"tool",content:`BLOCKED: ${E.fnName} denied \u2014 this is a server issue. Use ssh_exec on 94.130.37.43 instead.`,tool_call_id:E.callId};break}}let ds=c?{skipSpinner:!0,skipSummaries:!0}:{},Wm=Pe.some(E=>E.fnName==="ask_user"),wc=!ds.skipSummaries&&!Ne,Kr=null;wc&&!Wm?(Ne=!0,ds.skipSpinner=!0,process.stdout.isTTY?(process.stdout.write(ka(Pe,X,!1,"blink")),Kr=!0):qt||process.stdout.write(ka(Pe,X,!1)+`
954
+ `)):wc&&(Ne=!0,ds.skipSpinner=!0),c&&c._paused&&c.resume();let{results:bc,summaries:Bm}=await g_(Pe,!0,{...ds,skipSummaries:!0});if(Kr&&(Kr=null,process.stdout.write(`\r\x1B[2K${ka(Pe,X,!1)}
955
+ `)),!ds.skipSummaries){let E=Bm.filter((D,Y)=>!(Pe[Y]&&Pe[Y].fnName==="ask_user"));for(let D of E)console.log(D);console.log("");let v=Pe.filter(D=>D&&D.fnName!=="ask_user").map(D=>D.fnName),J=se.record(0,v,U,M);J&&Xb(J)}for(let E of Pe){if(E.canExecute||!E.errorResult)continue;let v=typeof E.errorResult.content=="string"?E.errorResult.content:"";if((v.startsWith("BLOCKED:")||v.startsWith("PLAN MODE:"))&&(un++,un>=mc)){re(`${$.red} \u2716 Loop abort: ${un} consecutive blocked calls (pre-execution) \u2014 model not heeding BLOCKED messages${$.reset}`),c&&(c.stop(),c=null),i(null),We(X,S,M,U,K,{suppressHint:!0}),Ue(Q);return}}for(let E=0;E<Pe.length;E++){let v=Pe[E];if(!v.canExecute)continue;let J=bc[E].content,D=J.split(`
956
+ `)[0],Y=!D.startsWith("ERROR")&&!D.startsWith("CANCELLED")&&!D.startsWith("Command failed")&&!D.startsWith("EXIT");if(!Y&&(v.fnName==="edit_file"||v.fnName==="patch_file")&&v.args?.path&&D.includes("old_text not found")&&ss.set(v.args.path,!0),Y&&v.fnName==="write_file"&&v.args?.path){let j=v.args.path.split("/").pop(),H=v.args.path.includes("/tests/")||v.args.path.includes("\\tests\\");if(/^(test_|demo_|temp_|tmp_|scratch_)/.test(j)&&!H){re(`${$.yellow} \u26A0 Temp file: "${j}" \u2014 delete with bash rm when done to keep the workspace clean${$.reset}`);let ue={role:"user",content:`[HINT] "${v.args.path}" looks like a temporary test/demo file. Delete it with bash("rm ${v.args.path}") as soon as you're done \u2014 orphaned temp files count against session quality.`};Q.push(ue),b.push(ue)}}if(Y&&["write_file","edit_file","patch_file"].includes(v.fnName)&&v.args&&v.args.path){ss.delete(v.args.path),M.add(v.args.path);let j=(I.get(v.args.path)||0)+1;I.set(v.args.path,j);let H=v.args.path.split("/").slice(-2).join("/");if(j===W){re(`${$.yellow} \u26A0 Loop warning: "${H}" edited ${j}\xD7 \u2014 possible edit loop${$.reset}`);let te={role:"user",content:`[SYSTEM WARNING] "${v.args.path}" edited ${j}\xD7. One more edit max, then move on.`};Q.push(te),b.push(te)}else if(j>=oe){re(`${$.red} \u2716 Loop abort: "${H}" edited ${j}\xD7 \u2014 aborting to prevent runaway loop${$.reset}`),c&&(c.stop(),c=null),i(null),We(X,S,M,U,K,{suppressHint:!0}),Ue(Q);return}}if((v.fnName==="bash"||v.fnName==="ssh_exec")&&v.args&&v.args.command){let j=v.args.command.replace(/\d+/g,"N").replace(/\s+/g," ").trim().slice(0,100),H=(V.get(j)||0)+1;if(V.set(j,H),H===Z){re(`${$.yellow} \u26A0 Loop warning: same bash command run ${H}\xD7 \u2014 possible debug loop${$.reset}`);let te={role:"user",content:`[SYSTEM WARNING] Same bash command ${H}\xD7. Debug loop detected \u2014 try a different approach.`};Q.push(te),b.push(te)}else if(H>=ge){re(`${$.red} \u2716 Loop abort: same bash command run ${H}\xD7 \u2014 aborting runaway debug loop${$.reset}`),c&&(c.stop(),c=null),i(null),We(X,S,M,U,K,{suppressHint:!0}),Ue(Q);return}}if(v.fnName==="ssh_exec"){if(Nt++,Nt>=Um){re(`${$.red} \u2716 SSH storm abort: ${Nt} consecutive ssh_exec calls \u2014 aborting${$.reset}`),c&&(c.stop(),c=null),i(null),We(X,S,M,U,K,{suppressHint:!0}),Ue(Q);return}else if(Nt===jr){{let H=Je(),{messages:te}=jt(b,H);b=te}rs=!0,re(`${$.yellow} \u26A0 SSH storm warning: ${Nt} consecutive ssh_exec calls \u2014 blocking further SSH${$.reset}`);let j={role:"user",content:`[SYSTEM WARNING] ${Nt} consecutive SSH calls. Synthesize findings now \u2014 no more SSH.`};Q.push(j),b.push(j)}}else v.canExecute&&(Nt=0);if(Y&&v.fnName==="grep"&&v.args&&v.args.pattern){let j=`${v.args.pattern}|${v.args.path||""}`,H=(fe.get(j)||0)+1;if(fe.set(j,H),H===we){re(`${$.yellow} \u26A0 Loop warning: grep pattern "${v.args.pattern.slice(0,40)}" run ${H}\xD7 \u2014 possible search loop${$.reset}`);let te={role:"user",content:`[SYSTEM WARNING] Same grep pattern ${H}\xD7. Results unchanged \u2014 use existing data or try different pattern.`};Q.push(te),b.push(te)}else if(H>=be){re(`${$.red} \u2716 Loop abort: grep pattern run ${H}\xD7 \u2014 aborting runaway search loop${$.reset}`),c&&(c.stop(),c=null),i(null),We(X,S,M,U,K,{suppressHint:!0}),Ue(Q);return}if(v.args.path){let te=(je.get(v.args.path)||0)+1;if(je.set(v.args.path,te),te===Ge){let ue=v.args.path.split("/").slice(-2).join("/");re(`${$.yellow} \u26A0 Loop warning: "${ue}" grepped ${te}\xD7 with different patterns \u2014 context flood risk${$.reset}`);let $e={role:"user",content:`[SYSTEM WARNING] "${v.args.path}" grepped ${te}\xD7 \u2014 file already in context. Use existing data, stop searching.`};Q.push($e),b.push($e)}}}if(Y&&(v.fnName==="bash"||v.fnName==="ssh_exec")&&J.includes('"valid":true')){{let H=Je();if(Ot(b,H).percentage>=60){let{messages:ue,tokensRemoved:$e}=jt(b,H);$e>0&&(b=ue,console.log(`${$.dim} [pre-stop-compress \u2014 ~${$e} tokens freed before STOP injection, now ${Math.round(Ot(b,H).percentage)}%]${$.reset}`))}}let j={role:"user",content:'[SYSTEM STOP] Tool result contains {"valid":true}. The token/service is valid and reachable. STOP all further investigation immediately. Report to the user that the token is valid, the service is healthy, and no fix is needed. Do NOT read any more log files.'};Q.push(j),b.push(j),console.log(`${$.cyan} \u2713 Health-check stop signal detected \u2014 injecting STOP instruction${$.reset}`)}if(J.startsWith("BLOCKED:")){if(un++,un>=mc){re(`${$.red} \u2716 Loop abort: ${un} consecutive blocked calls \u2014 model not heeding BLOCKED messages${$.reset}`),c&&(c.stop(),c=null),i(null),We(X,S,M,U,K,{suppressHint:!0}),Ue(Q);return}}else un=0;if(Y)ln=0,Fr=!0;else if(ln++,ln===Dm){re(`${$.yellow} \u26A0 Loop warning: ${ln} consecutive tool errors \u2014 possible stuck loop${$.reset}`);let j={role:"user",content:`[SYSTEM WARNING] ${ln} consecutive errors. Stuck loop \u2014 try fundamentally different approach or declare done.`};Q.push(j),b.push(j)}else if(ln>=jm){re(`${$.red} \u2716 Loop abort: ${ln} consecutive errors \u2014 aborting stuck loop${$.reset}`),c&&(c.stop(),c=null),i(null),We(X,S,M,U,K,{suppressHint:!0}),Ue(Q);return}if(Y&&v.fnName==="read_file"&&v.args&&v.args.path){U.add(v.args.path);let j=(Nn.get(v.args.path)||0)+1;if(Nn.set(v.args.path,j),v.args.line_start!=null){let ue=v.args.line_start||1,$e=v.args.line_end||ue+350;Gs.has(v.args.path)||Gs.set(v.args.path,[]),Gs.get(v.args.path).push([ue,$e])}if(v._scrollWarn){let{sectionCount:ue,path:$e}=v._scrollWarn,Ie={role:"user",content:`[SYSTEM WARNING] "${$e}" \u2014 you have now read ${ue} different sections of this file. This is a file-scroll pattern. Stop reading sections and use grep_search to find the specific lines you need instead.`};Q.push(Ie),b.push(Ie),re(`${$.yellow} \u26A0 Scroll warning: "${$e.split("/").slice(-2).join("/")}" \u2014 ${ue} sections read \u2014 use grep instead${$.reset}`)}let H=v.args.path.split("/").slice(-2).join("/"),te=!v.args?.line_start&&!v.args?.line_end;if(te&&j===Lr){{let $e=Je();if(Ot(b,$e).percentage>=60){let{messages:de}=jt(b,$e);b=de}}re(`${$.yellow} \u26A0 Loop warning: "${H}" read unbounded ${j}\xD7 \u2014 use line_start/line_end${$.reset}`);let ue={role:"user",content:`[SYSTEM WARNING] "${v.args.path}" read ${j}\xD7 without line ranges. Use line_start/line_end to read specific sections \u2014 do not re-read the full file.`};Q.push(ue),b.push(ue)}else if(te&&j>=Lm){re(`${$.red} \u2716 Loop abort: "${H}" read unbounded ${j}\xD7 \u2014 aborting runaway read loop${$.reset}`),c&&(c.stop(),c=null),i(null),We(X,S,M,U,K,{suppressHint:!0}),Ue(Q);return}}if(v.fnName==="spawn_agents"){let j=(J.match(/\bStatus: done\b/g)||[]).length;if((J.match(/\bStatus: truncated\b/g)||[]).length>0&&j===0){if(dn++,dn===qm){re(`${$.yellow} \u26A0 Swarm warning: all sub-agents hit iteration limit ${dn}\xD7 in a row${$.reset}`);let te={role:"user",content:`[SYSTEM WARNING] Sub-agents truncated ${dn}\xD7 in a row. Stop spawning \u2014 try different approach or report findings.`};Q.push(te),b.push(te)}else if(dn>=Fm){console.log(`${$.red} \u2716 Swarm abort: all sub-agents hit iteration limit ${dn}\xD7 \u2014 aborting stuck swarm${$.reset}`),c&&(c.stop(),c=null),i(null),We(X,S,M,U,K,{suppressHint:!0}),Ue(Q);return}}else j>0&&(dn=0)}}for(let E of bc)Q.push(E),b.push(E);{let E=Je();if(Ot(b,E).percentage>=78){let{messages:J,tokensRemoved:D}=jt(b,E);D>0&&(b=J,console.log(`${$.dim} [auto-compressed \u2014 ~${D} tokens freed, now ${Math.round(Ot(b,E).percentage)}%]${$.reset}`))}}let _c=y_();if(_c){let E={role:"user",content:`[User note mid-run]: ${_c}`};Q.push(E),b.push(E),console.log(`${$.cyan} \u270E Context added${$.reset}`)}}if(dt>=io){c&&(c.stop(),c=null),i(null),We(X,S,M,U,K),Ue(Q),Bf(Q);let{getActiveProviderName:qe}=Te();if(qe()==="ollama"&&qr<hc){if(M.size===0&&!Fr){console.log(`${$.yellow} \u26A0 Max iterations reached with no progress. Stopping.${$.reset}`);break e}qr++,io=20,console.log(`${$.dim} \u2500\u2500 auto-extending (+20 turns, ext ${qr}/${hc}) \u2500\u2500${$.reset}`);continue e}if(console.log(`
957
957
  ${$.yellow}\u26A0 Max iterations reached.${$.reset}`),await ep(" Continue for 20 more turns?")){io=20;continue e}console.log(`${$.dim} Tip: set "maxIterations" in .nex/config.json or use --max-turns${$.reset}`)}break e}}dp.exports={processInput:C_,clearConversation:__,getConversationLength:k_,getConversationMessages:v_,setConversationMessages:S_,setAbortSignalGetter:e_,setMaxIterations:Zb,invalidateSystemPromptCache:Ma,clearToolFilterCache:c_,getCachedFilteredTools:op,buildSystemPrompt:lp,getProjectContextHash:rp,buildUserContent:sp,detectAndTruncateLoop:Aa,injectMidRunNote:$_,resetSessionTracking:up}});var Te=G((Qv,gp)=>{var{OllamaProvider:A_}=Kc(),{OpenAIProvider:O_}=dl(),{AnthropicProvider:N_}=hl(),{GeminiProvider:M_}=wl(),{LocalProvider:P_}=xl(),{checkBudget:I_}=Un(),qa={top:{ollama:"kimi-k2:1t",openai:"gpt-4.1",anthropic:"claude-sonnet-4-5",gemini:"gemini-2.5-pro"},strong:{ollama:"qwen3-coder:480b",openai:"gpt-4o",anthropic:"claude-sonnet",gemini:"gemini-2.5-flash"},fast:{ollama:"devstral-small-2:24b",openai:"gpt-4.1-mini",anthropic:"claude-haiku",gemini:"gemini-2.0-flash"}},fp={};for(let[t,e]of Object.entries(qa))for(let n of Object.values(e))fp[n]=t;function pp(t,e){let n=fp[t];return n&&qa[n][e]||t}var Ye={},ut=null,Be=null,zs=[];function vt(){if(Object.keys(Ye).length>0)return;is("ollama",new A_),is("openai",new O_),is("anthropic",new N_),is("gemini",new M_),is("local",new P_);let t=process.env.DEFAULT_PROVIDER||"ollama",e=process.env.DEFAULT_MODEL||null;Ye[t]?(ut=t,Be=e||Ye[t].defaultModel):(ut="ollama",Be="kimi-k2.5");let n=process.env.FALLBACK_CHAIN;n&&(zs=n.split(",").map(o=>o.trim()).filter(Boolean))}function is(t,e){Ye[t]=e}function L_(t){return vt(),Ye[t]||null}function Fa(){return vt(),Ye[ut]||null}function D_(){return vt(),ut}function j_(){return vt(),Be}function q_(){vt();let t=Fa();if(!t)return{id:Be,name:Be,provider:ut};let e=t.getModel(Be);return e?{...e,provider:ut}:{id:Be,name:Be,provider:ut}}function mp(t){if(!t)return{provider:null,model:null};let e=t.indexOf(":");if(e>0){let n=t.slice(0,e);if(Ye[n]||["ollama","openai","anthropic","gemini","local"].includes(n))return{provider:n,model:t.slice(e+1)}}return{provider:null,model:t}}function F_(t){vt();let{provider:e,model:n}=mp(t);if(e){let s=Ye[e];return s&&(s.getModel(n)||e==="local"||e==="ollama")?(ut=e,Be=n,br(),!0):!1}let o=Fa();if(o&&o.getModel(n))return Be=n,br(),!0;for(let[s,r]of Object.entries(Ye))if(r.getModel(n))return ut=s,Be=n,br(),!0;return!1}function br(){try{let{invalidateSystemPromptCache:t,clearToolFilterCache:e}=ve();t(),e()}catch{}try{let{invalidateTokenRatioCache:t}=Qe();t()}catch{}}function U_(){vt();let t=new Set;for(let e of Object.values(Ye))for(let n of e.getModelNames())t.add(n);return Array.from(t)}function W_(){return vt(),Object.entries(Ye).map(([t,e])=>({provider:t,configured:e.isConfigured(),models:Object.values(e.getModels()).map(n=>({...n,active:t===ut&&n.id===Be}))}))}function B_(){vt();let t=[];for(let[e,n]of Object.entries(Ye)){let o=n.isConfigured();for(let s of Object.values(n.getModels()))t.push({spec:`${e}:${s.id}`,name:s.name,provider:e,configured:o})}return t}function H_(t){zs=Array.isArray(t)?t:[]}function G_(){return[...zs]}function K_(t){let e=t.message||"",n=t.code||"";return!!(e.includes("429")||e.includes("500")||e.includes("502")||e.includes("503")||e.includes("504")||n==="ECONNABORTED"||n==="ETIMEDOUT"||n==="ECONNREFUSED"||n==="ECONNRESET"||n==="EHOSTUNREACH"||n==="ENETUNREACH"||n==="EPIPE"||n==="ERR_SOCKET_CONNECTION_TIMEOUT"||e.includes("socket disconnected")||e.includes("TLS")||e.includes("ECONNRESET")||e.includes("ECONNABORTED")||e.includes("network")||e.includes("ETIMEDOUT"))}async function hp(t){let e=[ut,...zs.filter(r=>r!==ut)],n,o=0,s=0;for(let r=0;r<e.length;r++){let i=e[r],c=Ye[i];if(!c||!c.isConfigured())continue;s++;let l=I_(i);if(!l.allowed){o++,n=new Error(`Budget limit reached for ${i}: $${l.spent.toFixed(2)} / $${l.limit.toFixed(2)}`);continue}try{let u=r>0,d=u?pp(Be,i):Be;return u&&d!==Be&&process.stderr.write(` [fallback: ${i}:${d}]
958
958
  `),await t(c,i,d)}catch(u){if(n=u,K_(u)&&r<e.length-1)continue;throw u}}throw o>0&&o===s?new Error("All providers are over budget. Use /budget to check limits or /budget <provider> off to remove a limit."):s===0?new Error("No configured provider available"):n||new Error("No configured provider available")}async function Y_(t,e,n={}){return vt(),hp((o,s,r)=>o.stream(t,e,{model:r,signal:n.signal,...n}))}async function z_(t,e,n={}){if(vt(),n.provider){let o=Ye[n.provider];if(!o||!o.isConfigured())throw new Error(`Provider '${n.provider}' is not available`);let s={model:n.model||Be,...n};try{return await o.chat(t,e,s)}catch(r){if(typeof o.stream=="function")try{return await o.stream(t,e,{...s,onToken:()=>{}})}catch{}throw r}}return hp(async(o,s,r)=>{try{return await o.chat(t,e,{model:r,...n})}catch(i){if(typeof o.stream=="function")try{return await o.stream(t,e,{model:r,...n,onToken:()=>{}})}catch{}throw i}})}function X_(){vt();let t=[];for(let[e,n]of Object.entries(Ye))n.isConfigured()&&t.push({name:e,models:Object.values(n.getModels())});return t}function J_(){for(let t of Object.keys(Ye))delete Ye[t];ut=null,Be=null,zs=[]}gp.exports={registerProvider:is,getProvider:L_,getActiveProvider:Fa,getActiveProviderName:D_,getActiveModelId:j_,getActiveModel:q_,setActiveModel:F_,getModelNames:U_,parseModelSpec:mp,listProviders:W_,listAllModels:B_,callStream:Y_,callChat:z_,getConfiguredProviders:X_,setFallbackChain:H_,getFallbackChain:G_,resolveModelForProvider:pp,MODEL_EQUIVALENTS:qa,_reset:J_}});var Wa=G((Zv,$p)=>{"use strict";var Yt=require("fs"),_r=require("path"),V_=require("readline"),ye="\x1B[0m",xr="\x1B[1m",Ve="\x1B[2m",kr="\x1B[33m",Ua="\x1B[36m",Xs="\x1B[32m";function Q_(t){return(e,n="")=>new Promise(o=>{let s=n?` ${Ve}[${n}]${ye}`:"";t.question(` ${Ua}${e}${s}${ye}: `,r=>o(r.trim()||n))})}function Js(t,e){return new Promise(n=>{e&&e.pause(),process.stdout.write(` ${Ua}${t}${ye}: `);let o=process.stdin,s=o.isRaw,r="";o.setRawMode(!0),o.resume(),o.setEncoding("utf8");let i=c=>{c==="\r"||c===`
959
959
  `?(o.setRawMode(s||!1),o.removeListener("data",i),process.stdout.write(`
@@ -1068,28 +1068,28 @@ ${n}`}];try{let i=((await Rp(o,[],{temperature:0,maxTokens:2e3})).content||"").t
1068
1068
  ${i.content}`;n(c,l.content+d),s.push({name:c,reason:i.reason||"",action:"updated"})}else n(c,i.content),s.push({name:c,reason:i.reason||"",action:"created"})}return{written:s,skipped:r}}Pp.exports={learnFromSession:$x,learnBrainFromSession:wx,reflectOnSession:Ap,reflectBrain:Mp,applyMemories:Op,applyNexAdditions:Np,LEARN_MIN_MESSAGES:Ha}});var Fp=G((rS,qp)=>{var{spawn:bx}=require("child_process"),Ip=require("path"),Lp=require("fs"),_x=require("os"),cn=new Map;function Dp(t){return typeof t!="string"?t:t.replace(/\$\{([^}]+)\}/g,(e,n)=>process.env[n]!==void 0?process.env[n]:"")}function jp(t){let e=t||process.env.NEX_MCP_CONFIG||null,n=e?[e]:[Ip.join(process.cwd(),".nex","mcp.json"),Ip.join(_x.homedir(),".nex","mcp.json")];for(let o of n)if(Lp.existsSync(o))try{return JSON.parse(Lp.readFileSync(o,"utf-8"))}catch{}return{servers:{}}}function Sr(t,e,n={},o=1e4){return new Promise((s,r)=>{let i=`${Date.now()}-${Math.random().toString(36).slice(2,6)}`,c=JSON.stringify({jsonrpc:"2.0",id:i,method:e,params:n})+`
1069
1069
  `,l="",u=setTimeout(()=>{f(),r(new Error(`MCP request timeout: ${e}`))},o);function d(m){l+=m.toString();let h=l.split(`
1070
1070
  `);for(let p of h)if(p.trim())try{let g=JSON.parse(p);if(g.id===i){f(),g.error?r(new Error(`MCP error: ${g.error.message||JSON.stringify(g.error)}`)):s(g.result);return}}catch{}l=h[h.length-1]||""}function f(){clearTimeout(u),t.stdout.removeListener("data",d)}t.stdout.on("data",d);try{t.stdin.write(c)}catch(m){f(),r(new Error(`MCP write failed: ${m.message}`))}})}async function xx(t){let n=jp(t).servers||{},o=[];for(let[s,r]of Object.entries(n)){if(cn.has(s)){let d=cn.get(s);o.push({name:s,tools:d.tools.length});continue}let i={};for(let[d,f]of Object.entries(r.env||{}))i[d]=Dp(f);let c=["PATH","HOME","USER","SHELL","LANG","TERM","NODE_ENV"],l={};for(let d of c)process.env[d]!==void 0&&(l[d]=process.env[d]);let u;try{u=bx(r.command,r.args||[],{stdio:["pipe","pipe","pipe"],env:{...l,...i}})}catch(d){console.warn(`[mcp-client] Failed to spawn '${s}': ${d.message}`),o.push({name:s,tools:0,error:d.message});continue}try{await Sr(u,"initialize",{protocolVersion:"2024-11-05",capabilities:{},clientInfo:{name:"nex-code",version:"0.4.8"}});let d=await Sr(u,"tools/list",{}),f=d&&d.tools||[];cn.set(s,{name:s,proc:u,tools:f,config:r}),o.push({name:s,tools:f.length})}catch(d){console.warn(`[mcp-client] Server '${s}' failed to initialize: ${d.message}`);try{u.kill()}catch{}o.push({name:s,tools:0,error:d.message})}}return o}async function kx(t,e,n={}){let o=cn.get(t);if(!o)throw new Error(`MCP server not connected: ${t}`);let s=await Sr(o.proc,"tools/call",{name:e,arguments:n});return s&&Array.isArray(s.content)?s.content.filter(r=>r.type==="text").map(r=>r.text).join(`
1071
- `):JSON.stringify(s)}function vx(){let t=[];for(let[e,n]of cn)for(let o of n.tools)t.push({type:"function",function:{name:`mcp_${e}_${o.name}`,description:`[MCP:${e}] ${o.description||""}`,parameters:o.inputSchema||{type:"object",properties:{}}}});return t}function Sx(){for(let[t,e]of cn){try{e.proc.kill()}catch{}cn.delete(t)}}function Ex(){let t=[];for(let[e,n]of cn)t.push({name:e,connected:!0,toolCount:n.tools.length});return t}qp.exports={loadMcpServers:xx,callMcpTool:kx,getMcpTools:vx,shutdownMcpServers:Sx,listMcpServers:Ex,_interpolateEnv:Dp,_readConfig:jp,_sendRequest:Sr}});var Hp=G((aS,Bp)=>{var tt=require("fs"),ls=require("path"),iS=require("os"),Tx=require("readline"),{C:Y}=Oe(),Up=".nex",Ka=null;function Rx(t){Ka=t}function nt(t,e=""){let n=e?` ${Y.dim}[${e}]${Y.reset}`:"",o=` ${Y.cyan}${t}${n}${Y.reset}: `;return new Promise(s=>{let r=i=>{let c=i.trim()||e;s(c)};if(Ka)Ka.question(o,r);else{let i=Tx.createInterface({input:process.stdin,output:process.stdout});i.question(o,c=>{i.close(),r(c)})}})}function cs(t,e=!0){return nt(`${t} (${e?"Y/n":"y/N"})`,e?"y":"n").then(o=>o.toLowerCase()!=="n"&&o.toLowerCase()!=="no")}async function Ya(t,e,n){let o=e.map((c,l)=>`${Y.dim}${l+1})${Y.reset} ${c}`).join(" ");console.log(` ${Y.cyan}${t}${Y.reset}`),console.log(` ${o}`);let s=n?e.indexOf(n)+1:1,r=await nt("Enter number",String(s)),i=parseInt(r,10)-1;return e[Math.max(0,Math.min(i,e.length-1))]}async function Cx(){let t=ls.join(process.cwd(),Up),e=ls.join(t,"servers.json"),n={};if(tt.existsSync(e))try{n=JSON.parse(tt.readFileSync(e,"utf-8"))}catch{}console.log(`
1072
- ${Y.bold}${Y.cyan}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557${Y.reset}`),console.log(`${Y.bold}${Y.cyan}\u2551 nex-code Server Setup Wizard \u2551${Y.reset}`),console.log(`${Y.bold}${Y.cyan}\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D${Y.reset}
1073
- `);let o=Object.keys(n);if(o.length>0&&(console.log(`${Y.dim}Existing profiles: ${o.join(", ")}${Y.reset}`),!await cs("Add or update a server profile?",!0))){console.log(`${Y.dim}No changes made.${Y.reset}
1071
+ `):JSON.stringify(s)}function vx(){let t=[];for(let[e,n]of cn)for(let o of n.tools)t.push({type:"function",function:{name:`mcp_${e}_${o.name}`,description:`[MCP:${e}] ${o.description||""}`,parameters:o.inputSchema||{type:"object",properties:{}}}});return t}function Sx(){for(let[t,e]of cn){try{e.proc.kill()}catch{}cn.delete(t)}}function Ex(){let t=[];for(let[e,n]of cn)t.push({name:e,connected:!0,toolCount:n.tools.length});return t}qp.exports={loadMcpServers:xx,callMcpTool:kx,getMcpTools:vx,shutdownMcpServers:Sx,listMcpServers:Ex,_interpolateEnv:Dp,_readConfig:jp,_sendRequest:Sr}});var Hp=G((aS,Bp)=>{var tt=require("fs"),ls=require("path"),iS=require("os"),Tx=require("readline"),{C:z}=Oe(),Up=".nex",Ka=null;function Rx(t){Ka=t}function nt(t,e=""){let n=e?` ${z.dim}[${e}]${z.reset}`:"",o=` ${z.cyan}${t}${n}${z.reset}: `;return new Promise(s=>{let r=i=>{let c=i.trim()||e;s(c)};if(Ka)Ka.question(o,r);else{let i=Tx.createInterface({input:process.stdin,output:process.stdout});i.question(o,c=>{i.close(),r(c)})}})}function cs(t,e=!0){return nt(`${t} (${e?"Y/n":"y/N"})`,e?"y":"n").then(o=>o.toLowerCase()!=="n"&&o.toLowerCase()!=="no")}async function Ya(t,e,n){let o=e.map((c,l)=>`${z.dim}${l+1})${z.reset} ${c}`).join(" ");console.log(` ${z.cyan}${t}${z.reset}`),console.log(` ${o}`);let s=n?e.indexOf(n)+1:1,r=await nt("Enter number",String(s)),i=parseInt(r,10)-1;return e[Math.max(0,Math.min(i,e.length-1))]}async function Cx(){let t=ls.join(process.cwd(),Up),e=ls.join(t,"servers.json"),n={};if(tt.existsSync(e))try{n=JSON.parse(tt.readFileSync(e,"utf-8"))}catch{}console.log(`
1072
+ ${z.bold}${z.cyan}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557${z.reset}`),console.log(`${z.bold}${z.cyan}\u2551 nex-code Server Setup Wizard \u2551${z.reset}`),console.log(`${z.bold}${z.cyan}\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D${z.reset}
1073
+ `);let o=Object.keys(n);if(o.length>0&&(console.log(`${z.dim}Existing profiles: ${o.join(", ")}${z.reset}`),!await cs("Add or update a server profile?",!0))){console.log(`${z.dim}No changes made.${z.reset}
1074
1074
  `);return}let s={...n},r=!0;for(;r;){console.log(`
1075
- ${Y.bold}\u2500\u2500\u2500 New Server Profile \u2500\u2500\u2500${Y.reset}`);let l=await nt("Profile name (e.g. prod, staging, macbook)");if(!l){console.log(`${Y.red} Name is required.${Y.reset}`);continue}let u=await nt("Host / IP address");if(!u){console.log(`${Y.red} Host is required.${Y.reset}`);continue}let d=await nt("SSH user","root"),f=await nt("SSH port","22"),m=parseInt(f,10)||22,h=await nt("SSH key path (leave empty for SSH agent)",""),p=await Ya("Operating system",["almalinux9","macos","ubuntu","debian","other"],"almalinux9"),g=await cs("Allow sudo commands?",!0),y={host:u,user:d};m!==22&&(y.port=m),h&&(y.key=h),p!=="other"&&(y.os=p),g&&(y.sudo=!0),s[l]=y,console.log(`
1076
- ${Y.green}\u2713${Y.reset} Profile "${l}" added: ${d}@${u}${m!==22?`:${m}`:""}${p!=="other"?` [${p}]`:""}`),r=await cs(`
1075
+ ${z.bold}\u2500\u2500\u2500 New Server Profile \u2500\u2500\u2500${z.reset}`);let l=await nt("Profile name (e.g. prod, staging, macbook)");if(!l){console.log(`${z.red} Name is required.${z.reset}`);continue}let u=await nt("Host / IP address");if(!u){console.log(`${z.red} Host is required.${z.reset}`);continue}let d=await nt("SSH user","root"),f=await nt("SSH port","22"),m=parseInt(f,10)||22,h=await nt("SSH key path (leave empty for SSH agent)",""),p=await Ya("Operating system",["almalinux9","macos","ubuntu","debian","other"],"almalinux9"),g=await cs("Allow sudo commands?",!0),y={host:u,user:d};m!==22&&(y.port=m),h&&(y.key=h),p!=="other"&&(y.os=p),g&&(y.sudo=!0),s[l]=y,console.log(`
1076
+ ${z.green}\u2713${z.reset} Profile "${l}" added: ${d}@${u}${m!==22?`:${m}`:""}${p!=="other"?` [${p}]`:""}`),r=await cs(`
1077
1077
  Add another server?`,!1)}tt.existsSync(t)||tt.mkdirSync(t,{recursive:!0}),tt.writeFileSync(e,JSON.stringify(s,null,2)+`
1078
1078
  `,"utf-8"),console.log(`
1079
- ${Y.green}\u2713 Saved .nex/servers.json (${Object.keys(s).length} profile${Object.keys(s).length!==1?"s":""})${Y.reset}`);let i=ls.join(process.cwd(),".gitignore");tt.existsSync(i)&&(tt.readFileSync(i,"utf-8").includes(".nex/")||await cs("Add .nex/ to .gitignore?",!0)&&(tt.appendFileSync(i,`
1079
+ ${z.green}\u2713 Saved .nex/servers.json (${Object.keys(s).length} profile${Object.keys(s).length!==1?"s":""})${z.reset}`);let i=ls.join(process.cwd(),".gitignore");tt.existsSync(i)&&(tt.readFileSync(i,"utf-8").includes(".nex/")||await cs("Add .nex/ to .gitignore?",!0)&&(tt.appendFileSync(i,`
1080
1080
  # nex-code server profiles
1081
1081
  .nex/
1082
- `),console.log(`${Y.green}\u2713 Added .nex/ to .gitignore${Y.reset}`))),await cs(`
1082
+ `),console.log(`${z.green}\u2713 Added .nex/ to .gitignore${z.reset}`))),await cs(`
1083
1083
  Set up deploy configs (.nex/deploy.json)?`,!1)&&await Wp(s,t),console.log(`
1084
- ${Y.dim}Use /servers to list profiles, /servers ping to check connectivity.${Y.reset}
1084
+ ${z.dim}Use /servers to list profiles, /servers ping to check connectivity.${z.reset}
1085
1085
  `)}async function Wp(t,e){let n=e||ls.join(process.cwd(),Up),o=ls.join(n,"deploy.json"),s={};if(tt.existsSync(o))try{s=JSON.parse(tt.readFileSync(o,"utf-8"))}catch{}if(!t){let u=ls.join(n,"servers.json");if(tt.existsSync(u))try{t=JSON.parse(tt.readFileSync(u,"utf-8"))}catch{t={}}else t={}}let r=Object.keys(t);console.log(`
1086
- ${Y.bold}${Y.cyan}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557${Y.reset}`),console.log(`${Y.bold}${Y.cyan}\u2551 Deploy Config Wizard \u2551${Y.reset}`),console.log(`${Y.bold}${Y.cyan}\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D${Y.reset}
1087
- `);let i=Object.keys(s);i.length>0&&console.log(`${Y.dim}Existing deploy configs: ${i.join(", ")}${Y.reset}`);let c={...s},l=!0;for(;l;){console.log(`
1088
- ${Y.bold}\u2500\u2500\u2500 New Deploy Config \u2500\u2500\u2500${Y.reset}`);let u=await nt("Config name (e.g. prod, staging)");if(!u){console.log(`${Y.red} Name is required.${Y.reset}`);continue}let d;r.length>0?d=await Ya("Target server",r,r[0]):d=await nt("Target server (profile name or user@host)");let f=await Ya("Deploy method",["rsync","git"],"rsync"),m="",h=[],p="";if(f==="rsync"){m=await nt("Local path to sync (e.g. dist/ or ./build)","dist/");let x=await nt("Exclude paths (comma-separated, e.g. node_modules,.env)","node_modules,.env");h=x?x.split(",").map(_=>_.trim()).filter(Boolean):[]}else p=await nt("Branch to pull (leave empty for current remote branch)","main");let g=await nt(f==="git"?"Remote repo path (e.g. /home/jarvis/my-app)":"Remote destination path (e.g. /var/www/app)");if(!g){console.log(`${Y.red} Remote path is required.${Y.reset}`);continue}let y=await nt("Command to run on remote after deploy (leave empty to skip)",""),w=await nt("Health check URL or remote command (leave empty to skip)",""),k={server:d,method:f,remote_path:g};f==="rsync"?(k.local_path=m,h.length>0&&(k.exclude=h)):p&&(k.branch=p),y&&(k.deploy_script=y),w&&(k.health_check=w),c[u]=k;let R=f==="git"?`${d}:${g}${p?` (${p})`:""}`:`${m.endsWith("/")?m:m+"/"} \u2192 ${d}:${g}`;console.log(`
1089
- ${Y.green}\u2713${Y.reset} Deploy config "${u}": [${f}] ${R}`),y&&console.log(` ${Y.dim} Then: ${y}${Y.reset}`),w&&console.log(` ${Y.dim} Health: ${w}${Y.reset}`),l=await cs(`
1086
+ ${z.bold}${z.cyan}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557${z.reset}`),console.log(`${z.bold}${z.cyan}\u2551 Deploy Config Wizard \u2551${z.reset}`),console.log(`${z.bold}${z.cyan}\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D${z.reset}
1087
+ `);let i=Object.keys(s);i.length>0&&console.log(`${z.dim}Existing deploy configs: ${i.join(", ")}${z.reset}`);let c={...s},l=!0;for(;l;){console.log(`
1088
+ ${z.bold}\u2500\u2500\u2500 New Deploy Config \u2500\u2500\u2500${z.reset}`);let u=await nt("Config name (e.g. prod, staging)");if(!u){console.log(`${z.red} Name is required.${z.reset}`);continue}let d;r.length>0?d=await Ya("Target server",r,r[0]):d=await nt("Target server (profile name or user@host)");let f=await Ya("Deploy method",["rsync","git"],"rsync"),m="",h=[],p="";if(f==="rsync"){m=await nt("Local path to sync (e.g. dist/ or ./build)","dist/");let x=await nt("Exclude paths (comma-separated, e.g. node_modules,.env)","node_modules,.env");h=x?x.split(",").map(_=>_.trim()).filter(Boolean):[]}else p=await nt("Branch to pull (leave empty for current remote branch)","main");let g=await nt(f==="git"?"Remote repo path (e.g. /home/jarvis/my-app)":"Remote destination path (e.g. /var/www/app)");if(!g){console.log(`${z.red} Remote path is required.${z.reset}`);continue}let y=await nt("Command to run on remote after deploy (leave empty to skip)",""),w=await nt("Health check URL or remote command (leave empty to skip)",""),k={server:d,method:f,remote_path:g};f==="rsync"?(k.local_path=m,h.length>0&&(k.exclude=h)):p&&(k.branch=p),y&&(k.deploy_script=y),w&&(k.health_check=w),c[u]=k;let R=f==="git"?`${d}:${g}${p?` (${p})`:""}`:`${m.endsWith("/")?m:m+"/"} \u2192 ${d}:${g}`;console.log(`
1089
+ ${z.green}\u2713${z.reset} Deploy config "${u}": [${f}] ${R}`),y&&console.log(` ${z.dim} Then: ${y}${z.reset}`),w&&console.log(` ${z.dim} Health: ${w}${z.reset}`),l=await cs(`
1090
1090
  Add another deploy config?`,!1)}tt.existsSync(n)||tt.mkdirSync(n,{recursive:!0}),tt.writeFileSync(o,JSON.stringify(c,null,2)+`
1091
1091
  `,"utf-8"),console.log(`
1092
- ${Y.green}\u2713 Saved .nex/deploy.json (${Object.keys(c).length} config${Object.keys(c).length!==1?"s":""})${Y.reset}`),console.log(`${Y.dim}Use: deploy prod (or with explicit params)${Y.reset}
1092
+ ${z.green}\u2713 Saved .nex/deploy.json (${Object.keys(c).length} config${Object.keys(c).length!==1?"s":""})${z.reset}`),console.log(`${z.dim}Use: deploy prod (or with explicit params)${z.reset}
1093
1093
  `)}Bp.exports={runServerWizard:Cx,runDeployWizard:Wp,setWizardRL:Rx}});var za=G((cS,zp)=>{"use strict";var Ax=require("os"),Gp=require("path"),Vs=require("fs"),Qs=Gp.join(Ax.homedir(),".nex-code","model-routing.json"),Er={frontend:{id:"frontend",label:"Frontend",icon:"\u2B21",envVar:"NEX_ROUTE_FRONTEND",pattern:/\b(react|vue|angular|svelte|jsx|tsx|html|css|scss|sass|tailwind|bootstrap|component|dom\b|ui\s|button|modal|navbar|sidebar|stylesheet|responsive|flexbox|grid|animation|frontend|front.end|onclick|hover|transition|web\s+design|landing\s+page|browser\s+event)\b/i},sysadmin:{id:"sysadmin",label:"Sysadmin",icon:"\u2699",envVar:"NEX_ROUTE_SYSADMIN",pattern:/\b(nginx|apache|docker|kubernetes|k8s|systemd|systemctl|deploy(ment)?|server\s+config|firewall|iptables\b|ssh\s+key|cron(job)?|ansible|terraform|ci\/cd|pipeline|container\b|pod\b|apt\s+install|yum\s+install|daemon|pm2|supervisor|logrotate|ssl\s+cert|lets.encrypt|reverse\s+proxy|load\s+balanc|haproxy|vhost|virtual\s+host)\b/i},data:{id:"data",label:"Data",icon:"\u2B21",envVar:"NEX_ROUTE_DATA",pattern:/\b(sql\b|mysql|postgres(ql)?|sqlite|mongodb|redis\b|query\b|database|db\s+migration|schema\s+change|table\s+join|aggregate\b|pandas\b|dataframe|\.csv\b|etl\b|data\s+transform|data\s+pipeline|analytics|data\s+warehouse|dbt\b|orm\b|knex|sequelize|prisma\s+schema)\b/i},agentic:{id:"agentic",label:"Agentic",icon:"\u2B21",envVar:"NEX_ROUTE_AGENTIC",pattern:/\b(spawn\s+agent|agent\s+swarm|multi.?agent|parallel\s+agent|orchestrat|coordinate\s+multiple\s+agent|delegate.+agent|sub.?agent|architect.*coder)\b/i},coding:{id:"coding",label:"Coding",icon:"\u2B21",envVar:"NEX_ROUTE_CODING",pattern:null}},Kp=["agentic","frontend","sysadmin","data","coding"];function Ox(t){if(!t||t.length<8)return null;for(let e of Kp){let n=Er[e];if(!n.pattern||n.pattern.test(t))return n}return Er.coding}function Yp(){try{if(Vs.existsSync(Qs))return JSON.parse(Vs.readFileSync(Qs,"utf-8"))}catch{}return{}}function Nx(t){let e=Er[t];return e?.envVar&&process.env[e.envVar]?process.env[e.envVar]:Yp()[t]||null}function Mx(t){let e=Gp.dirname(Qs);Vs.existsSync(e)||Vs.mkdirSync(e,{recursive:!0}),Vs.writeFileSync(Qs,JSON.stringify(t,null,2))}zp.exports={CATEGORIES:Er,DETECTION_ORDER:Kp,detectCategory:Ox,getModelForCategory:Nx,saveRoutingConfig:Mx,loadRoutingConfig:Yp,ROUTING_CONFIG_PATH:Qs}});var Ar=G((lS,Vp)=>{"use strict";var Cr=require("os"),Zs=require("path"),ze=require("fs"),Px=require("axios"),Ix=require("https"),Tr=Zs.join(Cr.homedir(),".nex-code","known-models.json"),Lx="https://ollama.com/api/tags",Dx=60,jx={"qwen3-coder:480b":131072,"devstral-2:123b":131072,"devstral-small-2:24b":131072,"kimi-k2:1t":262144,"kimi-k2.5":262144,"kimi-k2-thinking":262144,"minimax-m2.7:cloud":2e5,"minimax-m2.5":131072,"qwen3.5:397b":262144,"qwen3.5:35b-a3b":262144,"deepseek-v3.2":131072,"cogito-2.1:671b":131072,"glm-5":128e3,"glm-4.7":128e3};function Xa(){try{if(ze.existsSync(Tr))return JSON.parse(ze.readFileSync(Tr,"utf-8"))}catch{}return{benchmarked:[],lastChecked:null}}function qx(t){let e=Zs.dirname(Tr);ze.existsSync(e)||ze.mkdirSync(e,{recursive:!0}),ze.writeFileSync(Tr,JSON.stringify(t,null,2))}function Fx(t){let e=Xa(),n=new Set(e.benchmarked);for(let o of t)n.add(o);e.benchmarked=[...n],e.lastChecked=new Date().toISOString(),qx(e)}async function Xp(){let t=process.env.OLLAMA_API_KEY;if(!t)throw new Error("OLLAMA_API_KEY not set");let e=new Ix.Agent({keepAlive:!0});return((await Px.get(Lx,{headers:{Authorization:`Bearer ${t}`},timeout:15e3,httpsAgent:e})).data?.models||[]).map(o=>(o.name||o.model||"").replace(/:latest$/,"")).filter(Boolean)}async function Ux(){let t=await Xp(),e=Xa(),n=new Set(e.benchmarked),o=t.filter(s=>!n.has(s));return{allCloud:t,newModels:o,store:e}}var Ja="<!-- nex-benchmark-start -->",Rr="<!-- nex-benchmark-end -->",Wx={"devstral-2:123b":"Default \u2014 fastest + most reliable tool selection","devstral-small-2:24b":"Fast sub-agents, simple lookups","qwen3-coder:480b":"Coding-heavy sessions, heavy sub-agents","kimi-k2:1t":"Large repos (>100K tokens)","kimi-k2.5":"Large repos \u2014 faster than k2:1t","minimax-m2.7:cloud":"Complex swarm / multi-agent sessions (Toolathon SOTA)","minimax-m2.5":"Multi-agent, large context","qwen3.5:35b-a3b":"Fast MoE with 256K context"};function Bx(t){return t?t>=25e4?"256K":t>=19e4?"200K":t>=128e3?"131K":t>=64e3?"64K":`${Math.round(t/1024)}K`:"?"}function Jp(t,e){let n=["\u{1F947}","\u{1F948}","\u{1F949}"],o=(e||new Date().toISOString()).split("T")[0],s=t.filter(r=>r.score>=Dx).map((r,i)=>{let c=n[i]||"\u2014",l=Bx(jx[r.model]),u=Wx[r.model]||"\u2014",d=`${(r.avgLatency/1e3).toFixed(1)}s`,f=i===0?`**${r.score}**`:String(r.score);return`| ${c} | \`${r.model}\` | ${f} | ${d} | ${l} | ${u} |`}).join(`
1094
1094
  `);return`${Ja}
1095
1095
  <!-- Updated: ${o} \u2014 run \`/benchmark --discover\` after new Ollama Cloud releases -->
@@ -1365,7 +1365,7 @@ ${a.bold}Checking Ollama Cloud for new models...${a.reset}`);let b;try{b=await y
1365
1365
  `);break}console.log(`${a.cyan}New models to benchmark (${O.length}):${a.reset} ${O.join(", ")}
1366
1366
  `);let C=require("os"),L=He.join(C.homedir(),".nex-code","benchmark-results.json"),Ee=[];try{st.existsSync(L)&&(Ee=JSON.parse(st.readFileSync(L,"utf-8")))}catch{}let me="",ae=await x({newModels:O,existingRanking:Ee,onProgress:({model:K,task:se,done:I,score:W,error:oe})=>{if(!I){K!==me&&(me&&process.stdout.write(`
1367
1367
  `),me=K,process.stdout.write(`${a.cyan}${K}${a.reset} `));return}let V=oe?`${a.red}\u2717${a.reset}`:W>=80?`${a.green}\xB7${a.reset}`:W>=40?`${a.yellow}\xB7${a.reset}`:`${a.red}\xB7${a.reset}`;process.stdout.write(V)}});me&&process.stdout.write(`
1368
- `);try{st.writeFileSync(L,JSON.stringify(ae,null,2))}catch{}w(N);let le=He.join(process.cwd(),"README.md"),ee=k(ae,le),pe=R(ae),{buildCategoryWinners:z}=An(),{updateRoutingConfig:S}=Ar(),M=z(ae),U=S(M);if(ee&&console.log(`${a.green}README.md benchmark table updated${a.reset}`),pe.updated?console.log(`${a.green}DEFAULT_MODEL: ${pe.previousModel} \u2192 ${pe.newModel}${a.reset}`):pe.reason&&console.log(`${a.dim}models.env unchanged: ${pe.reason}${a.reset}`),U.changes.length>0){console.log(`${a.green}Routing updated:${a.reset}`);for(let K of U.changes)console.log(` ${a.dim}${K}${a.reset}`)}return console.log(),!0}let{runBenchmark:s,DEFAULT_MODELS:r,QUICK_MODELS:i}=An(),c=o.includes("--quick"),l=o.find(y=>y.startsWith("--models=")),u=l?l.replace("--models=","").split(",").map(y=>y.trim()).filter(Boolean):[],d=c?7:15,f=u.length>0?u:c?i:r;console.log(`
1368
+ `);try{st.writeFileSync(L,JSON.stringify(ae,null,2))}catch{}w(N);let le=He.join(process.cwd(),"README.md"),ee=k(ae,le),pe=R(ae),{buildCategoryWinners:X}=An(),{updateRoutingConfig:S}=Ar(),M=X(ae),U=S(M);if(ee&&console.log(`${a.green}README.md benchmark table updated${a.reset}`),pe.updated?console.log(`${a.green}DEFAULT_MODEL: ${pe.previousModel} \u2192 ${pe.newModel}${a.reset}`):pe.reason&&console.log(`${a.dim}models.env unchanged: ${pe.reason}${a.reset}`),U.changes.length>0){console.log(`${a.green}Routing updated:${a.reset}`);for(let K of U.changes)console.log(` ${a.dim}${K}${a.reset}`)}return console.log(),!0}let{runBenchmark:s,DEFAULT_MODELS:r,QUICK_MODELS:i}=An(),c=o.includes("--quick"),l=o.find(y=>y.startsWith("--models=")),u=l?l.replace("--models=","").split(",").map(y=>y.trim()).filter(Boolean):[],d=c?7:15,f=u.length>0?u:c?i:r;console.log(`
1369
1369
  ${a.bold}Starting benchmark${a.reset} ${a.dim}${d} tasks \xB7 ${f.length} models \xB7 ollama cloud${a.reset}`),console.log(`${a.dim}Models: ${f.join(", ")}${a.reset}
1370
1370
  `);let m="",h=0,p=d*f.length,g=await s({models:f,quick:c,onProgress:({model:y,task:w,done:k,score:R,error:x})=>{if(!k){y!==m&&(m&&process.stdout.write(`
1371
1371
  `),m=y,process.stdout.write(`${a.cyan}${y}${a.reset} `));return}h++;let _=x?`${a.red}\u2717${a.reset}`:R>=80?`${a.green}\xB7${a.reset}`:R>=40?`${a.yellow}\xB7${a.reset}`:`${a.red}\xB7${a.reset}`;process.stdout.write(_)}});if(m&&process.stdout.write(`
@@ -1399,7 +1399,7 @@ ${a.yellow} Task cancelled. Press Ctrl+C again to exit.${a.reset}`),k=!1,p.setP
1399
1399
  `)),me()}if(O){let fe=oo(V);return fe&&N.push(...fe.split(`
1400
1400
  `)),!0}return V.includes(`
1401
1401
  `)&&V.length>40&&!O?(N.push(...V.replace(/\r/g,"").split(`
1402
- `)),me()):I.call(process.stdin,W,...oe)}}let ee=0;function pe(){if(ee>0){let I=y._scrollEnd,W="\x1B7";for(let oe=0;oe<ee;oe++)W+=`\x1B[${I-ee+1+oe};1H\x1B[2K`;W+="\x1B8",y.rawWrite(W),ee=0}}function z(I){let W=[...ro,...Ir()].filter(be=>be.cmd.startsWith(I));if(!W.length||W.length===1&&W[0].cmd===I)return;let oe=y._scrollEnd,V=Math.min(10,oe-2);if(V<1)return;let Z=W.slice(0,V),ge=Math.max(...Z.map(be=>be.cmd.length));ee=Z.length,W.length>V&&ee++;let fe=oe-ee+1,we="\x1B7";for(let be=0;be<Z.length;be++){let{cmd:je,desc:Ge}=Z[be],Jt=je.substring(0,I.length),Nn=je.substring(I.length),Lr=" ".repeat(Math.max(0,ge-je.length+2));we+=`\x1B[${fe+be};1H\x1B[2K ${a.cyan}${Jt}${a.reset}${a.dim}${Nn}${Lr}${Ge}${a.reset}`}W.length>V&&(we+=`\x1B[${fe+Z.length};1H\x1B[2K ${a.dim}\u2026 +${W.length-V} more${a.reset}`),we+="\x1B8",y.rawWrite(we)}process.stdin.isTTY&&process.stdin.on("keypress",(I,W)=>{pe(),!(W&&(W.name==="tab"||W.name==="return"))&&setImmediate(()=>{p.line&&p.line.startsWith("/")&&z(p.line)})});let S=null,M=`${a.dim}...${a.reset} `;function U(I){return(I.match(/[^\s\d](\d{1,2})\.\s+\S/g)||[]).length<2?I:I.replace(/([^\s\d])(\d{1,2})\.\s+/g,(oe,V,Z)=>`${V}
1402
+ `)),me()):I.call(process.stdin,W,...oe)}}let ee=0;function pe(){if(ee>0){let I=y._scrollEnd,W="\x1B7";for(let oe=0;oe<ee;oe++)W+=`\x1B[${I-ee+1+oe};1H\x1B[2K`;W+="\x1B8",y.rawWrite(W),ee=0}}function X(I){let W=[...ro,...Ir()].filter(be=>be.cmd.startsWith(I));if(!W.length||W.length===1&&W[0].cmd===I)return;let oe=y._scrollEnd,V=Math.min(10,oe-2);if(V<1)return;let Z=W.slice(0,V),ge=Math.max(...Z.map(be=>be.cmd.length));ee=Z.length,W.length>V&&ee++;let fe=oe-ee+1,we="\x1B7";for(let be=0;be<Z.length;be++){let{cmd:je,desc:Ge}=Z[be],Jt=je.substring(0,I.length),Nn=je.substring(I.length),Lr=" ".repeat(Math.max(0,ge-je.length+2));we+=`\x1B[${fe+be};1H\x1B[2K ${a.cyan}${Jt}${a.reset}${a.dim}${Nn}${Lr}${Ge}${a.reset}`}W.length>V&&(we+=`\x1B[${fe+Z.length};1H\x1B[2K ${a.dim}\u2026 +${W.length-V} more${a.reset}`),we+="\x1B8",y.rawWrite(we)}process.stdin.isTTY&&process.stdin.on("keypress",(I,W)=>{pe(),!(W&&(W.name==="tab"||W.name==="return"))&&setImmediate(()=>{p.line&&p.line.startsWith("/")&&X(p.line)})});let S=null,M=`${a.dim}...${a.reset} `;function U(I){return(I.match(/[^\s\d](\d{1,2})\.\s+\S/g)||[]).length<2?I:I.replace(/([^\s\d])(\d{1,2})\.\s+/g,(oe,V,Z)=>`${V}
1403
1403
  ${Z}. `).trim()}let{loadSession:K}=At(),{setConversationMessages:se}=ve();if(e()===0){let I=K("_autosave");if(I&&I.messages&&I.messages.length>0&&Date.now()-new Date(I.updatedAt).getTime()<1440*60*1e3){let{confirm:oe}=Xe();if(await oe("Previous session found. Resume?")){let ge=I.messages,fe=ge.length>20?ge.slice(-20):ge;se(fe);let{getUsage:we,forceCompress:be}=Qe();if(we(fe,[]).percentage>=30){let{messages:Ge}=be(fe,[]);se(Ge)}}}}p.setPrompt(wt()),p.prompt(),p.on("line",async I=>{if(pe(),Object.keys(L).length>0&&(I=ae(I),le(),p.setPrompt(wt())),k){let Z=I.trim();if(Z){let{injectMidRunNote:ge}=ve();ge(Z),process.stdout.write(`${a.cyan} \u270E Queued \u2014 will be applied in the next step${a.reset}
1404
1404
  `),p.prompt()}return}if(S!==null){if(S._mode==="triple"){if(I.trim()==='"""'){let Z=S.join(`
1405
1405
  `).trim();if(S=null,Z){Pr(Z.replace(/\n/g,"\\n")),k=!0,p.prompt(),R=0,x=!1,_&&(clearTimeout(_),_=null),zt=new AbortController;try{await n(Z)}catch(fe){if(!zt?.signal?.aborted){let we=fe.message?.split(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nex-code",
3
- "version": "0.4.13",
3
+ "version": "0.4.15",
4
4
  "description": "The open-source agentic coding CLI. Free with Ollama Cloud — switch to OpenAI, Anthropic or Gemini anytime. Alternative to Claude Code & Gemini CLI.",
5
5
  "bin": {
6
6
  "nex-code": "./dist/nex-code.js"