nex-code 0.3.60 → 0.3.62
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.
- package/dist/nex-code.js +4 -4
- package/package.json +1 -1
package/dist/nex-code.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var D=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var ks=D((vb,xf)=>{xf.exports={name:"nex-code",version:"0.3.
|
|
2
|
+
var D=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var ks=D((vb,xf)=>{xf.exports={name:"nex-code",version:"0.3.62",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",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",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"},jest:{coverageThreshold:{global:{lines:45,functions:30,branches:35},"./cli/sub-agent.js":{lines:70,functions:65,branches:55}}}}});var Ut=D((Sb,fa)=>{"use strict";var ia="\x1B[0m",aa="\x1B[1m",cn="\x1B[2m";function A(t,e,s){return`\x1B[38;2;${t};${e};${s}m`}function vf(){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
|
`),n=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(n){let r=parseInt(n[1].slice(0,2),16),i=parseInt(n[2].slice(0,2),16),c=parseInt(n[3].slice(0,2),16);return .299*r+.587*i+.114*c<128}}catch{}return null}function ca(){let t=require("os");return require("path").join(t.homedir(),".nex-code",".theme_cache.json")}function Sf(t){try{let s=require("fs").readFileSync(ca(),"utf8"),o=JSON.parse(s);if(o&&typeof o[t]=="boolean")return o[t]}catch{}return null}function Ef(t,e){try{let s=require("fs"),o=require("path"),n=ca(),r=o.dirname(n),i={};try{i=JSON.parse(s.readFileSync(n,"utf8"))}catch{}i[t]=e;let c=Object.keys(i);c.length>50&&c.slice(0,c.length-50).forEach(l=>delete i[l]),s.existsSync(r)||s.mkdirSync(r,{recursive:!0}),s.writeFileSync(n,JSON.stringify(i),"utf8")}catch{}}function Tf(){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 s=process.env.TERM_SESSION_ID||"default",o=Sf(s);if(o!==null)return o;let n=vf(),r=n!==null?n:!0;return Ef(s,r),r}var la=Tf(),ua={reset:ia,bold:aa,dim:cn,primary:A(80,190,255),secondary:A(60,170,190),success:A(80,210,120),warning:A(245,175,50),error:A(230,80,80),muted:cn,subtle:A(130,130,145),tool_read:A(80,190,255),tool_write:A(245,165,55),tool_exec:A(185,100,235),tool_search:A(70,185,190),tool_git:A(90,210,100),tool_web:A(100,215,250),tool_sysadmin:A(225,150,75),tool_default:A(100,205,115),syn_keyword:A(185,100,235),syn_string:A(90,210,120),syn_number:A(245,175,50),syn_comment:cn,syn_key:A(80,190,255),diff_add:A(80,210,120),diff_rem:A(230,80,80),banner_logo:A(80,200,255),banner_name:A(80,200,255),banner_version:cn,banner_model:cn,banner_yolo:A(245,175,50),footer_sep:cn,footer_model:A(80,175,235),footer_branch:A(80,210,100),footer_project:A(130,130,145),footer_divider:A(80,80,95),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"},da={reset:ia,bold:aa,dim:A(110,110,120),primary:A(0,110,190),secondary:A(0,125,148),success:A(0,148,62),warning:A(168,92,0),error:A(188,32,32),muted:A(110,110,120),subtle:A(155,155,165),tool_read:A(0,110,190),tool_write:A(168,92,0),tool_exec:A(128,42,188),tool_search:A(0,122,148),tool_git:A(0,138,62),tool_web:A(0,112,178),tool_sysadmin:A(168,82,0),tool_default:A(0,138,62),syn_keyword:A(128,42,188),syn_string:A(0,138,62),syn_number:A(168,92,0),syn_comment:A(135,135,148),syn_key:A(0,110,190),diff_add:A(0,148,62),diff_rem:A(188,32,32),banner_logo:A(0,122,205),banner_name:A(0,122,205),banner_version:A(100,100,118),banner_model:A(100,100,118),banner_yolo:A(168,62,0),footer_sep:A(168,168,178),footer_model:A(0,102,175),footer_branch:A(0,138,62),footer_project:A(135,135,148),footer_divider:A(168,168,178),white:A(40,40,52),red:A(188,32,32),green:A(0,148,62),yellow:A(168,92,0),blue:A(0,110,190),magenta:A(128,42,188),cyan:A(0,125,148),gray:A(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:A(0,158,182),brightMagenta:A(158,52,208),brightBlue:A(0,112,208)},Rf=la?ua:da;fa.exports={T:Rf,isDark:la,DARK:ua,LIGHT:da}});var Pn=D((Eb,ma)=>{var{T:P}=Ut(),Ss=5,ln=(()=>{let t=[];for(let e=0;e<Ss;e++)t.push(e);for(let e=Ss-2;e>=1;e--)t.push(e);return t})(),pa=["\u273D","\u2726","\u2727","\u2726"],Yo=class{constructor(e="Thinking..."){this.text=e,this.frame=0,this.interval=null,this.startTime=null}_render(){if(this._stopped)return;let e=ln[this.frame%ln.length],s="";for(let n=0;n<Ss;n++)s+=n===e?`${P.cyan}\u25CF${P.reset}`:" ";let o="";if(this.startTime){let n=Math.floor((Date.now()-this.startTime)/1e3);if(n>=60){let r=Math.floor(n/60),i=n%60;o=` ${P.dim}${r}m ${String(i).padStart(2,"0")}s${P.reset}`}else n>=1&&(o=` ${P.dim}${n}s${P.reset}`)}process.stderr.write(`\x1B[2K\r${s} ${P.dim}${this.text}${P.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}},Xo=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 s=Math.floor(e/60),o=e%60;return s>0?`${s}m ${String(o).padStart(2,"0")}s`:`${o}s`}_render(){if(this._stopped)return;let e=ln[this.frame%ln.length],s=`${P.cyan}\u25CF${P.reset}`,o=`${P.dim}\u25CB${P.reset}`,n=this._formatElapsed(),r=n?` ${P.dim}${n}${P.reset}`:"",i="";for(let c=0;c<this.labels.length;c++){let l,u;switch(this.statuses[c]){case"done":l=`${P.green}\u2713${P.reset}`,u=P.dim;break;case"error":l=`${P.red}\u2717${P.reset}`,u=P.dim;break;default:l=c===e?s:" ",u=""}let d=c===this.labels.length-1?r:"";i+=`\x1B[2K ${l} ${u}${this.labels[c]}${P.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 s=0;s<this.lineCount;s++)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,s){e>=0&&e<this.statuses.length&&(this.statuses[e]=s)}stop(){this._stopped=!0,this.interval&&(clearInterval(this.interval),this.interval=null),this._renderFinal(),process.stderr.write("\x1B[?25h")}_renderFinal(){let e=this._formatElapsed(),s=e?` ${P.dim}${e}${P.reset}`:"",o="";for(let n=0;n<this.labels.length;n++){let r;switch(this.statuses[n]){case"done":r=`${P.green}\u2713${P.reset}`;break;case"error":r=`${P.red}\u2717${P.reset}`;break;default:r=`${P.yellow}\u25CB${P.reset}`}let i=n===this.labels.length-1?s:"";o+=`\x1B[2K ${r} ${P.dim}${this.labels[n]}${P.reset}${i}
|
|
@@ -77,7 +77,7 @@ ${o}`,_compacted:!0,_originalCount:t.length},tokensRemoved:n-r}}catch{return nul
|
|
|
77
77
|
`);S=k.pop()||"";for(let v of k){let R=v.trim();if(R.startsWith("data: ")){let C=R.slice(6),O;try{O=JSON.parse(C)}catch{continue}switch(O.type){case"content_block_start":{let L=O.content_block;L?.type==="tool_use"&&(b=y.length,y.push({id:L.id,name:L.name,inputJson:""}));break}case"content_block_delta":{let L=O.delta;L?.type==="text_delta"&&L.text&&(l(L.text),$+=L.text),L?.type==="input_json_delta"&&L.partial_json!==void 0&&b>=0&&(y[b].inputJson+=L.partial_json);break}case"content_block_stop":b=-1;break;case"message_stop":p({content:$,tool_calls:this._buildToolCalls(y)});return}}}}),h.data.on("error",w=>{o.signal?.aborted||g(new Error(`Stream error: ${w.message}`))}),h.data.on("end",()=>{p({content:$,tool_calls:this._buildToolCalls(y)})})})}normalizeResponse(e){let s="",o=[];for(let n of e.content||[])n.type==="text"?s+=n.text:n.type==="tool_use"&&o.push({id:n.id,function:{name:n.name,arguments:n.input}});return{content:s,tool_calls:o}}_buildToolCalls(e){return e.filter(s=>s.name).map(s=>{let o={};if(s.inputJson)try{o=JSON.parse(s.inputJson)}catch{o=s.inputJson}return{id:s.id||`anthropic-${Date.now()}`,function:{name:s.name,arguments:o}}})}};Ja.exports={AnthropicProvider:lr,ANTHROPIC_MODELS:Xa}});var tc=D((qb,ec)=>{var Qa=require("axios"),{BaseProvider:Mp}=un(),{serializeMessage:Db}=ot(),Za={"gemini-3.1-pro-preview":{id:"gemini-3.1-pro-preview",name:"Gemini 3.1 Pro Preview",maxTokens:65536,contextWindow:1048576},"gemini-3-flash-preview":{id:"gemini-3-flash-preview",name:"Gemini 3 Flash Preview",maxTokens:65536,contextWindow:1048576},"gemini-2.5-pro":{id:"gemini-2.5-pro",name:"Gemini 2.5 Pro",maxTokens:65536,contextWindow:1048576},"gemini-2.5-flash":{id:"gemini-2.5-flash",name:"Gemini 2.5 Flash",maxTokens:65536,contextWindow:1048576},"gemini-2.5-flash-lite":{id:"gemini-2.5-flash-lite",name:"Gemini 2.5 Flash Lite",maxTokens:65536,contextWindow:1048576},"gemini-2.0-flash":{id:"gemini-2.0-flash",name:"Gemini 2.0 Flash",maxTokens:8192,contextWindow:1048576},"gemini-2.0-flash-lite":{id:"gemini-2.0-flash-lite",name:"Gemini 2.0 Flash Lite",maxTokens:8192,contextWindow:1048576},"gemini-1.5-pro":{id:"gemini-1.5-pro",name:"Gemini 1.5 Pro",maxTokens:8192,contextWindow:1048576},"gemini-1.5-flash":{id:"gemini-1.5-flash",name:"Gemini 1.5 Flash",maxTokens:8192,contextWindow:1048576}},ur=class extends Mp{constructor(e={}){super({name:"gemini",baseUrl:e.baseUrl||"https://generativelanguage.googleapis.com/v1beta/openai",models:e.models||Za,defaultModel:e.defaultModel||"gemini-2.5-flash",...e}),this.timeout=e.timeout||18e4,this.temperature=e.temperature??.2}isConfigured(){return!!this.getApiKey()}getApiKey(){return process.env.GEMINI_API_KEY||process.env.GOOGLE_API_KEY||null}_getHeaders(){let e=this.getApiKey();if(!e)throw new Error("GEMINI_API_KEY not set");return{Authorization:`Bearer ${e}`,"Content-Type":"application/json"}}_messageFormatCache=new WeakMap;_messageStringCache=new Map;_maxCacheSize=200;formatMessages(e){let s=[];for(let o of e){if(this._messageFormatCache.has(o)){s.push(this._messageFormatCache.get(o));continue}let n=this._getMessageCacheKey(o);if(this._messageStringCache.has(n)){let i=this._messageStringCache.get(n);this._messageFormatCache.set(o,i),s.push(i);continue}let r=this._formatSingleMessage(o);this._messageStringCache.size<this._maxCacheSize&&this._messageStringCache.set(n,r),this._messageFormatCache.set(o,r),s.push(r)}return{messages:s}}_getMessageCacheKey(e){let s=e.role||"",o=typeof e.content=="string"?e.content.substring(0,100):"",n=e.tool_calls?e.tool_calls.length:0;return`${s}:${o.length}:${n}`}_formatSingleMessage(e){if(e.role==="assistant"&&e.tool_calls)return{role:"assistant",content:e.content||"",tool_calls:e.tool_calls.map(s=>({id:s.id||`call-${Date.now()}`,type:"function",function:{name:s.function.name,arguments:typeof s.function.arguments=="string"?s.function.arguments:JSON.stringify(s.function.arguments)}}))};if(e.role==="tool")return{role:"tool",content:typeof e.content=="string"?e.content:JSON.stringify(e.content),tool_call_id:e.tool_call_id};if(e.role==="user"&&Array.isArray(e.content)){let s=[];for(let o of e.content)if(o.type==="text")s.push({type:"text",text:o.text??""});else if(o.type==="image"&&o.data){let n=o.data.startsWith("data:")?o.data:`data:${o.media_type||"image/png"};base64,${o.data}`;s.push({type:"image_url",image_url:{url:n,detail:"auto"}})}return{role:"user",content:s}}return{role:e.role,content:e.content}}async chat(e,s,o={}){let n=o.model||this.defaultModel,r=this.getModel(n),i=o.maxTokens||r?.maxTokens||8192,{messages:c}=this.formatMessages(e),l={model:n,messages:c,max_tokens:i,temperature:o.temperature??this.temperature};s&&s.length>0&&(l.tools=s);let u=await Qa.post(`${this.baseUrl}/chat/completions`,l,{timeout:o.timeout||this.timeout,headers:this._getHeaders()});return this.normalizeResponse(u.data)}async stream(e,s,o={}){let n=o.model||this.defaultModel,r=this.getModel(n),i=o.maxTokens||r?.maxTokens||8192,c=o.onToken||(()=>{}),{messages:l}=this.formatMessages(e),u={model:n,messages:l,max_tokens:i,temperature:o.temperature??this.temperature,stream:!0};s&&s.length>0&&(u.tools=s);let d;try{d=await Qa.post(`${this.baseUrl}/chat/completions`,u,{timeout:o.timeout||this.timeout,headers:this._getHeaders(),responseType:"stream",signal:o.signal})}catch(f){if(f.name==="CanceledError"||f.name==="AbortError"||f.code==="ERR_CANCELED")throw f;let m=f.response?.data?.error?.message||f.message;throw new Error(`API Error: ${m}`)}return new Promise((f,m)=>{let h="",p={},g="";o.signal&&o.signal.addEventListener("abort",()=>{d.data.destroy(),m(new DOMException("The operation was aborted","AbortError"))},{once:!0}),d.data.on("data",$=>{g+=$.toString();let y=g.split(`
|
|
78
78
|
`);g=y.pop()||"";for(let b of y){let S=b.trim();if(!S||!S.startsWith("data: "))continue;let w=S.slice(6);if(w==="[DONE]"){f({content:h,tool_calls:this._buildToolCalls(p)});return}let k;try{k=JSON.parse(w)}catch{continue}let v=k.choices?.[0]?.delta;if(v&&(v.content&&(c(v.content),h+=v.content),v.tool_calls))for(let R of v.tool_calls){let C=R.index??0;p[C]||(p[C]={id:R.id||"",name:"",arguments:""}),R.id&&(p[C].id=R.id),R.function?.name&&(p[C].name+=R.function.name),R.function?.arguments&&(p[C].arguments+=R.function.arguments)}}}),d.data.on("error",$=>{o.signal?.aborted||m(new Error(`Stream error: ${$.message}`))}),d.data.on("end",()=>{f({content:h,tool_calls:this._buildToolCalls(p)})})})}normalizeResponse(e){let s=e.choices?.[0]?.message||{},o=(s.tool_calls||[]).map(n=>({id:n.id,function:{name:n.function.name,arguments:n.function.arguments}}));return{content:s.content||"",tool_calls:o}}_buildToolCalls(e){return Object.values(e).filter(s=>s.name).map(s=>({id:s.id||`call-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,function:{name:s.name,arguments:s.arguments}}))}};ec.exports={GeminiProvider:ur,GEMINI_MODELS:Za}});var oc=D((Fb,sc)=>{var Ms=require("axios"),{BaseProvider:Pp}=un(),nc="http://localhost:11434",dr=class extends Pp{constructor(e={}){super({name:"local",baseUrl:e.baseUrl||process.env.OLLAMA_HOST||process.env.OLLAMA_LOCAL_URL||nc,models:e.models||{},defaultModel:e.defaultModel||null,...e}),this.timeout=e.timeout||3e5,this.temperature=e.temperature??.2,this._modelsLoaded=!1}isConfigured(){return!0}async loadModels(){if(this._modelsLoaded)return this.models;try{let s=(await Ms.get(`${this.baseUrl}/api/tags`,{timeout:5e3})).data?.models||[];this.models={};for(let o of s){let n=o.name||o.model;if(!n)continue;let r=n.replace(/:latest$/,""),i=32768;try{let c=await Ms.post(`${this.baseUrl}/api/show`,{name:n},{timeout:5e3}),l=c.data?.model_info||c.data?.details||{};i=l["general.context_length"]||l["llama.context_length"]||this._parseContextFromModelfile(c.data?.modelfile)||32768}catch{}this.models[r]={id:r,name:o.name,maxTokens:Math.min(8192,Math.floor(i*.1)),contextWindow:i}}!this.defaultModel&&Object.keys(this.models).length>0&&(this.defaultModel=Object.keys(this.models)[0]),this._modelsLoaded=!0}catch{this.models={},this._modelsLoaded=!1}return this.models}getModels(){return this.models}getModelNames(){return Object.keys(this.models)}_formatMessages(e){return e.map(s=>{if(s.role==="user"&&Array.isArray(s.content)){let o=[],n=[];for(let i of s.content)i.type==="text"?o.push(i.text??""):i.type==="image"&&i.data&&n.push(i.data);let r={role:"user",content:o.join(`
|
|
79
79
|
`)};return n.length>0&&(r.images=n),r}return s})}async chat(e,s,o={}){this._modelsLoaded||await this.loadModels();let n=o.model||this.defaultModel;if(!n)throw new Error("No local model available. Is Ollama running?");let r=await Ms.post(`${this.baseUrl}/api/chat`,{model:n,messages:this._formatMessages(e),tools:s&&s.length>0?s:void 0,stream:!1,options:{temperature:o.temperature??this.temperature,num_predict:o.maxTokens||8192}},{timeout:o.timeout||this.timeout});return this.normalizeResponse(r.data)}async stream(e,s,o={}){this._modelsLoaded||await this.loadModels();let n=o.model||this.defaultModel;if(!n)throw new Error("No local model available. Is Ollama running?");let r=o.onToken||(()=>{}),i;try{i=await Ms.post(`${this.baseUrl}/api/chat`,{model:n,messages:this._formatMessages(e),tools:s&&s.length>0?s:void 0,stream:!0,options:{temperature:o.temperature??this.temperature,num_predict:o.maxTokens||8192}},{timeout:o.timeout||this.timeout,responseType:"stream",signal:o.signal})}catch(c){if(c.name==="CanceledError"||c.name==="AbortError"||c.code==="ERR_CANCELED")throw c;let l=c.response?.data?.error||c.message;throw new Error(`API Error: ${l}`)}return new Promise((c,l)=>{let u="",d=[],f="";o.signal&&o.signal.addEventListener("abort",()=>{i.data.destroy(),l(new DOMException("The operation was aborted","AbortError"))},{once:!0}),i.data.on("data",m=>{f+=m.toString();let h=f.split(`
|
|
80
|
-
`);f=h.pop()||"";for(let p of h){if(!p.trim())continue;let g;try{g=JSON.parse(p)}catch{continue}if(g.message?.content&&(r(g.message.content),u+=g.message.content),g.message?.tool_calls&&(d=d.concat(g.message.tool_calls)),g.done){c({content:u,tool_calls:this._normalizeToolCalls(d)});return}}}),i.data.on("error",m=>{o.signal?.aborted||l(new Error(`Stream error: ${m.message}`))}),i.data.on("end",()=>{if(f.trim())try{let m=JSON.parse(f);m.message?.content&&(r(m.message.content),u+=m.message.content),m.message?.tool_calls&&(d=d.concat(m.message.tool_calls))}catch{}c({content:u,tool_calls:this._normalizeToolCalls(d)})})})}normalizeResponse(e){let s=e.message||{};return{content:s.content||"",tool_calls:this._normalizeToolCalls(s.tool_calls||[])}}_parseContextFromModelfile(e){if(!e)return null;let s=e.match(/PARAMETER\s+num_ctx\s+(\d+)/i);return s?parseInt(s[1],10):null}_normalizeToolCalls(e){return e.map((s,o)=>({id:s.id||`local-${Date.now()}-${o}`,function:{name:s.function?.name||s.name||"unknown",arguments:s.function?.arguments||s.arguments||{}}}))}};sc.exports={LocalProvider:dr,DEFAULT_LOCAL_URL:nc}});var At=D((Ub,ic)=>{"use strict";var Ke=require("fs"),rc=require("path");function Ip(t){if(!t||isNaN(t))return!1;try{return process.kill(t,0),!0}catch(e){return e.code==="EPERM"}}function Lp(t){try{Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,t)}catch{let e=Date.now()+t;for(;Date.now()<e;);}}function jp(t,e){let s=rc.dirname(t),o=rc.join(s,`.nex-tmp.${process.pid}.${Date.now()}`);try{Ke.existsSync(s)||Ke.mkdirSync(s,{recursive:!0}),Ke.writeFileSync(o,e,"utf-8"),Ke.renameSync(o,t)}catch(n){try{Ke.unlinkSync(o)}catch{}throw n}}function Dp(t,e,{timeout:s=5e3,retryMs:o=50}={}){let n=t+".lock",r=Date.now()+s;for(;;){let i=-1;try{i=Ke.openSync(n,"wx"),Ke.writeSync(i,Buffer.from(String(process.pid))),Ke.closeSync(i),i=-1;try{return e()}finally{try{Ke.unlinkSync(n)}catch{}}}catch(c){if(i!==-1)try{Ke.closeSync(i)}catch{}if(c.code!=="EEXIST")throw c;try{let l=Ke.readFileSync(n,"utf-8").trim(),u=parseInt(l,10);if(!Ip(u)){try{Ke.unlinkSync(n)}catch{}continue}}catch{continue}if(Date.now()>=r){try{Ke.unlinkSync(n)}catch{}return e()}Lp(o)}}}ic.exports={atomicWrite:jp,withFileLockSync:Dp}});var mn=D((Wb,pc)=>{var pn=require("fs"),fr=require("path"),{atomicWrite:qp,withFileLockSync:Fp}=At(),ac={openai:{"gpt-4o":{input:2.5,output:10},"gpt-4o-mini":{input:.15,output:.6},"gpt-4.1":{input:2,output:8},"gpt-4.1-mini":{input:.4,output:1.6},"gpt-4.1-nano":{input:.1,output:.4},o1:{input:15,output:60},o3:{input:10,output:40},"o3-mini":{input:1.1,output:4.4},"o4-mini":{input:1.1,output:4.4}},anthropic:{"claude-sonnet":{input:3,output:15},"claude-opus":{input:5,output:25},"claude-haiku":{input:.8,output:4},"claude-sonnet-4-5":{input:3,output:15},"claude-sonnet-4":{input:3,output:15}},gemini:{"gemini-2.5-pro":{input:1.25,output:10},"gemini-2.5-flash":{input:.15,output:.6},"gemini-2.0-flash":{input:.1,output:.4},"gemini-2.0-flash-lite":{input:.075,output:.3}},ollama:{"qwen3-coder:480b":{input:0,output:0},"qwen3-coder-next":{input:0,output:0},"devstral-2:123b":{input:0,output:0},"devstral-small-2:24b":{input:0,output:0},"kimi-k2.5":{input:0,output:0},"kimi-k2:1t":{input:0,output:0},"deepseek-v3.2":{input:0,output:0},"minimax-m2.5":{input:0,output:0},"glm-5":{input:0,output:0},"glm-4.7":{input:0,output:0},"gpt-oss:120b":{input:0,output:0}},local:{}},Ps=[],Ot={};function Up(t,e,s,o){if(Ps.push({provider:t,model:e,input:s,output:o}),Ot[t]!==void 0){let n=dc(t);n.allowed||process.stderr.write(`\x1B[33m\u26A0 Budget limit reached for ${t}: $${n.spent.toFixed(2)} / $${n.limit.toFixed(2)}\x1B[0m
|
|
80
|
+
`);f=h.pop()||"";for(let p of h){if(!p.trim())continue;let g;try{g=JSON.parse(p)}catch{continue}if(g.message?.content&&(r(g.message.content),u+=g.message.content),g.message?.tool_calls&&(d=d.concat(g.message.tool_calls)),g.done){c({content:u,tool_calls:this._normalizeToolCalls(d)});return}}}),i.data.on("error",m=>{o.signal?.aborted||l(new Error(`Stream error: ${m.message}`))}),i.data.on("end",()=>{if(f.trim())try{let m=JSON.parse(f);m.message?.content&&(r(m.message.content),u+=m.message.content),m.message?.tool_calls&&(d=d.concat(m.message.tool_calls))}catch{}c({content:u,tool_calls:this._normalizeToolCalls(d)})})})}normalizeResponse(e){let s=e.message||{};return{content:s.content||"",tool_calls:this._normalizeToolCalls(s.tool_calls||[])}}_parseContextFromModelfile(e){if(!e)return null;let s=e.match(/PARAMETER\s+num_ctx\s+(\d+)/i);return s?parseInt(s[1],10):null}_normalizeToolCalls(e){return e.map((s,o)=>({id:s.id||`local-${Date.now()}-${o}`,function:{name:s.function?.name||s.name||"unknown",arguments:s.function?.arguments||s.arguments||{}}}))}};sc.exports={LocalProvider:dr,DEFAULT_LOCAL_URL:nc}});var At=D((Ub,ic)=>{"use strict";var Ke=require("fs"),rc=require("path");function Ip(t){if(!t||isNaN(t))return!1;try{return process.kill(t,0),!0}catch(e){return e.code==="EPERM"}}function Lp(t){try{Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,t)}catch{let e=Date.now()+t;for(;Date.now()<e;);}}function jp(t,e){let s=rc.dirname(t),o=rc.join(s,`.nex-tmp.${process.pid}.${Date.now()}`);try{Ke.existsSync(s)||Ke.mkdirSync(s,{recursive:!0}),Ke.writeFileSync(o,e,"utf-8"),Ke.renameSync(o,t)}catch(n){try{Ke.unlinkSync(o)}catch{}throw n}}function Dp(t,e,{timeout:s=5e3,retryMs:o=50}={}){let n=t+".lock",r=Date.now()+s;for(;;){let i=-1;try{i=Ke.openSync(n,"wx"),Ke.writeSync(i,Buffer.from(String(process.pid))),Ke.closeSync(i),i=-1;try{return e()}finally{try{Ke.unlinkSync(n)}catch{}}}catch(c){if(i!==-1)try{Ke.closeSync(i)}catch{}if(c.code!=="EEXIST")throw c;try{let l=Ke.readFileSync(n,"utf-8").trim(),u=parseInt(l,10);if(!Ip(u)){try{Ke.unlinkSync(n)}catch{}continue}}catch(l){if(l.code&&l.code!=="ENOENT")throw l;continue}if(Date.now()>=r){try{Ke.unlinkSync(n)}catch{}return e()}Lp(o)}}}ic.exports={atomicWrite:jp,withFileLockSync:Dp}});var mn=D((Wb,pc)=>{var pn=require("fs"),fr=require("path"),{atomicWrite:qp,withFileLockSync:Fp}=At(),ac={openai:{"gpt-4o":{input:2.5,output:10},"gpt-4o-mini":{input:.15,output:.6},"gpt-4.1":{input:2,output:8},"gpt-4.1-mini":{input:.4,output:1.6},"gpt-4.1-nano":{input:.1,output:.4},o1:{input:15,output:60},o3:{input:10,output:40},"o3-mini":{input:1.1,output:4.4},"o4-mini":{input:1.1,output:4.4}},anthropic:{"claude-sonnet":{input:3,output:15},"claude-opus":{input:5,output:25},"claude-haiku":{input:.8,output:4},"claude-sonnet-4-5":{input:3,output:15},"claude-sonnet-4":{input:3,output:15}},gemini:{"gemini-2.5-pro":{input:1.25,output:10},"gemini-2.5-flash":{input:.15,output:.6},"gemini-2.0-flash":{input:.1,output:.4},"gemini-2.0-flash-lite":{input:.075,output:.3}},ollama:{"qwen3-coder:480b":{input:0,output:0},"qwen3-coder-next":{input:0,output:0},"devstral-2:123b":{input:0,output:0},"devstral-small-2:24b":{input:0,output:0},"kimi-k2.5":{input:0,output:0},"kimi-k2:1t":{input:0,output:0},"deepseek-v3.2":{input:0,output:0},"minimax-m2.5":{input:0,output:0},"glm-5":{input:0,output:0},"glm-4.7":{input:0,output:0},"gpt-oss:120b":{input:0,output:0}},local:{}},Ps=[],Ot={};function Up(t,e,s,o){if(Ps.push({provider:t,model:e,input:s,output:o}),Ot[t]!==void 0){let n=dc(t);n.allowed||process.stderr.write(`\x1B[33m\u26A0 Budget limit reached for ${t}: $${n.spent.toFixed(2)} / $${n.limit.toFixed(2)}\x1B[0m
|
|
81
81
|
`)}}function pr(t,e){let s=ac[t];return s?s[e]||{input:0,output:0}:{input:0,output:0}}function cc(t){let e=pr(t.provider,t.model);return(t.input*e.input+t.output*e.output)/1e6}function lc(){let t={};for(let r of Ps){let i=`${r.provider}:${r.model}`;t[i]||(t[i]={provider:r.provider,model:r.model,input:0,output:0}),t[i].input+=r.input,t[i].output+=r.output}let e=Object.values(t).map(r=>({...r,cost:cc(r)})),s=e.reduce((r,i)=>r+i.cost,0),o=e.reduce((r,i)=>r+i.input,0),n=e.reduce((r,i)=>r+i.output,0);return{totalCost:s,totalInput:o,totalOutput:n,breakdown:e}}function Wp(){let{totalCost:t,totalInput:e,totalOutput:s,breakdown:o}=lc();if(o.length===0)return"No token usage recorded this session.";let n=[];n.push("Session Token Usage:"),n.push("");for(let r of o){let i=r.cost>0?`$${r.cost.toFixed(4)}`:"free";n.push(` ${r.provider}:${r.model}`),n.push(` Input: ${r.input.toLocaleString()} tokens`),n.push(` Output: ${r.output.toLocaleString()} tokens`),n.push(` Cost: ${i}`)}return n.push(""),n.push(` Total: ${e.toLocaleString()} in + ${s.toLocaleString()} out = $${t.toFixed(4)}`),n.join(`
|
|
82
82
|
`)}function Bp(t,e,s,o){let n=pr(t,e),r=(s*n.input+o*n.output)/1e6;return r<=0?"":`[~$${r.toFixed(4)}]`}function Hp(){Ps=[]}function Gp(t,e){Ot[t]=e}function Kp(t){delete Ot[t]}function zp(){return{...Ot}}function uc(t){let e=0;for(let s of Ps)s.provider===t&&(e+=cc(s));return e}function dc(t){let e=uc(t),s=Ot[t];if(s===void 0)return{allowed:!0,spent:e,limit:null,remaining:null};let o=Math.max(0,s-e);return{allowed:e<s,spent:e,limit:s,remaining:o}}function fc(){let t=fr.join(process.cwd(),".nex","config.json");if(pn.existsSync(t))try{let e=JSON.parse(pn.readFileSync(t,"utf-8"));e.costLimits&&typeof e.costLimits=="object"&&(Ot={...e.costLimits})}catch{}}function Yp(){let t=fr.join(process.cwd(),".nex"),e=fr.join(t,"config.json");pn.existsSync(t)||pn.mkdirSync(t,{recursive:!0}),Fp(e,()=>{let s={};if(pn.existsSync(e))try{s=JSON.parse(pn.readFileSync(e,"utf-8"))}catch{s={}}s.costLimits=Ot,qp(e,JSON.stringify(s,null,2))})}function Xp(){Ot={}}fc();pc.exports={PRICING:ac,trackUsage:Up,getSessionCosts:lc,formatCosts:Wp,formatCostHint:Bp,resetCosts:Hp,getPricing:pr,setCostLimit:Gp,removeCostLimit:Kp,getCostLimits:zp,getProviderSpend:uc,checkBudget:dc,loadCostLimits:fc,saveCostLimits:Yp,resetCostLimits:Xp}});var gc=D((Bb,hc)=>{"use strict";var Jp=new Set(["read_file","grep","glob","search_files","list_directory"]),Vp=new Set(["write_file","edit_file","patch_file"]),Qp=new Set(["bash"]),Zp=new Set(["web_search","web_fetch","perplexity_search"]);function mc(t,e){let s=0,o=0,n=0,r=0,i=0;for(let[c,l]of t)i+=l,Jp.has(c)&&(s+=l),Vp.has(c)&&(o+=l),Qp.has(c)&&(n+=l),Zp.has(c)&&(r+=l);return i===0?`Phase ${e}`:r/i>.5?"Research":s/i>.5?"Exploration":o/i>.3?"Implementation":n/i>.3&&o/i<.15?"Verification":`Phase ${e}`}var mr=class{constructor(e){this._N=e,this._disabled=e<=0,this._phaseNum=0,this._linesThisPhase=0,this._stepsThisPhase=0,this._phaseCounts=new Map,this._phaseStart=Date.now()}record(e,s,o,n){if(this._disabled)return null;this._linesThisPhase+=e,this._stepsThisPhase++;for(let i of s)this._phaseCounts.set(i,(this._phaseCounts.get(i)||0)+1);if(this._stepsThisPhase<this._N)return null;this._phaseNum++;let r={fire:!0,inViewport:this._isInViewport(),linesBack:this._linesThisPhase,phaseNum:this._phaseNum,phaseName:mc(this._phaseCounts,this._phaseNum),stepCount:this._stepsThisPhase,toolCounts:new Map(this._phaseCounts),elapsed:Date.now()-this._phaseStart,filesRead:new Set(o),filesModified:new Set(n)};return this._linesThisPhase=0,this._stepsThisPhase=0,this._phaseCounts=new Map,this._phaseStart=Date.now(),r}_isInViewport(){if(!process.stdout.isTTY)return!1;let e=Math.max(1,(process.stdout.rows||24)-2);return this._linesThisPhase<=e}};hc.exports={MilestoneTracker:mr,_phaseName:mc}});var Is=D((Hb,$c)=>{var Ln=we(),em={"kimi-k2.5":{id:"kimi-k2.5",name:"Kimi K2.5",max_tokens:16384},"qwen3-coder:480b":{id:"qwen3-coder:480b",name:"Qwen3 Coder 480B",max_tokens:16384}};function tm(){return Ln.getActiveModel()}function nm(t){return Ln.setActiveModel(t)}function sm(){return Ln.getModelNames()}function om(t){if(!t)return null;if(typeof t=="object")return t;try{return JSON.parse(t)}catch{}try{let o=t.replace(/,\s*([}\]])/g,"$1").replace(/'/g,'"');return JSON.parse(o)}catch{}let e=t.match(/\{[\s\S]*\}/);if(e)try{return JSON.parse(e[0])}catch{}try{let o=t.replace(/(\{|,)\s*([a-zA-Z_]\w*)\s*:/g,'$1"$2":');return JSON.parse(o)}catch{}let s=t.match(/```(?:json)?\s*([\s\S]*?)```/);if(s)try{return JSON.parse(s[1].trim())}catch{}return null}async function rm(t,e){let{C:s}=ye(),{Spinner:o}=ye(),n=new o("Thinking...");n.start();let r=!0,i="";try{let c=await Ln.callStream(t,e,{onToken:l=>{r&&(n.stop(),process.stdout.write(`${s.blue}`),r=!1),process.stdout.write(l),i+=l}});return r?n.stop():process.stdout.write(`${s.reset}
|
|
83
83
|
`),c}catch(c){throw n.stop(),c}}async function im(t,e){return Ln.callChat(t,e)}$c.exports={MODELS:em,getActiveModel:tm,setActiveModel:nm,getModelNames:sm,callOllamaStream:rm,callOllama:im,parseToolArgs:om}});var bc=D((Kb,wc)=>{var Ls=require("path"),{C:T}=ye(),{T:hr,isDark:Gb}=Ut(),{confirm:am,getAutoConfirm:cm}=je(),yc=2e3;function jn(t,e){let s=t.split(`
|
|
@@ -103,7 +103,7 @@ ${ge.bold}${ge.cyan}Suggested message:${ge.reset}`),e.push(` ${ge.cyan}${t.summ
|
|
|
103
103
|
...(truncated)`:s;e.push(`
|
|
104
104
|
DIFF:
|
|
105
105
|
${o}`)}return e.join(`
|
|
106
|
-
`)}xc.exports={isGitRepo:$m,getCurrentBranch:ym,getStatus:$r,getDiff:Ds,getChangedFiles:yr,analyzeDiff:kc,createBranch:wm,commit:bm,formatDiffSummary:_m,getDiffContext:xm,getMergeConflicts:km}});var yt=D((Xb,Cc)=>{var Se=require("fs").promises,Yb=require("fs"),Ze=require("path"),vm=require("crypto"),{execSync:Dn}=require("child_process"),Sm=100*1024,Ec=50,De=[],hn=[];function Em(t,e,s,o){for(De.push({tool:t,filePath:e,oldContent:s,newContent:o,timestamp:Date.now()});De.length>Ec;)De.shift();hn.length=0,Tc(De[De.length-1]).catch(()=>{})}async function Tm(){if(De.length===0)return null;let t=De.pop();if(t.oldContent===null)try{await Se.unlink(t.filePath)}catch{}else await Se.writeFile(t.filePath,t.oldContent,"utf-8");return hn.push(t),{tool:t.tool,filePath:t.filePath,wasCreated:t.oldContent===null}}async function Rm(){if(hn.length===0)return null;let t=hn.pop();return await Se.writeFile(t.filePath,t.newContent,"utf-8"),De.push(t),{tool:t.tool,filePath:t.filePath}}function Cm(t=10){return De.slice(-t).reverse().map(e=>({tool:e.tool,filePath:e.filePath,timestamp:e.timestamp}))}function Am(){return De.length}function Om(){return hn.length}function Nm(){De.length=0,hn.length=0
|
|
106
|
+
`)}xc.exports={isGitRepo:$m,getCurrentBranch:ym,getStatus:$r,getDiff:Ds,getChangedFiles:yr,analyzeDiff:kc,createBranch:wm,commit:bm,formatDiffSummary:_m,getDiffContext:xm,getMergeConflicts:km}});var yt=D((Xb,Cc)=>{var Se=require("fs").promises,Yb=require("fs"),Ze=require("path"),vm=require("crypto"),{execSync:Dn}=require("child_process"),Sm=100*1024,Ec=50,De=[],hn=[];function Em(t,e,s,o){for(De.push({tool:t,filePath:e,oldContent:s,newContent:o,timestamp:Date.now()});De.length>Ec;)De.shift();hn.length=0,Tc(De[De.length-1]).catch(()=>{})}async function Tm(){if(De.length===0)return null;let t=De.pop();if(t.oldContent===null)try{await Se.unlink(t.filePath)}catch{}else await Se.writeFile(t.filePath,t.oldContent,"utf-8");return hn.push(t),{tool:t.tool,filePath:t.filePath,wasCreated:t.oldContent===null}}async function Rm(){if(hn.length===0)return null;let t=hn.pop();return await Se.writeFile(t.filePath,t.newContent,"utf-8"),De.push(t),{tool:t.tool,filePath:t.filePath}}function Cm(t=10){return De.slice(-t).reverse().map(e=>({tool:e.tool,filePath:e.filePath,timestamp:e.timestamp}))}function Am(){return De.length}function Om(){return hn.length}function Nm({diskToo:t=!0}={}){if(De.length=0,hn.length=0,t){let e=Fs();Se.readdir(e).then(s=>{for(let o of s)o.endsWith(".json")&&Se.unlink(Ze.join(e,o)).catch(()=>{})}).catch(()=>{})}}function Fs(){return Ze.join(process.cwd(),".nex","history")}async function vc(t,e){if(t==null)return{inline:!0,content:t};if(Buffer.byteLength(t,"utf-8")<=Sm)return{inline:!0,content:t};let s=vm.createHash("sha256").update(t,"utf-8").digest("hex"),o=Ze.join(e,"blobs");return await Se.mkdir(o,{recursive:!0}),await Se.writeFile(Ze.join(o,s),t,"utf-8"),{inline:!1,hash:s}}async function Tc(t){let e=Fs();await Se.mkdir(e,{recursive:!0});let s=Ze.basename(t.filePath).replace(/[^a-zA-Z0-9]/g,"-"),o=`${t.timestamp}-${s}.json`,n=await vc(t.oldContent,e),r=await vc(t.newContent,e),i={tool:t.tool,filePath:t.filePath,timestamp:t.timestamp,oldContent:n.inline?{inline:!0,content:n.content}:{inline:!1,hash:n.hash},newContent:r.inline?{inline:!0,content:r.content}:{inline:!1,hash:r.hash}};await Se.writeFile(Ze.join(e,o),JSON.stringify(i),"utf-8")}async function Sc(t,e){if(!t)return null;if(t.inline)return t.content;let s=Ze.join(e,"blobs",t.hash);return Se.readFile(s,"utf-8")}async function Mm(){let t=Fs(),e;try{e=await Se.readdir(t)}catch{return 0}let s=e.filter(n=>n.endsWith(".json")).sort(),o=0;for(let n of s)try{let r=await Se.readFile(Ze.join(t,n),"utf-8"),i=JSON.parse(r),c=await Sc(i.oldContent,t),l=await Sc(i.newContent,t);De.push({tool:i.tool,filePath:i.filePath,timestamp:i.timestamp,oldContent:c,newContent:l}),o++}catch{}for(;De.length>Ec;)De.shift();return o}async function Pm(t=7){let e=Fs(),s;try{s=await Se.readdir(e)}catch{return 0}let o=Date.now()-t*24*60*60*1e3,n=s.filter(u=>u.endsWith(".json")),r=0,i=new Set,c=[];for(let u of n)try{let d=await Se.readFile(Ze.join(e,u),"utf-8"),f=JSON.parse(d);f.timestamp<o?(c.push(u),r++):(f.oldContent&&!f.oldContent.inline&&f.oldContent.hash&&i.add(f.oldContent.hash),f.newContent&&!f.newContent.inline&&f.newContent.hash&&i.add(f.newContent.hash))}catch{}for(let u of c)try{await Se.unlink(Ze.join(e,u))}catch{}let l=Ze.join(e,"blobs");try{let u=await Se.readdir(l);for(let d of u)if(!i.has(d))try{await Se.unlink(Ze.join(l,d))}catch{}}catch{}return r}var qs="nex-snapshot";function Im(t,e=process.cwd()){let s=t?`${qs}-${t.replace(/[^a-zA-Z0-9_-]/g,"-")}`:`${qs}-${Date.now()}`;try{return Dn("git status --porcelain",{cwd:e,timeout:1e4}).toString().trim()?(Dn(`git stash push -u -m "${s}"`,{cwd:e,timeout:15e3}),Dn("git stash pop",{cwd:e,timeout:1e4}),{name:s,label:s,ok:!0}):{name:s,label:s,ok:!1,error:"No changes to snapshot (working tree clean)"}}catch(o){return{name:s,label:s,ok:!1,error:o.message}}}function Rc(t=process.cwd()){try{let e=Dn("git stash list",{cwd:t,timeout:1e4}).toString().trim();return e?e.split(`
|
|
107
107
|
`).map(s=>{let o=s.match(/^stash@\{(\d+)\}:\s+(?:WIP on [^:]+:\s+\S+\s+|On \S+:\s+)(.*)/);if(!o)return null;let n=o[2].trim();return n.startsWith(qs)?{index:parseInt(o[1],10),label:n,shortName:n.replace(`${qs}-`,""),date:s}:null}).filter(Boolean):[]}catch{return[]}}function Lm(t,e=process.cwd()){try{let s=Rc(e);if(s.length===0)return{ok:!1,error:"No snapshots found"};let o;return t===void 0||t==="last"?o=s[0]:typeof t=="number"?o=s.find(n=>n.index===t):o=s.find(n=>n.label===t||n.shortName===t||n.shortName.includes(String(t))),o?(Dn(`git stash apply stash@{${o.index}}`,{cwd:e,timeout:15e3}),{ok:!0,label:o.label}):{ok:!1,error:`Snapshot not found: ${t}`}}catch(s){return{ok:!1,error:s.message}}}Cc.exports={recordChange:Em,undo:Tm,redo:Rm,getHistory:Cm,getUndoCount:Am,getRedoCount:Om,clearHistory:Nm,persistEntry:Tc,loadPersistedHistory:Mm,pruneHistory:Pm,createSnapshot:Im,listSnapshots:Rc,restoreSnapshot:Lm}});var Nt=D((Jb,Pc)=>{var ue=require("fs"),qe=require("path"),{atomicWrite:jm,withFileLockSync:Dm}=At(),Fe=[];function qn(){return qe.join(process.cwd(),".nex","skills")}function Ac(){return qe.join(process.cwd(),".nex","config.json")}function Oc(){let t=qn();return ue.existsSync(t)||ue.mkdirSync(t,{recursive:!0}),t}function _r(){let t=Ac();if(!ue.existsSync(t))return[];try{let e=JSON.parse(ue.readFileSync(t,"utf-8"));return e.skills&&Array.isArray(e.skills.disabled)?e.skills.disabled:[]}catch{return[]}}function Nc(t){let e=Ac(),s=qe.dirname(e);ue.existsSync(s)||ue.mkdirSync(s,{recursive:!0}),Dm(e,()=>{let o={};if(ue.existsSync(e))try{o=JSON.parse(ue.readFileSync(e,"utf-8"))}catch{o={}}o.skills||(o.skills={}),o.skills.disabled=t,jm(e,JSON.stringify(o,null,2))})}function Mc(t,e){let s=[];if(typeof t!="object"||t===null)return{valid:!1,errors:["Module must export an object"]};if(t.name!==void 0&&typeof t.name!="string"&&s.push("name must be a string"),t.description!==void 0&&typeof t.description!="string"&&s.push("description must be a string"),t.instructions!==void 0&&typeof t.instructions!="string"&&s.push("instructions must be a string"),t.commands!==void 0)if(!Array.isArray(t.commands))s.push("commands must be an array");else for(let o=0;o<t.commands.length;o++){let n=t.commands[o];(!n.cmd||typeof n.cmd!="string")&&s.push(`commands[${o}].cmd must be a non-empty string`),n.handler!==void 0&&typeof n.handler!="function"&&s.push(`commands[${o}].handler must be a function`)}if(t.tools!==void 0)if(!Array.isArray(t.tools))s.push("tools must be an array");else for(let o=0;o<t.tools.length;o++){let n=t.tools[o];(!n.function||!n.function.name||typeof n.function.name!="string")&&s.push(`tools[${o}].function.name must be a non-empty string`),n.execute!==void 0&&typeof n.execute!="function"&&s.push(`tools[${o}].execute must be a function`)}return{valid:s.length===0,errors:s}}function wr(t){try{let e=ue.readFileSync(t,"utf-8").trim();return e?{name:qe.basename(t,".md"),type:"prompt",filePath:t,instructions:e,commands:[],tools:[]}:null}catch{return null}}function br(t){try{let e=require(t),{valid:s,errors:o}=Mc(e,t);return s?{name:e.name||qe.basename(t,".js"),type:"script",filePath:t,description:e.description||"",instructions:e.instructions||"",commands:(e.commands||[]).map(r=>({cmd:r.cmd.startsWith("/")?r.cmd:`/${r.cmd}`,desc:r.desc||r.description||"",handler:r.handler||null})),tools:(e.tools||[]).map(r=>({type:r.type||"function",function:{name:r.function.name,description:r.function.description||"",parameters:r.function.parameters||{type:"object",properties:{}}},execute:r.execute||null}))}:(console.error(`Skill validation failed: ${t}
|
|
108
108
|
${o.join(`
|
|
109
109
|
`)}`),null)}catch(e){return console.error(`Failed to load skill: ${t}: ${e.message}`),null}}function kr(){Fe=[];let t=_r(),e=qn(),s=[];if(ue.existsSync(e))try{s=ue.readdirSync(e)}catch{s=[]}for(let n of s){let r=qe.join(e,n),i;try{i=ue.statSync(r)}catch{continue}if(!i.isFile())continue;let c=null;n.endsWith(".md")?c=wr(r):n.endsWith(".js")&&(c=br(r)),c&&(c.enabled=!t.includes(c.name),Fe.push(c))}let o=qe.join(__dirname,"skills");if(!process.env.NEX_SKIP_BUILTIN_SKILLS&&ue.existsSync(o)){let n;try{n=ue.readdirSync(o).filter(r=>r.endsWith(".md")||r.endsWith(".js"))}catch{n=[]}for(let r of n){let i=qe.join(o,r),c=qe.basename(r,qe.extname(r));if(Fe.some(d=>d.name===c))continue;let l;try{l=ue.statSync(i)}catch{continue}if(!l.isFile())continue;let u=r.endsWith(".md")?wr(i):br(i);u&&(u._builtin=!0,u.enabled=!t.includes(u.name),Fe.push(u))}}return Fe}function qm(){let t=[];for(let e of Fe)!e.enabled||!e.instructions||t.push(`[Skill: ${e.name}]
|
|
@@ -181,7 +181,7 @@ ${i.join(`
|
|
|
181
181
|
`;es.appendFileSync(Ql(),s,"utf-8")}catch{}}function Zl(t){if(!t||typeof t!="object")return{};let e={};for(let[s,o]of Object.entries(t))/key|token|password|secret|credential/i.test(s)?e[s]="***":typeof o=="string"&&o.length>500?e[s]=o.substring(0,500)+`... (${o.length} chars)`:e[s]=o;return e}function eu(t={}){let e=Vl(),s=t.days||1,o=[];for(let n=0;n<s;n++){let r=t.date||new Date(Date.now()-n*864e5).toISOString().split("T")[0],i=Yr.join(e,`${r}.jsonl`);if(!es.existsSync(i))continue;let c=es.readFileSync(i,"utf-8").split(`
|
|
182
182
|
`).filter(l=>l.trim());for(let l of c)try{let u=JSON.parse(l);if(t.tool&&u.tool!==t.tool)continue;o.push(u)}catch{}if(t.date)break}return o}function qg(t=1){let e=eu({days:t});if(e.length===0)return{totalCalls:0,byTool:{},avgDuration:0,successRate:1};let s={},o=0,n=0;for(let r of e)s[r.tool]=(s[r.tool]||0)+1,o+=r.duration||0,r.success&&n++;return{totalCalls:e.length,byTool:s,avgDuration:Math.round(o/e.length),successRate:n/e.length}}function Fg(t){Xr=t}function Ug(){return Xr}function Wg(){Xt=null}tu.exports={logToolExecution:Dg,sanitizeArgs:Zl,readAuditLog:eu,getAuditSummary:qg,setAuditEnabled:Fg,isAuditEnabled:Ug,getAuditLogPath:Ql,_reset:Wg}});var rt=D((h_,fu)=>{var _e=require("fs").promises,nu=require("fs"),le=require("path"),ce=require("util").promisify(require("child_process").exec),su=require("util").promisify(require("child_process").execFile),{spawnSync:Bg}=require("child_process"),Vr=require("axios"),{isForbidden:Hg,isDangerous:Gg,isCritical:ou,confirm:it}=je(),{showClaudeDiff:co,showClaudeNewFile:Kg,showEditDiff:p_,confirmFileChange:ts}=bc(),{C:F,Spinner:zg,getToolSpinnerText:Yg}=ye(),{isGitRepo:Qr,getCurrentBranch:ru,getStatus:Xg,getDiff:Jg}=Kt(),{recordChange:lo}=yt(),{fuzzyFindText:iu,findMostSimilar:os}=Qc(),{runDiagnostics:ns}=el(),{findFileInIndex:Vg,getFileIndex:m_}=Nr(),{resolveProfile:et,sshExec:Ue,scpUpload:Qg,scpDownload:Zg}=wn(),{resolveDeployConfig:e$,loadDeployConfigs:t$}=Lr(),{getEditMode:au}=eo(),n$=/^(vim?|nano|emacs|pico|less|more|top|htop|iftop|iotop|glances|telnet\s|screen|tmux|fzf|gum|dialog|whiptail|man\s|node\s*$|python3?\s*$|irb\s*$|rails\s*c|psql\s|mysql\s|redis-cli|mongosh?|sqlite3)\b/,s$=/^ssh\s/,o$=/^ssh(?:\s+-\S+)*\s+\S+@?\S+\s+["']?[^-]/;async function tt(t){return _e.access(t).then(()=>!0).catch(()=>!1)}async function uo(t){if(!t)return{fixedPath:null,message:""};let e=t.replace(/\/+/g,"/").replace(/^~\//,`${require("os").homedir()}/`),s=We(e);if(s&&await tt(s))return{fixedPath:s,message:`(auto-fixed path: ${t} \u2192 ${e})`};let o=[".js",".ts",".jsx",".tsx",".mjs",".cjs",".json"],n=le.extname(t);if(!n)for(let i of o){let c=We(t+i);if(c&&await tt(c))return{fixedPath:c,message:`(auto-fixed: added ${i} extension)`}}if(n){let i=t.replace(/\.[^.]+$/,"");for(let c of o){if(c===n)continue;let l=We(i+c);if(l&&await tt(l))return{fixedPath:l,message:`(auto-fixed: ${n} \u2192 ${c})`}}}let r=le.basename(t);if(r&&r.length>2)try{let i=Vg(r).map(c=>We(c));if(i.length===1)return{fixedPath:i[0],message:`(auto-fixed: found ${r} at ${le.relative(process.cwd(),i[0])})`};if(i.length>1&&i.length<=5)return{fixedPath:null,message:`File not found. Did you mean one of:
|
|
183
183
|
${i.map(l=>le.relative(process.cwd(),l)).map(l=>` - ${l}`).join(`
|
|
184
|
-
`)}`}}catch{}return{fixedPath:null,message:""}}function r$(t){return/\bprintenv\b/.test(t)?"printenv exposes all secrets. Use `echo $VAR_NAME` for a single variable, or `env | grep PATTERN` for filtered output.":/cat\s+.*\.env\b/.test(t)?'Reading .env directly is blocked. Use `grep -v "KEY=" .env` to inspect non-secret entries, or ask the user to share specific values.':/cat\s+.*credentials/i.test(t)?"Credentials files are blocked. Reference the variable name from the application config instead.":/python3?\s+-c\s/.test(t)?"Inline python -c is blocked. Write a temporary script file and run it with `python3 script.py` instead.":/node\s+-e\s/.test(t)?"Inline node -e is blocked. Write a temporary script file and run it with `node script.js` instead.":/curl.*-X\s*POST|curl.*--data/.test(t)?"curl POST is blocked to prevent data exfiltration. Use the application's own API client or ask the user to run the request.":/base64.*\|.*bash/.test(t)?"Piping base64-decoded content to bash is blocked. Decode the content first, inspect it, then run explicitly.":/\beval\s*\(/.test(t)?"eval is blocked. Execute the command directly without eval.":/(?:^|[;&|]\s*)history(?:\s|$)/.test(t)?"Shell history is blocked. Look at git log or project files for context instead.":""}function uu(t,e){let s=[];if(/command not found|not recognized/i.test(t)){let o=e.match(/^(\S+)/),n=o?o[1]:"";/^(npx|npm|node|yarn|pnpm|bun)$/.test(n)?s.push("HINT: Node.js/npm may not be in PATH. Check your Node.js installation."):/^(python|python3|pip|pip3)$/.test(n)?s.push("HINT: Python may not be installed. Try: brew install python3 (macOS) or apt install python3 (Linux)"):s.push(`HINT: "${n}" is not installed. Try installing it with your package manager.`)}if(/Cannot find module|MODULE_NOT_FOUND/i.test(t)){let o=t.match(/Cannot find module '([^']+)'/),n=o?o[1]:"";n&&!n.startsWith(".")&&!n.startsWith("/")?s.push(`HINT: Missing npm package "${n}". Run: npm install ${n}`):s.push("HINT: Module not found. Check the import path or run npm install.")}if(/permission denied|EACCES/i.test(t)&&s.push("HINT: Permission denied. Check file permissions or try a different approach."),/EADDRINUSE|address already in use/i.test(t)){let o=t.match(/port (\d+)|:(\d+)/),n=o?o[1]||o[2]:"";s.push(`HINT: Port ${n||""} is already in use. Kill the process or use a different port.`)}if(/SyntaxError|Unexpected token/i.test(t)&&s.push("HINT: Syntax error in the code. Check the file at the line number shown above."),/TS\d{4}:/i.test(t)&&s.push("HINT: TypeScript compilation error. Fix the type issue at the indicated line."),/Test Suites:.*failed|Tests:.*failed/i.test(t)&&s.push("HINT: Test failures detected. Read the error output above to identify failing tests."),/fatal: not a git repository/i.test(t)&&s.push("HINT: Not inside a git repository. Run git init or cd to a git project."),/^curl\b/.test(e)){let o=t.match(/curl:\s*\((\d+)\)/),n=o?parseInt(o[1],10):null;n===6||/Could not resolve host/i.test(t)?s.push("HINT: Hostname could not be resolved. Check DNS or use an IP address directly."):n===7||/Failed to connect|Connection refused/i.test(t)?s.push("HINT: Service not running or port wrong. Check if the service is up and the port is correct."):n===22||/HTTP error/i.test(t)?s.push("HINT: HTTP 4xx/5xx response. The endpoint exists but returned an error status."):n===28||/timed out/i.test(t)?s.push("HINT: Request timed out. The host may be unreachable or the service is slow."):(n===35||/SSL.*error/i.test(t))&&s.push("HINT: SSL/TLS handshake failed. Try with --insecure to bypass, or check the certificate.")}if(/remote port forwarding failed/i.test(t)){let o=t.match(/port (\d+)/),n=o?o[1]:"";s.push(`HINT: SSH remote port forwarding failed for port ${n}. The port may already be bound on the server. Check with: ssh server "ss -tuln | grep ${n}" and kill any lingering process with that port.`)}return/bind.*Cannot assign requested address|Address already in use/i.test(t)&&s.push("HINT: Port is already in use. Find the process with: ss -tuln | grep <port> and kill it, then retry."),/Connection.*timed out|ssh.*timeout/i.test(t)&&/^ssh\b/.test(e)&&s.push("HINT: SSH connection timed out. Check if the host is reachable: ping <host> and verify the port with: nc -zv <host> 22"),/cp.*\$f.*\$f\.bak.*sed.*-i\.bak|sed.*-i\.bak.*cp.*\$f.*\$f\.bak/i.test(e)&&s.push('HINT: Using both cp with .bak and sed -i.bak creates double backups (.bak.bak). Choose one method: either cp "$f" "$f.bak" OR sed -i.bak, not both.'),s.length===0?t:t+`
|
|
184
|
+
`)}`}}catch{}return{fixedPath:null,message:""}}function r$(t){return/\bprintenv\b/.test(t)?"printenv exposes all secrets. Use `echo $VAR_NAME` for a single variable, or `env | grep PATTERN` for filtered output.":/cat\s+.*\.env\b/.test(t)?'Reading .env directly is blocked. Use `grep -v "KEY=" .env` to inspect non-secret entries, or ask the user to share specific values.':/cat\s+.*credentials/i.test(t)?"Credentials files are blocked. Reference the variable name from the application config instead.":/python3?\s+-c\s/.test(t)?"Inline python -c is blocked. Write a temporary script file and run it with `python3 script.py` instead.":/node\s+-e\s/.test(t)?"Inline node -e is blocked. Write a temporary script file and run it with `node script.js` instead.":/curl.*-X\s*POST|curl.*--data/.test(t)?"curl POST is blocked to prevent data exfiltration. Use the application's own API client or ask the user to run the request.":/base64.*\|.*bash/.test(t)?"Piping base64-decoded content to bash is blocked. Decode the content first, inspect it, then run explicitly.":/\beval\s*\(/.test(t)?"eval is blocked. Execute the command directly without eval.":/(?:^|[;&|]\s*)history(?:\s|$)/.test(t)?"Shell history is blocked. Look at git log or project files for context instead.":""}function uu(t,e){let s=[];if(/command not found|: not found|not recognized/i.test(t)){let o=e.match(/^(\S+)/),n=o?o[1]:"";/^(npx|npm|node|yarn|pnpm|bun)$/.test(n)?s.push("HINT: Node.js/npm may not be in PATH. Check your Node.js installation."):/^(python|python3|pip|pip3)$/.test(n)?s.push("HINT: Python may not be installed. Try: brew install python3 (macOS) or apt install python3 (Linux)"):s.push(`HINT: "${n}" is not installed. Try installing it with your package manager.`)}if(/Cannot find module|MODULE_NOT_FOUND/i.test(t)){let o=t.match(/Cannot find module '([^']+)'/),n=o?o[1]:"";n&&!n.startsWith(".")&&!n.startsWith("/")?s.push(`HINT: Missing npm package "${n}". Run: npm install ${n}`):s.push("HINT: Module not found. Check the import path or run npm install.")}if(/permission denied|EACCES/i.test(t)&&s.push("HINT: Permission denied. Check file permissions or try a different approach."),/EADDRINUSE|address already in use/i.test(t)){let o=t.match(/port (\d+)|:(\d+)/),n=o?o[1]||o[2]:"";s.push(`HINT: Port ${n||""} is already in use. Kill the process or use a different port.`)}if(/SyntaxError|Unexpected token/i.test(t)&&s.push("HINT: Syntax error in the code. Check the file at the line number shown above."),/TS\d{4}:/i.test(t)&&s.push("HINT: TypeScript compilation error. Fix the type issue at the indicated line."),/Test Suites:.*failed|Tests:.*failed/i.test(t)&&s.push("HINT: Test failures detected. Read the error output above to identify failing tests."),/fatal: not a git repository/i.test(t)&&s.push("HINT: Not inside a git repository. Run git init or cd to a git project."),/^curl\b/.test(e)){let o=t.match(/curl:\s*\((\d+)\)/),n=o?parseInt(o[1],10):null;n===6||/Could not resolve host/i.test(t)?s.push("HINT: Hostname could not be resolved. Check DNS or use an IP address directly."):n===7||/Failed to connect|Connection refused/i.test(t)?s.push("HINT: Service not running or port wrong. Check if the service is up and the port is correct."):n===22||/HTTP error/i.test(t)?s.push("HINT: HTTP 4xx/5xx response. The endpoint exists but returned an error status."):n===28||/timed out/i.test(t)?s.push("HINT: Request timed out. The host may be unreachable or the service is slow."):(n===35||/SSL.*error/i.test(t))&&s.push("HINT: SSL/TLS handshake failed. Try with --insecure to bypass, or check the certificate.")}if(/remote port forwarding failed/i.test(t)){let o=t.match(/port (\d+)/),n=o?o[1]:"";s.push(`HINT: SSH remote port forwarding failed for port ${n}. The port may already be bound on the server. Check with: ssh server "ss -tuln | grep ${n}" and kill any lingering process with that port.`)}return/bind.*Cannot assign requested address|Address already in use/i.test(t)&&s.push("HINT: Port is already in use. Find the process with: ss -tuln | grep <port> and kill it, then retry."),/Connection.*timed out|ssh.*timeout/i.test(t)&&/^ssh\b/.test(e)&&s.push("HINT: SSH connection timed out. Check if the host is reachable: ping <host> and verify the port with: nc -zv <host> 22"),/cp.*\$f.*\$f\.bak.*sed.*-i\.bak|sed.*-i\.bak.*cp.*\$f.*\$f\.bak/i.test(e)&&s.push('HINT: Using both cp with .bak and sed -i.bak creates double backups (.bak.bak). Choose one method: either cp "$f" "$f.bak" OR sed -i.bak, not both.'),s.length===0?t:t+`
|
|
185
185
|
|
|
186
186
|
`+s.join(`
|
|
187
187
|
`)}function du(t,e,s){let o=os(t,e);if(!o)return null;let n=Math.max(2,Math.ceil(e.length*.03));return o.distance>n?null:{autoFixed:!0,matchText:o.text,content:t.split(o.text).join(s),distance:o.distance,line:o.line}}var cu=!1,Jt=null;function i$(){Jt&&(Jt(),Jt=null)}var ei=null;function a$(t){ei=t}async function Zr(){if(!cu){cu=!0;try{let{stdout:t}=await ce("git rev-parse --is-inside-work-tree",{cwd:process.cwd(),timeout:5e3});if(!(t.trim()==="true"))return;await ce('git stash push -m "nex-code-checkpoint" --include-untracked',{cwd:process.cwd(),timeout:1e4}),await ce("git stash pop",{cwd:process.cwd(),timeout:1e4}),await ce("git tag -f nex-checkpoint",{cwd:process.cwd(),timeout:5e3})}catch{}}}var c$=[/\.ssh\//i,/\.gnupg\//i,/\.aws\//i,/\.config\/gcloud/i,/\/etc\/shadow/,/\/etc\/passwd/,/\/etc\/sudoers/,/\.env(?:\.|$)/,/credentials/i,/\.npmrc$/,/\.docker\/config\.json/,/\.kube\/config/];function We(t){let e=le.isAbsolute(t)?le.resolve(t):le.resolve(process.cwd(),t);for(let s of c$)if(s.test(e))return null;return e}var l$=[{type:"function",function:{name:"bash",description:"Execute a bash command in the project directory. Timeout: 90s. Use for: running tests, installing packages, git commands, build tools, starting servers. Do NOT use bash for file operations when a dedicated tool exists \u2014 use read_file instead of cat, edit_file instead of sed, glob instead of find, grep instead of grep/rg. Always quote paths with spaces. Prefer specific commands over rm -rf. Destructive or dangerous commands require user confirmation.",parameters:{type:"object",properties:{command:{type:"string",description:"The bash command to execute"}},required:["command"]}}},{type:"function",function:{name:"read_file",description:"Read a file's contents with line numbers. Always read a file BEFORE editing it to see exact content. Use line_start/line_end for large files to read specific sections. Prefer this over bash cat/head/tail. Files are read with UTF-8 encoding. For binary files, use bash with appropriate flags. Alternative: use util.promisify(fs.readFile) for programmatic access.",parameters:{type:"object",properties:{path:{type:"string",description:"File path (relative or absolute)"},line_start:{type:"number",description:"Start line (1-based, optional)"},line_end:{type:"number",description:"End line (1-based, optional)"}},required:["path"]}}},{type:"function",function:{name:"write_file",description:"Create a new file or completely overwrite an existing file. For targeted changes to existing files, prefer edit_file or patch_file instead \u2014 they only send the diff and are safer. Only use write_file when creating new files or when the entire content needs to be replaced.",parameters:{type:"object",properties:{path:{type:"string",description:"File path"},content:{type:"string",description:"Full file content"}},required:["path","content"]}}},{type:"function",function:{name:"edit_file",description:"Replace specific text in a file. IMPORTANT: old_text must match the file content EXACTLY \u2014 including all whitespace, indentation (tabs vs spaces), and newlines. Always read_file first to see the exact content before editing. If old_text is not found, the edit fails. For multiple changes to the same file, prefer patch_file instead.",parameters:{type:"object",properties:{path:{type:"string",description:"File path"},old_text:{type:"string",description:"Exact text to find (must match file content precisely)"},new_text:{type:"string",description:"Replacement text"}},required:["path","old_text","new_text"]}}},{type:"function",function:{name:"list_directory",description:"List files and directories in a tree view. Use this to understand project structure. For finding specific files by pattern, prefer glob instead.",parameters:{type:"object",properties:{path:{type:"string",description:"Directory path"},max_depth:{type:"number",description:"Max depth (default: 2)"},pattern:{type:"string",description:"File filter glob (e.g. '*.js')"}},required:["path"]}}},{type:"function",function:{name:"search_files",description:"Search for a text pattern across files (regex). Returns matching lines with file paths. For simple content search, grep is equivalent. For finding files by name, use glob instead.",parameters:{type:"object",properties:{path:{type:"string",description:"Directory to search"},pattern:{type:"string",description:"Search pattern (regex)"},file_pattern:{type:"string",description:"File filter (e.g. '*.js')"}},required:["path","pattern"]}}},{type:"function",function:{name:"glob",description:"Find files matching a glob pattern. Fast file search by name/extension. Use this to find files before reading them. Examples: '**/*.test.js' (all test files), 'src/**/*.ts' (all TypeScript in src). Prefer this over bash find/ls.",parameters:{type:"object",properties:{pattern:{type:"string",description:"Glob pattern (e.g. '**/*.ts', 'src/**/*.test.js')"},path:{type:"string",description:"Base directory (default: project root)"}},required:["pattern"]}}},{type:"function",function:{name:"grep",description:"Search file contents with regex. Returns matching lines with file paths and line numbers. Supports output modes (content/files_with_matches/count), context lines, head_limit, offset, type filter, and multiline. Prefer this over bash grep/rg.",parameters:{type:"object",properties:{pattern:{type:"string",description:"Regex pattern to search for"},path:{type:"string",description:"Directory or file to search (default: project root)"},include:{type:"string",description:"File filter glob (e.g. '*.js', '*.ts')"},ignore_case:{type:"boolean",description:"Case-insensitive search"},output_mode:{type:"string",enum:["content","files_with_matches","count"],description:"Output mode: content (matching lines), files_with_matches (file paths only), count (match counts). Default: content"},context:{type:"number",description:"Lines of context around each match (like grep -C)"},before_context:{type:"number",description:"Lines before each match (like grep -B)"},after_context:{type:"number",description:"Lines after each match (like grep -A)"},head_limit:{type:"number",description:"Limit output to first N results"},offset:{type:"number",description:"Skip first N results"},type:{type:"string",description:"File type filter (e.g. 'js', 'py', 'ts') \u2014 maps to --include='*.ext'"},multiline:{type:"boolean",description:"Enable multiline matching (grep -Pz)"}},required:["pattern"]}}},{type:"function",function:{name:"patch_file",description:"Apply multiple text replacements to a file atomically. All patches are validated before any are applied \u2014 if one fails, none are written. Prefer this over multiple edit_file calls when making several changes to the same file. Like edit_file, all old_text values must match exactly.",parameters:{type:"object",properties:{path:{type:"string",description:"File path"},patches:{type:"array",description:"Array of { old_text, new_text } replacements to apply in order",items:{type:"object",properties:{old_text:{type:"string",description:"Text to find"},new_text:{type:"string",description:"Replacement text"}},required:["old_text","new_text"]}}},required:["path","patches"]}}},{type:"function",function:{name:"web_fetch",description:"Fetch content from a URL and return text. HTML tags are stripped. Use for reading documentation, API responses, or web pages. Will not work with authenticated/private URLs.",parameters:{type:"object",properties:{url:{type:"string",description:"URL to fetch"},max_length:{type:"number",description:"Max response length in chars (default: 10000)"}},required:["url"]}}},{type:"function",function:{name:"web_search",description:"Search the web. Uses Perplexity (grounded, AI-summarized) if PERPLEXITY_API_KEY is set, otherwise DuckDuckGo. Returns titles, URLs, and summaries. Use to find documentation, solutions, or current information beyond your knowledge cutoff.",parameters:{type:"object",properties:{query:{type:"string",description:"Search query"},max_results:{type:"number",description:"Max results (default: 5)"}},required:["query"]}}},{type:"function",function:{name:"browser_open",description:"Open a URL in a headless browser and return the page title, text content, and links. More reliable than web_fetch for JavaScript-heavy pages. Requires playwright (npm install playwright && npx playwright install chromium).",parameters:{type:"object",properties:{url:{type:"string",description:"URL to open"},wait_for:{type:"string",enum:["domcontentloaded","networkidle","load"],description:"When to consider page loaded (default: domcontentloaded)"}},required:["url"]}}},{type:"function",function:{name:"browser_screenshot",description:"Take a screenshot of a URL in a headless browser. Returns the screenshot file path. The path can be pasted into the next message for visual analysis. Requires playwright.",parameters:{type:"object",properties:{url:{type:"string",description:"URL to screenshot"},full_page:{type:"boolean",description:"Capture full page (default: false \u2014 viewport only)"},width:{type:"number",description:"Viewport width in px (default: 1280)"},height:{type:"number",description:"Viewport height in px (default: 800)"}},required:["url"]}}},{type:"function",function:{name:"browser_click",description:"Click an element on a web page (by CSS selector or visible text). Returns the new URL after navigation. Requires playwright.",parameters:{type:"object",properties:{url:{type:"string",description:"URL to navigate to first"},selector:{type:"string",description:"CSS selector of element to click (mutually exclusive with text)"},text:{type:"string",description:"Visible text of element to click (mutually exclusive with selector)"}},required:["url"]}}},{type:"function",function:{name:"browser_fill",description:"Fill a form field on a web page and optionally submit. Requires playwright.",parameters:{type:"object",properties:{url:{type:"string",description:"URL to navigate to first"},selector:{type:"string",description:"CSS selector of the input field"},value:{type:"string",description:"Value to fill in"},submit:{type:"boolean",description:"Press Enter to submit after filling (default: false)"}},required:["url","selector","value"]}}},{type:"function",function:{name:"ask_user",description:"Ask the user a clarifying question with 2-3 specific options. Use when the user's intent is ambiguous. Always provide concrete, actionable options. The user can select an option or type a custom answer.",parameters:{type:"object",properties:{question:{type:"string",description:"The clarifying question to ask"},options:{type:"array",items:{type:"string"},description:"2-3 specific, actionable answer options for the user to choose from",minItems:1,maxItems:3}},required:["question","options"]}}},{type:"function",function:{name:"git_status",description:"Get git status: current branch, changed files, staged/unstaged state. Use before git operations to understand the current state.",parameters:{type:"object",properties:{},required:[]}}},{type:"function",function:{name:"git_diff",description:"Get git diff for changed files. Shows additions and deletions.",parameters:{type:"object",properties:{staged:{type:"boolean",description:"Show only staged changes (default: false)"},file:{type:"string",description:"Diff specific file only (optional)"}},required:[]}}},{type:"function",function:{name:"git_log",description:"Show recent git commits (short format).",parameters:{type:"object",properties:{count:{type:"number",description:"Number of commits to show (default: 10)"},file:{type:"string",description:"Show commits for specific file (optional)"}},required:[]}}},{type:"function",function:{name:"task_list",description:"Create and manage a task list for complex multi-step tasks. Use for tasks with 3+ steps to track progress. Actions: create (new list with tasks), update (mark task in_progress/done/failed), get (view current list). Always update task status as you work.",parameters:{type:"object",properties:{action:{type:"string",enum:["create","update","get"],description:"Action to perform"},name:{type:"string",description:"Task list name (for create)"},tasks:{type:"array",description:"Array of tasks to create (for create)",items:{type:"object",properties:{description:{type:"string",description:"Task description"},depends_on:{type:"array",items:{type:"string"},description:"IDs of prerequisite tasks"}},required:["description"]}},task_id:{type:"string",description:"Task ID to update (for update)"},status:{type:"string",enum:["in_progress","done","failed"],description:"New status (for update)"},result:{type:"string",description:"Result summary (for update, optional)"}},required:["action"]}}},{type:"function",function:{name:"gh_run_list",description:"List recent GitHub Actions workflow runs for this repository. Shows run status, conclusion, branch, and timing. Use to check CI/CD status or find a run ID.",parameters:{type:"object",properties:{limit:{type:"number",description:"Number of runs to show (default: 10, max: 30)"},workflow:{type:"string",description:"Filter by workflow name or filename (optional)"},branch:{type:"string",description:"Filter by branch name (optional)"},status:{type:"string",enum:["completed","in_progress","queued","failure","success"],description:"Filter by status (optional)"}},required:[]}}},{type:"function",function:{name:"gh_run_view",description:"View details of a specific GitHub Actions workflow run: steps, logs, errors. Use gh_run_list first to get the run ID.",parameters:{type:"object",properties:{run_id:{type:"string",description:"The run ID (from gh_run_list)"},log:{type:"boolean",description:"Include full log output (default: false \u2014 shows step summary only)"}},required:["run_id"]}}},{type:"function",function:{name:"gh_workflow_trigger",description:"Trigger a GitHub Actions workflow dispatch event. Only works for workflows with workflow_dispatch trigger. Requires user confirmation.",parameters:{type:"object",properties:{workflow:{type:"string",description:"Workflow filename (e.g. ci.yml) or name"},branch:{type:"string",description:"Branch to run on (default: current branch)"},inputs:{type:"object",description:"Workflow input parameters as key-value pairs (optional)"}},required:["workflow"]}}},{type:"function",function:{name:"spawn_agents",description:"Run multiple independent sub-agents in parallel (max 5 at top level, max 2 when called from within a sub-agent). Each agent has its own conversation context. Use when 2+ tasks can run simultaneously \u2014 e.g. reading multiple files, analyzing separate modules, independent research. Do NOT use for tasks that depend on each other or modify the same file. Keep task descriptions specific and self-contained. SWARM PATTERN: Sub-agents can call spawn_agents once (max nesting depth 2) to enable Architect\u2192Coder\u2192Reviewer pipelines: a coder agent spawns 1-2 reviewer agents that validate and fix its own output before returning results to the parent.",parameters:{type:"object",properties:{agents:{type:"array",description:"Array of agent definitions to run in parallel (max 5)",items:{type:"object",properties:{task:{type:"string",description:"Task description for the agent"},context:{type:"string",description:"Additional context (optional)"},max_iterations:{type:"number",description:"Max iterations (default: 10, max: 15)"},model:{type:"string",description:'Override model for this agent (provider:model, e.g. "anthropic:claude-haiku"). Auto-selected if omitted.'}},required:["task"]}}},required:["agents"]}}},{type:"function",function:{name:"switch_model",description:"Switch the active AI model mid-conversation. Use when a different model is better for the next steps \u2014 e.g. switch to a fast model for simple lookups, or a more capable model for complex refactoring. The switch persists for all subsequent turns.",parameters:{type:"object",properties:{model:{type:"string",description:'Model spec: "provider:model" (e.g. "ollama:devstral-small-2:24b") or just model name'}},required:["model"]}}},{type:"function",function:{name:"k8s_pods",description:"List Kubernetes pods. Shows pod name, status, restarts, and age. Runs kubectl locally or via SSH on a remote server. Use namespace to filter, or omit for all namespaces.",parameters:{type:"object",properties:{namespace:{type:"string",description:"Namespace to list pods in (default: all namespaces)"},label:{type:"string",description:'Label selector filter (e.g. "app=nginx")'},context:{type:"string",description:"kubectl context to use (optional)"},server:{type:"string",description:"Remote server as user@host to run kubectl via SSH (optional, local kubectl if omitted)"}},required:[]}}},{type:"function",function:{name:"k8s_logs",description:'Fetch logs from a Kubernetes pod. Use tail to limit output, since for time-based filtering (e.g. "1h", "30m").',parameters:{type:"object",properties:{pod:{type:"string",description:"Pod name"},namespace:{type:"string",description:"Namespace (default: default)"},container:{type:"string",description:"Container name (required if pod has multiple containers)"},tail:{type:"number",description:"Number of recent lines to show (default: 100)"},since:{type:"string",description:'Show logs since duration (e.g. "1h", "30m", "5s")'},context:{type:"string",description:"kubectl context (optional)"},server:{type:"string",description:"Remote server user@host (optional)"}},required:["pod"]}}},{type:"function",function:{name:"k8s_exec",description:"Execute a command inside a running Kubernetes pod (kubectl exec). Requires user confirmation. Use for inspecting container state, reading configs, or debugging.",parameters:{type:"object",properties:{pod:{type:"string",description:"Pod name"},command:{type:"string",description:'Command to run in the pod (e.g. "env", "ls /app", "cat /etc/config.yaml")'},namespace:{type:"string",description:"Namespace (default: default)"},container:{type:"string",description:"Container name (optional)"},context:{type:"string",description:"kubectl context (optional)"},server:{type:"string",description:"Remote server user@host (optional)"}},required:["pod","command"]}}},{type:"function",function:{name:"k8s_apply",description:"Apply a Kubernetes manifest file (kubectl apply -f). Requires confirmation before applying to the cluster. Use dry_run=true to validate without applying.",parameters:{type:"object",properties:{file:{type:"string",description:"Path to manifest YAML file (relative or absolute)"},namespace:{type:"string",description:"Override namespace (optional)"},dry_run:{type:"boolean",description:"Validate only without applying (default: false)"},context:{type:"string",description:"kubectl context (optional)"},server:{type:"string",description:"Remote server user@host (optional)"}},required:["file"]}}},{type:"function",function:{name:"k8s_rollout",description:"Manage Kubernetes deployment rollouts: check status, restart (rolling update), view history, or undo (rollback). Restart and undo require confirmation.",parameters:{type:"object",properties:{action:{type:"string",enum:["status","restart","history","undo"],description:"Action: status (check rollout progress), restart (rolling restart), history (show revision history), undo (rollback to previous revision)"},deployment:{type:"string",description:"Deployment name"},namespace:{type:"string",description:"Namespace (default: default)"},context:{type:"string",description:"kubectl context (optional)"},server:{type:"string",description:"Remote server user@host (optional)"}},required:["action","deployment"]}}},{type:"function",function:{name:"brain_write",description:"Write or update a knowledge document in the project brain (.nex/brain/). Use this to persist important findings, architecture decisions, debugging insights, or conventions discovered during the session. The user can review changes via /brain review or git diff.",parameters:{type:"object",properties:{name:{type:"string",description:'Document name (without .md extension). Use kebab-case. Examples: "api-auth-flow", "db-schema-notes", "deployment-checklist"'},content:{type:"string",description:"Full Markdown content. Use headings (#), lists (-), and code blocks. Include optional YAML frontmatter with tags."},mode:{type:"string",enum:["create","update","append"],description:"create: new document (fails if exists). update: overwrite existing. append: add to end of existing document."}},required:["name","content","mode"]}}},{type:"function",function:{name:"ssh_exec",description:'Execute a command on a remote server via SSH. Server is a profile name from .nex/servers.json (e.g. "prod") or "user@host". Use for: checking status, reading logs, running deployments. Destructive commands (restart, delete, modify config) require confirmation. For service management prefer service_manage; for logs prefer service_logs.',parameters:{type:"object",properties:{server:{type:"string",description:'Profile name (from .nex/servers.json) or "user@host"'},command:{type:"string",description:"Shell command to run on the remote server"},sudo:{type:"boolean",description:"Run command with sudo (only if profile has sudo:true). Default: false"},timeout:{type:"number",description:"Timeout in seconds. Default: 30"}},required:["server","command"]}}},{type:"function",function:{name:"ssh_upload",description:"Upload a local file or directory to a remote server via SCP. Recursive for directories. Requires confirmation before upload.",parameters:{type:"object",properties:{server:{type:"string",description:'Profile name or "user@host"'},local_path:{type:"string",description:"Local path to upload (file or directory)"},remote_path:{type:"string",description:"Destination path on the remote server (absolute preferred)"}},required:["server","local_path","remote_path"]}}},{type:"function",function:{name:"ssh_download",description:"Download a file or directory from a remote server via SCP. Recursive for directories.",parameters:{type:"object",properties:{server:{type:"string",description:'Profile name or "user@host"'},remote_path:{type:"string",description:"Path on the remote server to download"},local_path:{type:"string",description:"Local destination path"}},required:["server","remote_path","local_path"]}}},{type:"function",function:{name:"remote_agent",description:'Delegate a coding task to nex-code running on a remote server. Use this when the task involves server-side projects (musikschule, stadtkapelle, cahill, schoensgibl, jarvis) that live on almalinux9/jarvis. Runs nex-code --auto on the server and streams output. Server is a profile name from .nex/servers.json or "user@host".',parameters:{type:"object",properties:{server:{type:"string",description:'Profile name from .nex/servers.json (e.g. "almalinux9") or "user@host"'},task:{type:"string",description:"The full task description to run on the remote nex-code"},project_path:{type:"string",description:"Working directory on the remote server (e.g. /home/jarvis/jarvis-agent). Defaults to home directory."},model:{type:"string",description:"Model to use on remote nex-code (e.g. qwen3-coder:480b). Defaults to server default."}},required:["server","task"]}}},{type:"function",function:{name:"service_manage",description:"Manage a systemd service on a remote (or local) server. Uses systemctl. Status is read-only; start/stop/restart/reload/enable/disable require confirmation. For AlmaLinux 9: runs via SSH with sudo if configured.",parameters:{type:"object",properties:{server:{type:"string",description:'Profile name or "user@host". Omit or use "local" for local machine.'},service:{type:"string",description:'Service name (e.g. "nginx", "gunicorn", "postgresql")'},action:{type:"string",enum:["status","start","stop","restart","reload","enable","disable"],description:"systemctl action to perform"}},required:["service","action"]}}},{type:"function",function:{name:"service_logs",description:"Fetch systemd service logs via journalctl. Works on AlmaLinux 9 and any systemd Linux. Read-only, no confirmation needed.",parameters:{type:"object",properties:{server:{type:"string",description:'Profile name or "user@host". Omit or use "local" for local machine.'},service:{type:"string",description:'Service name (e.g. "nginx", "gunicorn")'},lines:{type:"number",description:"Number of recent log lines to fetch. Default: 50"},since:{type:"string",description:'Time filter, e.g. "1 hour ago", "today", "2024-01-01 12:00". Optional.'},follow:{type:"boolean",description:"Tail logs in real-time (follow mode). Default: false"}},required:["service"]}}},{type:"function",function:{name:"container_list",description:"List Docker containers on a server (or locally). Shows container ID, name, image, status, and ports. Read-only, no confirmation needed.",parameters:{type:"object",properties:{server:{type:"string",description:'Profile name or "user@host". Omit or use "local" for local machine.'},all:{type:"boolean",description:"Show all containers including stopped ones. Default: false (running only)."}},required:[]}}},{type:"function",function:{name:"container_logs",description:"Fetch logs from a Docker container on a server (or locally). Read-only, no confirmation needed.",parameters:{type:"object",properties:{server:{type:"string",description:'Profile name or "user@host". Omit or use "local" for local machine.'},container:{type:"string",description:"Container name or ID."},lines:{type:"number",description:"Number of recent log lines. Default: 50."},since:{type:"string",description:'Time filter, e.g. "1h", "30m", "2024-01-01T12:00:00". Optional.'}},required:["container"]}}},{type:"function",function:{name:"container_exec",description:"Execute a command inside a running Docker container. Destructive or state-changing commands require confirmation.",parameters:{type:"object",properties:{server:{type:"string",description:'Profile name or "user@host". Omit or use "local" for local machine.'},container:{type:"string",description:"Container name or ID."},command:{type:"string",description:'Command to run inside the container (e.g. "cat /etc/nginx/nginx.conf").'}},required:["container","command"]}}},{type:"function",function:{name:"container_manage",description:'Start, stop, restart, or remove a Docker container. All actions except "inspect" require confirmation.',parameters:{type:"object",properties:{server:{type:"string",description:'Profile name or "user@host". Omit or use "local" for local machine.'},container:{type:"string",description:"Container name or ID."},action:{type:"string",enum:["start","stop","restart","remove","inspect"],description:"Action to perform on the container."}},required:["container","action"]}}},{type:"function",function:{name:"frontend_recon",description:"MANDATORY first step before creating or significantly modifying any frontend file (HTML template, Vue/React component, CSS). Scans the project and returns: (1) design tokens \u2014 CSS variables, Tailwind theme colors/fonts, (2) main layout/index page structure, (3) a reference component of the same type, (4) detected JS/CSS framework stack. Call this BEFORE writing any markup or styles. Never skip it for frontend tasks.",parameters:{type:"object",properties:{type:{type:"string",description:'Type of frontend file you are about to create. Used to find a relevant reference component. Examples: "list", "form", "detail", "dashboard", "modal", "component". Optional but improves reference quality.'}},required:[]}}},{type:"function",function:{name:"deploy",description:'Deploy to a remote server. Supports two methods: "rsync" (sync local files) and "git" (git pull on remote). Can use a named config from .nex/deploy.json. Requires confirmation before executing.',parameters:{type:"object",properties:{config:{type:"string",description:'Named deploy config from .nex/deploy.json (e.g. "prod"). Overrides all other params if provided.'},method:{type:"string",enum:["rsync","git"],description:'Deploy method: "rsync" syncs local files (default), "git" runs git pull on the remote.'},server:{type:"string",description:'Profile name or "user@host". Required if no config.'},remote_path:{type:"string",description:"Remote project directory. Required for git method; destination path for rsync."},local_path:{type:"string",description:"Local directory or file to sync. Required for rsync method."},branch:{type:"string",description:"Branch to pull (git method only). Defaults to current remote branch."},deploy_script:{type:"string",description:'Shell command(s) to run on the remote after sync/pull (e.g. "npm ci && systemctl restart myapp"). Optional.'},health_check:{type:"string",description:"URL (HTTP GET) or shell command to verify the service is healthy after deploy. If it fails, the deploy is marked as failed. Optional."},exclude:{type:"array",items:{type:"string"},description:"Paths to exclude from rsync. Optional."},dry_run:{type:"boolean",description:"Show what would happen without executing. Default: false."}},required:[]}}},{type:"function",function:{name:"deployment_status",description:"Check deployment status across all configured servers. Reads .nex/deploy.json configs and checks service health on each server. Returns a status summary table.",parameters:{type:"object",properties:{config:{type:"string",description:"Specific deploy config name to check (optional \u2014 checks all if omitted)"}},required:[]}}},{type:"function",function:{name:"sysadmin",description:"Senior sysadmin operations on a remote (or local) Linux server. Covers: system audit, disk_usage, process_list, network_status, package management (dnf/apt), user management, firewall (firewalld/ufw/iptables), cron, SSL cert checks, log tailing, large file discovery, systemd service management, process kill, journalctl log querying. Read-only actions run without confirmation; state-changing actions require user approval.",parameters:{type:"object",properties:{server:{type:"string",description:'Profile name or "user@host". Omit or use "local" for local machine.'},action:{type:"string",enum:["audit","disk_usage","process_list","network_status","package","user_manage","firewall","cron","ssl_check","log_tail","find_large","service","kill_process","journalctl"],description:"Sysadmin operation. audit=full health overview; disk_usage=df+du; process_list=top procs; network_status=open ports; package=dnf/apt; user_manage=users/keys; firewall=rules; cron=crontab; ssl_check=cert expiry+days; log_tail=tail any log; find_large=big files; service=systemd unit management; kill_process=kill by PID or name; journalctl=query system journal."},path:{type:"string",description:"File or directory path. For disk_usage (default /), log_tail (required), find_large (default /)."},lines:{type:"number",description:"Lines to tail for log_tail or journalctl. Default: 100."},limit:{type:"number",description:"Result count for process_list (default 20) or find_large (default 20)."},sort_by:{type:"string",enum:["cpu","mem"],description:"Sort order for process_list. Default: cpu."},min_size:{type:"string",description:'Minimum file size for find_large. Default: "100M". Examples: "50M", "1G".'},package_action:{type:"string",enum:["install","remove","update","list","upgrade"],description:"Package sub-action for action=package."},packages:{type:"array",items:{type:"string"},description:"Package name(s) for install/remove/update."},user_action:{type:"string",enum:["list","create","delete","add_ssh_key","info"],description:"User sub-action for action=user_manage."},user:{type:"string",description:"Linux username for user_manage or cron."},groups:{type:"array",items:{type:"string"},description:'Groups to assign on user create (e.g. ["sudo", "docker"]).'},ssh_key:{type:"string",description:"SSH public key string to add for user_action=add_ssh_key."},firewall_action:{type:"string",enum:["status","allow","deny","remove","reload"],description:"Firewall sub-action for action=firewall."},port:{type:"string",description:'Port/protocol for firewall rules, e.g. "80/tcp", "443", "8080/udp".'},cron_action:{type:"string",enum:["list","add","remove"],description:"Cron sub-action for action=cron."},schedule:{type:"string",description:'Cron schedule expression for cron add, e.g. "0 2 * * *".'},command:{type:"string",description:"Command for cron add, or substring to match for cron remove."},domain:{type:"string",description:`Domain for ssl_check (e.g. "example.com"). Auto-detects Let's Encrypt cert on server; falls back to live TLS probe.`},cert_path:{type:"string",description:'Explicit path to cert file on server for ssl_check (e.g. "/etc/letsencrypt/live/x/cert.pem").'},service_name:{type:"string",description:'Systemd unit name for action=service (e.g. "nginx", "jarvis-api", "gunicorn"). .service suffix optional.'},service_action:{type:"string",enum:["status","start","stop","restart","reload","enable","disable","list_failed"],description:"Sub-action for action=service. list_failed shows all failed units."},pid:{type:"number",description:"Process ID to kill for action=kill_process."},process_name:{type:"string",description:"Process name to kill (uses pkill) for action=kill_process. Use with pid for safety."},signal:{type:"string",enum:["SIGTERM","SIGKILL","SIGHUP","SIGINT"],description:"Signal for kill_process. Default: SIGTERM."},unit:{type:"string",description:'Systemd unit to filter for journalctl (e.g. "nginx", "jarvis-api"). Omit for system-wide.'},since:{type:"string",description:'Time filter for journalctl, e.g. "1 hour ago", "today", "2026-03-17 10:00". Default: last 200 lines.'},priority:{type:"string",enum:["emerg","alert","crit","err","warning","notice","info","debug"],description:"Minimum log priority for journalctl. Default: no filter."}},required:["action"]}}}];function ss(t,{server:e,context:s}={}){let o=e?e.replace(/[^a-zA-Z0-9@._-]/g,""):null,n=s?s.replace(/[^a-zA-Z0-9._/-]/g,""):null,r="kubectl";if(n&&(r+=` --context ${n}`),r+=` ${t}`,o){let i=r.replace(/\\/g,"\\\\").replace(/"/g,'\\"');return`ssh -o ConnectTimeout=10 -o BatchMode=yes ${o} "${i}"`}return r}async function lu(t,e,s={}){switch(t){case"bash":{let o=e.command,n=Hg(o);if(n){let d=r$(o);return`BLOCKED: Command matches forbidden pattern: ${n}${d?`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nex-code",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.62",
|
|
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"
|