flintmaker 0.2.5 → 0.5.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.
@@ -1,27 +0,0 @@
1
- import{a as G,c as Z,d as K,e as V}from"./chunk-EUPBID7K.js";import{a as pt,b as ft}from"./chunk-O4FFCD22.js";import{A as ht,B as lt,a as D,b as J,c as z,d as Q,f as L,g as I,h as N,i as X,k as U,m as W,n as F,o as tt,p as et,q as st,r as it,s as rt,t as M,u as q,v as k,w as nt,x as g,y as ot,z as at}from"./chunk-YHI6436D.js";import{A as Pt,b as ct,c as w,d as ut,f as dt,g as mt,h as x,i as gt,j as bt,k as wt,l as xt,m as v,o as vt,p as yt,r as y,s as p,t as St,u as $t,v as Ct,w as T,x as Mt,y as kt,z as Tt}from"./chunk-YCYJUZK6.js";import{b as o}from"./chunk-5PRYZOW7.js";import"./chunk-K3ZZ2VJH.js";import{existsSync as Vt}from"node:fs";import{homedir as Xt}from"node:os";import{join as te}from"node:path";var S=class{text="";cursor=0;set(t,e=t.length){this.text=t,this.cursor=Math.max(0,Math.min(e,t.length))}clear(){this.set("")}insert(t){this.text=this.text.slice(0,this.cursor)+t+this.text.slice(this.cursor),this.cursor+=t.length}prevIndex(t){if(t<=0)return 0;let e=this.text.charCodeAt(t-1);return e>=56320&&e<=57343&&t>=2?t-2:t-1}nextIndex(t){if(t>=this.text.length)return this.text.length;let e=this.text.codePointAt(t);return t+(e>65535?2:1)}backspace(){if(this.cursor===0)return;let t=this.prevIndex(this.cursor);this.text=this.text.slice(0,t)+this.text.slice(this.cursor),this.cursor=t}del(){this.cursor>=this.text.length||(this.text=this.text.slice(0,this.cursor)+this.text.slice(this.nextIndex(this.cursor)))}left(){this.cursor=this.prevIndex(this.cursor)}right(){this.cursor=this.nextIndex(this.cursor)}lineStart(t=this.cursor){return this.text.lastIndexOf(`
2
- `,t-1)+1}lineEnd(t=this.cursor){let e=this.text.indexOf(`
3
- `,t);return e<0?this.text.length:e}home(){this.cursor=this.lineStart()}end(){this.cursor=this.lineEnd()}wordLeft(){let t=this.cursor;for(;t>0&&/\s/.test(this.text[t-1]);)t--;for(;t>0&&!/\s/.test(this.text[t-1]);)t--;this.cursor=t}wordRight(){let t=this.cursor;for(;t<this.text.length&&/\s/.test(this.text[t]);)t++;for(;t<this.text.length&&!/\s/.test(this.text[t]);)t++;this.cursor=t}deleteWordBack(){let t=this.cursor;this.wordLeft(),this.text=this.text.slice(0,this.cursor)+this.text.slice(t)}killToEnd(){let t=this.lineEnd();this.text=this.text.slice(0,this.cursor)+this.text.slice(t===this.cursor?t+1:t)}killToStart(){let t=this.lineStart();this.text=this.text.slice(0,t)+this.text.slice(this.cursor),this.cursor=t}get onFirstLine(){return this.text.lastIndexOf(`
4
- `,this.cursor-1)<0}get onLastLine(){return this.text.indexOf(`
5
- `,this.cursor)<0}vertical(t){if(t<0?this.onFirstLine:this.onLastLine)return!1;let e=w(this.text.slice(this.lineStart(),this.cursor)),s=t<0?this.lineStart(this.lineStart()-1):this.lineEnd()+1,i=s,r=0,n=this.lineEnd(s);for(;i<n;){let l=ct(this.text.codePointAt(i));if(r+l>e)break;r+=l,i=this.nextIndex(i)}return this.cursor=i,!0}currentToken(){let t=this.cursor;for(;t>0&&!/\s/.test(this.text[t-1]);)t--;return{start:t,text:this.text.slice(t,this.cursor)}}replaceToken(t,e){this.text=this.text.slice(0,t)+e+this.text.slice(this.cursor),this.cursor=t+e.length}layout(t){let e=[],s=0,i=0,r=0;for(let n of this.text.split(`
6
- `)){let l=dt(n,Math.max(1,t)),a=r;l.forEach((h,c)=>{let b=c===l.length-1,d=a+h.length;this.cursor>=a&&(this.cursor<d||b&&this.cursor===d)&&(s=e.length,i=w(h.slice(0,this.cursor-a))),e.push(h),a=d}),r+=n.length+1}return i>=t&&(s+=1,i=0,s>=e.length&&e.push("")),{rows:e,row:s,col:i}}};import{readFileSync as At,statSync as qt}from"node:fs";import{dirname as _t,join as Et,resolve as Rt}from"node:path";function Ot(u){let t=Rt(u);for(let e=0;e<40;e++){let s=Et(t,".git");try{let r=s;if(qt(s).isFile()){let a=/^gitdir:\s*(.+)$/m.exec(At(s,"utf8"));if(!a)return null;r=Rt(t,a[1].trim())}let n=At(Et(r,"HEAD"),"utf8").trim(),l=/^ref: refs\/heads\/(.+)$/.exec(n);return l?l[1]:n.slice(0,7)}catch{}let i=_t(t);if(i===t)return null;t=i}return null}import{appendFileSync as Bt,mkdirSync as Yt,readFileSync as jt,writeFileSync as Ht}from"node:fs";import{homedir as Jt}from"node:os";import{dirname as zt,join as Qt}from"node:path";var Gt=()=>process.env.FLINT_HISTORY||Qt(Jt(),".flintmaker","history"),_=500,P=class{constructor(t=Gt()){this.file=t;if(t)try{this.entries=jt(t,"utf8").split(`
7
- `).filter(Boolean).map(e=>{try{let s=JSON.parse(e);return typeof s=="string"?s:null}catch{return null}}).filter(e=>e!==null).slice(-_)}catch{}}file;entries=[];index=-1;draft="";add(t){this.reset();let e=t.trim();if(!(!e||this.entries.at(-1)===e)&&(this.entries.push(e),!!this.file))try{Yt(zt(this.file),{recursive:!0,mode:448}),this.entries.length>_*1.5?(this.entries=this.entries.slice(-_),Ht(this.file,this.entries.map(s=>JSON.stringify(s)).join(`
8
- `)+`
9
- `,{mode:384})):Bt(this.file,JSON.stringify(e)+`
10
- `,{mode:384})}catch{}}prev(t){return this.entries.length===0||(this.index===-1&&(this.draft=t,this.index=this.entries.length),this.index===0)?null:(this.index--,this.entries[this.index])}next(){return this.index===-1?null:(this.index++,this.index>=this.entries.length?(this.index=-1,this.draft):this.entries[this.index])}reset(){this.index=-1,this.draft=""}};var Zt={1:"home",2:"insert",3:"delete",4:"end",5:"pageup",6:"pagedown",7:"home",8:"end"},B={A:"up",B:"down",C:"right",D:"left",H:"home",F:"end",Z:"tab"},Dt={13:"enter",9:"tab",27:"escape",127:"backspace",8:"backspace",32:"space"};function Y(u){let t=(u??1)-1;return{shift:!!(t&1),meta:!!(t&2)||!!(t&8),ctrl:!!(t&4)}}function Lt(u,t){let e=Y(t);if(Dt[u])return{name:Dt[u],...e,...u===32&&!e.ctrl&&!e.meta?{text:" "}:{}};let s=String.fromCodePoint(u);return e.ctrl||e.meta?{name:s.toLowerCase(),...e}:{name:s,text:e.shift?s.toUpperCase():s,...e}}var It="\x1B[200~",Kt="\x1B[201~",A=class{constructor(t={}){this.opts=t}opts;buf="";paste=null;pasteUntil=0;feed(t){if(this.opts.pasteHeuristic&&this.paste===null&&this.buf===""&&t!==""&&!t.includes("\x1B")){let s=(this.opts.now??Date.now)();if(/[\r\n][^\r\n]/.test(t)||s<this.pasteUntil)return this.pasteUntil=s+40,[{name:"paste",text:t.replace(/\r\n?/g,`
11
- `)}]}this.buf+=t;let e=[];for(;;){if(this.paste!==null){let r=this.buf.indexOf(Kt);if(r<0)return this.paste+=this.buf,this.buf="",e;this.paste+=this.buf.slice(0,r),this.buf=this.buf.slice(r+Kt.length),e.push({name:"paste",text:this.paste.replace(/\r\n?/g,`
12
- `)}),this.paste=null;continue}if(this.buf==="")return e;if(this.buf.startsWith(It)){this.buf=this.buf.slice(It.length),this.paste="";continue}if(this.buf==="\x1B")return e;let[s,i]=this.one(this.buf);if(i===0)return e;this.buf=this.buf.slice(i),s&&e.push(s)}}flush(){if(this.paste!==null||this.buf==="")return[];let t=this.buf;return this.buf="",t.startsWith("\x1B")?[{name:"escape"},...this.feed(t.slice(1))]:this.feed(t)}get pending(){return this.buf!==""&&this.paste===null}one(t){let e=t[0];if(e==="\x1B"){let n=t[1];if(n==="["){let h=/^\x1b\[([0-9;:?<>]*)([ -/]*)([@-~])/.exec(t);if(!h)return t.length<16?[null,0]:[{name:"escape"},1];let[c,b,,d]=h,m=b.split(";").map(f=>Number(f.split(":")[0])||void 0);return d==="u"?[Lt(m[0]??0,m[1]),c.length]:d==="~"?m[0]===27&&m[2]!==void 0?[Lt(m[2],m[1]),c.length]:[{name:Zt[String(m[0])]??"unknown",...Y(m[1])},c.length]:d==="Z"?[{name:"tab",shift:!0},c.length]:B[d]?[{name:B[d],...Y(m[1])},c.length]:d==="I"||d==="O"?[{name:d==="I"?"focusin":"focusout"},c.length]:[{name:"unknown"},c.length]}if(n==="O"&&t.length>=3)return[{name:B[t[2]]??{P:"f1",Q:"f2",R:"f3",S:"f4"}[t[2]]??"unknown"},3];if(n==="\x1B")return[{name:"escape"},1];if(n==="\r"||n===`
13
- `)return[{name:"enter",meta:!0},2];if(n==="\x7F"||n==="\b")return[{name:"backspace",meta:!0},2];let l=t.codePointAt(1),a=l>65535?3:2;return[{name:String.fromCodePoint(l).toLowerCase(),meta:!0},a]}if(e==="\r")return[{name:"enter"},t[1]===`
14
- `?2:1];if(e===`
15
- `)return[{name:"enter",ctrl:!0},1];if(e===" ")return[{name:"tab"},1];if(e==="\x7F"||e==="\b")return[{name:"backspace"},1];if(e==="\0")return[{name:"space",ctrl:!0},1];let s=e.charCodeAt(0);if(s<32)return[{name:String.fromCharCode(s+96),ctrl:!0},1];let i=t.codePointAt(0),r=String.fromCodePoint(i);return[{name:r,text:r},r.length]}},E=u=>u.name==="enter"&&!!(u.shift||u.meta||u.ctrl);var Nt="\x1B[?2026h",Ut="\x1B[?2026l",$=class{constructor(t){this.out=t;this.lastCols=this.cols}out;lines=[];cursor=null;cursorRow=0;widths=[];lastCols;get cols(){return Math.max(20,this.out.columns||80)}get rows(){return Math.max(10,this.out.rows||24)}eraseSeq(){let t=this.cursorRow;if(this.cols<this.lastCols){t=0;for(let e=0;e<this.cursorRow;e++)t+=Math.max(1,Math.ceil(this.widths[e]/this.cols))}return(t>0?`\x1B[${t}A`:"")+"\r\x1B[J"}drawSeq(){let t=this.cols,e=this.lines.map(r=>w(r)>t-1?ut(r,t-1):r);if(this.widths=e.map(w),this.lastCols=t,e.length===0)return this.cursorRow=0,"";let s=e.join(`\x1B[K\r
16
- `)+"\x1B[K",i=e.length-1;if(this.cursor){let r=Math.min(this.cursor.row,i);i-r>0&&(s+=`\x1B[${i-r}A`),s+="\r"+(this.cursor.col>0?`\x1B[${this.cursor.col}C`:"")+"\x1B[?25h",this.cursorRow=r}else s+="\x1B[?25l",this.cursorRow=i;return s}render(t,e=null){if(e?.row===this.cursor?.row&&e?.col===this.cursor?.col&&t.length===this.lines.length&&t.every((i,r)=>i===this.lines[r])&&this.cols===this.lastCols)return;let s=this.eraseSeq();this.lines=t,this.cursor=e,this.out.write(Nt+"\x1B[?25l"+s+this.drawSeq()+Ut)}commit(t,e){if(t.length===0)return;let s=this.eraseSeq();e&&(this.lines=e.lines,this.cursor=e.cursor);let i=t.flatMap(r=>r.split(`
17
- `)).map(r=>r+"\x1B[K").join(`\r
18
- `)+`\r
19
- `;this.out.write(Nt+"\x1B[?25l"+s+i+this.drawSeq()+Ut)}clear(){let t=this.eraseSeq();this.lines=[],this.cursor=null,this.widths=[],this.cursorRow=0,this.out.write(t+"\x1B[?25h")}};var R=["ask","auto","plan"],ee=new Set(["write_file","edit_file"]),j=class{constructor(t){this.opts=t;this.model=t.model,this.mode=t.mode??"ask",this.client=t.client,this.branch=Ot(t.ws.root),this.cwdShort=Pt(t.ws.root,Xt(),28),this.md=new ft(()=>this.screen.cols-1)}opts;screen=new $(process.stdout);editor=new S;feedback=new S;history=new P;parser=new A({pasteHeuristic:process.platform==="win32"});escTimer;mode="ask";model;client;me=null;usage=null;branch;cwdShort;conversation=[];busy=null;sessionCredits=0;frame=0;spinTimer;md;assistantStarted=!1;running=null;headerShown=!1;lastStats=null;prompt=null;suggestions=null;suggestionsDismissed=!1;queue=[];hint=null;statusNote=null;updateRequested=!1;exitArmedUntil=0;allowedKinds=new Set;welcomePending=!0;renderQueued=!1;finished;closed=!1;run(){let t=process.stdin;t.setRawMode(!0),t.setEncoding("utf8"),t.resume(),process.stdout.write("\x1B[?2004h\x1B[>1u"),t.on("data",this.onData),process.stdout.on("resize",this.onResize),process.on("exit",this.restoreTerminal);for(let e of["SIGTERM","SIGHUP"])process.on(e,()=>this.exit());return this.render(),setTimeout(()=>{import("./highlight-QJIBHZTN.js").then(e=>pt(e.highlight)).catch(()=>{})},50),this.loadAccount(),new Promise(e=>this.finished=e)}restoreTerminal=()=>{if(!this.closed){this.closed=!0;try{process.stdout.write("\x1B[<u\x1B[?2004l\x1B[?25h"),process.stdin.isTTY&&process.stdin.setRawMode(!1)}catch{}}};exit(t="Bye."){this.busy?.controller.abort(),this.stopSpinner(),this.prompt=null,this.screen.clear();let e=this.sessionCredits?o.grey(` ${q(this.sessionCredits)} credits used this session.`):"";process.stdout.write(`${o.ember("\u2726")} ${o.grey(t)}${e}\r
20
- `),this.restoreTerminal(),U(null),W(null),process.stdin.off("data",this.onData),process.stdout.off("resize",this.onResize),process.stdin.pause(),this.finished?.()}async loadAccount(){try{this.me=await this.client.me(),this.usage=this.me.usage,this.commitWelcome()}catch(t){this.commitWelcome(),this.showError(t,!1)}}commitWelcome(){this.welcomePending&&(this.welcomePending=!1,this.commit(["",...this.welcomeLines()]),U(t=>this.commit(["",`${o.ember("\u2726")} ${o.grey(t)}`])),W(t=>{this.statusNote=t,this.schedule()}))}welcomeLines(){return xt({version:this.opts.version,email:this.me?.user.email,plan:this.me?.user.plan,credits:this.usage?k(this.usage):void 0,model:this.model,cwd:this.cwdShort,status:this.me?void 0:"connecting\u2026",updated:this.opts.updated},this.screen.cols)}schedule=()=>{this.renderQueued||this.closed||(this.renderQueued=!0,setTimeout(()=>{this.renderQueued=!1,this.render()},16))};onResize=()=>this.render();render(){if(this.closed)return;let{lines:t,cursor:e}=this.compose();this.screen.render(t,e)}compose(){let t=this.screen.cols,e=[],s=[],i=null;if(this.welcomePending&&e.push("",...this.welcomeLines()),this.running&&e.push("",y(this.running.name,this.running.detail,"running",t)),this.busy&&!this.prompt&&e.push("",vt(this.frame,Date.now()-this.busy.start,this.busy.credits,t,this.busy.verb)),this.prompt?.kind==="menu")s.push("",...Mt(this.prompt.question,this.prompt.options,this.prompt.selected,t,this.prompt.esc));else{for(let f of this.queue)s.push(o.grey(` \u23F5 queued: ${f.split(`
21
- `)[0]}`));s.push("");let h=this.prompt?.kind==="feedback"?this.feedback:this.editor,c=this.prompt?.kind==="feedback"?"\u270E ":"\u276F ",b=h.layout(Tt(t,c)),d=this.prompt?.kind==="feedback"?"Tell flint what to do differently (enter to send \xB7 esc to skip)":this.busy?"Type to queue a follow-up\u2026":this.conversation.length===0?'Describe a task, or try "explain this project" \xB7 @ to attach a file':"Reply, or describe the next task\u2026",m=kt(b.rows,b,t,{placeholder:d,prefix:c,maxRows:Math.max(3,Math.min(10,this.screen.rows-12))});if(i={row:s.length+m.cursorRow,col:m.cursorCol},s.push(...m.lines),this.suggestions&&!this.prompt){let{items:f,selected:H}=this.suggestions,O=Math.max(0,Math.min(H-3,f.length-7));f.slice(O,O+7).forEach((C,Wt)=>{let Ft=O+Wt===H?o.ember(`\u276F ${C.label}`):` ${C.label}`;s.push(` ${Ft}${C.hint?o.grey(` ${C.hint}`):""}`)}),f.length>7&&s.push(o.grey(` ${f.length} matches \xB7 tab to complete`))}}s.push(this.footerLine());let r=this.screen.rows-1-e.length-s.length,n=this.previewLines(),l=r>0?n.slice(Math.max(0,n.length-r)):[],a=[...l,...e,...s];return i&&(i={row:i.row+l.length+e.length,col:i.col}),{lines:a,cursor:this.prompt?.kind==="menu"?null:i}}previewLines(){if(!this.md.started)return[];let t=this.md.preview();return t.length===0?[]:this.assistantStarted?["",...t]:["",this.marker(t[0]),...t.slice(1)]}footerLine(){let t=Date.now();return this.hint&&this.hint.until<t&&(this.hint=null),yt({model:this.model,mode:this.mode,credits:this.usage?k(this.usage):void 0,cwd:this.cwdShort,branch:this.branch,hint:this.hint?.text,note:this.statusNote??void 0},this.screen.cols)}flash(t,e=2500){this.hint={text:t,until:Date.now()+e},this.schedule(),setTimeout(this.schedule,e+20)}commit(t){this.closed||this.screen.commit(t,this.compose())}marker(t){return t.startsWith(" ")?o.gold("\u2726")+" "+t.slice(2):t}commitAssistant(t){t.length!==0&&(this.assistantStarted||(this.assistantStarted=!0,t=["",this.marker(t[0]),...t.slice(1)]),this.commit(t))}flushMarkdown(){this.commitAssistant(this.md.end()),this.assistantStarted=!1}showError(t,e=!0){if(t instanceof L&&t.reason==="update_required"&&this.opts.onUpdateRequired)return this.updateRequested?void 0:(this.updateRequested=!0,this.opts.onUpdateRequired(),this.exit(`${t.message} Updating flint\u2026`));let s=X(t,{interactive:!0,retry:e?"Press \u2191 then enter to try again.":void 0});this.commit(["",...T(s.title,s.lines,this.screen.cols,s.tone)]),this.render()}info(t,e){this.commit(["",...T(t,e,this.screen.cols,"info")])}note(t,e=o.grey){this.commit([` ${o.grey("\u23BF")} ${e(t)}`])}startSpinner(t){let e=new AbortController;this.busy={start:Date.now(),credits:0,verb:t??v[Math.floor(Math.random()*v.length)],controller:e};let s=!t,i=0;return this.spinTimer=setInterval(()=>{this.frame++,s&&++i%40===0&&this.busy&&(this.busy.verb=v[(v.indexOf(this.busy.verb)+1)%v.length]),this.schedule()},100),e}stopSpinner(){this.spinTimer&&clearInterval(this.spinTimer),this.spinTimer=void 0,this.busy=null}onData=t=>{this.escTimer&&clearTimeout(this.escTimer);for(let e of this.parser.feed(t))this.safeKey(e);this.parser.pending&&(this.escTimer=setTimeout(()=>this.parser.flush().forEach(e=>this.safeKey(e)),30))};safeKey(t){try{this.onKey(t)}catch(e){this.showError(e,!1)}}onKey(t){if(t.name==="c"&&t.ctrl)return this.ctrlC();if(this.prompt?.kind==="menu")return this.menuKey(t,this.prompt);if(this.prompt?.kind==="feedback"){let s=this.prompt;return t.name==="escape"?s.resolve(null):t.name==="enter"&&!E(t)?s.resolve(this.feedback.text.trim()):(this.editKey(this.feedback,t),this.schedule())}if(t.name==="tab"&&t.shift)return this.cycleMode();if(t.name==="escape")return this.busy?this.interrupt():this.suggestions?(this.suggestions=null,this.suggestionsDismissed=!0,this.schedule()):void 0;if(t.name==="enter"&&!E(t))return this.enter();if(t.name==="tab")return this.complete();if((t.name==="up"||t.name==="down")&&!t.shift&&!t.meta)return this.upDown(t.name==="up"?-1:1);if(t.name==="d"&&t.ctrl&&this.editor.text==="")return this.exit();if(t.name==="l"&&t.ctrl)return process.stdout.write("\x1B[2J\x1B[3J\x1B[H"),this.screen=new $(process.stdout),this.render();let e=this.editor.text;this.editKey(this.editor,t),this.editor.text!==e&&(this.history.reset(),this.suggestionsDismissed=!1),this.updateSuggestions(),this.schedule()}editKey(t,e){if(e.name==="paste")return t.insert(x(e.text??"").replace(/\t/g," "));if(E(e))return t.insert(`
22
- `);let s=e.ctrl||e.meta;switch(e.name){case"backspace":return s?t.deleteWordBack():t.backspace();case"delete":return t.del();case"left":return s?t.wordLeft():t.left();case"right":return s?t.wordRight():t.right();case"home":return t.home();case"end":return t.end()}if(e.ctrl){switch(e.name){case"a":return t.home();case"e":return t.end();case"b":return t.left();case"f":return t.right();case"k":return t.killToEnd();case"u":return t.killToStart();case"w":return t.deleteWordBack();case"d":return t.del();case"h":return t.backspace()}return}if(e.meta)return e.name==="b"?t.wordLeft():e.name==="f"?t.wordRight():e.name==="d"?t.deleteWordBack():void 0;e.text&&t.insert(e.text)}ctrlC(){if(this.prompt?.kind==="menu")return this.prompt.resolve(null);if(this.prompt?.kind==="feedback")return this.prompt.resolve(null);if(this.busy)return this.interrupt();if(this.editor.text)return this.editor.clear(),this.suggestions=null,this.schedule();if(Date.now()<this.exitArmedUntil)return this.exit();this.exitArmedUntil=Date.now()+2e3,this.flash("Press Ctrl+C again to exit",2e3)}interrupt(){!this.busy||this.busy.controller.signal.aborted||(this.busy.controller.abort(),this.flash("Interrupting\u2026",1500))}cycleMode(){this.mode=R[(R.indexOf(this.mode)+1)%R.length],this.schedule()}upDown(t){if(this.suggestions){let s=this.suggestions.items.length;return this.suggestions.selected=(this.suggestions.selected+t+s)%s,this.schedule()}if(this.editor.vertical(t))return this.schedule();let e=t<0?this.history.prev(this.editor.text):this.history.next();e!==null&&this.editor.set(e),this.updateSuggestions(),this.schedule()}updateSuggestions(){if(this.suggestionsDismissed)return void(this.suggestions=null);let t=this.editor.text;if(/^\/[\w-]*$/.test(t)&&this.editor.cursor===t.length){let s=st(t).map(r=>({value:`/${r.name}`,label:`/${r.name}${r.args?" "+r.args:""}`,hint:r.description})),i=this.suggestions?.kind==="slash"?this.suggestions.selected:0;this.suggestions=s.length?{items:s,selected:Math.min(i,s.length-1),kind:"slash",start:0}:null;return}let e=this.editor.currentToken();if(e.text.startsWith("@")){let s=rt(this.opts.ws.root,e.text.slice(1)).map(i=>({value:`@${i}`,label:i}));this.suggestions=s.length?{items:s,selected:0,kind:"path",start:e.start}:null;return}this.suggestions=null}complete(){if(!this.suggestions&&(this.updateSuggestions(),!this.suggestions))return;let t=this.suggestions;if(t.kind==="slash")this.editor.set(t.items[t.selected].value+" "),this.suggestions=null;else{let e=this.editor.currentToken(),s=t.items.map(n=>n.value),i=it(s),r=i.length>e.text.length?i:t.items[t.selected].value;this.editor.replaceToken(e.start,r+(r.endsWith("/")||s.length>1&&r===i?"":" ")),this.updateSuggestions()}this.schedule()}enter(){let t=this.editor;if(t.cursor===t.text.length&&t.text.endsWith("\\"))return t.backspace(),t.insert(`
23
- `),this.schedule();if(this.suggestions?.kind==="slash"){let s=this.suggestions.items[this.suggestions.selected].value;F.some(i=>`/${i.name}`===t.text.trim())||t.set(s)}let e=t.text.trim();if(e){if(this.history.add(e),t.clear(),this.suggestions=null,this.busy)return this.queue.push(e),this.schedule();this.submit(e)}}async submit(t){try{let s=tt(t);s?await this.command(s.name,s.args,!!s.command):await this.turn(t)}catch(s){this.stopSpinner(),this.showError(s,!1)}let e=this.queue.shift();e!==void 0&&!this.closed&&this.submit(e)}menuKey(t,e){let s=e.options.length;if(t.name==="up"||t.name==="tab"&&t.shift)e.selected=(e.selected-1+s)%s;else if(t.name==="down"||t.name==="tab")e.selected=(e.selected+1)%s;else{if(t.name==="enter")return e.resolve(e.selected);if(t.name==="escape")return e.resolve(null);if(/^[1-9]$/.test(t.name)&&Number(t.name)<=s)return e.resolve(Number(t.name)-1);if(t.name==="y")return e.resolve(0);if(t.name==="n")return e.resolve(s-1)}this.schedule()}ask(t,e,s=0,i="cancel"){return new Promise(r=>{this.prompt={kind:"menu",question:t,options:e,selected:s,esc:i,resolve:n=>{this.prompt=null,this.render(),r(n)}},this.render()})}askFeedback(){return this.feedback.clear(),new Promise(t=>{this.prompt={kind:"feedback",resolve:e=>{this.prompt=null,this.render(),t(e)}},this.render()})}echo(t){let e=t.split(`
24
- `);this.commit(["",...e.map((s,i)=>`${i===0?o.ember("\u276F"):" "} ${o.bold(x(s))}`)])}stepper(t){return this.client.stepper(()=>this.model,()=>t.signal,(e,s)=>{this.busy&&(this.busy.credits+=e),this.sessionCredits+=e,this.usage=s})}async turn(t,e=t){this.echo(e);let s=await ht(this.opts.ws,t,{first:this.conversation.length===0,mode:this.mode});s.memory&&this.note(`Using ${M} project memory`);for(let h of s.attachments)h.error?this.note(`Could not attach ${h.path}: ${h.error}`,o.gold):this.note(`Attached ${h.path} (${h.lines} line${h.lines===1?"":"s"})`);let i=this.startSpinner(),r=Date.now(),n=[...this.conversation,{role:"user",content:s.content}],l=!1;try{this.conversation=await Q(this.opts.ws,n,this.stepper(i),this.agentUI(i),{signal:i.signal})}catch(h){l=!0,this.flushMarkdown();let c=h.partial;c&&c.length>n.length&&(this.conversation=c),this.showError(h),h instanceof L&&h.reason==="signed_out"&&K()}this.flushMarkdown(),this.running=null;let a=this.busy?.credits??0;if(this.stopSpinner(),this.hint?.text==="Interrupting\u2026"&&(this.hint=null),i.signal.aborted)this.commit(["",` ${o.gold("\u23F9")} ${o.grey("Interrupted \xB7 tell flint what to do instead")}`]);else if(!l){let c=[`${Math.max(1,Math.round((Date.now()-r)/1e3))}s`,`${a} credit${a===1?"":"s"}`,this.usage?k(this.usage):null].filter(Boolean);this.commit(["",o.grey(` \u273B ${c.join(" \xB7 ")}`)])}this.render()}agentUI(t){let e=()=>this.screen.cols;return{onDelta:s=>{this.running&&(this.running=null),this.commitAssistant(this.md.push(x(s))),this.schedule()},onToolStart:(s,i)=>{this.flushMarkdown(),this.lastDetail=i,this.lastFeedback="",this.headerShown=!1,this.lastStats=null,this.running={name:s,detail:i},this.schedule()},onToolResult:(s,i,r="")=>{this.running=null;let n=[],l=this.lastDetail;if(!i)this.headerShown||n.push("",y(s,l,"error",e())),n.push(...p(r,e(),3,o.red));else if(ee.has(s))if(/^(Created|Updated) /.test(r)){let a=this.lastStats;n.push(...p(`${r.startsWith("Created")?"Created":"Updated"}${a?` \xB7 +${a.added} -${a.removed}`:""}`,e()))}else n.push(...p(r===D?"Interrupted":r.startsWith("Plan mode")?"Skipped (plan mode)":this.declinedText("Not applied"),e()));else if(s==="run_command")if(/^(The user declined|Plan mode is on)/.test(r))n.push(...p(r.startsWith("Plan mode")?"Skipped (plan mode)":this.declinedText("Not run"),e()));else if(r===D||r.startsWith("[interrupted by the user before"))n.push(...p("Interrupted",e()));else{let a=/\n?\[(exit code (\d+|null)|timed out after \d+s|interrupted by the user|could not run command[^\]]*)\]$/.exec(r),h=(a?r.slice(0,a.index):r).trimEnd(),c=!a||a[2]!=="0";this.headerShown||n.push("",y(s,l,c?"error":"ok",e())),h?n.push(...p(h,e(),5)):c||n.push(...p("Done (no output)",e())),c&&a&&n.push(` ${h?" ":o.grey("\u23BF")} ${o.red(a[1])}`)}else{let a=St(s,r);n.push("",y(s,l,"ok",e(),a.suffix)),a.detail&&n.push(...p(a.detail,e()))}this.commit(n),this.schedule()},approveChange:async s=>(this.running=null,this.headerShown=!0,this.lastStats=$t(s.diff),this.lastDetail=s.path,this.commit(["",y(s.created?"write_file":"edit_file",s.path,"ok",e()),...Ct(s.diff,s.path,e(),s.created)]),this.mode==="plan"?{declined:"Plan mode is on, so no files may be changed. Put this change in your plan instead."}:this.opts.autoYes||this.mode==="auto"?!0:this.decide(t,`${s.created?"Create":"Make this edit to"} ${o.ember(x(s.path))}?`,"Yes, and don't ask again for edits this session","change",()=>{this.mode="auto"})),approveCommand:async s=>{this.running=null,this.headerShown=!0;let i=x(s),r=mt(`${o.ember("\u25CF")} ${o.bold("Run")} ${i}`,e()-1," ");if(this.commit(["",...r]),this.mode==="plan")return{declined:"Plan mode is on, so no commands may run. Put this command in your plan instead."};if(this.opts.autoYes)return!0;let n=lt(s);return n&&this.allowedKinds.has(n)?(this.note(`Allowed (${n} commands are approved for this session)`),!0):this.decide(t,"Run this command?",n?`Yes, and don't ask again for "${n}" commands this session`:null,"command",()=>n&&this.allowedKinds.add(n))}}}lastDetail="";declinedText(t){return this.lastFeedback?`${t} \xB7 you said: ${this.lastFeedback.split(`
25
- `)[0]}`:t}lastFeedback="";async decide(t,e,s,i,r){let n=[{label:"Yes"}];s&&n.push({label:s,hint:i==="change"?"(auto-accept edits)":void 0}),n.push({label:"No, tell flint what to do differently"});let l=await this.ask(e,n,0,"stop flint");if(l===null)return t.abort(),!1;if(l===0)return!0;if(s&&l===1)return r(),!0;let a=await this.askFeedback();return a===null||a===""?!1:(this.lastFeedback=a,{declined:`The user declined this ${i} and said: ${JSON.stringify(a)}. Follow their instruction instead.`})}async command(t,e,s){if(!s){let i=et(t);return this.echo(`/${t}${e?" "+e:""}`),this.note(`Unknown command /${t}.${i?` Did you mean /${i}?`:""} Type /help for the list.`,o.gold),this.render()}switch(t){case"help":return this.help();case"exit":return this.exit();case"clear":return this.conversation=[],this.commit(["",o.grey(` ${"\u2500".repeat(3)} new conversation ${"\u2500".repeat(Math.max(3,Math.min(40,this.screen.cols-26)))}`)]),this.render();case"mode":{let i=e.toLowerCase(),r=R.includes(i)?i:i==="auto-accept"?"auto":null;return r?this.mode=r:this.cycleMode(),this.note(`Mode: ${gt[this.mode]}`),this.render()}case"model":return this.modelCommand(e);case"credits":return this.creditsCommand();case"init":return this.initCommand();case"compact":return this.compactCommand();case"login":return this.loginCommand();case"update":return this.opts.onUpdateNow?(this.opts.onUpdateNow(),this.exit("Checking for a newer flint\u2026")):(this.note("Run flint update in your terminal to update."),this.render());case"logout":return K(),this.exit("Signed out. Run flint login to connect again.")}}help(){let t=F.map(s=>`${o.ember(`/${s.name}`)}${s.args?o.grey(" "+s.args):""} ${o.grey(s.description)}`),e=[`${o.bold("enter")} send \xB7 ${o.bold("shift+enter")}, ${o.bold("ctrl+j")} or ${o.bold("\\")} new line`,`${o.bold("@path")} attach a file \xB7 ${o.bold("tab")} complete \xB7 ${o.bold("\u2191/\u2193")} history`,`${o.bold("esc")} interrupt \xB7 ${o.bold("shift+tab")} mode \xB7 ${o.bold("ctrl+c")} twice to exit`];this.commit(["",...wt([o.bold("Commands"),...t,"",o.bold("Keys"),...e],Math.min(this.screen.cols-1,76),{border:o.ember})]),this.render()}async modelCommand(t){let e=t==="smart"||t==="standard"?t:null;if(!t){let s=["standard","smart"].map(r=>({label:`${g[r].label}${r===this.model?o.grey(" (current)"):""}`,hint:`${g[r].cost} \xB7 ${g[r].note}`})),i=await this.ask("Choose a model",s,this.model==="smart"?1:0);if(i===null)return;e=i===1?"smart":"standard"}if(!e)return this.note("Usage: /model standard | smart",o.gold);if(e==="smart"&&(this.me?.user.plan??"free")==="free")return this.commit(["",...T("Smart needs a paid plan",["You are on the Free plan, so flint stays on Standard.",`Upgrade: ${N}`],this.screen.cols,"warn")]),this.render();this.model=e,this.note(`Model: ${bt[e]} \xB7 ${g[e].cost}`),this.render()}async creditsCommand(){try{this.me=await this.client.me(),this.usage=this.me.usage;let t=this.sessionCredits?[`This session: ${q(this.sessionCredits)} credits`]:[];this.info("Credits",[...nt(this.usage),...t,"",`Standard ${g.standard.cost} \xB7 Smart ${g.smart.cost}`,`More credits: ${N}`])}catch(t){this.showError(t,!1)}this.render()}async initCommand(){if(Vt(te(this.opts.ws.root,M)))return this.info(`${M} already exists`,["flint reads it at the start of every conversation.","Edit it by hand, or ask flint to update it."]),this.render();await this.turn(ot,"/init")}async compactCommand(){if(this.conversation.length<3)return this.note("Nothing to compact yet."),this.render();this.echo("/compact");let t=this.startSpinner("Compacting");try{let e=this.conversation,s="";for(let r=0;r<4&&!s;r++)try{if(s=(await this.stepper(t)([...e,{role:"user",content:at}],()=>{})).text.trim(),!s)throw new Error("The summary came back empty. Try again, or use /clear.")}catch(n){if(!(n instanceof J))throw n;e=z(e)}if(!s)throw new Error("This conversation is too long to summarise. Start a new one with /clear.");let i=this.conversation.length;this.conversation=[{role:"user",content:`Summary of our conversation so far (compacted to save context):
26
-
27
- ${s}`},{role:"assistant",content:"Thanks, I have the context. What should we do next?"}],this.note(`Compacted ${i} messages into a summary`),this.commit(p(s,this.screen.cols,6).map(r=>r.replace("\u23BF"," ")))}catch(e){t.signal.aborted||this.showError(e,!1)}this.stopSpinner(),this.render()}async loginCommand(){let t=V(null),e=new I(t),s=this.startSpinner("Waiting for approval in your browser");try{let i=await e.deviceLogin((r,n)=>{this.info("Connect your FlintMaker account",[`Your code: ${o.bold(o.gold(r))}`,`Opening ${n}`,"Approve it in the browser \xB7 esc to cancel"]),G(n),this.render()},s.signal);Z({token:i.token,email:i.user.email,api:e.base}),this.client=new I(t,i.token),this.me=await this.client.me(),this.usage=this.me.usage,this.note(`Signed in as ${i.user.email}`,o.green)}catch(i){s.signal.aborted||this.showError(i,!1)}this.stopSpinner(),this.render()}};async function Ke(u){await new j(u).run()}export{j as App,Ke as interactive};