novacode 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import{parseArgs as e}from"node:util";import t from"chalk";import{dirname as n,extname as r,isAbsolute as i,join as a,relative as o,resolve as s}from"node:path";import c,{homedir as l}from"node:os";import{appendFile as u,chmod as d,mkdir as f,readFile as p,readdir as m,rm as h,stat as g,writeFile as _}from"node:fs/promises";import{Box as v,Text as y,render as b,useInput as x}from"ink";import{useState as S}from"react";import{jsx as C,jsxs as w}from"react/jsx-runtime";import{spawn as T}from"node:child_process";import{glob as E}from"glob";import{fileURLToPath as ee}from"node:url";import te from"semver";function ne(e){let t=[];for(let n of e)if(n.role===`user`){let e=typeof n.content==`string`?[{text:n.content}]:n.content.map(e=>e.type===`text`?{text:e.text}:e.type===`image`?{inline_data:{mime_type:e.mime,data:e.data}}:{text:``});t.push({role:`user`,parts:e})}else if(n.role===`assistant`){let e=n.content.map(e=>e.type===`text`?{text:e.text,thought_signature:e.signature}:e.type===`thinking`?{thought:!0,text:e.text,thought_signature:e.signature}:e.type===`tool_call`?{function_call:{name:e.name,args:e.args},thought_signature:e.signature}:{text:``});t.push({role:`model`,parts:e})}else if(n.role===`tool_result`){let e={function_response:{name:n.tool,response:{content:n.content.map(e=>e.type===`text`?e.text:JSON.stringify(e)).join(`
3
- `)}}},r=t[t.length-1];r&&r.role===`user`&&r.parts.some(e=>e.function_response)?r.parts.push(e):t.push({role:`user`,parts:[e]})}return t}function re(e){return e.length===0?[]:[{function_declarations:e.map(e=>({name:e.name,description:e.description,parameters:e.parameters}))}]}const ie=e=>{let t=new D;return(async()=>{let n={in:0,out:0},r=[];try{let i=`${e.baseUrl||`https://generativelanguage.googleapis.com`}/v1beta/models/${e.model.id}:streamGenerateContent?alt=sse&key=${e.apiKey}`,a={contents:ne(e.messages),system_instruction:e.system?{parts:[{text:e.system}]}:void 0,tools:e.tools.length>0?re(e.tools):void 0,generationConfig:{thinkingConfig:e.model.supportsThinking?{thinkingLevel:`low`}:void 0}},o=await fetch(i,{method:`POST`,headers:{"Content-Type":`application/json`,"Api-Revision":`2026-05-20`},body:JSON.stringify(a),signal:e.signal});if(!o.ok){let e=await o.text(),n=e;try{let t=JSON.parse(e);n=t.error?.message||t.message||e}catch{}let r=`Gemini Error (${o.status}): ${n}`;t.push({type:`text_delta`,text:r}),t.finish({content:[{type:`text`,text:r}],usage:{in:0,out:0},stop:`error`});return}let s=o.body?.getReader();if(!s){t.finish({content:[],usage:{in:0,out:0},stop:`error`});return}let c=new TextDecoder,l=``,u=`stop`;for(;;){let{done:e,value:i}=await s.read();if(e)break;l+=c.decode(i,{stream:!0});let a=l.split(`
4
- `);l=a.pop()??``;for(let e of a){let i=e.trim();if(!i?.startsWith(`data: `))continue;let a=i.slice(6);try{let e=JSON.parse(a),i=e.candidates?.[0];if(e.usageMetadata&&(n={in:e.usageMetadata.promptTokenCount||n.in,out:e.usageMetadata.candidatesTokenCount||n.out},t.push({type:`usage`,usage:n})),!i)continue;if(i.finishReason){let e=i.finishReason;e===`STOP`?u=`stop`:e===`MAX_TOKENS`?u=`length`:(e===`SAFETY`||e===`RECITATION`||e===`OTHER`)&&(u=`error`)}let o=i.content?.parts;if(o)for(let e of o){let n=e.thought_signature||e.thoughtSignature;if(e.text)if(e.thought===!0||typeof e.thought==`string`){let n=typeof e.thought==`string`?e.thought:e.text;t.push({type:`thinking_delta`,text:n})}else{t.push({type:`text_delta`,text:e.text});let i=r[r.length-1];i?.type===`text`?i.text+=e.text:r.push({type:`text`,text:e.text,signature:n})}let i=e.functionCall||e.function_call;if(i){let e=i.name,a=i.args||{},o={type:`tool_call`,id:`call_${Math.random().toString(36).slice(2,9)}`,name:e,args:a,signature:n};r.push(o),t.push({type:`tool_call`,call:o}),u=`tool_use`}}}catch{a.trim()!==``&&a.trim()}}}t.finish({content:r,usage:n,stop:u})}catch(i){if(e.signal?.aborted){t.finish({content:r,usage:n,stop:`aborted`});return}let a=`Gemini Network/Request Error: ${i instanceof Error?i.message:String(i)}`;t.push({type:`text_delta`,text:a}),t.finish({content:[{type:`text`,text:a}],usage:{in:0,out:0},stop:`error`})}})(),t};function ae(e){if(e.role===`user`)return{role:`user`,content:typeof e.content==`string`?e.content:e.content.map(e=>e.type===`text`?{type:`text`,text:e.text}:e.type===`image`?{type:`image_url`,image_url:{url:`data:${e.mime};base64,${e.data}`}}:{type:`text`,text:``})};if(e.role===`assistant`){let t=[],n=[];for(let r of e.content)r.type===`text`&&t.push(r.text),r.type===`tool_call`&&n.push({type:`function`,id:r.id,function:{name:r.name,arguments:JSON.stringify(r.args)}});let r={role:`assistant`,content:t.length>0?t.join(``):null};return n.length>0&&(r.tool_calls=n),r}return e.role===`tool_result`?{role:`tool`,tool_call_id:e.callId,content:e.content.map(e=>e.type===`text`?e.text:JSON.stringify(e)).join(`
5
- `)}:{role:`user`,content:``}}function oe(e){return e.map(e=>({type:`function`,function:{name:e.name,description:e.description,parameters:e.parameters}}))}const se=e=>{let t=new D;return(async()=>{let n=``,r=new Map,i={in:0,out:0};try{let a={model:e.model.id,messages:[{role:`system`,content:e.system},...e.messages.map(ae)],tools:e.tools.length>0?oe(e.tools):void 0,stream:!0},o=await fetch(`${e.baseUrl}/chat/completions`,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${e.apiKey}`},body:JSON.stringify(a),signal:e.signal});if(!o.ok){let e=await o.text(),n=`API error ${o.status}: ${e}`;t.push({type:`text_delta`,text:n}),t.finish({content:[{type:`text`,text:n}],usage:{in:0,out:0},stop:`error`});return}let s=o.body?.getReader();if(!s){t.finish({content:[],usage:{in:0,out:0},stop:`error`});return}let c=new TextDecoder,l=``,u=`stop`;for(;;){let{done:e,value:a}=await s.read();if(e)break;l+=c.decode(a,{stream:!0});let o=l.split(`
6
- `);l=o.pop()??``;for(let e of o){let a=e.trim();if(!a?.startsWith(`data: `))continue;let o=a.slice(6);if(o!==`[DONE]`)try{let e=JSON.parse(o),a=e.choices?.[0]?.delta;if(!a)continue;a.content&&(t.push({type:`text_delta`,text:a.content}),n+=a.content);let s=a.reasoning_content||a.reasoning||a.thinking;if(s&&t.push({type:`thinking_delta`,text:s}),a.tool_calls)for(let e of a.tool_calls){let t=e.index??0;r.has(t)||r.set(t,{id:e.id??``,name:e.function?.name??``,args:``});let n=r.get(t);e.id&&(n.id=e.id),e.function?.name&&(n.name=e.function.name),e.function?.arguments&&(n.args+=e.function.arguments)}e.usage&&(i={in:e.usage.prompt_tokens??0,out:e.usage.completion_tokens??0},t.push({type:`usage`,usage:i}));let c=e.choices?.[0]?.finish_reason;c&&(u=c)}catch{}}}let d=[];n&&d.push({type:`text`,text:n});for(let[,e]of r)d.push({type:`tool_call`,id:e.id,name:e.name,args:JSON.parse(e.args||`{}`)}),t.push({type:`tool_call`,call:{type:`tool_call`,id:e.id,name:e.name,args:JSON.parse(e.args||`{}`)}}),u=`tool_use`;t.finish({content:d,usage:i,stop:u})}catch(a){if(e.signal?.aborted){let e=[];n&&e.push({type:`text`,text:n});for(let[,t]of r)try{e.push({type:`tool_call`,id:t.id,name:t.name,args:JSON.parse(t.args||`{}`)})}catch{}t.finish({content:e,usage:i,stop:`aborted`});return}let o=`Unexpected error: ${a instanceof Error?a.message:String(a)}`;t.push({type:`text_delta`,text:o}),t.finish({content:[{type:`text`,text:o}],usage:{in:0,out:0},stop:`error`})}})(),t};var D=class{#e=[];#t=!1;#n;#r;#i;#a=!1;push(e){if(!this.#a)if(this.#r){let t=this.#r;this.#r=void 0,t(e)}else this.#e.push(e)}finish(e){this.#t=!0,this.#n=e,this.#r&&this.#r(void 0),this.#i&&this.#i(e)}abort(){this.#a=!0,this.#t=!0,this.#r&&this.#r(void 0),this.#i&&this.#i(void 0)}async*[Symbol.asyncIterator](){for(;!this.#t||this.#e.length>0;){if(this.#e.length>0){yield this.#e.shift();continue}if(this.#t)break;let e=await new Promise(e=>{this.#r=e});e!==void 0&&(yield e)}}get result(){return this.#n}get isDone(){return this.#t}};const ce=new Map([[`openai`,se],[`gemini`,ie]]);function O(e){let t=ce.get(e.api);if(!t)throw Error(`No provider registered for API format: ${e.api}`);let n=t(e),r=new D;return(async()=>{for await(let e of n)e.type===`text_delta`?r.push({type:`text_delta`,text:e.text??``}):e.type===`thinking_delta`?r.push({type:`thinking_delta`,text:e.text??``}):e.type===`tool_call`&&e.call?r.push({type:`tool_call`,call:{type:`tool_call`,id:e.call.id,name:e.call.name,args:e.call.args}}):e.type===`usage`&&e.usage&&r.push({type:`usage`,usage:e.usage});let e=n.result;e?r.finish(e):r.finish({content:[],usage:{in:0,out:0},stop:`stop`})})(),r}function k(e){let t=0;for(let n of e)if(typeof n.content==`string`)t+=n.content.length;else if(Array.isArray(n.content))for(let e of n.content)e.type===`text`&&(t+=e.text.length);return Math.ceil(t/4)}function A(e){return{type:`text`,text:e}}function j(e,t){return t===e||t.startsWith(`${e}/`)?o(e,t)||`.`:t}function le(e){if(typeof e!=`string`)return e;let t=e,n=``;if(e.startsWith(`file://`)&&(t=e.slice(7),n=`file://`),i(t)){let e=process.cwd();return n+j(e,t)}return e}function ue(e,n=!1){return e?Object.entries(e).map(([e,r])=>{let i=typeof r==`string`?le(r):JSON.stringify(r),a=i.length>40?`${i.slice(0,40)}…`:i;return`${n?t.dim(`${e}:`):`${e}:`} ${a}`}).join(` `):``}function M(e){let t=Date.now()-e,n=Math.floor(t/1e3),r=Math.floor(n/60),i=Math.floor(r/60);return n<60?`just now`:r<60?`${r}m ago`:i<24?`${i}h ago`:new Date(e).toLocaleDateString()}const de=e=>typeof e==`object`&&!!e&&e.type===`tool_call`;function fe(e,t,n,r){let i=new D,a=[],o=n.maxTurns??50,s={role:`user`,content:e,ts:Date.now()},c={...t,messages:[...t.messages,s]};return a.push(s),(async()=>{i.push({type:`start`});try{let e=0;for(;e<o&&!r?.aborted;){e++,i.push({type:`turn`});let t=k(c.messages);t>n.model.contextWindow*.9&&i.push({type:`text_delta`,text:`[warning] Approaching context limit (~${Math.round(t/1e3)}k / ${Math.round(n.model.contextWindow/1e3)}k tokens)`});let o=await pe(c,n,i,r);if(a.push(o),c={...c,messages:[...c.messages,o]},i.push({type:`assistant_msg`,msg:o}),o.stop===`error`||o.stop===`aborted`){i.push({type:`turn_end`,msg:o,results:[]});break}let s=o.content.filter(de);if(s.length===0){i.push({type:`turn_end`,msg:o,results:[]});break}let l=[];for(let e of s){if(r?.aborted)break;let t=c.tools.find(t=>t.def.name===e.name);if(!t){let t={role:`tool_result`,callId:e.id,tool:e.name,content:[A(`Unknown tool: ${e.name}`)],isError:!0,ts:Date.now()};l.push(t),c={...c,messages:[...c.messages,t]},a.push(t);continue}let o=await n.beforeTool?.(e,e.args,c);if(o?.block){let t={role:`tool_result`,callId:e.id,tool:e.name,content:[A(o.reason??`Blocked`)],isError:!0,ts:Date.now()};l.push(t),c={...c,messages:[...c.messages,t]},a.push(t);continue}let s=await t.execute(e.args,r),u={role:`tool_result`,callId:e.id,tool:e.name,args:e.args,content:s.content,isError:s.isError,ts:Date.now()};l.push(u),c={...c,messages:[...c.messages,u]},a.push(u),i.push({type:`tool_result`,callId:e.id,result:u,args:e.args}),await n.afterTool?.(e,u,c)}i.push({type:`turn_end`,msg:o,results:l})}e>=o&&i.push({type:`text_delta`,text:`[max turns reached (${o})]`})}catch(e){if(e.name===`AbortError`){i.finish(a);return}throw e}i.finish(a)})(),i}async function pe(e,t,n,r){let i=O({api:t.api,model:t.model,apiKey:t.apiKey,baseUrl:t.baseUrl,system:e.system,messages:e.messages,tools:e.tools.map(e=>e.def),signal:r}),a=[],o={in:0,out:0};for await(let e of i)if(e.type===`text_delta`&&e.text){let t=a[a.length-1];t?.type===`text`?t.text+=e.text:a.push(A(e.text)),n.push({type:`text_delta`,text:e.text})}else e.type===`thinking_delta`&&e.text?n.push({type:`thinking_delta`,text:e.text}):e.type===`tool_call`&&e.call?(a.push(e.call),n.push({type:`tool_call`,call:e.call})):e.type===`usage`&&e.usage&&(o=e.usage,n.push({type:`usage`,usage:o}));let s=i.result?.content&&i.result.content.length>0?i.result.content:a,c=s.some(e=>e.type===`tool_call`)?s.filter(e=>e.type!==`text`||e.text.trim().length>0):s,l=i.result;return l?{role:`assistant`,content:c,model:t.model.id,provider:t.model.provider,usage:l.usage,stop:l.stop,ts:Date.now()}:{role:`assistant`,content:c,model:t.model.id,provider:t.model.provider,usage:o,stop:c.some(e=>e.type===`tool_call`)?`tool_use`:`stop`,ts:Date.now()}}var me=class{#e;#t;#n;#r=[];#i;#a;#o;constructor(e){this.#e=e.api,this.#t=e.model,this.#a=e.apiKey,this.#o=e.baseUrl,this.#n=e.system,this.#i=e.tools,this.#r=e.messages??[]}get model(){return this.#t}get messages(){return this.#r}get tools(){return this.#i}get apiKey(){return this.#a}get baseUrl(){return this.#o}updateConfig(e){this.#e=e.api,this.#t=e.model,this.#a=e.apiKey,this.#o=e.baseUrl}setTools(e){this.#i=e}setMessages(e){this.#r=e}setModel(e){this.#t=e}prompt(e,t){return fe(e,{system:this.#n,messages:this.#r,tools:this.#i},{api:this.#e,model:this.#t,apiKey:this.#a,baseUrl:this.#o},t)}};function he(e,t,n=[],r){let i=t.map(e=>`- ${e.def.name}: ${e.def.description}`).join(`
2
+ import{parseArgs as e}from"node:util";import t from"chalk";import{dirname as n,extname as r,isAbsolute as i,join as a,relative as o,resolve as s}from"node:path";import c,{homedir as l}from"node:os";import{chmod as u,mkdir as d,readFile as f,readdir as p,stat as m,writeFile as h}from"node:fs/promises";import{Box as g,Text as _,render as v,useInput as y}from"ink";import{useState as b}from"react";import{jsx as x,jsxs as S}from"react/jsx-runtime";import{DatabaseSync as C}from"node:sqlite";import{mkdirSync as ee}from"node:fs";import{spawn as w}from"node:child_process";import{glob as te}from"glob";import{fileURLToPath as ne}from"node:url";import re from"semver";function ie(e){let t=[];for(let n of e)if(n.role===`user`){let e=typeof n.content==`string`?[{text:n.content}]:n.content.map(e=>e.type===`text`?{text:e.text}:e.type===`image`?{inline_data:{mime_type:e.mime,data:e.data}}:{text:``});t.push({role:`user`,parts:e})}else if(n.role===`assistant`){let e=n.content.map(e=>e.type===`text`?{text:e.text,thought_signature:e.signature}:e.type===`thinking`?{thought:!0,text:e.text,thought_signature:e.signature}:e.type===`tool_call`?{function_call:{name:e.name,args:e.args},thought_signature:e.signature}:{text:``});t.push({role:`model`,parts:e})}else if(n.role===`tool_result`){let e={function_response:{name:n.tool,response:{content:n.content.map(e=>e.type===`text`?e.text:JSON.stringify(e)).join(`
3
+ `)}}},r=t[t.length-1];r&&r.role===`user`&&r.parts.some(e=>e.function_response)?r.parts.push(e):t.push({role:`user`,parts:[e]})}return t}function ae(e){return e.length===0?[]:[{function_declarations:e.map(e=>({name:e.name,description:e.description,parameters:e.parameters}))}]}const oe=e=>{let t=new T;return(async()=>{let n={in:0,out:0},r=[];try{let i=`${e.baseUrl||`https://generativelanguage.googleapis.com`}/v1beta/models/${e.model.id}:streamGenerateContent?alt=sse&key=${e.apiKey}`,a={contents:ie(e.messages),system_instruction:e.system?{parts:[{text:e.system}]}:void 0,tools:e.tools.length>0?ae(e.tools):void 0,generationConfig:{thinkingConfig:e.model.supportsThinking?{thinkingLevel:`low`}:void 0}},o=await fetch(i,{method:`POST`,headers:{"Content-Type":`application/json`,"Api-Revision":`2026-05-20`},body:JSON.stringify(a),signal:e.signal});if(!o.ok){let e=await o.text(),n=e;try{let t=JSON.parse(e);n=t.error?.message||t.message||e}catch{}let r=`Gemini Error (${o.status}): ${n}`;t.push({type:`text_delta`,text:r}),t.finish({content:[{type:`text`,text:r}],usage:{in:0,out:0},stop:`error`});return}let s=o.body?.getReader();if(!s){t.finish({content:[],usage:{in:0,out:0},stop:`error`});return}let c=new TextDecoder,l=``,u=`stop`;for(;;){let{done:e,value:i}=await s.read();if(e)break;l+=c.decode(i,{stream:!0});let a=l.split(`
4
+ `);l=a.pop()??``;for(let e of a){let i=e.trim();if(!i?.startsWith(`data: `))continue;let a=i.slice(6);try{let e=JSON.parse(a),i=e.candidates?.[0];if(e.usageMetadata&&(n={in:e.usageMetadata.promptTokenCount||n.in,out:e.usageMetadata.candidatesTokenCount||n.out},t.push({type:`usage`,usage:n})),!i)continue;if(i.finishReason){let e=i.finishReason;e===`STOP`?u=`stop`:e===`MAX_TOKENS`?u=`length`:(e===`SAFETY`||e===`RECITATION`||e===`OTHER`)&&(u=`error`)}let o=i.content?.parts;if(o)for(let e of o){let n=e.thought_signature||e.thoughtSignature;if(e.text)if(e.thought===!0||typeof e.thought==`string`){let n=typeof e.thought==`string`?e.thought:e.text;t.push({type:`thinking_delta`,text:n})}else{t.push({type:`text_delta`,text:e.text});let i=r[r.length-1];i?.type===`text`?i.text+=e.text:r.push({type:`text`,text:e.text,signature:n})}let i=e.functionCall||e.function_call;if(i){let e=i.name,a=i.args||{},o={type:`tool_call`,id:`call_${Math.random().toString(36).slice(2,9)}`,name:e,args:a,signature:n};r.push(o),t.push({type:`tool_call`,call:o}),u=`tool_use`}}}catch{a.trim()!==``&&a.trim()}}}t.finish({content:r,usage:n,stop:u})}catch(i){if(e.signal?.aborted){t.finish({content:r,usage:n,stop:`aborted`});return}let a=`Gemini Network/Request Error: ${i instanceof Error?i.message:String(i)}`;t.push({type:`text_delta`,text:a}),t.finish({content:[{type:`text`,text:a}],usage:{in:0,out:0},stop:`error`})}})(),t};function se(e){if(e.role===`user`)return{role:`user`,content:typeof e.content==`string`?e.content:e.content.map(e=>e.type===`text`?{type:`text`,text:e.text}:e.type===`image`?{type:`image_url`,image_url:{url:`data:${e.mime};base64,${e.data}`}}:{type:`text`,text:``})};if(e.role===`assistant`){let t=[],n=[];for(let r of e.content)r.type===`text`&&t.push(r.text),r.type===`tool_call`&&n.push({type:`function`,id:r.id,function:{name:r.name,arguments:JSON.stringify(r.args)}});let r={role:`assistant`,content:t.length>0?t.join(``):null};return n.length>0&&(r.tool_calls=n),r}return e.role===`tool_result`?{role:`tool`,tool_call_id:e.callId,content:e.content.map(e=>e.type===`text`?e.text:JSON.stringify(e)).join(`
5
+ `)}:{role:`user`,content:``}}function ce(e){return e.map(e=>({type:`function`,function:{name:e.name,description:e.description,parameters:e.parameters}}))}const le=e=>{let t=new T;return(async()=>{let n=``,r=new Map,i={in:0,out:0};try{let a={model:e.model.id,messages:[{role:`system`,content:e.system},...e.messages.map(se)],tools:e.tools.length>0?ce(e.tools):void 0,stream:!0},o=await fetch(`${e.baseUrl}/chat/completions`,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${e.apiKey}`},body:JSON.stringify(a),signal:e.signal});if(!o.ok){let e=await o.text(),n=`API error ${o.status}: ${e}`;t.push({type:`text_delta`,text:n}),t.finish({content:[{type:`text`,text:n}],usage:{in:0,out:0},stop:`error`});return}let s=o.body?.getReader();if(!s){t.finish({content:[],usage:{in:0,out:0},stop:`error`});return}let c=new TextDecoder,l=``,u=`stop`;for(;;){let{done:e,value:a}=await s.read();if(e)break;l+=c.decode(a,{stream:!0});let o=l.split(`
6
+ `);l=o.pop()??``;for(let e of o){let a=e.trim();if(!a?.startsWith(`data: `))continue;let o=a.slice(6);if(o!==`[DONE]`)try{let e=JSON.parse(o),a=e.choices?.[0]?.delta;if(!a)continue;a.content&&(t.push({type:`text_delta`,text:a.content}),n+=a.content);let s=a.reasoning_content||a.reasoning||a.thinking;if(s&&t.push({type:`thinking_delta`,text:s}),a.tool_calls)for(let e of a.tool_calls){let t=e.index??0;r.has(t)||r.set(t,{id:e.id??``,name:e.function?.name??``,args:``});let n=r.get(t);e.id&&(n.id=e.id),e.function?.name&&(n.name=e.function.name),e.function?.arguments&&(n.args+=e.function.arguments)}e.usage&&(i={in:e.usage.prompt_tokens??0,out:e.usage.completion_tokens??0},t.push({type:`usage`,usage:i}));let c=e.choices?.[0]?.finish_reason;c&&(u=c)}catch{}}}let d=[];n&&d.push({type:`text`,text:n});for(let[,e]of r)d.push({type:`tool_call`,id:e.id,name:e.name,args:JSON.parse(e.args||`{}`)}),t.push({type:`tool_call`,call:{type:`tool_call`,id:e.id,name:e.name,args:JSON.parse(e.args||`{}`)}}),u=`tool_use`;t.finish({content:d,usage:i,stop:u})}catch(a){if(e.signal?.aborted){let e=[];n&&e.push({type:`text`,text:n});for(let[,t]of r)try{e.push({type:`tool_call`,id:t.id,name:t.name,args:JSON.parse(t.args||`{}`)})}catch{}t.finish({content:e,usage:i,stop:`aborted`});return}let o=`Unexpected error: ${a instanceof Error?a.message:String(a)}`;t.push({type:`text_delta`,text:o}),t.finish({content:[{type:`text`,text:o}],usage:{in:0,out:0},stop:`error`})}})(),t};var T=class{#e=[];#t=!1;#n;#r;#i;#a=!1;push(e){if(!this.#a)if(this.#r){let t=this.#r;this.#r=void 0,t(e)}else this.#e.push(e)}finish(e){this.#t=!0,this.#n=e,this.#r&&this.#r(void 0),this.#i&&this.#i(e)}abort(){this.#a=!0,this.#t=!0,this.#r&&this.#r(void 0),this.#i&&this.#i(void 0)}async*[Symbol.asyncIterator](){for(;!this.#t||this.#e.length>0;){if(this.#e.length>0){yield this.#e.shift();continue}if(this.#t)break;let e=await new Promise(e=>{this.#r=e});e!==void 0&&(yield e)}}get result(){return this.#n}get isDone(){return this.#t}};const ue=new Map([[`openai`,le],[`gemini`,oe]]);function de(e){let t=ue.get(e.api);if(!t)throw Error(`No provider registered for API format: ${e.api}`);let n=t(e),r=new T;return(async()=>{for await(let e of n)e.type===`text_delta`?r.push({type:`text_delta`,text:e.text??``}):e.type===`thinking_delta`?r.push({type:`thinking_delta`,text:e.text??``}):e.type===`tool_call`&&e.call?r.push({type:`tool_call`,call:{type:`tool_call`,id:e.call.id,name:e.call.name,args:e.call.args}}):e.type===`usage`&&e.usage&&r.push({type:`usage`,usage:e.usage});let e=n.result;e?r.finish(e):r.finish({content:[],usage:{in:0,out:0},stop:`stop`})})(),r}function fe(e){let t=0;for(let n of e)if(typeof n.content==`string`)t+=n.content.length;else if(Array.isArray(n.content))for(let e of n.content)e.type===`text`&&(t+=e.text.length);return Math.ceil(t/4)}function E(e){return{type:`text`,text:e}}function D(e,t){return t===e||t.startsWith(`${e}/`)?o(e,t)||`.`:t}function pe(e){if(typeof e!=`string`)return e;let t=e,n=``;if(e.startsWith(`file://`)&&(t=e.slice(7),n=`file://`),i(t)){let e=process.cwd();return n+D(e,t)}return e}function me(e,n=!1){return e?Object.entries(e).map(([e,r])=>{let i=typeof r==`string`?pe(r):JSON.stringify(r),a=i.length>40?`${i.slice(0,40)}…`:i;return`${n?t.dim(`${e}:`):`${e}:`} ${a}`}).join(` `):``}function he(e){let t=Date.now()-e,n=Math.floor(t/1e3),r=Math.floor(n/60),i=Math.floor(r/60);return n<60?`just now`:r<60?`${r}m ago`:i<24?`${i}h ago`:new Date(e).toLocaleDateString()}const ge=e=>typeof e==`object`&&!!e&&e.type===`tool_call`;function _e(e,t,n){let r=new T,i=[],a=t.maxTurns??50,o=e;return(async()=>{r.push({type:`start`});try{let e=0;for(;e<a&&!n?.aborted;){e++,r.push({type:`turn`});let a=fe(o.messages);a>t.model.contextWindow*.9&&r.push({type:`text_delta`,text:`[warning] Approaching context limit (~${Math.round(a/1e3)}k / ${Math.round(t.model.contextWindow/1e3)}k tokens)`});let s=await ve(o,t,r,n);if(i.push(s),o={...o,messages:[...o.messages,s]},r.push({type:`assistant_msg`,msg:s}),s.stop===`error`||s.stop===`aborted`){r.push({type:`turn_end`,msg:s,results:[]});break}let c=s.content.filter(ge);if(c.length===0){r.push({type:`turn_end`,msg:s,results:[]});break}let l=[];for(let e of c){if(n?.aborted)break;let a=o.tools.find(t=>t.def.name===e.name);if(!a){let t={role:`tool_result`,callId:e.id,tool:e.name,content:[E(`Unknown tool: ${e.name}`)],isError:!0,ts:Date.now()};l.push(t),o={...o,messages:[...o.messages,t]},i.push(t);continue}let s=await t.beforeTool?.(e,e.args,o);if(s?.block){let t={role:`tool_result`,callId:e.id,tool:e.name,content:[E(s.reason??`Blocked`)],isError:!0,ts:Date.now()};l.push(t),o={...o,messages:[...o.messages,t]},i.push(t);continue}let c=await a.execute(e.args,n),u={role:`tool_result`,callId:e.id,tool:e.name,args:e.args,content:c.content,isError:c.isError,ts:Date.now()};l.push(u),o={...o,messages:[...o.messages,u]},i.push(u),r.push({type:`tool_result`,callId:e.id,result:u,args:e.args}),await t.afterTool?.(e,u,o)}r.push({type:`turn_end`,msg:s,results:l})}e>=a&&r.push({type:`text_delta`,text:`[max turns reached (${a})]`})}catch(e){if(e.name===`AbortError`){r.finish(i);return}throw e}r.finish(i)})(),r}async function ve(e,t,n,r){let i=de({api:t.api,model:t.model,apiKey:t.apiKey,baseUrl:t.baseUrl,system:e.system,messages:e.messages,tools:e.tools.map(e=>e.def),signal:r}),a=[],o={in:0,out:0};for await(let e of i)if(e.type===`text_delta`&&e.text){let t=a[a.length-1];t?.type===`text`?t.text+=e.text:a.push(E(e.text)),n.push({type:`text_delta`,text:e.text})}else e.type===`thinking_delta`&&e.text?n.push({type:`thinking_delta`,text:e.text}):e.type===`tool_call`&&e.call?(a.push(e.call),n.push({type:`tool_call`,call:e.call})):e.type===`usage`&&e.usage&&(o=e.usage,n.push({type:`usage`,usage:o}));let s=i.result?.content&&i.result.content.length>0?i.result.content:a,c=s.some(e=>e.type===`tool_call`)?s.filter(e=>e.type!==`text`||e.text.trim().length>0):s,l=i.result;return l?{role:`assistant`,content:c,model:t.model.id,provider:t.model.provider,usage:l.usage,stop:l.stop,ts:Date.now()}:{role:`assistant`,content:c,model:t.model.id,provider:t.model.provider,usage:o,stop:c.some(e=>e.type===`tool_call`)?`tool_use`:`stop`,ts:Date.now()}}var ye=class{#e;#t;#n;#r=[];#i;#a;#o;constructor(e){this.#e=e.api,this.#t=e.model,this.#a=e.apiKey,this.#o=e.baseUrl,this.#n=e.system,this.#i=e.tools,this.#r=e.messages??[]}get model(){return this.#t}get messages(){return this.#r}get tools(){return this.#i}get apiKey(){return this.#a}get baseUrl(){return this.#o}updateConfig(e){this.#e=e.api,this.#t=e.model,this.#a=e.apiKey,this.#o=e.baseUrl}setTools(e){this.#i=e}setMessages(e){this.#r=e}setModel(e){this.#t=e}prompt(e){return _e({system:this.#n,messages:this.#r,tools:this.#i},{api:this.#e,model:this.#t,apiKey:this.#a,baseUrl:this.#o},e)}};function be(e,t,n=[],r){let i=t.map(e=>`- ${e.def.name}: ${e.def.description}`).join(`
7
7
  `),a=c.platform(),o=c.arch();return`You are Nova, an expert coding assistant. Help users with coding tasks using the tools available.
8
8
 
9
9
  Format your responses with clean, standard markdown. Use headers (##, ###), bold text (**bold**), inline code (\`code\`), and code blocks (\`\`\`lang) to make your output clear and readable in the terminal.
@@ -49,44 +49,80 @@ ${n.length>0?n.map(e=>`- ${e.name}: ${e.description} (path: ${e.path}/SKILL.md)`
49
49
 
50
50
  **IMPORTANT:** Before responding to a task that matches any skill above, you MUST first read the skill's SKILL.md file using the read tool with the full absolute path, then follow its instructions exactly. Do not skip this step.
51
51
 
52
- ${r?`\n<project_context>\nProject-specific instructions and guidelines:\n\n<project_instructions path="AGENTS.md">\n${r}\n</project_instructions>\n</project_context>`:``}`}async function N(e,t,n={}){let[r,i]=t;if(r===`list`||r===`ls`){let t=n.limit??10,r=await e.list(t);if(r.length===0){console.log(`No sessions found.`);return}console.log(`ID`.padEnd(25),`TITLE / UPDATED`),console.log(`-`.repeat(60));for(let e of r){let t=M(e.updated),n=e.title?`"${e.title}" (${t})`:t;console.log(e.id.padEnd(25),n)}return}if(r===`delete`||r===`rm`){if(n.all){await e.deleteAll(),console.log(`All sessions deleted.`);return}i||(console.error(`Usage: nova --session rm <id> or --session rm --all`),process.exit(1)),await e.delete(i)?console.log(`Deleted session: ${i}`):(console.error(`Session not found: ${i}`),process.exit(1));return}console.error(`Unknown session subcommand.`),process.exit(1)}const P=[{id:`glm`,name:`GLM (Z.AI)`,api:`openai`,baseUrl:`https://api.z.ai/api/coding/paas/v4`,envKey:`GLM_API_KEY`},{id:`gemini`,name:`Gemini (Google)`,api:`gemini`,baseUrl:`https://generativelanguage.googleapis.com`,envKey:`GEMINI_API_KEY`},{id:`deepseek`,name:`DeepSeek`,api:`openai`,baseUrl:`https://api.deepseek.com`,envKey:`DEEPSEEK_API_KEY`},{id:`openai`,name:`OpenAI`,api:`openai`,baseUrl:`https://api.openai.com/v1`,envKey:`OPENAI_API_KEY`}],F=[{id:`glm-5.1`,name:`GLM-5.1`,provider:`glm`,contextWindow:128e3,maxTokens:4096,supportsThinking:!1},{id:`glm-5`,name:`GLM-5`,provider:`glm`,contextWindow:128e3,maxTokens:4096,supportsThinking:!1},{id:`glm-5-turbo`,name:`GLM-5 Turbo`,provider:`glm`,contextWindow:128e3,maxTokens:4096,supportsThinking:!1},{id:`glm-4.7`,name:`GLM-4.7`,provider:`glm`,contextWindow:128e3,maxTokens:4096,supportsThinking:!1},{id:`glm-4.7-flash`,name:`GLM-4.7 Flash (Free)`,provider:`glm`,contextWindow:128e3,maxTokens:4096,supportsThinking:!1},{id:`glm-4.5-flash`,name:`GLM-4.5 Flash (Free)`,provider:`glm`,contextWindow:128e3,maxTokens:4096,supportsThinking:!1},{id:`gemini-3.5-flash`,name:`Gemini 3.5 Flash`,provider:`gemini`,contextWindow:1e6,maxTokens:65536,supportsThinking:!0},{id:`gemini-3.1-pro-preview`,name:`Gemini 3.1 Pro Preview`,provider:`gemini`,contextWindow:2e6,maxTokens:65536,supportsThinking:!0},{id:`gemini-3.1-pro-preview-customtools`,name:`Gemini 3.1 Pro (Custom Tools)`,provider:`gemini`,contextWindow:2e6,maxTokens:65536,supportsThinking:!0},{id:`gemini-3.1-flash-lite`,name:`Gemini 3.1 Flash-Lite`,provider:`gemini`,contextWindow:1e6,maxTokens:65536,supportsThinking:!0},{id:`gemini-3.1-flash-lite-preview`,name:`Gemini 3.1 Flash-Lite Preview`,provider:`gemini`,contextWindow:1e6,maxTokens:65536,supportsThinking:!0},{id:`gemini-3-flash-preview`,name:`Gemini 3 Flash Preview`,provider:`gemini`,contextWindow:1e6,maxTokens:65536,supportsThinking:!0},{id:`gemini-2.5-pro`,name:`Gemini 2.5 Pro`,provider:`gemini`,contextWindow:2e6,maxTokens:65536,supportsThinking:!1},{id:`gemini-2.5-flash`,name:`Gemini 2.5 Flash`,provider:`gemini`,contextWindow:1e6,maxTokens:65536,supportsThinking:!1},{id:`gemini-2.5-flash-lite`,name:`Gemini 2.5 Flash-Lite`,provider:`gemini`,contextWindow:1e6,maxTokens:65536,supportsThinking:!1},{id:`gemini-2.5-computer-use-preview-10-2025`,name:`Gemini 2.5 Computer Use`,provider:`gemini`,contextWindow:1e6,maxTokens:65536,supportsThinking:!1},{id:`deepseek-chat`,name:`DeepSeek V3`,provider:`deepseek`,contextWindow:64e3,maxTokens:8192,supportsThinking:!1},{id:`deepseek-reasoner`,name:`DeepSeek R1`,provider:`deepseek`,contextWindow:64e3,maxTokens:8192,supportsThinking:!0},{id:`gpt-4o`,name:`GPT-4o`,provider:`openai`,contextWindow:128e3,maxTokens:16384,supportsThinking:!1},{id:`o4-mini`,name:`o4-mini`,provider:`openai`,contextWindow:2e5,maxTokens:1e5,supportsThinking:!0}];function I(e){return P.find(t=>t.id===e)}function ge(e){return F.filter(t=>t.provider===e)}const L=()=>a(process.env.HOME??`~`,`.novacode`),R=()=>a(L(),`config.json`),z=()=>a(L(),`auth.json`),B={provider:``,model:``},V={apiKeys:{}};async function _e(){try{return await g(R()),!0}catch{return!1}}async function H(){try{let e=JSON.parse(await p(R(),`utf-8`));return{...B,...e}}catch{return{...B}}}async function U(){try{let e=JSON.parse(await p(z(),`utf-8`));return{...V,...e}}catch{return{...V}}}async function W(){await f(L(),{recursive:!0})}async function ve(e){await W(),await _(R(),JSON.stringify(e,null,2))}async function ye(e){await W(),await _(z(),JSON.stringify(e,null,2));try{await d(z(),384)}catch{}}function be({message:e,options:t,header:n,onSelect:r}){let[i,a]=S(0);return x((e,n)=>{if(n.escape){r(null);return}if(n.upArrow){a(e=>(e-1+t.length)%t.length);return}if(n.downArrow){a(e=>(e+1)%t.length);return}n.return&&r(t[i]?.value??null)}),w(v,{flexDirection:`column`,paddingX:1,children:[n&&C(v,{marginBottom:1,children:C(y,{children:n})}),C(v,{marginBottom:1,children:C(y,{bold:!0,children:e})}),t.map((e,t)=>w(v,{children:[w(y,{color:t===i?`green`:void 0,children:[t===i?`❯ `:` `,e.label]}),e.hint&&t===i&&w(y,{dimColor:!0,children:[` `,e.hint]})]},e.value)),C(v,{marginTop:1,children:C(y,{dimColor:!0,children:`↑↓ navigate · Enter select · Esc cancel`})})]})}function xe({message:e,validate:t,onSubmit:n}){let[r,i]=S(``),[a,o]=S(``);return x((e,a)=>{if(a.escape){n(null);return}if(a.return){let e=t?.(r);if(e){o(e);return}n(r);return}if(a.backspace||a.delete){i(e=>e.slice(0,-1)),o(``);return}e&&(i(t=>t+e),o(``))}),w(v,{flexDirection:`column`,paddingX:1,children:[C(v,{marginBottom:1,children:C(y,{bold:!0,children:e})}),w(v,{children:[C(y,{color:`green`,children:`│ `}),C(y,{dimColor:!0,children:`*`.repeat(r.length)}),C(y,{color:`green`,children:`│`})]}),a&&C(v,{children:C(y,{color:`red`,children:a})}),C(v,{marginTop:1,children:C(y,{dimColor:!0,children:`Enter submit · Esc cancel`})})]})}function Se({message:e,onConfirm:t}){let[n,r]=S(!0);return x((e,i)=>{if(i.escape){t(null);return}if(i.leftArrow||i.rightArrow||i.tab){r(e=>!e);return}i.return&&t(n)}),w(v,{flexDirection:`column`,paddingX:1,children:[C(v,{marginBottom:1,children:C(y,{bold:!0,children:e})}),C(v,{children:w(y,{color:n?`green`:void 0,children:[n?`❯ `:` `,`Yes`]})}),C(v,{children:w(y,{color:n?void 0:`red`,children:[n?` `:`❯ `,`No`]})}),C(v,{marginTop:1,children:C(y,{dimColor:!0,children:`←→ toggle · Enter confirm · Esc cancel`})})]})}function Ce(e,t,n){return new Promise(r=>{let{unmount:i}=b(C(be,{message:e,options:t,header:n,onSelect:e=>{i(),r(e)}}))})}function we(e,t){return new Promise(n=>{let{unmount:r}=b(C(xe,{message:e,validate:t,onSubmit:e=>{r(),n(e)}}))})}async function Te(){console.log(t.bold.cyan(`
52
+ ${r?`\n<project_context>\nProject-specific instructions and guidelines:\n\n<project_instructions path="AGENTS.md">\n${r}\n</project_instructions>\n</project_context>`:``}`}function xe(e){return e===0?`-`:e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}async function O(e,t,n={}){let[r,i]=t;if(r===`list`||r===`ls`){let t=n.limit??10,r=await e.list(t);if(r.length===0){console.log(`No sessions found.`);return}console.log(`ID`.padEnd(25),`TITLE / UPDATED`.padEnd(35),`TOKENS`),console.log(`-`.repeat(75));for(let e of r){let t=he(e.updated),n=e.title?`"${e.title}" (${t})`:t,r=xe(e.inputTokens+e.outputTokens);console.log(e.id.padEnd(25),n.padEnd(35),r)}return}if(r===`delete`||r===`rm`){if(n.all){await e.deleteAll(),console.log(`All sessions deleted.`);return}i||(console.error(`Usage: nova --sessions rm <id> or --sessions rm --all`),process.exit(1)),await e.delete(i)?console.log(`Deleted session: ${i}`):(console.error(`Session not found: ${i}`),process.exit(1));return}console.error(`Unknown session subcommand.`),process.exit(1)}const k=[{id:`glm`,name:`GLM (Z.AI)`,api:`openai`,baseUrl:`https://api.z.ai/api/coding/paas/v4`,envKey:`GLM_API_KEY`},{id:`gemini`,name:`Gemini (Google)`,api:`gemini`,baseUrl:`https://generativelanguage.googleapis.com`,envKey:`GEMINI_API_KEY`},{id:`deepseek`,name:`DeepSeek`,api:`openai`,baseUrl:`https://api.deepseek.com`,envKey:`DEEPSEEK_API_KEY`},{id:`openai`,name:`OpenAI`,api:`openai`,baseUrl:`https://api.openai.com/v1`,envKey:`OPENAI_API_KEY`}],A=[{id:`glm-5.1`,name:`GLM-5.1`,provider:`glm`,contextWindow:128e3,maxTokens:4096,supportsThinking:!1},{id:`glm-5`,name:`GLM-5`,provider:`glm`,contextWindow:128e3,maxTokens:4096,supportsThinking:!1},{id:`glm-5-turbo`,name:`GLM-5 Turbo`,provider:`glm`,contextWindow:128e3,maxTokens:4096,supportsThinking:!1},{id:`glm-4.7`,name:`GLM-4.7`,provider:`glm`,contextWindow:128e3,maxTokens:4096,supportsThinking:!1},{id:`glm-4.7-flash`,name:`GLM-4.7 Flash (Free)`,provider:`glm`,contextWindow:128e3,maxTokens:4096,supportsThinking:!1},{id:`glm-4.5-flash`,name:`GLM-4.5 Flash (Free)`,provider:`glm`,contextWindow:128e3,maxTokens:4096,supportsThinking:!1},{id:`gemini-3.5-flash`,name:`Gemini 3.5 Flash`,provider:`gemini`,contextWindow:1e6,maxTokens:65536,supportsThinking:!0},{id:`gemini-3.1-pro-preview`,name:`Gemini 3.1 Pro Preview`,provider:`gemini`,contextWindow:2e6,maxTokens:65536,supportsThinking:!0},{id:`gemini-3.1-pro-preview-customtools`,name:`Gemini 3.1 Pro (Custom Tools)`,provider:`gemini`,contextWindow:2e6,maxTokens:65536,supportsThinking:!0},{id:`gemini-3.1-flash-lite`,name:`Gemini 3.1 Flash-Lite`,provider:`gemini`,contextWindow:1e6,maxTokens:65536,supportsThinking:!0},{id:`gemini-3.1-flash-lite-preview`,name:`Gemini 3.1 Flash-Lite Preview`,provider:`gemini`,contextWindow:1e6,maxTokens:65536,supportsThinking:!0},{id:`gemini-3-flash-preview`,name:`Gemini 3 Flash Preview`,provider:`gemini`,contextWindow:1e6,maxTokens:65536,supportsThinking:!0},{id:`gemini-2.5-pro`,name:`Gemini 2.5 Pro`,provider:`gemini`,contextWindow:2e6,maxTokens:65536,supportsThinking:!1},{id:`gemini-2.5-flash`,name:`Gemini 2.5 Flash`,provider:`gemini`,contextWindow:1e6,maxTokens:65536,supportsThinking:!1},{id:`gemini-2.5-flash-lite`,name:`Gemini 2.5 Flash-Lite`,provider:`gemini`,contextWindow:1e6,maxTokens:65536,supportsThinking:!1},{id:`gemini-2.5-computer-use-preview-10-2025`,name:`Gemini 2.5 Computer Use`,provider:`gemini`,contextWindow:1e6,maxTokens:65536,supportsThinking:!1},{id:`deepseek-chat`,name:`DeepSeek V3`,provider:`deepseek`,contextWindow:64e3,maxTokens:8192,supportsThinking:!1},{id:`deepseek-reasoner`,name:`DeepSeek R1`,provider:`deepseek`,contextWindow:64e3,maxTokens:8192,supportsThinking:!0},{id:`gpt-4o`,name:`GPT-4o`,provider:`openai`,contextWindow:128e3,maxTokens:16384,supportsThinking:!1},{id:`o4-mini`,name:`o4-mini`,provider:`openai`,contextWindow:2e5,maxTokens:1e5,supportsThinking:!0}];function j(e){return k.find(t=>t.id===e)}function Se(e){return A.filter(t=>t.provider===e)}const M=()=>a(process.env.HOME??`~`,`.novacode`),N=()=>a(M(),`config.json`),P=()=>a(M(),`auth.json`),F={provider:``,model:``},I={apiKeys:{}};async function Ce(){try{return await m(N()),!0}catch{return!1}}async function L(){try{let e=JSON.parse(await f(N(),`utf-8`));return{...F,...e}}catch{return{...F}}}async function R(){try{let e=JSON.parse(await f(P(),`utf-8`));return{...I,...e}}catch{return{...I}}}async function z(){await d(M(),{recursive:!0})}async function B(e){await z(),await h(N(),JSON.stringify(e,null,2))}async function V(e){await z(),await h(P(),JSON.stringify(e,null,2));try{await u(P(),384)}catch{}}function we({message:e,options:t,header:n,footer:r,onSelect:i}){let[a,o]=b(0);return y((e,n)=>{if(n.escape){i(null);return}if(n.upArrow){o(e=>(e-1+t.length)%t.length);return}if(n.downArrow){o(e=>(e+1)%t.length);return}n.return&&i(t[a]?.value??null)}),S(g,{flexDirection:`column`,paddingX:1,children:[n&&x(g,{marginBottom:1,children:x(_,{children:n})}),x(g,{marginBottom:1,children:x(_,{bold:!0,children:e})}),t.map((e,t)=>S(g,{children:[S(_,{color:t===a?`green`:void 0,children:[t===a?`❯ `:` `,e.label]}),e.hint&&t===a&&S(_,{dimColor:!0,children:[` `,e.hint]})]},e.value)),x(g,{marginTop:1,children:x(_,{dimColor:!0,children:`↑↓ navigate · Enter select · Esc cancel`})}),r&&x(g,{marginTop:1,children:x(_,{children:r})})]})}function Te({message:e,validate:t,onSubmit:n}){let[r,i]=b(``),[a,o]=b(``);return y((e,a)=>{if(a.escape){n(null);return}if(a.return){let e=t?.(r);if(e){o(e);return}n(r);return}if(a.backspace||a.delete){i(e=>e.slice(0,-1)),o(``);return}e&&(i(t=>t+e),o(``))}),S(g,{flexDirection:`column`,paddingX:1,children:[x(g,{marginBottom:1,children:x(_,{bold:!0,children:e})}),S(g,{children:[x(_,{color:`green`,children:`│ `}),x(_,{dimColor:!0,children:`*`.repeat(r.length)}),x(_,{color:`green`,children:`│`})]}),a&&x(g,{children:x(_,{color:`red`,children:a})}),x(g,{marginTop:1,children:x(_,{dimColor:!0,children:`Enter submit · Esc cancel`})})]})}function Ee({message:e,onConfirm:t}){let[n,r]=b(!0);return y((e,i)=>{if(i.escape){t(null);return}if(i.leftArrow||i.rightArrow||i.tab){r(e=>!e);return}i.return&&t(n)}),S(g,{flexDirection:`column`,paddingX:1,children:[x(g,{marginBottom:1,children:x(_,{bold:!0,children:e})}),x(g,{children:S(_,{color:n?`green`:void 0,children:[n?`❯ `:` `,`Yes`]})}),x(g,{children:S(_,{color:n?void 0:`red`,children:[n?` `:`❯ `,`No`]})}),x(g,{marginTop:1,children:x(_,{dimColor:!0,children:`←→ toggle · Enter confirm · Esc cancel`})})]})}function De(e,t,n,r){return new Promise(i=>{let{unmount:a}=v(x(we,{message:e,options:t,header:n,footer:r,onSelect:e=>{a(),i(e)}}))})}function Oe(e,t){return new Promise(n=>{let{unmount:r}=v(x(Te,{message:e,validate:t,onSubmit:e=>{r(),n(e)}}))})}async function ke(){console.log(t.bold.cyan(`
53
53
  ⚡ Nova — your coding companion
54
- `));let e=await Ce(`Pick a provider`,P.map(e=>({value:e.id,label:e.name})));e||(console.log(t.dim(`Cancelled`)),process.exit(0));let n=I(e);n||(console.log(t.red(`Unknown provider`)),process.exit(1));let r=await we(`Enter ${n.name} API key`);r||(console.log(t.dim(`Cancelled`)),process.exit(0));let i=await Ce(`Pick a default model`,ge(e).map(e=>({value:e.id,label:`${e.name} (${(e.contextWindow/1e3).toFixed(0)}k ctx)`})));i||(console.log(t.dim(`Cancelled`)),process.exit(0));let a={provider:e,model:i};return await ve(a),await ye({apiKeys:{[e]:r}}),console.log(t.green(`
54
+ `));let e=await De(`Pick a provider`,k.map(e=>({value:e.id,label:e.name})));e||(console.log(t.dim(`Cancelled`)),process.exit(0));let n=j(e);n||(console.log(t.red(`Unknown provider`)),process.exit(1));let r=await Oe(`Enter ${n.name} API key`);r||(console.log(t.dim(`Cancelled`)),process.exit(0));let i=await De(`Pick a default model`,Se(e).map(e=>({value:e.id,label:`${e.name} (${(e.contextWindow/1e3).toFixed(0)}k ctx)`})));i||(console.log(t.dim(`Cancelled`)),process.exit(0));let a={provider:e,model:i};return await B(a),await V({apiKeys:{[e]:r}}),console.log(t.green(`
55
55
  ✓ Ready. Type your prompt or /help for commands
56
- `)),a}const Ee=/^[a-z0-9]+(-[a-z0-9]+)*$/;function De(e){return e.length>64?{valid:!1,warning:`Skill name exceeds 64 characters: "${e}"`}:Ee.test(e)?{valid:!0}:{valid:!1,warning:`Skill name contains invalid characters (use lowercase, numbers, hyphens): "${e}"`}}function Oe(e){let t=e.match(/^---\s*\n([\s\S]*?)\n---/);if(!t)return null;let n=t[1],r,i;for(let e of n.split(`
57
- `)){let t=e.match(/^name:\s*(.+)$/);t&&(r=t[1].trim());let n=e.match(/^description:\s*(.+)$/);n&&(i=n[1].trim())}return r?{name:r,description:i}:null}async function ke(e,t){let n=a(e,`SKILL.md`);try{let{readFile:r}=await import(`node:fs/promises`),i=Oe(await r(n,`utf-8`));return i?.name?i.description?{name:i.name,description:i.description,path:e,source:t}:(console.warn(`Skill missing description, skipping: ${e}`),null):null}catch{return null}}async function Ae(e,t){let n=[];try{let r=await m(e,{withFileTypes:!0});for(let i of r){if(!i.isDirectory())continue;let r=await ke(a(e,i.name),t);r&&n.push(r)}}catch{}return n}async function je(e){let t=[a(l(),`.agents`,`skills`),a(l(),`.novacode`,`skills`)],n=[s(e,`.agents`,`skills`),s(e,`.novacode`,`skills`)],r=[];for(let e of t)r.push(...await Ae(e,`global`));for(let e of n)r.push(...await Ae(e,`project`));let i=new Set,o=[];for(let e of r){let t=De(e.name);if(t.valid||console.warn(t.warning),i.has(e.name)){console.warn(`Duplicate skill name "${e.name}", keeping first occurrence`);continue}i.add(e.name),e.description.length>1024&&console.warn(`Skill description exceeds 1024 characters: "${e.name}"`),o.push({name:e.name,description:e.description,path:e.path,source:e.source})}return o}async function Me(e){let[t,n]=await Promise.all([je(e),Ne(e)]);return{skills:t,agentsMd:n}}async function Ne(e){try{return await p(a(e,`AGENTS.md`),`utf-8`)}catch{return null}}function Pe(){return`${Date.now().toString(36)}-${crypto.randomUUID().slice(0,8)}`}var Fe=class{#e;constructor(e){this.#e=e}#t(e){return a(this.#e,e)}#n(e){return a(this.#t(e),`metadata.json`)}#r(e){return a(this.#t(e),`messages.jsonl`)}#i(e){return a(this.#t(e),`history.jsonl`)}async create(e,t,n){let r=Pe(),i=Date.now(),a={id:r,cwd:e,model:t,provider:n,title:null,created:i,updated:i};return await f(this.#t(r),{recursive:!0}),await _(this.#n(r),JSON.stringify(a,null,2)),a}async get(e){try{let t=await p(this.#n(e),`utf-8`);return JSON.parse(t)}catch{return null}}async list(e=10){try{let t=(await m(this.#e,{withFileTypes:!0})).filter(e=>e.isDirectory()).map(e=>e.name).sort((e,t)=>t.localeCompare(e)).slice(0,Math.max(e*2,50)),n=[];for(let e of t){let t=await this.get(e);t&&n.push(t)}return n.sort((e,t)=>t.updated-e.updated),n.slice(0,e)}catch{return[]}}async latest(){return(await this.list(1))[0]??null}async delete(e){try{return await h(this.#t(e),{recursive:!0,force:!0}),!0}catch{return!1}}async deleteAll(){try{await h(this.#e,{recursive:!0,force:!0}),await f(this.#e,{recursive:!0})}catch{}}async append(e,t,n=!0){let r=await this.get(e);if(!r)return;r.updated=Date.now(),await _(this.#n(e),JSON.stringify(r,null,2));let i=`${JSON.stringify(t)}\n`;await u(this.#r(e),i),n&&await u(this.#i(e),i)}async messages(e){try{return(await p(this.#r(e),`utf-8`)).split(`
58
- `).filter(e=>e.trim().length>0).map(e=>JSON.parse(e))}catch{return[]}}async history(e){try{return(await p(this.#i(e),`utf-8`)).split(`
59
- `).filter(e=>e.trim().length>0).map(e=>JSON.parse(e))}catch{return this.messages(e)}}async messageCount(e){try{return(await p(this.#r(e),`utf-8`)).split(`
60
- `).filter(e=>e.trim().length>0).length}catch{return 0}}async setTitle(e,t){let n=await this.get(e);n&&(n.title=t,n.updated=Date.now(),await _(this.#n(e),JSON.stringify(n,null,2)))}async replaceMessages(e,t){let n=t.map(e=>JSON.stringify(e)).join(`
61
- `)+(t.length>0?`
62
- `:``);await _(this.#r(e),n)}async prune(e=10){try{let t=(await m(this.#e,{withFileTypes:!0})).filter(e=>e.isDirectory()).map(e=>e.name).sort((e,t)=>t.localeCompare(e)),n=e>0?t.slice(0,e):t;for(let e of n)await this.messageCount(e)===0&&await this.delete(e)}catch{}}close(){}};let G=null;async function Ie(e){if(G)return G;let t=a(e??a(process.env.HOME??`~`,`.novacode`),`sessions`);return await f(t,{recursive:!0}),G=new Fe(t),G}const Le=new Set([`.jpg`,`.jpeg`,`.png`,`.gif`,`.webp`]);function K(e,t){let n=s(e,t);if(n!==e&&!n.startsWith(`${e}/`))throw Error(`Path outside project: ${t}`);return n}function Re(e){return{def:{name:`read`,description:`Read file contents. Supports text and images (jpg, png, gif, webp). Text output is truncated to 2000 lines.`,parameters:{type:`object`,properties:{path:{type:`string`,description:`Path to file (relative or absolute)`},offset:{type:`number`,description:`Start line (1-based, default 1)`},limit:{type:`number`,description:`Max lines to read (default 2000)`}},required:[`path`]}},async execute(t){try{let n=K(e,t.path),i=r(n).toLowerCase();if(Le.has(i))return{content:[{type:`image`,data:(await p(n)).toString(`base64`),mime:i===`.jpg`?`image/jpeg`:`image/${i.slice(1)}`}],isError:!1};let a=(await p(n,`utf-8`)).split(`
63
- `),o=Math.max(0,(Number(t.offset??1)||1)-1),s=Number(t.limit??2e3)||2e3,c=a.slice(o,o+s),l=o+s<a.length;return{content:[A(c.join(`
64
- `)+(l?`\n…${a.length-o-s} more lines`:``))],isError:!1}}catch(e){return{content:[A(`Error reading file: ${e.message}`)],isError:!0}}}}}function ze(e){return{def:{name:`write`,description:`Write content to a file. Creates the file and parent directories if needed.`,parameters:{type:`object`,properties:{path:{type:`string`,description:`Path to file`},content:{type:`string`,description:`Content to write`}},required:[`path`,`content`]}},async execute(t){try{let r=K(e,t.path),i=t.content;await f(n(r),{recursive:!0}),await _(r,i);let a=j(e,r);return{content:[A(`Wrote ${i.length} bytes → ${a}`)],isError:!1}}catch(e){return{content:[A(`Error writing file: ${e.message}`)],isError:!0}}}}}function Be(e){return{def:{name:`edit`,description:`Edit a file using exact text replacement. Each edit's oldText must be unique in the file.`,parameters:{type:`object`,properties:{path:{type:`string`,description:`Path to file`},edits:{type:`array`,description:`Array of {oldText, newText} replacements. oldText must be unique. Non-overlapping.`,items:{type:`object`,properties:{oldText:{type:`string`,description:`Exact text to find (must be unique)`},newText:{type:`string`,description:`Replacement text`}},required:[`oldText`,`newText`]}}},required:[`path`,`edits`]}},async execute(t){try{let n=K(e,t.path),r;try{r=await p(n,`utf-8`)}catch{return{content:[A(`File not found: ${t.path}`)],isError:!0}}let i=t.edits;for(let e of i){let t=r.split(e.oldText).length-1;if(t===0)return{content:[A(`oldText not found: "${e.oldText.slice(0,80)}…"`)],isError:!0};if(t>1)return{content:[A(`oldText found ${t} times — add surrounding context to make it unique: "${e.oldText.slice(0,60)}…"`)],isError:!0}}for(let e of i)r=r.replace(e.oldText,e.newText);return await _(n,r),{content:[A(`Edited ${j(e,n)} (${i.length} replacement${i.length>1?`s`:``})`)],isError:!1}}catch(e){return{content:[A(`Error editing file: ${e.message}`)],isError:!0}}}}}function Ve(e){return{def:{name:`git`,description:`Execute safe, non-interactive git commands (status, diff, log, add, commit) in the repository.`,parameters:{type:`object`,properties:{action:{type:`string`,enum:[`status`,`diff`,`log`,`add`,`commit`],description:`The git action to execute`},args:{type:`array`,description:`Optional additional arguments or file paths for the git action`,items:{type:`string`}}},required:[`action`]}},async execute(t,n){let r=t.action,i=t.args||[];if(!new Set([`status`,`diff`,`log`,`add`,`commit`]).has(r))return{content:[A(`Error: Git action '${r}' is not supported.`)],isError:!0};try{let t=[`git`,r,...i],a=T(t[0],t.slice(1),{cwd:e,stdio:[`ignore`,`pipe`,`pipe`],env:{...process.env,PAGER:`cat`}}),o=``,s=``;a.stdout.on(`data`,e=>{o+=e.toString()}),a.stderr.on(`data`,e=>{s+=e.toString()});let c=()=>{a.kill(`SIGKILL`),a.stdout.destroy(),a.stderr.destroy()};n?.addEventListener(`abort`,c,{once:!0});let l;try{l=await new Promise((e,t)=>{a.on(`error`,t),a.on(`close`,t=>e(t??-1))})}finally{n?.removeEventListener(`abort`,c)}let u=5e4,d=``;return o&&(d+=o.slice(0,u)),s&&(d&&(d+=`
56
+ `)),a}const Ae=/^[a-z0-9]+(-[a-z0-9]+)*$/;function je(e){return e.length>64?{valid:!1,warning:`Skill name exceeds 64 characters: "${e}"`}:Ae.test(e)?{valid:!0}:{valid:!1,warning:`Skill name contains invalid characters (use lowercase, numbers, hyphens): "${e}"`}}function Me(e){let t=e.match(/^---\s*\n([\s\S]*?)\n---/);if(!t)return null;let n=t[1],r,i;for(let e of n.split(`
57
+ `)){let t=e.match(/^name:\s*(.+)$/);t&&(r=t[1].trim());let n=e.match(/^description:\s*(.+)$/);n&&(i=n[1].trim())}return r?{name:r,description:i}:null}async function Ne(e,t){let n=a(e,`SKILL.md`);try{let{readFile:r}=await import(`node:fs/promises`),i=Me(await r(n,`utf-8`));return i?.name?i.description?{name:i.name,description:i.description,path:e,source:t}:(console.warn(`Skill missing description, skipping: ${e}`),null):null}catch{return null}}async function Pe(e,t){let n=[];try{let r=await p(e,{withFileTypes:!0});for(let i of r){if(!i.isDirectory())continue;let r=await Ne(a(e,i.name),t);r&&n.push(r)}}catch{}return n}async function Fe(e){let t=[a(l(),`.agents`,`skills`),a(l(),`.novacode`,`skills`)],n=[s(e,`.agents`,`skills`),s(e,`.novacode`,`skills`)],r=[];for(let e of t)r.push(...await Pe(e,`global`));for(let e of n)r.push(...await Pe(e,`project`));let i=new Set,o=[];for(let e of r){let t=je(e.name);if(t.valid||console.warn(t.warning),i.has(e.name)){console.warn(`Duplicate skill name "${e.name}", keeping first occurrence`);continue}i.add(e.name),e.description.length>1024&&console.warn(`Skill description exceeds 1024 characters: "${e.name}"`),o.push({name:e.name,description:e.description,path:e.path,source:e.source})}return o}async function Ie(e){let[t,n]=await Promise.all([Fe(e),Le(e)]);return{skills:t,agentsMd:n}}async function Le(e){try{return await f(a(e,`AGENTS.md`),`utf-8`)}catch{return null}}let H=null;function Re(e){if(H)return H;let t=e??a(process.env.HOME??`~`,`.novacode`,`state.db`);return ee(a(t,`..`),{recursive:!0}),H=new C(t,{enableForeignKeyConstraints:!0}),H.exec(`PRAGMA journal_mode = WAL`),H.exec(`
58
+ CREATE TABLE IF NOT EXISTS sessions (
59
+ id TEXT PRIMARY KEY,
60
+ cwd TEXT NOT NULL,
61
+ model TEXT NOT NULL,
62
+ provider TEXT NOT NULL,
63
+ title TEXT,
64
+ parent_session_id TEXT,
65
+ end_reason TEXT,
66
+ created INTEGER NOT NULL,
67
+ updated INTEGER NOT NULL,
68
+ input_tokens INTEGER DEFAULT 0,
69
+ output_tokens INTEGER DEFAULT 0,
70
+ message_count INTEGER DEFAULT 0
71
+ );
72
+
73
+ CREATE TABLE IF NOT EXISTS messages (
74
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
75
+ session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
76
+ seq INTEGER NOT NULL,
77
+ role TEXT NOT NULL,
78
+ content TEXT,
79
+ tool_call_id TEXT,
80
+ tool_name TEXT,
81
+ tool_args TEXT,
82
+ model TEXT,
83
+ provider TEXT,
84
+ usage_input INTEGER DEFAULT 0,
85
+ usage_output INTEGER DEFAULT 0,
86
+ stop_reason TEXT,
87
+ is_error INTEGER DEFAULT 0,
88
+ ts INTEGER NOT NULL
89
+ );
90
+
91
+ CREATE INDEX IF NOT EXISTS idx_sessions_updated ON sessions(updated DESC);
92
+ CREATE INDEX IF NOT EXISTS idx_sessions_parent ON sessions(parent_session_id);
93
+ CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id, seq);
94
+ `),H}function ze(){H&&=(H.close(),null)}function Be(){return`${Date.now().toString(36)}-${crypto.randomUUID().slice(0,8)}`}const Ve=`$json:`;function U(e){return e==null?null:typeof e==`string`?e:Ve+JSON.stringify(e)}function He(e){return e===null?``:e.startsWith(Ve)?JSON.parse(e.slice(6)):e}function Ue(e){let t=e.role,n=He(e.content),r=e.ts;return t===`user`?{role:`user`,content:n,ts:r}:t===`assistant`?{role:`assistant`,content:n||[],model:e.model??``,provider:e.provider??``,usage:{in:e.usage_input??0,out:e.usage_output??0},stop:e.stop_reason??`stop`,error:void 0,ts:r}:{role:`tool_result`,callId:e.tool_call_id??``,tool:e.tool_name??``,args:e.tool_args?JSON.parse(e.tool_args):void 0,content:n||[],isError:!!e.is_error,ts:r}}function W(e){return{id:e.id,cwd:e.cwd,model:e.model,provider:e.provider,title:e.title??null,parentSessionId:e.parent_session_id??null,endReason:e.end_reason??null,created:e.created,updated:e.updated,inputTokens:e.input_tokens??0,outputTokens:e.output_tokens??0,messageCount:e.message_count??0}}var We=class{#e;#t=new Map;constructor(e){e instanceof C?this.#e=e:this.#e=Re(e)}#n(e){let t=this.#t.get(e);t&&(this.#e.prepare(`INSERT OR IGNORE INTO sessions (id, cwd, model, provider, title, parent_session_id, end_reason, created, updated, input_tokens, output_tokens, message_count)
95
+ VALUES (?, ?, ?, ?, ?, ?, NULL, ?, ?, 0, 0, 0)`).run(e,t.cwd,t.model,t.provider,t.title,t.parentSessionId,t.created,t.created),this.#t.delete(e))}async create(e,t,n){let r=Be(),i=Date.now();return this.#t.set(r,{cwd:e,model:t,provider:n,title:null,parentSessionId:null,created:i}),{id:r,cwd:e,model:t,provider:n,title:null,parentSessionId:null,endReason:null,created:i,updated:i,inputTokens:0,outputTokens:0,messageCount:0}}async get(e){let t=this.#e.prepare(`SELECT * FROM sessions WHERE id = ?`).get(e);if(t)return W(t);let n=this.#t.get(e);return n?{id:e,cwd:n.cwd,model:n.model,provider:n.provider,title:n.title,parentSessionId:n.parentSessionId,endReason:null,created:n.created,updated:n.created,inputTokens:0,outputTokens:0,messageCount:0}:null}async list(e=10){return this.#e.prepare(`SELECT * FROM sessions WHERE end_reason IS NULL ORDER BY updated DESC LIMIT ?`).all(e).map(W)}async latest(){let e=this.#e.prepare(`SELECT * FROM sessions WHERE end_reason IS NULL ORDER BY updated DESC LIMIT 1`).get();return e?W(e):null}async delete(e){let t=this.#t.delete(e),n=this.#e.prepare(`DELETE FROM sessions WHERE id = ?`).run(e);return t||n.changes>0}async deleteAll(){this.#t.clear(),this.#e.exec(`DELETE FROM messages; DELETE FROM sessions`)}async append(e,t){this.#n(e);let n=Date.now(),r=t.role,i=null,a=null,o=null,s=null,c=null,l=null,u=0,d=0,f=null,p=0;r===`user`?i=U(t.content):r===`assistant`?(i=U(t.content),c=t.model??null,l=t.provider??null,u=t.usage?.in??0,d=t.usage?.out??0,f=t.stop??null,t.error&&(p=1)):r===`tool_result`&&(i=U(t.content),a=t.callId??null,o=t.tool??null,s=t.args?JSON.stringify(t.args):null,p=+!!t.isError);let m=this.#e.prepare(`SELECT COALESCE(MAX(seq), 0) + 1 AS next_seq FROM messages WHERE session_id = ?`).get(e)?.next_seq;this.#e.prepare(`INSERT INTO messages (session_id, seq, role, content, tool_call_id, tool_name, tool_args, model, provider, usage_input, usage_output, stop_reason, is_error, ts)
96
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(e,m,r,i,a,o,s,c,l,u,d,f,p,t.ts??n),this.#e.prepare(`UPDATE sessions SET message_count = message_count + 1, updated = ?, input_tokens = input_tokens + ?, output_tokens = output_tokens + ? WHERE id = ?`).run(n,u,d,e)}async messages(e){return this.#e.prepare(`SELECT * FROM messages WHERE session_id = ? ORDER BY seq`).all(e).map(Ue)}async history(e){let t=this.#r(e);if(t.length<=1)return this.messages(e);let n=t.map((e,t)=>`WHEN '${e}' THEN ${t}`).join(` `);return this.#e.prepare(`SELECT m.* FROM messages m
97
+ WHERE m.session_id IN (${t.map(()=>`?`).join(`,`)})
98
+ ORDER BY CASE m.session_id ${n} END ASC, m.seq ASC`).all(...t).map(Ue)}async messageCount(e){return this.#e.prepare(`SELECT message_count FROM sessions WHERE id = ?`).get(e)?.message_count??0}async setTitle(e,t){this.#n(e),this.#e.prepare(`UPDATE sessions SET title = ?, updated = ? WHERE id = ?`).run(t,Date.now(),e)}async replaceMessages(e,t){t.length>0&&this.#n(e),this.#e.prepare(`DELETE FROM messages WHERE session_id = ?`).run(e),this.#e.prepare(`UPDATE sessions SET message_count = 0, updated = ? WHERE id = ?`).run(Date.now(),e);let n=0;for(let r of t)n++,await this.#i(e,n,r);this.#e.prepare(`UPDATE sessions SET message_count = ?, updated = ? WHERE id = ?`).run(n,Date.now(),e)}async endSession(e,t){this.#n(e),this.#e.prepare(`UPDATE sessions SET end_reason = ?, updated = ? WHERE id = ?`).run(t,Date.now(),e)}async createContinuation(e,t,n,r){let i=Be(),a=Date.now();return this.#t.set(i,{cwd:t,model:n,provider:r,title:null,parentSessionId:e,created:a}),{id:i,cwd:t,model:n,provider:r,title:null,parentSessionId:e,endReason:null,created:a,updated:a,inputTokens:0,outputTokens:0,messageCount:0}}#r(e){let t=[],n=e,r=new Set;for(;n&&!r.has(n);){t.push(n),r.add(n);let e=this.#e.prepare(`SELECT parent_session_id FROM sessions WHERE id = ?`).get(n);n=e?e.parent_session_id??``:this.#t.get(n)?.parentSessionId??``}return t.reverse(),t}async#i(e,t,n){let r=n.role,i=null,a=null,o=null,s=null,c=null,l=null,u=0,d=0,f=null,p=0;r===`user`?i=U(n.content):r===`assistant`?(i=U(n.content),c=n.model??null,l=n.provider??null,u=n.usage?.in??0,d=n.usage?.out??0,f=n.stop??null,n.error&&(p=1)):r===`tool_result`&&(i=U(n.content),a=n.callId??null,o=n.tool??null,s=n.args?JSON.stringify(n.args):null,p=+!!n.isError),this.#e.prepare(`INSERT INTO messages (session_id, seq, role, content, tool_call_id, tool_name, tool_args, model, provider, usage_input, usage_output, stop_reason, is_error, ts)
99
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(e,t,r,i,a,o,s,c,l,u,d,f,p,n.ts??Date.now())}async prune(){this.#e.exec(`DELETE FROM sessions WHERE message_count = 0`)}close(){ze()}};let G=null;async function Ge(e){return G||(G=new We(e?`${e}/state.db`:void 0),G)}const Ke=new Set([`.jpg`,`.jpeg`,`.png`,`.gif`,`.webp`]);function K(e,t){let n=s(e,t);if(n!==e&&!n.startsWith(`${e}/`))throw Error(`Path outside project: ${t}`);return n}function qe(e){return{def:{name:`read`,description:`Read file contents. Supports text and images (jpg, png, gif, webp). Text output is truncated to 2000 lines.`,parameters:{type:`object`,properties:{path:{type:`string`,description:`Path to file (relative or absolute)`},offset:{type:`number`,description:`Start line (1-based, default 1)`},limit:{type:`number`,description:`Max lines to read (default 2000)`}},required:[`path`]}},async execute(t){try{let n=K(e,t.path),i=r(n).toLowerCase();if(Ke.has(i))return{content:[{type:`image`,data:(await f(n)).toString(`base64`),mime:i===`.jpg`?`image/jpeg`:`image/${i.slice(1)}`}],isError:!1};let a=(await f(n,`utf-8`)).split(`
100
+ `),o=Math.max(0,(Number(t.offset??1)||1)-1),s=Number(t.limit??2e3)||2e3,c=a.slice(o,o+s),l=o+s<a.length;return{content:[E(c.join(`
101
+ `)+(l?`\n…${a.length-o-s} more lines`:``))],isError:!1}}catch(e){return{content:[E(`Error reading file: ${e.message}`)],isError:!0}}}}}function Je(e){return{def:{name:`write`,description:`Write content to a file. Creates the file and parent directories if needed.`,parameters:{type:`object`,properties:{path:{type:`string`,description:`Path to file`},content:{type:`string`,description:`Content to write`}},required:[`path`,`content`]}},async execute(t){try{let r=K(e,t.path),i=t.content;await d(n(r),{recursive:!0}),await h(r,i);let a=D(e,r);return{content:[E(`Wrote ${i.length} bytes → ${a}`)],isError:!1}}catch(e){return{content:[E(`Error writing file: ${e.message}`)],isError:!0}}}}}function Ye(e){return{def:{name:`edit`,description:`Edit a file using exact text replacement. Each edit's oldText must be unique in the file.`,parameters:{type:`object`,properties:{path:{type:`string`,description:`Path to file`},edits:{type:`array`,description:`Array of {oldText, newText} replacements. oldText must be unique. Non-overlapping.`,items:{type:`object`,properties:{oldText:{type:`string`,description:`Exact text to find (must be unique)`},newText:{type:`string`,description:`Replacement text`}},required:[`oldText`,`newText`]}}},required:[`path`,`edits`]}},async execute(t){try{let n=K(e,t.path),r;try{r=await f(n,`utf-8`)}catch{return{content:[E(`File not found: ${t.path}`)],isError:!0}}let i=t.edits;for(let e of i){let t=r.split(e.oldText).length-1;if(t===0)return{content:[E(`oldText not found: "${e.oldText.slice(0,80)}…"`)],isError:!0};if(t>1)return{content:[E(`oldText found ${t} times — add surrounding context to make it unique: "${e.oldText.slice(0,60)}…"`)],isError:!0}}for(let e of i)r=r.replace(e.oldText,e.newText);return await h(n,r),{content:[E(`Edited ${D(e,n)} (${i.length} replacement${i.length>1?`s`:``})`)],isError:!1}}catch(e){return{content:[E(`Error editing file: ${e.message}`)],isError:!0}}}}}function Xe(e){return{def:{name:`git`,description:`Execute safe, non-interactive git commands (status, diff, log, add, commit) in the repository.`,parameters:{type:`object`,properties:{action:{type:`string`,enum:[`status`,`diff`,`log`,`add`,`commit`],description:`The git action to execute`},args:{type:`array`,description:`Optional additional arguments or file paths for the git action`,items:{type:`string`}}},required:[`action`]}},async execute(t,n){let r=t.action,i=t.args||[];if(!new Set([`status`,`diff`,`log`,`add`,`commit`]).has(r))return{content:[E(`Error: Git action '${r}' is not supported.`)],isError:!0};try{let t=[`git`,r,...i],a=w(t[0],t.slice(1),{cwd:e,stdio:[`ignore`,`pipe`,`pipe`],env:{...process.env,PAGER:`cat`}}),o=``,s=``;a.stdout.on(`data`,e=>{o+=e.toString()}),a.stderr.on(`data`,e=>{s+=e.toString()});let c=()=>{a.kill(`SIGKILL`),a.stdout.destroy(),a.stderr.destroy()};n?.addEventListener(`abort`,c,{once:!0});let l;try{l=await new Promise((e,t)=>{a.on(`error`,t),a.on(`close`,t=>e(t??-1))})}finally{n?.removeEventListener(`abort`,c)}let u=5e4,d=``;return o&&(d+=o.slice(0,u)),s&&(d&&(d+=`
65
102
  `),d+=s.slice(0,u-d.length)),d.length>=u&&(d+=`
66
- …truncated`),{content:[A(d||`(no output)`)],isError:l!==0}}catch(e){return{content:[A(`Error running git: ${e.message}`)],isError:!0}}}}}function He(e){return{def:{name:`glob`,description:`Find files by glob pattern (e.g. **/*.ts, src/**/*.test.ts).`,parameters:{type:`object`,properties:{pattern:{type:`string`,description:`Glob pattern (e.g. **/*.ts)`},path:{type:`string`,description:`Directory to search in (default .)`},nocase:{type:`boolean`,description:`Case-insensitive search (default false)`}},required:[`pattern`]}},async execute(t){try{let n=t.path||`.`,r=s(e,n);if(r!==e&&!r.startsWith(`${e}/`))throw Error(`Path outside project: ${n}`);let i=t.pattern,a=(await E(i,{cwd:r,nocase:!!t.nocase})).slice(0,500),c=o(e,r),l=c?`${c}/`:``,u=a.map(e=>l+e);return{content:[A(u.length>0?u.join(`
67
- `):`No files found`)],isError:!1}}catch(e){return{content:[A(`Error: ${e.message}`)],isError:!0}}}}}function Ue(e){return{def:{name:`grep`,description:`Search file contents with a regex pattern. Returns matching lines with file paths and line numbers.`,parameters:{type:`object`,properties:{pattern:{type:`string`,description:`Regex pattern to search for`},path:{type:`string`,description:`Directory or file to search in (default .)`},glob:{type:`string`,description:`File filter glob (e.g. *.ts)`}},required:[`pattern`]}},async execute(t,n){try{let r=t.path||`.`,i=s(e,r);if(i!==e&&!i.startsWith(`${e}/`))throw Error(`Path outside project: ${r}`);let a=t.pattern,c=t.glob,l=o(e,i)||`.`;try{let t=[`rg`,`--line-number`,`--max-count`,`200`];c&&t.push(`--glob=${c}`),t.push(`--`,a,l);let r=T(t[0],t.slice(1),{cwd:e,stdio:[`ignore`,`pipe`,`pipe`]}),i=()=>{r.kill(),r.stdout.destroy(),r.stderr.destroy()};n?.addEventListener(`abort`,i,{once:!0});let o=``;r.stdout.on(`data`,e=>{o+=e.toString()});let s;try{s=await new Promise((e,t)=>{r.on(`error`,t),r.on(`close`,t=>e(t??-1))})}finally{n?.removeEventListener(`abort`,i)}if(s===0)return{content:[A(o.split(`
103
+ …truncated`),{content:[E(d||`(no output)`)],isError:l!==0}}catch(e){return{content:[E(`Error running git: ${e.message}`)],isError:!0}}}}}function Ze(e){return{def:{name:`glob`,description:`Find files by glob pattern (e.g. **/*.ts, src/**/*.test.ts).`,parameters:{type:`object`,properties:{pattern:{type:`string`,description:`Glob pattern (e.g. **/*.ts)`},path:{type:`string`,description:`Directory to search in (default .)`},nocase:{type:`boolean`,description:`Case-insensitive search (default false)`}},required:[`pattern`]}},async execute(t){try{let n=t.path||`.`,r=s(e,n);if(r!==e&&!r.startsWith(`${e}/`))throw Error(`Path outside project: ${n}`);let i=t.pattern,a=(await te(i,{cwd:r,nocase:!!t.nocase})).slice(0,500),c=o(e,r),l=c?`${c}/`:``,u=a.map(e=>l+e);return{content:[E(u.length>0?u.join(`
104
+ `):`No files found`)],isError:!1}}catch(e){return{content:[E(`Error: ${e.message}`)],isError:!0}}}}}function Qe(e){return{def:{name:`grep`,description:`Search file contents with a regex pattern. Returns matching lines with file paths and line numbers.`,parameters:{type:`object`,properties:{pattern:{type:`string`,description:`Regex pattern to search for`},path:{type:`string`,description:`Directory or file to search in (default .)`},glob:{type:`string`,description:`File filter glob (e.g. *.ts)`}},required:[`pattern`]}},async execute(t,n){try{let r=t.path||`.`,i=s(e,r);if(i!==e&&!i.startsWith(`${e}/`))throw Error(`Path outside project: ${r}`);let a=t.pattern,c=t.glob,l=o(e,i)||`.`;try{let t=[`rg`,`--line-number`,`--max-count`,`200`];c&&t.push(`--glob=${c}`),t.push(`--`,a,l);let r=w(t[0],t.slice(1),{cwd:e,stdio:[`ignore`,`pipe`,`pipe`]}),i=()=>{r.kill(),r.stdout.destroy(),r.stderr.destroy()};n?.addEventListener(`abort`,i,{once:!0});let o=``;r.stdout.on(`data`,e=>{o+=e.toString()});let s;try{s=await new Promise((e,t)=>{r.on(`error`,t),r.on(`close`,t=>e(t??-1))})}finally{n?.removeEventListener(`abort`,i)}if(s===0)return{content:[E(o.split(`
68
105
  `).slice(0,200).join(`
69
- `)||`No matches`)],isError:!1}}catch{}let u=await E(c||`**/*`,{cwd:i,ignore:[`**/node_modules/**`,`**/.git/**`]}),d=l===`.`?``:`${l}/`,f=new RegExp(a,`i`),m=[];for(let e of u.slice(0,500)){if(n?.aborted)break;try{let t=(await p(s(i,e),`utf-8`)).split(`
70
- `);for(let n=0;n<t.length&&m.length<200;n++){let r=t[n];r&&f.test(r)&&m.push(`${d}${e}:${n+1}:${r}`)}}catch{}}return{content:[A(m.join(`
71
- `)||`No matches`)],isError:!1}}catch(e){return{content:[A(`Error: ${e.message}`)],isError:!0}}}}}function We(e){return{def:{name:`ls`,description:`List directory contents.`,parameters:{type:`object`,properties:{path:{type:`string`,description:`Directory to list (default .)`}},required:[]}},async execute(t){try{return{content:[A((await m(s(e,t.path||`.`),{withFileTypes:!0})).map(e=>{let t=e.isDirectory()?`/`:e.isSymbolicLink()?`@`:``;return`${e.name}${t}`}).join(`
72
- `)||`(empty)`)],isError:!1}}catch(e){return{content:[A(`Error: ${e.message}`)],isError:!0}}}}}function Ge(e){return{def:{name:`tree`,description:`Print a visual directory tree structure, ignoring common ignored folders like node_modules and .git.`,parameters:{type:`object`,properties:{path:{type:`string`,description:`Directory to start tree from (default .)`},depth:{type:`number`,description:`Maximum depth to traverse (default 3)`}},required:[]}},async execute(t){try{let n=s(e,t.path||`.`),r=Number(t.depth??3)||3,i=new Set([`.git`,`node_modules`,`dist`,`build`,`.svelte-kit`,`.next`,`out`,`.scannerwork`,`coverage`]);async function a(e,t,n){if(t>r)return``;let o=``,c=(await m(e,{withFileTypes:!0})).filter(e=>!i.has(e.name)).sort((e,t)=>e.isDirectory()&&!t.isDirectory()?-1:!e.isDirectory()&&t.isDirectory()?1:e.name.localeCompare(t.name));for(let r=0;r<c.length;r++){let i=c[r],l=r===c.length-1,u=l?`└── `:`├── `,d=n+(l?` `:`│ `);o+=`${n}${u}${i.name}${i.isDirectory()?`/`:``}\n`,i.isDirectory()&&(o+=await a(s(e,i.name),t+1,d))}return o}return{content:[A(await a(n,1,``)||`(empty)`)],isError:!1}}catch(e){return{content:[A(`Error: ${e.message}`)],isError:!0}}}}}function Ke(e){return{def:{name:`bash`,description:`Execute a shell command. Returns stdout and stderr. Timeout after N seconds (default 120).`,parameters:{type:`object`,properties:{command:{type:`string`,description:`Shell command to run`},timeout:{type:`number`,description:`Timeout in seconds (default 120)`}},required:[`command`]}},async execute(t,n){let r=t.command,i=(Number(t.timeout)||120)*1e3;try{let t=T(`sh`,[`-c`,r],{cwd:e,stdio:[`ignore`,`pipe`,`pipe`]}),a=``,o=``;t.stdout.on(`data`,e=>{a+=e.toString()}),t.stderr.on(`data`,e=>{o+=e.toString()});let s=!1,c=setTimeout(()=>{s=!0,t.kill(`SIGKILL`),t.stdout.destroy(),t.stderr.destroy()},i),l=()=>{s=!0,t.kill(`SIGKILL`),t.stdout.destroy(),t.stderr.destroy()};n?.addEventListener(`abort`,l,{once:!0});let u;try{u=await new Promise((e,n)=>{t.on(`error`,n),t.on(`close`,t=>e(t??-1))})}finally{clearTimeout(c),n?.removeEventListener(`abort`,l)}let d=5e4,f=``;return a&&(f+=a.slice(0,d)),o&&(f&&(f+=`
106
+ `)||`No matches`)],isError:!1}}catch{}let u=await te(c||`**/*`,{cwd:i,ignore:[`**/node_modules/**`,`**/.git/**`]}),d=l===`.`?``:`${l}/`,p=new RegExp(a,`i`),m=[];for(let e of u.slice(0,500)){if(n?.aborted)break;try{let t=(await f(s(i,e),`utf-8`)).split(`
107
+ `);for(let n=0;n<t.length&&m.length<200;n++){let r=t[n];r&&p.test(r)&&m.push(`${d}${e}:${n+1}:${r}`)}}catch{}}return{content:[E(m.join(`
108
+ `)||`No matches`)],isError:!1}}catch(e){return{content:[E(`Error: ${e.message}`)],isError:!0}}}}}function $e(e){return{def:{name:`ls`,description:`List directory contents.`,parameters:{type:`object`,properties:{path:{type:`string`,description:`Directory to list (default .)`}},required:[]}},async execute(t){try{return{content:[E((await p(s(e,t.path||`.`),{withFileTypes:!0})).map(e=>{let t=e.isDirectory()?`/`:e.isSymbolicLink()?`@`:``;return`${e.name}${t}`}).join(`
109
+ `)||`(empty)`)],isError:!1}}catch(e){return{content:[E(`Error: ${e.message}`)],isError:!0}}}}}function et(e){return{def:{name:`tree`,description:`Print a visual directory tree structure, ignoring common ignored folders like node_modules and .git.`,parameters:{type:`object`,properties:{path:{type:`string`,description:`Directory to start tree from (default .)`},depth:{type:`number`,description:`Maximum depth to traverse (default 3)`}},required:[]}},async execute(t){try{let n=s(e,t.path||`.`),r=Number(t.depth??3)||3,i=new Set([`.git`,`node_modules`,`dist`,`build`,`.svelte-kit`,`.next`,`out`,`.scannerwork`,`coverage`]);async function a(e,t,n){if(t>r)return``;let o=``,c=(await p(e,{withFileTypes:!0})).filter(e=>!i.has(e.name)).sort((e,t)=>e.isDirectory()&&!t.isDirectory()?-1:!e.isDirectory()&&t.isDirectory()?1:e.name.localeCompare(t.name));for(let r=0;r<c.length;r++){let i=c[r],l=r===c.length-1,u=l?`└── `:`├── `,d=n+(l?` `:`│ `);o+=`${n}${u}${i.name}${i.isDirectory()?`/`:``}\n`,i.isDirectory()&&(o+=await a(s(e,i.name),t+1,d))}return o}return{content:[E(await a(n,1,``)||`(empty)`)],isError:!1}}catch(e){return{content:[E(`Error: ${e.message}`)],isError:!0}}}}}function tt(e){return{def:{name:`bash`,description:`Execute a shell command. Returns stdout and stderr. Timeout after N seconds (default 120).`,parameters:{type:`object`,properties:{command:{type:`string`,description:`Shell command to run`},timeout:{type:`number`,description:`Timeout in seconds (default 120)`}},required:[`command`]}},async execute(t,n){let r=t.command,i=(Number(t.timeout)||120)*1e3;try{let t=w(`sh`,[`-c`,r],{cwd:e,stdio:[`ignore`,`pipe`,`pipe`]}),a=``,o=``;t.stdout.on(`data`,e=>{a+=e.toString()}),t.stderr.on(`data`,e=>{o+=e.toString()});let s=!1,c=setTimeout(()=>{s=!0,t.kill(`SIGKILL`),t.stdout.destroy(),t.stderr.destroy()},i),l=()=>{s=!0,t.kill(`SIGKILL`),t.stdout.destroy(),t.stderr.destroy()};n?.addEventListener(`abort`,l,{once:!0});let u;try{u=await new Promise((e,n)=>{t.on(`error`,n),t.on(`close`,t=>e(t??-1))})}finally{clearTimeout(c),n?.removeEventListener(`abort`,l)}let d=5e4,f=``;return a&&(f+=a.slice(0,d)),o&&(f&&(f+=`
73
110
  `),f+=o.slice(0,d-f.length)),f.length>=d&&(f+=`
74
- …truncated`),s&&(f+=`\n[timeout after ${i/1e3}s]`),f+=`\n[exit ${u}]`,{content:[A(f)],isError:u!==0||s}}catch(e){return{content:[A(`Error: ${e.message}`)],isError:!0}}}}}const q=5e4;function J(e,t,n){let r;do r=e,e=e.replace(t,n);while(e!==r);return e}function Y(e){let t=e;return t=J(t,/<!--[\s\S]*?-->/g,``),t=J(t,/<script[\s\S]*?<\/script\s*>/gi,``),t=J(t,/<style[\s\S]*?<\/style\s*>/gi,``),t=t.replace(/<a[^>]*href=["']?([^"'>\s]*)["']?[^>]*>([\s\S]*?)<\/a>/gi,`[$2]($1)`).replace(/<\/?(p|div|br|h[1-6]|li|tr|blockquote|pre|hr)[^>]*>/gi,`
111
+ …truncated`),s&&(f+=`\n[timeout after ${i/1e3}s]`),f+=`\n[exit ${u}]`,{content:[E(f)],isError:u!==0||s}}catch(e){return{content:[E(`Error: ${e.message}`)],isError:!0}}}}}const q=5e4;function J(e,t,n){let r;do r=e,e=e.replace(t,n);while(e!==r);return e}function Y(e){let t=e;return t=J(t,/<!--[\s\S]*?-->/g,``),t=J(t,/<script[\s\S]*?<\/script\s*>/gi,``),t=J(t,/<style[\s\S]*?<\/style\s*>/gi,``),t=t.replace(/<a[^>]*href=["']?([^"'>\s]*)["']?[^>]*>([\s\S]*?)<\/a>/gi,`[$2]($1)`).replace(/<\/?(p|div|br|h[1-6]|li|tr|blockquote|pre|hr)[^>]*>/gi,`
75
112
  `).replace(/<[^>]+>/g,``).replace(/&lt;/g,`<`).replace(/&gt;/g,`>`).replace(/&quot;/g,`"`).replace(/&#34;/g,`"`).replace(/&#x22;/g,`"`).replace(/&#39;/g,`'`).replace(/&#x27;/g,`'`).replace(/&apos;/g,`'`).replace(/&ldquo;/g,`"`).replace(/&rdquo;/g,`"`).replace(/&lsquo;/g,`'`).replace(/&rsquo;/g,`'`).replace(/&nbsp;/g,` `).replace(/&amp;/g,`&`).replace(/[ \t]+/g,` `).replace(/\n{3,}/g,`
76
113
 
77
- `).trim(),t.length>q&&(t=`${t.slice(0,q)}\n…truncated`),t}function qe(){return{def:{name:`web_search`,description:`Search the web using DuckDuckGo. Returns up to 10 results with titles, URLs, and snippets. Use this when you need information from the internet.`,parameters:{type:`object`,properties:{query:{type:`string`,description:`Search query`}},required:[`query`]}},async execute(e,t){let n=e.query;if(!n.trim())return{content:[A(`Error: empty search query`)],isError:!0};try{let e=`https://html.duckduckgo.com/html/?q=${encodeURIComponent(n)}`,r=await fetch(e,{signal:t??void 0,headers:{"User-Agent":`Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36`}});if(!r.ok)return{content:[A(`Search failed: HTTP ${r.status}`)],isError:!0};let i=await r.text(),a=[],o=/<div[^>]*class="[^"]*result__body[^"]*"[^>]*>/gi,s=[];for(let e of i.matchAll(o))e.index!==void 0&&s.push(e.index);if(s.length>0)for(let e=0;e<s.length;e++){let t=s[e],n=s[e+1]??i.length;a.push(i.slice(t,n))}let c=[],l=/<a[^>]*class="result__a"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/i,u=/<a[^>]*class="result__snippet"[^>]*>([\s\S]*?)<\/a>/i;for(let e of a){if(c.length>=10)break;let t=l.exec(e);if(!t)continue;let n=t[1],r=Y(t[2]),i=u.exec(e),a=i?Y(i[1]):``,o=n;try{let e=n.startsWith(`//`)?`https:${n}`:n.startsWith(`/`)?`https://duckduckgo.com${n}`:n,t=new URL(e).searchParams.get(`uddg`);t&&(o=t)}catch{}c.push(`## ${r}\n${o}\n${a}`)}return c.length===0?{content:[A(`No results found.`)],isError:!1}:{content:[A(c.join(`
114
+ `).trim(),t.length>q&&(t=`${t.slice(0,q)}\n…truncated`),t}function nt(){return{def:{name:`web_search`,description:`Search the web using DuckDuckGo. Returns up to 10 results with titles, URLs, and snippets. Use this when you need information from the internet.`,parameters:{type:`object`,properties:{query:{type:`string`,description:`Search query`}},required:[`query`]}},async execute(e,t){let n=e.query;if(!n.trim())return{content:[E(`Error: empty search query`)],isError:!0};try{let e=`https://html.duckduckgo.com/html/?q=${encodeURIComponent(n)}`,r=await fetch(e,{signal:t??void 0,headers:{"User-Agent":`Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36`}});if(!r.ok)return{content:[E(`Search failed: HTTP ${r.status}`)],isError:!0};let i=await r.text(),a=[],o=/<div[^>]*class="[^"]*result__body[^"]*"[^>]*>/gi,s=[];for(let e of i.matchAll(o))e.index!==void 0&&s.push(e.index);if(s.length>0)for(let e=0;e<s.length;e++){let t=s[e],n=s[e+1]??i.length;a.push(i.slice(t,n))}let c=[],l=/<a[^>]*class="result__a"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/i,u=/<a[^>]*class="result__snippet"[^>]*>([\s\S]*?)<\/a>/i;for(let e of a){if(c.length>=10)break;let t=l.exec(e);if(!t)continue;let n=t[1],r=Y(t[2]),i=u.exec(e),a=i?Y(i[1]):``,o=n;try{let e=n.startsWith(`//`)?`https:${n}`:n.startsWith(`/`)?`https://duckduckgo.com${n}`:n,t=new URL(e).searchParams.get(`uddg`);t&&(o=t)}catch{}c.push(`## ${r}\n${o}\n${a}`)}return c.length===0?{content:[E(`No results found.`)],isError:!1}:{content:[E(c.join(`
78
115
 
79
- `))],isError:!1}}catch(e){let t=e.message;return t.includes(`abort`)?{content:[A(`Search aborted.`)],isError:!0}:{content:[A(`Search error: ${t}`)],isError:!0}}}}}function Je(){return{def:{name:`web_fetch`,description:`Fetch and read the content of a web page. Returns the page text with HTML tags stripped. Useful for reading documentation, articles, or API references.`,parameters:{type:`object`,properties:{url:{type:`string`,description:`URL to fetch`}},required:[`url`]}},async execute(e,t){let n=e.url;if(!n.trim())return{content:[A(`Error: empty URL`)],isError:!0};try{new URL(n)}catch{return{content:[A(`Error: invalid URL: ${n}`)],isError:!0}}try{let e=await fetch(n,{signal:t??void 0,headers:{"User-Agent":`Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36`,Accept:`text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8`},redirect:`follow`});if(!e.ok)return{content:[A(`Fetch failed: HTTP ${e.status} ${e.statusText}`)],isError:!0};let r=(e.headers.get(`content-type`)??``).toLowerCase(),i=await e.text();return r.includes(`text/html`)||r.includes(`application/xhtml+xml`)||i.trim().toLowerCase().startsWith(`<!doctype html`)||i.trim().toLowerCase().startsWith(`<html`)?{content:[A(Y(i))],isError:!1}:{content:[A(i.length>q?`${i.slice(0,q)}\n…truncated`:i)],isError:!1}}catch(e){let t=e.message;return t.includes(`abort`)?{content:[A(`Fetch aborted.`)],isError:!0}:{content:[A(`Fetch error: ${t}`)],isError:!0}}}}}function Ye(e){return[Re(e),ze(e),Be(e),Ke(e),He(e),Ue(e),We(e),Ge(e),Ve(e),qe(),Je()]}const Xe=n(ee(import.meta.url));let X=null,Z=null;async function Q(){if(Z)return Z;try{let e=await p(a(Xe,`..`,`package.json`),`utf-8`);return Z=JSON.parse(e).version??`0.0.0`,Z}catch{return`0.0.0`}}async function Ze(){if(X)return X;try{let e=T(`npm`,[`info`,`novacode`,`version`],{stdio:[`ignore`,`pipe`,`ignore`]}),t=await new Promise((t,n)=>{let r=``;e.stdout.on(`data`,e=>{r+=e.toString()}),e.on(`error`,n),e.on(`close`,()=>t(r.trim()))});if(t)return X=t,t}catch{}return null}async function Qe(){let e=await Q(),t=await Ze();return t?{hasUpdate:te.gt(t,e),current:e,latest:t}:null}async function $(e=!1){try{let t=T(`npm`,[`update`,`-g`,`novacode`],{stdio:e?`ignore`:`inherit`}),n=await new Promise((e,n)=>{t.on(`error`,n),t.on(`close`,t=>e(t??-1))});return n===0?(e||console.log(`✓ novacode updated to latest version successfully.`),!0):(e||(console.error(`Update failed (exit code ${n})`),process.exit(1)),!1)}catch(t){return e||(console.error(`Update failed: ${t.message}`),process.exit(1)),!1}}function $e(){let{values:t,positionals:n}=e({options:{help:{type:`boolean`,short:`h`},version:{type:`boolean`,short:`v`},provider:{type:`string`},model:{type:`string`},"api-key":{type:`string`},session:{type:`string`,short:`s`},resume:{type:`boolean`},n:{type:`string`},limit:{type:`string`},all:{type:`boolean`}},strict:!1,allowPositionals:!0});return{flags:t,args:n}}function et(e,t){return F.find(n=>t?n.provider===t&&n.id===e:n.id===e)}async function tt(){let{flags:e,args:n}=$e();if(e.version){let e=await Q();console.log(`nova ${e}`),process.exit(0)}if(e.help&&(console.log(`nova — open-source coding agent
116
+ `))],isError:!1}}catch(e){let t=e.message;return t.includes(`abort`)?{content:[E(`Search aborted.`)],isError:!0}:{content:[E(`Search error: ${t}`)],isError:!0}}}}}function rt(){return{def:{name:`web_fetch`,description:`Fetch and read the content of a web page. Returns the page text with HTML tags stripped. Useful for reading documentation, articles, or API references.`,parameters:{type:`object`,properties:{url:{type:`string`,description:`URL to fetch`}},required:[`url`]}},async execute(e,t){let n=e.url;if(!n.trim())return{content:[E(`Error: empty URL`)],isError:!0};try{new URL(n)}catch{return{content:[E(`Error: invalid URL: ${n}`)],isError:!0}}try{let e=await fetch(n,{signal:t??void 0,headers:{"User-Agent":`Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36`,Accept:`text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8`},redirect:`follow`});if(!e.ok)return{content:[E(`Fetch failed: HTTP ${e.status} ${e.statusText}`)],isError:!0};let r=(e.headers.get(`content-type`)??``).toLowerCase(),i=await e.text();return r.includes(`text/html`)||r.includes(`application/xhtml+xml`)||i.trim().toLowerCase().startsWith(`<!doctype html`)||i.trim().toLowerCase().startsWith(`<html`)?{content:[E(Y(i))],isError:!1}:{content:[E(i.length>q?`${i.slice(0,q)}\n…truncated`:i)],isError:!1}}catch(e){let t=e.message;return t.includes(`abort`)?{content:[E(`Fetch aborted.`)],isError:!0}:{content:[E(`Fetch error: ${t}`)],isError:!0}}}}}function it(e){return[qe(e),Je(e),Ye(e),tt(e),Ze(e),Qe(e),$e(e),et(e),Xe(e),nt(),rt()]}const at=n(ne(import.meta.url));let X=null,Z=null;async function Q(){if(Z)return Z;try{let e=await f(a(at,`..`,`package.json`),`utf-8`);return Z=JSON.parse(e).version??`0.0.0`,Z}catch{return`0.0.0`}}async function ot(){if(X)return X;try{let e=w(`npm`,[`info`,`novacode`,`version`],{stdio:[`ignore`,`pipe`,`ignore`]}),t=await new Promise((t,n)=>{let r=``;e.stdout.on(`data`,e=>{r+=e.toString()}),e.on(`error`,n),e.on(`close`,()=>t(r.trim()))});if(t)return X=t,t}catch{}return null}async function st(){let e=await Q(),t=await ot();return t?{hasUpdate:re.gt(t,e),current:e,latest:t}:null}async function $(e=!1){try{let t=w(`npm`,[`update`,`-g`,`novacode`],{stdio:e?`ignore`:`inherit`}),n=await new Promise((e,n)=>{t.on(`error`,n),t.on(`close`,t=>e(t??-1))});return n===0?(e||console.log(`✓ novacode updated to latest version successfully.`),!0):(e||(console.error(`Update failed (exit code ${n})`),process.exit(1)),!1)}catch(t){return e||(console.error(`Update failed: ${t.message}`),process.exit(1)),!1}}function ct(){let{values:t,positionals:n}=e({options:{help:{type:`boolean`,short:`h`},version:{type:`boolean`,short:`v`},provider:{type:`string`},model:{type:`string`},"api-key":{type:`string`},sessions:{type:`string`,short:`s`},resume:{type:`boolean`,short:`r`},all:{type:`boolean`}},strict:!1,allowPositionals:!0});return{flags:t,args:n}}function lt(e,t){return A.find(n=>t?n.provider===t&&n.id===e:n.id===e)}async function ut(){let e=Number(process.versions.node.split(`.`)[0]);(!e||e<24)&&(console.error(`novacode requires Node.js >= 24. You have ${process.version}.`),console.error(`Upgrade: https://nodejs.org/`),process.exit(1));let{flags:n,args:r}=ct();if(n.version){let e=await Q();console.log(`nova ${e}`),process.exit(0)}if(n.help&&(console.log(`nova — open-source coding agent
80
117
 
81
118
  Usage:
82
119
  nova Interactive mode
83
120
  nova update Update to latest version
84
- nova --session ls List sessions (last 10 by default)
85
- nova --session ls -n N List last N sessions
86
- nova --session rm <id> Delete a specific session
87
- nova --session rm --all Delete all sessions
88
- nova --session <id> Resume a session by ID
89
- nova --resume Resume the most recent session
121
+ nova -s ls [limit] List sessions (last 10 by default)
122
+ nova -s rm <id> Delete a specific session
123
+ nova -s rm --all Delete all sessions
124
+ nova -s <id> Resume a session by ID
125
+ nova -r, --resume Resume the most recent session
90
126
 
91
127
  Options:
92
128
  -h, --help Show help
@@ -94,7 +130,8 @@ Options:
94
130
  --provider <id> Provider to use
95
131
  --model <id> Model to use
96
132
  --api-key <key> API key override
97
- -s, --session <id> Resume/manage session`),process.exit(0)),n[0]===`update`){await $();return}n.length>0&&!e.session&&(console.error(t.yellow(`Unknown command: ${n.join(` `)}`)),console.error("Run `nova --help` for usage."),process.exit(1));let r=new AbortController,i=()=>{r.abort(),process.stderr.write(`
133
+ -s, --sessions <id> Resume/manage sessions
134
+ -r, --resume Resume the most recent session`),process.exit(0)),r[0]===`update`){await $();return}r.length>0&&!n.sessions&&(console.error(t.yellow(`Unknown command: ${r.join(` `)}`)),console.error("Run `nova --help` for usage."),process.exit(1));let i=new AbortController,a=()=>{i.abort(),process.stderr.write(`
98
135
  Aborted.
99
- `),process.exit(130)};process.on(`SIGINT`,i),process.on(`SIGTERM`,i);let a=await(await _e()?H():Te()),o=await U(),s=await Ie();if(await s.prune(),e.session){let t=e.session;if(t===`ls`||t===`list`){await N(s,[`ls`],{limit:parseInt(e.n||e.limit||`10`,10)});return}if(t===`rm`||t===`delete`){let t=n[0],r=!!e.all;await N(s,[`rm`,t??``],{all:r});return}}let c=null;e.resume?(c=await s.latest(),c||(console.error(`No recent session found to resume.`),process.exit(1))):e.session&&(c=await s.get(e.session),c||(console.error(`Session not found: ${e.session}`),process.exit(1)));let l=e.provider||c?.provider||a.provider,u=e.model||c?.model||a.model,d=e[`api-key`]||o.apiKeys[l],f=I(l);f||(console.error(`Unknown provider: ${l}`),console.error(`Available: ${I(`glm`)?`glm, `:``}gemini, deepseek, openai`),process.exit(1)),d||(console.error(`No API key for ${f.name}. Set ${f.envKey} or run nova for onboarding.`),process.exit(1));let p=et(u,l);if(!p){console.error(`Unknown model: ${u}`),console.error(`Available models:`);for(let e of F.filter(e=>e.provider===l))console.error(` ${e.id} — ${e.name}`);process.exit(1)}let m=process.cwd(),h=Ye(m),{skills:g,agentsMd:_}=await Me(m),v=he(m,h,g,_??void 0);c||=await s.create(m,p.id,l);let y=c.id,b=await s.messages(y),x=new me({api:f.api,model:p,apiKey:d,baseUrl:f.baseUrl,system:v,tools:h,messages:b});process.off(`SIGINT`,i),process.off(`SIGTERM`,i);let{interactive:S}=await import(`./app-CbJSUNmf.mjs`);await S(x,s,y,g,!!_)}process.on(`unhandledRejection`,e=>{console.error(`Unhandled rejection:`,e),process.exit(1)}),tt().catch(e=>{console.error(`Fatal:`,e),process.exit(1)});export{O as _,xe as a,H as c,F as d,P as f,ue as g,M as h,Se as i,ye as l,k as m,Q as n,be as o,I as p,$ as r,U as s,Qe as t,ve as u};
136
+ `),process.exit(130)};process.on(`SIGINT`,a),process.on(`SIGTERM`,a);let o=await(await Ce()?L():ke()),s=await R(),c=await Ge();if(await c.prune(),n.sessions){let e=n.sessions;if(e===`ls`||e===`list`){let e=r[0]?parseInt(r[0],10):10;await O(c,[`ls`],{limit:Number.isNaN(e)?10:e});return}if(e===`rm`||e===`delete`){let e=r[0],t=!!n.all;await O(c,[`rm`,e??``],{all:t});return}}let l=null;n.resume?(l=await c.latest(),l||(console.error(`No recent session found to resume.`),process.exit(1))):n.sessions&&(l=await c.get(n.sessions),l||(console.error(`Session not found: ${n.sessions}`),process.exit(1)));let u=n.provider||l?.provider||o.provider,d=n.model||l?.model||o.model,f=n[`api-key`]||s.apiKeys[u],p=j(u);p||(console.error(`Unknown provider: ${u}`),console.error(`Available: ${j(`glm`)?`glm, `:``}gemini, deepseek, openai`),process.exit(1)),f||(console.error(`No API key for ${p.name}. Set ${p.envKey} or run nova for onboarding.`),process.exit(1));let m=lt(d,u);if(!m){console.error(`Unknown model: ${d}`),console.error(`Available models:`);for(let e of A.filter(e=>e.provider===u))console.error(` ${e.id} — ${e.name}`);process.exit(1)}let h=process.cwd(),g=it(h),{skills:_,agentsMd:v}=await Ie(h),y=be(h,g,_,v??void 0);l||=await c.create(h,m.id,u);let b=l.id,x=await c.messages(b),S=new ye({api:p.api,model:m,apiKey:f,baseUrl:p.baseUrl,system:y,tools:g,messages:x});process.off(`SIGINT`,a),process.off(`SIGTERM`,a);let{interactive:C}=await import(`./app-C_2My7n6.mjs`);await C(S,c,b,_,!!v)}process.on(`unhandledRejection`,e=>{console.error(`Unhandled rejection:`,e),process.exit(1)}),ut().catch(e=>{console.error(`Fatal:`,e),process.exit(1)});export{de as _,Te as a,L as c,A as d,k as f,me as g,he as h,Ee as i,V as l,fe as m,Q as n,we as o,j as p,$ as r,R as s,st as t,B as u};
100
137
  //# sourceMappingURL=main.mjs.map