novacode 0.9.0 → 0.10.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.
@@ -0,0 +1,52 @@
1
+ import{t as e}from"./reset-C2XGbjKJ.mjs";import{C as t,S as n,_ as r,b as i,c as a,d as o,f as s,g as c,h as l,m as u,n as d,o as f,p,r as m,s as h,t as g,u as _,v,x as y,y as b}from"./main.mjs";import x from"chalk";import{Box as S,Static as ee,Text as C,render as w,useApp as te,useInput as ne}from"ink";import{memo as T,useCallback as E,useEffect as D,useMemo as re,useRef as O,useState as k}from"react";import{Fragment as A,jsx as j,jsxs as M}from"react/jsx-runtime";function N(e){return typeof e.content==`string`?e.content:e.content.filter(e=>e.type===`text`).map(e=>e.type===`text`?e.text:``).join(``)}function P(e){let t=0;if(typeof e.content==`string`)t+=e.content.length;else if(Array.isArray(e.content))for(let n of e.content)n.type===`text`&&(t+=n.text.length);return Math.ceil(t/4)}async function ie(e,t,r,i,a,o,s){let c=n(r),l=Math.max(2e4,Math.round(i.contextWindow*.1)),u=0,d=r.length;for(let e=r.length-1;e>=0;e--){let t=r[e],n=P(t);if(u+n<=l)u+=n,d=e;else break}if(d<=0)return{compacted:!1,tokensBefore:c,tokensAfter:c};let f=r.slice(d),p=await ae(r.slice(0,d).map(e=>e.role===`user`?`User: ${N(e)}`:e.role===`assistant`?`Assistant: ${N(e)}`:e.role===`tool_result`&&`tool`in e?`Tool(${e.tool}): ${N(e).slice(0,200)}`:``).join(`
2
+
3
+ `),i,a,o);if(!p)return{compacted:!1,tokensBefore:c,tokensAfter:c};let m={role:`user`,content:`[Prior context summary]\n${p}`,ts:Date.now()};await e.endSession(t,`compacted`);let h=await e.createContinuation(t,s,i.id,i.provider),g=[m,...f];for(let t=0;t<g.length;t++)await e.append(h.id,g[t]);let _=n(g);return _>=c?{compacted:!1,tokensBefore:c,tokensAfter:c}:{compacted:!0,summary:p,tokensBefore:c,tokensAfter:_,newSessionId:h.id}}async function ae(e,n,i,a){let o=r(n.provider);if(!o)return null;let s=t({apiFormat:o.apiFormat,model:n,apiKey:i,baseUrl:a,system:`Summarize this coding session concisely. Cover: what was asked, files touched, what was done, key decisions. Keep it under 300 words.`,messages:[{role:`user`,content:e,ts:Date.now()}],tools:[]}),c=``;for await(let e of s)e.type===`text_delta`&&e.text&&(c+=e.text);return c.trim()||null}async function oe(e,n,i,a){let o=r(n.provider);if(!o)return null;let s=e.slice(0,4).map(e=>e.role===`user`?`User: ${N(e)}`:e.role===`assistant`?`Assistant: ${N(e)}`:``).join(`
4
+ `),c=t({apiFormat:o.apiFormat,model:n,apiKey:i,baseUrl:a,system:`Generate a very short, descriptive, and concise title for this coding conversation. Do not use quotes or prefixes like 'Title:'. Max 6 words.`,messages:[{role:`user`,content:s,ts:Date.now()}],tools:[]}),l=``;for await(let e of c)e.type===`text_delta`&&e.text&&(l+=e.text);return l.trim().replace(/^["']|["']$/g,``)||null}async function F(e,t,n){let r=await ie(t,n,e.messages,e.model,e.apiKey,e.baseUrl,process.cwd());if(r.compacted){let i=await t.messages(r.newSessionId??n);e.setMessages(i);let a=Math.round((r.tokensBefore-r.tokensAfter)/r.tokensBefore*100);return{result:x.green(`✓ Compacted (${a}% reduction)`),newSessionId:r.newSessionId}}return{result:x.yellow(`Context is small enough, no compaction needed.`)}}async function I(e,t,n){let i=await o(),a=await _();if(e)return await L(e.trim(),t);if(!n)return x.red(`Prompts not available in this context`);let s=u.filter(e=>r(e.provider)&&!!a.apiKeys[e.provider]);if(!s.length)return x.yellow(`No models available. Use /providers to add a provider API key.`);let c=Math.max(...s.map(e=>e.id.length),20),l=[];for(let e of s){let t=e.id===i.model&&e.provider===i.provider,n=r(e.provider);l.push({value:`${e.provider}:${e.id}`,label:`${t?x.green(`●`):`○`} ${e.id.padEnd(c+2)} ${R(e.contextWindow).padEnd(8)}`,hint:n.name})}let d=await n.select({message:`Model`,options:l});if(!d)return``;let[f,m]=d.split(`:`),h=u.find(e=>e.provider===f&&e.id===m),g=r(f);return!h||!g?x.red(`Error: Model or provider not found`):(i.provider=f,i.model=m,await p(i),t.updateConfig({apiFormat:g.apiFormat,model:h,apiKey:a.apiKeys[f]??``,baseUrl:g.baseUrl}),x.green(`✓ Switched to ${m}`))}async function L(e,t){let n=await o(),i=await _(),a=u.find(t=>t.id===e);if(!a)return x.yellow(`"${e}" not found. Use /models`);let s=a.provider;if(!i.apiKeys[s])return x.yellow(`No API key configured for ${s}. Use /providers`);let c=r(s);return c?(n.provider=s,n.model=e,await p(n),t.updateConfig({apiFormat:c.apiFormat,model:a,apiKey:i.apiKeys[s],baseUrl:c.baseUrl}),x.green(`✓ Switched to ${e}`)):x.red(`Error: Provider not found`)}const R=e=>e>=1e6?`${e/1e6}M`:`${e/1e3}K`;async function z(e,t){if(!t)return x.red(`Prompts not available in this context`);let n=await o(),r=await _(),i=l.filter(e=>!!r.apiKeys[e.id]).sort((e,t)=>e.name.localeCompare(t.name)),a=i.length===0?x.dim(`No providers configured. Use 'Add Provider' below.`):i.map(e=>{let t=e.id===n.provider,r=t?x.green(` ●`):``,i=t?n.model:c(e.id)?.id??``;return` ✅ ${e.name.padEnd(24)} ${i}${r}`}).join(`
5
+ `),s=await t.select({message:`Action`,header:a,options:[{value:`add`,label:`Add Provider`},{value:`update`,label:`Update API Key`},{value:`remove`,label:`Remove API Key`},{value:`default`,label:`Set Default Provider`},{value:`back`,label:`Back`}]});return!s||s===`back`?``:s===`add`?B(e,t):s===`update`?V(e,t):s===`remove`?H(e,t):s===`default`?U(e,t):``}async function B(e,t){let n=await _(),i=await o(),a=l.filter(e=>!n.apiKeys[e.id]).sort((e,t)=>e.name.localeCompare(t.name));if(a.length===0)return x.yellow(`All providers already have API keys configured.`);let d=await t.select({message:`Add Provider`,options:a.map(e=>({value:e.id,label:e.name}))});if(!d)return``;let f=r(d);if(!f)return x.red(`Error: Provider not found`);let m=await t.password({message:`${f.name} API Key`,validate:e=>!e||e.length<8?`Enter a valid key`:void 0});if(!m)return``;n.apiKeys[f.id]=m,await s(n);let h=u.filter(e=>e.provider===f.id),g=c(f.id),v=g?.id??``;if(g&&await t.select({message:`Model Selection`,options:[{value:`latest`,label:`Use default (${g.id})`},{value:`choose`,label:`Choose a model ID...`}]})===`choose`){let e=await t.select({message:`Select Model ID`,options:h.map(e=>({value:e.id,label:e.name}))});e&&(v=e)}let y=!i.provider;if(i.provider&&i.provider!==f.id&&await t.confirm({message:`Set ${f.name} as the default provider?`})&&(y=!0),y){i.provider=f.id,i.model=v,await p(i);let t=u.find(e=>e.id===v);t&&e.updateConfig({apiFormat:f.apiFormat,model:t,apiKey:m,baseUrl:f.baseUrl})}return x.green(`✓ ${f.name} configured`)}async function V(e,t){let n=await _(),i=l.filter(e=>!!n.apiKeys[e.id]).sort((e,t)=>e.name.localeCompare(t.name));if(i.length===0)return x.yellow(`No providers configured. Use 'Add Provider' first.`);let a=await t.select({message:`Update API Key`,options:i.map(e=>({value:e.id,label:e.name}))});if(!a)return``;let c=r(a);if(!c)return x.red(`Error: Provider not found`);let d=await t.password({message:`New key for ${c.name}`});if(!d)return``;n.apiKeys[c.id]=d,await s(n);let f=await o();if(f.provider===c.id){let t=u.find(e=>e.id===f.model&&e.provider===f.provider);t&&e.updateConfig({apiFormat:c.apiFormat,model:t,apiKey:d,baseUrl:c.baseUrl})}return x.green(`✓ Key updated`)}async function H(e,t){let n=await _(),i=await o(),a=l.filter(e=>!!n.apiKeys[e.id]).sort((e,t)=>e.name.localeCompare(t.name));if(a.length===0)return x.yellow(`No configured providers to remove.`);let u=await t.select({message:`Remove API Key`,options:a.map(e=>({value:e.id,label:e.name}))});if(!u||!await t.confirm({message:`Are you sure you want to remove the API key for ${u}?`}))return``;if(delete n.apiKeys[u],await s(n),i.provider===u){i.provider=``,i.model=``;let t=Object.keys(n.apiKeys)[0];if(t){let a=r(t),o=c(t);a&&o&&(i.provider=t,i.model=o.id,e.updateConfig({apiFormat:a.apiFormat,model:o,apiKey:n.apiKeys[t],baseUrl:a.baseUrl}))}await p(i)}return x.green(`✓ Removed API key for ${u}`)}async function U(e,t){let n=await o(),i=await _(),a=[...l].sort((e,t)=>e.name.localeCompare(t.name)),s=await t.select({message:`Default Provider`,options:a.map(e=>({value:e.id,label:`${i.apiKeys[e.id]?`✅`:`❌`} ${e.name}`}))});if(!s)return``;if(!i.apiKeys[s])return x.yellow(`No API key for ${s}. Please set one first.`);let u=r(s),d=c(s);return!u||!d?x.red(`Error: Provider or model not found`):(n.provider=s,n.model=d.id,await p(n),e.updateConfig({apiFormat:u.apiFormat,model:d,apiKey:i.apiKeys[s],baseUrl:u.baseUrl}),x.green(`✓ Default set to ${u.name} (${d.id})`))}const se=[{name:`models`,desc:`Switch model`,aliases:[`model`]},{name:`providers`,desc:`Manage providers`,aliases:[`prov`,`config`,`cfg`]},{name:`compact`,desc:`Compact context`},{name:`sessions`,desc:`List and switch sessions`},{name:`resume`,desc:`Resume previous session`},{name:`update`,desc:`Update novacode`},{name:`skills`,desc:`List available skills`},{name:`reset`,desc:`Reset all nova data`},{name:`help`,desc:`Show help`},{name:`clear`,desc:`Clear screen & start new session`,aliases:[`new`]},{name:`quit`,desc:`Exit (Ctrl+D)`,aliases:[`exit`]}],ce=`
6
+ ${x.bold(`Commands:`)}
7
+ ${se.map(e=>` /${e.name.padEnd(12)} ${e.desc}`).join(`
8
+ `)}
9
+
10
+ ${x.bold(`CLI:`)}
11
+ nova update Update to latest version
12
+ nova reset Delete all nova data and exit
13
+ nova -s ls List sessions
14
+ nova -s <id> / --sessions Resume sessions by ID
15
+ nova -r / --resume Resume last sessions
16
+ nova -s rm <id> Delete specific sessions
17
+ nova -s rm --all Delete all sessions
18
+
19
+ ${x.dim(`Keys:`)}
20
+ Esc Abort
21
+ ↑ / ↓ History
22
+ `;async function le(t,n,r,i,a,o,s,c,l=[]){let[u,...d]=t.slice(1).split(` `),f=d.join(` `);switch(u){case`models`:case`model`:return I(f,n,a);case`providers`:case`prov`:case`config`:case`cfg`:return z(n,a);case`compact`:if(!r||!i)return x.red(`Session store not available`);{let{result:e,newSessionId:t}=await F(n,r,i);return t&&s&&await s(t),e}case`skills`:return G(l);case`sessions`:{if(!r||!a||!s)return x.red(`Session switching not available`);let e=await r.list(50);if(e.length===0)return x.yellow(`No sessions found.`);let t=e.map((e,t)=>{let n=v(e.updated),r=e.title?`"${e.title}"`:`Session: ${e.id}`;return e.id===i&&(r=e.title?`Current: "${e.title}"`:`Current Session`),{value:e.id,label:`${t+1}. ${r}`,hint:n}}),n=[x.bold(`
23
+ CLI Sessions Shortcuts:`),` ${x.cyan(`nova -r`)} / ${x.cyan(`--resume`)} Resume last sessions`,` ${x.cyan(`nova -s <id>`)} / ${x.cyan(`--sessions <id>`)} Resume specific sessions by ID`,` ${x.cyan(`nova -s ls [limit]`)} List last sessions (default: 10)`,` ${x.cyan(`nova -s rm <id>`)} Delete specific sessions`,` ${x.cyan(`nova -s rm --all`)} Delete all sessions`].join(`
24
+ `),o=await a.select({message:`Select a session to load:`,options:t,footer:n});if(o){await s(o);let t=e.find(e=>e.id===o),n=t?.title?`${t.title} (id: ${o})`:o;return x.green(`✓ Switched to session: ${n}`)}return x.yellow(`Session selection cancelled.`)}case`resume`:return"Use `nova --resume` from the CLI to resume your last session.";case`update`:return W();case`reset`:return e(a,o);case`help`:return ce;case`clear`:case`new`:return console.clear(),c&&await c(),``;case`quit`:return o?o():process.exit(0),null;case`exit`:return o?o():process.exit(0),null;default:return x.yellow(`Unknown: /${u}. Type /help`)}}async function W(){let e=await g();return e?e.hasUpdate?(console.log(x.yellow(`\n⚡ Updating novacode to v${e.latest}...`)),await m(!0)?x.green(`✓ Successfully updated to v${e.latest}! Please restart nova to apply changes.`):x.red(`✗ Update failed. Please try running 'nova update' manually in your terminal.`)):x.green(`✓ Already up to date (v${e.current})`):x.yellow(`Could not check for updates.`)}function G(e){if(e.length===0)return`${x.yellow(`No skills found.`)}\n\nSkill directories scanned (precedence order):\n .novacode/skills/\n .agents/skills/\n ~/.novacode/skills/\n ~/.agents/skills/`;let t=y(e),n=`${x.bold(`Available Skills:`)}\n`,r=1;for(let e of t){let t=e[0],a=e.length>1?`${x.yellow(`${t.name} (duplicate)`)}`:x.green(t.name);n+=`${r++}. ${a} — ${t.description}\n`;for(let t of e)n+=` ${x.dim(i(t.path))}\n`}return n+=x.dim(`
25
+ Skills are auto-loaded by the agent when relevant to your task.`),n}const K=[`⠋`,`⠙`,`⠹`,`⠸`,`⠼`,`⠴`,`⠦`,`⠧`,`⠇`,`⠏`],ue={read:`blue`,write:`magenta`,edit:`yellow`,bash:`cyan`,glob:`green`,find:`green`,grep:`green`,tree:`green`},q=[`Terminated by user`,`Aborted by user`,`Execution stopped`,`Interrupted by user`,`Agent halted`,`Stopped by user`];function de(){let[e,t]=k(0);return D(()=>{let e=setInterval(()=>{t(e=>(e+1)%K.length)},80);return()=>clearInterval(e)},[]),j(C,{color:`yellow`,children:K[e]})}function fe(){let[e,t]=k(!0);return D(()=>{let e=setInterval(()=>t(e=>!e),530);return()=>clearInterval(e)},[]),j(C,{color:`white`,children:e?`█`:` `})}function pe({stream:e,thinking:t,busy:n,status:r}){return e||t||n?M(S,{flexDirection:`column`,marginTop:0,children:[e&&j(S,{flexDirection:`row`,children:j(S,{flexGrow:1,flexShrink:1,children:M(C,{children:[e,j(fe,{})]})})}),n&&!e&&!t&&M(S,{flexDirection:`row`,children:[j(S,{marginRight:1,children:j(de,{})}),j(C,{dimColor:!0,children:r?r.replace(`⏳ `,``):x.yellow(`working…`)})]}),t&&!e&&M(S,{flexDirection:`row`,children:[j(S,{marginRight:1,children:j(de,{})}),j(C,{dimColor:!0,children:x.yellow(`Thinking…`)})]})]}):null}function J(e){let t=e;return t=t.replace(/`([^`]+)`/g,(e,t)=>x.yellow(t)),t=t.replace(/\*\*([^*]+)\*\*/g,(e,t)=>x.bold(t)),t=t.replace(/__([^_]+)__/,(e,t)=>x.bold(t)),t=t.replace(/\*([^*]+)\*/g,(e,t)=>x.italic(t)),t=t.replace(/_([^_]+)_/g,(e,t)=>x.italic(t)),t=t.replace(/\[([^\]]+)\]\(([^)]+)\)/g,(e,t,n)=>`${x.blue(t)} ${x.dim(`(${n})`)}`),t}const Y=e=>new Set(e.split(/\s+/).filter(Boolean)),X=Y(`
26
+ abstract as async await break case catch class const continue debugger default delete do else enum export extends
27
+ false finally for from function get if implements import in instanceof interface is let new null of package private
28
+ protected public readonly return set static super switch this throw true try type typeof undefined var void while
29
+ with yield
30
+ `),Z=Y(`
31
+ False None True and as assert async await break class continue def del elif else except finally for from global if
32
+ import in is lambda nonlocal not or pass raise return try while with yield
33
+ `),me=Y(`
34
+ if then else elif fi for in do done while until case esac function return break continue local export readonly
35
+ declare typeset
36
+ `),Q=Y(`
37
+ break case chan const continue default defer else fallthrough for func go goto if import interface map package range
38
+ return select struct switch type var nil true false
39
+ `),$=Y(`
40
+ as async await break const continue crate dyn else enum extern false fn for if impl in let loop match mod move mut
41
+ pub ref return self Self static struct super trait true type unsafe use where while yield
42
+ `),he=Y(`
43
+ select from where and or not in is null as by group order limit offset insert into values update set delete create
44
+ table drop alter add column primary key foreign references join left right inner outer on
45
+ `),ge={go:{comment:`//`,keywords:Q},json:{comment:null,keywords:Y(`true false null`)},py:{comment:`#`,keywords:Z},rust:{comment:`//`,keywords:$},sh:{comment:`#`,keywords:me},sql:{comment:`--`,keywords:he},ts:{comment:`//`,keywords:X},yaml:{comment:`#`,keywords:Y(`true false null yes no on off`)}},_e={bash:`sh`,javascript:`ts`,js:`ts`,jsx:`ts`,python:`py`,rs:`rust`,shell:`sh`,tsx:`ts`,typescript:`ts`,yml:`yaml`,zsh:`sh`},ve=e=>ge[_e[e]??e]??null,ye=e=>ve(e)!==null,be=/'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*`|\b\d+(?:\.\d+)?\b|[A-Za-z_$][\w$]*/g;function xe(e,t){let n=ve(t);if(!n)return e;if(n.comment&&e.trimStart().startsWith(n.comment))return x.gray(e);let r=``,i=0;for(let t of e.matchAll(be)){let a=t[0];if(!a)continue;let o=t.index??0;o>i&&(r+=e.slice(i,o));let s=a[0];s===`"`||s===`'`||s==="`"?r+=x.green(a):s&&s>=`0`&&s<=`9`?r+=x.yellow(a):n.keywords.has(a)?r+=x.magenta(a):r+=a,i=o+a.length}return i<e.length&&(r+=e.slice(i)),r}var Se=class{#e=!1;#t=``;constructor(e){e&&(this.#e=e.inCodeBlock,this.#t=e.codeBlockLang)}getState(){return{inCodeBlock:this.#e,codeBlockLang:this.#t}}renderChunk(e){return e.split(`
46
+ `).map(e=>this.renderLine(e)).join(`
47
+ `)}renderLine(e){let t=e.match(/^\s*(`{3,}|~{3,})(.*)$/);if(t)return this.#e?(this.#e=!1,``):(this.#e=!0,this.#t=(t[2]??``).trim(),this.#t?x.gray(`─ ${this.#t}`):``);if(this.#e){let t=this.#t;return` ${ye(t)?xe(e,t):x.dim(e)}`}if(e.startsWith(`#`)){let t=e.match(/^(#{1,6})\s+(.*)$/);if(t?.[1]&&t[2]){let e=t[1].length,n=t[2];return e===1?x.bold.magenta.underline(n):e===2?x.bold.blue(n):x.bold.cyan(n)}}let n=e;return(n.startsWith(`- `)||n.startsWith(`* `))&&(n=` ${x.yellow(`•`)} ${n.slice(2)}`),J(n)}};function Ce(e){return new Se().renderChunk(e)}var we=class{#e=``;#t=``;#n={inCodeBlock:!1,codeBlockLang:``};#r=``;#i=``;update(e){if(e===this.#r)return this.#i;this.#e&&!e.startsWith(this.#e)&&(this.#e=``,this.#t=``,this.#n={inCodeBlock:!1,codeBlockLang:``});let t=Ee(e,this.#e.length,this.#n);if(t>this.#e.length){let n=e.slice(0,t),r=this.#e?n.slice(this.#e.length):n,i=new Se(this.#n);this.#t+=i.renderChunk(r),this.#e=n,this.#n=i.getState()}let n=e.slice(this.#e.length),r=new Se(this.#n),i=n?r.renderChunk(n):``;return this.#r=e,this.#i=this.#t+i,this.#i}reset(){this.#e=``,this.#t=``,this.#n={inCodeBlock:!1,codeBlockLang:``},this.#r=``,this.#i=``}};function Te(e,t){let n=e.inCodeBlock,r=e.codeBlockLang;for(let e of t.split(`
48
+ `)){let t=e.trim();/^(?:`{3,}|~{3,})/.test(t)&&(n?(n=!1,r=``):(n=!0,r=t.slice(3).trim()))}return{inCodeBlock:n,codeBlockLang:r}}function Ee(e,t,n){let r=e.length;for(;r>t;){let i=e.lastIndexOf(`
49
+
50
+ `,r-1);if(i<t)return t;let a=i+2;if(!Te(n,e.slice(t,a)).inCodeBlock)return a;r=i}return t}function De(e){return e.role===`user`||e.role===`tool_result`?!0:e.role===`assistant`?e.model===`system`||e.stop===`aborted`?!0:e.content.some(e=>e.type===`text`?e.text.trim().length>0:!1):!1}const Oe=T(function({content:e,isFirst:t}){let n=process.stdout.columns||80,r=Math.max(10,n-2),i=`─`.repeat(r);return M(S,{flexDirection:`column`,marginTop:+!t,marginBottom:1,children:[j(C,{color:`green`,children:i}),M(S,{flexDirection:`row`,children:[j(S,{flexShrink:0,marginRight:1,children:j(C,{bold:!0,color:`greenBright`,children:`❯`})}),j(S,{flexGrow:1,flexShrink:1,children:j(C,{children:e})})]}),j(C,{color:`green`,children:i})]})}),ke=T(function({text:e}){return j(C,{children:Ce(e)})}),Ae=T(function({content:e,isAborted:t,termPhrase:n}){return M(S,{flexDirection:`column`,marginTop:0,children:[j(C,{children:e}),t&&j(S,{marginTop:0,children:M(C,{color:`red`,italic:!0,children:[`▲ `,n]})})]})}),je=T(function({tool:e,args:t,isError:n,resText:r}){let i=e===`read`,a=i?r.split(`
51
+ `).length:0,o=ue[e]||`white`;return M(S,{flexDirection:`row`,marginTop:0,children:[M(C,{color:n?`red`:`green`,children:[n?`✗`:`✓`,` `]}),j(C,{color:o,bold:!0,children:e}),t&&M(C,{children:[` `,t]}),i&&!n&&M(C,{dimColor:!0,children:[` (`,a,` lines)`]}),n&&r&&M(C,{color:`red`,children:[` `,r.slice(0,80)]})]})}),Me=T(function({msg:e,isFirst:t}){if(e.role===`user`)return j(Oe,{content:typeof e.content==`string`?e.content:e.content.map(e=>e.type===`text`?e.text:``).join(``),isFirst:t});if(e.role===`assistant`){if(e.model===`system`)return j(S,{flexDirection:`column`,marginTop:0,children:e.content.map((e,t)=>e.type===`text`?j(ke,{text:e.text},t):null)});let t=e.stop===`aborted`;if(!(t||e.content.some(e=>e.type===`text`)))return null;let n=e.content.filter(e=>e.type===`text`).map(e=>e.text).join(``),r=t?q[e.ts%q.length]??`Terminated by user`:``;return j(Ae,{content:Ce(n),isAborted:t,termPhrase:r})}if(e.role===`tool_result`){let t=e.args?b(e.args,!0):``,n=e.content.map(e=>e.type===`text`?e.text:``).join(``).trim();return j(je,{tool:e.tool,args:t,isError:e.isError,resText:n})}return null});function Ne(e){let t=e/1e3;return t>=100?`${Math.round(t)}K`:`${t.toFixed(1)}K`}function Pe(e,t){if(e===0)return`0/${Ne(t)}`;let n=Math.round(e/t*100);return`${Ne(e)}/${Ne(t)} (${n}%)`}function Fe({model:e,usage:t,busy:n,suggestions:r,selCmdIdx:i,exitConfirmKey:a,tip:o}){return M(S,{justifyContent:`space-between`,children:[j(S,{children:r.length>0?j(S,{flexDirection:`column`,marginLeft:2,children:r.map((e,t)=>M(S,{children:[M(C,{color:t===i?`black`:`yellow`,backgroundColor:t===i?`yellow`:void 0,children:[`/`,e.name.padEnd(10)]}),M(C,{dimColor:!0,children:[` `,e.desc]})]},e.name))}):a===`C`?j(C,{color:`yellow`,children:`Press Ctrl+C again to exit`}):n?M(S,{children:[j(C,{dimColor:!0,children:`Esc abort`}),o&&M(A,{children:[j(C,{dimColor:!0,children:` · `}),j(C,{color:`cyan`,dimColor:!0,children:o})]})]}):j(C,{dimColor:!0,children:`Enter to send · /help for commands`})}),M(S,{children:[j(C,{dimColor:!0,children:Pe(t.in,e.contextWindow)}),j(C,{dimColor:!0,children:` │ `}),j(C,{dimColor:!0,children:e.id})]})]})}function Ie(){let[e,t]=k(``),n=O(``),r=O(new we),i=O(null),a=O(!1),o=E(()=>{if(i.current=null,!a.current)return;a.current=!1;let e=n.current;t(r.current.update(e))},[]);return{bufferedStream:e,append:E(e=>{n.current+=e,a.current=!0,i.current||=setTimeout(o,16)},[o]),reset:E(()=>{i.current&&=(clearTimeout(i.current),null),n.current=``,a.current=!1,r.current.reset(),t(``)},[])}}const Le=[`/compact: shrink context when it gets long`,`/models: switch between providers and models`,`Up/Down: scroll through your input history`,`Tab: autocomplete slash commands`,`Ctrl+C twice: exit novacode`,`Ctrl+D: quick exit`,`/clear: wipe screen and start a fresh session`,`/sessions: browse and resume past sessions`,`/skills: list auto-loaded agent skills`,`/providers: manage API keys and providers`,`/update: check and install the latest version`,`Esc: abort the current response`,`nova -r: resume last session from CLI`,`AGENTS.md: project context loaded automatically`,`/reset: wipe all nova data and start fresh`];function Re(e){let[t,n]=k(null),r=O(!1),i=E(()=>Le[Math.floor(Math.random()*Le.length)],[]);return e&&!r.current?n(i()):!e&&r.current&&n(null),r.current=e,t}async function ze(e,t,n,r=[],i=!1){process.stdout.write(`\x1B[?25l`);let a=await d();if(process.stdout.write(`${x.cyan.bold(`⚡ novacode`)} ${x.gray(`v${a}`)}\n`),i&&process.stdout.write(`${x.dim(` context:`)} ${x.cyan(`AGENTS.md`)}\n`),r.length>0){let e=y(r).map(e=>e.length>1?`${x.cyan(e[0].name)} ${x.yellow(`(duplicate)`)}`:x.cyan(e[0].name)).join(`, `);process.stdout.write(`${x.dim(` skills:`)} ${e}\n`)}let o=await t.history(n);try{let{waitUntilExit:i}=w(j(Be,{agent:e,store:t,sessionId:n,skills:r,initialHistory:o}),{exitOnCtrlC:!1});await i()}finally{process.stdout.write(`\x1B[?25h`),await t.prune()}}function Be({agent:e,store:t,sessionId:n,skills:i,initialHistory:o}){let[s,c]=k(n),[l,d]=k(o),p=E(async n=>{let i=await t.get(n);if(!i)return;let a=r(i.provider),o=u.find(e=>e.id===i.model&&e.provider===i.provider)||u.find(e=>e.id===i.model);if(a&&o){let t=(await _()).apiKeys[i.provider]||``;e.updateConfig({apiFormat:a.apiFormat,model:o,apiKey:t,baseUrl:a.baseUrl})}let s=await t.messages(n),l=await t.history(n);e.setMessages(s),d(l),c(n)},[t,e]),m=E(async()=>{let n=e.model,r=await t.create(process.cwd(),n.id,n.provider);e.setMessages([]),d([]),c(r.id)},[t,e]),[v,y]=k(!1),[b,w]=k(!1),[T,A]=k(``),[N,P]=k(``),[ie,ae]=k({in:0,out:0}),[F,I]=k(0),[L,R]=k({type:`chat`}),z=O(null),B=O([]),V=O(-1),H=O(null),[U,ce]=k(null),{exit:W}=te(),G=O(null),[K,ue]=k(null),{bufferedStream:q,append:de,reset:J}=Ie(),Y=Re(b);D(()=>{(async()=>{let e=await g();e?.hasUpdate&&ce({current:e.current,latest:e.latest})})()},[]);let X=T.startsWith(`/`)&&!T.includes(` `),Z=X?se.filter(e=>e.name.startsWith(T.slice(1).toLowerCase())||e.aliases?.some(e=>e.startsWith(T.slice(1).toLowerCase()))):[],me={select:E(e=>new Promise(t=>{z.current=t,R({type:`select`,...e})}),[]),password:E(e=>new Promise(t=>{z.current=t,R({type:`password`,...e})}),[]),confirm:E(e=>new Promise(t=>{z.current=t,R({type:`confirm`,...e})}),[])};function Q(e){let t=z.current;z.current=null,R({type:`chat`}),t?.(e)}function $(n){d(e=>[...e,n]),e.setMessages([...e.messages,n]),t.append(s,n).catch(e=>{console.error(`Error appending message to session store:`,e)})}D(()=>{I(0)},[T]),ne((n,r)=>{if(r.ctrl&&(n===`c`||n===`d`)){if(b){n===`c`&&(H.current&&=(H.current.abort(),null));return}if(n===`d`){W();return}let e=Date.now();G.current&&G.current.key===`C`&&e-G.current.ts<2e3?W():(G.current={key:`C`,ts:e},ue(`C`),setTimeout(()=>{G.current?.key===`C`&&Date.now()-G.current.ts>=2e3&&(G.current=null,ue(null))},2e3));return}if(L.type!==`chat`)return;if(r.escape){H.current?(H.current.abort(),H.current=null):T&&A(``);return}if(r.upArrow){if(X&&Z.length>0){I(e=>e>0?e-1:Z.length-1);return}B.current.length>0&&(V.current=Math.min(V.current+1,B.current.length-1),A(B.current[V.current]??``));return}if(r.downArrow){if(X&&Z.length>0){I(e=>e<Z.length-1?e+1:0);return}V.current=Math.max(V.current-1,-1),A(V.current>=0?B.current[V.current]??``:``);return}if(r.tab){if(X&&Z.length>0){let e=Z[F];e&&A(`/${e.name} `)}return}if(!r.return){A(e=>r.backspace||r.delete?e.slice(0,-1):e+(n||``));return}if(b)return;let a=T.trim();if(a){if(X&&Z.length>0){let e=Z[F];e&&(a=`/${e.name}`)}if(A(``),B.current.unshift(a),V.current=-1,a.startsWith(`/`)){a===`/compact`&&(w(!0),P(`Compacting...`)),le(a,e,t,s,me,W,p,m,i).then(e=>{w(!1),P(``),e&&$({role:`assistant`,content:[{type:`text`,text:e}],model:`system`,provider:`system`,usage:{in:0,out:0},stop:`stop`,ts:Date.now()})});return}$({role:`user`,content:a,ts:Date.now()}),H.current=new AbortController,he(e.prompt(H.current.signal))}});async function he(n){try{for await(let r of n)switch(r.type){case`start`:w(!0),J(),y(!1),P(``);break;case`text_delta`:r.text&&(y(!1),de(r.text));break;case`thinking_delta`:y(!0);break;case`assistant_msg`:$(r.msg),J(),y(!1);break;case`tool_call`:P(x.dim(`⏳ ${r.call.name}…`));break;case`tool_result`:$(r.result),P(r.result.isError?x.red(`✗ ${r.result.tool}`):x.green(`✓ ${r.result.tool}`));break;case`turn_end`:P(``),t.get(s).then(n=>{n&&!n.title&&e.messages.length>=2&&oe(e.messages,e.model,e.apiKey,e.baseUrl).then(e=>{e&&t.setTitle(s,e).catch(()=>{})}).catch(()=>{})}).catch(()=>{});break;case`usage`:r.usage&&ae(r.usage)}}catch(e){$({role:`assistant`,model:`system`,provider:`system`,content:[{type:`text`,text:x.red(`Error: ${e.message}`)}],usage:{in:0,out:0},stop:`error`,ts:Date.now()})}finally{H.current=null,w(!1),J(),y(!1),P(``)}}let ge=re(()=>l.filter(De),[l]);return L.type===`select`?j(a,{message:L.message,options:L.options,header:L.header,footer:L.footer,onSelect:Q}):L.type===`password`?j(h,{message:L.message,validate:L.validate,onSubmit:Q}):L.type===`confirm`?j(f,{message:L.message,onConfirm:Q}):M(S,{flexDirection:`column`,paddingX:1,width:`100%`,children:[j(ee,{items:ge,children:(e,t)=>j(Me,{msg:e,isFirst:t===0},`${e.ts}-${t}`)}),j(pe,{stream:q,thinking:v,busy:b,status:N}),M(S,{flexDirection:`column`,marginTop:ge.length>0||q||v||b?1:0,children:[U&&M(S,{borderStyle:`round`,borderColor:`yellow`,paddingX:1,marginBottom:1,flexDirection:`column`,children:[M(C,{color:`yellow`,bold:!0,children:[`⬆ Update Available (v`,U.current,` → v`,U.latest,`)`]}),M(C,{dimColor:!0,children:[`Run `,j(C,{color:`cyan`,children:`/update`}),` or `,j(C,{color:`cyan`,children:`nova update`}),` to upgrade.`]})]}),j(S,{flexDirection:`column`,borderStyle:`single`,borderTop:!0,borderBottom:!0,borderColor:`green`,borderLeft:!1,borderRight:!1,paddingTop:0,paddingBottom:0,marginBottom:0,children:M(S,{flexDirection:`row`,children:[j(S,{flexShrink:0,marginRight:1,children:j(C,{bold:!0,color:`greenBright`,children:`❯`})}),j(S,{flexGrow:1,flexShrink:1,children:M(C,{children:[T,j(fe,{})]})})]})}),j(Fe,{model:e.model,usage:ie,busy:b,suggestions:Z,selCmdIdx:F,exitConfirmKey:K,tip:Y})]})]})}export{ze as interactive};
52
+ //# sourceMappingURL=app-B8kQsXHF.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-B8kQsXHF.mjs","names":["runCompact","#inCodeBlock","#codeBlockLang","#lastFullText","#lastFullOutput","#stableText","#stableOutput","#stableFenceState"],"sources":["../src/session/compact.ts","../src/commands/compact.ts","../src/commands/models.ts","../src/commands/providers.ts","../src/commands/index.ts","../src/tui/constants.ts","../src/tui/components/liveArea.tsx","../src/tui/markdown/richText.ts","../src/tui/markdown/syntax.ts","../src/tui/markdown/renderer.ts","../src/tui/markdown/stream.ts","../src/tui/components/message.tsx","../src/tui/components/statusBar.tsx","../src/tui/hooks/useStreamBuffer.ts","../src/tui/hooks/useTip.ts","../src/tui/app.tsx"],"sourcesContent":["import { getProvider } from \"../config/catalog.ts\"\nimport { stream } from \"../llm/stream.ts\"\nimport { estimateTokens } from \"../tokens.ts\"\nimport type { CompactResult, Model, Msg } from \"../types.ts\"\nimport type { SessionStore } from \"./store.ts\"\n\nfunction extractText(msg: Msg): string {\n\tif (typeof msg.content === \"string\") return msg.content\n\treturn msg.content\n\t\t.filter((c) => c.type === \"text\")\n\t\t.map((c) => (c.type === \"text\" ? c.text : \"\"))\n\t\t.join(\"\")\n}\n\nfunction estimateMsgTokens(msg: Msg): number {\n\tlet chars = 0\n\tif (typeof msg.content === \"string\") {\n\t\tchars += msg.content.length\n\t} else if (Array.isArray(msg.content)) {\n\t\tfor (const part of msg.content) {\n\t\t\tif (part.type === \"text\") chars += part.text.length\n\t\t}\n\t}\n\treturn Math.ceil(chars / 4)\n}\n\nexport async function compact(\n\tstore: SessionStore,\n\tsessionId: string,\n\tmessages: Msg[],\n\tmodel: Model,\n\tapiKey: string,\n\tbaseUrl: string,\n\tcwd: string,\n): Promise<CompactResult> {\n\tconst tokensBefore = estimateTokens(messages)\n\n\t// Tail protection token budget: 10% of total context window, minimum 20,000 tokens\n\tconst tailTokenBudget = Math.max(20000, Math.round(model.contextWindow * 0.1))\n\n\tlet accumulatedTokens = 0\n\tlet cutIndex = messages.length\n\n\t// Walk backward from the end to dynamically select the tail messages based purely on token budget\n\tfor (let i = messages.length - 1; i >= 0; i--) {\n\t\tconst msg = messages[i]!\n\t\tconst msgTokens = estimateMsgTokens(msg)\n\n\t\tif (accumulatedTokens + msgTokens <= tailTokenBudget) {\n\t\t\taccumulatedTokens += msgTokens\n\t\t\tcutIndex = i\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif (cutIndex <= 0) {\n\t\treturn { compacted: false, tokensBefore, tokensAfter: tokensBefore }\n\t}\n\n\tconst tail = messages.slice(cutIndex)\n\tconst old = messages.slice(0, cutIndex)\n\n\tconst convo = old\n\t\t.map((m) => {\n\t\t\tif (m.role === \"user\") return `User: ${extractText(m)}`\n\t\t\tif (m.role === \"assistant\") return `Assistant: ${extractText(m)}`\n\t\t\tif (m.role === \"tool_result\" && \"tool\" in m)\n\t\t\t\treturn `Tool(${m.tool}): ${extractText(m).slice(0, 200)}`\n\t\t\treturn \"\"\n\t\t})\n\t\t.join(\"\\n\\n\")\n\n\tconst summary = await generateSummary(convo, model, apiKey, baseUrl)\n\tif (!summary) {\n\t\treturn { compacted: false, tokensBefore, tokensAfter: tokensBefore }\n\t}\n\n\tconst summaryMsg: Msg = {\n\t\trole: \"user\",\n\t\tcontent: `[Prior context summary]\\n${summary}`,\n\t\tts: Date.now(),\n\t}\n\n\tawait store.endSession(sessionId, \"compacted\")\n\tconst newSession = await store.createContinuation(sessionId, cwd, model.id, model.provider)\n\n\tconst newMsgs = [summaryMsg, ...tail]\n\tfor (let i = 0; i < newMsgs.length; i++) {\n\t\tawait store.append(newSession.id, newMsgs[i]!)\n\t}\n\n\tconst tokensAfter = estimateTokens(newMsgs)\n\tif (tokensAfter >= tokensBefore) {\n\t\treturn { compacted: false, tokensBefore, tokensAfter: tokensBefore }\n\t}\n\n\treturn { compacted: true, summary, tokensBefore, tokensAfter, newSessionId: newSession.id }\n}\n\nasync function generateSummary(\n\tconvo: string,\n\tmodel: Model,\n\tapiKey: string,\n\tbaseUrl: string,\n): Promise<string | null> {\n\tconst provider = getProvider(model.provider)\n\tif (!provider) return null\n\n\tconst es = stream({\n\t\tapiFormat: provider.apiFormat,\n\t\tmodel,\n\t\tapiKey,\n\t\tbaseUrl,\n\t\tsystem:\n\t\t\t\"Summarize this coding session concisely. Cover: what was asked, files touched, what was done, key decisions. Keep it under 300 words.\",\n\t\tmessages: [{ role: \"user\", content: convo, ts: Date.now() }],\n\t\ttools: [],\n\t})\n\n\tlet summary = \"\"\n\tfor await (const ev of es) {\n\t\tif (ev.type === \"text_delta\" && ev.text) {\n\t\t\tsummary += ev.text\n\t\t}\n\t}\n\n\treturn summary.trim() || null\n}\n\nexport async function generateSessionTitle(\n\tmessages: Msg[],\n\tmodel: Model,\n\tapiKey: string,\n\tbaseUrl: string,\n): Promise<string | null> {\n\tconst provider = getProvider(model.provider)\n\tif (!provider) return null\n\n\tconst convo = messages\n\t\t.slice(0, 4)\n\t\t.map((m) => {\n\t\t\tif (m.role === \"user\") return `User: ${extractText(m)}`\n\t\t\tif (m.role === \"assistant\") return `Assistant: ${extractText(m)}`\n\t\t\treturn \"\"\n\t\t})\n\t\t.join(\"\\n\")\n\n\tconst es = stream({\n\t\tapiFormat: provider.apiFormat,\n\t\tmodel,\n\t\tapiKey,\n\t\tbaseUrl,\n\t\tsystem:\n\t\t\t\"Generate a very short, descriptive, and concise title for this coding conversation. Do not use quotes or prefixes like 'Title:'. Max 6 words.\",\n\t\tmessages: [{ role: \"user\", content: convo, ts: Date.now() }],\n\t\ttools: [],\n\t})\n\n\tlet title = \"\"\n\tfor await (const ev of es) {\n\t\tif (ev.type === \"text_delta\" && ev.text) {\n\t\t\ttitle += ev.text\n\t\t}\n\t}\n\n\treturn title.trim().replace(/^[\"']|[\"']$/g, \"\") || null\n}\n","import chalk from \"chalk\"\nimport type { Agent } from \"../agent/agent.ts\"\nimport { compact as runCompact } from \"../session/compact.ts\"\nimport type { SessionStore } from \"../session/store.ts\"\n\nexport async function handleCompact(\n\tagent: Agent,\n\tstore: SessionStore,\n\tsessionId: string,\n): Promise<{ result: string; newSessionId?: string }> {\n\tconst res = await runCompact(\n\t\tstore,\n\t\tsessionId,\n\t\tagent.messages,\n\t\tagent.model,\n\t\tagent.apiKey,\n\t\tagent.baseUrl,\n\t\tprocess.cwd(),\n\t)\n\n\tif (res.compacted) {\n\t\tconst msgs = await store.messages(res.newSessionId ?? sessionId)\n\t\tagent.setMessages(msgs)\n\t\tconst pct = Math.round(((res.tokensBefore - res.tokensAfter) / res.tokensBefore) * 100)\n\t\treturn {\n\t\t\tresult: chalk.green(`✓ Compacted (${pct}% reduction)`),\n\t\t\tnewSessionId: res.newSessionId,\n\t\t}\n\t}\n\n\treturn { result: chalk.yellow(\"Context is small enough, no compaction needed.\") }\n}\n","import chalk from \"chalk\"\nimport type { Agent } from \"../agent/agent.ts\"\nimport { getProvider, MODELS } from \"../config/catalog.ts\"\nimport { loadAuth, loadConfig, saveConfig } from \"../config/store.ts\"\nimport type { Prompts } from \"../types.ts\"\n\nexport async function handleModels(args: string, agent: Agent, prompts?: Prompts): Promise<string> {\n\tconst config = await loadConfig()\n\tconst auth = await loadAuth()\n\n\tif (args) return await switchDirect(args.trim(), agent)\n\n\tif (!prompts) return chalk.red(\"Prompts not available in this context\")\n\n\tconst activeModels = MODELS.filter((m) => {\n\t\tconst pDef = getProvider(m.provider)\n\t\treturn pDef && !!auth.apiKeys[m.provider]\n\t})\n\n\tif (!activeModels.length)\n\t\treturn chalk.yellow(\"No models available. Use /providers to add a provider API key.\")\n\n\tconst maxLen = Math.max(...activeModels.map((m) => m.id.length), 20)\n\n\tconst options: Array<{ value: string; label: string; hint?: string }> = []\n\tfor (const m of activeModels) {\n\t\tconst cur = m.id === config.model && m.provider === config.provider\n\t\tconst pDef = getProvider(m.provider)!\n\n\t\toptions.push({\n\t\t\tvalue: `${m.provider}:${m.id}`,\n\t\t\tlabel: `${cur ? chalk.green(\"●\") : \"○\"} ${m.id.padEnd(maxLen + 2)} ${fmt(m.contextWindow).padEnd(8)}`,\n\t\t\thint: pDef.name,\n\t\t})\n\t}\n\n\tconst pick = await prompts.select({ message: \"Model\", options })\n\tif (!pick) return \"\"\n\n\tconst [pk, mid] = pick.split(\":\")\n\tconst selectedModel = MODELS.find((m) => m.provider === pk && m.id === mid)\n\tconst selectedProvider = getProvider(pk!)\n\n\tif (!selectedModel || !selectedProvider) return chalk.red(\"Error: Model or provider not found\")\n\n\tconfig.provider = pk!\n\tconfig.model = mid!\n\tawait saveConfig(config)\n\n\tagent.updateConfig({\n\t\tapiFormat: selectedProvider.apiFormat,\n\t\tmodel: selectedModel,\n\t\tapiKey: auth.apiKeys[pk!] ?? \"\",\n\t\tbaseUrl: selectedProvider.baseUrl,\n\t})\n\treturn chalk.green(`✓ Switched to ${mid}`)\n}\n\nasync function switchDirect(id: string, agent: Agent): Promise<string> {\n\tconst config = await loadConfig()\n\tconst auth = await loadAuth()\n\n\tconst m = MODELS.find((m) => m.id === id)\n\tif (!m) return chalk.yellow(`\"${id}\" not found. Use /models`)\n\n\tconst pk = m.provider\n\tif (!auth.apiKeys[pk]) {\n\t\treturn chalk.yellow(`No API key configured for ${pk}. Use /providers`)\n\t}\n\n\tconst selectedProvider = getProvider(pk)\n\tif (!selectedProvider) return chalk.red(\"Error: Provider not found\")\n\n\tconfig.provider = pk\n\tconfig.model = id\n\tawait saveConfig(config)\n\n\tagent.updateConfig({\n\t\tapiFormat: selectedProvider.apiFormat,\n\t\tmodel: m,\n\t\tapiKey: auth.apiKeys[pk],\n\t\tbaseUrl: selectedProvider.baseUrl,\n\t})\n\n\treturn chalk.green(`✓ Switched to ${id}`)\n}\n\nconst fmt = (n: number) => (n >= 1_000_000 ? `${n / 1_000_000}M` : `${n / 1000}K`)\n","import chalk from \"chalk\"\nimport type { Agent } from \"../agent/agent.ts\"\nimport { getDefaultModel, getProvider, MODELS, PROVIDERS } from \"../config/catalog.ts\"\nimport { loadAuth, loadConfig, saveAuth, saveConfig } from \"../config/store.ts\"\nimport type { Prompts } from \"../types.ts\"\n\nexport async function handleProviders(agent: Agent, prompts?: Prompts): Promise<string> {\n\tif (!prompts) return chalk.red(\"Prompts not available in this context\")\n\n\tconst config = await loadConfig()\n\tconst auth = await loadAuth()\n\tconst configured = PROVIDERS.filter((p) => !!auth.apiKeys[p.id]).sort((a, b) =>\n\t\ta.name.localeCompare(b.name),\n\t)\n\n\tconst headerLines =\n\t\tconfigured.length === 0\n\t\t\t? chalk.dim(\"No providers configured. Use 'Add Provider' below.\")\n\t\t\t: configured\n\t\t\t\t\t.map((p) => {\n\t\t\t\t\t\tconst isDefault = p.id === config.provider\n\t\t\t\t\t\tconst active = isDefault ? chalk.green(\" ●\") : \"\"\n\t\t\t\t\t\tconst currentModel = isDefault ? config.model : (getDefaultModel(p.id)?.id ?? \"\")\n\t\t\t\t\t\treturn ` ✅ ${p.name.padEnd(24)} ${currentModel}${active}`\n\t\t\t\t\t})\n\t\t\t\t\t.join(\"\\n\")\n\n\tconst act = await prompts.select({\n\t\tmessage: \"Action\",\n\t\theader: headerLines,\n\t\toptions: [\n\t\t\t{ value: \"add\", label: \"Add Provider\" },\n\t\t\t{ value: \"update\", label: \"Update API Key\" },\n\t\t\t{ value: \"remove\", label: \"Remove API Key\" },\n\t\t\t{ value: \"default\", label: \"Set Default Provider\" },\n\t\t\t{ value: \"back\", label: \"Back\" },\n\t\t],\n\t})\n\tif (!act || act === \"back\") return \"\"\n\n\tif (act === \"add\") return addProvider(agent, prompts)\n\tif (act === \"update\") return updateKey(agent, prompts)\n\tif (act === \"remove\") return removeKey(agent, prompts)\n\tif (act === \"default\") return setDefault(agent, prompts)\n\treturn \"\"\n}\n\nasync function addProvider(agent: Agent, prompts: Prompts): Promise<string> {\n\tconst auth = await loadAuth()\n\tconst config = await loadConfig()\n\n\tconst available = PROVIDERS.filter((p) => !auth.apiKeys[p.id]).sort((a, b) =>\n\t\ta.name.localeCompare(b.name),\n\t)\n\tif (available.length === 0) {\n\t\treturn chalk.yellow(\"All providers already have API keys configured.\")\n\t}\n\n\tconst pick = await prompts.select({\n\t\tmessage: \"Add Provider\",\n\t\toptions: available.map((p) => ({ value: p.id, label: p.name })),\n\t})\n\tif (!pick) return \"\"\n\n\tconst pDef = getProvider(pick)\n\tif (!pDef) return chalk.red(\"Error: Provider not found\")\n\n\tconst key = await prompts.password({\n\t\tmessage: `${pDef.name} API Key`,\n\t\tvalidate: (v) => (!v || v.length < 8 ? \"Enter a valid key\" : undefined),\n\t})\n\tif (!key) return \"\"\n\n\tauth.apiKeys[pDef.id] = key\n\tawait saveAuth(auth)\n\n\tconst providerModels = MODELS.filter((m) => m.provider === pDef.id)\n\tconst defaultModel = getDefaultModel(pDef.id)\n\tlet selectedModelId = defaultModel?.id ?? \"\"\n\n\tif (defaultModel) {\n\t\tconst choice = await prompts.select({\n\t\t\tmessage: \"Model Selection\",\n\t\t\toptions: [\n\t\t\t\t{ value: \"latest\", label: `Use default (${defaultModel.id})` },\n\t\t\t\t{ value: \"choose\", label: \"Choose a model ID...\" },\n\t\t\t],\n\t\t})\n\n\t\tif (choice === \"choose\") {\n\t\t\tconst pickedModel = await prompts.select({\n\t\t\t\tmessage: \"Select Model ID\",\n\t\t\t\toptions: providerModels.map((m) => ({ value: m.id, label: m.name })),\n\t\t\t})\n\t\t\tif (pickedModel) {\n\t\t\t\tselectedModelId = pickedModel\n\t\t\t}\n\t\t}\n\t}\n\n\tlet makeDefault = !config.provider\n\tif (config.provider && config.provider !== pDef.id) {\n\t\tconst confirm = await prompts.confirm({\n\t\t\tmessage: `Set ${pDef.name} as the default provider?`,\n\t\t})\n\t\tif (confirm) {\n\t\t\tmakeDefault = true\n\t\t}\n\t}\n\n\tif (makeDefault) {\n\t\tconfig.provider = pDef.id\n\t\tconfig.model = selectedModelId\n\t\tawait saveConfig(config)\n\t\tconst modelDef = MODELS.find((m) => m.id === selectedModelId)\n\t\tif (modelDef) {\n\t\t\tagent.updateConfig({\n\t\t\t\tapiFormat: pDef.apiFormat,\n\t\t\t\tmodel: modelDef,\n\t\t\t\tapiKey: key,\n\t\t\t\tbaseUrl: pDef.baseUrl,\n\t\t\t})\n\t\t}\n\t}\n\n\treturn chalk.green(`✓ ${pDef.name} configured`)\n}\n\nasync function updateKey(agent: Agent, prompts: Prompts): Promise<string> {\n\tconst auth = await loadAuth()\n\n\tconst configured = PROVIDERS.filter((p) => !!auth.apiKeys[p.id]).sort((a, b) =>\n\t\ta.name.localeCompare(b.name),\n\t)\n\tif (configured.length === 0) {\n\t\treturn chalk.yellow(\"No providers configured. Use 'Add Provider' first.\")\n\t}\n\n\tconst pick = await prompts.select({\n\t\tmessage: \"Update API Key\",\n\t\toptions: configured.map((p) => ({ value: p.id, label: p.name })),\n\t})\n\tif (!pick) return \"\"\n\n\tconst pDef = getProvider(pick)\n\tif (!pDef) return chalk.red(\"Error: Provider not found\")\n\n\tconst key = await prompts.password({ message: `New key for ${pDef.name}` })\n\tif (!key) return \"\"\n\n\tauth.apiKeys[pDef.id] = key\n\tawait saveAuth(auth)\n\n\tconst config = await loadConfig()\n\tif (config.provider === pDef.id) {\n\t\tconst currentModel = MODELS.find((m) => m.id === config.model && m.provider === config.provider)\n\t\tif (currentModel) {\n\t\t\tagent.updateConfig({\n\t\t\t\tapiFormat: pDef.apiFormat,\n\t\t\t\tmodel: currentModel,\n\t\t\t\tapiKey: key,\n\t\t\t\tbaseUrl: pDef.baseUrl,\n\t\t\t})\n\t\t}\n\t}\n\n\treturn chalk.green(\"✓ Key updated\")\n}\n\nasync function removeKey(agent: Agent, prompts: Prompts): Promise<string> {\n\tconst auth = await loadAuth()\n\tconst config = await loadConfig()\n\n\tconst configured = PROVIDERS.filter((p) => !!auth.apiKeys[p.id]).sort((a, b) =>\n\t\ta.name.localeCompare(b.name),\n\t)\n\tif (configured.length === 0) {\n\t\treturn chalk.yellow(\"No configured providers to remove.\")\n\t}\n\n\tconst pick = await prompts.select({\n\t\tmessage: \"Remove API Key\",\n\t\toptions: configured.map((p) => ({ value: p.id, label: p.name })),\n\t})\n\tif (!pick) return \"\"\n\n\tconst confirm = await prompts.confirm({\n\t\tmessage: `Are you sure you want to remove the API key for ${pick}?`,\n\t})\n\tif (!confirm) return \"\"\n\n\tdelete auth.apiKeys[pick]\n\tawait saveAuth(auth)\n\n\tif (config.provider === pick) {\n\t\tconfig.provider = \"\"\n\t\tconfig.model = \"\"\n\t\tconst next = Object.keys(auth.apiKeys)[0]\n\t\tif (next) {\n\t\t\tconst pDef = getProvider(next)\n\t\t\tconst mDef = getDefaultModel(next)\n\t\t\tif (pDef && mDef) {\n\t\t\t\tconfig.provider = next\n\t\t\t\tconfig.model = mDef.id\n\t\t\t\tagent.updateConfig({\n\t\t\t\t\tapiFormat: pDef.apiFormat,\n\t\t\t\t\tmodel: mDef,\n\t\t\t\t\tapiKey: auth.apiKeys[next]!,\n\t\t\t\t\tbaseUrl: pDef.baseUrl,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t\tawait saveConfig(config)\n\t}\n\n\treturn chalk.green(`✓ Removed API key for ${pick}`)\n}\n\nasync function setDefault(agent: Agent, prompts: Prompts): Promise<string> {\n\tconst config = await loadConfig()\n\tconst auth = await loadAuth()\n\n\tconst sortedProviders = [...PROVIDERS].sort((a, b) => a.name.localeCompare(b.name))\n\tconst pick = await prompts.select({\n\t\tmessage: \"Default Provider\",\n\t\toptions: sortedProviders.map((p) => ({\n\t\t\tvalue: p.id,\n\t\t\tlabel: `${auth.apiKeys[p.id] ? \"✅\" : \"❌\"} ${p.name}`,\n\t\t})),\n\t})\n\tif (!pick) return \"\"\n\n\tif (!auth.apiKeys[pick]) {\n\t\treturn chalk.yellow(`No API key for ${pick}. Please set one first.`)\n\t}\n\n\tconst pDef = getProvider(pick)\n\tconst mDef = getDefaultModel(pick)\n\n\tif (!pDef || !mDef) return chalk.red(\"Error: Provider or model not found\")\n\n\tconfig.provider = pick\n\tconfig.model = mDef.id\n\tawait saveConfig(config)\n\n\tagent.updateConfig({\n\t\tapiFormat: pDef.apiFormat,\n\t\tmodel: mDef,\n\t\tapiKey: auth.apiKeys[pick],\n\t\tbaseUrl: pDef.baseUrl,\n\t})\n\n\treturn chalk.green(`✓ Default set to ${pDef.name} (${mDef.id})`)\n}\n","import chalk from \"chalk\"\nimport type { Agent } from \"../agent/agent.ts\"\nimport { formatRelativeTime } from \"../format.ts\"\nimport { shortenPath } from \"../paths.ts\"\nimport type { SessionStore } from \"../session/store.ts\"\nimport { groupSkills } from \"../skills/index.ts\"\nimport type { Cmd, Prompts, Skill } from \"../types.ts\"\nimport { checkForUpdate, runUpdate } from \"../update.ts\"\nimport { handleCompact } from \"./compact.ts\"\nimport { handleModels } from \"./models.ts\"\nimport { handleProviders } from \"./providers.ts\"\nimport { handleInteractiveReset } from \"./reset.ts\"\n\nexport const COMMANDS: Cmd[] = [\n\t{ name: \"models\", desc: \"Switch model\", aliases: [\"model\"] },\n\t{ name: \"providers\", desc: \"Manage providers\", aliases: [\"prov\", \"config\", \"cfg\"] },\n\t{ name: \"compact\", desc: \"Compact context\" },\n\t{ name: \"sessions\", desc: \"List and switch sessions\" },\n\t{ name: \"resume\", desc: \"Resume previous session\" },\n\t{ name: \"update\", desc: \"Update novacode\" },\n\t{ name: \"skills\", desc: \"List available skills\" },\n\t{ name: \"reset\", desc: \"Reset all nova data\" },\n\t{ name: \"help\", desc: \"Show help\" },\n\t{ name: \"clear\", desc: \"Clear screen & start new session\", aliases: [\"new\"] },\n\t{ name: \"quit\", desc: \"Exit (Ctrl+D)\", aliases: [\"exit\"] },\n]\n\nconst HELP = `\n${chalk.bold(\"Commands:\")}\n${COMMANDS.map((c) => ` /${c.name.padEnd(12)} ${c.desc}`).join(\"\\n\")}\n\n${chalk.bold(\"CLI:\")}\n nova update Update to latest version\n nova reset Delete all nova data and exit\n nova -s ls List sessions\n nova -s <id> / --sessions Resume sessions by ID\n nova -r / --resume Resume last sessions\n nova -s rm <id> Delete specific sessions\n nova -s rm --all Delete all sessions\n\n${chalk.dim(\"Keys:\")}\n Esc Abort\n ↑ / ↓ History\n`\n\nexport async function dispatch(\n\tinput: string,\n\tagent: Agent,\n\tstore?: SessionStore,\n\tsessionId?: string,\n\tprompts?: Prompts,\n\tonExit?: () => void,\n\tonSwitchSession?: (sessionId: string) => Promise<void>,\n\tonNewSession?: () => Promise<void>,\n\tskills: Skill[] = [],\n): Promise<string | null> {\n\tconst [cmd, ...rest] = input.slice(1).split(\" \")\n\tconst args = rest.join(\" \")\n\n\tswitch (cmd) {\n\t\tcase \"models\":\n\t\tcase \"model\":\n\t\t\treturn handleModels(args, agent, prompts)\n\t\tcase \"providers\":\n\t\tcase \"prov\":\n\t\tcase \"config\":\n\t\tcase \"cfg\":\n\t\t\treturn handleProviders(agent, prompts)\n\t\tcase \"compact\":\n\t\t\tif (!store || !sessionId) return chalk.red(\"Session store not available\")\n\t\t\t{\n\t\t\t\tconst { result, newSessionId } = await handleCompact(agent, store, sessionId)\n\t\t\t\tif (newSessionId && onSwitchSession) await onSwitchSession(newSessionId)\n\t\t\t\treturn result\n\t\t\t}\n\t\tcase \"skills\":\n\t\t\treturn handleSkills(skills)\n\t\tcase \"sessions\": {\n\t\t\tif (!store || !prompts || !onSwitchSession)\n\t\t\t\treturn chalk.red(\"Session switching not available\")\n\t\t\tconst sessions = await store.list(50)\n\t\t\tif (sessions.length === 0) return chalk.yellow(\"No sessions found.\")\n\t\t\tconst options = sessions.map((s, idx) => {\n\t\t\t\tconst relTime = formatRelativeTime(s.updated)\n\t\t\t\tlet label = s.title ? `\"${s.title}\"` : `Session: ${s.id}`\n\t\t\t\tif (s.id === sessionId) {\n\t\t\t\t\tlabel = s.title ? `Current: \"${s.title}\"` : \"Current Session\"\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tvalue: s.id,\n\t\t\t\t\tlabel: `${idx + 1}. ${label}`,\n\t\t\t\t\thint: relTime,\n\t\t\t\t}\n\t\t\t})\n\t\t\tconst footer = [\n\t\t\t\tchalk.bold(\"\\nCLI Sessions Shortcuts:\"),\n\t\t\t\t` ${chalk.cyan(\"nova -r\")} / ${chalk.cyan(\"--resume\")} Resume last sessions`,\n\t\t\t\t` ${chalk.cyan(\"nova -s <id>\")} / ${chalk.cyan(\"--sessions <id>\")} Resume specific sessions by ID`,\n\t\t\t\t` ${chalk.cyan(\"nova -s ls [limit]\")} List last sessions (default: 10)`,\n\t\t\t\t` ${chalk.cyan(\"nova -s rm <id>\")} Delete specific sessions`,\n\t\t\t\t` ${chalk.cyan(\"nova -s rm --all\")} Delete all sessions`,\n\t\t\t].join(\"\\n\")\n\n\t\t\tconst selectedId = await prompts.select({\n\t\t\t\tmessage: \"Select a session to load:\",\n\t\t\t\toptions,\n\t\t\t\tfooter,\n\t\t\t})\n\t\t\tif (selectedId) {\n\t\t\t\tawait onSwitchSession(selectedId)\n\t\t\t\tconst selectedSession = sessions.find((s) => s.id === selectedId)\n\t\t\t\tconst displayName = selectedSession?.title\n\t\t\t\t\t? `${selectedSession.title} (id: ${selectedId})`\n\t\t\t\t\t: selectedId\n\t\t\t\treturn chalk.green(`✓ Switched to session: ${displayName}`)\n\t\t\t}\n\t\t\treturn chalk.yellow(\"Session selection cancelled.\")\n\t\t}\n\t\tcase \"resume\":\n\t\t\treturn \"Use `nova --resume` from the CLI to resume your last session.\"\n\t\tcase \"update\":\n\t\t\treturn handleUpdate()\n\t\tcase \"reset\":\n\t\t\treturn handleInteractiveReset(prompts, onExit)\n\t\tcase \"help\":\n\t\t\treturn HELP\n\t\tcase \"clear\":\n\t\tcase \"new\":\n\t\t\tconsole.clear()\n\t\t\tif (onNewSession) await onNewSession()\n\t\t\treturn \"\"\n\t\tcase \"quit\":\n\t\t\tif (onExit) {\n\t\t\t\tonExit()\n\t\t\t} else {\n\t\t\t\tprocess.exit(0)\n\t\t\t}\n\t\t\treturn null\n\t\tcase \"exit\":\n\t\t\tif (onExit) {\n\t\t\t\tonExit()\n\t\t\t} else {\n\t\t\t\tprocess.exit(0)\n\t\t\t}\n\t\t\treturn null\n\t\tdefault:\n\t\t\treturn chalk.yellow(`Unknown: /${cmd}. Type /help`)\n\t}\n}\n\nasync function handleUpdate(): Promise<string> {\n\tconst info = await checkForUpdate()\n\tif (!info) return chalk.yellow(\"Could not check for updates.\")\n\tif (!info.hasUpdate) return chalk.green(`✓ Already up to date (v${info.current})`)\n\n\tconsole.log(chalk.yellow(`\\n⚡ Updating novacode to v${info.latest}...`))\n\tconst success = await runUpdate(true)\n\tif (success) {\n\t\treturn chalk.green(\n\t\t\t`✓ Successfully updated to v${info.latest}! Please restart nova to apply changes.`,\n\t\t)\n\t}\n\treturn chalk.red(\"✗ Update failed. Please try running 'nova update' manually in your terminal.\")\n}\n\nfunction handleSkills(skills: Skill[]): string {\n\tif (skills.length === 0) {\n\t\treturn `${chalk.yellow(\"No skills found.\")}\\n\\nSkill directories scanned (precedence order):\\n .novacode/skills/\\n .agents/skills/\\n ~/.novacode/skills/\\n ~/.agents/skills/`\n\t}\n\n\tconst groups = groupSkills(skills)\n\tlet out = `${chalk.bold(\"Available Skills:\")}\\n`\n\tlet n = 1\n\tfor (const group of groups) {\n\t\tconst first = group[0]!\n\t\tconst name =\n\t\t\tgroup.length > 1 ? `${chalk.yellow(`${first.name} (duplicate)`)}` : chalk.green(first.name)\n\t\tout += `${n++}. ${name} — ${first.description}\\n`\n\t\tfor (const s of group) {\n\t\t\tout += ` ${chalk.dim(shortenPath(s.path))}\\n`\n\t\t}\n\t}\n\tout += chalk.dim(\"\\nSkills are auto-loaded by the agent when relevant to your task.\")\n\treturn out\n}\n","/**\n * TUI-specific static constants and configuration styles.\n */\n\nexport const SPINNER_FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"]\n\nexport const TOOL_STYLE: Record<string, string> = {\n\tread: \"blue\",\n\twrite: \"magenta\",\n\tedit: \"yellow\",\n\tbash: \"cyan\",\n\tglob: \"green\",\n\tfind: \"green\",\n\tgrep: \"green\",\n\ttree: \"green\",\n}\n\nexport const TERMINATION_PHRASES = [\n\t\"Terminated by user\",\n\t\"Aborted by user\",\n\t\"Execution stopped\",\n\t\"Interrupted by user\",\n\t\"Agent halted\",\n\t\"Stopped by user\",\n]\n","import chalk from \"chalk\"\nimport { Box, Text } from \"ink\"\nimport { useEffect, useState } from \"react\"\nimport { SPINNER_FRAMES } from \"../constants.ts\"\n\nexport function Spinner() {\n\tconst [frame, setFrame] = useState(0)\n\n\tuseEffect(() => {\n\t\tconst timer = setInterval(() => {\n\t\t\tsetFrame((f) => (f + 1) % SPINNER_FRAMES.length)\n\t\t}, 80)\n\t\treturn () => clearInterval(timer)\n\t}, [])\n\n\treturn <Text color=\"yellow\">{SPINNER_FRAMES[frame]}</Text>\n}\n\nexport function Cursor() {\n\tconst [visible, setVisible] = useState(true)\n\tuseEffect(() => {\n\t\tconst timer = setInterval(() => setVisible((v) => !v), 530)\n\t\treturn () => clearInterval(timer)\n\t}, [])\n\treturn <Text color=\"white\">{visible ? \"█\" : \" \"}</Text>\n}\n\nexport function LiveArea({\n\tstream,\n\tthinking,\n\tbusy,\n\tstatus,\n}: {\n\tstream: string\n\tthinking: boolean\n\tbusy: boolean\n\tstatus: string\n}) {\n\tconst isActive = !!(stream || thinking || busy)\n\tif (!isActive) return null\n\n\treturn (\n\t\t<Box flexDirection=\"column\" marginTop={0}>\n\t\t\t{stream && (\n\t\t\t\t<Box flexDirection=\"row\">\n\t\t\t\t\t<Box flexGrow={1} flexShrink={1}>\n\t\t\t\t\t\t<Text>\n\t\t\t\t\t\t\t{stream}\n\t\t\t\t\t\t\t<Cursor />\n\t\t\t\t\t\t</Text>\n\t\t\t\t\t</Box>\n\t\t\t\t</Box>\n\t\t\t)}\n\t\t\t{busy && !stream && !thinking && (\n\t\t\t\t<Box flexDirection=\"row\">\n\t\t\t\t\t<Box marginRight={1}>\n\t\t\t\t\t\t<Spinner />\n\t\t\t\t\t</Box>\n\t\t\t\t\t<Text dimColor>{status ? status.replace(\"⏳ \", \"\") : chalk.yellow(\"working…\")}</Text>\n\t\t\t\t</Box>\n\t\t\t)}\n\t\t\t{thinking && !stream && (\n\t\t\t\t<Box flexDirection=\"row\">\n\t\t\t\t\t<Box marginRight={1}>\n\t\t\t\t\t\t<Spinner />\n\t\t\t\t\t</Box>\n\t\t\t\t\t<Text dimColor>{chalk.yellow(\"Thinking…\")}</Text>\n\t\t\t\t</Box>\n\t\t\t)}\n\t\t</Box>\n\t)\n}\n","import chalk from \"chalk\"\n\nexport function formatRichText(text: string): string {\n\tlet formatted = text\n\tformatted = formatted.replace(/`([^`]+)`/g, (_, code) => chalk.yellow(code))\n\tformatted = formatted.replace(/\\*\\*([^*]+)\\*\\*/g, (_, bold) => chalk.bold(bold))\n\tformatted = formatted.replace(/__([^_]+)__/, (_, bold) => chalk.bold(bold))\n\tformatted = formatted.replace(/\\*([^*]+)\\*/g, (_, italic) => chalk.italic(italic))\n\tformatted = formatted.replace(/_([^_]+)_/g, (_, italic) => chalk.italic(italic))\n\tformatted = formatted.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, (_, label, url) => {\n\t\treturn `${chalk.blue(label)} ${chalk.dim(`(${url})`)}`\n\t})\n\treturn formatted\n}\n","import chalk from \"chalk\"\n\ninterface LangSpec {\n\tcomment: null | string\n\tkeywords: Set<string>\n}\n\nconst kw = (s: string): Set<string> => new Set(s.split(/\\s+/).filter(Boolean))\n\nconst TS = kw(`\n\tabstract as async await break case catch class const continue debugger default delete do else enum export extends\n\tfalse finally for from function get if implements import in instanceof interface is let new null of package private\n\tprotected public readonly return set static super switch this throw true try type typeof undefined var void while\n\twith yield\n`)\n\nconst PY = kw(`\n\tFalse None True and as assert async await break class continue def del elif else except finally for from global if\n\timport in is lambda nonlocal not or pass raise return try while with yield\n`)\n\nconst SH = kw(`\n\tif then else elif fi for in do done while until case esac function return break continue local export readonly\n\tdeclare typeset\n`)\n\nconst GO = kw(`\n\tbreak case chan const continue default defer else fallthrough for func go goto if import interface map package range\n\treturn select struct switch type var nil true false\n`)\n\nconst RUST = kw(`\n\tas async await break const continue crate dyn else enum extern false fn for if impl in let loop match mod move mut\n\tpub ref return self Self static struct super trait true type unsafe use where while yield\n`)\n\nconst SQL = kw(`\n\tselect from where and or not in is null as by group order limit offset insert into values update set delete create\n\ttable drop alter add column primary key foreign references join left right inner outer on\n`)\n\nconst LANGS: Record<string, LangSpec> = {\n\tgo: { comment: \"//\", keywords: GO },\n\tjson: { comment: null, keywords: kw(\"true false null\") },\n\tpy: { comment: \"#\", keywords: PY },\n\trust: { comment: \"//\", keywords: RUST },\n\tsh: { comment: \"#\", keywords: SH },\n\tsql: { comment: \"--\", keywords: SQL },\n\tts: { comment: \"//\", keywords: TS },\n\tyaml: { comment: \"#\", keywords: kw(\"true false null yes no on off\") },\n}\n\nconst ALIAS: Record<string, string> = {\n\tbash: \"sh\",\n\tjavascript: \"ts\",\n\tjs: \"ts\",\n\tjsx: \"ts\",\n\tpython: \"py\",\n\trs: \"rust\",\n\tshell: \"sh\",\n\ttsx: \"ts\",\n\ttypescript: \"ts\",\n\tyml: \"yaml\",\n\tzsh: \"sh\",\n}\n\nconst resolve = (lang: string): LangSpec | null => LANGS[ALIAS[lang] ?? lang] ?? null\n\nexport const isHighlightable = (lang: string): boolean => resolve(lang) !== null\n\nconst TOKEN_RE =\n\t/'(?:[^'\\\\]|\\\\.)*'|\"(?:[^\"\\\\]|\\\\.)*\"|`(?:[^`\\\\]|\\\\.)*`|\\b\\d+(?:\\.\\d+)?\\b|[A-Za-z_$][\\w$]*/g\n\nexport function highlightCode(line: string, lang: string): string {\n\tconst spec = resolve(lang)\n\tif (!spec) return line\n\n\tif (spec.comment && line.trimStart().startsWith(spec.comment)) {\n\t\treturn chalk.gray(line)\n\t}\n\n\tlet result = \"\"\n\tlet last = 0\n\n\tfor (const m of line.matchAll(TOKEN_RE)) {\n\t\tconst tok = m[0]\n\t\tif (!tok) continue\n\t\tconst start = m.index ?? 0\n\t\tif (start > last) result += line.slice(last, start)\n\n\t\tconst ch = tok[0]\n\t\tif (ch === '\"' || ch === \"'\" || ch === \"`\") {\n\t\t\tresult += chalk.green(tok)\n\t\t} else if (ch && ch >= \"0\" && ch <= \"9\") {\n\t\t\tresult += chalk.yellow(tok)\n\t\t} else if (spec.keywords.has(tok)) {\n\t\t\tresult += chalk.magenta(tok)\n\t\t} else {\n\t\t\tresult += tok\n\t\t}\n\n\t\tlast = start + tok.length\n\t}\n\n\tif (last < line.length) result += line.slice(last)\n\treturn result\n}\n","import chalk from \"chalk\"\nimport { formatRichText } from \"./richText.ts\"\nimport { highlightCode, isHighlightable } from \"./syntax.ts\"\n\nexport type FenceState = { inCodeBlock: boolean; codeBlockLang: string }\n\nexport class MarkdownRenderer {\n\t#inCodeBlock = false\n\t#codeBlockLang = \"\"\n\n\tconstructor(seed?: FenceState) {\n\t\tif (seed) {\n\t\t\tthis.#inCodeBlock = seed.inCodeBlock\n\t\t\tthis.#codeBlockLang = seed.codeBlockLang\n\t\t}\n\t}\n\n\tgetState(): FenceState {\n\t\treturn {\n\t\t\tinCodeBlock: this.#inCodeBlock,\n\t\t\tcodeBlockLang: this.#codeBlockLang,\n\t\t}\n\t}\n\n\trenderChunk(text: string): string {\n\t\treturn text\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => this.renderLine(line))\n\t\t\t.join(\"\\n\")\n\t}\n\n\trenderLine(line: string): string {\n\t\tconst fence = line.match(/^\\s*(`{3,}|~{3,})(.*)$/)\n\t\tif (fence) {\n\t\t\tif (this.#inCodeBlock) {\n\t\t\t\tthis.#inCodeBlock = false\n\t\t\t\treturn \"\"\n\t\t\t}\n\t\t\tthis.#inCodeBlock = true\n\t\t\tthis.#codeBlockLang = (fence[2] ?? \"\").trim()\n\t\t\treturn this.#codeBlockLang ? chalk.gray(`─ ${this.#codeBlockLang}`) : \"\"\n\t\t}\n\n\t\tif (this.#inCodeBlock) {\n\t\t\tconst lang = this.#codeBlockLang\n\t\t\tconst code = isHighlightable(lang) ? highlightCode(line, lang) : chalk.dim(line)\n\t\t\treturn ` ${code}`\n\t\t}\n\n\t\tif (line.startsWith(\"#\")) {\n\t\t\tconst match = line.match(/^(#{1,6})\\s+(.*)$/)\n\t\t\tif (match?.[1] && match[2]) {\n\t\t\t\tconst level = match[1].length\n\t\t\t\tconst content = match[2]\n\t\t\t\tif (level === 1) return chalk.bold.magenta.underline(content)\n\t\t\t\tif (level === 2) return chalk.bold.blue(content)\n\t\t\t\treturn chalk.bold.cyan(content)\n\t\t\t}\n\t\t}\n\n\t\tlet formatted = line\n\t\tif (formatted.startsWith(\"- \") || formatted.startsWith(\"* \")) {\n\t\t\tformatted = ` ${chalk.yellow(\"•\")} ${formatted.slice(2)}`\n\t\t}\n\n\t\treturn formatRichText(formatted)\n\t}\n}\n\nexport function formatMarkdown(text: string): string {\n\treturn new MarkdownRenderer().renderChunk(text)\n}\n","import { type FenceState, MarkdownRenderer } from \"./renderer.ts\"\n\nexport class StreamingMarkdownRenderer {\n\t#stableText = \"\"\n\t#stableOutput = \"\"\n\t#stableFenceState: FenceState = { inCodeBlock: false, codeBlockLang: \"\" }\n\t#lastFullText = \"\"\n\t#lastFullOutput = \"\"\n\n\tupdate(fullText: string): string {\n\t\tif (fullText === this.#lastFullText) return this.#lastFullOutput\n\n\t\tif (this.#stableText && !fullText.startsWith(this.#stableText)) {\n\t\t\tthis.#stableText = \"\"\n\t\t\tthis.#stableOutput = \"\"\n\t\t\tthis.#stableFenceState = { inCodeBlock: false, codeBlockLang: \"\" }\n\t\t}\n\n\t\tconst boundary = findStableBoundary(fullText, this.#stableText.length, this.#stableFenceState)\n\n\t\tif (boundary > this.#stableText.length) {\n\t\t\tconst newStable = fullText.slice(0, boundary)\n\t\t\tconst chunk = this.#stableText ? newStable.slice(this.#stableText.length) : newStable\n\t\t\tconst renderer = new MarkdownRenderer(this.#stableFenceState)\n\t\t\tthis.#stableOutput += renderer.renderChunk(chunk)\n\t\t\tthis.#stableText = newStable\n\t\t\tthis.#stableFenceState = renderer.getState()\n\t\t}\n\n\t\tconst unstable = fullText.slice(this.#stableText.length)\n\t\tconst renderer = new MarkdownRenderer(this.#stableFenceState)\n\t\tconst unstableOutput = unstable ? renderer.renderChunk(unstable) : \"\"\n\n\t\tthis.#lastFullText = fullText\n\t\tthis.#lastFullOutput = this.#stableOutput + unstableOutput\n\t\treturn this.#lastFullOutput\n\t}\n\n\treset(): void {\n\t\tthis.#stableText = \"\"\n\t\tthis.#stableOutput = \"\"\n\t\tthis.#stableFenceState = { inCodeBlock: false, codeBlockLang: \"\" }\n\t\tthis.#lastFullText = \"\"\n\t\tthis.#lastFullOutput = \"\"\n\t}\n}\n\nfunction getFenceStateFromSeed(seed: FenceState, text: string): FenceState {\n\tlet inCodeBlock = seed.inCodeBlock\n\tlet codeBlockLang = seed.codeBlockLang\n\n\tfor (const line of text.split(\"\\n\")) {\n\t\tconst trimmed = line.trim()\n\t\tif (/^(?:`{3,}|~{3,})/.test(trimmed)) {\n\t\t\tif (inCodeBlock) {\n\t\t\t\tinCodeBlock = false\n\t\t\t\tcodeBlockLang = \"\"\n\t\t\t} else {\n\t\t\t\tinCodeBlock = true\n\t\t\t\tcodeBlockLang = trimmed.slice(3).trim()\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { inCodeBlock, codeBlockLang }\n}\n\nfunction findStableBoundary(text: string, minIndex: number, stableFenceState: FenceState): number {\n\tlet idx = text.length\n\n\twhile (idx > minIndex) {\n\t\tconst boundary = text.lastIndexOf(\"\\n\\n\", idx - 1)\n\t\tif (boundary < minIndex) return minIndex\n\n\t\tconst splitAt = boundary + 2\n\t\tconst slice = text.slice(minIndex, splitAt)\n\t\tconst state = getFenceStateFromSeed(stableFenceState, slice)\n\t\tif (!state.inCodeBlock) {\n\t\t\treturn splitAt\n\t\t}\n\t\tidx = boundary\n\t}\n\n\treturn minIndex\n}\n","import { Box, Text } from \"ink\"\nimport { memo } from \"react\"\nimport { formatToolArgs } from \"../../format.ts\"\nimport type { Msg } from \"../../types.ts\"\nimport { TERMINATION_PHRASES, TOOL_STYLE } from \"../constants.ts\"\nimport { formatMarkdown } from \"../markdown/index.ts\"\n\nexport function hasMeaningfulContent(msg: Msg): boolean {\n\tif (msg.role === \"user\") return true\n\tif (msg.role === \"tool_result\") return true\n\tif (msg.role === \"assistant\") {\n\t\tif (msg.model === \"system\") return true\n\t\tif (msg.stop === \"aborted\") return true\n\t\treturn msg.content.some((c) => {\n\t\t\tif (c.type === \"text\") return c.text.trim().length > 0\n\t\t\treturn false\n\t\t})\n\t}\n\treturn false\n}\n\nconst UserMessage = memo(function UserMessage({\n\tcontent,\n\tisFirst,\n}: {\n\tcontent: string\n\tisFirst: boolean\n}) {\n\tconst columns = process.stdout.columns || 80\n\tconst dividerWidth = Math.max(10, columns - 2)\n\tconst divider = \"─\".repeat(dividerWidth)\n\n\treturn (\n\t\t<Box flexDirection=\"column\" marginTop={isFirst ? 0 : 1} marginBottom={1}>\n\t\t\t<Text color=\"green\">{divider}</Text>\n\t\t\t<Box flexDirection=\"row\">\n\t\t\t\t<Box flexShrink={0} marginRight={1}>\n\t\t\t\t\t<Text bold color=\"greenBright\">\n\t\t\t\t\t\t{\"❯\"}\n\t\t\t\t\t</Text>\n\t\t\t\t</Box>\n\t\t\t\t<Box flexGrow={1} flexShrink={1}>\n\t\t\t\t\t<Text>{content}</Text>\n\t\t\t\t</Box>\n\t\t\t</Box>\n\t\t\t<Text color=\"green\">{divider}</Text>\n\t\t</Box>\n\t)\n})\n\nconst SystemMessage = memo(function SystemMessage({ text }: { text: string }) {\n\treturn <Text>{formatMarkdown(text)}</Text>\n})\n\nconst AssistantMessage = memo(function AssistantMessage({\n\tcontent,\n\tisAborted,\n\ttermPhrase,\n}: {\n\tcontent: string\n\tisAborted: boolean\n\ttermPhrase: string\n}) {\n\treturn (\n\t\t<Box flexDirection=\"column\" marginTop={0}>\n\t\t\t<Text>{content}</Text>\n\t\t\t{isAborted && (\n\t\t\t\t<Box marginTop={0}>\n\t\t\t\t\t<Text color=\"red\" italic>\n\t\t\t\t\t\t▲ {termPhrase}\n\t\t\t\t\t</Text>\n\t\t\t\t</Box>\n\t\t\t)}\n\t\t</Box>\n\t)\n})\n\nconst ToolResultMessage = memo(function ToolResultMessage({\n\ttool,\n\targs,\n\tisError,\n\tresText,\n}: {\n\ttool: string\n\targs: string\n\tisError: boolean\n\tresText: string\n}) {\n\tconst isRead = tool === \"read\"\n\tconst lineCount = isRead ? resText.split(\"\\n\").length : 0\n\tconst color = TOOL_STYLE[tool] || \"white\"\n\n\treturn (\n\t\t<Box flexDirection=\"row\" marginTop={0}>\n\t\t\t<Text color={isError ? \"red\" : \"green\"}>{isError ? \"✗\" : \"✓\"} </Text>\n\t\t\t<Text color={color} bold>\n\t\t\t\t{tool}\n\t\t\t</Text>\n\t\t\t{args && <Text> {args}</Text>}\n\t\t\t{isRead && !isError && <Text dimColor> ({lineCount} lines)</Text>}\n\t\t\t{isError && resText && <Text color=\"red\"> {resText.slice(0, 80)}</Text>}\n\t\t</Box>\n\t)\n})\n\nexport const Message = memo(function Message({ msg, isFirst }: { msg: Msg; isFirst: boolean }) {\n\tif (msg.role === \"user\") {\n\t\tconst content =\n\t\t\ttypeof msg.content === \"string\"\n\t\t\t\t? msg.content\n\t\t\t\t: msg.content.map((c) => (c.type === \"text\" ? c.text : \"\")).join(\"\")\n\t\treturn <UserMessage content={content} isFirst={isFirst} />\n\t}\n\n\tif (msg.role === \"assistant\") {\n\t\tif (msg.model === \"system\") {\n\t\t\treturn (\n\t\t\t\t<Box flexDirection=\"column\" marginTop={0}>\n\t\t\t\t\t{msg.content.map((c, i) =>\n\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: stable turn content\n\t\t\t\t\t\tc.type === \"text\" ? <SystemMessage key={i} text={c.text} /> : null,\n\t\t\t\t\t)}\n\t\t\t\t</Box>\n\t\t\t)\n\t\t}\n\n\t\tconst isAborted = msg.stop === \"aborted\"\n\t\tconst hasVisibleContent = isAborted || msg.content.some((c) => c.type === \"text\")\n\t\tif (!hasVisibleContent) return null\n\n\t\tconst textContent = msg.content\n\t\t\t.filter((c) => c.type === \"text\")\n\t\t\t.map((c) => c.text)\n\t\t\t.join(\"\")\n\n\t\tconst termPhrase = isAborted\n\t\t\t? (TERMINATION_PHRASES[msg.ts % TERMINATION_PHRASES.length] ?? \"Terminated by user\")\n\t\t\t: \"\"\n\n\t\tconst rendered = formatMarkdown(textContent)\n\t\treturn <AssistantMessage content={rendered} isAborted={isAborted} termPhrase={termPhrase} />\n\t}\n\n\tif (msg.role === \"tool_result\") {\n\t\tconst args = msg.args ? formatToolArgs(msg.args, true) : \"\"\n\t\tconst resText = msg.content\n\t\t\t.map((c) => (c.type === \"text\" ? c.text : \"\"))\n\t\t\t.join(\"\")\n\t\t\t.trim()\n\n\t\treturn <ToolResultMessage tool={msg.tool} args={args} isError={msg.isError} resText={resText} />\n\t}\n\n\treturn null\n})\n","import { Box, Text } from \"ink\"\nimport type { Model, Usage } from \"../../types.ts\"\n\nfunction fmtK(n: number): string {\n\tconst k = n / 1000\n\treturn k >= 100 ? `${Math.round(k)}K` : `${k.toFixed(1)}K`\n}\n\nfunction formatTokenUsage(used: number, contextWindow: number): string {\n\tif (used === 0) return `0/${fmtK(contextWindow)}`\n\tconst pct = Math.round((used / contextWindow) * 100)\n\treturn `${fmtK(used)}/${fmtK(contextWindow)} (${pct}%)`\n}\n\nexport function StatusBar({\n\tmodel,\n\tusage,\n\tbusy,\n\tsuggestions,\n\tselCmdIdx,\n\texitConfirmKey,\n\ttip,\n}: {\n\tmodel: Model\n\tusage: Usage\n\tbusy: boolean\n\tsuggestions: Array<{ name: string; desc: string }>\n\tselCmdIdx: number\n\texitConfirmKey: \"C\" | null\n\ttip: string | null\n}) {\n\treturn (\n\t\t<Box justifyContent=\"space-between\">\n\t\t\t<Box>\n\t\t\t\t{suggestions.length > 0 ? (\n\t\t\t\t\t<Box flexDirection=\"column\" marginLeft={2}>\n\t\t\t\t\t\t{suggestions.map((s, i) => (\n\t\t\t\t\t\t\t<Box key={s.name}>\n\t\t\t\t\t\t\t\t<Text\n\t\t\t\t\t\t\t\t\tcolor={i === selCmdIdx ? \"black\" : \"yellow\"}\n\t\t\t\t\t\t\t\t\tbackgroundColor={i === selCmdIdx ? \"yellow\" : undefined}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t/{s.name.padEnd(10)}\n\t\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t\t\t<Text dimColor> {s.desc}</Text>\n\t\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</Box>\n\t\t\t\t) : exitConfirmKey === \"C\" ? (\n\t\t\t\t\t<Text color=\"yellow\">Press Ctrl+C again to exit</Text>\n\t\t\t\t) : busy ? (\n\t\t\t\t\t<Box>\n\t\t\t\t\t\t<Text dimColor>Esc abort</Text>\n\t\t\t\t\t\t{tip && (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<Text dimColor> · </Text>\n\t\t\t\t\t\t\t\t<Text color=\"cyan\" dimColor>\n\t\t\t\t\t\t\t\t\t{tip}\n\t\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</Box>\n\t\t\t\t) : (\n\t\t\t\t\t<Text dimColor>Enter to send · /help for commands</Text>\n\t\t\t\t)}\n\t\t\t</Box>\n\n\t\t\t<Box>\n\t\t\t\t<Text dimColor>{formatTokenUsage(usage.in, model.contextWindow)}</Text>\n\t\t\t\t<Text dimColor> │ </Text>\n\t\t\t\t<Text dimColor>{model.id}</Text>\n\t\t\t</Box>\n\t\t</Box>\n\t)\n}\n","import { useCallback, useRef, useState } from \"react\"\nimport { StreamingMarkdownRenderer } from \"../markdown/index.ts\"\n\nconst FLUSH_MS = 16\n\n/**\n * Hook that manages a streaming text buffer with frame-rate-limited flushes\n * and incremental markdown rendering.\n *\n * - `append(text)`: add a text delta (called from the event loop)\n * - `bufferedStream`: the current rendered text (updated at ~60fps)\n * - `reset()`: clear all state for a new turn\n *\n * Internally, deltas accumulate in a raw buffer. A 16ms timer flushes\n * the buffer into state, triggering a React re-render. This prevents\n * per-delta renders while keeping the stream smooth.\n */\nexport function useStreamBuffer(): {\n\tbufferedStream: string\n\tappend: (text: string) => void\n\treset: () => void\n} {\n\tconst [bufferedStream, setBufferedStream] = useState(\"\")\n\tconst rawBuf = useRef(\"\")\n\tconst renderer = useRef(new StreamingMarkdownRenderer())\n\tconst timer = useRef<ReturnType<typeof setTimeout> | null>(null)\n\tconst dirty = useRef(false)\n\n\tconst flush = useCallback(() => {\n\t\ttimer.current = null\n\t\tif (!dirty.current) return\n\t\tdirty.current = false\n\t\tconst raw = rawBuf.current\n\t\tconst rendered = renderer.current.update(raw)\n\t\tsetBufferedStream(rendered)\n\t}, [])\n\n\tconst append = useCallback(\n\t\t(text: string) => {\n\t\t\trawBuf.current += text\n\t\t\tdirty.current = true\n\t\t\tif (!timer.current) {\n\t\t\t\ttimer.current = setTimeout(flush, FLUSH_MS)\n\t\t\t}\n\t\t},\n\t\t[flush],\n\t)\n\n\tconst reset = useCallback(() => {\n\t\tif (timer.current) {\n\t\t\tclearTimeout(timer.current)\n\t\t\ttimer.current = null\n\t\t}\n\t\trawBuf.current = \"\"\n\t\tdirty.current = false\n\t\trenderer.current.reset()\n\t\tsetBufferedStream(\"\")\n\t}, [])\n\n\treturn { bufferedStream, append, reset }\n}\n","import { useCallback, useRef, useState } from \"react\"\n\nconst TIPS = [\n\t\"/compact: shrink context when it gets long\",\n\t\"/models: switch between providers and models\",\n\t\"Up/Down: scroll through your input history\",\n\t\"Tab: autocomplete slash commands\",\n\t\"Ctrl+C twice: exit novacode\",\n\t\"Ctrl+D: quick exit\",\n\t\"/clear: wipe screen and start a fresh session\",\n\t\"/sessions: browse and resume past sessions\",\n\t\"/skills: list auto-loaded agent skills\",\n\t\"/providers: manage API keys and providers\",\n\t\"/update: check and install the latest version\",\n\t\"Esc: abort the current response\",\n\t\"nova -r: resume last session from CLI\",\n\t\"AGENTS.md: project context loaded automatically\",\n\t\"/reset: wipe all nova data and start fresh\",\n]\n\nexport function useTip(busy: boolean): string | null {\n\tconst [tip, setTip] = useState<string | null>(null)\n\tconst lastBusy = useRef(false)\n\n\tconst pick = useCallback(() => {\n\t\treturn TIPS[Math.floor(Math.random() * TIPS.length)]!\n\t}, [])\n\n\tif (busy && !lastBusy.current) {\n\t\tsetTip(pick())\n\t} else if (!busy && lastBusy.current) {\n\t\tsetTip(null)\n\t}\n\tlastBusy.current = busy\n\n\treturn tip\n}\n","import chalk from \"chalk\"\nimport { Box, render, Static, Text, useApp, useInput } from \"ink\"\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\"\nimport type { Agent } from \"../agent/agent.ts\"\nimport { COMMANDS, dispatch } from \"../commands/index.ts\"\nimport { getProvider, MODELS } from \"../config/catalog.ts\"\nimport { loadAuth } from \"../config/store.ts\"\nimport { generateSessionTitle } from \"../session/compact.ts\"\nimport type { SessionStore } from \"../session/store.ts\"\nimport { groupSkills } from \"../skills/index.ts\"\nimport type { Msg, Prompts, Skill, Usage } from \"../types.ts\"\nimport { checkForUpdate, getCurrentVersion } from \"../update.ts\"\nimport { Cursor, LiveArea } from \"./components/liveArea.tsx\"\nimport { hasMeaningfulContent, Message } from \"./components/message.tsx\"\nimport { StatusBar } from \"./components/statusBar.tsx\"\nimport { useStreamBuffer } from \"./hooks/useStreamBuffer.ts\"\nimport { useTip } from \"./hooks/useTip.ts\"\nimport { ConfirmPrompt, PasswordPrompt, SelectPrompt } from \"./prompts.tsx\"\n\ntype PromptMode =\n\t| { type: \"chat\" }\n\t| {\n\t\t\ttype: \"select\"\n\t\t\tmessage: string\n\t\t\toptions: Array<{ value: string; label: string; hint?: string }>\n\t\t\theader?: string\n\t\t\tfooter?: string\n\t }\n\t| {\n\t\t\ttype: \"password\"\n\t\t\tmessage: string\n\t\t\tvalidate?: (v: string) => string | undefined\n\t }\n\t| { type: \"confirm\"; message: string }\n\nexport async function interactive(\n\tagent: Agent,\n\tstore: SessionStore,\n\tsessionId: string,\n\tskills: Skill[] = [],\n\thasAgentsMd = false,\n): Promise<void> {\n\tprocess.stdout.write(\"\\x1B[?25l\")\n\tconst version = await getCurrentVersion()\n\tprocess.stdout.write(`${chalk.cyan.bold(\"⚡ novacode\")} ${chalk.gray(`v${version}`)}\\n`)\n\tif (hasAgentsMd) {\n\t\tprocess.stdout.write(`${chalk.dim(\" context:\")} ${chalk.cyan(\"AGENTS.md\")}\\n`)\n\t}\n\tif (skills.length > 0) {\n\t\tconst skillNames = groupSkills(skills)\n\t\t\t.map((g) =>\n\t\t\t\tg.length > 1\n\t\t\t\t\t? `${chalk.cyan(g[0]!.name)} ${chalk.yellow(\"(duplicate)\")}`\n\t\t\t\t\t: chalk.cyan(g[0]!.name),\n\t\t\t)\n\t\t\t.join(\", \")\n\t\tprocess.stdout.write(`${chalk.dim(\" skills:\")} ${skillNames}\\n`)\n\t}\n\n\tconst initialHistory = await store.history(sessionId)\n\n\ttry {\n\t\tconst { waitUntilExit } = render(\n\t\t\t<App\n\t\t\t\tagent={agent}\n\t\t\t\tstore={store}\n\t\t\t\tsessionId={sessionId}\n\t\t\t\tskills={skills}\n\t\t\t\tinitialHistory={initialHistory}\n\t\t\t/>,\n\t\t\t{ exitOnCtrlC: false },\n\t\t)\n\t\tawait waitUntilExit()\n\t} finally {\n\t\tprocess.stdout.write(\"\\x1B[?25h\")\n\t\tawait store.prune()\n\t}\n}\n\nfunction App({\n\tagent,\n\tstore,\n\tsessionId: initialSessionId,\n\tskills,\n\tinitialHistory,\n}: {\n\tagent: Agent\n\tstore: SessionStore\n\tsessionId: string\n\tskills: Skill[]\n\tinitialHistory: Msg[]\n}) {\n\tconst [currSessionId, setCurrSessionId] = useState(initialSessionId)\n\tconst [msgs, setMsgs] = useState<Msg[]>(initialHistory)\n\n\tconst handleSwitchSession = useCallback(\n\t\tasync (newSessionId: string) => {\n\t\t\tconst s = await store.get(newSessionId)\n\t\t\tif (!s) return\n\n\t\t\tconst provider = getProvider(s.provider)\n\t\t\tconst model =\n\t\t\t\tMODELS.find((m) => m.id === s.model && m.provider === s.provider) ||\n\t\t\t\tMODELS.find((m) => m.id === s.model)\n\t\t\tif (provider && model) {\n\t\t\t\tconst auth = await loadAuth()\n\t\t\t\tconst apiKey = auth.apiKeys[s.provider] || \"\"\n\t\t\t\tagent.updateConfig({\n\t\t\t\t\tapiFormat: provider.apiFormat,\n\t\t\t\t\tmodel,\n\t\t\t\t\tapiKey,\n\t\t\t\t\tbaseUrl: provider.baseUrl,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tconst activeMsgs = await store.messages(newSessionId)\n\t\t\tconst fullHistory = await store.history(newSessionId)\n\t\t\tagent.setMessages(activeMsgs)\n\t\t\tsetMsgs(fullHistory)\n\t\t\tsetCurrSessionId(newSessionId)\n\t\t},\n\t\t[store, agent],\n\t)\n\n\tconst handleNewSession = useCallback(async () => {\n\t\tconst m = agent.model\n\t\tconst session = await store.create(process.cwd(), m.id, m.provider)\n\t\tagent.setMessages([])\n\t\tsetMsgs([])\n\t\tsetCurrSessionId(session.id)\n\t}, [store, agent])\n\n\tconst [thinking, setThinking] = useState(false)\n\tconst [busy, setBusy] = useState(false)\n\tconst [input, setInput] = useState(\"\")\n\tconst [status, setStatus] = useState(\"\")\n\tconst [usage, setUsage] = useState<Usage>({ in: 0, out: 0 })\n\tconst [selCmdIdx, setSelCmdIdx] = useState(0)\n\tconst [mode, setMode] = useState<PromptMode>({ type: \"chat\" })\n\tconst resolveRef = useRef<((v: unknown) => void) | null>(null)\n\tconst history = useRef<string[]>([])\n\tconst hIdx = useRef(-1)\n\tconst abortCtrl = useRef<AbortController | null>(null)\n\tconst [updateInfo, setUpdateInfo] = useState<{\n\t\tcurrent: string\n\t\tlatest: string\n\t} | null>(null)\n\tconst { exit } = useApp()\n\tconst lastExitPress = useRef<{ key: \"C\"; ts: number } | null>(null)\n\tconst [exitConfirmKey, setExitConfirmKey] = useState<\"C\" | null>(null)\n\n\tconst { bufferedStream, append: appendStream, reset: resetStream } = useStreamBuffer()\n\tconst tip = useTip(busy)\n\n\tuseEffect(() => {\n\t\tconst check = async () => {\n\t\t\tconst info = await checkForUpdate()\n\t\t\tif (info?.hasUpdate) {\n\t\t\t\tsetUpdateInfo({ current: info.current, latest: info.latest })\n\t\t\t}\n\t\t}\n\t\tcheck()\n\t}, [])\n\n\tconst isTypingCmd = input.startsWith(\"/\") && !input.includes(\" \")\n\tconst suggestions = isTypingCmd\n\t\t? COMMANDS.filter(\n\t\t\t\t(c) =>\n\t\t\t\t\tc.name.startsWith(input.slice(1).toLowerCase()) ||\n\t\t\t\t\tc.aliases?.some((a) => a.startsWith(input.slice(1).toLowerCase())),\n\t\t\t)\n\t\t: []\n\n\tconst prompts: Prompts = {\n\t\tselect: useCallback(\n\t\t\t(config) =>\n\t\t\t\tnew Promise((resolve) => {\n\t\t\t\t\tresolveRef.current = resolve as (v: unknown) => void\n\t\t\t\t\tsetMode({ type: \"select\", ...config })\n\t\t\t\t}),\n\t\t\t[],\n\t\t),\n\t\tpassword: useCallback(\n\t\t\t(config) =>\n\t\t\t\tnew Promise((resolve) => {\n\t\t\t\t\tresolveRef.current = resolve as (v: unknown) => void\n\t\t\t\t\tsetMode({ type: \"password\", ...config })\n\t\t\t\t}),\n\t\t\t[],\n\t\t),\n\t\tconfirm: useCallback(\n\t\t\t(config) =>\n\t\t\t\tnew Promise((resolve) => {\n\t\t\t\t\tresolveRef.current = resolve as (v: unknown) => void\n\t\t\t\t\tsetMode({ type: \"confirm\", ...config })\n\t\t\t\t}),\n\t\t\t[],\n\t\t),\n\t}\n\n\tfunction resolvePrompt(value: unknown) {\n\t\tconst fn = resolveRef.current\n\t\tresolveRef.current = null\n\t\tsetMode({ type: \"chat\" })\n\t\tfn?.(value)\n\t}\n\n\tfunction commitMsg(msg: Msg) {\n\t\tsetMsgs((prev) => [...prev, msg])\n\t\tagent.setMessages([...agent.messages, msg])\n\t\tstore.append(currSessionId, msg).catch((err) => {\n\t\t\tconsole.error(\"Error appending message to session store:\", err)\n\t\t})\n\t}\n\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: reset selection on input change\n\tuseEffect(() => {\n\t\tsetSelCmdIdx(0)\n\t}, [input])\n\n\tuseInput((ch, key) => {\n\t\tif (key.ctrl && (ch === \"c\" || ch === \"d\")) {\n\t\t\tif (busy) {\n\t\t\t\tif (ch === \"c\") {\n\t\t\t\t\tif (abortCtrl.current) {\n\t\t\t\t\t\tabortCtrl.current.abort()\n\t\t\t\t\t\tabortCtrl.current = null\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (ch === \"d\") {\n\t\t\t\texit()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst now = Date.now()\n\t\t\tif (\n\t\t\t\tlastExitPress.current &&\n\t\t\t\tlastExitPress.current.key === \"C\" &&\n\t\t\t\tnow - lastExitPress.current.ts < 2000\n\t\t\t) {\n\t\t\t\texit()\n\t\t\t} else {\n\t\t\t\tlastExitPress.current = { key: \"C\", ts: now }\n\t\t\t\tsetExitConfirmKey(\"C\")\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tif (lastExitPress.current?.key === \"C\" && Date.now() - lastExitPress.current.ts >= 2000) {\n\t\t\t\t\t\tlastExitPress.current = null\n\t\t\t\t\t\tsetExitConfirmKey(null)\n\t\t\t\t\t}\n\t\t\t\t}, 2000)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tif (mode.type !== \"chat\") return\n\n\t\tif (key.escape) {\n\t\t\tif (abortCtrl.current) {\n\t\t\t\tabortCtrl.current.abort()\n\t\t\t\tabortCtrl.current = null\n\t\t\t} else if (input) {\n\t\t\t\tsetInput(\"\")\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tif (key.upArrow) {\n\t\t\tif (isTypingCmd && suggestions.length > 0) {\n\t\t\t\tsetSelCmdIdx((prev) => (prev > 0 ? prev - 1 : suggestions.length - 1))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (history.current.length > 0) {\n\t\t\t\thIdx.current = Math.min(hIdx.current + 1, history.current.length - 1)\n\t\t\t\tsetInput(history.current[hIdx.current] ?? \"\")\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tif (key.downArrow) {\n\t\t\tif (isTypingCmd && suggestions.length > 0) {\n\t\t\t\tsetSelCmdIdx((prev) => (prev < suggestions.length - 1 ? prev + 1 : 0))\n\t\t\t\treturn\n\t\t\t}\n\t\t\thIdx.current = Math.max(hIdx.current - 1, -1)\n\t\t\tsetInput(hIdx.current >= 0 ? (history.current[hIdx.current] ?? \"\") : \"\")\n\t\t\treturn\n\t\t}\n\t\tif (key.tab) {\n\t\t\tif (isTypingCmd && suggestions.length > 0) {\n\t\t\t\tconst match = suggestions[selCmdIdx]\n\t\t\t\tif (match) {\n\t\t\t\t\tsetInput(`/${match.name} `)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tif (!key.return) {\n\t\t\tsetInput((prev) => {\n\t\t\t\tif (key.backspace || key.delete) return prev.slice(0, -1)\n\t\t\t\treturn prev + (ch || \"\")\n\t\t\t})\n\t\t\treturn\n\t\t}\n\n\t\tif (busy) return\n\n\t\tlet line = input.trim()\n\t\tif (!line) return\n\n\t\tif (isTypingCmd && suggestions.length > 0) {\n\t\t\tconst match = suggestions[selCmdIdx]\n\t\t\tif (match) {\n\t\t\t\tline = `/${match.name}`\n\t\t\t}\n\t\t}\n\n\t\tsetInput(\"\")\n\t\thistory.current.unshift(line)\n\t\thIdx.current = -1\n\n\t\tif (line.startsWith(\"/\")) {\n\t\t\tif (line === \"/compact\") {\n\t\t\t\tsetBusy(true)\n\t\t\t\tsetStatus(\"Compacting...\")\n\t\t\t}\n\t\t\tdispatch(\n\t\t\t\tline,\n\t\t\t\tagent,\n\t\t\t\tstore,\n\t\t\t\tcurrSessionId,\n\t\t\t\tprompts,\n\t\t\t\texit,\n\t\t\t\thandleSwitchSession,\n\t\t\t\thandleNewSession,\n\t\t\t\tskills,\n\t\t\t).then((r) => {\n\t\t\t\tsetBusy(false)\n\t\t\t\tsetStatus(\"\")\n\t\t\t\tif (r) {\n\t\t\t\t\tcommitMsg({\n\t\t\t\t\t\trole: \"assistant\",\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: r }],\n\t\t\t\t\t\tmodel: \"system\",\n\t\t\t\t\t\tprovider: \"system\",\n\t\t\t\t\t\tusage: { in: 0, out: 0 },\n\t\t\t\t\t\tstop: \"stop\",\n\t\t\t\t\t\tts: Date.now(),\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t})\n\t\t\treturn\n\t\t}\n\n\t\tconst userMsg: Msg = { role: \"user\", content: line, ts: Date.now() }\n\t\tcommitMsg(userMsg)\n\n\t\tabortCtrl.current = new AbortController()\n\t\tconst eventStream = agent.prompt(abortCtrl.current.signal)\n\n\t\trunEventLoop(eventStream)\n\t})\n\n\tasync function runEventLoop(eventStream: ReturnType<Agent[\"prompt\"]>) {\n\t\ttry {\n\t\t\tfor await (const ev of eventStream) {\n\t\t\t\tswitch (ev.type) {\n\t\t\t\t\tcase \"start\":\n\t\t\t\t\t\tsetBusy(true)\n\t\t\t\t\t\tresetStream()\n\t\t\t\t\t\tsetThinking(false)\n\t\t\t\t\t\tsetStatus(\"\")\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"text_delta\":\n\t\t\t\t\t\tif (ev.text) {\n\t\t\t\t\t\t\tsetThinking(false)\n\t\t\t\t\t\t\tappendStream(ev.text)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"thinking_delta\":\n\t\t\t\t\t\tsetThinking(true)\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"assistant_msg\":\n\t\t\t\t\t\tcommitMsg(ev.msg)\n\t\t\t\t\t\tresetStream()\n\t\t\t\t\t\tsetThinking(false)\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"tool_call\":\n\t\t\t\t\t\tsetStatus(chalk.dim(`⏳ ${ev.call.name}…`))\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"tool_result\":\n\t\t\t\t\t\tcommitMsg(ev.result)\n\t\t\t\t\t\tsetStatus(\n\t\t\t\t\t\t\tev.result.isError\n\t\t\t\t\t\t\t\t? chalk.red(`✗ ${ev.result.tool}`)\n\t\t\t\t\t\t\t\t: chalk.green(`✓ ${ev.result.tool}`),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"turn_end\":\n\t\t\t\t\t\tsetStatus(\"\")\n\t\t\t\t\t\tstore\n\t\t\t\t\t\t\t.get(currSessionId)\n\t\t\t\t\t\t\t.then((s) => {\n\t\t\t\t\t\t\t\tif (s && !s.title && agent.messages.length >= 2) {\n\t\t\t\t\t\t\t\t\tgenerateSessionTitle(agent.messages, agent.model, agent.apiKey, agent.baseUrl)\n\t\t\t\t\t\t\t\t\t\t.then((title) => {\n\t\t\t\t\t\t\t\t\t\t\tif (title) {\n\t\t\t\t\t\t\t\t\t\t\t\tstore.setTitle(currSessionId, title).catch(() => {})\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t.catch(() => {})\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.catch(() => {})\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase \"usage\":\n\t\t\t\t\t\tif (ev.usage) setUsage(ev.usage)\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst errMsg: Msg = {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tmodel: \"system\",\n\t\t\t\tprovider: \"system\",\n\t\t\t\tcontent: [{ type: \"text\", text: chalk.red(`Error: ${(err as Error).message}`) }],\n\t\t\t\tusage: { in: 0, out: 0 },\n\t\t\t\tstop: \"error\",\n\t\t\t\tts: Date.now(),\n\t\t\t}\n\t\t\tcommitMsg(errMsg)\n\t\t} finally {\n\t\t\tabortCtrl.current = null\n\t\t\tsetBusy(false)\n\t\t\tresetStream()\n\t\t\tsetThinking(false)\n\t\t\tsetStatus(\"\")\n\t\t}\n\t}\n\n\tconst visibleMsgs = useMemo(() => msgs.filter(hasMeaningfulContent), [msgs])\n\n\tif (mode.type === \"select\") {\n\t\treturn (\n\t\t\t<SelectPrompt\n\t\t\t\tmessage={mode.message}\n\t\t\t\toptions={mode.options}\n\t\t\t\theader={mode.header}\n\t\t\t\tfooter={mode.footer}\n\t\t\t\tonSelect={resolvePrompt}\n\t\t\t/>\n\t\t)\n\t}\n\tif (mode.type === \"password\") {\n\t\treturn (\n\t\t\t<PasswordPrompt message={mode.message} validate={mode.validate} onSubmit={resolvePrompt} />\n\t\t)\n\t}\n\tif (mode.type === \"confirm\") {\n\t\treturn <ConfirmPrompt message={mode.message} onConfirm={resolvePrompt} />\n\t}\n\n\treturn (\n\t\t<Box flexDirection=\"column\" paddingX={1} width=\"100%\">\n\t\t\t<Static items={visibleMsgs}>\n\t\t\t\t{(m, i) => <Message key={`${m.ts}-${i}`} msg={m} isFirst={i === 0} />}\n\t\t\t</Static>\n\n\t\t\t<LiveArea stream={bufferedStream} thinking={thinking} busy={busy} status={status} />\n\n\t\t\t<Box\n\t\t\t\tflexDirection=\"column\"\n\t\t\t\tmarginTop={visibleMsgs.length > 0 || bufferedStream || thinking || busy ? 1 : 0}\n\t\t\t>\n\t\t\t\t{updateInfo && (\n\t\t\t\t\t<Box\n\t\t\t\t\t\tborderStyle=\"round\"\n\t\t\t\t\t\tborderColor=\"yellow\"\n\t\t\t\t\t\tpaddingX={1}\n\t\t\t\t\t\tmarginBottom={1}\n\t\t\t\t\t\tflexDirection=\"column\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<Text color=\"yellow\" bold>\n\t\t\t\t\t\t\t⬆ Update Available (v{updateInfo.current} → v{updateInfo.latest})\n\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t<Text dimColor>\n\t\t\t\t\t\t\tRun <Text color=\"cyan\">/update</Text> or <Text color=\"cyan\">nova update</Text> to\n\t\t\t\t\t\t\tupgrade.\n\t\t\t\t\t\t</Text>\n\t\t\t\t\t</Box>\n\t\t\t\t)}\n\n\t\t\t\t<Box\n\t\t\t\t\tflexDirection=\"column\"\n\t\t\t\t\tborderStyle=\"single\"\n\t\t\t\t\tborderTop\n\t\t\t\t\tborderBottom\n\t\t\t\t\tborderColor=\"green\"\n\t\t\t\t\tborderLeft={false}\n\t\t\t\t\tborderRight={false}\n\t\t\t\t\tpaddingTop={0}\n\t\t\t\t\tpaddingBottom={0}\n\t\t\t\t\tmarginBottom={0}\n\t\t\t\t>\n\t\t\t\t\t<Box flexDirection=\"row\">\n\t\t\t\t\t\t<Box flexShrink={0} marginRight={1}>\n\t\t\t\t\t\t\t<Text bold color=\"greenBright\">\n\t\t\t\t\t\t\t\t{\"❯\"}\n\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t</Box>\n\t\t\t\t\t\t<Box flexGrow={1} flexShrink={1}>\n\t\t\t\t\t\t\t<Text>\n\t\t\t\t\t\t\t\t{input}\n\t\t\t\t\t\t\t\t<Cursor />\n\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t</Box>\n\t\t\t\t\t</Box>\n\t\t\t\t</Box>\n\n\t\t\t\t<StatusBar\n\t\t\t\t\tmodel={agent.model}\n\t\t\t\t\tusage={usage}\n\t\t\t\t\tbusy={busy}\n\t\t\t\t\tsuggestions={suggestions}\n\t\t\t\t\tselCmdIdx={selCmdIdx}\n\t\t\t\t\texitConfirmKey={exitConfirmKey}\n\t\t\t\t\ttip={tip}\n\t\t\t\t/>\n\t\t\t</Box>\n\t\t</Box>\n\t)\n}\n"],"mappings":"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"}